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);