QmlDesigner: Fix copy / paste bug

Fix a bug in calculating the scatter value when pasting an object. Also
some tweaks and clean ups in the same file.

Fixes: QDS-2982
Change-Id: Ic2847d03ccf03d188c5fbca2cd14bc74b9d20223
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Mahmoud Badri
2020-10-22 23:25:27 +03:00
parent 8d8473daf6
commit 2bf40dddfd

View File

@@ -217,6 +217,7 @@ Utils::FilePath DesignDocument::fileName() const
{ {
if (editor()) if (editor())
return editor()->document()->filePath(); return editor()->document()->filePath();
return Utils::FilePath(); return Utils::FilePath();
} }
@@ -239,14 +240,11 @@ void DesignDocument::loadDocument(QPlainTextEdit *edit)
{ {
Q_CHECK_PTR(edit); Q_CHECK_PTR(edit);
connect(edit, &QPlainTextEdit::undoAvailable, connect(edit, &QPlainTextEdit::undoAvailable, this, &DesignDocument::undoAvailable);
this, &DesignDocument::undoAvailable); connect(edit, &QPlainTextEdit::redoAvailable, this, &DesignDocument::redoAvailable);
connect(edit, &QPlainTextEdit::redoAvailable, connect(edit, &QPlainTextEdit::modificationChanged, this, &DesignDocument::dirtyStateChanged);
this, &DesignDocument::redoAvailable);
connect(edit, &QPlainTextEdit::modificationChanged,
this, &DesignDocument::dirtyStateChanged);
m_documentTextModifier.reset(new BaseTextEditModifier(dynamic_cast<TextEditor::TextEditorWidget*>(plainTextEdit()))); m_documentTextModifier.reset(new BaseTextEditModifier(qobject_cast<TextEditor::TextEditorWidget *>(plainTextEdit())));
connect(m_documentTextModifier.data(), &TextModifier::textChanged, this, &DesignDocument::updateQrcFiles); connect(m_documentTextModifier.data(), &TextModifier::textChanged, this, &DesignDocument::updateQrcFiles);
@@ -266,7 +264,6 @@ void DesignDocument::changeToDocumentModel()
viewManager().detachRewriterView(); viewManager().detachRewriterView();
viewManager().detachViewsExceptRewriterAndComponetView(); viewManager().detachViewsExceptRewriterAndComponetView();
m_inFileComponentModel.reset(); m_inFileComponentModel.reset();
viewManager().attachRewriterView(); viewManager().attachRewriterView();
@@ -299,7 +296,8 @@ void DesignDocument::updateQrcFiles()
ProjectExplorer::Project *currentProject = ProjectExplorer::SessionManager::projectForFile(fileName()); ProjectExplorer::Project *currentProject = ProjectExplorer::SessionManager::projectForFile(fileName());
if (currentProject) { if (currentProject) {
for (const Utils::FilePath &fileName : currentProject->files(ProjectExplorer::Project::SourceFiles)) { const auto srcFiles = currentProject->files(ProjectExplorer::Project::SourceFiles);
for (const Utils::FilePath &fileName : srcFiles) {
if (fileName.endsWith(".qrc")) if (fileName.endsWith(".qrc"))
QmlJS::ModelManagerInterface::instance()->updateQrcFile(fileName.toString()); QmlJS::ModelManagerInterface::instance()->updateQrcFile(fileName.toString());
} }
@@ -350,6 +348,7 @@ bool DesignDocument::isUndoAvailable() const
{ {
if (plainTextEdit()) if (plainTextEdit())
return plainTextEdit()->document()->isUndoAvailable(); return plainTextEdit()->document()->isUndoAvailable();
return false; return false;
} }
@@ -357,6 +356,7 @@ bool DesignDocument::isRedoAvailable() const
{ {
if (plainTextEdit()) if (plainTextEdit())
return plainTextEdit()->document()->isRedoAvailable(); return plainTextEdit()->document()->isRedoAvailable();
return false; return false;
} }
@@ -408,9 +408,8 @@ void DesignDocument::deleteSelected()
return; return;
} }
rewriterView()->executeInTransaction("DesignDocument::deleteSelected", [this](){ rewriterView()->executeInTransaction("DesignDocument::deleteSelected", [this]() {
QList<ModelNode> toDelete = view()->selectedModelNodes(); const QList<ModelNode> toDelete = view()->selectedModelNodes();
for (ModelNode node : toDelete) { for (ModelNode node : toDelete) {
if (node.isValid() && !node.isRootNode() && QmlObjectNode::isValidQmlObjectNode(node)) if (node.isValid() && !node.isRootNode() && QmlObjectNode::isValidQmlObjectNode(node))
QmlObjectNode(node).destroy(); QmlObjectNode(node).destroy();
@@ -442,32 +441,33 @@ static void scatterItem(const ModelNode &pastedNode, const ModelNode &targetNode
return; return;
bool scatter = false; bool scatter = false;
foreach (const ModelNode &childNode, targetNode.directSubModelNodes()) { for (const ModelNode &childNode : targetNode.directSubModelNodes()) {
if ((childNode.variantProperty("x").value() == pastedNode.variantProperty("x").value()) && if (childNode.variantProperty("x").value() == pastedNode.variantProperty("x").value() &&
(childNode.variantProperty("y").value() == pastedNode.variantProperty("y").value())) childNode.variantProperty("y").value() == pastedNode.variantProperty("y").value()) {
scatter = true; scatter = true;
break;
}
} }
if (!scatter) if (!scatter)
return; return;
if (offset == -2000) { if (offset == -2000) { // scatter in range
double x = pastedNode.variantProperty("x").value().toDouble(); double x = pastedNode.variantProperty("x").value().toDouble();
double y = pastedNode.variantProperty("y").value().toDouble(); double y = pastedNode.variantProperty("y").value().toDouble();
double targetWidth = 20;
double targetHeight = 20; const double scatterRange = 20.;
x = x + double(QRandomGenerator::global()->generate()) / RAND_MAX * targetWidth x += QRandomGenerator::global()->generateDouble() * scatterRange - scatterRange / 2;
- targetWidth / 2; y += QRandomGenerator::global()->generateDouble() * scatterRange - scatterRange / 2;
y = y + double(QRandomGenerator::global()->generate()) / RAND_MAX * targetHeight
- targetHeight / 2;
pastedNode.variantProperty("x").setValue(int(x));
pastedNode.variantProperty("y").setValue(int(y));
} else {
double x = pastedNode.variantProperty("x").value().toDouble();
double y = pastedNode.variantProperty("y").value().toDouble();
x = x + offset;
y = y + offset;
pastedNode.variantProperty("x").setValue(int(x)); pastedNode.variantProperty("x").setValue(int(x));
pastedNode.variantProperty("y").setValue(int(y)); pastedNode.variantProperty("y").setValue(int(y));
} else { // offset
int x = pastedNode.variantProperty("x").value().toInt();
int y = pastedNode.variantProperty("y").value().toInt();
x += offset;
y += offset;
pastedNode.variantProperty("x").setValue(x);
pastedNode.variantProperty("y").setValue(y);
} }
} }
@@ -495,7 +495,7 @@ void DesignDocument::paste()
if (!view.selectedModelNodes().isEmpty()) if (!view.selectedModelNodes().isEmpty())
targetNode = view.selectedModelNodes().constFirst(); targetNode = view.selectedModelNodes().constFirst();
//In case we copy and paste a selection we paste in the parent item // in case we copy and paste a selection we paste in the parent item
if ((view.selectedModelNodes().count() == selectedNodes.count()) && targetNode.isValid() && targetNode.hasParentProperty()) { if ((view.selectedModelNodes().count() == selectedNodes.count()) && targetNode.isValid() && targetNode.hasParentProperty()) {
targetNode = targetNode.parentProperty().parentModelNode(); targetNode = targetNode.parentProperty().parentModelNode();
} else { } else {
@@ -516,19 +516,20 @@ void DesignDocument::paste()
if (!targetNode.isValid()) if (!targetNode.isValid())
targetNode = view.rootModelNode(); targetNode = view.rootModelNode();
foreach (const ModelNode &node, selectedNodes) { for (const ModelNode &node : qAsConst(selectedNodes)) {
foreach (const ModelNode &node2, selectedNodes) { for (const ModelNode &node2 : qAsConst(selectedNodes)) {
if (node.isAncestorOf(node2)) if (node.isAncestorOf(node2))
selectedNodes.removeAll(node2); selectedNodes.removeAll(node2);
} }
} }
rewriterView()->executeInTransaction("DesignDocument::paste1", [&view, selectedNodes, targetNode](){ rewriterView()->executeInTransaction("DesignDocument::paste1", [&view, selectedNodes, targetNode]() {
QList<ModelNode> pastedNodeList; QList<ModelNode> pastedNodeList;
int offset = double(QRandomGenerator::global()->generate()) / RAND_MAX * 20 - 10; const double scatterRange = 20.;
int offset = QRandomGenerator::global()->generateDouble() * scatterRange - scatterRange / 2;
foreach (const ModelNode &node, selectedNodes) { for (const ModelNode &node : qAsConst(selectedNodes)) {
PropertyName defaultProperty(targetNode.metaInfo().defaultPropertyName()); PropertyName defaultProperty(targetNode.metaInfo().defaultPropertyName());
ModelNode pastedNode(view.insertModel(node)); ModelNode pastedNode(view.insertModel(node));
pastedNodeList.append(pastedNode); pastedNodeList.append(pastedNode);
@@ -572,11 +573,11 @@ void DesignDocument::paste()
PropertyName defaultProperty(targetNode.metaInfo().defaultPropertyName()); PropertyName defaultProperty(targetNode.metaInfo().defaultPropertyName());
scatterItem(pastedNode, targetNode); scatterItem(pastedNode, targetNode);
if (targetNode.metaInfo().propertyIsListProperty(defaultProperty)) { if (targetNode.metaInfo().propertyIsListProperty(defaultProperty))
targetNode.nodeListProperty(defaultProperty).reparentHere(pastedNode); targetNode.nodeListProperty(defaultProperty).reparentHere(pastedNode);
} else { else
qWarning() << "Cannot reparent to" << targetNode; qWarning() << "Cannot reparent to" << targetNode;
}
view.setSelectedModelNodes({pastedNode}); view.setSelectedModelNodes({pastedNode});
}); });
view.model()->clearMetaInfoCache(); view.model()->clearMetaInfoCache();
@@ -591,7 +592,6 @@ void DesignDocument::selectAll()
DesignDocumentView view; DesignDocumentView view;
currentModel()->attachView(&view); currentModel()->attachView(&view);
QList<ModelNode> allNodesExceptRootNode(view.allModelNodes()); QList<ModelNode> allNodesExceptRootNode(view.allModelNodes());
allNodesExceptRootNode.removeOne(view.rootModelNode()); allNodesExceptRootNode.removeOne(view.rootModelNode());
view.setSelectedModelNodes(allNodesExceptRootNode); view.setSelectedModelNodes(allNodesExceptRootNode);
@@ -607,7 +607,6 @@ void DesignDocument::setEditor(Core::IEditor *editor)
m_textEditor = editor; m_textEditor = editor;
// if the user closed the file explicit we do not want to do anything with it anymore // if the user closed the file explicit we do not want to do anything with it anymore
connect(Core::EditorManager::instance(), &Core::EditorManager::aboutToSave, connect(Core::EditorManager::instance(), &Core::EditorManager::aboutToSave,
this, [this](Core::IDocument *document) { this, [this](Core::IDocument *document) {
if (m_textEditor && m_textEditor->document() == document) { if (m_textEditor && m_textEditor->document() == document) {
@@ -622,8 +621,7 @@ void DesignDocument::setEditor(Core::IEditor *editor)
m_textEditor.clear(); m_textEditor.clear();
}); });
connect(editor->document(), &Core::IDocument::filePathChanged, connect(editor->document(), &Core::IDocument::filePathChanged, this, &DesignDocument::updateFileName);
this, &DesignDocument::updateFileName);
updateActiveTarget(); updateActiveTarget();
updateActiveTarget(); updateActiveTarget();
@@ -678,7 +676,6 @@ static Target *getActiveTarget(DesignDocument *designDocument)
if (!currentProject) if (!currentProject)
return nullptr; return nullptr;
QObject::connect(ProjectTree::instance(), &ProjectTree::currentProjectChanged, QObject::connect(ProjectTree::instance(), &ProjectTree::currentProjectChanged,
designDocument, &DesignDocument::updateActiveTarget, Qt::UniqueConnection); designDocument, &DesignDocument::updateActiveTarget, Qt::UniqueConnection);