diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp index a41ef1c81ce..19538382ca3 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 #include "edit3dwidget.h" +#include "designdocumentview.h" #include "edit3dactions.h" #include "edit3dcanvas.h" #include "edit3dview.h" @@ -11,6 +12,7 @@ #include "qmldesignerconstants.h" #include "qmldesignerplugin.h" #include "qmlvisualnode.h" +#include "timelineactions.h" #include "viewmanager.h" #include @@ -185,6 +187,10 @@ void Edit3DWidget::createContextMenu() QmlDesignerPlugin::instance()->currentDesignDocument()->copySelected(); }); + m_pasteAction = m_contextMenu->addAction(tr("Paste"), [&] { + QmlDesignerPlugin::instance()->currentDesignDocument()->paste(); + }); + m_deleteAction = m_contextMenu->addAction(tr("Delete"), [&] { view()->executeInTransaction("Edit3DWidget::createContextMenu", [&] { for (ModelNode &node : m_view->selectedModelNodes()) @@ -192,7 +198,6 @@ void Edit3DWidget::createContextMenu() }); }); - m_contextMenu->addSeparator(); m_alignCameraAction = m_contextMenu->addAction(tr("Align Camera to View"), [&] { @@ -206,6 +211,38 @@ void Edit3DWidget::createContextMenu() m_contextMenu->addSeparator(); } +bool Edit3DWidget::isPasteAvailable() const +{ + if (TimelineActions::clipboardContainsKeyframes()) + return false; + + auto pasteModel(DesignDocumentView::pasteToModel(view()->externalDependencies())); + if (!pasteModel) + return false; + + DesignDocumentView docView{view()->externalDependencies()}; + pasteModel->attachView(&docView); + auto rootNode = docView.rootModelNode(); + + if (rootNode.type() == "empty") + return false; + + QList allNodes; + if (rootNode.id() == "__multi__selection__") + allNodes << rootNode.directSubModelNodes(); + else + allNodes << rootNode; + + bool hasNon3DNode = std::any_of(allNodes.begin(), allNodes.end(), [](const ModelNode &node) { + return !node.metaInfo().isQtQuick3DNode(); + }); + + if (hasNon3DNode) + return false; + + return true; +} + // Called by the view to update the "create" sub-menu when the Quick3D entries are ready. void Edit3DWidget::updateCreateSubMenu(const QStringList &keys, const QHash> &entriesMap) @@ -333,8 +370,9 @@ void Edit3DWidget::showContextMenu(const QPoint &pos, const ModelNode &modelNode m_editComponentAction->setEnabled(isSingleComponent); m_editMaterialAction->setEnabled(isModel); - m_deleteAction->setEnabled(isNotRoot); m_copyAction->setEnabled(isNotRoot); + m_pasteAction->setEnabled(isPasteAvailable()); + m_deleteAction->setEnabled(isNotRoot); m_alignCameraAction->setEnabled(isCamera); m_alignViewAction->setEnabled(isCamera); diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h index 5a49d8bc1cd..e7d45956f56 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h +++ b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h @@ -51,6 +51,8 @@ private: void linkActivated(const QString &link); void createContextMenu(); + bool isPasteAvailable() const; + QPointer m_edit3DView; QPointer m_view; QPointer m_canvas; @@ -62,8 +64,9 @@ private: QPointer m_contextMenu; QPointer m_editComponentAction; QPointer m_editMaterialAction; - QPointer m_deleteAction; QPointer m_copyAction; + QPointer m_pasteAction; + QPointer m_deleteAction; QPointer m_alignCameraAction; QPointer m_alignViewAction; QPointer m_createSubMenu;