diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml index f505d9fc50c..a1627fb874a 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml @@ -27,7 +27,9 @@ import QtQuick 2.1 import HelperWidgets 2.0 import StudioControls 1.0 as StudioControls import StudioTheme 1.0 as StudioTheme +import QtQuickDesignerTheme 1.0 import QtQuick.Layouts 1.0 +import QtQuick.Controls 2.5 RowLayout { id: urlChooser @@ -50,6 +52,58 @@ RowLayout { StudioControls.ComboBox { id: comboBox + // Note: highlightedIndex property isn't used because it has no setter and it doesn't reset + // when the combobox is closed by focusing on some other control. + property int hoverIndex: -1 + + ToolTip { + visible: comboBox.hovered + text: urlChooser.backendValue.valueToString + delay: 1000 + } + + delegate: ItemDelegate { + id: delegateItem + width: parent.width + height: 20 + highlighted: comboBox.hoverIndex === index + + indicator: Label { // selected item check mark + padding: 5 + y: (parent.height - height) / 2 + text: StudioTheme.Constants.tickIcon + font.pixelSize: 10 + font.family: StudioTheme.Constants.iconFont.family + color: Theme.color(comboBox.hoverIndex === index ? Theme.PanelTextColorLight + : Theme.QmlDesigner_HighlightColor) + visible: comboBox.currentIndex === index + } + + contentItem: Label { + leftPadding: 10 + text: modelData + anchors.top: parent.top + color: Theme.color(Theme.PanelTextColorLight) + font.pixelSize: 13 + } + + background: Rectangle { + anchors.fill: parent + color: parent.highlighted ? Theme.color(Theme.QmlDesigner_HighlightColor) : "transparent" + } + + ToolTip { + visible: delegateItem.hovered && comboBox.highlightedIndex === index + text: fileModel.fullPathModel[index] + delay: 1000 + } + + onHoveredChanged: { + if (hovered) + comboBox.hoverIndex = index + } + } + actionIndicator.icon.color: extFuncLogic.color actionIndicator.icon.text: extFuncLogic.glyph actionIndicator.onClicked: extFuncLogic.show() @@ -78,7 +132,9 @@ RowLayout { if (urlChooser.backendValue.isBound) return urlChooser.backendValue.expression - return urlChooser.backendValue.valueToString + var fullPath = urlChooser.backendValue.valueToString; + var fileName = fullPath.substr(fullPath.lastIndexOf('/') + 1); + return fileName; } onTextValueChanged: comboBox.setCurrentText(comboBox.textValue) @@ -87,7 +143,7 @@ RowLayout { editable: true - model: fileModel.fileModel + model: fileModel.fileNameModel onModelChanged: { if (!comboBox.isComplete) @@ -115,19 +171,17 @@ RowLayout { function handleActivate(index) { - var cText = comboBox.textAt(index) - - if (index === -1) - cText = comboBox.editText - if (urlChooser.backendValue === undefined) return if (!comboBox.isComplete) return - if (urlChooser.backendValue.value !== cText) - urlChooser.backendValue.value = cText + if (index === -1) // select first item if index is invalid + index = 0 + + if (urlChooser.backendValue.value !== fileModel.fullPathModel[index]) + urlChooser.backendValue.value = fileModel.fullPathModel[index] comboBox.dirty = false } @@ -145,13 +199,29 @@ RowLayout { } } + Connections { + target: comboBox + function onStateChanged(state) + { + // update currentIndex when the popup opens to override the default behavior in super classes + // that selects currentIndex based on values in the combo box. + if (comboBox.popup.opened) { + var index = fileModel.fullPathModel.indexOf(urlChooser.backendValue.value) + if (index !== -1) { + comboBox.currentIndex = index + comboBox.hoverIndex = index + } + } + } + } + StudioControls.AbstractButton { buttonIcon: StudioTheme.Constants.addFile iconColor: urlChooser.textColor onClicked: { fileModel.openFileDialog() - if (fileModel.fileName !== "") - urlChooser.backendValue.value = fileModel.fileName + if (fileModel.path !== "") + urlChooser.backendValue.value = fileModel.path } } } diff --git a/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.cpp b/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.cpp index 63f17f284a7..a42db492d9e 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.cpp @@ -42,8 +42,7 @@ FileResourcesModel::FileResourcesModel(QObject *parent) : void FileResourcesModel::setModelNodeBackend(const QVariant &modelNodeBackend) { - - auto modelNodeBackendObject = modelNodeBackend.value(); + auto modelNodeBackendObject = modelNodeBackend.value(); const auto backendObjectCasted = qobject_cast(modelNodeBackendObject); @@ -64,6 +63,7 @@ void FileResourcesModel::setFileNameStr(const QString &fileName) { setFileName(QUrl(fileName)); } + void FileResourcesModel::setFileName(const QUrl &fileName) { if (fileName == m_fileName) @@ -103,26 +103,25 @@ QString FileResourcesModel::filter() const return m_filter; } -QStringList FileResourcesModel::fileModel() const +QStringList FileResourcesModel::fullPathModel() const { - if (m_model.isEmpty()) - return QStringList(QString()); + return m_fullPathModel; +} - return m_model; +QStringList FileResourcesModel::fileNameModel() const +{ + return m_fileNameModel; } void FileResourcesModel::openFileDialog() { - QString modelPath; - - modelPath = m_path.toLocalFile(); + QString modelPath = m_path.toLocalFile(); m_lastModelPath = modelPath; bool documentChanged = m_lastModelPath == modelPath; - //First we try the last path this browser widget was opened with - //if the document was not changed + //First we try the last path this browser widget was opened with if the document was not changed QString path = documentChanged ? QString() : m_currentPath; @@ -154,7 +153,7 @@ void FileResourcesModel::openFileDialog() void FileResourcesModel::registerDeclarativeType() { - qmlRegisterType("HelperWidgets",2,0,"FileResourcesModel"); + qmlRegisterType("HelperWidgets", 2, 0, "FileResourcesModel"); } QVariant FileResourcesModel::modelNodeBackend() const @@ -167,8 +166,7 @@ bool filterMetaIcons(const QString &fileName) QFileInfo info(fileName); - if (info.dir().path().split("/").contains("designer")) { - + if (info.dir().path().split('/').contains("designer")) { QDir currentDir = info.dir(); int i = 0; @@ -192,7 +190,8 @@ bool filterMetaIcons(const QString &fileName) void FileResourcesModel::setupModel() { m_lock = true; - m_model.clear(); + m_fullPathModel.clear(); + m_fileNameModel.clear(); m_dirPath = QFileInfo(m_path.toLocalFile()).dir(); @@ -201,11 +200,15 @@ void FileResourcesModel::setupModel() QDirIterator it(m_dirPath.absolutePath(), filterList, QDir::Files, QDirIterator::Subdirectories); while (it.hasNext()) { QString absolutePath = it.next(); - if (filterMetaIcons(absolutePath)) - m_model.append(m_dirPath.relativeFilePath(absolutePath)); + if (filterMetaIcons(absolutePath)) { + QString filePath = m_dirPath.relativeFilePath(absolutePath); + m_fullPathModel.append(filePath); + m_fileNameModel.append(filePath.mid(filePath.lastIndexOf('/') + 1)); + } } m_lock = false; - emit fileModelChanged(); + emit fullPathModelChanged(); + emit fileNameModelChanged(); } diff --git a/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.h b/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.h index dc124b5739e..e0a19643479 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.h +++ b/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.h @@ -42,7 +42,8 @@ class FileResourcesModel : public QObject Q_PROPERTY(QVariant modelNodeBackendProperty READ modelNodeBackend WRITE setModelNodeBackend NOTIFY modelNodeBackendChanged) Q_PROPERTY(QUrl path READ path WRITE setPath) Q_PROPERTY(QUrl dirPath READ dirPath) - Q_PROPERTY(QStringList fileModel READ fileModel NOTIFY fileModelChanged) + Q_PROPERTY(QStringList fullPathModel READ fullPathModel NOTIFY fullPathModelChanged) + Q_PROPERTY(QStringList fileNameModel READ fileNameModel NOTIFY fileNameModelChanged) public: explicit FileResourcesModel(QObject *parent = nullptr); @@ -56,7 +57,8 @@ public: QUrl dirPath() const; void setFilter(const QString &filter); QString filter() const; - QStringList fileModel() const; + QStringList fullPathModel() const; + QStringList fileNameModel() const; void setupModel(); Q_INVOKABLE void openFileDialog(); @@ -66,7 +68,8 @@ public: signals: void fileNameChanged(const QUrl &fileName); void modelNodeBackendChanged(); - void fileModelChanged(); + void fullPathModelChanged(); + void fileNameModelChanged(); private: QVariant modelNodeBackend() const; @@ -79,7 +82,8 @@ private: bool m_lock; QString m_currentPath; QString m_lastModelPath; - QStringList m_model; + QStringList m_fullPathModel; + QStringList m_fileNameModel; };