From 1324525ecc363c40295ec57f88a8469de6aab8ad Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 28 Jan 2016 15:50:57 -0800 Subject: [PATCH] Make file dialog compatible with QFileDialog::getOpenFile --- interface/resources/qml/desktop/Desktop.qml | 6 ++ .../resources/qml/dialogs/FileDialog.qml | 36 +++++++---- .../dialogs/fileDialog/FileTypeSelection.qml | 27 ++++++++ libraries/ui/src/OffscreenUi.cpp | 62 +++++++++++++++++++ libraries/ui/src/OffscreenUi.h | 2 +- 5 files changed, 121 insertions(+), 12 deletions(-) create mode 100644 interface/resources/qml/dialogs/fileDialog/FileTypeSelection.qml diff --git a/interface/resources/qml/desktop/Desktop.qml b/interface/resources/qml/desktop/Desktop.qml index 8c4f73c200..b610dbf73c 100644 --- a/interface/resources/qml/desktop/Desktop.qml +++ b/interface/resources/qml/desktop/Desktop.qml @@ -257,6 +257,12 @@ FocusScope { return queryDialogBuilder.createObject(desktop, properties); } + Component { id: fileDialogBuilder; FileDialog { } } + function fileOpenDialog(properties) { + return fileDialogBuilder.createObject(desktop, properties); + } + + MenuMouseHandler { id: menuPopperUpper } function popupMenu(point) { menuPopperUpper.popup(desktop, rootMenu.items, point); diff --git a/interface/resources/qml/dialogs/FileDialog.qml b/interface/resources/qml/dialogs/FileDialog.qml index 9d2278f460..353e2df494 100644 --- a/interface/resources/qml/dialogs/FileDialog.qml +++ b/interface/resources/qml/dialogs/FileDialog.qml @@ -12,6 +12,27 @@ import "fileDialog" //FIXME implement shortcuts for favorite location ModalWindow { id: root + resizable: true + width: 640 + height: 480 + + Settings { + category: "FileDialog" + property alias width: root.width + property alias height: root.height + property alias x: root.x + property alias y: root.y + } + + + // Set from OffscreenUi::getOpenFile() + property alias caption: root.title; + // Set from OffscreenUi::getOpenFile() + property alias dir: model.folder; + // Set from OffscreenUi::getOpenFile() + property alias filter: selectionType.filtersString; + // Set from OffscreenUi::getOpenFile() + property int options; // <-- FIXME unused property bool selectDirectory: false; property bool showHidden: false; @@ -19,17 +40,11 @@ ModalWindow { property bool multiSelect: false; // FIXME implement property bool saveDialog: false; + property var helper: fileDialogHelper + property alias model: fileTableView.model signal selectedFile(var file); signal canceled(); - resizable: true - width: 640 - height: 480 - - property var helper: fileDialogHelper - property alias model: fileTableView.model - property alias filterModel: selectionType.model - property alias folder: model.folder Rectangle { anchors.fill: parent @@ -120,6 +135,7 @@ ModalWindow { onDoubleClicked: navigateToRow(row); model: FolderListModel { id: model + nameFilters: selectionType.currentFilter showDirsFirst: true showDotAndDotDot: false showFiles: !root.selectDirectory @@ -157,12 +173,10 @@ ModalWindow { readOnly: true } - ComboBox { + FileTypeSelection { id: selectionType anchors { bottom: buttonRow.top; bottomMargin: 8; right: parent.right; rightMargin: 8; left: buttonRow.left } visible: !selectDirectory - model: ListModel { ListElement { text: "All Files (*.*)"; filter: "*.*" } } -// onCurrentIndexChanged: model.nameFilters = [ filterModel.get(currentIndex).filter ] KeyNavigation.left: fileTableView KeyNavigation.right: openButton } diff --git a/interface/resources/qml/dialogs/fileDialog/FileTypeSelection.qml b/interface/resources/qml/dialogs/fileDialog/FileTypeSelection.qml new file mode 100644 index 0000000000..a3ab652e32 --- /dev/null +++ b/interface/resources/qml/dialogs/fileDialog/FileTypeSelection.qml @@ -0,0 +1,27 @@ +import QtQuick 2.5 + +import "../../controls" as VrControls + +VrControls.ComboBox { + id: root + property string filtersString: "All Files (*.*)"; + property var currentFilter: [ "*.*" ]; + + // Per http://doc.qt.io/qt-5/qfiledialog.html#getOpenFileName the string can contain + // multiple filters separated by semicolons + // ex: "Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)" + model: filtersString.split(';;'); + + enabled: model.length > 1 + + onCurrentTextChanged: { + var globRegex = /\((.*)\)$/ + var globs = globRegex.exec(currentText); + if (!globs[1]) { + console.warn("Unable to parse filter " + currentText); + return; + } + currentFilter = globs[1].split(" "); + } +} + diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp index d7d28bef84..f399cd95a1 100644 --- a/libraries/ui/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -412,4 +412,66 @@ void OffscreenUi::toggleMenu(const QPoint& screenPosition) { } +class FileDialogListener : public ModalDialogListener { + Q_OBJECT + + friend class OffscreenUi; + FileDialogListener(QQuickItem* messageBox) : ModalDialogListener(messageBox) { + if (_finished) { + return; + } + connect(_dialog, SIGNAL(selectedFile(QVariant)), this, SLOT(onSelectedFile(QVariant))); + } + +private slots: + void onSelectedFile(QVariant file) { + _result = file; + _finished = true; + disconnect(_dialog); + } +}; + +QString OffscreenUi::fileOpenDialog(const QString& caption, const QString& dir, const QString& filter, QString* selectedFilter, QFileDialog::Options options) { + if (QThread::currentThread() != thread()) { + QString result; + QMetaObject::invokeMethod(this, "fileOpenDialog", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(QString, result), + Q_ARG(QString, caption), + Q_ARG(QString, dir), + Q_ARG(QString, filter), + Q_ARG(QString*, selectedFilter), + Q_ARG(QFileDialog::Options, options)); + return result; + } + + // FIXME support returning the selected filter... somehow? + QVariantMap map; + map.insert("caption", caption); + map.insert("dir", QUrl::fromLocalFile(dir)); + map.insert("filter", filter); + map.insert("options", static_cast(options)); + + QVariant buildDialogResult; + bool invokeResult = QMetaObject::invokeMethod(_desktop, "fileOpenDialog", + Q_RETURN_ARG(QVariant, buildDialogResult), + Q_ARG(QVariant, QVariant::fromValue(map))); + + if (!invokeResult) { + qWarning() << "Failed to create file open dialog"; + return QString(); + } + + QVariant result = FileDialogListener(qvariant_cast(buildDialogResult)).waitForResult(); + if (!result.isValid()) { + return QString(); + } + qDebug() << result.toString(); + return result.toUrl().toLocalFile(); +} + +QString OffscreenUi::getOpenFileName(void* ignored, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options) { + return DependencyManager::get()->fileOpenDialog(caption, dir, filter, selectedFilter, options); +} + + #include "OffscreenUi.moc" diff --git a/libraries/ui/src/OffscreenUi.h b/libraries/ui/src/OffscreenUi.h index 73307b38f7..8ad6641e06 100644 --- a/libraries/ui/src/OffscreenUi.h +++ b/libraries/ui/src/OffscreenUi.h @@ -82,11 +82,11 @@ public: Q_INVOKABLE QMessageBox::StandardButton messageBox(QMessageBox::Icon icon, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton); Q_INVOKABLE QVariant inputDialog(const QString& query, const QString& placeholderText = QString(), const QString& currentValue = QString()); + Q_INVOKABLE QString fileOpenDialog(const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = 0, QFileDialog::Options options = 0); // FIXME implement static QVariant query(const QString& query, const QString& placeholderText = QString(), const QString& currentValue = QString()); - // FIXME implement // Compatibility with QFileDialog::getOpenFileName static QString getOpenFileName(void* ignored, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = 0, QFileDialog::Options options = 0);