diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp index 5292c2f1999..d4528893637 100644 --- a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp +++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp @@ -58,6 +58,7 @@ #include #include #include +#include #include @@ -241,6 +242,56 @@ ModelNodePreviewImageOperation DesignerActionManager::modelNodePreviewOperation( return op; } +bool DesignerActionManager::externalDragHasSupportedAssets(const QMimeData *mimeData) const +{ + if (!mimeData->hasUrls()) + return false; + + QSet filtersSet; + const QList handlers = addResourceHandler(); + for (const AddResourceHandler &handler : handlers) + filtersSet.insert(handler.filter); + + const QList urls = mimeData->urls(); + for (const QUrl &url : urls) { + QString suffix = "*." + url.fileName().split('.').last().toLower(); + if (filtersSet.contains(suffix)) // accept drop if it contains a valid file + return true; + } + + return false; +} + +void DesignerActionManager::handleExternalAssetsDrop(const QMimeData *mimeData) const +{ + const QList handlers = addResourceHandler(); + // create suffix to categry and category to operation hashes + QHash suffixCategory; + QHash categoryOperation; + for (const AddResourceHandler &handler : handlers) { + suffixCategory.insert(handler.filter, handler.category); + categoryOperation.insert(handler.category, handler.operation); + } + + // add files grouped by categories (so that files under same category run under 1 operation) + QHash categoryFiles; + const QList urls = mimeData->urls(); + for (const QUrl &url : urls) { + QString suffix = "*." + url.fileName().split('.').last().toLower(); + QString category = suffixCategory.value(suffix); + if (!category.isEmpty()) + categoryFiles[category].append(url.toLocalFile()); + } + + // run operations + const QStringList categories = categoryFiles.keys(); + for (const QString &category : categories) { + AddResourceOperation operation = categoryOperation.value(category); + QStringList files = categoryFiles.value(category); + operation(files, {}); + } +} + class VisiblityModelNodeAction : public ModelNodeContextMenuAction { public: diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h index 36253fc4453..e0fe93f601d 100644 --- a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h +++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h @@ -38,6 +38,7 @@ QT_BEGIN_NAMESPACE class QGraphicsItem; class QGraphicsWidget; +class QMimeData; QT_END_NAMESPACE namespace QmlDesigner { @@ -135,6 +136,8 @@ public: void registerModelNodePreviewHandler(const ModelNodePreviewImageHandler &handler); bool hasModelNodePreviewHandler(const ModelNode &node) const; ModelNodePreviewImageOperation modelNodePreviewOperation(const ModelNode &node) const; + bool externalDragHasSupportedAssets(const QMimeData *data) const; + void handleExternalAssetsDrop(const QMimeData *data) const; private: void addTransitionEffectAction(const TypeName &typeName); diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp index ec8a1a69d9b..025b6227893 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp @@ -40,6 +40,7 @@ #include #include +#include #include namespace QmlDesigner { @@ -47,6 +48,8 @@ namespace QmlDesigner { Edit3DWidget::Edit3DWidget(Edit3DView *view) : m_view(view) { + setAcceptDrops(true); + Core::Context context(Constants::C_QMLEDITOR3D); m_context = new Core::IContext(this); m_context->setContext(context); @@ -159,4 +162,19 @@ Edit3DView *Edit3DWidget::view() const return m_view.data(); } +void Edit3DWidget::dragEnterEvent(QDragEnterEvent *dragEnterEvent) +{ + const DesignerActionManager &actionManager = QmlDesignerPlugin::instance() + ->viewManager().designerActionManager(); + if (actionManager.externalDragHasSupportedAssets(dragEnterEvent->mimeData())) + dragEnterEvent->acceptProposedAction(); } + +void Edit3DWidget::dropEvent(QDropEvent *dropEvent) +{ + const DesignerActionManager &actionManager = QmlDesignerPlugin::instance() + ->viewManager().designerActionManager(); + actionManager.handleExternalAssetsDrop(dropEvent->mimeData()); +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h index ca44a955f5e..e7223ceb8c9 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h +++ b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h @@ -48,6 +48,10 @@ public: void showCanvas(bool show); +protected: + void dragEnterEvent(QDragEnterEvent *dragEnterEvent) override; + void dropEvent(QDropEvent *dropEvent) override; + private: void linkActivated(const QString &link); diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp index b6716939f96..1f9fc4487b6 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp +++ b/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp @@ -53,6 +53,7 @@ #include #include +#include #include #include #include @@ -63,6 +64,8 @@ namespace QmlDesigner { FormEditorWidget::FormEditorWidget(FormEditorView *view) : m_formEditorView(view) { + setAcceptDrops(true); + Core::Context context(Constants::C_QMLFORMEDITOR); m_context = new Core::IContext(this); m_context->setContext(context); @@ -582,4 +585,19 @@ void FormEditorWidget::showEvent(QShowEvent *event) } } +void FormEditorWidget::dragEnterEvent(QDragEnterEvent *dragEnterEvent) +{ + const DesignerActionManager &actionManager = QmlDesignerPlugin::instance() + ->viewManager().designerActionManager(); + if (actionManager.externalDragHasSupportedAssets(dragEnterEvent->mimeData())) + dragEnterEvent->acceptProposedAction(); +} + +void FormEditorWidget::dropEvent(QDropEvent *dropEvent) +{ + const DesignerActionManager &actionManager = QmlDesignerPlugin::instance() + ->viewManager().designerActionManager(); + actionManager.handleExternalAssetsDrop(dropEvent->mimeData()); +} + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorwidget.h b/src/plugins/qmldesigner/components/formeditor/formeditorwidget.h index d0c1fa7c5ee..64b1e1a4eeb 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorwidget.h +++ b/src/plugins/qmldesigner/components/formeditor/formeditorwidget.h @@ -49,6 +49,7 @@ class QmlItemNode; class FormEditorWidget : public QWidget { Q_OBJECT + public: FormEditorWidget(FormEditorView *view); @@ -93,6 +94,8 @@ protected: DocumentWarningWidget *errorWidget(); void hideEvent(QHideEvent *event) override; void showEvent(QShowEvent *event) override; + void dragEnterEvent(QDragEnterEvent *dragEnterEvent) override; + void dropEvent(QDropEvent *dropEvent) override; private: void changeTransformTool(bool checked); diff --git a/src/plugins/qmldesigner/components/navigator/navigatorwidget.cpp b/src/plugins/qmldesigner/components/navigator/navigatorwidget.cpp index 453865966be..4e77b7d4b1d 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatorwidget.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatorwidget.cpp @@ -49,6 +49,8 @@ NavigatorWidget::NavigatorWidget(NavigatorView *view) : m_treeView(new NavigatorTreeView) , m_navigatorView(view) { + setAcceptDrops(true); + m_treeView->setDragEnabled(true); m_treeView->setAcceptDrops(true); m_treeView->setSelectionMode(QAbstractItemView::ExtendedSelection); @@ -184,4 +186,19 @@ NavigatorView *NavigatorWidget::navigatorView() const return m_navigatorView.data(); } +void NavigatorWidget::dragEnterEvent(QDragEnterEvent *dragEnterEvent) +{ + const DesignerActionManager &actionManager = QmlDesignerPlugin::instance() + ->viewManager().designerActionManager(); + if (actionManager.externalDragHasSupportedAssets(dragEnterEvent->mimeData())) + dragEnterEvent->acceptProposedAction(); +} + +void NavigatorWidget::dropEvent(QDropEvent *dropEvent) +{ + const DesignerActionManager &actionManager = QmlDesignerPlugin::instance() + ->viewManager().designerActionManager(); + actionManager.handleExternalAssetsDrop(dropEvent->mimeData()); +} + } diff --git a/src/plugins/qmldesigner/components/navigator/navigatorwidget.h b/src/plugins/qmldesigner/components/navigator/navigatorwidget.h index 9c1c962c435..d8dc0938566 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatorwidget.h +++ b/src/plugins/qmldesigner/components/navigator/navigatorwidget.h @@ -43,6 +43,7 @@ class NavigatorView; class NavigatorWidget: public QFrame { Q_OBJECT + public: NavigatorWidget(NavigatorView *view); @@ -63,10 +64,13 @@ signals: void filterToggled(bool); void reverseOrderToggled(bool); -private: // functions +protected: + void dragEnterEvent(QDragEnterEvent *dragEnterEvent) override; + void dropEvent(QDropEvent *dropEvent) override; + +private: NavigatorView *navigatorView() const; -private: // variables NavigatorTreeView *m_treeView; QPointer m_navigatorView; }; diff --git a/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp b/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp index b8747f7102d..6f45bbb5636 100644 --- a/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp +++ b/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp @@ -53,6 +53,8 @@ TextEditorWidget::TextEditorWidget(TextEditorView *textEditorView) , m_textEditorView(textEditorView) , m_statusBar(new TextEditorStatusBar(this)) { + setAcceptDrops(true); + QBoxLayout *layout = new QVBoxLayout(this); layout->setContentsMargins(0, 0, 0, 0); layout->setSpacing(0); @@ -179,7 +181,7 @@ void TextEditorWidget::setBlockCursorSelectionSynchronisation(bool b) m_blockCursorSelectionSynchronisation = b; } -bool TextEditorWidget::eventFilter( QObject *, QEvent *event) +bool TextEditorWidget::eventFilter(QObject *, QEvent *event) { static std::vector overrideKeys = { Qt::Key_Delete, Qt::Key_Backspace, Qt::Key_Insert, Qt::Key_Escape }; @@ -216,5 +218,19 @@ bool TextEditorWidget::eventFilter( QObject *, QEvent *event) return false; } +void TextEditorWidget::dragEnterEvent(QDragEnterEvent *dragEnterEvent) +{ + const DesignerActionManager &actionManager = QmlDesignerPlugin::instance() + ->viewManager().designerActionManager(); + if (actionManager.externalDragHasSupportedAssets(dragEnterEvent->mimeData())) + dragEnterEvent->acceptProposedAction(); +} + +void TextEditorWidget::dropEvent(QDropEvent *dropEvent) +{ + const DesignerActionManager &actionManager = QmlDesignerPlugin::instance() + ->viewManager().designerActionManager(); + actionManager.handleExternalAssetsDrop(dropEvent->mimeData()); +} } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/texteditor/texteditorwidget.h b/src/plugins/qmldesigner/components/texteditor/texteditorwidget.h index 8f0ba40e47f..96a8361069f 100644 --- a/src/plugins/qmldesigner/components/texteditor/texteditorwidget.h +++ b/src/plugins/qmldesigner/components/texteditor/texteditorwidget.h @@ -63,6 +63,8 @@ public: protected: bool eventFilter(QObject *object, QEvent *event) override; + void dragEnterEvent(QDragEnterEvent *dragEnterEvent) override; + void dropEvent(QDropEvent *dropEvent) override; private: void updateSelectionByCursorPosition();