diff options
Diffstat (limited to 'tests/manual')
4 files changed, 346 insertions, 13 deletions
diff --git a/tests/manual/wasm/localfiles/main.cpp b/tests/manual/wasm/localfiles/main.cpp index 862bff50a47..90e8c2e90f6 100644 --- a/tests/manual/wasm/localfiles/main.cpp +++ b/tests/manual/wasm/localfiles/main.cpp @@ -5,6 +5,81 @@ #include <emscripten/val.h> #include <emscripten.h> +class DropZone : public QLabel +{ + Q_OBJECT +public: + explicit DropZone(QWidget *parent = nullptr) : QLabel(parent) + { + setAcceptDrops(true); + setFrameStyle(QFrame::Box | QFrame::Sunken); + setAlignment(Qt::AlignCenter); + setText("Drop files here\n(will read first file)"); + setMinimumSize(400, 150); + setStyleSheet("QLabel { background-color: #f0f0f0; border: 2px dashed #999; padding: 20px; }"); + } + +Q_SIGNALS: + void filesDropped(const QList<QUrl> &urls); + +protected: + void dragEnterEvent(QDragEnterEvent *event) override + { + if (event->mimeData()->hasUrls()) { + event->acceptProposedAction(); + setStyleSheet("QLabel { background-color: #e0f0ff; border: 2px dashed #0066cc; padding: 20px; }"); + } + } + + void dragLeaveEvent(QDragLeaveEvent *event) override + { + Q_UNUSED(event); + setStyleSheet("QLabel { background-color: #f0f0f0; border: 2px dashed #999; padding: 20px; }"); + } + + void dropEvent(QDropEvent *event) override + { + const QMimeData *mimeData = event->mimeData(); + + if (mimeData->hasUrls()) { + QList<QUrl> urls = mimeData->urls(); + + qDebug() << "=== Files Dropped ==="; + qDebug() << "Number of files:" << urls.size(); + + for (int i = 0; i < urls.size(); ++i) { + const QUrl &url = urls.at(i); + qDebug() << "\n--- File" << (i + 1) << "---"; + qDebug() << "URL:" << url; + qDebug() << "URL toString:" << url.toString(); + qDebug() << "URL scheme:" << url.scheme(); + qDebug() << "URL path:" << url.path(); + qDebug() << "URL fileName:" << url.fileName(); + qDebug() << "isLocalFile:" << url.isLocalFile(); + + if (url.isLocalFile()) { + QString filePath = url.toLocalFile(); + qDebug() << "Local file path:" << filePath; + + QFileInfo fileInfo(filePath); + qDebug() << "File name:" << fileInfo.fileName(); + qDebug() << "File size:" << fileInfo.size(); + qDebug() << "File exists:" << fileInfo.exists(); + qDebug() << "Is readable:" << fileInfo.isReadable(); + qDebug() << "Absolute path:" << fileInfo.absoluteFilePath(); + qDebug() << "Last modified:" << fileInfo.lastModified().toString(); + } + } + qDebug() << "===================\n"; + + event->acceptProposedAction(); + emit filesDropped(urls); + } + + setStyleSheet("QLabel { background-color: #f0f0f0; border: 2px dashed #999; padding: 20px; }"); + } +}; + class AppWindow : public QObject { Q_OBJECT @@ -12,21 +87,39 @@ public: AppWindow() : m_layout(new QVBoxLayout(&m_loadFileUi)), m_window(emscripten::val::global("window")), m_showOpenFilePickerFunction(m_window["showOpenFilePicker"]), - m_showSaveFilePickerFunction(m_window["showSaveFilePicker"]) + m_showSaveFilePickerFunction(m_window["showSaveFilePicker"]), + m_fileDialog(new QFileDialog(&m_loadFileUi)), + m_isLoadOperation(true) { - addWidget<QLabel>("Filename filter"); - const bool localFileApiAvailable = !m_showOpenFilePickerFunction.isUndefined() && !m_showSaveFilePickerFunction.isUndefined(); m_useLocalFileApisCheckbox = addWidget<QCheckBox>("Use the window.showXFilePicker APIs"); m_useLocalFileApisCheckbox->setEnabled(localFileApiAvailable); m_useLocalFileApisCheckbox->setChecked(localFileApiAvailable); + connect(m_useLocalFileApisCheckbox, &QCheckBox::toggled, + std::bind(&AppWindow::onUseLocalFileApisCheckboxToggled, this)); + + m_useStandardFileDialogCheckbox = addWidget<QCheckBox>("Use standard QFileDialog API"); + connect(m_useStandardFileDialogCheckbox, &QCheckBox::toggled, + std::bind(&AppWindow::onUseStandardFileDialogCheckboxToggled, this)); + m_useStandardFileDialogCheckbox->setChecked(true); + + m_useExecModeCheckbox = addWidget<QCheckBox>("Use exec() instead of open()"); + m_useExecModeCheckbox->setChecked(false); + + addWidget<QLabel>("Filename filter"); - m_filterEdit = addWidget<QLineEdit>("Images (*.png *.jpg);;PDF (*.pdf);;*.txt"); + m_filterCombo = addWidget<QComboBox>(); + m_filterCombo->addItem("*"); + m_filterCombo->addItem("Images (*.png *.jpg);;PDF (*.pdf);;*.txt"); + m_filterCombo->setCurrentIndex(0); // Make "*" the default auto* loadFile = addWidget<QPushButton>("Load File"); + m_dropZone = addWidget<DropZone>(); + connect(m_dropZone, &DropZone::filesDropped, this, &AppWindow::onFilesDropped); + m_fileInfo = addWidget<QLabel>("Opened file:"); m_fileInfo->setTextInteractionFlags(Qt::TextSelectableByMouse); @@ -43,11 +136,13 @@ public: m_loadFileUi.setLayout(m_layout); - QObject::connect(m_useLocalFileApisCheckbox, &QCheckBox::toggled, std::bind(&AppWindow::onUseLocalFileApisCheckboxToggled, this)); QObject::connect(loadFile, &QPushButton::clicked, this, &AppWindow::onLoadClicked); - QObject::connect(m_saveFile, &QPushButton::clicked, std::bind(&AppWindow::onSaveClicked, this)); + + // Connect to both fileSelected and accepted signals for compatibility + QObject::connect(m_fileDialog, &QFileDialog::fileSelected, this, &AppWindow::onFileSelected); + QObject::connect(m_fileDialog, &QFileDialog::accepted, this, &AppWindow::onDialogAccepted); } void show() { @@ -67,6 +162,29 @@ private Q_SLOTS: m_showSaveFilePickerFunction : emscripten::val::undefined()); } + void onUseStandardFileDialogCheckboxToggled() + { + m_useLocalFileApisCheckbox->setChecked(m_useStandardFileDialogCheckbox->isChecked()); + } + + void onFilesDropped(const QList<QUrl> &urls) + { + if (urls.isEmpty()) + return; + + // Load the first dropped file + const QUrl &url = urls.first(); + + if (url.isLocalFile()) { + QString filePath = url.toLocalFile(); + loadFileWithQFile(filePath); + } else { + // Try using the URL string directly for non-file:// URLs (like weblocalfile://) + QString urlString = url.toString(); + loadFileWithQFile(urlString); + } + } + void onFileContentReady(const QString &fileName, const QByteArray &fileContents) { m_fileContent = fileContents; @@ -89,16 +207,108 @@ private Q_SLOTS: void onLoadClicked() { - QFileDialog::getOpenFileContent( - m_filterEdit->text(), - std::bind(&AppWindow::onFileContentReady, this, std::placeholders::_1, std::placeholders::_2), - &m_loadFileUi); + if (m_useStandardFileDialogCheckbox->isChecked()) { + m_isLoadOperation = true; + m_fileDialog->setFileMode(QFileDialog::ExistingFile); + m_fileDialog->setAcceptMode(QFileDialog::AcceptOpen); + m_fileDialog->setNameFilter(m_filterCombo->currentText()); + m_fileDialog->setWindowTitle("Open File"); + + if (m_useExecModeCheckbox->isChecked()) { + qDebug() << "Using exec() mode"; + int result = m_fileDialog->exec(); + if (result == QDialog::Accepted) { + QStringList files = m_fileDialog->selectedFiles(); + if (!files.isEmpty()) { + onFileSelected(files.first()); + } + } + } else { + qDebug() << "Using open() mode"; + m_fileDialog->open(); + } + } else { + QFileDialog::getOpenFileContent( + m_filterCombo->currentText(), + std::bind(&AppWindow::onFileContentReady, this, std::placeholders::_1, std::placeholders::_2), + &m_loadFileUi); + } } void onSaveClicked() { - m_fileInfo->setText("Saving file... (no result information with current API)"); - QFileDialog::saveFileContent(m_fileContent, m_savedFileNameEdit->text()); + if (m_useStandardFileDialogCheckbox->isChecked()) { + m_isLoadOperation = false; + m_fileDialog->setFileMode(QFileDialog::AnyFile); + m_fileDialog->setAcceptMode(QFileDialog::AcceptSave); + m_fileDialog->setNameFilter(m_filterCombo->currentText()); + m_fileDialog->setWindowTitle("Save File"); + m_fileDialog->selectFile(m_savedFileNameEdit->text()); + + if (m_useExecModeCheckbox->isChecked()) { + qDebug() << "Using exec() mode for save"; + int result = m_fileDialog->exec(); + if (result == QDialog::Accepted) { + QStringList files = m_fileDialog->selectedFiles(); + if (!files.isEmpty()) { + onFileSelected(files.first()); + } + } + } else { + qDebug() << "Using open() mode for save"; + m_fileDialog->open(); + } + } else { + m_fileInfo->setText("Saving file... (no result information with current API)"); + QFileDialog::saveFileContent(m_fileContent, m_savedFileNameEdit->text()); + } + } + + void onDialogAccepted() + { + QStringList files = m_fileDialog->selectedFiles(); + if (!files.isEmpty()) { + onFileSelected(files.first()); + } + } + + void onFileSelected(const QString &fileName) + { + qDebug() << "onFileSelected" << fileName; + + if (m_isLoadOperation) { + loadFileWithQFile(fileName); + } else { + saveFileWithQFile(fileName); + } + } + + void loadFileWithQFile(const QString &fileName) + { + qDebug() << "loadFileWithQFile" << fileName; + + QFile file(fileName); + if (file.open(QIODevice::ReadOnly)) { + qDebug() << "loadFileWithQFile" << fileName; + QByteArray fileContents = file.readAll(); + file.close(); + onFileContentReady(QFileInfo(fileName).fileName(), fileContents); + } else { + m_fileInfo->setText(QString("Failed to open file: %1").arg(file.errorString())); + } + } + + void saveFileWithQFile(const QString &fileName) + { + QFile file(fileName); + if (file.open(QIODevice::WriteOnly)) { + qint64 bytesWritten = file.write(m_fileContent); + file.close(); + bool success = (bytesWritten == m_fileContent.size()); + m_fileInfo->setText(QString("File save result: %1").arg(success ? "success" : "failed")); + } else { + m_fileInfo->setText(QString("Failed to save file: %1").arg(file.errorString())); + } } private: @@ -113,7 +323,10 @@ private: QWidget m_loadFileUi; QCheckBox* m_useLocalFileApisCheckbox; - QLineEdit* m_filterEdit; + QCheckBox* m_useStandardFileDialogCheckbox; + QCheckBox* m_useExecModeCheckbox; + DropZone* m_dropZone; + QComboBox* m_filterCombo; QVBoxLayout *m_layout; QLabel* m_fileInfo; QLabel* m_fileHash; @@ -124,6 +337,9 @@ private: emscripten::val m_showOpenFilePickerFunction; emscripten::val m_showSaveFilePickerFunction; + QFileDialog* m_fileDialog; + bool m_isLoadOperation; + QByteArray m_fileContent; }; diff --git a/tests/manual/widgets/itemviews/CMakeLists.txt b/tests/manual/widgets/itemviews/CMakeLists.txt index 4a67078103c..bae613b4fb9 100644 --- a/tests/manual/widgets/itemviews/CMakeLists.txt +++ b/tests/manual/widgets/itemviews/CMakeLists.txt @@ -5,3 +5,4 @@ add_subdirectory(qheaderview) add_subdirectory(qtreeview) add_subdirectory(qtreewidget) add_subdirectory(tableview-span-navigation) +add_subdirectory(qtablewidget-sort-indicator) diff --git a/tests/manual/widgets/itemviews/qtablewidget-sort-indicator/CMakeLists.txt b/tests/manual/widgets/itemviews/qtablewidget-sort-indicator/CMakeLists.txt new file mode 100644 index 00000000000..9d1ef6e7931 --- /dev/null +++ b/tests/manual/widgets/itemviews/qtablewidget-sort-indicator/CMakeLists.txt @@ -0,0 +1,16 @@ +# Copyright (C) 2025 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +##################################################################### +## qtablewidget-sort-indicator Binary: +##################################################################### + +qt_internal_add_manual_test(qtablewidget-sort-indicator + GUI + SOURCES + main.cpp + LIBRARIES + Qt::CorePrivate + Qt::Gui + Qt::Widgets +) diff --git a/tests/manual/widgets/itemviews/qtablewidget-sort-indicator/main.cpp b/tests/manual/widgets/itemviews/qtablewidget-sort-indicator/main.cpp new file mode 100644 index 00000000000..b3464c67c89 --- /dev/null +++ b/tests/manual/widgets/itemviews/qtablewidget-sort-indicator/main.cpp @@ -0,0 +1,100 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QApplication> +#include <QTableWidget> +#include <QHeaderView> +#include <QVBoxLayout> +#include <QGroupBox> +#include <QRadioButton> +#include <QLabel> + +QString createStyleSheet(const char *sortArrowPos) +{ + QString styleSheet {R"( + QHeaderView::section { + background-color: #f0f0f0; + padding: 5px; + border: 1px solid #ffffff; + font-weight: bold; + } + + QHeaderView::up-arrow, QHeaderView::down-arrow { + width: 24px; + height: 24px; + subcontrol-position: %1; + subcontrol-origin: padding; + } + )"}; + + return styleSheet.arg(sortArrowPos); +} + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + + QWidget mainWidget; + mainWidget.setWindowTitle("QTableWidget sort indicator overlap with clipping"); + + const QStringList headerLabels { "Header", "LongHeaderText"}; + const QStringList column1 { "Alpha", "Beta", "Gamma" }; + const QStringList column2 { "1", "2", "3" }; + + QTableWidget tableWidget(3, 2, &mainWidget); + tableWidget.setHorizontalHeaderLabels(headerLabels); + + for (int i {0} ; i < column1.size() ; ++i) { + tableWidget.setItem(i, 0, new QTableWidgetItem(column1[i])); + tableWidget.setItem(i, 1, new QTableWidgetItem(column2[i])); + } + + tableWidget.setSortingEnabled(true); + tableWidget.setStyleSheet(createStyleSheet("center right")); + tableWidget.adjustSize(); + + QVBoxLayout mainLayout {&mainWidget}; + QGroupBox buttonBox; + QVBoxLayout buttonLayout {&buttonBox}; + QRadioButton leftButton {"Left-aligned sort indicator"}; + QRadioButton centerButton {"Center-aligned sort indicator"}; + QRadioButton rightButton {"Right-aligned sort indicator"}; + + buttonLayout.addWidget(&leftButton); + buttonLayout.addWidget(¢erButton); + buttonLayout.addWidget(&rightButton); + + mainLayout.addWidget(&tableWidget); + mainLayout.addWidget(&buttonBox); + + QLabel instructions { QT_TR_NOOP(R"(<html>Instructions: +<ol> +<li>There are 3 options for alignment of the column header sort arrow: left, center, and right. Click one of the 3 radio buttons to select the sort arrow alignment. +</li> +<li>Click the left column header to sort the table. The sort arrow should appear at its correct alignment without overlapping the text. +</li> +<li>Click the right column header. The sort arrow should appear at its correct alignment. The left and right alignment should clip the text without changing its position. The center alignment should not clip the text at all. +</ol> + </html>)")}; + instructions.setTextFormat(Qt::AutoText); + instructions.setWordWrap(true); + mainLayout.addWidget(&instructions); + + QObject::connect(&leftButton, &QRadioButton::clicked, &app, [&](bool checked) { + if (checked) + tableWidget.setStyleSheet(createStyleSheet("center left")); + }); + QObject::connect(¢erButton, &QRadioButton::clicked, &app, [&](bool checked) { + if (checked) + tableWidget.setStyleSheet(createStyleSheet("top center")); + }); + QObject::connect(&rightButton, &QRadioButton::clicked, &app, [&](bool checked) { + if (checked) + tableWidget.setStyleSheet(createStyleSheet("center right")); + }); + + leftButton.click(); + mainWidget.show(); + + return app.exec(); +} |
