QmlDesigner: Allow dropping external assets

External assets can be dropped to Form Editor, 3D Editor, Text Editor, and Navigator.

Fixes: QDS-5045
Change-Id: I2de06ab118350a8d0809b286c16d06e7edea92e4
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Mahmoud Badri
2021-09-30 13:42:48 +03:00
parent a07112258b
commit 9e38e710d3
10 changed files with 139 additions and 3 deletions

View File

@@ -58,6 +58,7 @@
#include <QGraphicsLinearLayout> #include <QGraphicsLinearLayout>
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QMessageBox> #include <QMessageBox>
#include <QMimeData>
#include <exception> #include <exception>
@@ -241,6 +242,56 @@ ModelNodePreviewImageOperation DesignerActionManager::modelNodePreviewOperation(
return op; return op;
} }
bool DesignerActionManager::externalDragHasSupportedAssets(const QMimeData *mimeData) const
{
if (!mimeData->hasUrls())
return false;
QSet<QString> filtersSet;
const QList<AddResourceHandler> handlers = addResourceHandler();
for (const AddResourceHandler &handler : handlers)
filtersSet.insert(handler.filter);
const QList<QUrl> 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<AddResourceHandler> handlers = addResourceHandler();
// create suffix to categry and category to operation hashes
QHash<QString, QString> suffixCategory;
QHash<QString, AddResourceOperation> 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<QString, QStringList> categoryFiles;
const QList<QUrl> 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 class VisiblityModelNodeAction : public ModelNodeContextMenuAction
{ {
public: public:

View File

@@ -38,6 +38,7 @@
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QGraphicsItem; class QGraphicsItem;
class QGraphicsWidget; class QGraphicsWidget;
class QMimeData;
QT_END_NAMESPACE QT_END_NAMESPACE
namespace QmlDesigner { namespace QmlDesigner {
@@ -135,6 +136,8 @@ public:
void registerModelNodePreviewHandler(const ModelNodePreviewImageHandler &handler); void registerModelNodePreviewHandler(const ModelNodePreviewImageHandler &handler);
bool hasModelNodePreviewHandler(const ModelNode &node) const; bool hasModelNodePreviewHandler(const ModelNode &node) const;
ModelNodePreviewImageOperation modelNodePreviewOperation(const ModelNode &node) const; ModelNodePreviewImageOperation modelNodePreviewOperation(const ModelNode &node) const;
bool externalDragHasSupportedAssets(const QMimeData *data) const;
void handleExternalAssetsDrop(const QMimeData *data) const;
private: private:
void addTransitionEffectAction(const TypeName &typeName); void addTransitionEffectAction(const TypeName &typeName);

View File

@@ -40,6 +40,7 @@
#include <utils/utilsicons.h> #include <utils/utilsicons.h>
#include <QActionGroup> #include <QActionGroup>
#include <QMimeData>
#include <QVBoxLayout> #include <QVBoxLayout>
namespace QmlDesigner { namespace QmlDesigner {
@@ -47,6 +48,8 @@ namespace QmlDesigner {
Edit3DWidget::Edit3DWidget(Edit3DView *view) : Edit3DWidget::Edit3DWidget(Edit3DView *view) :
m_view(view) m_view(view)
{ {
setAcceptDrops(true);
Core::Context context(Constants::C_QMLEDITOR3D); Core::Context context(Constants::C_QMLEDITOR3D);
m_context = new Core::IContext(this); m_context = new Core::IContext(this);
m_context->setContext(context); m_context->setContext(context);
@@ -159,4 +162,19 @@ Edit3DView *Edit3DWidget::view() const
return m_view.data(); 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

View File

@@ -48,6 +48,10 @@ public:
void showCanvas(bool show); void showCanvas(bool show);
protected:
void dragEnterEvent(QDragEnterEvent *dragEnterEvent) override;
void dropEvent(QDropEvent *dropEvent) override;
private: private:
void linkActivated(const QString &link); void linkActivated(const QString &link);

View File

@@ -53,6 +53,7 @@
#include <QActionGroup> #include <QActionGroup>
#include <QFileDialog> #include <QFileDialog>
#include <QMimeData>
#include <QPainter> #include <QPainter>
#include <QPicture> #include <QPicture>
#include <QVBoxLayout> #include <QVBoxLayout>
@@ -63,6 +64,8 @@ namespace QmlDesigner {
FormEditorWidget::FormEditorWidget(FormEditorView *view) FormEditorWidget::FormEditorWidget(FormEditorView *view)
: m_formEditorView(view) : m_formEditorView(view)
{ {
setAcceptDrops(true);
Core::Context context(Constants::C_QMLFORMEDITOR); Core::Context context(Constants::C_QMLFORMEDITOR);
m_context = new Core::IContext(this); m_context = new Core::IContext(this);
m_context->setContext(context); 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 } // namespace QmlDesigner

View File

@@ -49,6 +49,7 @@ class QmlItemNode;
class FormEditorWidget : public QWidget class FormEditorWidget : public QWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
FormEditorWidget(FormEditorView *view); FormEditorWidget(FormEditorView *view);
@@ -93,6 +94,8 @@ protected:
DocumentWarningWidget *errorWidget(); DocumentWarningWidget *errorWidget();
void hideEvent(QHideEvent *event) override; void hideEvent(QHideEvent *event) override;
void showEvent(QShowEvent *event) override; void showEvent(QShowEvent *event) override;
void dragEnterEvent(QDragEnterEvent *dragEnterEvent) override;
void dropEvent(QDropEvent *dropEvent) override;
private: private:
void changeTransformTool(bool checked); void changeTransformTool(bool checked);

View File

@@ -49,6 +49,8 @@ NavigatorWidget::NavigatorWidget(NavigatorView *view)
: m_treeView(new NavigatorTreeView) : m_treeView(new NavigatorTreeView)
, m_navigatorView(view) , m_navigatorView(view)
{ {
setAcceptDrops(true);
m_treeView->setDragEnabled(true); m_treeView->setDragEnabled(true);
m_treeView->setAcceptDrops(true); m_treeView->setAcceptDrops(true);
m_treeView->setSelectionMode(QAbstractItemView::ExtendedSelection); m_treeView->setSelectionMode(QAbstractItemView::ExtendedSelection);
@@ -184,4 +186,19 @@ NavigatorView *NavigatorWidget::navigatorView() const
return m_navigatorView.data(); 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());
}
} }

View File

@@ -43,6 +43,7 @@ class NavigatorView;
class NavigatorWidget: public QFrame class NavigatorWidget: public QFrame
{ {
Q_OBJECT Q_OBJECT
public: public:
NavigatorWidget(NavigatorView *view); NavigatorWidget(NavigatorView *view);
@@ -63,10 +64,13 @@ signals:
void filterToggled(bool); void filterToggled(bool);
void reverseOrderToggled(bool); void reverseOrderToggled(bool);
private: // functions protected:
void dragEnterEvent(QDragEnterEvent *dragEnterEvent) override;
void dropEvent(QDropEvent *dropEvent) override;
private:
NavigatorView *navigatorView() const; NavigatorView *navigatorView() const;
private: // variables
NavigatorTreeView *m_treeView; NavigatorTreeView *m_treeView;
QPointer<NavigatorView> m_navigatorView; QPointer<NavigatorView> m_navigatorView;
}; };

View File

@@ -53,6 +53,8 @@ TextEditorWidget::TextEditorWidget(TextEditorView *textEditorView)
, m_textEditorView(textEditorView) , m_textEditorView(textEditorView)
, m_statusBar(new TextEditorStatusBar(this)) , m_statusBar(new TextEditorStatusBar(this))
{ {
setAcceptDrops(true);
QBoxLayout *layout = new QVBoxLayout(this); QBoxLayout *layout = new QVBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0); layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(0); layout->setSpacing(0);
@@ -216,5 +218,19 @@ bool TextEditorWidget::eventFilter( QObject *, QEvent *event)
return false; 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 } // namespace QmlDesigner

View File

@@ -63,6 +63,8 @@ public:
protected: protected:
bool eventFilter(QObject *object, QEvent *event) override; bool eventFilter(QObject *object, QEvent *event) override;
void dragEnterEvent(QDragEnterEvent *dragEnterEvent) override;
void dropEvent(QDropEvent *dropEvent) override;
private: private:
void updateSelectionByCursorPosition(); void updateSelectionByCursorPosition();