2022-08-19 15:59:36 +02:00
|
|
|
// Copyright (C) 2016 The Qt Company Ltd.
|
2022-12-21 10:12:09 +01:00
|
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
2013-01-23 12:31:22 +01:00
|
|
|
|
|
|
|
#include "designdocument.h"
|
|
|
|
#include "designdocumentview.h"
|
2013-08-02 13:25:45 +02:00
|
|
|
#include "documentmanager.h"
|
2022-07-25 20:16:58 +02:00
|
|
|
#include "qmldesignerconstants.h"
|
|
|
|
#include "qmlvisualnode.h"
|
2013-01-23 12:31:22 +01:00
|
|
|
|
2022-07-25 20:16:58 +02:00
|
|
|
#include <auxiliarydataproperties.h>
|
2023-09-21 13:00:40 +02:00
|
|
|
#ifndef QDS_USE_PROJECTSTORAGE
|
|
|
|
# include <metainfo.h>
|
|
|
|
#endif
|
2023-05-11 20:07:48 +02:00
|
|
|
#include <model/modelresourcemanagement.h>
|
2022-07-25 20:16:58 +02:00
|
|
|
#include <nodeinstanceview.h>
|
2013-01-23 12:31:22 +01:00
|
|
|
#include <nodelistproperty.h>
|
2022-07-25 20:16:58 +02:00
|
|
|
#include <rewritingexception.h>
|
2024-02-19 15:57:08 +01:00
|
|
|
#include <utils3d.h>
|
2013-01-23 12:31:22 +01:00
|
|
|
#include <variantproperty.h>
|
2013-02-05 14:52:25 +01:00
|
|
|
#include <viewmanager.h>
|
2022-07-25 20:16:58 +02:00
|
|
|
#include <qmldesignerplugin.h>
|
|
|
|
#include <qmlobjectnode.h>
|
2013-01-23 12:31:22 +01:00
|
|
|
|
2014-11-19 17:58:33 +01:00
|
|
|
#include <projectexplorer/projecttree.h>
|
2013-01-23 12:31:22 +01:00
|
|
|
#include <projectexplorer/project.h>
|
|
|
|
#include <projectexplorer/target.h>
|
2023-02-14 15:47:22 +01:00
|
|
|
#include <projectexplorer/projectmanager.h>
|
2014-03-26 19:41:51 +01:00
|
|
|
#include <projectexplorer/kit.h>
|
2023-08-11 11:23:12 +02:00
|
|
|
#include <qtsupport/qtkitaspect.h>
|
2013-01-23 12:31:22 +01:00
|
|
|
#include <qtsupport/qtsupportconstants.h>
|
|
|
|
#include <qtsupport/qtversionmanager.h>
|
2020-03-12 15:55:30 +02:00
|
|
|
#include <coreplugin/icore.h>
|
2015-02-26 13:22:35 +01:00
|
|
|
#include <coreplugin/idocument.h>
|
2017-10-17 17:43:53 +02:00
|
|
|
#include <coreplugin/editormanager/editormanager.h>
|
2020-10-06 12:29:09 +02:00
|
|
|
#include <utils/algorithm.h>
|
2020-11-07 22:18:57 +02:00
|
|
|
#include <timelineactions.h>
|
QmlDesigner: Allow inserting SVG snippets
Allows to paste SVG clipboard content into the Form Editor. It will
create a Group item which acts as the SVGs view box and groups multiple
items together. All SVG items will be transformed into SvgPathItem.
* Supports all basic SVG shapes path, rect, polygon, circle, ellipse
* Supports the following SVG presentation attributes as CSS-inline
definition, XML-attribute, style element: fill, stroke, stroke-width,
opacity, fill-opacity, stroke-opacity
* Supports all transform operations
Task-number: QDS-5259
Change-Id: I9b7027992de60e5c87f2031251348dbb31fe03fe
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
2021-10-11 09:46:21 +02:00
|
|
|
#include <svgpasteaction.h>
|
2013-01-23 12:31:22 +01:00
|
|
|
|
2016-06-21 14:01:41 +02:00
|
|
|
#include <qmljs/qmljsmodelmanagerinterface.h>
|
|
|
|
|
QmlDesigner: Allow inserting SVG snippets
Allows to paste SVG clipboard content into the Form Editor. It will
create a Group item which acts as the SVGs view box and groups multiple
items together. All SVG items will be transformed into SvgPathItem.
* Supports all basic SVG shapes path, rect, polygon, circle, ellipse
* Supports the following SVG presentation attributes as CSS-inline
definition, XML-attribute, style element: fill, stroke, stroke-width,
opacity, fill-opacity, stroke-opacity
* Supports all transform operations
Task-number: QDS-5259
Change-Id: I9b7027992de60e5c87f2031251348dbb31fe03fe
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
2021-10-11 09:46:21 +02:00
|
|
|
#include <utils/qtcassert.h>
|
|
|
|
|
2013-01-23 12:31:22 +01:00
|
|
|
#include <QFileInfo>
|
|
|
|
#include <QUrl>
|
|
|
|
#include <QDebug>
|
|
|
|
|
|
|
|
#include <QApplication>
|
2020-10-06 12:29:09 +02:00
|
|
|
#include <QMessageBox>
|
2020-09-17 12:04:27 +02:00
|
|
|
#include <QPlainTextEdit>
|
|
|
|
#include <QRandomGenerator>
|
QmlDesigner: Allow inserting SVG snippets
Allows to paste SVG clipboard content into the Form Editor. It will
create a Group item which acts as the SVGs view box and groups multiple
items together. All SVG items will be transformed into SvgPathItem.
* Supports all basic SVG shapes path, rect, polygon, circle, ellipse
* Supports the following SVG presentation attributes as CSS-inline
definition, XML-attribute, style element: fill, stroke, stroke-width,
opacity, fill-opacity, stroke-opacity
* Supports all transform operations
Task-number: QDS-5259
Change-Id: I9b7027992de60e5c87f2031251348dbb31fe03fe
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
2021-10-11 09:46:21 +02:00
|
|
|
#include <QClipboard>
|
2013-01-23 12:31:22 +01:00
|
|
|
|
|
|
|
enum {
|
|
|
|
debug = false
|
|
|
|
};
|
|
|
|
|
|
|
|
namespace QmlDesigner {
|
|
|
|
|
|
|
|
/**
|
|
|
|
\class QmlDesigner::DesignDocument
|
|
|
|
|
|
|
|
DesignDocument acts as a facade to a model representing a qml document,
|
|
|
|
and the different views/widgets accessing it.
|
|
|
|
*/
|
2024-04-11 18:13:10 +02:00
|
|
|
DesignDocument::DesignDocument([[maybe_unused]] const QUrl &filePath,
|
|
|
|
ProjectStorageDependencies projectStorageDependencies,
|
2022-09-15 15:01:49 +02:00
|
|
|
ExternalDependenciesInterface &externalDependencies)
|
2023-08-01 12:57:11 +02:00
|
|
|
#ifdef QDS_USE_PROJECTSTORAGE
|
|
|
|
: m_documentModel(Model::create(projectStorageDependencies,
|
|
|
|
"Item",
|
|
|
|
{Import::createLibraryImport("QtQuick")},
|
2024-04-11 18:13:10 +02:00
|
|
|
filePath,
|
2023-08-01 12:57:11 +02:00
|
|
|
std::make_unique<ModelResourceManagement>()))
|
|
|
|
#else
|
2023-05-11 20:07:48 +02:00
|
|
|
: m_documentModel(
|
|
|
|
Model::create("QtQuick.Item", 1, 0, nullptr, std::make_unique<ModelResourceManagement>()))
|
2022-09-15 15:01:49 +02:00
|
|
|
, m_subComponentManager(new SubComponentManager(m_documentModel.get(), externalDependencies))
|
2023-09-21 13:00:40 +02:00
|
|
|
#endif
|
2022-09-15 15:01:49 +02:00
|
|
|
, m_rewriterView(new RewriterView(externalDependencies, RewriterView::Amend))
|
2022-07-27 16:59:06 +02:00
|
|
|
, m_documentLoaded(false)
|
|
|
|
, m_currentTarget(nullptr)
|
2023-06-08 15:25:44 +02:00
|
|
|
, m_projectStorageDependencies(projectStorageDependencies)
|
2022-09-15 15:01:49 +02:00
|
|
|
, m_externalDependencies{externalDependencies}
|
2025-01-21 12:42:58 +01:00
|
|
|
{
|
|
|
|
#ifndef QDS_USE_PROJECTSTORAGE
|
|
|
|
m_rewriterView->setIsDocumentRewriterView(true);
|
|
|
|
#endif
|
|
|
|
}
|
2013-01-23 12:31:22 +01:00
|
|
|
|
2018-07-24 23:56:45 +02:00
|
|
|
DesignDocument::~DesignDocument() = default;
|
2013-01-23 12:31:22 +01:00
|
|
|
|
|
|
|
Model *DesignDocument::currentModel() const
|
|
|
|
{
|
2023-08-01 12:57:11 +02:00
|
|
|
if (m_inFileComponentModel) {
|
2022-07-27 16:59:06 +02:00
|
|
|
return m_inFileComponentModel.get();
|
2023-08-01 12:57:11 +02:00
|
|
|
}
|
2013-07-10 18:12:07 +02:00
|
|
|
|
2022-07-27 16:59:06 +02:00
|
|
|
return m_documentModel.get();
|
2013-01-23 12:31:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Model *DesignDocument::documentModel() const
|
|
|
|
{
|
2022-07-27 16:59:06 +02:00
|
|
|
return m_documentModel.get();
|
2013-01-23 12:31:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
QWidget *DesignDocument::centralWidget() const
|
|
|
|
{
|
|
|
|
return qobject_cast<QWidget*>(parent());
|
|
|
|
}
|
|
|
|
|
|
|
|
const ViewManager &DesignDocument::viewManager() const
|
|
|
|
{
|
|
|
|
return QmlDesignerPlugin::instance()->viewManager();
|
|
|
|
}
|
|
|
|
|
|
|
|
ViewManager &DesignDocument::viewManager()
|
|
|
|
{
|
|
|
|
return QmlDesignerPlugin::instance()->viewManager();
|
|
|
|
}
|
|
|
|
|
|
|
|
static ComponentTextModifier *createComponentTextModifier(TextModifier *originalModifier,
|
|
|
|
RewriterView *rewriterView,
|
|
|
|
const QString &componentText,
|
|
|
|
const ModelNode &componentNode)
|
|
|
|
{
|
2015-07-16 17:06:52 +02:00
|
|
|
bool explicitComponent = componentText.contains(QLatin1String("Component"));
|
2013-01-23 12:31:22 +01:00
|
|
|
|
|
|
|
ModelNode rootModelNode = rewriterView->rootModelNode();
|
|
|
|
|
|
|
|
int componentStartOffset;
|
|
|
|
int componentEndOffset;
|
|
|
|
|
|
|
|
int rootStartOffset = rewriterView->nodeOffset(rootModelNode);
|
|
|
|
|
|
|
|
if (explicitComponent) { //the component is explciit we have to find the first definition inside
|
|
|
|
componentStartOffset = rewriterView->firstDefinitionInsideOffset(componentNode);
|
|
|
|
componentEndOffset = componentStartOffset + rewriterView->firstDefinitionInsideLength(componentNode);
|
|
|
|
} else { //the component is implicit
|
|
|
|
componentStartOffset = rewriterView->nodeOffset(componentNode);
|
|
|
|
componentEndOffset = componentStartOffset + rewriterView->nodeLength(componentNode);
|
|
|
|
}
|
|
|
|
|
2016-10-19 13:48:40 +02:00
|
|
|
return new ComponentTextModifier(originalModifier, componentStartOffset, componentEndOffset, rootStartOffset);
|
2013-01-23 12:31:22 +01:00
|
|
|
}
|
|
|
|
|
2013-02-04 11:16:46 +01:00
|
|
|
bool DesignDocument::loadInFileComponent(const ModelNode &componentNode)
|
2013-01-23 12:31:22 +01:00
|
|
|
{
|
2017-04-26 14:32:02 +02:00
|
|
|
QString componentText = rewriterView()->extractText({componentNode}).value(componentNode);
|
2013-01-23 12:31:22 +01:00
|
|
|
|
|
|
|
if (componentText.isEmpty())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!componentNode.isRootNode()) {
|
|
|
|
//change to subcomponent model
|
2024-05-02 19:47:34 +02:00
|
|
|
changeToInFileComponentModel(createComponentTextModifier(m_documentTextModifier.get(),
|
|
|
|
rewriterView(),
|
|
|
|
componentText,
|
|
|
|
componentNode));
|
2013-01-23 12:31:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-09-14 11:46:08 +02:00
|
|
|
const AbstractView *DesignDocument::view() const
|
2013-02-05 14:52:25 +01:00
|
|
|
{
|
2022-10-10 17:41:03 +02:00
|
|
|
return viewManager().view();
|
2013-02-05 14:52:25 +01:00
|
|
|
}
|
|
|
|
|
2022-10-27 12:17:22 +02:00
|
|
|
ModelPointer DesignDocument::createInFileComponentModel()
|
2013-07-10 18:12:07 +02:00
|
|
|
{
|
2024-03-06 19:37:43 +01:00
|
|
|
#ifdef QDS_USE_PROJECTSTORAGE
|
|
|
|
auto model = m_documentModel->createModel("Item", std::make_unique<ModelResourceManagement>());
|
|
|
|
#else
|
2023-05-11 20:07:48 +02:00
|
|
|
auto model = Model::create("QtQuick.Item",
|
|
|
|
1,
|
|
|
|
0,
|
|
|
|
nullptr,
|
|
|
|
std::make_unique<ModelResourceManagement>());
|
2013-07-10 18:12:07 +02:00
|
|
|
model->setFileUrl(m_documentModel->fileUrl());
|
2021-11-01 16:33:20 +02:00
|
|
|
model->setMetaInfo(m_documentModel->metaInfo());
|
2023-09-21 13:00:40 +02:00
|
|
|
#endif
|
2013-07-10 18:12:07 +02:00
|
|
|
|
|
|
|
return model;
|
|
|
|
}
|
|
|
|
|
QmlDesigner: Allow inserting SVG snippets
Allows to paste SVG clipboard content into the Form Editor. It will
create a Group item which acts as the SVGs view box and groups multiple
items together. All SVG items will be transformed into SvgPathItem.
* Supports all basic SVG shapes path, rect, polygon, circle, ellipse
* Supports the following SVG presentation attributes as CSS-inline
definition, XML-attribute, style element: fill, stroke, stroke-width,
opacity, fill-opacity, stroke-opacity
* Supports all transform operations
Task-number: QDS-5259
Change-Id: I9b7027992de60e5c87f2031251348dbb31fe03fe
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
2021-10-11 09:46:21 +02:00
|
|
|
bool DesignDocument::pasteSVG()
|
|
|
|
{
|
|
|
|
SVGPasteAction svgPasteAction;
|
|
|
|
|
|
|
|
if (!svgPasteAction.containsSVG(QApplication::clipboard()->text()))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
rewriterView()->executeInTransaction("DesignDocument::paste1", [&]() {
|
|
|
|
ModelNode targetNode;
|
|
|
|
|
|
|
|
// If nodes are currently selected make the first node in selection the target
|
|
|
|
if (!view()->selectedModelNodes().isEmpty())
|
|
|
|
targetNode = view()->firstSelectedModelNode();
|
|
|
|
|
|
|
|
// If target is still invalid make the root node the target
|
|
|
|
if (!targetNode.isValid())
|
|
|
|
targetNode = view()->rootModelNode();
|
|
|
|
|
|
|
|
// Check if document has studio components import, if not create it
|
|
|
|
QmlDesigner::Import import = QmlDesigner::Import::createLibraryImport("QtQuick.Studio.Components", "1.0");
|
|
|
|
if (!currentModel()->hasImport(import, true, true)) {
|
|
|
|
QmlDesigner::Import studioComponentsImport = QmlDesigner::Import::createLibraryImport("QtQuick.Studio.Components", "1.0");
|
|
|
|
try {
|
|
|
|
currentModel()->changeImports({studioComponentsImport}, {});
|
|
|
|
} catch (const QmlDesigner::Exception &) {
|
|
|
|
QTC_ASSERT(false, return);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
svgPasteAction.createQmlObjectNode(targetNode);
|
|
|
|
});
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-11-08 17:20:38 +02:00
|
|
|
void DesignDocument::moveNodesToPosition(const QList<ModelNode> &nodes, const std::optional<QVector3D> &position)
|
|
|
|
{
|
|
|
|
if (!nodes.size())
|
|
|
|
return;
|
|
|
|
|
|
|
|
QList<ModelNode> movingNodes = nodes;
|
|
|
|
DesignDocumentView view{m_externalDependencies};
|
|
|
|
currentModel()->attachView(&view);
|
|
|
|
|
|
|
|
ModelNode targetNode; // the node that new nodes should be placed in
|
|
|
|
if (!view.selectedModelNodes().isEmpty())
|
|
|
|
targetNode = view.firstSelectedModelNode();
|
|
|
|
|
|
|
|
// in case we copy and paste a selection we paste in the parent item
|
2023-06-07 13:03:11 +02:00
|
|
|
if ((view.selectedModelNodes().size() == movingNodes.size()) && targetNode.hasParentProperty()) {
|
2022-11-08 17:20:38 +02:00
|
|
|
targetNode = targetNode.parentProperty().parentModelNode();
|
|
|
|
} else if (view.selectedModelNodes().isEmpty()) {
|
|
|
|
// if selection is empty and copied nodes are all 3D nodes, paste them under the active scene
|
|
|
|
bool all3DNodes = Utils::allOf(movingNodes, [](const ModelNode &node) {
|
|
|
|
return node.metaInfo().isQtQuick3DNode();
|
|
|
|
});
|
|
|
|
|
|
|
|
if (all3DNodes) {
|
2024-02-19 15:57:08 +01:00
|
|
|
int activeSceneId = Utils3D::active3DSceneId(m_documentModel.get());
|
|
|
|
|
|
|
|
if (activeSceneId != -1) {
|
|
|
|
NodeListProperty sceneNodeProperty = QmlVisualNode::findSceneNodeProperty(
|
|
|
|
rootModelNode().view(), activeSceneId);
|
|
|
|
targetNode = sceneNodeProperty.parentModelNode();
|
2022-11-08 17:20:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!targetNode.isValid())
|
|
|
|
targetNode = view.rootModelNode();
|
|
|
|
|
|
|
|
for (const ModelNode &node : std::as_const(movingNodes)) {
|
|
|
|
for (const ModelNode &node2 : std::as_const(movingNodes)) {
|
|
|
|
if (node.isAncestorOf(node2))
|
|
|
|
movingNodes.removeAll(node2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isSingleNode = movingNodes.size() == 1;
|
|
|
|
if (isSingleNode) {
|
|
|
|
ModelNode singleNode = movingNodes.first();
|
|
|
|
if (targetNode.hasParentProperty()
|
|
|
|
&& singleNode.simplifiedTypeName() == targetNode.simplifiedTypeName()
|
|
|
|
&& singleNode.variantProperty("width").value() == targetNode.variantProperty("width").value()
|
|
|
|
&& singleNode.variantProperty("height").value() == targetNode.variantProperty("height").value()) {
|
|
|
|
targetNode = targetNode.parentProperty().parentModelNode();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const PropertyName defaultPropertyName = targetNode.metaInfo().defaultPropertyName();
|
|
|
|
if (!targetNode.metaInfo().property(defaultPropertyName).isListProperty())
|
|
|
|
qWarning() << Q_FUNC_INFO << "Cannot reparent to" << targetNode;
|
|
|
|
NodeListProperty parentProperty = targetNode.nodeListProperty(defaultPropertyName);
|
|
|
|
QList<ModelNode> pastedNodeList;
|
|
|
|
|
|
|
|
std::optional<QmlVisualNode> firstVisualNode;
|
|
|
|
QVector3D translationVect;
|
|
|
|
for (const ModelNode &node : std::as_const(movingNodes)) {
|
|
|
|
ModelNode pastedNode(view.insertModel(node));
|
|
|
|
pastedNodeList.append(pastedNode);
|
|
|
|
parentProperty.reparentHere(pastedNode);
|
|
|
|
|
|
|
|
QmlVisualNode visualNode(pastedNode);
|
2024-05-24 13:42:38 +02:00
|
|
|
if (!firstVisualNode && visualNode) {
|
2022-11-08 17:20:38 +02:00
|
|
|
firstVisualNode = visualNode;
|
2024-05-24 13:42:38 +02:00
|
|
|
translationVect = (position && firstVisualNode) ? *position - firstVisualNode->position()
|
|
|
|
: QVector3D();
|
2022-11-08 17:20:38 +02:00
|
|
|
}
|
|
|
|
visualNode.translate(translationVect);
|
|
|
|
}
|
|
|
|
|
|
|
|
view.setSelectedModelNodes(pastedNodeList);
|
|
|
|
view.model()->clearMetaInfoCache();
|
|
|
|
}
|
|
|
|
|
2021-11-02 15:05:11 +02:00
|
|
|
bool DesignDocument::inFileComponentModelActive() const
|
|
|
|
{
|
2022-07-27 16:59:06 +02:00
|
|
|
return bool(m_inFileComponentModel);
|
2021-11-02 15:05:11 +02:00
|
|
|
}
|
|
|
|
|
2017-01-10 17:08:14 +01:00
|
|
|
QList<DocumentMessage> DesignDocument::qmlParseWarnings() const
|
2016-04-26 15:50:34 +02:00
|
|
|
{
|
|
|
|
return m_rewriterView->warnings();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool DesignDocument::hasQmlParseWarnings() const
|
|
|
|
{
|
2016-06-29 16:00:00 +02:00
|
|
|
return !m_rewriterView->warnings().isEmpty();
|
2016-04-26 15:50:34 +02:00
|
|
|
}
|
|
|
|
|
2017-01-10 17:08:14 +01:00
|
|
|
QList<DocumentMessage> DesignDocument::qmlParseErrors() const
|
2013-01-23 12:31:22 +01:00
|
|
|
{
|
|
|
|
return m_rewriterView->errors();
|
|
|
|
}
|
|
|
|
|
2016-04-26 15:50:34 +02:00
|
|
|
bool DesignDocument::hasQmlParseErrors() const
|
2013-01-23 12:31:22 +01:00
|
|
|
{
|
2016-06-29 16:00:00 +02:00
|
|
|
return !m_rewriterView->errors().isEmpty();
|
2013-01-23 12:31:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
QString DesignDocument::displayName() const
|
|
|
|
{
|
2015-07-09 14:02:36 +02:00
|
|
|
return fileName().toString();
|
2013-01-23 12:31:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
QString DesignDocument::simplfiedDisplayName() const
|
|
|
|
{
|
2013-11-11 22:20:47 +02:00
|
|
|
if (rootModelNode().id().isEmpty())
|
2013-01-23 12:31:22 +01:00
|
|
|
return rootModelNode().id();
|
2013-11-11 22:20:47 +02:00
|
|
|
else
|
2013-01-23 12:31:22 +01:00
|
|
|
return rootModelNode().simplifiedTypeName();
|
|
|
|
}
|
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
void DesignDocument::updateFileName(const Utils::FilePath & /*oldFileName*/, const Utils::FilePath &newFileName)
|
2013-01-23 12:31:22 +01:00
|
|
|
{
|
|
|
|
if (m_documentModel)
|
2014-12-21 21:54:30 +02:00
|
|
|
m_documentModel->setFileUrl(QUrl::fromLocalFile(newFileName.toString()));
|
2013-01-23 12:31:22 +01:00
|
|
|
|
|
|
|
if (m_inFileComponentModel)
|
2014-12-21 21:54:30 +02:00
|
|
|
m_inFileComponentModel->setFileUrl(QUrl::fromLocalFile(newFileName.toString()));
|
2013-01-23 12:31:22 +01:00
|
|
|
|
|
|
|
emit displayNameChanged(displayName());
|
|
|
|
}
|
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
Utils::FilePath DesignDocument::fileName() const
|
2013-01-23 12:31:22 +01:00
|
|
|
{
|
2023-08-02 08:09:26 +02:00
|
|
|
return editor() ? editor()->document()->filePath() : Utils::FilePath();
|
2013-01-23 12:31:22 +01:00
|
|
|
}
|
|
|
|
|
2019-10-30 08:25:31 +01:00
|
|
|
ProjectExplorer::Target *DesignDocument::currentTarget() const
|
2013-01-23 12:31:22 +01:00
|
|
|
{
|
2019-10-30 08:25:31 +01:00
|
|
|
return m_currentTarget;
|
2013-01-23 12:31:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool DesignDocument::isDocumentLoaded() const
|
|
|
|
{
|
|
|
|
return m_documentLoaded;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DesignDocument::resetToDocumentModel()
|
|
|
|
{
|
2021-11-24 14:46:05 +01:00
|
|
|
const QPlainTextEdit *edit = plainTextEdit();
|
|
|
|
if (edit)
|
|
|
|
edit->document()->clearUndoRedoStacks();
|
|
|
|
|
2013-07-10 18:12:07 +02:00
|
|
|
m_inFileComponentModel.reset();
|
2013-01-23 12:31:22 +01:00
|
|
|
}
|
|
|
|
|
2013-02-04 15:03:46 +01:00
|
|
|
void DesignDocument::loadDocument(QPlainTextEdit *edit)
|
2013-01-23 12:31:22 +01:00
|
|
|
{
|
|
|
|
Q_CHECK_PTR(edit);
|
|
|
|
|
2020-10-22 23:25:27 +03:00
|
|
|
connect(edit, &QPlainTextEdit::undoAvailable, this, &DesignDocument::undoAvailable);
|
|
|
|
connect(edit, &QPlainTextEdit::redoAvailable, this, &DesignDocument::redoAvailable);
|
|
|
|
connect(edit, &QPlainTextEdit::modificationChanged, this, &DesignDocument::dirtyStateChanged);
|
2013-01-23 12:31:22 +01:00
|
|
|
|
2020-10-22 23:25:27 +03:00
|
|
|
m_documentTextModifier.reset(new BaseTextEditModifier(qobject_cast<TextEditor::TextEditorWidget *>(plainTextEdit())));
|
2016-06-21 14:01:41 +02:00
|
|
|
|
2024-05-02 19:47:34 +02:00
|
|
|
connect(m_documentTextModifier.get(),
|
|
|
|
&TextModifier::textChanged,
|
|
|
|
this,
|
|
|
|
&DesignDocument::updateQrcFiles);
|
2016-06-21 14:01:41 +02:00
|
|
|
|
2024-05-02 19:47:34 +02:00
|
|
|
m_rewriterView->setTextModifier(m_documentTextModifier.get());
|
2023-06-08 19:58:57 +02:00
|
|
|
|
2013-02-06 17:12:04 +01:00
|
|
|
m_inFileComponentTextModifier.reset();
|
2013-01-23 12:31:22 +01:00
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
updateFileName(Utils::FilePath(), fileName());
|
2013-01-23 12:31:22 +01:00
|
|
|
|
2016-06-21 14:01:41 +02:00
|
|
|
updateQrcFiles();
|
|
|
|
|
2013-02-04 15:03:46 +01:00
|
|
|
m_documentLoaded = true;
|
2013-01-23 12:31:22 +01:00
|
|
|
}
|
|
|
|
|
2013-02-07 13:25:58 +01:00
|
|
|
void DesignDocument::changeToDocumentModel()
|
|
|
|
{
|
|
|
|
viewManager().detachRewriterView();
|
|
|
|
viewManager().detachViewsExceptRewriterAndComponetView();
|
|
|
|
|
2021-11-24 14:46:05 +01:00
|
|
|
const QPlainTextEdit *edit = plainTextEdit();
|
|
|
|
if (edit)
|
|
|
|
edit->document()->clearUndoRedoStacks();
|
2021-11-11 13:23:23 +02:00
|
|
|
|
2024-05-02 19:47:34 +02:00
|
|
|
m_rewriterView->setTextModifier(m_documentTextModifier.get());
|
2023-06-08 19:58:57 +02:00
|
|
|
|
2013-07-10 18:12:07 +02:00
|
|
|
m_inFileComponentModel.reset();
|
2021-11-08 16:28:40 +02:00
|
|
|
m_inFileComponentTextModifier.reset();
|
2013-02-07 13:25:58 +01:00
|
|
|
|
2013-08-01 11:48:36 +02:00
|
|
|
viewManager().attachRewriterView();
|
2013-02-07 13:25:58 +01:00
|
|
|
viewManager().attachViewsExceptRewriterAndComponetView();
|
|
|
|
}
|
|
|
|
|
2020-02-24 16:27:45 +01:00
|
|
|
bool DesignDocument::isQtForMCUsProject() const
|
|
|
|
{
|
|
|
|
if (m_currentTarget)
|
|
|
|
return m_currentTarget->additionalData("CustomQtForMCUs").toBool();
|
|
|
|
|
2020-08-17 16:45:37 +02:00
|
|
|
return false;
|
2020-02-24 16:27:45 +01:00
|
|
|
}
|
|
|
|
|
2021-06-10 16:45:25 +02:00
|
|
|
Utils::FilePath DesignDocument::projectFolder() const
|
|
|
|
{
|
2023-02-14 15:47:22 +01:00
|
|
|
ProjectExplorer::Project *currentProject = ProjectExplorer::ProjectManager::projectForFile(fileName());
|
2021-06-10 16:45:25 +02:00
|
|
|
|
|
|
|
if (currentProject)
|
|
|
|
return currentProject->projectDirectory();
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2021-08-09 18:58:14 +02:00
|
|
|
bool DesignDocument::hasProject() const
|
|
|
|
{
|
2022-02-21 13:35:30 +02:00
|
|
|
return !DocumentManager::currentProjectDirPath().isEmpty();
|
2021-08-09 18:58:14 +02:00
|
|
|
}
|
|
|
|
|
2024-01-29 16:34:48 +02:00
|
|
|
void DesignDocument::setModified()
|
|
|
|
{
|
2024-05-02 19:47:34 +02:00
|
|
|
if (m_documentTextModifier)
|
2024-01-29 16:34:48 +02:00
|
|
|
m_documentTextModifier->textDocument()->setModified(true);
|
|
|
|
}
|
|
|
|
|
2013-08-01 11:48:36 +02:00
|
|
|
void DesignDocument::changeToInFileComponentModel(ComponentTextModifier *textModifer)
|
2013-02-07 13:25:58 +01:00
|
|
|
{
|
2013-08-01 11:48:36 +02:00
|
|
|
m_inFileComponentTextModifier.reset(textModifer);
|
2013-02-07 13:25:58 +01:00
|
|
|
viewManager().detachRewriterView();
|
|
|
|
viewManager().detachViewsExceptRewriterAndComponetView();
|
|
|
|
|
2021-11-24 14:46:05 +01:00
|
|
|
const QPlainTextEdit *edit = plainTextEdit();
|
|
|
|
if (edit)
|
|
|
|
edit->document()->clearUndoRedoStacks();
|
2021-11-11 13:23:23 +02:00
|
|
|
|
2022-07-27 16:59:06 +02:00
|
|
|
m_inFileComponentModel = createInFileComponentModel();
|
2013-02-07 13:25:58 +01:00
|
|
|
|
2024-05-02 19:47:34 +02:00
|
|
|
m_rewriterView->setTextModifier(m_inFileComponentTextModifier.get());
|
2023-06-08 19:58:57 +02:00
|
|
|
|
2013-08-01 11:48:36 +02:00
|
|
|
viewManager().attachRewriterView();
|
2013-02-07 13:25:58 +01:00
|
|
|
viewManager().attachViewsExceptRewriterAndComponetView();
|
|
|
|
}
|
|
|
|
|
2016-06-21 14:01:41 +02:00
|
|
|
void DesignDocument::updateQrcFiles()
|
|
|
|
{
|
2023-02-14 15:47:22 +01:00
|
|
|
ProjectExplorer::Project *currentProject = ProjectExplorer::ProjectManager::projectForFile(fileName());
|
2016-06-21 14:01:41 +02:00
|
|
|
|
|
|
|
if (currentProject) {
|
2020-10-22 23:25:27 +03:00
|
|
|
const auto srcFiles = currentProject->files(ProjectExplorer::Project::SourceFiles);
|
|
|
|
for (const Utils::FilePath &fileName : srcFiles) {
|
2016-06-21 14:01:41 +02:00
|
|
|
if (fileName.endsWith(".qrc"))
|
2022-06-20 12:35:13 +02:00
|
|
|
QmlJS::ModelManagerInterface::instance()->updateQrcFile(fileName);
|
2016-06-21 14:01:41 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-12 17:30:50 +02:00
|
|
|
void DesignDocument::changeToSubComponent(const ModelNode &componentNode)
|
2013-01-23 12:31:22 +01:00
|
|
|
{
|
|
|
|
if (QmlDesignerPlugin::instance()->currentDesignDocument() != this)
|
|
|
|
return;
|
|
|
|
|
2013-07-10 18:12:07 +02:00
|
|
|
if (m_inFileComponentModel)
|
2013-01-23 12:31:22 +01:00
|
|
|
changeToDocumentModel();
|
|
|
|
|
2013-02-04 11:16:46 +01:00
|
|
|
bool subComponentLoaded = loadInFileComponent(componentNode);
|
2013-01-23 12:31:22 +01:00
|
|
|
|
2013-02-06 17:12:04 +01:00
|
|
|
if (subComponentLoaded)
|
2013-08-01 11:48:36 +02:00
|
|
|
attachRewriterToModel();
|
2013-08-12 17:30:50 +02:00
|
|
|
|
|
|
|
QmlDesignerPlugin::instance()->viewManager().pushInFileComponentOnCrumbleBar(componentNode);
|
2013-09-26 18:46:39 +02:00
|
|
|
QmlDesignerPlugin::instance()->viewManager().setComponentNode(componentNode);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DesignDocument::changeToMaster()
|
|
|
|
{
|
|
|
|
if (QmlDesignerPlugin::instance()->currentDesignDocument() != this)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (m_inFileComponentModel)
|
|
|
|
changeToDocumentModel();
|
|
|
|
|
2016-10-07 14:16:49 +02:00
|
|
|
QmlDesignerPlugin::instance()->viewManager().pushFileOnCrumbleBar(fileName());
|
2013-09-26 18:46:39 +02:00
|
|
|
QmlDesignerPlugin::instance()->viewManager().setComponentNode(rootModelNode());
|
2013-01-23 12:31:22 +01:00
|
|
|
}
|
|
|
|
|
2013-08-01 11:48:36 +02:00
|
|
|
void DesignDocument::attachRewriterToModel()
|
2013-01-23 12:31:22 +01:00
|
|
|
{
|
|
|
|
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
|
|
|
|
Q_ASSERT(m_documentModel);
|
|
|
|
|
2013-08-01 11:48:36 +02:00
|
|
|
viewManager().attachRewriterView();
|
2013-01-23 12:31:22 +01:00
|
|
|
|
|
|
|
Q_ASSERT(m_documentModel);
|
|
|
|
QApplication::restoreOverrideCursor();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool DesignDocument::isUndoAvailable() const
|
|
|
|
{
|
|
|
|
if (plainTextEdit())
|
|
|
|
return plainTextEdit()->document()->isUndoAvailable();
|
2020-10-22 23:25:27 +03:00
|
|
|
|
2013-01-23 12:31:22 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool DesignDocument::isRedoAvailable() const
|
|
|
|
{
|
|
|
|
if (plainTextEdit())
|
|
|
|
return plainTextEdit()->document()->isRedoAvailable();
|
2020-10-22 23:25:27 +03:00
|
|
|
|
2013-01-23 12:31:22 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-01-23 17:50:34 +02:00
|
|
|
void DesignDocument::clearUndoRedoStacks() const
|
|
|
|
{
|
|
|
|
const QPlainTextEdit *edit = plainTextEdit();
|
|
|
|
if (edit)
|
|
|
|
edit->document()->clearUndoRedoStacks();
|
|
|
|
}
|
|
|
|
|
2013-01-23 12:31:22 +01:00
|
|
|
void DesignDocument::close()
|
|
|
|
{
|
|
|
|
m_documentLoaded = false;
|
|
|
|
emit designDocumentClosed();
|
|
|
|
}
|
|
|
|
|
2023-09-21 13:00:40 +02:00
|
|
|
#ifndef QDS_USE_PROJECTSTORAGE
|
2013-01-29 09:50:31 +01:00
|
|
|
void DesignDocument::updateSubcomponentManager()
|
|
|
|
{
|
|
|
|
Q_ASSERT(m_subComponentManager);
|
2021-03-02 17:15:59 +02:00
|
|
|
m_subComponentManager->update(QUrl::fromLocalFile(fileName().toString()),
|
|
|
|
currentModel()->imports() + currentModel()->possibleImports());
|
2013-01-29 09:50:31 +01:00
|
|
|
}
|
|
|
|
|
2021-10-29 15:39:05 +03:00
|
|
|
void DesignDocument::addSubcomponentManagerImport(const Import &import)
|
2021-04-15 12:07:28 +03:00
|
|
|
{
|
2021-10-29 15:39:05 +03:00
|
|
|
m_subComponentManager->addAndParseImport(import);
|
2021-04-15 12:07:28 +03:00
|
|
|
}
|
2023-09-21 13:00:40 +02:00
|
|
|
#endif
|
2021-04-15 12:07:28 +03:00
|
|
|
|
2013-01-23 12:31:22 +01:00
|
|
|
void DesignDocument::deleteSelected()
|
|
|
|
{
|
2013-07-10 18:12:07 +02:00
|
|
|
if (!currentModel())
|
2013-01-23 12:31:22 +01:00
|
|
|
return;
|
|
|
|
|
2020-10-06 12:29:09 +02:00
|
|
|
QStringList lockedNodes;
|
|
|
|
for (const ModelNode &modelNode : view()->selectedModelNodes()) {
|
|
|
|
for (const ModelNode &node : modelNode.allSubModelNodesAndThisNode()) {
|
2020-10-23 17:45:47 +03:00
|
|
|
if (node.isValid() && !node.isRootNode() && node.locked() && !lockedNodes.contains(node.id()))
|
2020-10-06 12:29:09 +02:00
|
|
|
lockedNodes.push_back(node.id());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!lockedNodes.empty()) {
|
|
|
|
Utils::sort(lockedNodes);
|
|
|
|
QString detailedText = QString("<b>" + tr("Locked items:") + "</b><br>");
|
|
|
|
|
2022-10-07 14:46:06 +02:00
|
|
|
for (const auto &id : std::as_const(lockedNodes))
|
2020-10-06 12:29:09 +02:00
|
|
|
detailedText.append("- " + id + "<br>");
|
|
|
|
|
|
|
|
detailedText.chop(QString("<br>").size());
|
|
|
|
|
|
|
|
QMessageBox msgBox;
|
|
|
|
msgBox.setTextFormat(Qt::RichText);
|
|
|
|
msgBox.setIcon(QMessageBox::Question);
|
|
|
|
msgBox.setWindowTitle(tr("Delete/Cut Item"));
|
|
|
|
msgBox.setText(QString(tr("Deleting or cutting this item will modify locked items.") + "<br><br>%1")
|
|
|
|
.arg(detailedText));
|
|
|
|
msgBox.setInformativeText(tr("Do you want to continue by removing the item (Delete) or removing it and copying it to the clipboard (Cut)?"));
|
|
|
|
msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
|
|
|
|
msgBox.setDefaultButton(QMessageBox::Ok);
|
|
|
|
|
|
|
|
if (msgBox.exec() == QMessageBox::Cancel)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-12-12 11:34:17 +01:00
|
|
|
rewriterView()->executeInTransaction("DesignDocument::deleteSelected", [this] {
|
2020-10-22 23:25:27 +03:00
|
|
|
const QList<ModelNode> toDelete = view()->selectedModelNodes();
|
2020-10-06 12:29:09 +02:00
|
|
|
for (ModelNode node : toDelete) {
|
2013-07-24 15:58:51 +02:00
|
|
|
if (node.isValid() && !node.isRootNode() && QmlObjectNode::isValidQmlObjectNode(node))
|
2013-01-23 12:31:22 +01:00
|
|
|
QmlObjectNode(node).destroy();
|
|
|
|
}
|
2019-05-31 16:49:04 +02:00
|
|
|
});
|
2013-01-23 12:31:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void DesignDocument::copySelected()
|
|
|
|
{
|
2022-09-15 15:01:49 +02:00
|
|
|
DesignDocumentView view{m_externalDependencies};
|
2013-01-23 12:31:22 +01:00
|
|
|
|
2013-07-10 18:12:07 +02:00
|
|
|
currentModel()->attachView(&view);
|
2013-01-23 12:31:22 +01:00
|
|
|
|
2022-09-15 15:01:49 +02:00
|
|
|
DesignDocumentView::copyModelNodes(view.selectedModelNodes(), m_externalDependencies);
|
2013-01-23 12:31:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void DesignDocument::cutSelected()
|
|
|
|
{
|
|
|
|
copySelected();
|
|
|
|
deleteSelected();
|
|
|
|
}
|
|
|
|
|
2022-11-10 15:44:45 +02:00
|
|
|
void DesignDocument::duplicateSelected()
|
|
|
|
{
|
|
|
|
DesignDocumentView view{m_externalDependencies};
|
|
|
|
currentModel()->attachView(&view);
|
|
|
|
const QList<ModelNode> selectedNodes = view.selectedModelNodes();
|
|
|
|
currentModel()->detachView(&view);
|
|
|
|
|
|
|
|
rewriterView()->executeInTransaction("DesignDocument::duplicateSelected", [this, selectedNodes]() {
|
|
|
|
moveNodesToPosition(selectedNodes, {});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-11-08 17:20:38 +02:00
|
|
|
void DesignDocument::paste()
|
2013-01-23 12:31:22 +01:00
|
|
|
{
|
2022-11-08 17:20:38 +02:00
|
|
|
pasteToPosition({});
|
2013-01-23 12:31:22 +01:00
|
|
|
}
|
|
|
|
|
2022-11-08 17:20:38 +02:00
|
|
|
void DesignDocument::pasteToPosition(const std::optional<QVector3D> &position)
|
2013-01-23 12:31:22 +01:00
|
|
|
{
|
QmlDesigner: Allow inserting SVG snippets
Allows to paste SVG clipboard content into the Form Editor. It will
create a Group item which acts as the SVGs view box and groups multiple
items together. All SVG items will be transformed into SvgPathItem.
* Supports all basic SVG shapes path, rect, polygon, circle, ellipse
* Supports the following SVG presentation attributes as CSS-inline
definition, XML-attribute, style element: fill, stroke, stroke-width,
opacity, fill-opacity, stroke-opacity
* Supports all transform operations
Task-number: QDS-5259
Change-Id: I9b7027992de60e5c87f2031251348dbb31fe03fe
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
2021-10-11 09:46:21 +02:00
|
|
|
if (pasteSVG())
|
|
|
|
return;
|
|
|
|
|
2020-11-07 22:18:57 +02:00
|
|
|
if (TimelineActions::clipboardContainsKeyframes()) // pasting keyframes is handled in TimelineView
|
|
|
|
return;
|
|
|
|
|
2022-09-15 15:01:49 +02:00
|
|
|
auto pasteModel = DesignDocumentView::pasteToModel(m_externalDependencies);
|
2013-01-23 12:31:22 +01:00
|
|
|
|
|
|
|
if (!pasteModel)
|
|
|
|
return;
|
|
|
|
|
2022-09-15 15:01:49 +02:00
|
|
|
DesignDocumentView view{m_externalDependencies};
|
2013-01-23 12:31:22 +01:00
|
|
|
pasteModel->attachView(&view);
|
|
|
|
ModelNode rootNode(view.rootModelNode());
|
|
|
|
|
|
|
|
if (rootNode.type() == "empty")
|
|
|
|
return;
|
|
|
|
|
2022-11-08 17:20:38 +02:00
|
|
|
QList<ModelNode> selectedNodes;
|
|
|
|
if (rootNode.id() == "__multi__selection__")
|
|
|
|
selectedNodes << rootNode.directSubModelNodes();
|
|
|
|
else
|
|
|
|
selectedNodes << rootNode;
|
2013-01-23 12:31:22 +01:00
|
|
|
|
2022-11-08 17:20:38 +02:00
|
|
|
pasteModel->detachView(&view);
|
2020-10-22 23:25:27 +03:00
|
|
|
|
2022-11-08 17:20:38 +02:00
|
|
|
rewriterView()->executeInTransaction("DesignDocument::pasteToPosition", [this, selectedNodes, position]() {
|
|
|
|
moveNodesToPosition(selectedNodes, position);
|
|
|
|
});
|
2013-01-23 12:31:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void DesignDocument::selectAll()
|
|
|
|
{
|
2013-07-10 18:12:07 +02:00
|
|
|
if (!currentModel())
|
2013-01-23 12:31:22 +01:00
|
|
|
return;
|
|
|
|
|
2022-09-15 15:01:49 +02:00
|
|
|
DesignDocumentView view{m_externalDependencies};
|
2013-07-10 18:12:07 +02:00
|
|
|
currentModel()->attachView(&view);
|
2013-01-23 12:31:22 +01:00
|
|
|
|
|
|
|
QList<ModelNode> allNodesExceptRootNode(view.allModelNodes());
|
|
|
|
allNodesExceptRootNode.removeOne(view.rootModelNode());
|
|
|
|
view.setSelectedModelNodes(allNodesExceptRootNode);
|
|
|
|
}
|
|
|
|
|
|
|
|
RewriterView *DesignDocument::rewriterView() const
|
|
|
|
{
|
2024-05-02 19:47:34 +02:00
|
|
|
return m_rewriterView.get();
|
2013-01-23 12:31:22 +01:00
|
|
|
}
|
|
|
|
|
2024-12-13 10:56:56 +02:00
|
|
|
#ifndef QDS_USE_PROJECTSTORAGE
|
|
|
|
static void removeUnusedImports(RewriterView *rewriter)
|
|
|
|
{
|
|
|
|
// Remove any import statements for asset based nodes (composed effect or imported3d)
|
|
|
|
// if there is no nodes using them in the scene.
|
|
|
|
QTC_ASSERT(rewriter && rewriter->model(), return);
|
|
|
|
|
|
|
|
GeneratedComponentUtils compUtils{rewriter->externalDependencies()};
|
|
|
|
|
|
|
|
const QString effectPrefix = compUtils.composedEffectsTypePrefix();
|
|
|
|
const QString imported3dPrefix = compUtils.import3dTypePrefix();
|
|
|
|
const QList<Utils::FilePath> qmlFiles = compUtils.imported3dComponents();
|
|
|
|
QHash<QString, QString> m_imported3dTypeMap;
|
|
|
|
for (const Utils::FilePath &qmlFile : qmlFiles) {
|
|
|
|
QString importName = compUtils.getImported3dImportName(qmlFile);
|
|
|
|
QString type = qmlFile.baseName();
|
|
|
|
m_imported3dTypeMap.insert(importName, type);
|
|
|
|
}
|
|
|
|
|
|
|
|
const Imports &imports = rewriter->model()->imports();
|
|
|
|
QHash<QString, Import> assetImports;
|
|
|
|
for (const Import &import : imports) {
|
|
|
|
if (import.url().startsWith(effectPrefix)) {
|
|
|
|
QString type = import.url().split('.').last();
|
|
|
|
assetImports.insert(type, import);
|
|
|
|
} else if (import.url().startsWith(imported3dPrefix)) {
|
|
|
|
assetImports.insert(m_imported3dTypeMap[import.url()], import);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const QList<ModelNode> allNodes = rewriter->allModelNodes();
|
|
|
|
for (const ModelNode &node : allNodes) {
|
|
|
|
if (QmlItemNode(node).isEffectItem()
|
|
|
|
|| (node.isComponent() && node.metaInfo().isQtQuick3DNode())) {
|
|
|
|
assetImports.remove(node.simplifiedTypeName());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!assetImports.isEmpty()) {
|
|
|
|
Imports removeImports;
|
|
|
|
for (const Import &import : assetImports)
|
|
|
|
removeImports.append(import);
|
|
|
|
rewriter->model()->changeImports({}, removeImports);
|
|
|
|
}
|
|
|
|
|
|
|
|
rewriter->forceAmend();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-01-23 12:31:22 +01:00
|
|
|
void DesignDocument::setEditor(Core::IEditor *editor)
|
|
|
|
{
|
|
|
|
m_textEditor = editor;
|
2017-10-17 17:43:53 +02:00
|
|
|
// if the user closed the file explicit we do not want to do anything with it anymore
|
2018-04-12 17:04:52 +02:00
|
|
|
|
|
|
|
connect(Core::EditorManager::instance(), &Core::EditorManager::aboutToSave,
|
|
|
|
this, [this](Core::IDocument *document) {
|
|
|
|
if (m_textEditor && m_textEditor->document() == document) {
|
2021-10-06 13:14:16 +02:00
|
|
|
if (m_documentModel && m_documentModel->rewriterView()) {
|
2024-12-13 10:56:56 +02:00
|
|
|
|
|
|
|
#ifdef QDS_USE_PROJECTSTORAGE
|
|
|
|
// TODO: ProjectStorage should handle this via Model somehow (QDS-14519)
|
|
|
|
#else
|
|
|
|
removeUnusedImports(rewriterView());
|
|
|
|
#endif
|
2018-04-12 17:04:52 +02:00
|
|
|
m_documentModel->rewriterView()->writeAuxiliaryData();
|
2021-10-06 13:14:16 +02:00
|
|
|
}
|
2018-04-12 17:04:52 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2017-10-17 17:43:53 +02:00
|
|
|
connect(Core::EditorManager::instance(), &Core::EditorManager::editorAboutToClose,
|
|
|
|
this, [this](Core::IEditor *editor) {
|
|
|
|
if (m_textEditor.data() == editor)
|
|
|
|
m_textEditor.clear();
|
|
|
|
});
|
|
|
|
|
2020-10-22 23:25:27 +03:00
|
|
|
connect(editor->document(), &Core::IDocument::filePathChanged, this, &DesignDocument::updateFileName);
|
2013-02-20 13:59:31 +01:00
|
|
|
|
2019-10-30 08:25:31 +01:00
|
|
|
updateActiveTarget();
|
|
|
|
updateActiveTarget();
|
2013-01-23 12:31:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Core::IEditor *DesignDocument::editor() const
|
|
|
|
{
|
|
|
|
return m_textEditor.data();
|
|
|
|
}
|
|
|
|
|
2014-07-23 19:10:38 +02:00
|
|
|
TextEditor::BaseTextEditor *DesignDocument::textEditor() const
|
2013-01-23 12:31:22 +01:00
|
|
|
{
|
2014-07-23 19:10:38 +02:00
|
|
|
return qobject_cast<TextEditor::BaseTextEditor*>(editor());
|
2013-01-23 12:31:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
QPlainTextEdit *DesignDocument::plainTextEdit() const
|
|
|
|
{
|
|
|
|
if (editor())
|
|
|
|
return qobject_cast<QPlainTextEdit*>(editor()->widget());
|
|
|
|
|
2018-07-24 23:56:45 +02:00
|
|
|
return nullptr;
|
2013-01-23 12:31:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
ModelNode DesignDocument::rootModelNode() const
|
|
|
|
{
|
|
|
|
return rewriterView()->rootModelNode();
|
|
|
|
}
|
|
|
|
|
|
|
|
void DesignDocument::undo()
|
|
|
|
{
|
2023-03-14 11:57:34 +01:00
|
|
|
if (rewriterView() && !rewriterView()->modificationGroupActive()) {
|
2013-01-23 12:31:22 +01:00
|
|
|
plainTextEdit()->undo();
|
2023-03-14 11:57:34 +01:00
|
|
|
rewriterView()->forceAmend();
|
|
|
|
}
|
2013-01-23 12:31:22 +01:00
|
|
|
|
|
|
|
viewManager().resetPropertyEditorView();
|
|
|
|
}
|
|
|
|
|
|
|
|
void DesignDocument::redo()
|
|
|
|
{
|
2023-03-14 11:57:34 +01:00
|
|
|
if (rewriterView() && !rewriterView()->modificationGroupActive()) {
|
2013-01-23 12:31:22 +01:00
|
|
|
plainTextEdit()->redo();
|
2023-03-14 11:57:34 +01:00
|
|
|
rewriterView()->forceAmend();
|
|
|
|
}
|
2013-01-23 12:31:22 +01:00
|
|
|
|
|
|
|
viewManager().resetPropertyEditorView();
|
|
|
|
}
|
|
|
|
|
2024-10-28 16:49:21 +01:00
|
|
|
static ProjectExplorer::Target *getActiveTarget(DesignDocument *designDocument)
|
2013-01-23 12:31:22 +01:00
|
|
|
{
|
2024-10-28 16:49:21 +01:00
|
|
|
auto currentProject = ProjectExplorer::ProjectManager::projectForFile(designDocument->fileName());
|
2013-01-23 12:31:22 +01:00
|
|
|
|
2014-03-05 15:17:43 +01:00
|
|
|
if (!currentProject)
|
2024-10-28 16:49:21 +01:00
|
|
|
currentProject = ProjectExplorer::ProjectTree::currentProject();
|
2014-03-05 15:17:43 +01:00
|
|
|
|
2013-01-23 12:31:22 +01:00
|
|
|
if (!currentProject)
|
2018-07-24 23:56:45 +02:00
|
|
|
return nullptr;
|
2013-01-23 12:31:22 +01:00
|
|
|
|
2024-10-28 16:49:21 +01:00
|
|
|
QObject::connect(ProjectExplorer::ProjectTree::instance(),
|
|
|
|
&ProjectExplorer::ProjectTree::currentProjectChanged,
|
|
|
|
designDocument,
|
|
|
|
&DesignDocument::updateActiveTarget,
|
|
|
|
Qt::UniqueConnection);
|
2013-01-23 12:31:22 +01:00
|
|
|
|
2024-10-28 16:49:21 +01:00
|
|
|
QObject::connect(currentProject,
|
|
|
|
&ProjectExplorer::Project::activeTargetChanged,
|
|
|
|
designDocument,
|
|
|
|
&DesignDocument::updateActiveTarget,
|
|
|
|
Qt::UniqueConnection);
|
2013-01-23 12:31:22 +01:00
|
|
|
|
2024-10-28 16:49:21 +01:00
|
|
|
auto target = currentProject->activeTarget();
|
2013-01-23 12:31:22 +01:00
|
|
|
|
2019-10-30 08:25:31 +01:00
|
|
|
if (!target || !target->kit()->isValid())
|
2018-07-24 23:56:45 +02:00
|
|
|
return nullptr;
|
2013-01-23 12:31:22 +01:00
|
|
|
|
2024-10-28 16:49:21 +01:00
|
|
|
QObject::connect(target,
|
|
|
|
&ProjectExplorer::Target::kitChanged,
|
|
|
|
designDocument,
|
|
|
|
&DesignDocument::updateActiveTarget,
|
|
|
|
Qt::UniqueConnection);
|
2014-03-26 19:41:51 +01:00
|
|
|
|
2019-10-30 08:25:31 +01:00
|
|
|
return target;
|
2013-01-23 12:31:22 +01:00
|
|
|
}
|
|
|
|
|
2019-10-30 08:25:31 +01:00
|
|
|
void DesignDocument::updateActiveTarget()
|
2013-01-23 12:31:22 +01:00
|
|
|
{
|
2019-10-30 08:25:31 +01:00
|
|
|
m_currentTarget = getActiveTarget(this);
|
|
|
|
viewManager().setNodeInstanceViewTarget(m_currentTarget);
|
2016-09-27 12:27:51 +02:00
|
|
|
}
|
|
|
|
|
2019-01-28 11:58:53 +01:00
|
|
|
void DesignDocument::contextHelp(const Core::IContext::HelpCallback &callback) const
|
2013-01-23 12:31:22 +01:00
|
|
|
{
|
2022-09-14 16:33:56 +02:00
|
|
|
if (auto v = view())
|
|
|
|
QmlDesignerPlugin::contextHelp(callback, v->contextHelpId());
|
2018-01-17 16:06:13 +01:00
|
|
|
else
|
2019-01-28 13:00:03 +01:00
|
|
|
callback({});
|
2013-01-23 12:31:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace QmlDesigner
|