From dfeff5b30d8b8c99dbe0f2d66cda99132e42fafa Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Tue, 2 Mar 2021 17:15:59 +0200 Subject: [PATCH] QmlDesigner: Search also possible imports in item library Possible imports are now also parsed for items in item library. They are only shown in case the search string is not empty. Starting a drag of unimported item will automatically add the import. Added a small manhattanlength check to the start of the drag to avoid unwanted import additions on clicks. Also fixed the item sorting to alphabetical order within categories. Task-number: QDS-3825 Change-Id: I93366182af3fd7eda38bf94d53807393ecf92a08 Reviewed-by: Thomas Hartmann Reviewed-by: Mahmoud Badri --- .../itemLibraryQmlSources/ItemDelegate.qml | 8 ++- .../itemLibraryQmlSources/ItemsView.qml | 35 ++++++++-- .../HelperWidgets/ImagePreviewTooltipArea.qml | 9 ++- .../components/integration/designdocument.cpp | 3 +- .../itemlibrarycategoriesmodel.cpp | 3 + .../itemlibrary/itemlibrarycategory.cpp | 2 + .../itemlibrary/itemlibraryimport.cpp | 66 +++++++++++++++---- .../itemlibrary/itemlibraryimport.h | 20 +++++- .../itemlibrary/itemlibraryitem.cpp | 17 ++++- .../components/itemlibrary/itemlibraryitem.h | 7 +- .../itemlibrary/itemlibraryitemsmodel.cpp | 2 +- .../itemlibrary/itemlibrarymodel.cpp | 65 +++++++++++------- .../components/itemlibrary/itemlibrarymodel.h | 2 + .../itemlibrary/itemlibrarywidget.cpp | 47 ++++++++++--- .../itemlibrary/itemlibrarywidget.h | 5 +- 15 files changed, 228 insertions(+), 63 deletions(-) diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml index f7cf00d92c3..045398205db 100644 --- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml +++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml @@ -29,6 +29,9 @@ import QtQuickDesignerTheme 1.0 import HelperWidgets 2.0 Item { + id: delegateRoot + signal showContextMenu() + Rectangle { anchors.rightMargin: 1 anchors.topMargin: 1 @@ -71,11 +74,12 @@ Item { ImagePreviewTooltipArea { id: mouseRegion - anchors.fill: parent + onShowContextMenu: delegateRoot.showContextMenu() onPressed: { - rootView.startDragAndDrop(itemLibraryEntry) + if (mouse.button === Qt.LeftButton) + rootView.startDragAndDrop(itemLibraryEntry, mapToGlobal(mouse.x, mouse.y)) } } } diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml index 2f792372331..a93bc173a81 100644 --- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml +++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml @@ -77,11 +77,14 @@ ScrollView { id: itemsView property string importToRemove: "" + property string importToAdd: "" + property var currentItem: null // called from C++ to close context menu on focus out function closeContextMenu() { - contextMenu.close() + importContextMenu.close() + itemContextMenu.close() } Item { @@ -99,11 +102,11 @@ ScrollView { 2 * cellVerticalMargin + cellVerticalSpacing StudioControls.Menu { - id: contextMenu + id: importContextMenu StudioControls.MenuItem { text: qsTr("Remove Module") - enabled: importToRemove !== "" && importToRemove !== "QtQuick" + enabled: importToRemove !== "" onTriggered: rootView.removeImport(importToRemove) } @@ -119,6 +122,19 @@ ScrollView { onTriggered: itemLibraryModel.collapseAll() } } + + StudioControls.Menu { + id: itemContextMenu + // Workaround for menu item implicit width not properly propagating to menu + width: importMenuItem.implicitWidth + + StudioControls.MenuItem { + id: importMenuItem + text: qsTr("Import Module: ") + importToAdd + enabled: currentItem + onTriggered: rootView.addImportForItem(currentItem) + } + } } Column { @@ -144,8 +160,8 @@ ScrollView { importExpanded = !importExpanded } onShowContextMenu: { - importToRemove = importUsed ? "" : importUrl - contextMenu.popup() + importToRemove = importRemovable ? importUrl : "" + importContextMenu.popup() } Column { @@ -180,6 +196,15 @@ ScrollView { visible: itemVisible width: styleConstants.cellWidth + itemGrid.flexibleWidth height: styleConstants.cellHeight + onShowContextMenu: { + if (!itemUsable) { + importToAdd = itemRequiredImport + if (importToAdd !== "") { + currentItem = itemLibraryEntry + itemContextMenu.popup() + } + } + } } } } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ImagePreviewTooltipArea.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ImagePreviewTooltipArea.qml index 5921bf50520..0f2f5b69b9e 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ImagePreviewTooltipArea.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ImagePreviewTooltipArea.qml @@ -30,12 +30,19 @@ import QtQuick.Layouts 1.0 MouseArea { id: mouseArea + signal showContextMenu() + onExited: tooltipBackend.hideTooltip() onCanceled: tooltipBackend.hideTooltip() - onClicked: forceActiveFocus() onPositionChanged: tooltipBackend.reposition() + onClicked: { + forceActiveFocus() + if (mouse.button === Qt.RightButton) + showContextMenu() + } hoverEnabled: true + acceptedButtons: Qt.LeftButton | Qt.RightButton Timer { interval: 1000 diff --git a/src/plugins/qmldesigner/components/integration/designdocument.cpp b/src/plugins/qmldesigner/components/integration/designdocument.cpp index ae4b09bdc41..c626f4baa59 100644 --- a/src/plugins/qmldesigner/components/integration/designdocument.cpp +++ b/src/plugins/qmldesigner/components/integration/designdocument.cpp @@ -370,7 +370,8 @@ void DesignDocument::close() void DesignDocument::updateSubcomponentManager() { Q_ASSERT(m_subComponentManager); - m_subComponentManager->update(QUrl::fromLocalFile(fileName().toString()), currentModel()->imports()); + m_subComponentManager->update(QUrl::fromLocalFile(fileName().toString()), + currentModel()->imports() + currentModel()->possibleImports()); } void DesignDocument::deleteSelected() diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.cpp index 1845c025400..1cc032090e2 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.cpp @@ -127,6 +127,9 @@ void ItemLibraryCategoriesModel::sortCategorySections() }; std::sort(m_categoryList.begin(), m_categoryList.end(), categorySort); + + for (const auto &category : qAsConst(m_categoryList)) + category->sortItems(); } void ItemLibraryCategoriesModel::resetModel() diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.cpp index 1662b0ce966..55ef88a97c6 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.cpp @@ -70,6 +70,8 @@ bool ItemLibraryCategory::updateItemVisibility(const QString &searchText, bool * bool itemVisible = item->itemName().toLower().contains(searchText) || item->typeName().toLower().contains(searchText); + if (searchText.isEmpty() && !item->isUsable()) + itemVisible = false; bool itemChanged = item->setVisible(itemVisible); *changed |= itemChanged; diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.cpp index f2f22b1b74f..649d879895d 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.cpp @@ -28,18 +28,22 @@ namespace QmlDesigner { -ItemLibraryImport::ItemLibraryImport(const Import &import, QObject *parent, bool isUserSection) +ItemLibraryImport::ItemLibraryImport(const Import &import, QObject *parent, SectionType sectionType) : QObject(parent), m_import(import), - m_isUserSection(isUserSection) + m_sectionType(sectionType) { + updateRemovable(); } QString ItemLibraryImport::importName() const { - if (m_isUserSection) + if (m_sectionType == SectionType::User) return userComponentsTitle(); + if (m_sectionType == SectionType::Unimported) + return unimportedComponentsTitle(); + if (importUrl() == "QtQuick") return tr("Default Components"); @@ -48,9 +52,12 @@ QString ItemLibraryImport::importName() const QString ItemLibraryImport::importUrl() const { - if (m_isUserSection) + if (m_sectionType == SectionType::User) return userComponentsTitle(); + if (m_sectionType == SectionType::Unimported) + return unimportedComponentsTitle(); + return m_import.url(); } @@ -61,11 +68,14 @@ bool ItemLibraryImport::importExpanded() const QString ItemLibraryImport::sortingName() const { - if (m_isUserSection) // user components always come first - return "_"; + if (m_sectionType == SectionType::User) + return "_"; // user components always come first + + if (m_sectionType == SectionType::Unimported) + return "zzzzzz"; // Unimported components always come last if (!hasCategories()) // imports with no categories are at the bottom of the list - return "zzzzz" + importName(); + return "zzzzz_" + importName(); return importName(); } @@ -113,6 +123,7 @@ bool ItemLibraryImport::setVisible(bool isVisible) { if (isVisible != m_isVisible) { m_isVisible = isVisible; + emit importVisibleChanged(); return true; } @@ -126,7 +137,11 @@ bool ItemLibraryImport::importVisible() const void ItemLibraryImport::setImportUsed(bool importUsed) { - m_importUsed = importUsed; + if (importUsed != m_importUsed) { + m_importUsed = importUsed; + updateRemovable(); + emit importUsedChanged(); + } } bool ItemLibraryImport::importUsed() const @@ -134,6 +149,11 @@ bool ItemLibraryImport::importUsed() const return m_importUsed; } +bool ItemLibraryImport::importRemovable() const +{ + return m_importRemovable; +} + bool ItemLibraryImport::hasCategories() const { return m_categoryModel.rowCount() > 0; @@ -146,7 +166,10 @@ void ItemLibraryImport::sortCategorySections() void ItemLibraryImport::setImportExpanded(bool expanded) { - m_importExpanded = expanded; + if (expanded != m_importExpanded) { + m_importExpanded = expanded; + emit importExpandChanged(); + } } ItemLibraryCategory *ItemLibraryImport::getCategorySection(const QString &categoryName) const @@ -159,15 +182,30 @@ ItemLibraryCategory *ItemLibraryImport::getCategorySection(const QString &catego return nullptr; } -bool ItemLibraryImport::isUserSection() const -{ - return m_isUserSection; -} - // static QString ItemLibraryImport::userComponentsTitle() { return tr("My Components"); } +QString ItemLibraryImport::unimportedComponentsTitle() +{ + return tr("All Other Components"); +} + +ItemLibraryImport::SectionType ItemLibraryImport::sectionType() const +{ + return m_sectionType; +} + +void ItemLibraryImport::updateRemovable() +{ + bool importRemovable = !m_importUsed && m_sectionType == SectionType::Default + && m_import.url() != "QtQuick"; + if (importRemovable != m_importRemovable) { + m_importRemovable = importRemovable; + emit importRemovableChanged(); + } +} + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.h index c922e984084..8993dfcb8b6 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.h @@ -41,10 +41,18 @@ class ItemLibraryImport : public QObject Q_PROPERTY(bool importVisible READ importVisible NOTIFY importVisibleChanged FINAL) Q_PROPERTY(bool importUsed READ importUsed NOTIFY importUsedChanged FINAL) Q_PROPERTY(bool importExpanded READ importExpanded WRITE setImportExpanded NOTIFY importExpandChanged FINAL) + Q_PROPERTY(bool importRemovable READ importRemovable NOTIFY importRemovableChanged FINAL) Q_PROPERTY(QObject *categoryModel READ categoryModel NOTIFY categoryModelChanged FINAL) public: - ItemLibraryImport(const Import &import, QObject *parent = nullptr, bool isUserSection = false); + enum class SectionType { + Default, + User, + Unimported + }; + + ItemLibraryImport(const Import &import, QObject *parent = nullptr, + SectionType sectionType = SectionType::Default); QString importName() const; QString importUrl() const; @@ -53,6 +61,7 @@ public: Import importEntry() const; bool importVisible() const; bool importUsed() const; + bool importRemovable() const; bool hasCategories() const; ItemLibraryCategory *getCategorySection(const QString &categoryName) const; @@ -66,21 +75,26 @@ public: void expandCategories(bool expand = true); static QString userComponentsTitle(); + static QString unimportedComponentsTitle(); - bool isUserSection() const; + SectionType sectionType() const; signals: void categoryModelChanged(); void importVisibleChanged(); void importUsedChanged(); void importExpandChanged(); + void importRemovableChanged(); private: + void updateRemovable(); + Import m_import; bool m_importExpanded = true; bool m_isVisible = true; bool m_importUsed = false; - bool m_isUserSection = false; // user components import section + bool m_importRemovable = false; + SectionType m_sectionType = SectionType::Default; ItemLibraryCategoriesModel m_categoryModel; }; diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitem.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitem.cpp index 31d5edb57cf..78e06f0b56b 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitem.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitem.cpp @@ -27,9 +27,10 @@ namespace QmlDesigner { -ItemLibraryItem::ItemLibraryItem(const ItemLibraryEntry &itemLibraryEntry, QObject *parent) - : QObject(parent), - m_itemLibraryEntry(itemLibraryEntry) +ItemLibraryItem::ItemLibraryItem(const ItemLibraryEntry &itemLibraryEntry, bool isUsable, QObject *parent) + : QObject(parent) + , m_itemLibraryEntry(itemLibraryEntry) + , m_isUsable(isUsable) { } @@ -61,6 +62,11 @@ QString ItemLibraryItem::componentPath() const return m_itemLibraryEntry.customComponentSource(); } +QString ItemLibraryItem::requiredImport() const +{ + return m_itemLibraryEntry.requiredImport(); +} + bool ItemLibraryItem::setVisible(bool isVisible) { if (isVisible != m_isVisible) { @@ -77,6 +83,11 @@ bool ItemLibraryItem::isVisible() const return m_isVisible; } +bool ItemLibraryItem::isUsable() const +{ + return m_isUsable; +} + QVariant ItemLibraryItem::itemLibraryEntry() const { return QVariant::fromValue(m_itemLibraryEntry); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitem.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitem.h index d7321b11794..564a2a9aa54 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitem.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitem.h @@ -43,18 +43,22 @@ class ItemLibraryItem: public QObject Q_PROPERTY(QString itemLibraryIconPath READ itemLibraryIconPath FINAL) Q_PROPERTY(bool itemVisible READ isVisible NOTIFY visibilityChanged FINAL) Q_PROPERTY(QString componentPath READ componentPath FINAL) + Q_PROPERTY(bool itemUsable READ isUsable FINAL) + Q_PROPERTY(QString itemRequiredImport READ requiredImport FINAL) public: - ItemLibraryItem(const ItemLibraryEntry &itemLibraryEntry, QObject *parent); + ItemLibraryItem(const ItemLibraryEntry &itemLibraryEntry, bool isImported, QObject *parent); ~ItemLibraryItem() override; QString itemName() const; QString typeName() const; QString itemLibraryIconPath() const; QString componentPath() const; + QString requiredImport() const; bool setVisible(bool isVisible); bool isVisible() const; + bool isUsable() const; QVariant itemLibraryEntry() const; @@ -64,6 +68,7 @@ signals: private: ItemLibraryEntry m_itemLibraryEntry; bool m_isVisible = true; + bool m_isUsable = false; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitemsmodel.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitemsmodel.cpp index b9530917241..f4f02d124d6 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitemsmodel.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitemsmodel.cpp @@ -70,7 +70,7 @@ void ItemLibraryItemsModel::addItem(ItemLibraryItem *element) { m_itemList.append(element); - element->setVisible(true); + element->setVisible(element->isUsable()); } const QList> &ItemLibraryItemsModel::items() const diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp index 25bef1edd4b..a11004d2102 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp @@ -167,7 +167,7 @@ void ItemLibraryModel::setSearchText(const QString &searchText) } } -Import entryToImport(const ItemLibraryEntry &entry) +Import ItemLibraryModel::entryToImport(const ItemLibraryEntry &entry) { if (entry.majorVersion() == -1 && entry.minorVersion() == -1) return Import::createFileImport(entry.requiredImport()); @@ -204,46 +204,61 @@ void ItemLibraryModel::update(ItemLibraryInfo *itemLibraryInfo, Model *model) bool valid = metaInfo.isValid() && metaInfo.majorVersion() == entry.majorVersion(); bool isItem = valid && metaInfo.isSubclassOf("QtQuick.Item"); - bool forceVisiblity = valid && NodeHints::fromItemLibraryEntry(entry).visibleInLibrary(); + bool forceVisibility = valid && NodeHints::fromItemLibraryEntry(entry).visibleInLibrary(); if (m_flowMode && metaInfo.isValid()) { isItem = metaInfo.isSubclassOf("FlowView.FlowItem") || metaInfo.isSubclassOf("FlowView.FlowWildcard") || metaInfo.isSubclassOf("FlowView.FlowDecision"); - forceVisiblity = isItem; + forceVisibility = isItem; } + bool blocked = false; const DesignerMcuManager &mcuManager = DesignerMcuManager::instance(); if (mcuManager.isMCUProject()) { const QSet blockTypes = mcuManager.bannedItems(); if (blockTypes.contains(QString::fromUtf8(entry.typeName()))) - valid = false; + blocked = true; } - if (valid && (isItem || forceVisiblity) // We can change if the navigator does support pure QObjects - && (entry.requiredImport().isEmpty() - || model->hasImport(entryToImport(entry), true, true))) { - + Import import = entryToImport(entry); + bool hasImport = model->hasImport(import, true, true); + bool isImportPossible = false; + if (!hasImport) + isImportPossible = model->isImportPossible(import, true, true); + bool isUsable = (valid && (isItem || forceVisibility)) + && (entry.requiredImport().isEmpty() || hasImport); + if (!blocked && (isUsable || isImportPossible)) { ItemLibraryImport *importSection = nullptr; - QString catName = entry.category(); - if (catName == ItemLibraryImport::userComponentsTitle()) { - // create an import section for user components - importSection = importByUrl(ItemLibraryImport::userComponentsTitle()); + if (isUsable) { + if (catName == ItemLibraryImport::userComponentsTitle()) { + // create an import section for user components + importSection = importByUrl(ItemLibraryImport::userComponentsTitle()); + if (!importSection) { + importSection = new ItemLibraryImport( + {}, this, ItemLibraryImport::SectionType::User); + m_importList.append(importSection); + importSection->setImportExpanded(loadExpandedState(catName)); + } + } else { + if (catName.startsWith("Qt Quick - ")) + catName = catName.mid(11); // remove "Qt Quick - " + importSection = importByUrl(entry.requiredImport()); + } + } else { + catName = ItemLibraryImport::unimportedComponentsTitle(); + importSection = importByUrl(catName); if (!importSection) { - importSection = new ItemLibraryImport({}, this, true); + importSection = new ItemLibraryImport( + {}, this, ItemLibraryImport::SectionType::Unimported); m_importList.append(importSection); importSection->setImportExpanded(loadExpandedState(catName)); } - } else { - if (catName.startsWith("Qt Quick - ")) - catName = catName.mid(11); // remove "Qt Quick - " - - importSection = importByUrl(entry.requiredImport()); } - if (!importSection) { // should not happen, but just in case + if (!importSection) { qWarning() << __FUNCTION__ << "No import section found! skipping entry: " << entry.name(); continue; } @@ -253,12 +268,12 @@ void ItemLibraryModel::update(ItemLibraryInfo *itemLibraryInfo, Model *model) if (!categorySection) { categorySection = new ItemLibraryCategory(catName, importSection); importSection->addCategory(categorySection); - if (!importSection->isUserSection()) + if (importSection->sectionType() == ItemLibraryImport::SectionType::Default) categorySection->setExpanded(loadExpandedState(categorySection->categoryName())); } // create item - auto item = new ItemLibraryItem(entry, categorySection); + auto item = new ItemLibraryItem(entry, isUsable, categorySection); categorySection->addItem(item); } } @@ -300,7 +315,9 @@ ItemLibraryImport *ItemLibraryModel::importByUrl(const QString &importUrl) const if (itemLibraryImport->importUrl() == importUrl || (importUrl.isEmpty() && itemLibraryImport->importUrl() == "QtQuick") || (importUrl == ItemLibraryImport::userComponentsTitle() - && itemLibraryImport->isUserSection())) { + && itemLibraryImport->sectionType() == ItemLibraryImport::SectionType::User) + || (importUrl == ItemLibraryImport::unimportedComponentsTitle() + && itemLibraryImport->sectionType() == ItemLibraryImport::SectionType::Unimported)) { return itemLibraryImport; } } @@ -324,9 +341,11 @@ void ItemLibraryModel::updateVisibility(bool *changed) for (ItemLibraryImport *import : std::as_const(m_importList)) { bool categoryChanged = false; bool hasVisibleItems = import->updateCategoryVisibility(m_searchText, &categoryChanged); - *changed |= categoryChanged; + if (import->sectionType() == ItemLibraryImport::SectionType::Unimported) + *changed |= import->setVisible(!m_searchText.isEmpty()); + // expand import if it has an item matching search criteria if (hasVisibleItems && !import->importExpanded()) import->setImportExpanded(); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h index 535bfb014f9..2412550a3a0 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h @@ -69,6 +69,8 @@ public: Q_INVOKABLE void expandAll(); Q_INVOKABLE void collapseAll(); + Import entryToImport(const ItemLibraryEntry &entry); + private: void updateVisibility(bool *changed); void addRoleNames(); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp index 1eb8813bda0..7ce542de024 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp @@ -86,15 +86,35 @@ bool ItemLibraryWidget::eventFilter(QObject *obj, QEvent *event) QMetaObject::invokeMethod(m_itemViewQuickWidget->rootObject(), "closeContextMenu"); } else if (event->type() == QMouseEvent::MouseMove) { if (m_itemToDrag.isValid()) { - ItemLibraryEntry entry = m_itemToDrag.value(); - auto drag = new QDrag(this); - drag->setPixmap(Utils::StyleHelper::dpiSpecificImageFile(entry.libraryEntryIconPath())); - drag->setMimeData(m_itemLibraryModel->getMimeData(entry)); - drag->exec(); - drag->deleteLater(); + QMouseEvent *me = static_cast(event); + if ((me->globalPos() - m_dragStartPoint).manhattanLength() > 10) { + ItemLibraryEntry entry = m_itemToDrag.value(); + // For drag to be handled correctly, we must have the component properly imported + // beforehand, so we import the module immediately when the drag starts + if (!entry.requiredImport().isEmpty()) { + Import import = Import::createLibraryImport(entry.requiredImport()); + if (!m_model->hasImport(import, true, true)) { + const QList possImports = m_model->possibleImports(); + for (const auto &possImport : possImports) { + if (possImport.url() == import.url()) { + m_model->changeImports({possImport}, {}); + break; + } + } + } + } - m_itemToDrag = {}; + auto drag = new QDrag(this); + drag->setPixmap(Utils::StyleHelper::dpiSpecificImageFile(entry.libraryEntryIconPath())); + drag->setMimeData(m_itemLibraryModel->getMimeData(entry)); + drag->exec(); + drag->deleteLater(); + + m_itemToDrag = {}; + } } + } else if (event->type() == QMouseEvent::MouseButtonRelease) { + m_itemToDrag = {}; } return QObject::eventFilter(obj, event); @@ -349,6 +369,7 @@ void ItemLibraryWidget::updateModel() void ItemLibraryWidget::updatePossibleImports(const QList &possibleImports) { m_itemLibraryAddImportModel->update(possibleImports); + delayedUpdateModel(); } void ItemLibraryWidget::updateUsedImports(const QList &usedImports) @@ -387,12 +408,13 @@ void ItemLibraryWidget::setResourcePath(const QString &resourcePath) updateSearch(); } -void ItemLibraryWidget::startDragAndDrop(const QVariant &itemLibEntry) +void ItemLibraryWidget::startDragAndDrop(const QVariant &itemLibEntry, const QPointF &mousePos) { // Actual drag is created after mouse has moved to avoid a QDrag bug that causes drag to stay // active (and blocks mouse release) if mouse is released at the same spot of the drag start. // This doesn't completely eliminate the bug but makes it significantly harder to produce. m_itemToDrag = itemLibEntry; + m_dragStartPoint = mousePos.toPoint(); } void ItemLibraryWidget::setFlowMode(bool b) @@ -409,6 +431,15 @@ void ItemLibraryWidget::removeImport(const QString &importUrl) m_model->changeImports({}, {importSection->importEntry()}); } +void ItemLibraryWidget::addImportForItem(const QVariant &entry) +{ + QTC_ASSERT(m_itemLibraryModel, return); + QTC_ASSERT(m_model, return); + + Import import = m_itemLibraryModel->entryToImport(entry.value()); + m_model->changeImports({import}, {}); +} + void ItemLibraryWidget::addResources(const QStringList &files) { auto document = QmlDesignerPlugin::instance()->currentDesignDocument(); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h index 66d95d0cd4b..0b78c485e58 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h @@ -39,6 +39,7 @@ #include #include #include +#include #include @@ -87,8 +88,9 @@ public: void setModel(Model *model); void setFlowMode(bool b); - Q_INVOKABLE void startDragAndDrop(const QVariant &itemLibEntry); + Q_INVOKABLE void startDragAndDrop(const QVariant &itemLibEntry, const QPointF &mousePos); Q_INVOKABLE void removeImport(const QString &importUrl); + Q_INVOKABLE void addImportForItem(const QVariant &entry); signals: void itemActivated(const QString& itemName); @@ -127,6 +129,7 @@ private: QVariant m_itemToDrag; bool m_updateRetry = false; QString m_filterText; + QPoint m_dragStartPoint; private slots: void handleTabChanged(int index);