From d2cc440c688540f85b7bd925625397511230f307 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 2 Jun 2022 17:05:26 +0300 Subject: [PATCH 01/96] QmlDesigner: Add checkerboard background in navigator preview tooltip Checkerboard helps visualizing alpha channel in previewed images. Fixes: QDS-7060 Change-Id: Idb0139f8d8fcbf595bbfba3b333cd3d49f18d8af Reviewed-by: Thomas Hartmann Reviewed-by: Mahmoud Badri Reviewed-by: --- .../components/navigator/checkers.png | Bin 0 -> 80 bytes .../components/navigator/navigator.qrc | 1 + .../components/navigator/previewtooltip.cpp | 14 ++- .../components/navigator/previewtooltip.ui | 88 +++++++++++++----- .../instances/nodeinstanceview.cpp | 12 ++- 5 files changed, 91 insertions(+), 24 deletions(-) create mode 100644 src/plugins/qmldesigner/components/navigator/checkers.png diff --git a/src/plugins/qmldesigner/components/navigator/checkers.png b/src/plugins/qmldesigner/components/navigator/checkers.png new file mode 100644 index 0000000000000000000000000000000000000000..72cb9f0350646967cbd0bdc5c69981796f43a2dd GIT binary patch literal 80 zcmeAS@N?(olHy`uVBq!ia0y~yVBi5^4h9AWhGIEpYX$}eaZeY=5RT~N3Kq8i2OAob f_*$Ac0?#lqSbc8ylogof3sUOo>gTe~DWM4fJ|+>W literal 0 HcmV?d00001 diff --git a/src/plugins/qmldesigner/components/navigator/navigator.qrc b/src/plugins/qmldesigner/components/navigator/navigator.qrc index fca836a09be..e595bae0f9b 100644 --- a/src/plugins/qmldesigner/components/navigator/navigator.qrc +++ b/src/plugins/qmldesigner/components/navigator/navigator.qrc @@ -13,5 +13,6 @@ export_unchecked.png export_unchecked@2x.png tooltip_placeholder.png + checkers.png diff --git a/src/plugins/qmldesigner/components/navigator/previewtooltip.cpp b/src/plugins/qmldesigner/components/navigator/previewtooltip.cpp index 800104bfb30..b352f1daa21 100644 --- a/src/plugins/qmldesigner/components/navigator/previewtooltip.cpp +++ b/src/plugins/qmldesigner/components/navigator/previewtooltip.cpp @@ -28,7 +28,8 @@ #include -#include +#include +#include namespace QmlDesigner { @@ -43,6 +44,17 @@ PreviewToolTip::PreviewToolTip(QWidget *parent) m_ui->typeLabel->setElideMode(Qt::ElideLeft); m_ui->infoLabel->setElideMode(Qt::ElideLeft); setStyleSheet(QString("QWidget { background-color: %1 }").arg(Utils::creatorTheme()->color(Utils::Theme::BackgroundColorNormal).name())); + m_ui->imageLabel->setStyleSheet("background-color: rgba(0, 0, 0, 0)"); + + static QPixmap checkers; + if (checkers.isNull()) { + checkers = {150, 150}; + QPainter painter(&checkers); + painter.setBrush(QPixmap(":/navigator/icon/checkers.png")); + painter.drawRect(0, 0, 150, 150); + } + m_ui->labelBackground->setPixmap(checkers); + } PreviewToolTip::~PreviewToolTip() diff --git a/src/plugins/qmldesigner/components/navigator/previewtooltip.ui b/src/plugins/qmldesigner/components/navigator/previewtooltip.ui index 1c06a248f03..c8520751a8e 100644 --- a/src/plugins/qmldesigner/components/navigator/previewtooltip.ui +++ b/src/plugins/qmldesigner/components/navigator/previewtooltip.ui @@ -81,28 +81,72 @@ 6 - - - - 0 - 0 - - - - - 150 - 150 - - - - QFrame::Box - - - QFrame::Plain - - - Qt::AlignCenter - + + + + + 0 + 0 + 150 + 150 + + + + + 0 + 0 + + + + + 150 + 150 + + + + QFrame::Box + + + QFrame::Plain + + + false + + + Qt::AlignCenter + + + + + + 0 + 0 + 150 + 150 + + + + + 0 + 0 + + + + + 150 + 150 + + + + QFrame::Box + + + QFrame::Plain + + + Qt::AlignCenter + + diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp index 29bf14d0269..db22d27fc3d 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp @@ -103,6 +103,7 @@ #include #include #include +#include #include @@ -1756,7 +1757,16 @@ void NodeInstanceView::timerEvent(QTimerEvent *event) QVariant NodeInstanceView::modelNodePreviewImageDataToVariant(const ModelNodePreviewImageData &imageData) { - static const QPixmap placeHolder(":/navigator/icon/tooltip_placeholder.png"); + static QPixmap placeHolder; + if (placeHolder.isNull()) { + QPixmap placeHolderSrc(":/navigator/icon/tooltip_placeholder.png"); + placeHolder = {150, 150}; + // Placeholder has transparency, but we don't want to show the checkerboard, so + // paint in the correct background color + placeHolder.fill(Utils::creatorTheme()->color(Utils::Theme::BackgroundColorNormal)); + QPainter painter(&placeHolder); + painter.drawPixmap(0, 0, 150, 150, placeHolderSrc); + } QVariantMap map; map.insert("type", imageData.type); From 7269aafbd8a1fddb7d43f783ac20b4d97bbc20c5 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Tue, 7 Jun 2022 13:39:25 +0300 Subject: [PATCH 02/96] QmlDesigner: Ensure material library is created when needed Added material library accessor to AbstractView, which creates the material library and moves existing materials under it in case it doesn't yet exist. Also added material assignment function to AbstractView. The reason these were added to AbstractView instead of being handled e.g. via custom notification in material editor is that they need to be called from multiple different views in the same transaction that triggers the need of material library. Fixes: QDS-7081 Change-Id: If2bb884f87d04c9f3599c2342df66ef51ec238ee Reviewed-by: Mahmoud Badri Reviewed-by: Thomas Hartmann --- .../components/edit3d/edit3dcanvas.cpp | 43 ++------- .../components/formeditor/dragtool.cpp | 15 +++ .../components/formeditor/dragtool.h | 1 + .../materialeditor/materialeditorview.cpp | 49 +--------- .../materialeditor/materialeditorview.h | 2 - .../navigator/navigatortreemodel.cpp | 83 +++++------------ .../components/navigator/navigatortreemodel.h | 1 - .../designercore/include/abstractview.h | 3 + .../designercore/model/abstractview.cpp | 92 +++++++++++++++++++ 9 files changed, 144 insertions(+), 145 deletions(-) diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp index efb9e24c1ca..02d798c1f6b 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp @@ -186,42 +186,17 @@ void Edit3DCanvas::dragEnterEvent(QDragEnterEvent *e) void Edit3DCanvas::dropEvent(QDropEvent *e) { - auto modelNode = QmlVisualNode::createQml3DNode(m_parent->view(), m_itemLibraryEntry, m_activeScene).modelNode(); - QTC_ASSERT(modelNode.isValid(), return); + m_parent->view()->executeInTransaction(__FUNCTION__, [&] { + auto modelNode = QmlVisualNode::createQml3DNode(m_parent->view(), m_itemLibraryEntry, m_activeScene).modelNode(); + QTC_ASSERT(modelNode.isValid(), return); - e->accept(); - m_parent->view()->setSelectedModelNode(modelNode); + e->accept(); + m_parent->view()->setSelectedModelNode(modelNode); - // if added node is a Model, assign it a material - if (modelNode.isSubclassOf("QtQuick3D.Model")) { - ModelNode matLib = m_parent->view()->modelNodeForId(Constants::MATERIAL_LIB_ID); - QTC_ASSERT(matLib.isValid(), return); - - const QList materials = matLib.directSubModelNodes(); - ModelNode material; - if (materials.size() > 0) { - for (const ModelNode &mat : materials) { - if (mat.isSubclassOf("QtQuick3D.Material")) { - material = mat; - break; - } - } - } - - // if no valid material, create a new default material - if (!material.isValid()) { - NodeMetaInfo metaInfo = m_parent->view()->model()->metaInfo("QtQuick3D.DefaultMaterial"); - material = m_parent->view()->createModelNode("QtQuick3D.DefaultMaterial", metaInfo.majorVersion(), - metaInfo.minorVersion()); - VariantProperty matNameProp = material.variantProperty("objectName"); - matNameProp.setValue("New Material"); - material.validId(); - matLib.defaultNodeListProperty().reparentHere(material); - } - - BindingProperty modelMatsProp = modelNode.bindingProperty("materials"); - modelMatsProp.setExpression(material.id()); - } + // if added node is a Model, assign it a material + if (modelNode.isSubclassOf("QtQuick3D.Model")) + m_parent->view()->assignMaterialTo3dModel(modelNode); + }); } void Edit3DCanvas::focusOutEvent(QFocusEvent *focusEvent) diff --git a/src/plugins/qmldesigner/components/formeditor/dragtool.cpp b/src/plugins/qmldesigner/components/formeditor/dragtool.cpp index c4a64adf8f5..819bf58b34a 100644 --- a/src/plugins/qmldesigner/components/formeditor/dragtool.cpp +++ b/src/plugins/qmldesigner/components/formeditor/dragtool.cpp @@ -33,6 +33,8 @@ #include #include "qmldesignerconstants.h" +#include + #include #include #include @@ -405,10 +407,23 @@ void DragTool::move(const QPointF &scenePosition, const QList & void DragTool::commitTransaction() { try { + handleView3dDrop(); m_rewriterTransaction.commit(); } catch (const RewritingException &e) { e.showException(); } } +void DragTool::handleView3dDrop() +{ + // If a View3D is dropped, we need to assign material to the included model + for (const QmlItemNode &dragNode : qAsConst(m_dragNodes)) { + if (dragNode.modelNode().isSubclassOf("QtQuick3D.View3D")) { + const QList models = dragNode.modelNode().subModelNodesOfType("QtQuick3D.Model"); + QTC_ASSERT(models.size() == 1, return); + view()->assignMaterialTo3dModel(models.at(0)); + } + } +} + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/formeditor/dragtool.h b/src/plugins/qmldesigner/components/formeditor/dragtool.h index 63d3de6e8f7..bb6f5622631 100644 --- a/src/plugins/qmldesigner/components/formeditor/dragtool.h +++ b/src/plugins/qmldesigner/components/formeditor/dragtool.h @@ -90,6 +90,7 @@ protected: void move(const QPointF &scenePos, const QList &itemList); void createDragNodes(const QMimeData *mimeData, const QPointF &scenePosition, const QList &itemList); void commitTransaction(); + void handleView3dDrop(); private: MoveManipulator m_moveManipulator; diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp index 29a74304d80..28c17d75611 100644 --- a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp +++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp @@ -78,47 +78,6 @@ MaterialEditorView::MaterialEditorView(QWidget *parent) m_stackedWidget->setMinimumWidth(250); } -void MaterialEditorView::ensureMaterialLibraryNode() -{ - if (!m_hasQuick3DImport) - return; - - m_materialLibrary = modelNodeForId(Constants::MATERIAL_LIB_ID); - if (m_materialLibrary.isValid()) - return; - - // create material library node - TypeName nodeType = rootModelNode().isSubclassOf("QtQuick3D.Node") ? "QtQuick3D.Node" : "QtQuick.Item"; - NodeMetaInfo metaInfo = model()->metaInfo(nodeType); - m_materialLibrary = createModelNode(nodeType, metaInfo.majorVersion(), metaInfo.minorVersion()); - - m_materialLibrary.setIdWithoutRefactoring(Constants::MATERIAL_LIB_ID); - rootModelNode().defaultNodeListProperty().reparentHere(m_materialLibrary); - - const QList materials = rootModelNode().subModelNodesOfType("QtQuick3D.Material"); - if (materials.isEmpty()) - return; - - RewriterTransaction transaction = beginRewriterTransaction( - "MaterialEditorView::ensureMaterialLibraryNode"); - - try { - // move all materials to under material library node - for (const ModelNode &node : materials) { - // if material has no name, set name to id - QString matName = node.variantProperty("objectName").value().toString(); - if (matName.isEmpty()) { - VariantProperty objNameProp = node.variantProperty("objectName"); - objNameProp.setValue(node.id()); - } - - m_materialLibrary.defaultNodeListProperty().reparentHere(node); - } - } catch (Exception &e) { - e.showException(); - } -} - MaterialEditorView::~MaterialEditorView() { qDeleteAll(m_qmlBackendHash); @@ -447,15 +406,13 @@ void MaterialEditorView::handleToolBarAction(int action) } case MaterialEditorContextObject::AddNewMaterial: { - ensureMaterialLibraryNode(); - executeInTransaction("MaterialEditorView:handleToolBarAction", [&] { NodeMetaInfo metaInfo = model()->metaInfo("QtQuick3D.DefaultMaterial"); ModelNode newMatNode = createModelNode("QtQuick3D.DefaultMaterial", metaInfo.majorVersion(), metaInfo.minorVersion()); renameMaterial(newMatNode, "New Material"); - m_materialLibrary.defaultNodeListProperty().reparentHere(newMatNode); + materialLibraryNode().defaultNodeListProperty().reparentHere(newMatNode); }); break; } @@ -759,8 +716,6 @@ void MaterialEditorView::duplicateMaterial(const ModelNode &material) { QTC_ASSERT(material.isValid(), return); - ensureMaterialLibraryNode(); - TypeName matType = material.type(); QmlObjectNode sourceMat(material); @@ -786,7 +741,7 @@ void MaterialEditorView::duplicateMaterial(const ModelNode &material) duplicateMat.setBindingProperty(prop.name(), prop.toBindingProperty().expression()); } - m_materialLibrary.defaultNodeListProperty().reparentHere(duplicateMat); + materialLibraryNode().defaultNodeListProperty().reparentHere(duplicateMat); }); } diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h index 3e8632d26f6..d9c9e4c1ba1 100644 --- a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h +++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h @@ -99,7 +99,6 @@ private: void highlightSupportedProperties(bool highlight = true); QString generateIdFromName(const QString &name); - void ensureMaterialLibraryNode(); void requestPreviewRender(); void applyMaterialToSelectedModels(const ModelNode &material, bool add = false); @@ -115,7 +114,6 @@ private: bool noValidSelection() const; ModelNode m_selectedMaterial; - ModelNode m_materialLibrary; QShortcut *m_updateShortcut = nullptr; int m_timerId = 0; QStackedWidget *m_stackedWidget = nullptr; diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp index 0a92f81d93f..d610014d5bf 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp @@ -686,18 +686,31 @@ void NavigatorTreeModel::handleItemLibraryItemDrop(const QMimeData *mimeData, in bool validContainer = false; ModelNode targetNode = targetProperty.parentModelNode(); - // don't allow dropping materials on any node but Models - QString itemType = QString::fromLatin1(itemLibraryEntry.typeName()); - if (itemType.startsWith("QtQuick3D.") && itemType.endsWith("Material") - && !targetNode.isSubclassOf("QtQuick3D.Model")) { - return; - } - QmlObjectNode newQmlObjectNode; m_view->executeInTransaction("NavigatorTreeModel::handleItemLibraryItemDrop", [&] { newQmlObjectNode = QmlItemNode::createQmlObjectNode(m_view, itemLibraryEntry, QPointF(), targetProperty, false); ModelNode newModelNode = newQmlObjectNode.modelNode(); if (newModelNode.isValid()) { + if (newModelNode.isSubclassOf("QtQuick3D.Material")) { + // Don't allow dropping materials on any node but Models + if (!targetNode.isSubclassOf("QtQuick3D.Model")) { + newQmlObjectNode.destroy(); + return; + } + // We can't have material initially parented if material library is created in this + // same transaction (rewriter will not allow it for some reason) + ModelNode matLib = m_view->modelNodeForId(Constants::MATERIAL_LIB_ID); + if (!matLib.isValid()) { + newQmlObjectNode.destroy(); + newQmlObjectNode = QmlItemNode::createQmlObjectNode( + m_view, itemLibraryEntry, QPointF(), NodeAbstractProperty(), false); + newModelNode = newQmlObjectNode.modelNode(); + if (!newModelNode.isValid()) + return; + } + m_view->assignMaterialTo3dModel(targetNode, newModelNode); + } + ChooseFromPropertyListDialog *dialog = ChooseFromPropertyListDialog::createIfNeeded( targetNode, newModelNode, Core::ICore::dialogParent()); if (dialog) { @@ -734,28 +747,10 @@ void NavigatorTreeModel::handleItemLibraryItemDrop(const QMimeData *mimeData, in if (newModelNode.isSubclassOf("QtQuick3D.View3D")) { const QList models = newModelNode.subModelNodesOfType("QtQuick3D.Model"); - QTC_ASSERT(models.size() == 1, return); - - assignMaterialToModel(models.at(0)); + m_view->assignMaterialTo3dModel(models.at(0)); } else if (newModelNode.isSubclassOf("QtQuick3D.Model")) { - assignMaterialToModel(newModelNode); - } - - // dropping a material on a model - if (newModelNode.isSubclassOf("QtQuick3D.Material") - && targetNode.isSubclassOf("QtQuick3D.Model")) { - // parent material to material library and assign it to target model - ModelNode matLib = m_view->modelNodeForId(Constants::MATERIAL_LIB_ID); - - QTC_ASSERT(matLib.isValid(), return); - - VariantProperty objName = newModelNode.variantProperty("objectName"); - objName.setValue("New Material"); - BindingProperty matsProp = targetNode.bindingProperty("materials"); - matsProp.setExpression(newModelNode.id()); - matLib.defaultNodeListProperty().reparentHere(newModelNode); - return; + m_view->assignMaterialTo3dModel(newModelNode); } if (!validContainer) { @@ -1089,40 +1084,6 @@ ModelNode NavigatorTreeModel::createTextureNode(const NodeAbstractProperty &targ return {}; } -// Add a material to a Quick3D.Model node -void NavigatorTreeModel::assignMaterialToModel(const ModelNode &node) -{ - ModelNode matLib = m_view->modelNodeForId(Constants::MATERIAL_LIB_ID); - - QTC_ASSERT(matLib.isValid(), return); - QTC_ASSERT(node.isSubclassOf("QtQuick3D.Model"), return); - - const QList materials = matLib.directSubModelNodes(); - ModelNode material; - if (materials.size() > 0) { - for (const ModelNode &mat : materials) { - if (mat.isSubclassOf("QtQuick3D.Material")) { - material = mat; - break; - } - } - } - - // if no valid material, create a new default material - if (!material.isValid()) { - NodeMetaInfo metaInfo = m_view->model()->metaInfo("QtQuick3D.DefaultMaterial"); - material = m_view->createModelNode("QtQuick3D.DefaultMaterial", metaInfo.majorVersion(), - metaInfo.minorVersion()); - VariantProperty matNameProp = material.variantProperty("objectName"); - matNameProp.setValue("New Material"); - material.validId(); - matLib.defaultNodeListProperty().reparentHere(material); - } - - BindingProperty modelMatsProp = node.bindingProperty("materials"); - modelMatsProp.setExpression(material.id()); -} - TypeName propertyType(const NodeAbstractProperty &property) { return property.parentModelNode().metaInfo().propertyTypeName(property.name()); diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h index 0fcb7aab3eb..96529816076 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h +++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h @@ -130,7 +130,6 @@ private: bool dropAsImage3dTexture(const ModelNode &targetNode, const NodeAbstractProperty &targetProp, const QString &imagePath, ModelNode &newNode, bool &outMoveNodesAfter); ModelNode createTextureNode(const NodeAbstractProperty &targetProp, const QString &imagePath); - void assignMaterialToModel(const ModelNode &node); QList nodesToPersistentIndex(const QList &modelNodes); void addImport(const QString &importName); QList filteredList(const NodeListProperty &property, bool filter, bool reverseOrder) const; diff --git a/src/plugins/qmldesigner/designercore/include/abstractview.h b/src/plugins/qmldesigner/designercore/include/abstractview.h index e37ed0fb4b6..18380aadb1a 100644 --- a/src/plugins/qmldesigner/designercore/include/abstractview.h +++ b/src/plugins/qmldesigner/designercore/include/abstractview.h @@ -259,6 +259,9 @@ public: void changeRootNodeType(const TypeName &type, int majorVersion, int minorVersion); + ModelNode materialLibraryNode(); + void assignMaterialTo3dModel(const ModelNode &modelNode, const ModelNode &materialNode = {}); + NodeInstanceView *nodeInstanceView() const; RewriterView *rewriterView() const; diff --git a/src/plugins/qmldesigner/designercore/model/abstractview.cpp b/src/plugins/qmldesigner/designercore/model/abstractview.cpp index 26040ba23d2..86dab970316 100644 --- a/src/plugins/qmldesigner/designercore/model/abstractview.cpp +++ b/src/plugins/qmldesigner/designercore/model/abstractview.cpp @@ -31,6 +31,10 @@ #include "nodeinstanceview.h" #include #include +#include +#include +#include +#include #ifndef QMLDESIGNER_TEST #include @@ -805,6 +809,94 @@ void AbstractView::changeRootNodeType(const TypeName &type, int majorVersion, in m_model.data()->d->changeRootNodeType(type, majorVersion, minorVersion); } +// Returns ModelNode for project's material library. +// If the material library doesn't exist yet, it is created and all existing materials are moved +// under material library. +// This function should be called only form inside a transaction, as it potentially does many +// changes to model. +ModelNode AbstractView::materialLibraryNode() +{ + ModelNode matLib = modelNodeForId(Constants::MATERIAL_LIB_ID); + if (matLib.isValid()) + return matLib; + + // Create material library node + TypeName nodeType = rootModelNode().isSubclassOf("QtQuick3D.Node") ? "QtQuick3D.Node" + : "QtQuick.Item"; + NodeMetaInfo metaInfo = model()->metaInfo(nodeType); + matLib = createModelNode(nodeType, metaInfo.majorVersion(), metaInfo.minorVersion()); + + matLib.setIdWithoutRefactoring(Constants::MATERIAL_LIB_ID); + rootModelNode().defaultNodeListProperty().reparentHere(matLib); + + const QList materials = rootModelNode().subModelNodesOfType("QtQuick3D.Material"); + if (materials.isEmpty()) + return matLib; + + // Move all materials to under material library node + for (const ModelNode &node : materials) { + // If material has no name, set name to id + QString matName = node.variantProperty("objectName").value().toString(); + if (matName.isEmpty()) { + VariantProperty objNameProp = node.variantProperty("objectName"); + objNameProp.setValue(node.id()); + } + + matLib.defaultNodeListProperty().reparentHere(node); + } + + return matLib; +} + +// Assigns given material to a 3D model. +// The assigned material is also inserted into material library if not already there. +// If given material is not valid, first existing material from material library is used, +// or if material library is empty, a new material is created. +// This function should be called only from inside a transaction, as it potentially does many +// changes to model. +void AbstractView::assignMaterialTo3dModel(const ModelNode &modelNode, const ModelNode &materialNode) +{ + QTC_ASSERT(modelNode.isValid() && modelNode.isSubclassOf("QtQuick3D.Model"), return); + + ModelNode matLib = materialLibraryNode(); + ModelNode newMaterialNode; + + if (materialNode.isValid() && materialNode.isSubclassOf("QtQuick3D.Material")) { + newMaterialNode = materialNode; + } else { + const QList materials = matLib.directSubModelNodes(); + if (materials.size() > 0) { + for (const ModelNode &mat : materials) { + if (mat.isSubclassOf("QtQuick3D.Material")) { + newMaterialNode = mat; + break; + } + } + } + + // if no valid material, create a new default material + if (!newMaterialNode.isValid()) { + NodeMetaInfo metaInfo = model()->metaInfo("QtQuick3D.DefaultMaterial"); + newMaterialNode = createModelNode("QtQuick3D.DefaultMaterial", metaInfo.majorVersion(), + metaInfo.minorVersion()); + newMaterialNode.validId(); + } + } + + QTC_ASSERT(newMaterialNode.isValid(), return); + + VariantProperty matNameProp = newMaterialNode.variantProperty("objectName"); + if (matNameProp.value().isNull()) + matNameProp.setValue("New Material"); + + if (!newMaterialNode.hasParentProperty() + || newMaterialNode.parentProperty() != matLib.defaultNodeListProperty()) { + matLib.defaultNodeListProperty().reparentHere(newMaterialNode); + } + BindingProperty modelMatsProp = modelNode.bindingProperty("materials"); + modelMatsProp.setExpression(newMaterialNode.id()); +} + ModelNode AbstractView::currentStateNode() const { if (model()) From 04b3962daf7f46e6ce053c79635eaabe6bb75f4c Mon Sep 17 00:00:00 2001 From: Brook Cronin Date: Tue, 31 May 2022 11:21:06 +0200 Subject: [PATCH 03/96] QmlDesigner: add new timeline animation icon Change-Id: I69efb2ed5a56fbf1848d00963ae70002f11b2e75 Reviewed-by: Alessandro Portale Reviewed-by: --- .../images/timeline-animation-16px.png | Bin 389 -> 296 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/plugins/qmldesigner/qtquickplugin/images/timeline-animation-16px.png b/src/plugins/qmldesigner/qtquickplugin/images/timeline-animation-16px.png index d4ecf00031f09ee20882ac301eb663031c71c0e4..31b8fed6668c63248c1edb37846174ed1895d85e 100644 GIT binary patch literal 296 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4rT@h1`S>QUe*XHm?$^HA3=9kvo-U3d65+9a-eN5V z9M0KWdoI6p&wf`Q>|NM6nOC22k^rxdOmw%+#b(oFh4ts{7PCEfa=kX2|CLVhx`dhk z94=gL(AdM^$J%c8BenIM_a=SLqnl0ts`}sl+4nYnxvrX?^m6X@uz0KQ&R<{c`CnLc iztv4F(qq~qwvNXfL2QfvykKBpVDNPHb6Mw<&;$VJje)iR delta 373 zcmZ3%)XF?TvYw5BfkFQB|3n4`MjuZX#}JF&-pd>PrUVMGKFBwZNLX~+p-D(6W5coo z0YL#Cy+=i)xVWXGJSrMYmg!5m>;Wxn@CQxPe&PDF;R=AC=Wd|9R_`*Y_-+ zb>@ua_cK0u&W%%oxT{~d9Px|PzqmrN{!sCsV>K=^|GgJf^4Cj#EBqDDmv!R#j3Xj( z2{QHtP0bxYO0@%=-#wOA%aXG_?B$a4-TlVt6ZV^rS#3IXHq7g#Z~TJA+c(@j_369R zCDpvHJG-Y`D%osx)g~_N)#Av@;b&Z3xRr05$l~7+Hm^|jt&XX*;PS}5jmc+1S8iUm zTjKnq?m0YyAKmjGZvVUVKwhYry`QG7QHOeDO)S?FeZGaUH{bOeG>1o?_uSds{-bH5 zPHl^`&CzV0^sP^=nWml)vbz$Y|51|rDTmS{<$F?lsy*YnI^H!jpE+r~CTZiQ`nBK1 g? Date: Wed, 8 Jun 2022 14:08:50 +0200 Subject: [PATCH 04/96] QmlDesigner: Make text label visible in 3d wizard Task-number: QDS-7054 Change-Id: I44a2d01c799b619b553c6b1e76c003324e7b80ba Reviewed-by: Thomas Hartmann --- .../projects/application-3d/Screen01.ui.qml.tpl | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/Screen01.ui.qml.tpl b/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/Screen01.ui.qml.tpl index 338621b72e0..24566ef2cc2 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/Screen01.ui.qml.tpl +++ b/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/Screen01.ui.qml.tpl @@ -16,12 +16,6 @@ Rectangle { color: Constants.backgroundColor - Text { - text: qsTr("Hello %{ProjectName}") - anchors.centerIn: parent - font.family: Constants.font.family - } - View3D { id: view3D anchors.fill: parent @@ -62,5 +56,12 @@ Rectangle { objectName: "Default Material" diffuseColor: "#4aee45" } + + Text { + text: qsTr("Hello %{ProjectName}") + anchors.top: parent.top + anchors.horizontalCenter: parent.horizontalCenter + anchors.topMargin: 100 + font.family: Constants.font.family } } From 55cf108f96564304db9b1b4951b93f24279451d6 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Wed, 8 Jun 2022 15:05:53 +0200 Subject: [PATCH 05/96] QmlDesigner: Update QDS version in template Change-Id: I0bfbd469d49568ec2be0b6b936c46bbc9160fbcb Reviewed-by: Thomas Hartmann --- .../studio_templates/projects/common/app.qmlproject.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/common/app.qmlproject.tpl b/share/qtcreator/qmldesigner/studio_templates/projects/common/app.qmlproject.tpl index 3d2490e8d9c..6b2195d6d1c 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/common/app.qmlproject.tpl +++ b/share/qtcreator/qmldesigner/studio_templates/projects/common/app.qmlproject.tpl @@ -90,7 +90,7 @@ Project { /* Required for deployment */ targetDirectory: "/opt/%{ProjectName}" - qdsVersion: "3.4" + qdsVersion: "3.5" quickVersion: "%{QtQuickVersion}" From 6d1478e1db134d37935b1c65adb226edf60e9f6e Mon Sep 17 00:00:00 2001 From: Artem Sokolovskii Date: Fri, 3 Jun 2022 15:10:46 +0200 Subject: [PATCH 06/96] Clang Format: Fix misplaced cursor after undo Fixed behavior, when after undo function cursor, jumps to the start of a file. Join the undo block generated by auto format with the last available undo block. This will place the cursor at the last edit position instead of the document beginning when triggering undo. Fixes: QTCREATORBUG-27608 Change-Id: I1bb630af00e997ac53f178594445293ceebcfa26 Reviewed-by: Reviewed-by: David Schulz --- src/plugins/cppeditor/cppeditordocument.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/cppeditor/cppeditordocument.cpp b/src/plugins/cppeditor/cppeditordocument.cpp index e79d8a17675..f8214401262 100644 --- a/src/plugins/cppeditor/cppeditordocument.cpp +++ b/src/plugins/cppeditor/cppeditordocument.cpp @@ -487,7 +487,7 @@ bool CppEditorDocument::save(QString *errorString, const Utils::FilePath &filePa if (!editedRanges.empty()) { QTextCursor cursor(document()); - cursor.beginEditBlock(); + cursor.joinPreviousEditBlock(); indenter()->format(editedRanges); cursor.endEditBlock(); } From 2e5892fbf0db0397b77556d3145faa68f8be11a2 Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Wed, 8 Jun 2022 14:58:28 +0200 Subject: [PATCH 07/96] QmlDesigner: Fix node component missing state prop Fix node components not showing the states property in the property editor. This is caused by querying majorVersion instead of majorQtQuickVersion. Task-number: QDS-6981 Change-Id: I0a87d921ce985f7fd58b92f526531c49622bb235 Reviewed-by: Mahmoud Badri Reviewed-by: --- .../propertyEditorQmlSources/QtQuick3D/Object3DPane.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Object3DPane.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Object3DPane.qml index 7cded878a1d..1a17b828081 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Object3DPane.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Object3DPane.qml @@ -33,7 +33,7 @@ PropertyEditorPane { id: itemPane ComponentSection { - showState: majorVersion >= 6 + showState: majorQtQuickVersion >= 6 } Column { From 1c6fa836480808a9fee2ddd9461fc4ad2c4b3058 Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Mon, 23 May 2022 00:04:31 +0200 Subject: [PATCH 08/96] QmlDesigner: Change FileResourcesModel Change FileResourcesModel to have one list of FileResourcesItem with properties absoluteFilePath, relativeFilePath and fileName instead of having two separated lists. Change-Id: Ib4b4884a6739658434844d2adb9c05c3871104e7 Reviewed-by: Thomas Hartmann Reviewed-by: Qt CI Bot --- .../imports/HelperWidgets/FontComboBox.qml | 4 +- .../imports/HelperWidgets/UrlChooser.qml | 33 +++++--- .../propertyeditor/fileresourcesmodel.cpp | 81 ++++++++++++------- .../propertyeditor/fileresourcesmodel.h | 54 ++++++++++--- 4 files changed, 115 insertions(+), 57 deletions(-) diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontComboBox.qml index 4b5f5caf4ac..6d9f56b178c 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontComboBox.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontComboBox.qml @@ -55,8 +55,8 @@ StudioControls.ComboBox { function setupModel() { var familyNames = ["Arial", "Times New Roman", "Courier", "Verdana", "Tahoma"] // default fonts - for (var i = 0; i < fileModel.fullPathModel.length; ++i) { // add custom fonts - var fontLoader = createFontLoader(fileModel.docPath + "/" + fileModel.fullPathModel[i]) + for (var i = 0; i < fileModel.model.length; ++i) { // add custom fonts + var fontLoader = createFontLoader(fileModel.docPath + "/" + fileModel.model[i].relativeFilePath) familyNames.push(fontLoader.name) } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml index f6766234d06..ee80d95a969 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml @@ -88,7 +88,8 @@ Row { } delegate: ItemDelegate { - required property string fullPath + required property string absoluteFilePath + required property string relativeFilePath required property string name required property int group required property int index @@ -150,9 +151,9 @@ Row { } ToolTip { - id: itemToolTip - visible: delegateRoot.hovered && comboBox.highlightedIndex === index - text: fullPath + id: delegateToolTip + visible: delegateRoot.hovered + text: delegateRoot.relativeFilePath delay: StudioTheme.Values.toolTipDelay height: StudioTheme.Values.toolTipHeight background: Rectangle { @@ -197,8 +198,9 @@ Row { if (root.backendValue.isBound) { comboBox.textValue = root.backendValue.expression } else { - var fullPath = root.backendValue.valueToString - comboBox.textValue = fullPath.substr(fullPath.lastIndexOf('/') + 1) + // Can be absolute or relative file path + var filePath = root.backendValue.valueToString + comboBox.textValue = filePath.substr(filePath.lastIndexOf('/') + 1) } comboBox.setCurrentText(comboBox.textValue) @@ -230,7 +232,7 @@ Row { // Check if value set by user matches with a name in the model then pick the full path let index = comboBox.find(inputValue) if (index !== -1) - inputValue = comboBox.items.get(index).model.fullPath + inputValue = comboBox.items.get(index).model.relativeFilePath root.backendValue.value = inputValue comboBox.dirty = false @@ -252,7 +254,7 @@ Row { let inputValue = comboBox.editText if (index >= 0) - inputValue = comboBox.items.get(index).model.fullPath + inputValue = comboBox.items.get(index).model.relativeFilePath if (root.backendValue.value !== inputValue) root.backendValue.value = inputValue @@ -284,17 +286,22 @@ Row { if (root.defaultItems !== undefined) { for (var i = 0; i < root.defaultItems.length; ++i) { comboBox.listModel.append({ - fullPath: root.defaultItems[i], + absoluteFilePath: "", + relativeFilePath: root.defaultItems[i], name: root.defaultItems[i], group: 0 }) } } - for (var j = 0; j < fileModel.fullPathModel.length; ++j) { + const myModel = fileModel.model + for (var j = 0; j < myModel.length; ++j) { + let item = myModel[j] + comboBox.listModel.append({ - fullPath: fileModel.fullPathModel[j], - name: fileModel.fileNameModel[j], + absoluteFilePath: item.absoluteFilePath, + relativeFilePath: item.relativeFilePath, + name: item.fileName, group: 1 }) } @@ -304,7 +311,7 @@ Row { Connections { target: fileModel - function onFullPathModelChanged() { + function onModelChanged() { root.createModel() comboBox.setCurrentText(comboBox.textValue) } diff --git a/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.cpp b/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.cpp index e15ff49744e..18fcba3efc2 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.cpp @@ -29,11 +29,11 @@ #include -#include #include +#include -#include #include +#include #include #include @@ -46,11 +46,13 @@ FileResourcesModel::FileResourcesModel(QObject *parent) , m_filter(QLatin1String("(*.*)")) { ProjectExplorer::Project *project = ProjectExplorer::SessionManager::projectForFile( - QmlDesigner::DocumentManager::currentFilePath()); + QmlDesigner::DocumentManager::currentFilePath()); if (project) { - connect(project, &ProjectExplorer::Project::fileListChanged, - this, &FileResourcesModel::refreshModel); + connect(project, + &ProjectExplorer::Project::fileListChanged, + this, + &FileResourcesModel::refreshModel); } } @@ -58,14 +60,14 @@ void FileResourcesModel::setModelNodeBackend(const QVariant &modelNodeBackend) { auto modelNodeBackendObject = modelNodeBackend.value(); - const auto backendObjectCasted = - qobject_cast(modelNodeBackendObject); + const auto backendObjectCasted = qobject_cast( + modelNodeBackendObject); if (backendObjectCasted) { QmlDesigner::Model *model = backendObjectCasted->qmlObjectNode().modelNode().model(); m_docPath = QDir{QFileInfo{model->fileUrl().toLocalFile()}.absolutePath()}; - m_path = QUrl::fromLocalFile(QmlDesigner::DocumentManager::currentProjectDirPath() - .toFileInfo().absoluteFilePath()); + m_path = QUrl::fromLocalFile( + QmlDesigner::DocumentManager::currentProjectDirPath().toFileInfo().absoluteFilePath()); } setupModel(); @@ -96,6 +98,8 @@ void FileResourcesModel::setPath(const QUrl &url) { m_path = url; setupModel(); + + emit pathChanged(url); } QUrl FileResourcesModel::path() const @@ -110,10 +114,13 @@ QUrl FileResourcesModel::docPath() const void FileResourcesModel::setFilter(const QString &filter) { - if (m_filter != filter) { - m_filter = filter; - setupModel(); - } + if (m_filter == filter) + return; + + m_filter = filter; + setupModel(); + + emit filterChanged(filter); } QString FileResourcesModel::filter() const @@ -121,14 +128,9 @@ QString FileResourcesModel::filter() const return m_filter; } -QStringList FileResourcesModel::fullPathModel() const +QList FileResourcesModel::model() const { - return m_fullPathModel; -} - -QStringList FileResourcesModel::fileNameModel() const -{ - return m_fileNameModel; + return m_model; } void FileResourcesModel::openFileDialog() @@ -164,6 +166,25 @@ void FileResourcesModel::openFileDialog() } } +QString FileResourcesModel::resolve(const QString &relative) const +{ + if (relative.startsWith('#')) + return relative; + + if (QDir::isAbsolutePath(relative)) + return relative; + + if (!QUrl::fromUserInput(relative, m_docPath.path()).isLocalFile()) + return relative; + + return QFileInfo(m_docPath, relative).absoluteFilePath(); +} + +bool FileResourcesModel::isLocal(const QString &path) const +{ + return QUrl::fromUserInput(path, m_docPath.path()).isLocalFile(); +} + void FileResourcesModel::registerDeclarativeType() { qmlRegisterType("HelperWidgets", 2, 0, "FileResourcesModel"); @@ -207,8 +228,7 @@ void FileResourcesModel::setupModel() void FileResourcesModel::refreshModel() { - m_fullPathModel.clear(); - m_fileNameModel.clear(); + m_model.clear(); QStringList filterList = m_filter.split(QLatin1Char(' ')); @@ -216,18 +236,17 @@ void FileResourcesModel::refreshModel() while (it.hasNext()) { QString absolutePath = it.next(); if (filterMetaIcons(absolutePath)) { - QString filePath = m_docPath.relativeFilePath(absolutePath); - m_fullPathModel.append(filePath); + QString relativeFilePath = m_docPath.relativeFilePath(absolutePath); + m_model.append( + FileResourcesItem(absolutePath, + relativeFilePath, + relativeFilePath.mid(relativeFilePath.lastIndexOf('/') + 1))); } } - Utils::sort(m_fullPathModel, [](const QString &s1, const QString &s2) { - return s1.mid(s1.lastIndexOf('/') + 1).toLower() < s2.mid(s2.lastIndexOf('/') + 1).toLower(); + Utils::sort(m_model, [](const FileResourcesItem &i1, const FileResourcesItem &i2) { + return i1.fileName().toLower() < i2.fileName().toLower(); }); - for (const QString &fullPath : qAsConst(m_fullPathModel)) - m_fileNameModel.append(fullPath.mid(fullPath.lastIndexOf('/') + 1)); - - emit fullPathModelChanged(); - emit fileNameModelChanged(); + emit modelChanged(); } diff --git a/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.h b/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.h index f0380c5a52e..5f49c936cb7 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.h +++ b/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.h @@ -33,17 +33,47 @@ #include #include +class FileResourcesItem +{ + Q_GADGET + + Q_PROPERTY(QString absoluteFilePath READ absoluteFilePath CONSTANT) + Q_PROPERTY(QString relativeFilePath READ relativeFilePath CONSTANT) + Q_PROPERTY(QString fileName READ fileName CONSTANT) + +public: + FileResourcesItem(const QString &absoluteFilePath, + const QString &relativeFilePath, + const QString &fileName) + : m_absoluteFilePath(absoluteFilePath) + , m_relativeFilePath(relativeFilePath) + , m_fileName(fileName) + {} + + FileResourcesItem() = default; + FileResourcesItem(const FileResourcesItem &other) = default; + FileResourcesItem &operator=(const FileResourcesItem &other) = default; + + const QString &absoluteFilePath() const { return m_absoluteFilePath; } + const QString &relativeFilePath() const { return m_relativeFilePath; } + const QString &fileName() const { return m_fileName; } + +private: + QString m_absoluteFilePath; + QString m_relativeFilePath; + QString m_fileName; +}; + class FileResourcesModel : public QObject { Q_OBJECT Q_PROPERTY(QString fileName READ fileName WRITE setFileNameStr NOTIFY fileNameChanged) - Q_PROPERTY(QString filter READ filter WRITE setFilter) + Q_PROPERTY(QString filter READ filter WRITE setFilter NOTIFY filterChanged) Q_PROPERTY(QVariant modelNodeBackendProperty READ modelNodeBackend WRITE setModelNodeBackend NOTIFY modelNodeBackendChanged) - Q_PROPERTY(QUrl path READ path WRITE setPath) - Q_PROPERTY(QUrl docPath READ docPath) - Q_PROPERTY(QStringList fullPathModel READ fullPathModel NOTIFY fullPathModelChanged) - Q_PROPERTY(QStringList fileNameModel READ fileNameModel NOTIFY fileNameModelChanged) + Q_PROPERTY(QUrl path READ path WRITE setPath NOTIFY pathChanged) + Q_PROPERTY(QUrl docPath READ docPath CONSTANT) + Q_PROPERTY(QList model READ model NOTIFY modelChanged) public: explicit FileResourcesModel(QObject *parent = nullptr); @@ -57,20 +87,23 @@ public: QUrl docPath() const; void setFilter(const QString &filter); QString filter() const; - QStringList fullPathModel() const; - QStringList fileNameModel() const; + QList model() const; + void setupModel(); void refreshModel(); Q_INVOKABLE void openFileDialog(); + Q_INVOKABLE QString resolve(const QString &relative) const; + Q_INVOKABLE bool isLocal(const QString &path) const; static void registerDeclarativeType(); signals: void fileNameChanged(const QUrl &fileName); + void filterChanged(const QString &filte); void modelNodeBackendChanged(); - void fullPathModelChanged(); - void fileNameModelChanged(); + void pathChanged(const QUrl &path); + void modelChanged(); private: QVariant modelNodeBackend() const; @@ -83,8 +116,7 @@ private: QString m_filter; QString m_currentPath; QString m_lastResourcePath; - QStringList m_fullPathModel; - QStringList m_fileNameModel; + QList m_model; }; QML_DECLARE_TYPE(FileResourcesModel) From bd51b4fdc2eb080b5883ebecea4a31320aa6ae2d Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Fri, 3 Jun 2022 14:34:11 +0200 Subject: [PATCH 09/96] QmlDesigner: Add tooltips to UrlChooser * Add tooltips with thumbnails to UrlChooser enable preview of image formats and meshes * Add property editor image provider which makes use of the image cache * Add mesh image cache collector in order to create thumbnails for meshes and built-in primitves * Fix typo in explicit image cache image provider * Add return value in time stamp provider if provided file does not exist Change-Id: I2290d2ace87ddd90e9899e343f2ad1ecd2993fdf Reviewed-by: Reviewed-by: Thomas Hartmann --- .../imports/HelperWidgets/UrlChooser.qml | 150 ++++++++++++++++-- src/plugins/qmldesigner/CMakeLists.txt | 4 +- .../propertyeditorimageprovider.cpp | 68 ++++++++ .../propertyeditorimageprovider.h | 48 ++++++ .../propertyeditorqmlbackend.cpp | 13 +- .../propertyeditor/propertyeditorqmlbackend.h | 3 +- .../propertyeditor/propertyeditorview.cpp | 24 +-- .../propertyeditor/propertyeditorview.h | 4 +- .../quick2propertyeditorview.cpp | 7 +- .../propertyeditor/quick2propertyeditorview.h | 2 +- .../explicitimagecacheimageprovider.cpp | 16 +- .../imagecache/meshimagecachecollector.cpp | 112 +++++++++++++ .../imagecache/meshimagecachecollector.h | 70 ++++++++ .../imagecache/smallimagecacheprovider.cpp | 87 ++++++++++ .../imagecache/smallimagecacheprovider.h | 68 ++++++++ .../imagecache/timestampprovider.cpp | 8 +- .../designercore/include/viewmanager.h | 3 +- .../designercore/model/viewmanager.cpp | 7 +- src/plugins/qmldesigner/qmldesignercore.cmake | 2 + src/plugins/qmldesigner/qmldesignerplugin.cpp | 3 +- src/plugins/qmldesigner/qmldesignerplugin.qbs | 6 + .../qmldesigner/qmldesignerprojectmanager.cpp | 33 ++-- .../qmldesigner/qmldesignerprojectmanager.h | 1 + 23 files changed, 682 insertions(+), 57 deletions(-) create mode 100644 src/plugins/qmldesigner/components/propertyeditor/propertyeditorimageprovider.cpp create mode 100644 src/plugins/qmldesigner/components/propertyeditor/propertyeditorimageprovider.h create mode 100644 src/plugins/qmldesigner/designercore/imagecache/meshimagecachecollector.cpp create mode 100644 src/plugins/qmldesigner/designercore/imagecache/meshimagecachecollector.h create mode 100644 src/plugins/qmldesigner/designercore/imagecache/smallimagecacheprovider.cpp create mode 100644 src/plugins/qmldesigner/designercore/imagecache/smallimagecacheprovider.h diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml index ee80d95a969..ec246f56f28 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml @@ -44,6 +44,9 @@ Row { // by QtQuick3D to add built-in primitives to the model. property var defaultItems + // Current item + property string absoluteFilePath: "" + FileResourcesModel { id: fileModel modelNodeBackendProperty: modelNodeBackend @@ -74,16 +77,64 @@ Row { visible: comboBox.hover && toolTip.text !== "" text: root.backendValue.valueToString delay: StudioTheme.Values.toolTipDelay - height: StudioTheme.Values.toolTipHeight + background: Rectangle { color: StudioTheme.Values.themeToolTipBackground border.color: StudioTheme.Values.themeToolTipOutline border.width: StudioTheme.Values.border } - contentItem: Text { - color: StudioTheme.Values.themeToolTipText - text: toolTip.text - verticalAlignment: Text.AlignVCenter + + contentItem: RowLayout { + spacing: 10 + + Item { + visible: thumbnail.status === Image.Ready + Layout.preferredWidth: 100 + Layout.preferredHeight: 100 + + Image { + id: checker + visible: !root.isMesh(root.absoluteFilePath) + anchors.fill: parent + fillMode: Image.Tile + source: "images/checkers.png" + } + + Image { + id: thumbnail + asynchronous: true + anchors.fill: parent + fillMode: Image.PreserveAspectFit + source: { + if (root.isBuiltInPrimitive(root.absoluteFilePath)) + return "image://qmldesigner_thumbnails/" + + root.absoluteFilePath.substring(1, root.absoluteFilePath.length) + + ".builtin" + + if (fileModel.isLocal(root.absoluteFilePath)) + return "image://qmldesigner_thumbnails/" + root.absoluteFilePath + + return root.absoluteFilePath + } + } + } + + ColumnLayout { + Text { + text: root.fileName(toolTip.text) + color: StudioTheme.Values.themeToolTipText + font: toolTip.font + } + + Text { + Layout.fillWidth: true + text: root.isBuiltInPrimitive(toolTip.text) ? qsTr("Built-in primitive") + : toolTip.text + font: toolTip.font + color: StudioTheme.Values.themeToolTipText + wrapMode: Text.WordWrap + } + } } } @@ -155,16 +206,62 @@ Row { visible: delegateRoot.hovered text: delegateRoot.relativeFilePath delay: StudioTheme.Values.toolTipDelay - height: StudioTheme.Values.toolTipHeight + background: Rectangle { color: StudioTheme.Values.themeToolTipBackground border.color: StudioTheme.Values.themeToolTipOutline border.width: StudioTheme.Values.border } - contentItem: Text { - color: StudioTheme.Values.themeToolTipText - text: itemToolTip.text - verticalAlignment: Text.AlignVCenter + + contentItem: RowLayout { + spacing: 10 + + Item { + visible: delegateThumbnail.status === Image.Ready + Layout.preferredWidth: 100 + Layout.preferredHeight: 100 + + Image { + id: delegateChecker + visible: !root.isMesh(delegateRoot.absoluteFilePath) + anchors.fill: parent + fillMode: Image.Tile + source: "images/checkers.png" + } + + Image { + id: delegateThumbnail + asynchronous: true + anchors.fill: parent + fillMode: Image.PreserveAspectFit + source: { + if (root.isBuiltInPrimitive(delegateRoot.name)) + return "image://qmldesigner_thumbnails/" + + delegateRoot.name.substring(1, delegateRoot.name.length) + + ".builtin" + + return "image://qmldesigner_thumbnails/" + delegateRoot.absoluteFilePath + } + } + } + + ColumnLayout { + Text { + text: delegateRoot.name + color: StudioTheme.Values.themeToolTipText + font: delegateToolTip.font + } + + Text { + Layout.fillWidth: true + text: root.isBuiltInPrimitive(delegateToolTip.text) + ? qsTr("Built-in primitive") + : delegateToolTip.text + font: delegateToolTip.font + color: StudioTheme.Values.themeToolTipText + wrapMode: Text.WordWrap + } + } } } } @@ -235,6 +332,10 @@ Row { inputValue = comboBox.items.get(index).model.relativeFilePath root.backendValue.value = inputValue + + if (!root.backendValue.isBound) + root.absoluteFilePath = fileModel.resolve(root.backendValue.value) + comboBox.dirty = false } @@ -259,6 +360,9 @@ Row { if (root.backendValue.value !== inputValue) root.backendValue.value = inputValue + if (!root.backendValue.isBound) + root.absoluteFilePath = fileModel.resolve(root.backendValue.value) + comboBox.dirty = false } @@ -275,6 +379,23 @@ Row { } } + function isBuiltInPrimitive(value) { + return value.startsWith('#') + } + + function isMesh(value) { + return root.isBuiltInPrimitive(value) + || root.hasFileExtension(root.fileName(value), "mesh") + } + + function hasFileExtension(fileName, extension) { + return fileName.split('.').pop() === extension + } + + function fileName(filePath) { + return filePath.substr(filePath.lastIndexOf('/') + 1) + } + function createModel() { // Build the combobox model comboBox.listModel.clear() @@ -322,6 +443,9 @@ Row { Component.onCompleted: { root.createModel() comboBox.updateTextValue() + + if (!root.backendValue.isBound) + root.absoluteFilePath = fileModel.resolve(root.backendValue.value) } function indexOf(model, criteria) { @@ -340,7 +464,7 @@ Row { if (comboBox.popup.opened && !root.backendValue.isBound) { var index = root.indexOf(comboBox.items, function(item) { - return item.fullPath === root.backendValue.value + return item.relativeFilePath === root.backendValue.value }) if (index !== -1) { @@ -359,8 +483,10 @@ Row { iconColor: root.textColor onClicked: { fileModel.openFileDialog() - if (fileModel.fileName !== "") + if (fileModel.fileName !== "") { root.backendValue.value = fileModel.fileName + root.absoluteFilePath = fileModel.resolve(root.backendValue.value) + } } } } diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index 1d56e323e9a..1ac2f477bf3 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -302,6 +302,7 @@ extend_qtc_plugin(QmlDesigner gradientpresetitem.cpp gradientpresetitem.h gradientpresetlistmodel.cpp gradientpresetlistmodel.h propertyeditorcontextobject.cpp propertyeditorcontextobject.h + propertyeditorimageprovider.cpp propertyeditorimageprovider.h propertyeditorqmlbackend.cpp propertyeditorqmlbackend.h propertyeditortransaction.cpp propertyeditortransaction.h propertyeditorvalue.cpp propertyeditorvalue.h @@ -389,7 +390,8 @@ extend_qtc_plugin(QmlDesigner SOURCES explicitimagecacheimageprovider.cpp explicitimagecacheimageprovider.h - + smallimagecacheprovider.cpp + smallimagecacheprovider.h ) extend_qtc_plugin(QmlDesigner diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorimageprovider.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorimageprovider.cpp new file mode 100644 index 00000000000..2037e1509e9 --- /dev/null +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorimageprovider.cpp @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "propertyeditorimageprovider.h" +#include "assetslibrarymodel.h" + +#include +#include +#include + +#include +#include + +namespace QmlDesigner { + +QQuickImageResponse *PropertyEditorImageProvider::requestImageResponse(const QString &id, + const QSize &requestedSize) +{ + const QString suffix = "*." + id.split('.').last().toLower(); + + if (suffix == "*.mesh") + return m_smallImageCacheProvider.requestImageResponse(id, requestedSize); + + if (suffix == "*.builtin") + return m_smallImageCacheProvider.requestImageResponse("#" + id.split('.').first(), + requestedSize); + + QImage image; + auto response = std::make_unique(image); + + QMetaObject::invokeMethod( + response.get(), + [response = QPointer(response.get()), image, suffix, id] { + if (AssetsLibraryModel::supportedImageSuffixes().contains(suffix)) + response->setImage(QImage(Utils::StyleHelper::dpiSpecificImageFile(id))); + else if (AssetsLibraryModel::supportedTexture3DSuffixes().contains(suffix)) + response->setImage(HdrImage{id}.image()); + else + response->abort(); + }, + Qt::QueuedConnection); + + return response.release(); +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorimageprovider.h b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorimageprovider.h new file mode 100644 index 00000000000..bb883e44504 --- /dev/null +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorimageprovider.h @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "imagecache/smallimagecacheprovider.h" + +#include + +namespace QmlDesigner { + +class PropertyEditorImageProvider : public QQuickAsyncImageProvider +{ +public: + PropertyEditorImageProvider(AsynchronousImageCache &imageCache, const QImage &defaultImage = {}) + : m_smallImageCacheProvider(imageCache, defaultImage) + {} + + QQuickImageResponse *requestImageResponse(const QString &id, + const QSize &requestedSize) override; + +private: + SmallImageCacheProvider m_smallImageCacheProvider; +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp index c73290bf76a..d00957fa8cf 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp @@ -95,9 +95,12 @@ static QObject *variantToQObject(const QVariant &value) namespace QmlDesigner { -PropertyEditorQmlBackend::PropertyEditorQmlBackend(PropertyEditorView *propertyEditor) : - m_view(new Quick2PropertyEditorView), m_propertyEditorTransaction(new PropertyEditorTransaction(propertyEditor)), m_dummyPropertyEditorValue(new PropertyEditorValue()), - m_contextObject(new PropertyEditorContextObject()) +PropertyEditorQmlBackend::PropertyEditorQmlBackend(PropertyEditorView *propertyEditor, + AsynchronousImageCache &imageCache) + : m_view(new Quick2PropertyEditorView(imageCache)) + , m_propertyEditorTransaction(new PropertyEditorTransaction(propertyEditor)) + , m_dummyPropertyEditorValue(new PropertyEditorValue()) + , m_contextObject(new PropertyEditorContextObject()) { m_view->engine()->setOutputWarningsToStandardError(QmlDesignerPlugin::instance() ->settings().value(DesignerSettingsKey::SHOW_PROPERTYEDITOR_WARNINGS).toBool()); @@ -115,7 +118,9 @@ PropertyEditorQmlBackend::PropertyEditorQmlBackend(PropertyEditorView *propertyE PropertyEditorQmlBackend::~PropertyEditorQmlBackend() = default; -void PropertyEditorQmlBackend::setupPropertyEditorValue(const PropertyName &name, PropertyEditorView *propertyEditor, const QString &type) +void PropertyEditorQmlBackend::setupPropertyEditorValue(const PropertyName &name, + PropertyEditorView *propertyEditor, + const QString &type) { QmlDesigner::PropertyName propertyName(name); propertyName.replace('.', '_'); diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.h b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.h index 983a917f2fd..7abfc550d87 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.h +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.h @@ -50,7 +50,8 @@ class PropertyEditorQmlBackend public: - PropertyEditorQmlBackend(PropertyEditorView *propertyEditor); + PropertyEditorQmlBackend(PropertyEditorView *propertyEditor, + class AsynchronousImageCache &imageCache); ~PropertyEditorQmlBackend(); void setup(const QmlObjectNode &fxObjectNode, const QString &stateName, const QUrl &qmlSpecificsFile, PropertyEditorView *propertyEditor); diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp index 7f190b62888..586c4dec054 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp @@ -69,16 +69,16 @@ static bool propertyIsAttachedLayoutProperty(const PropertyName &propertyName) return propertyName.contains("Layout."); } -PropertyEditorView::PropertyEditorView(QWidget *parent) : - AbstractView(parent), - m_parent(parent), - m_updateShortcut(nullptr), - m_timerId(0), - m_stackedWidget(new PropertyEditorWidget(parent)), - m_qmlBackEndForCurrentType(nullptr), - m_locked(false), - m_setupCompleted(false), - m_singleShotTimer(new QTimer(this)) +PropertyEditorView::PropertyEditorView(AsynchronousImageCache &imageCache) + : AbstractView() + , m_imageCache(imageCache) + , m_updateShortcut(nullptr) + , m_timerId(0) + , m_stackedWidget(new PropertyEditorWidget()) + , m_qmlBackEndForCurrentType(nullptr) + , m_locked(false) + , m_setupCompleted(false) + , m_singleShotTimer(new QTimer(this)) { m_qmlDir = PropertyEditorQmlBackend::propertyEditorResourcesPath(); @@ -117,7 +117,7 @@ void PropertyEditorView::setupPane(const TypeName &typeName) PropertyEditorQmlBackend *qmlBackend = m_qmlBackendHash.value(qmlFile.toString()); if (!qmlBackend) { - qmlBackend = new PropertyEditorQmlBackend(this); + qmlBackend = new PropertyEditorQmlBackend(this, m_imageCache); qmlBackend->initialSetup(typeName, qmlSpecificsFile, this); qmlBackend->setSource(qmlFile); @@ -484,7 +484,7 @@ void PropertyEditorView::setupQmlBackend() QString currentStateName = currentState().isBaseState() ? currentState().name() : QStringLiteral("invalid state"); if (!currentQmlBackend) { - currentQmlBackend = new PropertyEditorQmlBackend(this); + currentQmlBackend = new PropertyEditorQmlBackend(this, m_imageCache); m_stackedWidget->addWidget(currentQmlBackend->widget()); m_qmlBackendHash.insert(qmlFile.toString(), currentQmlBackend); diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h index 06e86fd57cd..3bbe5020506 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h @@ -51,7 +51,7 @@ class PropertyEditorView: public AbstractView Q_OBJECT public: - PropertyEditorView(QWidget *parent = nullptr); + PropertyEditorView(class AsynchronousImageCache &imageCache); ~PropertyEditorView() override; bool hasWidget() const override; @@ -119,8 +119,8 @@ private: //functions bool noValidSelection() const; private: //variables + AsynchronousImageCache &m_imageCache; ModelNode m_selectedNode; - QWidget *m_parent; QShortcut *m_updateShortcut; int m_timerId; PropertyEditorWidget* m_stackedWidget; diff --git a/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.cpp b/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.cpp index 35b74111d1e..08358353c10 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.cpp @@ -36,6 +36,7 @@ #include "gradientpresetdefaultlistmodel.h" #include "itemfiltermodel.h" #include "propertyeditorcontextobject.h" +#include "propertyeditorimageprovider.h" #include "propertyeditorqmlbackend.h" #include "propertyeditorvalue.h" #include "qmlanchorbindingproxy.h" @@ -45,11 +46,13 @@ namespace QmlDesigner { -Quick2PropertyEditorView::Quick2PropertyEditorView(QWidget *parent) : - QQuickWidget(parent) +Quick2PropertyEditorView::Quick2PropertyEditorView(AsynchronousImageCache &imageCache) + : QQuickWidget() { setResizeMode(QQuickWidget::SizeRootObjectToView); Theme::setupTheme(engine()); + engine()->addImageProvider("qmldesigner_thumbnails", + new PropertyEditorImageProvider(imageCache)); } void Quick2PropertyEditorView::registerQmlTypes() diff --git a/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.h b/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.h index 7bfc6f15580..ca92f2a6efd 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.h +++ b/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.h @@ -35,7 +35,7 @@ class Quick2PropertyEditorView : public QQuickWidget Q_OBJECT public: - explicit Quick2PropertyEditorView(QWidget *parent = nullptr); + explicit Quick2PropertyEditorView(class AsynchronousImageCache &imageCache); static void registerQmlTypes(); }; diff --git a/src/plugins/qmldesigner/designercore/imagecache/explicitimagecacheimageprovider.cpp b/src/plugins/qmldesigner/designercore/imagecache/explicitimagecacheimageprovider.cpp index d94221f3826..57a96f1c1c1 100644 --- a/src/plugins/qmldesigner/designercore/imagecache/explicitimagecacheimageprovider.cpp +++ b/src/plugins/qmldesigner/designercore/imagecache/explicitimagecacheimageprovider.cpp @@ -30,12 +30,12 @@ #include #include -namespace QmlDesigner { +namespace { -class ImageRespose : public QQuickImageResponse +class ImageResponse : public QQuickImageResponse { public: - ImageRespose(const QImage &defaultImage) + ImageResponse(const QImage &defaultImage) : m_image(defaultImage) {} @@ -57,14 +57,18 @@ private: QImage m_image; }; +} // namespace + +namespace QmlDesigner { + QQuickImageResponse *ExplicitImageCacheImageProvider::requestImageResponse(const QString &id, const QSize &) { - auto response = std::make_unique(m_defaultImage); + auto response = std::make_unique<::ImageResponse>(m_defaultImage); m_cache.requestImage( id, - [response = QPointer(response.get())](const QImage &image) { + [response = QPointer<::ImageResponse>(response.get())](const QImage &image) { QMetaObject::invokeMethod( response, [response, image] { @@ -73,7 +77,7 @@ QQuickImageResponse *ExplicitImageCacheImageProvider::requestImageResponse(const }, Qt::QueuedConnection); }, - [response = QPointer(response.get())](ImageCache::AbortReason abortReason) { + [response = QPointer<::ImageResponse>(response.get())](ImageCache::AbortReason abortReason) { QMetaObject::invokeMethod( response, [response, abortReason] { diff --git a/src/plugins/qmldesigner/designercore/imagecache/meshimagecachecollector.cpp b/src/plugins/qmldesigner/designercore/imagecache/meshimagecachecollector.cpp new file mode 100644 index 00000000000..7602ee7a119 --- /dev/null +++ b/src/plugins/qmldesigner/designercore/imagecache/meshimagecachecollector.cpp @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "meshimagecachecollector.h" +#include "imagecacheconnectionmanager.h" + +#include +#include +#include + +#include + +namespace QmlDesigner { + +MeshImageCacheCollector::MeshImageCacheCollector( + ImageCacheConnectionManager &connectionManager, + QSize captureImageMinimumSize, + QSize captureImageMaximumSize, + ImageCacheCollectorNullImageHandling nullImageHandling) + : m_imageCacheCollector(connectionManager, + captureImageMinimumSize, + captureImageMaximumSize, + nullImageHandling) +{} + +MeshImageCacheCollector::~MeshImageCacheCollector() = default; + +void MeshImageCacheCollector::start(Utils::SmallStringView name, + Utils::SmallStringView state, + const ImageCache::AuxiliaryData &auxiliaryData, + CaptureCallback captureCallback, + AbortCallback abortCallback) +{ + QTemporaryFile file(QDir::tempPath() + "/mesh-XXXXXX.qml"); + if (file.open()) { + QString qtQuickVersion; + QString qtQuick3DVersion; + QtSupport::QtVersion *qtVersion = QtSupport::QtKitAspect::qtVersion(target()->kit()); + if (qtVersion && qtVersion->qtVersion() < QtSupport::QtVersionNumber(6, 0, 0)) { + qtQuickVersion = "2.15"; + qtQuick3DVersion = "1.15"; + } + + QString content{ + R"(import QtQuick %1 + import QtQuick3D %2 + Node { + Model { + source: "%3" + DefaultMaterial { id: defaultMaterial; diffuseColor: "#ff999999" } + materials: [ defaultMaterial ] + } + })"}; + + content = content.arg(qtQuickVersion, qtQuick3DVersion, QString(name)); + + file.write(content.toUtf8()); + file.close(); + } + + Utils::PathString path{file.fileName()}; + + m_imageCacheCollector.start(path, state, auxiliaryData, captureCallback, abortCallback); +} + +std::pair MeshImageCacheCollector::createImage(Utils::SmallStringView, + Utils::SmallStringView, + const ImageCache::AuxiliaryData &) +{ + return {}; +} + +QIcon MeshImageCacheCollector::createIcon(Utils::SmallStringView, + Utils::SmallStringView, + const ImageCache::AuxiliaryData &) +{ + return {}; +} + +void MeshImageCacheCollector::setTarget(ProjectExplorer::Target *target) +{ + m_imageCacheCollector.setTarget(target); +} + +ProjectExplorer::Target *MeshImageCacheCollector::target() const +{ + return m_imageCacheCollector.target(); +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/imagecache/meshimagecachecollector.h b/src/plugins/qmldesigner/designercore/imagecache/meshimagecachecollector.h new file mode 100644 index 00000000000..c2cc63bfd9e --- /dev/null +++ b/src/plugins/qmldesigner/designercore/imagecache/meshimagecachecollector.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "imagecachecollectorinterface.h" +#include "imagecachecollector.h" + +namespace ProjectExplorer { +class Target; +} + +namespace QmlDesigner { + +class ImageCacheConnectionManager; + +class MeshImageCacheCollector final : public ImageCacheCollectorInterface +{ +public: + MeshImageCacheCollector(ImageCacheConnectionManager &connectionManager, + QSize captureImageMinimumSize, + QSize captureImageMaximumSize, + ImageCacheCollectorNullImageHandling nullImageHandling = {}); + + ~MeshImageCacheCollector(); + + void start(Utils::SmallStringView filePath, + Utils::SmallStringView state, + const ImageCache::AuxiliaryData &auxiliaryData, + CaptureCallback captureCallback, + AbortCallback abortCallback) override; + + std::pair createImage(Utils::SmallStringView filePath, + Utils::SmallStringView state, + const ImageCache::AuxiliaryData &auxiliaryData) override; + + QIcon createIcon(Utils::SmallStringView filePath, + Utils::SmallStringView state, + const ImageCache::AuxiliaryData &auxiliaryData) override; + + void setTarget(ProjectExplorer::Target *target); + ProjectExplorer::Target *target() const; + +private: + ImageCacheCollector m_imageCacheCollector; +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/imagecache/smallimagecacheprovider.cpp b/src/plugins/qmldesigner/designercore/imagecache/smallimagecacheprovider.cpp new file mode 100644 index 00000000000..36bd55c2fe6 --- /dev/null +++ b/src/plugins/qmldesigner/designercore/imagecache/smallimagecacheprovider.cpp @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "smallimagecacheprovider.h" + +#include + +#include + +namespace QmlDesigner { + +QQuickTextureFactory *ImageResponse::textureFactory() const +{ + return QQuickTextureFactory::textureFactoryForImage(m_image); +} + +void ImageResponse::setImage(const QImage &image) +{ + m_image = image; + + emit finished(); +} + +void ImageResponse::abort() +{ + emit finished(); +} + +QQuickImageResponse *SmallImageCacheProvider::requestImageResponse(const QString &id, const QSize &) +{ + auto response = std::make_unique(m_defaultImage); + + m_cache.requestSmallImage( + id, + [response = QPointer(response.get())](const QImage &image) { + QMetaObject::invokeMethod( + response, + [response, image] { + if (response) + response->setImage(image); + }, + Qt::QueuedConnection); + }, + [response = QPointer(response.get())]( + ImageCache::AbortReason abortReason) { + QMetaObject::invokeMethod( + response, + [response, abortReason] { + switch (abortReason) { + case ImageCache::AbortReason::Failed: + if (response) + response->abort(); + break; + case ImageCache::AbortReason::Abort: + response->cancel(); + break; + } + }, + Qt::QueuedConnection); + }); + + return response.release(); +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/imagecache/smallimagecacheprovider.h b/src/plugins/qmldesigner/designercore/imagecache/smallimagecacheprovider.h new file mode 100644 index 00000000000..05674143e67 --- /dev/null +++ b/src/plugins/qmldesigner/designercore/imagecache/smallimagecacheprovider.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include +#include + +namespace QmlDesigner { + +class AsynchronousImageCache; + +class ImageResponse : public QQuickImageResponse +{ +public: + ImageResponse(const QImage &defaultImage) + : m_image(defaultImage) + {} + + QQuickTextureFactory *textureFactory() const override; + + void setImage(const QImage &image); + + void abort(); + +private: + QImage m_image; +}; + +class SmallImageCacheProvider : public QQuickAsyncImageProvider +{ +public: + SmallImageCacheProvider(AsynchronousImageCache &imageCache, const QImage &defaultImage = {}) + : m_cache{imageCache} + , m_defaultImage(defaultImage) + {} + + QQuickImageResponse *requestImageResponse(const QString &id, + const QSize &requestedSize) override; + +private: + AsynchronousImageCache &m_cache; + QImage m_defaultImage; +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/imagecache/timestampprovider.cpp b/src/plugins/qmldesigner/designercore/imagecache/timestampprovider.cpp index 99573f175fb..67ccc7b75c0 100644 --- a/src/plugins/qmldesigner/designercore/imagecache/timestampprovider.cpp +++ b/src/plugins/qmldesigner/designercore/imagecache/timestampprovider.cpp @@ -28,11 +28,17 @@ #include #include +#include + namespace QmlDesigner { Sqlite::TimeStamp TimeStampProvider::timeStamp(Utils::SmallStringView name) const { - return QFileInfo{QString{name}}.lastModified().toSecsSinceEpoch(); + QFileInfo info{QString{name}}; + if (info.exists()) + return info.lastModified().toSecsSinceEpoch(); + + return {std::numeric_limits::max()}; } } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/include/viewmanager.h b/src/plugins/qmldesigner/designercore/include/viewmanager.h index dd77c07f459..1be785655a2 100644 --- a/src/plugins/qmldesigner/designercore/include/viewmanager.h +++ b/src/plugins/qmldesigner/designercore/include/viewmanager.h @@ -51,7 +51,8 @@ class ViewManagerData; class QMLDESIGNERCORE_EXPORT ViewManager { public: - ViewManager(class AsynchronousImageCache &imageCache); + ViewManager(class AsynchronousImageCache &imageCache, + class AsynchronousImageCache &meshImageCache); ~ViewManager(); void attachRewriterView(); diff --git a/src/plugins/qmldesigner/designercore/model/viewmanager.cpp b/src/plugins/qmldesigner/designercore/model/viewmanager.cpp index 8e96507cd53..2896c1571db 100644 --- a/src/plugins/qmldesigner/designercore/model/viewmanager.cpp +++ b/src/plugins/qmldesigner/designercore/model/viewmanager.cpp @@ -62,8 +62,9 @@ static Q_LOGGING_CATEGORY(viewBenchmark, "qtc.viewmanager.attach", QtWarningMsg) class ViewManagerData { public: - ViewManagerData(AsynchronousImageCache &imageCache) + ViewManagerData(AsynchronousImageCache &imageCache, AsynchronousImageCache &meshImageCache) : itemLibraryView(imageCache) + , propertyEditorView(meshImageCache) {} InteractiveConnectionManager connectionManager; @@ -94,8 +95,8 @@ static CrumbleBar *crumbleBar() { return QmlDesignerPlugin::instance()->mainWidget()->crumbleBar(); } -ViewManager::ViewManager(AsynchronousImageCache &imageCache) - : d(std::make_unique(imageCache)) +ViewManager::ViewManager(AsynchronousImageCache &imageCache, AsynchronousImageCache &meshImageCache) + : d(std::make_unique(imageCache, meshImageCache)) { d->formEditorView.setGotoErrorCallback([this](int line, int column) { d->textEditorView.gotoCursorPosition(line, column); diff --git a/src/plugins/qmldesigner/qmldesignercore.cmake b/src/plugins/qmldesigner/qmldesignercore.cmake index 83870a36fee..9a2b0b6f3e6 100644 --- a/src/plugins/qmldesigner/qmldesignercore.cmake +++ b/src/plugins/qmldesigner/qmldesignercore.cmake @@ -123,6 +123,8 @@ function(extend_with_qmldesigner_core target_name) imagecache/imagecachegeneratorinterface.h imagecache/imagecachestorage.h imagecache/imagecachestorageinterface.h + imagecache/meshimagecachecollector.cpp + imagecache/meshimagecachecollector.h imagecache/synchronousimagecache.cpp imagecache/timestampprovider.cpp imagecache/timestampprovider.h diff --git a/src/plugins/qmldesigner/qmldesignerplugin.cpp b/src/plugins/qmldesigner/qmldesignerplugin.cpp index e6f40d14fc6..5ab50135eb2 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.cpp +++ b/src/plugins/qmldesigner/qmldesignerplugin.cpp @@ -137,7 +137,8 @@ class QmlDesignerPluginPrivate { public: QmlDesignerProjectManager projectManager; - ViewManager viewManager{projectManager.asynchronousImageCache()}; + ViewManager viewManager{projectManager.asynchronousImageCache(), + projectManager.asynchronousMeshImageCache()}; DocumentManager documentManager; ShortCutManager shortCutManager; SettingsPage settingsPage; diff --git a/src/plugins/qmldesigner/qmldesignerplugin.qbs b/src/plugins/qmldesigner/qmldesignerplugin.qbs index ed113d4fe57..5266a146a3d 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.qbs +++ b/src/plugins/qmldesigner/qmldesignerplugin.qbs @@ -442,6 +442,10 @@ Project { "imagecache/imagecachegenerator.h", "imagecache/imagecachestorageinterface.h", "imagecache/imagecachestorage.h", + "imagecache/meshimagecachecollector.cpp", + "imagecache/meshimagecachecollector.h", + "imagecache/smallimagecacheprovider.cpp", + "imagecache/smallimagecacheprovider.h", "imagecache/synchronousimagecache.cpp", "imagecache/timestampproviderinterface.h", "imagecache/timestampprovider.h", @@ -737,6 +741,8 @@ Project { "propertyeditor/gradientpresetlistmodel.h", "propertyeditor/propertyeditorcontextobject.cpp", "propertyeditor/propertyeditorcontextobject.h", + "propertyeditor/propertyeditorimageprovider.cpp", + "propertyeditor/propertyeditorimageprovider.h", "propertyeditor/propertyeditortransaction.cpp", "propertyeditor/propertyeditortransaction.h", "propertyeditor/propertyeditorvalue.cpp", diff --git a/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp b/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp index 43070221bcf..90e54ba65bb 100644 --- a/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp +++ b/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp @@ -51,7 +51,8 @@ #include #include #include -#include +#include +#include #include @@ -79,7 +80,7 @@ QString defaultImagePath() return qobject_cast<::QmlProjectManager::QmlBuildSystem *>(target->buildSystem()); } -class TimeStampProvider : public TimeStampProviderInterface +class PreviewTimeStampProvider : public TimeStampProviderInterface { public: Sqlite::TimeStamp timeStamp(Utils::SmallStringView) const override @@ -102,15 +103,18 @@ class QmlDesignerProjectManager::ImageCacheData { public: Sqlite::Database database{Utils::PathString{ - Core::ICore::cacheResourcePath("imagecache-v2.db").toString()}, + Core::ICore::cacheResourcePath("imagecache-v2.db").toString()}, Sqlite::JournalMode::Wal, Sqlite::LockingMode::Normal}; ImageCacheStorage storage{database}; ImageCacheConnectionManager connectionManager; - ImageCacheCollector collector{connectionManager, QSize{300, 300}, QSize{600, 600}}; - ImageCacheGenerator generator{collector, storage}; + MeshImageCacheCollector meshImageCollector{connectionManager, QSize{300, 300}, QSize{600, 600}}; + ImageCacheGenerator meshGenerator{meshImageCollector, storage}; + ImageCacheCollector nodeInstanceCollector{connectionManager, QSize{300, 300}, QSize{600, 600}}; + ImageCacheGenerator nodeInstanceGenerator{nodeInstanceCollector, storage}; TimeStampProvider timeStampProvider; - AsynchronousImageCache asynchronousImageCache{storage, generator, timeStampProvider}; + AsynchronousImageCache asynchronousImageCache{storage, nodeInstanceGenerator, timeStampProvider}; + AsynchronousImageCache asynchronousMeshImageCache{storage, meshGenerator, timeStampProvider}; }; class QmlDesignerProjectManager::PreviewImageCacheData @@ -135,7 +139,7 @@ public: QSize{300, 300}, QSize{1000, 1000}, ImageCacheCollectorNullImageHandling::DontCaptureNullImage}; - TimeStampProvider timeStampProvider; + PreviewTimeStampProvider timeStampProvider; AsynchronousImageFactory factory; ::ProjectExplorer::Target *activeTarget = nullptr; }; @@ -180,6 +184,11 @@ AsynchronousImageCache &QmlDesignerProjectManager::asynchronousImageCache() return imageCacheData()->asynchronousImageCache; } +AsynchronousImageCache &QmlDesignerProjectManager::asynchronousMeshImageCache() +{ + return imageCacheData()->asynchronousMeshImageCache; +} + void QmlDesignerProjectManager::editorOpened(::Core::IEditor *) {} void QmlDesignerProjectManager::currentEditorChanged(::Core::IEditor *) @@ -218,17 +227,21 @@ QmlDesignerProjectManager::ImageCacheData *QmlDesignerProjectManager::imageCache m_imageCacheData = std::make_unique(); auto setTargetInImageCache = [imageCacheData = m_imageCacheData.get()](ProjectExplorer::Target *target) { - if (target == imageCacheData->collector.target()) + if (target == imageCacheData->nodeInstanceCollector.target()) return; if (target) imageCacheData->asynchronousImageCache.clean(); - imageCacheData->collector.setTarget(target); + // TODO wrap in function in image cache data + imageCacheData->meshImageCollector.setTarget(target); + imageCacheData->nodeInstanceCollector.setTarget(target); }; if (auto project = ProjectExplorer::SessionManager::startupProject(); project) { - m_imageCacheData->collector.setTarget(project->activeTarget()); + // TODO wrap in function in image cache data + m_imageCacheData->meshImageCollector.setTarget(project->activeTarget()); + m_imageCacheData->nodeInstanceCollector.setTarget(project->activeTarget()); QObject::connect(project, &ProjectExplorer::Project::activeTargetChanged, this, diff --git a/src/plugins/qmldesigner/qmldesignerprojectmanager.h b/src/plugins/qmldesigner/qmldesignerprojectmanager.h index 6b94fa9e6f4..68cd809be3d 100644 --- a/src/plugins/qmldesigner/qmldesignerprojectmanager.h +++ b/src/plugins/qmldesigner/qmldesignerprojectmanager.h @@ -59,6 +59,7 @@ public: void registerPreviewImageProvider(QQmlEngine *engine) const; class AsynchronousImageCache &asynchronousImageCache(); + class AsynchronousImageCache &asynchronousMeshImageCache(); private: void editorOpened(::Core::IEditor *editor); From 519f6fbda11cd6849e2ddbc804e20af2d2030012 Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Fri, 3 Jun 2022 13:40:39 +0200 Subject: [PATCH 10/96] QmlDesigner: Add drag'n'drop to PropertyEditorView * Implement drag and drop for UrlChooser and FontComboBox * Change the style of controls accepting drag payload and drag hovering. Utilize states for those styles. * Fix aspect ratio of drag pixmap * Fix issue that causes drag to continue after pressing the escape key Change-Id: I5cf67175abe936e60e8af00fa8c2f7a2dec355b3 Reviewed-by: Thomas Hartmann Reviewed-by: Reviewed-by: Mahmoud Badri --- .../imports/HelperWidgets/FontComboBox.qml | 34 ++++++++++++-- .../imports/HelperWidgets/UrlChooser.qml | 27 +++++++++++- .../imports/StudioControls/CheckIndicator.qml | 13 +++++- .../imports/StudioControls/ComboBox.qml | 44 ++++++++++++------- .../imports/StudioControls/ComboBoxInput.qml | 17 ++++--- .../imports/StudioControls/FilterComboBox.qml | 32 +++++++++++++- .../assetslibraryiconprovider.cpp | 2 +- .../assetslibrary/assetslibrarywidget.cpp | 4 -- .../itemlibrary/itemlibrarywidget.cpp | 4 -- .../propertyeditorcontextobject.cpp | 13 ++++++ .../propertyeditorcontextobject.h | 8 ++++ .../propertyeditor/propertyeditorvalue.cpp | 2 + .../propertyeditor/propertyeditorview.cpp | 27 +++++++++--- .../propertyeditor/propertyeditorview.h | 3 ++ .../qmldesigner/designercore/model/model.cpp | 4 +- 15 files changed, 191 insertions(+), 43 deletions(-) diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontComboBox.qml index 6d9f56b178c..8c05fa2f878 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontComboBox.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontComboBox.qml @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2022 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. @@ -36,6 +36,7 @@ StudioControls.ComboBox { property string fontFilter: "*.ttf *.otf" property bool showExtendedFunctionButton: true + hasActiveDrag: activeDragSuffix !== "" && root.fontFilter.includes(activeDragSuffix) labelColor: colorLogic.textColor editable: true @@ -47,16 +48,43 @@ StudioControls.ComboBox { filter: root.fontFilter } + DropArea { + id: dropArea + + anchors.fill: parent + + property string assetPath: "" + + onEntered: function(drag) { + dropArea.assetPath = drag.getDataAsString(drag.keys[0]).split(",")[0] + drag.accepted = root.hasActiveDrag + root.hasActiveHoverDrag = drag.accepted + } + + onExited: root.hasActiveHoverDrag = false + + onDropped: function(drop) { + drop.accepted = root.hasActiveHoverDrag + var fontLoader = root.createFontLoader("file:///" + dropArea.assetPath) + root.backendValue.value = fontLoader.name + root.currentIndex = root.find(root.backendValue.value) + root.hasActiveHoverDrag = false + root.backendValue.commitDrop(dropArea.assetPath) + } + } + function createFontLoader(fontUrl) { return Qt.createQmlObject('import QtQuick 2.0; FontLoader { source: "' + fontUrl + '"; }', root, "dynamicFontLoader") } function setupModel() { - var familyNames = ["Arial", "Times New Roman", "Courier", "Verdana", "Tahoma"] // default fonts + // default fonts + var familyNames = ["Arial", "Times New Roman", "Courier", "Verdana", "Tahoma"] for (var i = 0; i < fileModel.model.length; ++i) { // add custom fonts - var fontLoader = createFontLoader(fileModel.docPath + "/" + fileModel.model[i].relativeFilePath) + var fontLoader = root.createFontLoader(fileModel.docPath + "/" + + fileModel.model[i].relativeFilePath) familyNames.push(fontLoader.name) } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml index ec246f56f28..ecb4936bd7d 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2022 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. @@ -63,6 +63,7 @@ Row { property ListModel listModel: ListModel {} + hasActiveDrag: activeDragSuffix !== "" && root.filter.includes(activeDragSuffix) implicitWidth: StudioTheme.Values.singleControlColumnWidth + StudioTheme.Values.actionIndicatorWidth width: implicitWidth @@ -72,6 +73,30 @@ Row { // when the combobox is closed by focusing on some other control. property int hoverIndex: -1 + DropArea { + id: dropArea + + anchors.fill: parent + + property string assetPath: "" + + onEntered: function(drag) { + dropArea.assetPath = drag.getDataAsString(drag.keys[0]).split(",")[0] + drag.accepted = comboBox.hasActiveDrag + comboBox.hasActiveHoverDrag = drag.accepted + } + + onExited: comboBox.hasActiveHoverDrag = false + + onDropped: function(drop) { + drop.accepted = comboBox.hasActiveHoverDrag + comboBox.editText = dropArea.assetPath + comboBox.accepted() + comboBox.hasActiveHoverDrag = false + root.backendValue.commitDrop(dropArea.assetPath) + } + } + ToolTip { id: toolTip visible: comboBox.hover && toolTip.text !== "" diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/CheckIndicator.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/CheckIndicator.qml index 2d3bb74c3f7..5af0f5fe6e9 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/CheckIndicator.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/CheckIndicator.qml @@ -37,6 +37,9 @@ Rectangle { property bool pressed: checkIndicatorMouseArea.containsPress property bool checked: false + property bool hasActiveDrag: myControl.hasActiveDrag ?? false + property bool hasActiveHoverDrag: myControl.hasActiveHoverDrag ?? false + color: StudioTheme.Values.themeControlBackground border.width: 0 @@ -79,12 +82,20 @@ Rectangle { name: "default" when: myControl.enabled && checkIndicator.enabled && !myControl.edit && !checkIndicator.hover && !myControl.hover && !myControl.drag - && !checkIndicator.checked + && !checkIndicator.checked && !checkIndicator.hasActiveDrag PropertyChanges { target: checkIndicator color: StudioTheme.Values.themeControlBackground } }, + State { + name: "dragHover" + when: myControl.enabled && checkIndicator.hasActiveHoverDrag + PropertyChanges { + target: checkIndicator + color: StudioTheme.Values.themeControlBackgroundInteraction + } + }, State { name: "globalHover" when: myControl.enabled && checkIndicator.enabled && !myControl.drag diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBox.qml index 70cbdf000ec..f57a1c404e3 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBox.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBox.qml @@ -50,9 +50,6 @@ T.ComboBox { property alias textInput: comboBoxInput - property int borderWidth: myComboBox.hasActiveHoverDrag ? StudioTheme.Values.borderHover - : StudioTheme.Values.border - signal compressedActivated(int index, int reason) enum ActivatedReason { EditingFinished, Other } @@ -61,7 +58,7 @@ T.ComboBox { height: StudioTheme.Values.defaultControlHeight leftPadding: actionIndicator.width - rightPadding: popupIndicator.width + myComboBox.borderWidth + rightPadding: popupIndicator.width + StudioTheme.Values.border font.pixelSize: StudioTheme.Values.myFontSize wheelEnabled: false @@ -91,7 +88,6 @@ T.ComboBox { myControl: myComboBox text: myComboBox.editText - borderWidth: myComboBox.borderWidth onEditingFinished: { comboBoxInput.deselect() @@ -113,16 +109,16 @@ T.ComboBox { myControl: myComboBox myPopup: myComboBox.popup x: comboBoxInput.x + comboBoxInput.width - y: myComboBox.borderWidth - width: StudioTheme.Values.checkIndicatorWidth - myComboBox.borderWidth - height: StudioTheme.Values.checkIndicatorHeight - myComboBox.borderWidth * 2 + y: StudioTheme.Values.border + width: StudioTheme.Values.checkIndicatorWidth - StudioTheme.Values.border + height: StudioTheme.Values.checkIndicatorHeight - StudioTheme.Values.border * 2 } background: Rectangle { id: comboBoxBackground color: StudioTheme.Values.themeControlBackground border.color: StudioTheme.Values.themeControlOutline - border.width: myComboBox.borderWidth + border.width: StudioTheme.Values.border x: actionIndicator.width width: myComboBox.width - actionIndicator.width height: myComboBox.height @@ -149,7 +145,7 @@ T.ComboBox { width: comboBoxPopup.width - comboBoxPopup.leftPadding - comboBoxPopup.rightPadding - (comboBoxPopupScrollBar.visible ? comboBoxPopupScrollBar.contentItem.implicitWidth + 2 : 0) // TODO Magic number - height: StudioTheme.Values.height - 2 * myComboBox.borderWidth + height: StudioTheme.Values.height - 2 * StudioTheme.Values.border padding: 0 enabled: model.enabled === undefined ? true : model.enabled @@ -203,9 +199,9 @@ T.ComboBox { popup: T.Popup { id: comboBoxPopup - x: actionIndicator.width + myComboBox.borderWidth + x: actionIndicator.width + StudioTheme.Values.border y: myComboBox.height - width: myComboBox.width - actionIndicator.width - myComboBox.borderWidth * 2 + width: myComboBox.width - actionIndicator.width - StudioTheme.Values.border * 2 // TODO Setting the height on the popup solved the problem with the popup of height 0, // but it has the problem that it sometimes extend over the border of the actual window // and is then cut off. @@ -213,7 +209,7 @@ T.ComboBox { + comboBoxPopup.bottomPadding, myComboBox.Window.height - topMargin - bottomMargin, StudioTheme.Values.maxComboBoxPopupHeight) - padding: myComboBox.borderWidth + padding: StudioTheme.Values.border margins: 0 // If not defined margin will be -1 closePolicy: T.Popup.CloseOnPressOutside | T.Popup.CloseOnPressOutsideParent | T.Popup.CloseOnEscape | T.Popup.CloseOnReleaseOutside @@ -245,7 +241,7 @@ T.ComboBox { State { name: "default" when: myComboBox.enabled && !myComboBox.hover && !myComboBox.edit && !myComboBox.open - && !myComboBox.activeFocus + && !myComboBox.activeFocus && !myComboBox.hasActiveDrag PropertyChanges { target: myComboBox wheelEnabled: false @@ -257,9 +253,23 @@ T.ComboBox { PropertyChanges { target: comboBoxBackground color: StudioTheme.Values.themeControlBackground - border.color: myComboBox.hasActiveDrag ? StudioTheme.Values.themeInteraction - : StudioTheme.Values.themeControlOutline - border.width: myComboBox.borderWidth + } + }, + State { + name: "acceptsDrag" + when: myComboBox.enabled && myComboBox.hasActiveDrag && !myComboBox.hasActiveHoverDrag + PropertyChanges { + target: comboBoxBackground + border.color: StudioTheme.Values.themeControlOutlineInteraction + } + }, + State { + name: "dragHover" + when: myComboBox.enabled && myComboBox.hasActiveHoverDrag + PropertyChanges { + target: comboBoxBackground + color: StudioTheme.Values.themeControlBackgroundInteraction + border.color: StudioTheme.Values.themeControlOutlineInteraction } }, // This state is intended for ComboBoxes which aren't editable, but have focus e.g. via diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBoxInput.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBoxInput.qml index c6b91dc1ad0..e2596876987 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBoxInput.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBoxInput.qml @@ -34,7 +34,6 @@ TextInput { property bool edit: textInput.activeFocus property bool hover: mouseArea.containsMouse && textInput.enabled - property int borderWidth: StudioTheme.Values.border z: 2 font: myControl.font @@ -56,11 +55,11 @@ TextInput { Rectangle { id: textInputBackground - x: textInput.borderWidth - y: textInput.borderWidth + x: StudioTheme.Values.border + y: StudioTheme.Values.border z: -1 width: textInput.width - height: StudioTheme.Values.height - textInput.borderWidth * 2 + height: StudioTheme.Values.height - StudioTheme.Values.border * 2 color: StudioTheme.Values.themeControlBackground border.width: 0 } @@ -94,7 +93,7 @@ TextInput { State { name: "default" when: myControl.enabled && !textInput.edit && !textInput.hover && !myControl.hover - && !myControl.open + && !myControl.open && !myControl.hasActiveDrag PropertyChanges { target: textInputBackground color: StudioTheme.Values.themeControlBackground @@ -105,6 +104,14 @@ TextInput { acceptedButtons: Qt.LeftButton } }, + State { + name: "dragHover" + when: myControl.enabled && myControl.hasActiveHoverDrag + PropertyChanges { + target: textInputBackground + color: StudioTheme.Values.themeControlBackgroundInteraction + } + }, State { name: "globalHover" when: myControl.hover && !textInput.hover && !textInput.edit && !myControl.open diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/FilterComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/FilterComboBox.qml index 30142652ab3..c41fe060e50 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/FilterComboBox.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/FilterComboBox.qml @@ -87,6 +87,9 @@ Item { property alias popupScrollBar: popupScrollBar property alias popupMouseArea: popupMouseArea + property bool hasActiveDrag: false // an item that can be dropped here is being dragged + property bool hasActiveHoverDrag: false // an item that can be dropped her is being hovered on top + width: StudioTheme.Values.defaultControlWidth height: StudioTheme.Values.defaultControlHeight implicitHeight: StudioTheme.Values.defaultControlHeight @@ -468,9 +471,11 @@ Item { State { name: "default" when: root.enabled && !textInput.edit && !root.hover && !root.open + && !root.hasActiveDrag PropertyChanges { target: textInputBackground color: StudioTheme.Values.themeControlBackground + border.color: StudioTheme.Values.themeControlOutline } PropertyChanges { target: textInputMouseArea @@ -478,6 +483,23 @@ Item { acceptedButtons: Qt.LeftButton } }, + State { + name: "acceptsDrag" + when: root.enabled && root.hasActiveDrag && !root.hasActiveHoverDrag + PropertyChanges { + target: textInputBackground + border.color: StudioTheme.Values.themeInteraction + } + }, + State { + name: "dragHover" + when: root.enabled && root.hasActiveHoverDrag + PropertyChanges { + target: textInputBackground + color: StudioTheme.Values.themeControlBackgroundInteraction + border.color: StudioTheme.Values.themeInteraction + } + }, State { name: "globalHover" when: root.hover && !textInput.hover && !textInput.edit && !root.open @@ -585,12 +607,20 @@ Item { name: "default" when: root.enabled && checkIndicator.enabled && !root.edit && !checkIndicator.hover && !root.hover - && !checkIndicator.checked + && !checkIndicator.checked && !root.hasActiveHoverDrag PropertyChanges { target: checkIndicator color: StudioTheme.Values.themeControlBackground } }, + State { + name: "dragHover" + when: root.enabled && root.hasActiveHoverDrag + PropertyChanges { + target: checkIndicator + color: StudioTheme.Values.themeControlBackgroundInteraction + } + }, State { name: "globalHover" when: root.enabled && checkIndicator.enabled diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.cpp index 9d11d264008..943693f2232 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.cpp @@ -75,7 +75,7 @@ QPixmap AssetsLibraryIconProvider::requestPixmap(const QString &id, QSize *size, pixmap = Utils::StyleHelper::dpiSpecificImageFile(":/AssetsLibrary/images/assets_default.png"); if (requestedSize.isValid()) - return pixmap.scaled(requestedSize); + return pixmap.scaled(requestedSize, Qt::KeepAspectRatio); return pixmap; } diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp index 7cf91158d65..632574fb0fc 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp @@ -91,10 +91,6 @@ bool AssetsLibraryWidget::eventFilter(QObject *obj, QEvent *event) m_assetsToDrag.clear(); } } - } else if (event->type() == QMouseEvent::MouseButtonRelease) { - m_assetsToDrag.clear(); - if (m_model) - m_model->endDrag(); } return QObject::eventFilter(obj, event); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp index e6f2b2825e5..109078e1561 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp @@ -126,10 +126,6 @@ bool ItemLibraryWidget::eventFilter(QObject *obj, QEvent *event) m_itemToDrag = {}; } } - } else if (event->type() == QMouseEvent::MouseButtonRelease) { - m_itemToDrag = {}; - if (model) - model->endDrag(); } return QObject::eventFilter(obj, event); diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp index 3a9a138b2a3..8ba1325efaf 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp @@ -322,6 +322,19 @@ void PropertyEditorContextObject::insertKeyframe(const QString &propertyName) }); } +QString PropertyEditorContextObject::activeDragSuffix() const +{ + return m_activeDragSuffix; +} + +void PropertyEditorContextObject::setActiveDragSuffix(const QString &suffix) +{ + if (m_activeDragSuffix != suffix) { + m_activeDragSuffix = suffix; + emit activeDragSuffixChanged(); + } +} + int PropertyEditorContextObject::majorVersion() const { return m_majorVersion; diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.h b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.h index 6a3e410c8a1..f5a2224c8b7 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.h +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.h @@ -56,6 +56,8 @@ class PropertyEditorContextObject : public QObject Q_PROPERTY(int majorQtQuickVersion READ majorQtQuickVersion WRITE setMajorQtQuickVersion NOTIFY majorQtQuickVersionChanged) Q_PROPERTY(int minorQtQuickVersion READ minorQtQuickVersion WRITE setMinorQtQuickVersion NOTIFY minorQtQuickVersionChanged) + Q_PROPERTY(QString activeDragSuffix READ activeDragSuffix NOTIFY activeDragSuffixChanged) + Q_PROPERTY(bool hasAliasExport READ hasAliasExport NOTIFY hasAliasExportChanged) Q_PROPERTY(bool hasActiveTimeline READ hasActiveTimeline NOTIFY hasActiveTimelineChanged) @@ -102,6 +104,9 @@ public: Q_INVOKABLE bool isBlocked(const QString &propName) const; + QString activeDragSuffix() const; + void setActiveDragSuffix(const QString &suffix); + int majorVersion() const; int majorQtQuickVersion() const; int minorQtQuickVersion() const; @@ -134,6 +139,7 @@ signals: void specificQmlComponentChanged(); void hasAliasExportChanged(); void hasActiveTimelineChanged(); + void activeDragSuffixChanged(); public slots: @@ -182,6 +188,8 @@ private: bool m_aliasExport = false; bool m_setHasActiveTimeline = false; + + QString m_activeDragSuffix; }; class EasingCurveEditor : public QObject diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp index 1ef95365e13..867fd9bd65b 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp @@ -537,6 +537,8 @@ void PropertyEditorValue::commitDrop(const QString &path) // assign the texture to the property setExpressionWithEmit(texture.id()); } + + m_modelNode.view()->model()->endDrag(); } QStringList PropertyEditorValue::generateStringList(const QString &string) const diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp index 586c4dec054..b516bba9c95 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp @@ -26,8 +26,8 @@ #include "propertyeditorview.h" #include "propertyeditorqmlbackend.h" -#include "propertyeditorvalue.h" #include "propertyeditortransaction.h" +#include "propertyeditorvalue.h" #include #include @@ -850,7 +850,26 @@ void PropertyEditorView::nodeReparented(const ModelNode &node, m_qmlBackEndForCurrentType->backendAnchorBinding().setup(QmlItemNode(m_selectedNode)); } -void PropertyEditorView::setValue(const QmlObjectNode &qmlObjectNode, const PropertyName &name, const QVariant &value) +void PropertyEditorView::dragStarted(QMimeData *mimeData) +{ + if (!mimeData->hasFormat(Constants::MIME_TYPE_ASSETS)) + return; + + const QString assetPath = QString::fromUtf8(mimeData->data(Constants::MIME_TYPE_ASSETS)) + .split(',')[0]; + const QString suffix = "*." + assetPath.split('.').last().toLower(); + + m_qmlBackEndForCurrentType->contextObject()->setActiveDragSuffix(suffix); +} + +void PropertyEditorView::dragEnded() +{ + m_qmlBackEndForCurrentType->contextObject()->setActiveDragSuffix(""); +} + +void PropertyEditorView::setValue(const QmlObjectNode &qmlObjectNode, + const PropertyName &name, + const QVariant &value) { m_locked = true; m_qmlBackEndForCurrentType->setValue(qmlObjectNode, name, value); @@ -869,6 +888,4 @@ void PropertyEditorView::reloadQml() resetView(); } - -} //QmlDesigner - +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h index 3bbe5020506..09d6dc7f419 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h @@ -87,6 +87,9 @@ public: const NodeAbstractProperty &oldPropertyParent, AbstractView::PropertyChangeFlags propertyChange) override; + void dragStarted(QMimeData *mimeData) override; + void dragEnded() override; + void changeValue(const QString &name); void changeExpression(const QString &name); void exportPropertyAsAlias(const QString &name); diff --git a/src/plugins/qmldesigner/designercore/model/model.cpp b/src/plugins/qmldesigner/designercore/model/model.cpp index 4e38fb3cfb3..47ce515f9e2 100644 --- a/src/plugins/qmldesigner/designercore/model/model.cpp +++ b/src/plugins/qmldesigner/designercore/model/model.cpp @@ -1517,7 +1517,9 @@ void Model::startDrag(QMimeData *mimeData, const QPixmap &icon) auto drag = new QDrag(this); drag->setPixmap(icon); drag->setMimeData(mimeData); - drag->exec(); + if (drag->exec() == Qt::IgnoreAction) + endDrag(); + drag->deleteLater(); } From a5d501d22e78948c2bf300b5e6bf01ecd44352a0 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Thu, 9 Jun 2022 09:30:24 +0200 Subject: [PATCH 11/96] QmlDesigner: Fix template Add missing '}' Task-number: QDS-7125 Change-Id: I7ecf80d681de0400368e28b98179488db560381e Reviewed-by: Thomas Hartmann --- .../studio_templates/projects/application-3d/Screen01.ui.qml.tpl | 1 + 1 file changed, 1 insertion(+) diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/Screen01.ui.qml.tpl b/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/Screen01.ui.qml.tpl index 24566ef2cc2..843185a029f 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/Screen01.ui.qml.tpl +++ b/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/Screen01.ui.qml.tpl @@ -56,6 +56,7 @@ Rectangle { objectName: "Default Material" diffuseColor: "#4aee45" } + } Text { text: qsTr("Hello %{ProjectName}") From ab635dd4b220b88c96dd240ddc03670b7ddf8175 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Thu, 9 Jun 2022 12:33:48 +0200 Subject: [PATCH 12/96] QmlDesigner: Do license check only once We should only make the license check once. An evaluationLicense is handled as enterprise license. Change-Id: Ib4b53795a7d735c10b5238f1e7b76346a9bcc8e1 Reviewed-by: Reviewed-by: Tim Jenssen --- src/plugins/qmldesigner/dynamiclicensecheck.h | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/dynamiclicensecheck.h b/src/plugins/qmldesigner/dynamiclicensecheck.h index fb1e3661b85..8ddcf55a15e 100644 --- a/src/plugins/qmldesigner/dynamiclicensecheck.h +++ b/src/plugins/qmldesigner/dynamiclicensecheck.h @@ -37,6 +37,7 @@ namespace QmlDesigner { enum FoundLicense { + noLicense, community, professional, enterprise @@ -58,12 +59,28 @@ ExtensionSystem::IPlugin *licenseCheckerPlugin() FoundLicense checkLicense() { + static FoundLicense license = noLicense; + + if (license != noLicense) + return license; + if (auto plugin = Internal::licenseCheckerPlugin()) { bool retVal = false; + bool success = QMetaObject::invokeMethod(plugin, - "qdsEnterpriseLicense", + "evaluationLicense", Qt::DirectConnection, Q_RETURN_ARG(bool, retVal)); + + if (success && retVal) + return enterprise; + + retVal = false; + + success = QMetaObject::invokeMethod(plugin, + "qdsEnterpriseLicense", + Qt::DirectConnection, + Q_RETURN_ARG(bool, retVal)); if (success && retVal) return enterprise; else From 8ca39444f4cadff3ae543877008cd9f6443380db Mon Sep 17 00:00:00 2001 From: Mats Honkamaa Date: Mon, 6 Jun 2022 10:36:41 +0300 Subject: [PATCH 13/96] Doc: Add documentation for Material Editor and Browser - Add Material Editor and Browser docs - Reorganize and edit current materials docs Task-number: QDS-6991 Change-Id: Ibea128dc48c0c2e167abf36e7700d4516673b45b Reviewed-by: Mahmoud Badri --- .../images/icons/apply-material.png | Bin 0 -> 779 bytes .../images/material-editor-browser.webp | Bin 0 -> 49886 bytes .../images/materials-remove-material.png | Bin 0 -> 15142 bytes .../images/navigator-material-texture.png | Bin 0 -> 3820 bytes .../studio-qtquick-3d-default-material.webp | Bin 0 -> 13236 bytes .../images/studio-qtquick-3d-material.webp | Bin 0 -> 35562 bytes .../src/qtdesignstudio-toc.qdoc | 1 + .../qtdesignstudio-3d-editor.qdoc | 2 +- .../qtdesignstudio-3d-materials-shaders.qdoc | 173 +----------- .../src/views/qtquick-components-view.qdoc | 2 +- .../src/views/studio-material-editor.qdoc | 266 ++++++++++++++++++ 11 files changed, 278 insertions(+), 166 deletions(-) create mode 100644 doc/qtdesignstudio/images/icons/apply-material.png create mode 100644 doc/qtdesignstudio/images/material-editor-browser.webp create mode 100644 doc/qtdesignstudio/images/materials-remove-material.png create mode 100644 doc/qtdesignstudio/images/navigator-material-texture.png create mode 100644 doc/qtdesignstudio/images/studio-qtquick-3d-default-material.webp create mode 100644 doc/qtdesignstudio/images/studio-qtquick-3d-material.webp create mode 100644 doc/qtdesignstudio/src/views/studio-material-editor.qdoc diff --git a/doc/qtdesignstudio/images/icons/apply-material.png b/doc/qtdesignstudio/images/icons/apply-material.png new file mode 100644 index 0000000000000000000000000000000000000000..d0b347470bc17f110ef71a28c7919fa27a2805e9 GIT binary patch literal 779 zcmeAS@N?(olHy`uVBq!ia0y~yV31~DV36WqVqjo6`D(**1_q`}o-U3d9>}2@4g>4d+g`)D|kryA2qjq+&pdJ z(g;6+6Q;A*?Q>iCI^OToqnQ~&?;DiDf}A4!yWnJ(v|Bg6>gt5KI#4DUrP6~T)!!L3R&ex5`GCR zThe))TlcC$MB(~s$>|@3c+dG&fA?Ta_DTEF#gT|8L97Y}~u0K{& zt|~s6`^!c=;q9bSWZwJ4~mGEF+%RgJDe#RnJm%sTwzNeyGulgFk>dLw*?2-Rw zcEs_nSJOVsy!vaUbHnZVhK_&jR%&fJv1sQ)A)On%uCL$7>4xSCwI-S{PkHxT=aHGV zw)X?QZ#?r=SFSmuEB29(-{-L8%%5VVe7rt634iRB_I`f1^OS|~UN>=}gN$o$z486~ z-sw;K*NN9Y=^l+2Jn``1&;E6>zy2(-@SVFM{Al5vCp_sB-k-brB(>>$;z7aM;_rVL zW2c-@t!dsB<$L|PkyccMlD59|*1hL6l=tqe5Gu1Y|Lm;oEi`4ycAMsds~1-Mo1x~p z?n~L({gxm1Ut2k)f45!kG$lz+YCpihz`)??>gTe~DWM4f^lEnt literal 0 HcmV?d00001 diff --git a/doc/qtdesignstudio/images/material-editor-browser.webp b/doc/qtdesignstudio/images/material-editor-browser.webp new file mode 100644 index 0000000000000000000000000000000000000000..d3963b522e4730736f8433cf2375eb3ca0405977 GIT binary patch literal 49886 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

jPx+euynZ1j;dhuv>cX;ADv1wQ19oScV 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 OrG_&KFt9NMfcOBR3{X4( literal 0 HcmV?d00001 diff --git a/doc/qtdesignstudio/images/materials-remove-material.png b/doc/qtdesignstudio/images/materials-remove-material.png new file mode 100644 index 0000000000000000000000000000000000000000..9ef0a91e5be01fef54067ad05e81d574e6db631f GIT binary patch literal 15142 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 h99YO9`QyQl|GjhFeoo@r^NNoTB literal 0 HcmV?d00001 diff --git a/doc/qtdesignstudio/images/navigator-material-texture.png b/doc/qtdesignstudio/images/navigator-material-texture.png new file mode 100644 index 0000000000000000000000000000000000000000..4256e959c61e4c6ed9931c29df02aea9fada8429 GIT binary patch literal 3820 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 literal 0 HcmV?d00001 diff --git a/doc/qtdesignstudio/images/studio-qtquick-3d-default-material.webp b/doc/qtdesignstudio/images/studio-qtquick-3d-default-material.webp new file mode 100644 index 0000000000000000000000000000000000000000..0306408df162c565a399044e149a961f5adb3b29 GIT binary patch literal 13236 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 H01zJlA=b2d literal 0 HcmV?d00001 diff --git a/doc/qtdesignstudio/images/studio-qtquick-3d-material.webp b/doc/qtdesignstudio/images/studio-qtquick-3d-material.webp new file mode 100644 index 0000000000000000000000000000000000000000..1c5b1cecf28eb07e60d3528fbbe9f484672fb54e GIT binary patch literal 35562 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 literal 0 HcmV?d00001 diff --git a/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc index f3a7a0d4f7d..8cba9a73076 100644 --- a/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc +++ b/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc @@ -39,6 +39,7 @@ \list \li \l{Form Editor} \li \l{3D Editor} + \li \l{Material Editor and Browser} \li \l{Components} \li \l{Assets} \li \l{Navigator} diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-editor.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-editor.qdoc index dee9a01a9d9..1995c343b83 100644 --- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-editor.qdoc +++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-editor.qdoc @@ -26,7 +26,7 @@ /*! \previouspage qtquick-form-editor.html \page studio-3d-editor.html - \nextpage quick-components-view.html + \nextpage studio-material-editor.html \title 3D Editor diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-materials-shaders.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-materials-shaders.qdoc index 73d4f66937e..abddc903a97 100644 --- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-materials-shaders.qdoc +++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-materials-shaders.qdoc @@ -32,7 +32,7 @@ \title Materials and Shaders - \image studio-qtquick-3d-material.png "Material attached to model in Design mode" + \image studio-qtquick-3d-material.webp "Material attached to model in Design mode" Materials and shaders define how object surfaces are rendered in \QDS and live preview. As you change the properties of materials, new shaders are @@ -40,6 +40,10 @@ a shader depends on a combination of the properties that are set on it, and the context of the scene itself. + It is recommended that you use the \l {Material Editor and Browser} when + working with materials, but you can also add materials using the components + library. + The materials that you used in your imported scenes are imported to \QDS as \l{Qt Quick 3D} components. When you add a View3D component, it contains a DefaultMaterial component. You can use the following predefined Qt Quick @@ -62,171 +66,12 @@ defines an image and how the image is mapped to meshes in a 3D scene. For more information, see \l {Textures}. - You can modify material properties in the \uicontrol Properties view, as - instructed in the following sections. The availability of the properties - depends on the material type. + You can create and modify materials in + \uicontrol {Material Editor} and \uicontrol {Material Browser}. The availability + of the properties depends on the material type. - \image studio-qtquick-3d-default-material.png "DefaultMaterial properties" - - To enable the material to use vertex colors from the mesh, select the - \uicontrol {Enable vertex colors} check box. These are multiplied - by any other colors specified for the material. + \image studio-qtquick-3d-default-material.webp "DefaultMaterial properties" You can animate material properties in the \uicontrol Timeline view, as instructed in \l {Creating Timeline Animations}. - - \section1 Blending Colors - - To determine how the colors of a model blend with the colors of the models - behind it, set the \uicontrol {Blend mode} property. To make opaque objects - occlude the objects behind them, select \uicontrol {SourceOver}. - - For a lighter result, select \uicontrol Screen to blend colors using an - inverted multiply or \uicontrol ColorDodge to blend them by inverted - division. Color dodge procudes an even lighter result than screen. - - For a darker result, select \uicontrol Multiply to blend colors using a - multiply or \uicontrol ColorBurn to blend them by inverted division, where - the result also is inverted. Color burn produces an even darker result than - multiply. - - The screen and multiply modes are order-independent, so select them to - avoid \e popping, which can happen when using semi-opaque objects and - sorting the back and front faces or models. - - For a result with higher contrast, select \uicontrol Overlay, which is a mix - of the multiply and screen modes. - - \section1 Lighting Materials - - To set the lighting method for generating a material, use the - \uicontrol Lighting property. Select \uicontrol {Fragment lighting} to - calculate diffuse and specular lighting for each rendered pixel. Some - effects, such as Fresnel or a bump map, require fragment lighting. - - To skip lighting calculation, select \uicontrol {No lighting}. This is very - fast and quite effective when using image maps that do not need to be shaded - by lighting. - - To set the base color for the material, use the \uicontrol {Diffuse Color} - property. You can either use the color picker or specify a RBG value. Set - the diffuse color to black to create purely-specular materials, such as - metals or mirrors. To apply a texture to a material, set it as the value of - the \uicontrol {Diffuse map} property. Using a texture with transparency - also applies the alpha channel as an \uicontrol {Opacity map}. You can set - the opacity of the material independently of the model as the value of the - \uicontrol Opacity property. - - \section1 Self-Illuminating Materials - - To set the color and amount of self-illumination for a material, use the - \uicontrol {Emissive color} and \uicontrol {Emissive factor} properties. In - a scene with black ambient lighting, a material with an emissive factor of 0 - is black where the light does not shine on it. Setting the emissive factor - to 1 shows the material in its diffuse color instead. - - To use a Texture for specifying the emissive factor for different parts of - the material, set the \uicontrol {Emissive map} property. Using a grayscale - image does not affect the color of the result, while using a color image - produces glowing regions with the color affected by the emissive map. - - \section1 Using Highlights and Reflections - - You can control the highlights and reflections on a material by setting the - properties in the \uicontrol Specular group. You can use the color picker - or set a RGB value to specify the color used to adjust specular reflections. - Use white for no effect - - To use a color texture to modulate the amount and the color of specularity - across the surface of a material, set the \uicontrol {Specular map} - property. Set the \uicontrol {Specular amount} property to specify the - strength of specularity. This property does not affect the specular - reflection map, but it does affect the amount of reflections from a scene's - light probe. - - \note Unless your mesh is high-resolution, you may need to use fragment - lighting to get good specular highlights from scene lights. - - To determine how to calculate specular highlights for lights in the scene, - set the \uicontrol {Specular model}. In addition to the default mode, you - can use the GGX or Ward lighting model. - - To use a Texture for specular highlighting on a material, set the - \uicontrol {Reflection map} property. When the texture is applied using - environmental mapping (not UV mapping), the map appears to be reflecting - from the environment as you rotate the model. Specular reflection maps are - an easy way to add a high-quality look at a relatively low cost. - - To specify an image to use as the specular reflection map, set the - \uicontrol {Light probe} property. - - Crisp images cause your material to look very glossy. The more you - blur your image, the softer your material appears. - - To decrease head-on reflections (looking directly at the surface) - while maintaining reflections seen at grazing angles, set the - \uicontrol {Fresnel power} property. To select the angles to control, - set the \uicontrol {Index of refraction} property. - - To control the size of the specular highlights generated from lights and the - clarity of reflections in general, set the \uicontrol {Specular roughness} - property. Larger values increase the roughness, while softening specular - highlights and blurring reflections. To control the specular roughness of - the material using a Texture, set the \uicontrol {Roughness map property}. - - \section1 Simulating Geometry Displacement - - Specify the properties in the \uicontrol {Bump/Normal} group to simulate - fine geometry displacement across the surface of the material. Set the - \uicontrol {Bump map} property to use a grayscale texture for the - simulation. Brighter pixels indicate raised regions. - - To use a RGB image for simulation, set the \uicontrol {Normal map} property. - The RGB channels indicate XYZ normal deviations. - - The amount of displacement is controlled by the \uicontrol {Bump amount} - property. - - Bump and normal maps do not affect the silhouette of a model. To affect the - silhouette, set the \uicontrol {Displacement map} property. It specifies a - grayscale image used to offset the vertices of geometry across the surface - of the material. The \uicontrol {Displacement amount} property specifies the - offset amount. - - \section1 Specifying Material Translucency - - Set the properties in the \uicontrol Translucency group to control how much - light can pass through the material from behind. To use a grayscale texture, - specify it as the value of the \uicontrol {Translucency map} property. - - To specify the amount of light wrap for the translucency map, set the - \uicontrol {Diffuse light wrap} property. A value of 0 does not wrap the - light at all, while a value of 1 wraps the light all around the object. - - To specify the amount of falloff for the translucency based on - the angle of the normals of the object to the light source, set - the \uicontrol {Translucency falloff} property. - - \section1 Culling Faces - - Set the \uicontrol {Culling mode} property to determine whether the front - and back faces of a model are rendered. Culling modes check whether the - points in the polygon appear in clockwise or counter-clockwise order when - projected onto the screen. If front-facing polygons have a clockwise - winding, but the polygon projected on the screen has a counter-clockwise - winding, the projected polygon is rotated to face away from the camera and - is not rendered. Culling makes rendering objects quicker and more efficient - by reducing the number of polygons to draw. - - \section1 Applying Materials to Models - - To apply materials to models, you should first delete the default material, - and then drag-and-drop a new material from \l Assets to a model component - in \l Navigator. - - You can apply the same material to another component as well. Again, - delete the default material first. You should then select the component and - go to the \uicontrol Properties view. Find the \uicontrol Materials property, - select the \inlineimage icons/plus.png - icon, and choose the new material in the dropdown menu. */ diff --git a/doc/qtdesignstudio/src/views/qtquick-components-view.qdoc b/doc/qtdesignstudio/src/views/qtquick-components-view.qdoc index 464926ea351..2d800909d6d 100644 --- a/doc/qtdesignstudio/src/views/qtquick-components-view.qdoc +++ b/doc/qtdesignstudio/src/views/qtquick-components-view.qdoc @@ -25,7 +25,7 @@ /*! \page quick-components-view.html - \previouspage studio-3d-editor.html + \previouspage studio-material-editor.html \nextpage quick-assets.html \title Components diff --git a/doc/qtdesignstudio/src/views/studio-material-editor.qdoc b/doc/qtdesignstudio/src/views/studio-material-editor.qdoc new file mode 100644 index 00000000000..fcfa9823e9f --- /dev/null +++ b/doc/qtdesignstudio/src/views/studio-material-editor.qdoc @@ -0,0 +1,266 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Creator documentation. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** +****************************************************************************/ + +/*! + \page studio-material-editor.html + \previouspage studio-3d-editor.html + \nextpage quick-components-view.html + + + \title Material Editor and Browser + + In the \uicontrol {Material Editor} and \uicontrol {Material Browser} views, + you create and manage materials. + + \image material-editor-browser.webp "Material Editor and Browser" + + \section1 Creating a Material + + To create a new material, do one of the following: + + \list + \li In \uicontrol {Material Browser}, select \inlineimage icons/plus.png + . + \li In \uicontrol {Material Editor}, select \inlineimage icons/plus.png + . + \endlist + + \section1 Editing a Material + + To edit a material, select it in \uicontrol{Material Browser} and edit its + properties in \uicontrol{Material Editor}. If \uicontrol {Material Editor} + is closed, open it in one of the following ways: + + \list + \li In \uicontrol{Navigator}, right-click an object that has the material + assigned to it and select \uicontrol {Edit Material}. + \li In \uicontrol{Material Browser}, double-click a material. + \endlist + + \section1 Assigning a Material to an Object + + To assign a material to a 3D object in your project, first select the object + in \uicontrol Navigator or \uicontrol {3D Editor}. Then, do one of the + following: + + \list + \li In \uicontrol {Material Browser}, right-click the material and select + \uicontrol {Apply to Selected}. If there already is any material assigned + to the object, you can select whether to replace the material or to add + another material to the object. + \li In \uicontrol {Material Editor}, select + \inlineimage icons/apply-material.png + . This replaces any material already assigned to the object. + \endlist + + \section1 Removing a Material from an Object + + To remove an assigned material from an object: + \list 1 + \li In \uicontrol{Navigator}, select the object. + \li In \uicontrol{Properties}, select + \inlineimage icons/close.png + next to the material. + \image materials-remove-material.png + \endlist + + \section1 Using Texture Maps + + In \QDS you can add many different texture maps to your material. + + To add a texture map to a material: + \list 1 + \li Select the material in \uicontrol{Material Browser}. + \li From \uicontrol {Assets}, drag an image to the correct map field + in \uicontrol {Material Editor}. For example, to add a diffuse map, drag + the image to \uicontrol{Diffuse Map} in \uicontrol{Material Editor}. + \endlist + + \section2 Using a Reflection Map for Environmental Mapping + + To use a texture for environmental mapping, you need to set the mapping + mode to \e {environment}. + + To add a reflection map for environmental mapping to a material: + + \list 1 + \li Select the material in \uicontrol {Material Browser}. + \li From \uicontrol{Assets}, drag an image to + \uicontrol{Reflection Map}. + \li In \uicontrol {Navigator}, select + \inlineimage icons/filtericon.png + and then clear \uicontrol {Show Only Visible Components}. Now the + texture you just added to the material is visible in + \uicontrol {Navigator}. + \image navigator-material-texture.png + \li In \uicontrol {Navigator}, select the texture. + \li In \uicontrol {Properties}, set \uicontrol {Texture Mapping} to + \uicontrol {Environment}. + \endlist + + \section1 Blending Colors + + To determine how the colors of a model blend with the colors of the models + behind it, set the \uicontrol {Blend mode} property. To make opaque objects + occlude the objects behind them, select \uicontrol {SourceOver}. + + For a lighter result, select \uicontrol Screen to blend colors using an + inverted multiply or \uicontrol ColorDodge to blend them by inverted + division. Color dodge produces an even lighter result than screen. + + For a darker result, select \uicontrol Multiply to blend colors using a + multiply or \uicontrol ColorBurn to blend them by inverted division, where + the result also is inverted. Color burn produces an even darker result than + multiply. + + The screen and multiply modes are order-independent, so select them to + avoid \e popping, which can happen when using semi-opaque objects and + sorting the back and front faces or models. + + For a result with higher contrast, select \uicontrol Overlay, which is a mix + of the multiply and screen modes. + + \section1 Lighting Materials + + To set the lighting method for generating a material, use the + \uicontrol Lighting property. Select \uicontrol {Fragment lighting} to + calculate diffuse and specular lighting for each rendered pixel. Some + effects, such as Fresnel or a bump map, require fragment lighting. + + To skip lighting calculation, select \uicontrol {No lighting}. This is very + fast and quite effective when using image maps that do not need to be shaded + by lighting. + + To set the base color for the material, use the \uicontrol {Diffuse Color} + property. You can either use the color picker or specify a RBG value. Set + the diffuse color to black to create purely-specular materials, such as + metals or mirrors. To apply a texture to a material, set it as the value of + the \uicontrol {Diffuse map} property. Using a texture with transparency + also applies the alpha channel as an \uicontrol {Opacity map}. You can set + the opacity of the material independently of the model as the value of the + \uicontrol Opacity property. + + \section1 Self-Illuminating Materials + + To set the color and amount of self-illumination for a material, use the + \uicontrol {Emissive color} and \uicontrol {Emissive factor} properties. In + a scene with black ambient lighting, a material with an emissive factor of 0 + is black where the light does not shine on it. Setting the emissive factor + to 1 shows the material in its diffuse color instead. + + To use a Texture for specifying the emissive factor for different parts of + the material, set the \uicontrol {Emissive map} property. Using a grayscale + image does not affect the color of the result, while using a color image + produces glowing regions with the color affected by the emissive map. + + \section1 Using Highlights and Reflections + + You can control the highlights and reflections on a material by setting the + properties in the \uicontrol Specular group. You can use the color picker + or set a RGB value to specify the color used to adjust specular reflections. + Use white for no effect. + + To use a color texture to modulate the amount and the color of specularity + across the surface of a material, set the \uicontrol {Specular map} + property. Set the \uicontrol {Specular amount} property to specify the + strength of specularity. This property does not affect the specular + reflection map, but it does affect the amount of reflections from a scene's + light probe. + + \note Unless your mesh is high-resolution, you may need to use fragment + lighting to get good specular highlights from scene lights. + + To determine how to calculate specular highlights for lights in the scene, + set the \uicontrol {Specular model}. In addition to the default mode, you + can use the GGX or Ward lighting model. + + To use a Texture for specular highlighting on a material, set the + \uicontrol {Reflection map} property. When the texture is applied using + environmental mapping (not UV mapping), the map appears to be reflecting + from the environment as you rotate the model. Specular reflection maps are + an easy way to add a high-quality look at a relatively low cost. + + To specify an image to use as the specular reflection map, set the + \uicontrol {Light probe} property. + + Crisp images cause your material to look very glossy. The more you + blur your image, the softer your material appears. + + To decrease head-on reflections (looking directly at the surface) + while maintaining reflections seen at grazing angles, set the + \uicontrol {Fresnel power} property. To select the angles to control, + set the \uicontrol {Index of refraction} property. + + To control the size of the specular highlights generated from lights and the + clarity of reflections in general, set the \uicontrol {Specular roughness} + property. Larger values increase the roughness, while softening specular + highlights and blurring reflections. To control the specular roughness of + the material using a Texture, set the \uicontrol {Roughness map property}. + + \section1 Simulating Geometry Displacement + + Specify the properties in the \uicontrol {Bump/Normal} group to simulate + fine geometry displacement across the surface of the material. Set the + \uicontrol {Bump map} property to use a grayscale texture for the + simulation. Brighter pixels indicate raised regions. + + To use an image for simulation, set the \uicontrol {Normal map} property. + The RGB channels indicate XYZ normal deviations. + + The amount of displacement is controlled by the \uicontrol {Bump amount} + property. + + Bump and normal maps do not affect the silhouette of a model. To affect the + silhouette, set the \uicontrol {Displacement map} property. It specifies a + grayscale image used to offset the vertices of geometry across the surface + of the material. The \uicontrol {Displacement amount} property specifies the + offset amount. + + \section1 Specifying Material Translucency + + Set the properties in the \uicontrol Translucency group to control how much + light can pass through the material from behind. To use a grayscale texture, + specify it as the value of the \uicontrol {Translucency map} property. + + To specify the amount of light wrap for the translucency map, set the + \uicontrol {Diffuse light wrap} property. A value of 0 does not wrap the + light at all, while a value of 1 wraps the light all around the object. + + To specify the amount of falloff for the translucency based on + the angle of the normals of the object to the light source, set + the \uicontrol {Translucency falloff} property. + + \section1 Culling Faces + + Set the \uicontrol {Culling mode} property to determine whether the front + and back faces of a model are rendered. Culling modes check whether the + points in the polygon appear in clockwise or counter-clockwise order when + projected onto the screen. If front-facing polygons have a clockwise + winding, but the polygon projected on the screen has a counter-clockwise + winding, the projected polygon is rotated to face away from the camera and + is not rendered. Culling makes rendering objects quicker and more efficient + by reducing the number of polygons to draw. + +*/ From d8c605179ad4934c5f9a2060dd398a13821336c4 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Thu, 9 Jun 2022 19:40:23 +0200 Subject: [PATCH 14/96] QmlDesigner: Add option for smooth rendering in form editor Smooth rendering turns on MSAA and doubles the resolution for rendered items. With this option enabled everything stays smooth when zooming in. Around factor 8-10 pixels become clearly visible again, but it still looks relatively smooth. I added both MSAA and increased the resolution to one option, for simplicity. The smooth mode takes 4 times the shared memory, which should not be an issue in most cases. For now, the option is not the default. Task-number: QDS-7129 Task-number: QDS-7128 Change-Id: I8a778650bb40f8ba796960db9bc966e8a1efff4e Reviewed-by: Miikka Heikkinen --- .../instances/qt5nodeinstanceserver.cpp | 11 +++++++++-- .../instances/quickitemnodeinstance.cpp | 4 ++-- .../designercore/instances/puppetcreator.cpp | 6 ++++++ src/plugins/qmldesigner/designersettings.cpp | 1 + src/plugins/qmldesigner/designersettings.h | 1 + src/plugins/qmldesigner/settingspage.cpp | 2 ++ src/plugins/qmldesigner/settingspage.ui | 17 +++++++++++++++++ 7 files changed, 38 insertions(+), 4 deletions(-) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp index 32f63a8cd66..e7a98b74275 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp @@ -405,6 +405,9 @@ QImage Qt5NodeInstanceServer::grabItem(QQuickItem *item) QQuickItemPrivate *pItem = QQuickItemPrivate::get(item); const bool renderEffects = qEnvironmentVariableIsSet("QMLPUPPET_RENDER_EFFECTS"); + const bool smoothRendering = qEnvironmentVariableIsSet("QMLPUPPET_SMOOTH_RENDERING"); + + int scaleFactor = smoothRendering ? 2 : 1; if (renderEffects) { if (parentEffectItem(item)) @@ -470,6 +473,8 @@ QImage Qt5NodeInstanceServer::grabItem(QQuickItem *item) // us to render it to a texture that we can grab to an image. QSGRenderContext *rc = QQuickWindowPrivate::get(m_viewData.window.data())->context; QSGLayer *layer = rc->sceneGraphContext()->createLayer(rc); + if (smoothRendering) + layer->setSamples(4); layer->setItem(pItem->itemNode()); layer->setRect(QRectF(renderBoundingRect.x(), @@ -478,8 +483,8 @@ QImage Qt5NodeInstanceServer::grabItem(QQuickItem *item) -renderBoundingRect.height())); const QSize minSize = rc->sceneGraphContext()->minimumFBOSize(); - layer->setSize(QSize(qMax(minSize.width(), int(renderBoundingRect.width())), - qMax(minSize.height(), int(renderBoundingRect.height())))); + layer->setSize(QSize(qMax(minSize.width(), int(renderBoundingRect.width() * scaleFactor)), + qMax(minSize.height(), int(renderBoundingRect.height() * scaleFactor)))); layer->scheduleUpdate(); if (layer->updateTexture()) @@ -489,6 +494,8 @@ QImage Qt5NodeInstanceServer::grabItem(QQuickItem *item) delete layer; layer = nullptr; + + renderImage.setDevicePixelRatio(scaleFactor); }); m_viewData.renderControl->render(); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.cpp index 41d0015ce56..5b1f3171adb 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.cpp @@ -504,12 +504,12 @@ QImage QuickItemNodeInstance::renderImage() const if (s_unifiedRenderPath) { renderImage = nodeInstanceServer()->grabWindow(); renderImage = renderImage.copy(renderBoundingRect.toRect()); + /* When grabbing an offscren window the device pixel ratio is 1 */ + renderImage.setDevicePixelRatio(1); } else { renderImage = nodeInstanceServer()->grabItem(quickItem()); } - /* When grabbing an offscren window the device pixel ratio is 1 */ - renderImage.setDevicePixelRatio(1); #endif return renderImage; diff --git a/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp b/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp index a437e5c0be0..7d4beeacd8d 100644 --- a/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp +++ b/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp @@ -504,6 +504,12 @@ QProcessEnvironment PuppetCreator::processEnvironment() const #ifndef QMLDESIGNER_TEST const QString controlsStyle = m_designerSettings.value(DesignerSettingsKey:: CONTROLS_STYLE).toString(); + + const bool smoothRendering = m_designerSettings.value(DesignerSettingsKey::SMOOTH_RENDERING) + .toBool(); + + if (smoothRendering) + environment.set("QMLPUPPET_SMOOTH_RENDERING", "true"); #else const QString controlsStyle; #endif diff --git a/src/plugins/qmldesigner/designersettings.cpp b/src/plugins/qmldesigner/designersettings.cpp index 20083068c16..5474fd50d34 100644 --- a/src/plugins/qmldesigner/designersettings.cpp +++ b/src/plugins/qmldesigner/designersettings.cpp @@ -82,6 +82,7 @@ void DesignerSettings::fromSettings(QSettings *settings) restoreValue(settings, DesignerSettingsKey::ASK_BEFORE_DELETING_ASSET, true); const QStringList defaultValue = QStringList() << "#222222" << "#999999"; restoreValue(settings, DesignerSettingsKey::EDIT3DVIEW_BACKGROUND_COLOR, defaultValue); + restoreValue(settings, DesignerSettingsKey::SMOOTH_RENDERING, false); settings->endGroup(); settings->endGroup(); diff --git a/src/plugins/qmldesigner/designersettings.h b/src/plugins/qmldesigner/designersettings.h index 8c249fc65e0..4dbee7752ba 100644 --- a/src/plugins/qmldesigner/designersettings.h +++ b/src/plugins/qmldesigner/designersettings.h @@ -72,6 +72,7 @@ const char COLOR_PALETTE_FAVORITE[] = "ColorPaletteFavorite"; const char ALWAYS_DESIGN_MODE[] = "AlwaysDesignMode"; const char DISABLE_ITEM_LIBRARY_UPDATE_TIMER[] = "DisableItemLibraryUpdateTimer"; const char ASK_BEFORE_DELETING_ASSET[] = "AskBeforeDeletingAsset"; +const char SMOOTH_RENDERING[] = "SmoothRendering"; } class QMLDESIGNERCORE_EXPORT DesignerSettings : public QHash diff --git a/src/plugins/qmldesigner/settingspage.cpp b/src/plugins/qmldesigner/settingspage.cpp index 1af226ae49f..700402680a9 100644 --- a/src/plugins/qmldesigner/settingspage.cpp +++ b/src/plugins/qmldesigner/settingspage.cpp @@ -182,6 +182,7 @@ DesignerSettings SettingsPageWidget::settings() const m_ui.designerAlwaysDesignModeCheckBox->isChecked()); settings.insert(DesignerSettingsKey::ASK_BEFORE_DELETING_ASSET, m_ui.askBeforeDeletingAssetCheckBox->isChecked()); + settings.insert(DesignerSettingsKey::SMOOTH_RENDERING, m_ui.smoothRendering->isChecked()); return settings; } @@ -264,6 +265,7 @@ void SettingsPageWidget::setSettings(const DesignerSettings &settings) m_ui.emulationGroupBox->setVisible(showAdvancedFeatures); m_ui.debugGroupBox->setVisible(showAdvancedFeatures); m_ui.featureTimelineEditorCheckBox->setVisible(standaloneMode); + m_ui.smoothRendering->setChecked(settings.value(DesignerSettingsKey::SMOOTH_RENDERING).toBool()); } void SettingsPageWidget::apply() diff --git a/src/plugins/qmldesigner/settingspage.ui b/src/plugins/qmldesigner/settingspage.ui index eace952540a..004f8a68eb6 100644 --- a/src/plugins/qmldesigner/settingspage.ui +++ b/src/plugins/qmldesigner/settingspage.ui @@ -99,6 +99,23 @@ + + + + Enable Smooth Rendering in Form Editor + + + + + + + + + + Smooth Rendering: + + + From 36dbc62a1d67f02241e5c5860af083d7f4a0d7b5 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Tue, 7 Jun 2022 16:27:28 +0300 Subject: [PATCH 15/96] QmlDesigner: Queue puppet processes during import On some systems launcing multiple simultaneous import processes causes imports to fail. Fixed by only launching single process at a time and queuing the rest. Fixes: QDS-7107 Change-Id: I330c5920dcbd74d3b4f2e7f40899795a4fbaf3ac Reviewed-by: Thomas Hartmann --- .../qml2puppet/iconrenderer/iconrenderer.cpp | 3 +- .../itemlibrary/itemlibraryassetimporter.cpp | 166 ++++++++++-------- .../itemlibrary/itemlibraryassetimporter.h | 16 +- 3 files changed, 99 insertions(+), 86 deletions(-) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/iconrenderer/iconrenderer.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/iconrenderer/iconrenderer.cpp index 2dd653273cd..76deb3a3b39 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/iconrenderer/iconrenderer.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/iconrenderer/iconrenderer.cpp @@ -198,8 +198,7 @@ void IconRenderer::finishCreateIcon() render(saveFile); - // Allow little time for file operations to finish - QTimer::singleShot(1000, qGuiApp, &QGuiApplication::quit); + QTimer::singleShot(0, qGuiApp, &QGuiApplication::quit); } void IconRenderer::render(const QString &fileName) diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp index e3aae0cb7d5..8e8087dd214 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp @@ -37,6 +37,7 @@ #include #include +#include #include #include @@ -90,21 +91,16 @@ void ItemLibraryAssetImporter::importQuick3D(const QStringList &inputFiles, if (!isCancelled()) { const auto parseData = m_parseData; - for (const auto &pd : parseData) { - if (!startImportProcess(pd)) { - addError(tr("Failed to start import 3D asset process."), - pd.sourceInfo.absoluteFilePath()); - m_parseData.remove(pd.importId); - } - } + for (const auto &pd : parseData) + m_puppetQueue.append(pd.importId); + startNextImportProcess(); } if (!isCancelled()) { // Wait for puppet processes to finish - if (m_qmlPuppetProcesses.empty()) { + if (m_puppetQueue.isEmpty() && !m_puppetProcess) { postImport(); } else { - m_qmlPuppetCount = static_cast(m_qmlPuppetProcesses.size()); const QString progressTitle = tr("Importing 3D assets."); addInfo(progressTitle); notifyProgress(0, progressTitle); @@ -142,21 +138,14 @@ void ItemLibraryAssetImporter::addInfo(const QString &infoMsg, const QString &sr emit infoReported(infoMsg, srcPath); } -void ItemLibraryAssetImporter::importProcessFinished(int exitCode, QProcess::ExitStatus exitStatus, - int importId) +void ItemLibraryAssetImporter::importProcessFinished(int exitCode, QProcess::ExitStatus exitStatus) { Q_UNUSED(exitCode) - ++m_qmlImportFinishedCount; + m_puppetProcess.reset(); - m_qmlPuppetProcesses.erase( - std::remove_if(m_qmlPuppetProcesses.begin(), m_qmlPuppetProcesses.end(), - [&](const auto &entry) { - return !entry || entry->state() == QProcess::NotRunning; - })); - - if (m_parseData.contains(importId)) { - const ParseData &pd = m_parseData[importId]; + if (m_parseData.contains(m_currentImportId)) { + const ParseData &pd = m_parseData[m_currentImportId]; QString errStr; if (exitStatus == QProcess::ExitStatus::CrashExit) { errStr = tr("Import process crashed."); @@ -179,15 +168,19 @@ void ItemLibraryAssetImporter::importProcessFinished(int exitCode, QProcess::Exi addError(tr("Asset import process failed: \"%1\".") .arg(pd.sourceInfo.absoluteFilePath())); addError(errStr); - m_parseData.remove(importId); + m_parseData.remove(m_currentImportId); } } - if (m_qmlImportFinishedCount == m_qmlPuppetCount) { + int finishedCount = m_parseData.size() - m_puppetQueue.size(); + if (!m_puppetQueue.isEmpty()) + startNextImportProcess(); + + if (m_puppetQueue.isEmpty() && !m_puppetProcess) { notifyProgress(100); QTimer::singleShot(0, this, &ItemLibraryAssetImporter::postImport); } else { - notifyProgress(int(100. * (double(m_qmlImportFinishedCount) / double(m_qmlPuppetCount)))); + notifyProgress(int(100. * (double(finishedCount) / double(m_parseData.size())))); } } @@ -196,17 +189,17 @@ void ItemLibraryAssetImporter::iconProcessFinished(int exitCode, QProcess::ExitS Q_UNUSED(exitCode) Q_UNUSED(exitStatus) - m_qmlPuppetProcesses.erase( - std::remove_if(m_qmlPuppetProcesses.begin(), m_qmlPuppetProcesses.end(), - [&](const auto &entry) { - return !entry || entry->state() == QProcess::NotRunning; - })); + m_puppetProcess.reset(); - if (m_qmlPuppetProcesses.empty()) { + int finishedCount = m_parseData.size() - m_puppetQueue.size(); + if (!m_puppetQueue.isEmpty()) + startNextIconProcess(); + + if (m_puppetQueue.isEmpty() && !m_puppetProcess) { notifyProgress(100); QTimer::singleShot(0, this, &ItemLibraryAssetImporter::finalizeQuick3DImport); } else { - notifyProgress(int(100. * (1. - (double(m_qmlPuppetProcesses.size()) / double(m_qmlPuppetCount))))); + notifyProgress(int(100. * (double(finishedCount) / double(m_parseData.size())))); } } @@ -225,11 +218,11 @@ void ItemLibraryAssetImporter::reset() m_tempDir = new QTemporaryDir; m_importFiles.clear(); m_overwrittenImports.clear(); - m_qmlPuppetProcesses.clear(); - m_qmlPuppetCount = 0; - m_qmlImportFinishedCount = 0; + m_puppetProcess.reset(); m_parseData.clear(); m_requiredImports.clear(); + m_currentImportId = 0; + m_puppetQueue.clear(); } void ItemLibraryAssetImporter::parseFiles(const QStringList &filePaths, @@ -351,7 +344,7 @@ bool ItemLibraryAssetImporter::preParseQuick3DAsset(const QString &file, ParseDa return true; } -void ItemLibraryAssetImporter::postParseQuick3DAsset(const ParseData &pd) +void ItemLibraryAssetImporter::postParseQuick3DAsset(ParseData &pd) { QDir outDir = pd.outDir; if (pd.originalAssetName != pd.assetName) { @@ -452,8 +445,10 @@ void ItemLibraryAssetImporter::postParseQuick3DAsset(const ParseData &pd) "QtQuick3D", impVersionStr)); } } - if (impVersionMajor > 0 && impVersionMajor < 6 - && startIconProcess(24, iconFileName, qmlIt.filePath())) { + if (impVersionMajor > 0 && impVersionMajor < 6) { + pd.iconFile = iconFileName; + pd.iconSource = qmlIt.filePath(); + m_puppetQueue.append(pd.importId); // Since icon is generated by external process, the file won't be // ready for asset gathering below, so assume its generation succeeds // and add it now. @@ -589,84 +584,101 @@ ItemLibraryAssetImporter::OverwriteResult ItemLibraryAssetImporter::confirmAsset return OverwriteResult::Skip; } -bool ItemLibraryAssetImporter::startImportProcess(const ParseData &pd) +void ItemLibraryAssetImporter::startNextImportProcess() { + if (m_puppetQueue.isEmpty()) + return; + auto doc = QmlDesignerPlugin::instance()->currentDesignDocument(); Model *model = doc ? doc->currentModel() : nullptr; if (model) { PuppetCreator puppetCreator(doc->currentTarget(), model); puppetCreator.createQml2PuppetExecutableIfMissing(); - QStringList puppetArgs; - QJsonDocument optDoc(pd.options); - puppetArgs << "--import3dAsset" << pd.sourceInfo.absoluteFilePath() - << pd.outDir.absolutePath() << QString::fromUtf8(optDoc.toJson()); + bool done = false; + while (!m_puppetQueue.isEmpty() && !done) { + const ParseData pd = m_parseData.value(m_puppetQueue.takeLast()); + QStringList puppetArgs; + QJsonDocument optDoc(pd.options); - QProcessUniquePointer process = puppetCreator.createPuppetProcess( - "custom", - {}, - [&] {}, - [&](int exitCode, QProcess::ExitStatus exitStatus) { - importProcessFinished(exitCode, exitStatus, pd.importId); - }, - puppetArgs); + puppetArgs << "--import3dAsset" << pd.sourceInfo.absoluteFilePath() + << pd.outDir.absolutePath() << QString::fromUtf8(optDoc.toJson()); - if (process->waitForStarted(5000)) { - m_qmlPuppetProcesses.push_back(std::move(process)); - return true; - } else { - process.reset(); + m_currentImportId = pd.importId; + m_puppetProcess = puppetCreator.createPuppetProcess( + "custom", + {}, + [&] {}, + [&](int exitCode, QProcess::ExitStatus exitStatus) { + importProcessFinished(exitCode, exitStatus); + }, + puppetArgs); + + if (m_puppetProcess->waitForStarted(10000)) { + done = true; + } else { + addError(tr("Failed to start import 3D asset process."), + pd.sourceInfo.absoluteFilePath()); + m_parseData.remove(pd.importId); + m_puppetProcess.reset(); + } } } - return false; } -bool ItemLibraryAssetImporter::startIconProcess(int size, const QString &iconFile, - const QString &iconSource) +void ItemLibraryAssetImporter::startNextIconProcess() { + if (m_puppetQueue.isEmpty()) + return; + auto doc = QmlDesignerPlugin::instance()->currentDesignDocument(); Model *model = doc ? doc->currentModel() : nullptr; if (model) { PuppetCreator puppetCreator(doc->currentTarget(), model); puppetCreator.createQml2PuppetExecutableIfMissing(); - QStringList puppetArgs; - puppetArgs << "--rendericon" << QString::number(size) << iconFile << iconSource; - QProcessUniquePointer process = puppetCreator.createPuppetProcess( - "custom", - {}, - [&] {}, - [&](int exitCode, QProcess::ExitStatus exitStatus) { - iconProcessFinished(exitCode, exitStatus); - }, - puppetArgs); - if (process->waitForStarted(5000)) { - m_qmlPuppetProcesses.push_back(std::move(process)); - return true; - } else { - process.reset(); + bool done = false; + while (!m_puppetQueue.isEmpty() && !done) { + const ParseData pd = m_parseData.value(m_puppetQueue.takeLast()); + QStringList puppetArgs; + puppetArgs << "--rendericon" << QString::number(24) << pd.iconFile << pd.iconSource; + m_puppetProcess = puppetCreator.createPuppetProcess( + "custom", + {}, + [&] {}, + [&](int exitCode, QProcess::ExitStatus exitStatus) { + iconProcessFinished(exitCode, exitStatus); + }, + puppetArgs); + + if (m_puppetProcess->waitForStarted(10000)) { + done = true; + } else { + addError(tr("Failed to start icon generation process."), + pd.sourceInfo.absoluteFilePath()); + m_puppetProcess.reset(); + } } } - return false; } void ItemLibraryAssetImporter::postImport() { - Q_ASSERT(m_qmlPuppetProcesses.empty()); + QTC_ASSERT(m_puppetQueue.isEmpty() && !m_puppetProcess, return); if (!isCancelled()) { - for (const auto &pd : qAsConst(m_parseData)) + for (auto &pd : m_parseData) postParseQuick3DAsset(pd); + startNextIconProcess(); } if (!isCancelled()) { // Wait for icon generation processes to finish - if (m_qmlPuppetProcesses.empty()) { + if (m_puppetQueue.isEmpty() && !m_puppetProcess) { finalizeQuick3DImport(); } else { - m_qmlPuppetCount = static_cast(m_qmlPuppetProcesses.size()); const QString progressTitle = tr("Generating icons."); addInfo(progressTitle); notifyProgress(0, progressTitle); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h index 83be9af5f4e..1f0009eaab5 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h @@ -74,7 +74,7 @@ signals: void importFinished(); private slots: - void importProcessFinished(int exitCode, QProcess::ExitStatus exitStatus, int importId); + void importProcessFinished(int exitCode, QProcess::ExitStatus exitStatus); void iconProcessFinished(int exitCode, QProcess::ExitStatus exitStatus); private: @@ -87,6 +87,8 @@ private: QString assetName; QString originalAssetName; int importId; + QString iconFile; + QString iconSource; }; void notifyFinished(); @@ -96,7 +98,7 @@ private: const QSet &preselectedFilesForOverwrite); bool preParseQuick3DAsset(const QString &file, ParseData &pd, const QSet &preselectedFilesForOverwrite); - void postParseQuick3DAsset(const ParseData &pd); + void postParseQuick3DAsset(ParseData &pd); void copyImportedFiles(); void notifyProgress(int value, const QString &text); @@ -110,8 +112,8 @@ private: }; OverwriteResult confirmAssetOverwrite(const QString &assetName); - bool startImportProcess(const ParseData &pd); - bool startIconProcess(int size, const QString &iconFile, const QString &iconSource); + void startNextImportProcess(); + void startNextIconProcess(); void postImport(); void finalizeQuick3DImport(); QString sourceSceneTargetFilePath(const ParseData &pd); @@ -122,12 +124,12 @@ private: bool m_cancelled = false; QString m_importPath; QTemporaryDir *m_tempDir = nullptr; - std::vector m_qmlPuppetProcesses; - int m_qmlPuppetCount = 0; - int m_qmlImportFinishedCount = 0; + QProcessUniquePointer m_puppetProcess; int m_importIdCounter = 0; + int m_currentImportId = 0; QHash m_parseData; QString m_progressTitle; QList m_requiredImports; + QList m_puppetQueue; }; } // QmlDesigner From dedbbc75b564b0a93c89688d76a7cab6dbc06046 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Fri, 10 Jun 2022 15:23:16 +0300 Subject: [PATCH 16/96] QmlDesigner: Apply root item transform in Node component previews When generating a preview from a component with a 3D node for a root, the root Node transform is now applied when calculating camera zoom. Fixes: QDS-7131 Change-Id: I73054a09b3e82868c999ef6f9797dc941e625b33 Reviewed-by: Mahmoud Badri --- .../qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNodeView.qml | 2 +- .../qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml | 2 +- .../qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp | 6 +++--- .../qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNodeView.qml index 5c8b9e1cd72..b497b0419a1 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNodeView.qml @@ -37,7 +37,7 @@ View3D { function fitToViewPort(closeUp) { // The magic number is the distance from camera default pos to origin - _generalHelper.calculateNodeBoundsAndFocusCamera(theCamera, sourceModel, root, + _generalHelper.calculateNodeBoundsAndFocusCamera(theCamera, model, root, 1040, closeUp); } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml index 1762e3c9a4d..4da76ea097f 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml @@ -37,7 +37,7 @@ View3D { function fitToViewPort(closeUp) { // The magic number is the distance from camera default pos to origin - _generalHelper.calculateNodeBoundsAndFocusCamera(theCamera, sourceModel, root, + _generalHelper.calculateNodeBoundsAndFocusCamera(theCamera, model, root, 1040, closeUp); } diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp index 74c2eb270ef..590785a30e3 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp @@ -812,7 +812,7 @@ QVector3D GeneralHelper::pivotScenePosition(QQuick3DNode *node) const // Calculate bounds for given node, including all child nodes. // Returns true if the tree contains at least one Model node. bool GeneralHelper::getBounds(QQuick3DViewport *view3D, QQuick3DNode *node, QVector3D &minBounds, - QVector3D &maxBounds, bool recursive) + QVector3D &maxBounds) { if (!node) { const float halfExtent = 100.f; @@ -825,7 +825,7 @@ bool GeneralHelper::getBounds(QQuick3DViewport *view3D, QQuick3DNode *node, QVec auto nodePriv = QQuick3DObjectPrivate::get(node); auto renderNode = static_cast(nodePriv->spatialNode); - if (recursive && renderNode) { + if (renderNode) { #if QT_VERSION < QT_VERSION_CHECK(6, 4, 0) if (renderNode->flags.testFlag(QSSGRenderNode::Flag::TransformDirty)) renderNode->calculateLocalTransform(); @@ -850,7 +850,7 @@ bool GeneralHelper::getBounds(QQuick3DViewport *view3D, QQuick3DNode *node, QVec if (auto childNode = qobject_cast(child)) { QVector3D newMinBounds = minBounds; QVector3D newMaxBounds = maxBounds; - bool childHasModel = getBounds(view3D, childNode, newMinBounds, newMaxBounds, true); + bool childHasModel = getBounds(view3D, childNode, newMinBounds, newMaxBounds); // Ignore any subtrees that do not have Model in them as we don't need those // for visual bounds calculations if (childHasModel) { diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h index 5bb1fa1662f..8014a711875 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h @@ -130,7 +130,7 @@ private: void handlePendingToolStateUpdate(); QVector3D pivotScenePosition(QQuick3DNode *node) const; bool getBounds(QQuick3DViewport *view3D, QQuick3DNode *node, QVector3D &minBounds, - QVector3D &maxBounds, bool recursive = false); + QVector3D &maxBounds); QTimer m_overlayUpdateTimer; QTimer m_toolStateUpdateTimer; From 13c1b6f2373f3da6198e1111a96f5aee1036023a Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Fri, 10 Jun 2022 21:08:56 +0200 Subject: [PATCH 17/96] QmlDesigner: Do not apply smooth rendering if root is a 3D node Task-number: QDS-7136 Change-Id: I5260153b8d6131160a8d4b67418e81c6f6e4d862 Reviewed-by: Miikka Heikkinen --- .../qml2puppet/instances/qt5nodeinstanceserver.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp index e7a98b74275..3ccd6c60dce 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp @@ -407,8 +407,6 @@ QImage Qt5NodeInstanceServer::grabItem(QQuickItem *item) const bool renderEffects = qEnvironmentVariableIsSet("QMLPUPPET_RENDER_EFFECTS"); const bool smoothRendering = qEnvironmentVariableIsSet("QMLPUPPET_SMOOTH_RENDERING"); - int scaleFactor = smoothRendering ? 2 : 1; - if (renderEffects) { if (parentEffectItem(item)) return renderImage; @@ -430,17 +428,20 @@ QImage Qt5NodeInstanceServer::grabItem(QQuickItem *item) ServerNodeInstance instance = instanceForObject(item); + const bool rootIs3DObject = rootIsRenderable3DObject(); + // Setting layer enabled to false messes up the bounding rect. // Therefore we calculate it upfront. QRectF renderBoundingRect; if (instance.isValid()) renderBoundingRect = instance.boundingRect(); - - else if (rootIsRenderable3DObject()) + else if (rootIs3DObject) renderBoundingRect = item->boundingRect(); else renderBoundingRect = ServerNodeInstance::effectAdjustedBoundingRect(item); + const int scaleFactor = (smoothRendering && !rootIs3DObject) ? 2 : 1; + // Hide immediate children that have instances and are QQuickItems so we get only // the parent item's content, as compositing is handled on creator side. QSet layerChildren; @@ -521,7 +522,6 @@ QImage Qt5NodeInstanceServer::grabItem(QQuickItem *item) if (!isLayerEnabled(pItem)) pItem->derefFromEffectItem(false); - #else Q_UNUSED(item) #endif From 7ae288d355b9763ed495c1ebbf198809ed7e50f0 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Fri, 10 Jun 2022 21:10:52 +0200 Subject: [PATCH 18/96] QmlDesigner: Use changed properties to update 3D preview EffectReference is always dirty and it is the only dirty flag. Instead, we update now if any property changed. Task-number: QDS-7079 Change-Id: I157cf2d3b15120c33f4a6b3f53e526d555c7f80c Reviewed-by: Miikka Heikkinen --- .../qml2puppet/instances/qt5rendernodeinstanceserver.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5rendernodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5rendernodeinstanceserver.cpp index 2ff23395761..59e7a4aa821 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5rendernodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5rendernodeinstanceserver.cpp @@ -111,8 +111,6 @@ void Qt5RenderNodeInstanceServer::collectItemChangesAndSendChangeCommands() } } - clearChangedPropertyList(); - if (Internal::QuickItemNodeInstance::unifiedRenderPath()) { if (windowDirty) nodeInstanceClient()->pixmapChanged(createPixmapChangedCommand({rootNodeInstance()})); @@ -134,13 +132,15 @@ void Qt5RenderNodeInstanceServer::collectItemChangesAndSendChangeCommands() } if (rootIsRenderable3DObject() && rootNodeInstance().contentItem() - && DesignerSupport::isDirty(rootNodeInstance().contentItem(), - DesignerSupport::AllMask) + && !changedPropertyList().isEmpty() && nodeInstanceClient()->bytesToWrite() < 10000) { + Internal::QuickItemNodeInstance::updateDirtyNode(rootNodeInstance().contentItem()); nodeInstanceClient()->pixmapChanged(createPixmapChangedCommand({rootNodeInstance()})); } + clearChangedPropertyList(); + inFunction = false; } } From b307182e7694c433dbd31caa491696c1321c1361 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Mon, 13 Jun 2022 14:47:15 +0300 Subject: [PATCH 19/96] QmlDesigner: Fix occasional creator side crash related to puppet reset Change-Id: Iee032937b89b8ffcaa012c21b7cac029e1b286cf Reviewed-by: Mahmoud Badri --- .../qmldesigner/designercore/instances/nodeinstanceview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp index db22d27fc3d..278d65fcd9c 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp @@ -1717,7 +1717,7 @@ void NodeInstanceView::view3DAction(const View3DActionCommand &command) void NodeInstanceView::requestModelNodePreviewImage(const ModelNode &node, const ModelNode &renderNode) { - if (node.isValid()) { + if (m_nodeInstanceServer && node.isValid()) { auto instance = instanceForModelNode(node); if (instance.isValid()) { qint32 renderItemId = -1; From 50aadacb6e670597fc308d409bcdae96e7efa9c0 Mon Sep 17 00:00:00 2001 From: Samuel Ghinet Date: Wed, 8 Jun 2022 18:00:09 +0300 Subject: [PATCH 20/96] QDS Editor 3D: Allow the user to select (and reset) the color of grid lines Task-number: QDS-7122 Change-Id: I686269e61b53bd5e3d5d1225376930612d869072 Reviewed-by: Miikka Heikkinen Reviewed-by: Mahmoud Badri --- .../qmlpuppet/commands/createscenecommand.h | 7 +- .../qmlpuppet/commands/view3dactioncommand.h | 1 + .../qmlpuppet/mockfiles/qt5/EditView3D.qml | 18 ++- .../qmlpuppet/mockfiles/qt5/HelperGrid.qml | 1 + .../qmlpuppet/mockfiles/qt5/SceneView3D.qml | 1 + .../qmlpuppet/mockfiles/qt6/EditView3D.qml | 18 ++- .../qmlpuppet/mockfiles/qt6/HelperGrid.qml | 1 + .../qmlpuppet/mockfiles/qt6/SceneView3D.qml | 1 + .../qt5informationnodeinstanceserver.cpp | 30 +++-- .../qt5informationnodeinstanceserver.h | 2 +- src/plugins/qmldesigner/CMakeLists.txt | 1 + .../edit3d/backgroundcolorselection.cpp | 105 +++++++----------- .../edit3d/backgroundcolorselection.h | 13 ++- .../components/edit3d/edit3dactions.cpp | 3 +- .../components/edit3d/edit3dview.cpp | 99 ++++++++++++----- .../components/edit3d/edit3dview.h | 6 +- .../components/edit3d/edit3dviewconfig.h | 98 ++++++++++++++++ .../instances/nodeinstanceview.cpp | 31 ++---- src/plugins/qmldesigner/designersettings.cpp | 1 + src/plugins/qmldesigner/designersettings.h | 1 + .../qmldesigner/qmldesignerconstants.h | 1 + src/plugins/qmldesigner/qmldesignerplugin.qbs | 1 + 22 files changed, 299 insertions(+), 141 deletions(-) create mode 100644 src/plugins/qmldesigner/components/edit3d/edit3dviewconfig.h diff --git a/share/qtcreator/qml/qmlpuppet/commands/createscenecommand.h b/share/qtcreator/qml/qmlpuppet/commands/createscenecommand.h index c69d478875d..47196df8d24 100644 --- a/share/qtcreator/qml/qmlpuppet/commands/createscenecommand.h +++ b/share/qtcreator/qml/qmlpuppet/commands/createscenecommand.h @@ -61,7 +61,8 @@ public: QSize captureImageMinimumSize, QSize captureImageMaximumSize, qint32 stateInstanceId, - const QList &edit3dBackgroundColor) + const QList &edit3dBackgroundColor, + const QColor &edit3dGridColor) : instances(instanceContainer) , reparentInstances(reparentContainer) , ids(idVector) @@ -78,6 +79,7 @@ public: , captureImageMaximumSize(captureImageMaximumSize) , stateInstanceId{stateInstanceId} , edit3dBackgroundColor{edit3dBackgroundColor} + , edit3dGridColor{edit3dGridColor} {} friend QDataStream &operator<<(QDataStream &out, const CreateSceneCommand &command) @@ -98,6 +100,7 @@ public: out << command.captureImageMinimumSize; out << command.captureImageMaximumSize; out << command.edit3dBackgroundColor; + out << command.edit3dGridColor; return out; } @@ -120,6 +123,7 @@ public: in >> command.captureImageMinimumSize; in >> command.captureImageMaximumSize; in >> command.edit3dBackgroundColor; + in >> command.edit3dGridColor; return in; } @@ -141,6 +145,7 @@ public: QSize captureImageMaximumSize; qint32 stateInstanceId = 0; QList edit3dBackgroundColor; + QColor edit3dGridColor; }; QDebug operator<<(QDebug debug, const CreateSceneCommand &command); diff --git a/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h b/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h index cc3611df764..a1dc133032e 100644 --- a/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h +++ b/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h @@ -57,6 +57,7 @@ public: ParticlesRestart, ParticlesSeek, SelectBackgroundColor, + SelectGridColor, ResetBackgroundColor, }; diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/EditView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/EditView3D.qml index 9a95ca34b98..09a4ebdc3f3 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/EditView3D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/EditView3D.qml @@ -47,6 +47,7 @@ Item { property alias contentItem: contentItem property color backgroundGradientColorStart: "#222222" property color backgroundGradientColorEnd: "#999999" + property color gridColor: "#aaaaaa" enum SelectionMode { Item, Group } enum TransformMode { Move, Rotate, Scale } @@ -96,12 +97,14 @@ Item { {"usePerspective": usePerspective, "showSceneLight": showEditLight, "showGrid": showGrid, + "gridColor": gridColor, "importScene": activeScene, "cameraZoomFactor": cameraControl._zoomFactor, "z": 1}); editView.usePerspective = Qt.binding(function() {return usePerspective;}); editView.showSceneLight = Qt.binding(function() {return showEditLight;}); editView.showGrid = Qt.binding(function() {return showGrid;}); + editView.gridColor = Qt.binding(function() {return gridColor;}); editView.cameraZoomFactor = Qt.binding(function() {return cameraControl._zoomFactor;}); selectionBoxes.length = 0; @@ -217,10 +220,19 @@ Item { function updateViewStates(viewStates) { if ("selectBackgroundColor" in viewStates) { - var color = viewStates.selectBackgroundColor - backgroundGradientColorStart = color[0]; - backgroundGradientColorEnd = color[1]; + if (Array.isArray(viewStates.selectBackgroundColor)) { + var colors = viewStates.selectBackgroundColor + backgroundGradientColorStart = colors[0]; + backgroundGradientColorEnd = colors[1]; + } else { + var color = viewStates.selectBackgroundColor + backgroundGradientColorStart = color; + backgroundGradientColorEnd = color; + } } + + if ("selectGridColor" in viewStates) + viewRoot.gridColor = viewStates.selectGridColor } // If resetToDefault is true, tool states not specifically set to anything will be reset to diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/HelperGrid.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/HelperGrid.qml index e450a5a796c..d9df67fe7c4 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/HelperGrid.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/HelperGrid.qml @@ -33,6 +33,7 @@ Node { property alias lines: gridGeometry.lines property alias step: gridGeometry.step property alias subdivAlpha: subGridMaterial.opacity + property alias gridColor: mainGridMaterial.diffuseColor eulerRotation.x: 90 diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/SceneView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/SceneView3D.qml index 7a376179d82..4032e245ed0 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/SceneView3D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/SceneView3D.qml @@ -32,6 +32,7 @@ View3D { property bool usePerspective: false property alias showSceneLight: sceneLight.visible property alias showGrid: helperGrid.visible + property alias gridColor: helperGrid.gridColor property alias sceneHelpers: sceneHelpers property alias perspectiveCamera: scenePerspectiveCamera property alias orthoCamera: sceneOrthoCamera diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditView3D.qml index 228154a9a49..a3f14e9d113 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditView3D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditView3D.qml @@ -48,6 +48,7 @@ Item { property alias contentItem: contentItem property color backgroundGradientColorStart: "#222222" property color backgroundGradientColorEnd: "#999999" + property color gridColor: "#aaaaaa" enum SelectionMode { Item, Group } enum TransformMode { Move, Rotate, Scale } @@ -100,12 +101,14 @@ Item { {"usePerspective": usePerspective, "showSceneLight": showEditLight, "showGrid": showGrid, + "gridColor": gridColor, "importScene": activeScene, "cameraZoomFactor": cameraControl._zoomFactor, "z": 1}); editView.usePerspective = Qt.binding(function() {return usePerspective;}); editView.showSceneLight = Qt.binding(function() {return showEditLight;}); editView.showGrid = Qt.binding(function() {return showGrid;}); + editView.gridColor = Qt.binding(function() {return gridColor;}); editView.cameraZoomFactor = Qt.binding(function() {return cameraControl._zoomFactor;}); selectionBoxes.length = 0; @@ -211,10 +214,19 @@ Item { function updateViewStates(viewStates) { if ("selectBackgroundColor" in viewStates) { - var color = viewStates.selectBackgroundColor - backgroundGradientColorStart = color[0]; - backgroundGradientColorEnd = color[1]; + if (Array.isArray(viewStates.selectBackgroundColor)) { + var colors = viewStates.selectBackgroundColor + backgroundGradientColorStart = colors[0]; + backgroundGradientColorEnd = colors[1]; + } else { + var color = viewStates.selectBackgroundColor + backgroundGradientColorStart = color; + backgroundGradientColorEnd = color; + } } + + if ("selectGridColor" in viewStates) + viewRoot.gridColor = viewStates.selectGridColor } // If resetToDefault is true, tool states not specifically set to anything will be reset to diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/HelperGrid.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/HelperGrid.qml index 66f383518eb..ef10818eedc 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/HelperGrid.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/HelperGrid.qml @@ -33,6 +33,7 @@ Node { property alias lines: gridGeometry.lines property alias step: gridGeometry.step property alias subdivAlpha: subGridMaterial.opacity + property alias gridColor: mainGridMaterial.diffuseColor eulerRotation.x: 90 diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/SceneView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/SceneView3D.qml index e59392b1ee2..1d0e0377d3b 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/SceneView3D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/SceneView3D.qml @@ -32,6 +32,7 @@ View3D { property bool usePerspective: false property alias showSceneLight: sceneLight.visible property alias showGrid: helperGrid.visible + property alias gridColor: helperGrid.gridColor property alias sceneHelpers: sceneHelpers property alias perspectiveCamera: scenePerspectiveCamera property alias orthoCamera: sceneOrthoCamera diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp index effa871ce6d..d614901ca97 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp @@ -1742,7 +1742,7 @@ QObject *Qt5InformationNodeInstanceServer::find3DSceneRoot(QObject *obj) const } void Qt5InformationNodeInstanceServer::setup3DEditView(const QList &instanceList, - const QHash &toolStates) + const CreateSceneCommand &command) { #ifdef QUICK3D_MODULE if (!m_editView3DData.rootItem) @@ -1775,6 +1775,7 @@ void Qt5InformationNodeInstanceServer::setup3DEditView(const QList &toolStates = command.edit3dToolStates; QString lastSceneId; auto helper = qobject_cast(m_3dHelper); if (helper) { @@ -1828,11 +1829,23 @@ void Qt5InformationNodeInstanceServer::setup3DEditView(const QListcomponentCompleted(createComponentCompletedCommand(instanceList)); if (ViewConfig::isQuick3DMode()) { - setup3DEditView(instanceList, command.edit3dToolStates); + setup3DEditView(instanceList, command); updateRotationBlocks(command.auxiliaryChanges); } @@ -1963,12 +1976,6 @@ void Qt5InformationNodeInstanceServer::createScene(const CreateSceneCommand &com #ifdef IMPORT_QUICK3D_ASSETS QTimer::singleShot(0, this, &Qt5InformationNodeInstanceServer::resolveImportSupport); #endif - - if (!command.edit3dBackgroundColor.isEmpty()) { - View3DActionCommand backgroundColorCommand(View3DActionCommand::SelectBackgroundColor, - QVariant::fromValue(command.edit3dBackgroundColor)); - view3DAction(backgroundColorCommand); - } } void Qt5InformationNodeInstanceServer::sendChildrenChangedCommand(const QList &childList) @@ -2233,9 +2240,12 @@ void Qt5InformationNodeInstanceServer::view3DAction(const View3DActionCommand &c case View3DActionCommand::ShowCameraFrustum: updatedToolState.insert("showCameraFrustum", command.isEnabled()); break; - case View3DActionCommand::SelectBackgroundColor: { + case View3DActionCommand::SelectBackgroundColor: updatedViewState.insert("selectBackgroundColor", command.value()); break; + case View3DActionCommand::SelectGridColor: { + updatedViewState.insert("selectGridColor", command.value()); + break; } #ifdef QUICK3D_PARTICLES_MODULE case View3DActionCommand::ShowParticleEmitter: diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h index 291b2c3eecd..9f6e4506908 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h @@ -114,7 +114,7 @@ private: void createEditView3D(); void create3DPreviewView(); void setup3DEditView(const QList &instanceList, - const QHash &toolStates); + const CreateSceneCommand &command); void createCameraAndLightGizmos(const QList &instanceList) const; void add3DViewPorts(const QList &instanceList); void add3DScenes(const QList &instanceList); diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index 1ac2f477bf3..bd55391a314 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -158,6 +158,7 @@ extend_qtc_plugin(QmlDesigner SOURCES_PREFIX components/edit3d SOURCES edit3dview.cpp edit3dview.h + edit3dviewconfig.h edit3dwidget.cpp edit3dwidget.h edit3dcanvas.cpp edit3dcanvas.h edit3dactions.cpp edit3dactions.h diff --git a/src/plugins/qmldesigner/components/edit3d/backgroundcolorselection.cpp b/src/plugins/qmldesigner/components/edit3d/backgroundcolorselection.cpp index 76db41a177e..3d7a9207c08 100644 --- a/src/plugins/qmldesigner/components/edit3d/backgroundcolorselection.cpp +++ b/src/plugins/qmldesigner/components/edit3d/backgroundcolorselection.cpp @@ -23,85 +23,56 @@ ** ****************************************************************************/ -#include "backgroundcolorselection.h" +#pragma once + +#include -#include #include -#include -#include + +#include "backgroundcolorselection.h" +#include "edit3dviewconfig.h" using namespace QmlDesigner; -namespace { -QList readBackgroundColorConfiguration() -{ - QVariant var = QmlDesigner::DesignerSettings::getValue( - QmlDesigner::DesignerSettingsKey::EDIT3DVIEW_BACKGROUND_COLOR); - - if (!var.isValid()) - return {}; - - auto colorNameList = var.value>(); - QTC_ASSERT(colorNameList.size() == 2, return {}); - - return {colorNameList[0], colorNameList[1]}; -} - -void setBackgroundColorConfiguration(const QList &colorConfig) -{ - auto view = QmlDesignerPlugin::instance()->viewManager().nodeInstanceView(); - View3DActionCommand cmd(View3DActionCommand::SelectBackgroundColor, - QVariant::fromValue(colorConfig)); - view->view3DAction(cmd); -} - -void saveBackgroundColorConfiguration(const QList &colorConfig) -{ - QList colorsSaved = {colorConfig[0].name(), colorConfig[1].name()}; - QmlDesigner::DesignerSettings::setValue( - QmlDesigner::DesignerSettingsKey::EDIT3DVIEW_BACKGROUND_COLOR, - QVariant::fromValue(colorsSaved)); -} - -} // namespace - -QColorDialog *BackgroundColorSelection::createDialog(QWidget *parent) -{ - auto dialog = new QColorDialog(parent); - - dialog->setModal(true); - dialog->setAttribute(Qt::WA_DeleteOnClose); - - const QList oldColorConfig = readBackgroundColorConfiguration(); - - dialog->show(); - - QObject::connect(dialog, &QColorDialog::currentColorChanged, dialog, [](const QColor &color) { - setBackgroundColorConfiguration({color, color}); - }); - - QObject::connect(dialog, &QColorDialog::colorSelected, dialog, [](const QColor &color) { - saveBackgroundColorConfiguration({color, color}); - }); - - if (!oldColorConfig.isEmpty()) { - QObject::connect(dialog, &QColorDialog::rejected, dialog, [oldColorConfig]() { - setBackgroundColorConfiguration(oldColorConfig); - }); - } - - return dialog; -} - -void BackgroundColorSelection::showBackgroundColorSelectionWidget(QWidget *parent) +void BackgroundColorSelection::showBackgroundColorSelectionWidget(QWidget *parent, const QByteArray &key, + View3DActionCommand::Type cmdType) { if (m_dialog) return; - m_dialog = BackgroundColorSelection::createDialog(parent); + m_dialog = BackgroundColorSelection::createColorDialog(parent, key, cmdType); QTC_ASSERT(m_dialog, return); QObject::connect(m_dialog, &QWidget::destroyed, m_dialog, [&]() { m_dialog = nullptr; }); } + +QColorDialog *BackgroundColorSelection::createColorDialog(QWidget *parent, const QByteArray &key, + View3DActionCommand::Type cmdType) +{ + auto dialog = new QColorDialog(parent); + + dialog->setModal(true); + dialog->setAttribute(Qt::WA_DeleteOnClose); + + QList oldColorConfig = Edit3DViewConfig::load(key); + + dialog->show(); + + QObject::connect(dialog, &QColorDialog::currentColorChanged, dialog, [cmdType](const QColor &color) { + Edit3DViewConfig::set(cmdType, color); + }); + + QObject::connect(dialog, &QColorDialog::colorSelected, dialog, [key](const QColor &color) { + Edit3DViewConfig::save(key, color); + }); + + if (Edit3DViewConfig::isValid(oldColorConfig)) { + QObject::connect(dialog, &QColorDialog::rejected, dialog, [cmdType, oldColorConfig]() { + Edit3DViewConfig::set(cmdType, oldColorConfig); + }); + } + + return dialog; +} diff --git a/src/plugins/qmldesigner/components/edit3d/backgroundcolorselection.h b/src/plugins/qmldesigner/components/edit3d/backgroundcolorselection.h index d8832f40fda..f7df55b8e30 100644 --- a/src/plugins/qmldesigner/components/edit3d/backgroundcolorselection.h +++ b/src/plugins/qmldesigner/components/edit3d/backgroundcolorselection.h @@ -25,9 +25,13 @@ #pragma once -#include +#include +#include + +QT_FORWARD_DECLARE_CLASS(QColorDialog) namespace QmlDesigner { + class BackgroundColorSelection : public QObject { Q_OBJECT @@ -37,10 +41,13 @@ public: : QObject{parent} {} - static void showBackgroundColorSelectionWidget(QWidget *parent); + static void showBackgroundColorSelectionWidget(QWidget *parent, const QByteArray &key, + View3DActionCommand::Type cmdType); private: - static QColorDialog *createDialog(QWidget *parent); + static QColorDialog *createColorDialog(QWidget *parent, const QByteArray &key, + View3DActionCommand::Type cmdType); + inline static QColorDialog *m_dialog = nullptr; }; diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dactions.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dactions.cpp index 76343584c9c..e90f20767d1 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dactions.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dactions.cpp @@ -48,7 +48,8 @@ Edit3DActionTemplate::Edit3DActionTemplate(const QString &description, void Edit3DActionTemplate::actionTriggered(bool b) { - if (m_type != View3DActionCommand::Empty && m_type != View3DActionCommand::SelectBackgroundColor) { + if (m_type != View3DActionCommand::Empty && m_type != View3DActionCommand::SelectBackgroundColor + && m_type != View3DActionCommand::SelectGridColor) { auto view = QmlDesignerPlugin::instance()->viewManager().nodeInstanceView(); View3DActionCommand cmd(m_type, b); view->view3DAction(cmd); diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp index 1ef3055ada6..aa76d58370d 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp @@ -28,6 +28,8 @@ #include "edit3dcanvas.h" #include "edit3dview.h" #include "edit3dwidget.h" +#include "edit3dviewconfig.h" +#include "backgroundcolorselection.h" #include #include @@ -42,8 +44,6 @@ #include #include -#include - #include #include @@ -266,6 +266,70 @@ void Edit3DView::setSeeker(SeekerSlider *slider) m_seeker = slider; } +Edit3DAction *Edit3DView::createSelectBackgrounColorAction() +{ + QString description = QCoreApplication::translate("SelectBackgroundColorAction", + "Select Background Color"); + QString tooltip = QCoreApplication::translate("SelectBackgroundColorAction", + "Select a color for the background of the 3D Editor."); + + auto operation = [this](const SelectionContext &) { + BackgroundColorSelection::showBackgroundColorSelectionWidget( + edit3DWidget(), + DesignerSettingsKey::EDIT3DVIEW_BACKGROUND_COLOR, + View3DActionCommand::SelectBackgroundColor); + }; + + return new Edit3DAction( + Constants::EDIT3D_EDIT_SELECT_BACKGROUND_COLOR, View3DActionCommand::SelectBackgroundColor, + description, + {}, false, false, {}, {}, operation, + tooltip); +} + +Edit3DAction *Edit3DView::createGridColorSelectionAction() +{ + QString description = QCoreApplication::translate("SelectGridColorAction", "Select Grid Color"); + QString tooltip = QCoreApplication::translate("SelectGridColorAction", + "Select a color for the grid lines of the 3D Editor."); + + auto operation = [this](const SelectionContext &) { + BackgroundColorSelection::showBackgroundColorSelectionWidget( + edit3DWidget(), + DesignerSettingsKey::EDIT3DVIEW_GRID_COLOR, + View3DActionCommand::SelectGridColor); + }; + + return new Edit3DAction( + Constants::EDIT3D_EDIT_SELECT_GRID_COLOR, View3DActionCommand::SelectGridColor, + description, {}, false, false, {}, {}, operation, + tooltip); +} + +Edit3DAction *Edit3DView::createResetColorAction() +{ + QString description = QCoreApplication::translate("ResetEdit3DColorsAction", "Reset Colors"); + QString tooltip = QCoreApplication::translate("ResetEdit3DColorsAction", + "Reset the background color and the color of the " + "grid lines of the 3D Editor to the default valus."); + + auto operation = [](const SelectionContext &) { + QList bgColors = {QRgb(0x222222), QRgb(0x999999)}; + Edit3DViewConfig::set(View3DActionCommand::SelectBackgroundColor, bgColors); + Edit3DViewConfig::save(DesignerSettingsKey::EDIT3DVIEW_BACKGROUND_COLOR, bgColors); + + QColor gridColor{0xaaaaaa}; + Edit3DViewConfig::set(View3DActionCommand::SelectGridColor, gridColor); + Edit3DViewConfig::save(DesignerSettingsKey::EDIT3DVIEW_GRID_COLOR, gridColor); + }; + + return new Edit3DAction( + QmlDesigner::Constants::EDIT3D_EDIT_RESET_BACKGROUND_COLOR, View3DActionCommand::ResetBackgroundColor, + description, + {}, false, false, {}, {}, operation, + tooltip); +} + void Edit3DView::createEdit3DActions() { m_selectionModeAction @@ -338,32 +402,6 @@ void Edit3DView::createEdit3DActions() QKeySequence(Qt::Key_G), true, true, {}, {}, nullptr, QCoreApplication::translate("ShowGridAction", "Toggle the visibility of the helper grid.")); - SelectionContextOperation showBackgroundColorSelection = [this](const SelectionContext &) { - BackgroundColorSelection::showBackgroundColorSelectionWidget(edit3DWidget()); - }; - - m_backgroundColorSelectionAction = new Edit3DAction( - QmlDesigner::Constants::EDIT3D_EDIT_SELECT_BACKGROUND_COLOR, View3DActionCommand::SelectBackgroundColor, - QCoreApplication::translate("SelectBackgroundColorAction", "Select Background Color"), - {}, false, false, {}, {}, showBackgroundColorSelection, - QCoreApplication::translate("SelectBackgroundColorAction", "Select a color for the background of the 3D Editor.")); - - m_resetBackgroundColorAction = new Edit3DAction( - QmlDesigner::Constants::EDIT3D_EDIT_RESET_BACKGROUND_COLOR, View3DActionCommand::ResetBackgroundColor, - QCoreApplication::translate("ResetBackgroundColorAction", "Reset Background Color"), - {}, false, false, {}, {}, [](const SelectionContext &) { - QList colors = {QRgb(0x222222), QRgb(0x999999)}; - auto view = QmlDesignerPlugin::instance()->viewManager().nodeInstanceView(); - View3DActionCommand cmd(View3DActionCommand::SelectBackgroundColor, QVariant::fromValue(colors)); - view->view3DAction(cmd); - - QList colorsToSave = {colors[0].name(), colors[1].name()}; - QmlDesigner::DesignerSettings::setValue( - QmlDesigner::DesignerSettingsKey::EDIT3DVIEW_BACKGROUND_COLOR, - QVariant::fromValue(colorsToSave)); - }, - QCoreApplication::translate("ResetBackgroundColorAction", "Reset background color of the 3D Editor to the default value.")); - m_showSelectionBoxAction = new Edit3DAction( QmlDesigner::Constants::EDIT3D_EDIT_SHOW_SELECTION_BOX, View3DActionCommand::ShowSelectionBox, QCoreApplication::translate("ShowSelectionBoxAction", "Show Selection Boxes"), @@ -521,8 +559,9 @@ void Edit3DView::createEdit3DActions() m_visibilityToggleActions << m_showCameraFrustumAction; m_visibilityToggleActions << m_showParticleEmitterAction; - m_backgroundColorActions << m_backgroundColorSelectionAction; - m_backgroundColorActions << m_resetBackgroundColorAction; + m_backgroundColorActions << createSelectBackgrounColorAction(); + m_backgroundColorActions << createGridColorSelectionAction(); + m_backgroundColorActions << createResetColorAction(); } QVector Edit3DView::leftActions() const diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.h b/src/plugins/qmldesigner/components/edit3d/edit3dview.h index e5cb2aba51b..b817c20d1a4 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dview.h +++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.h @@ -85,6 +85,10 @@ private: void createEdit3DWidget(); void checkImports(); + Edit3DAction *createSelectBackgrounColorAction(); + Edit3DAction *createGridColorSelectionAction(); + Edit3DAction *createResetColorAction(); + QPointer m_edit3DWidget; QVector m_leftActions; QVector m_rightActions; @@ -101,8 +105,6 @@ private: Edit3DAction *m_orientationModeAction = nullptr; Edit3DAction *m_editLightAction = nullptr; Edit3DAction *m_showGridAction = nullptr; - Edit3DAction *m_backgroundColorSelectionAction = nullptr; - Edit3DAction *m_resetBackgroundColorAction = nullptr; Edit3DAction *m_showSelectionBoxAction = nullptr; Edit3DAction *m_showIconGizmoAction = nullptr; Edit3DAction *m_showCameraFrustumAction = nullptr; diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dviewconfig.h b/src/plugins/qmldesigner/components/edit3d/edit3dviewconfig.h new file mode 100644 index 00000000000..8e4081176af --- /dev/null +++ b/src/plugins/qmldesigner/components/edit3d/edit3dviewconfig.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include + +#include +#include + +#include +#include + +namespace QmlDesigner { + +class Edit3DViewConfig +{ +public: + static QList load(const char key[]) + { + QVariant var = DesignerSettings::getValue(key); + + if (!var.isValid()) + return {}; + + auto colorNameList = var.value(); + + return Utils::transform(colorNameList, [](const QString &colorName) { + return QColor{colorName}; + }); + } + + static void set(View3DActionCommand::Type type, const QList &colorConfig) + { + if (colorConfig.size() == 1) + set(type, colorConfig.at(0)); + else + setVariant(type, QVariant::fromValue(colorConfig)); + } + + static void set(View3DActionCommand::Type type, const QColor &color) + { + setVariant(type, QVariant::fromValue(color)); + } + + static void save(const QByteArray &key, const QList &colorConfig) + { + QStringList colorNames = Utils::transform(colorConfig, [](const QColor &color) { + return color.name(); + }); + + saveVariant(key, QVariant::fromValue(colorNames)); + } + + static void save(const QByteArray &key, const QColor &color) + { + saveVariant(key, QVariant::fromValue(color.name())); + } + + static bool isValid(const QList &colorConfig) { return !colorConfig.isEmpty(); } + +private: + static void setVariant(View3DActionCommand::Type type, const QVariant &colorConfig) + { + auto view = QmlDesignerPlugin::instance()->viewManager().nodeInstanceView(); + View3DActionCommand cmd(type, colorConfig); + view->view3DAction(cmd); + } + + static void saveVariant(const QByteArray &key, const QVariant &colorConfig) + { + DesignerSettings::setValue(key, colorConfig); + } +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp index 278d65fcd9c..196faf2848e 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp @@ -94,6 +94,8 @@ #include +#include + #include #include @@ -983,17 +985,6 @@ QList filterNodesForSkipItems(const QList &nodeList) return filteredNodeList; } -QList readBackgroundColorConfiguration(const QVariant &var) -{ - if (!var.isValid()) - return {}; - - auto colorNameList = var.value>(); - QTC_ASSERT(colorNameList.size() == 2, return {}); - - return {colorNameList[0], colorNameList[1]}; -} - CreateSceneCommand NodeInstanceView::createCreateSceneCommand() { QList nodeList = allModelNodes(); @@ -1148,16 +1139,15 @@ CreateSceneCommand NodeInstanceView::createCreateSceneCommand() if (stateNode.isValid() && stateNode.metaInfo().isSubclassOf("QtQuick.State", 1, 0)) stateInstanceId = stateNode.internalId(); - QVariant value + QColor gridColor; + QList backgroundColor; + #ifndef QMLDESIGNER_TEST - = QmlDesigner::DesignerSettings::getValue( - QmlDesigner::DesignerSettingsKey::EDIT3DVIEW_BACKGROUND_COLOR); -#else - = {}; + backgroundColor = Edit3DViewConfig::load(DesignerSettingsKey::EDIT3DVIEW_BACKGROUND_COLOR); + QList gridColorList = Edit3DViewConfig::load(DesignerSettingsKey::EDIT3DVIEW_GRID_COLOR); + if (!gridColorList.isEmpty()) + gridColor = gridColorList.at(0); #endif - QList edit3dBackgroundColor; - if (value.isValid()) - edit3dBackgroundColor = readBackgroundColorConfiguration(value); return CreateSceneCommand( instanceContainerList, @@ -1180,7 +1170,8 @@ CreateSceneCommand NodeInstanceView::createCreateSceneCommand() m_captureImageMinimumSize, m_captureImageMaximumSize, stateInstanceId, - edit3dBackgroundColor); + backgroundColor, + gridColor); } ClearSceneCommand NodeInstanceView::createClearSceneCommand() const diff --git a/src/plugins/qmldesigner/designersettings.cpp b/src/plugins/qmldesigner/designersettings.cpp index 5474fd50d34..1b9651d471d 100644 --- a/src/plugins/qmldesigner/designersettings.cpp +++ b/src/plugins/qmldesigner/designersettings.cpp @@ -82,6 +82,7 @@ void DesignerSettings::fromSettings(QSettings *settings) restoreValue(settings, DesignerSettingsKey::ASK_BEFORE_DELETING_ASSET, true); const QStringList defaultValue = QStringList() << "#222222" << "#999999"; restoreValue(settings, DesignerSettingsKey::EDIT3DVIEW_BACKGROUND_COLOR, defaultValue); + restoreValue(settings, DesignerSettingsKey::EDIT3DVIEW_GRID_COLOR, "#aaaaaa"); restoreValue(settings, DesignerSettingsKey::SMOOTH_RENDERING, false); settings->endGroup(); diff --git a/src/plugins/qmldesigner/designersettings.h b/src/plugins/qmldesigner/designersettings.h index 4dbee7752ba..f39268b1869 100644 --- a/src/plugins/qmldesigner/designersettings.h +++ b/src/plugins/qmldesigner/designersettings.h @@ -50,6 +50,7 @@ const char WARNING_FOR_DESIGNER_FEATURES_IN_EDITOR[] = "WarnAboutQtQuickDesigner const char SHOW_DEBUGVIEW[] = "ShowQtQuickDesignerDebugView"; const char ENABLE_DEBUGVIEW[] = "EnableQtQuickDesignerDebugView"; const char EDIT3DVIEW_BACKGROUND_COLOR[] = "Edit3DViewBackgroundColor"; +const char EDIT3DVIEW_GRID_COLOR[] = "Edit3DViewGridLineColor"; const char ALWAYS_SAVE_IN_CRUMBLEBAR[] = "AlwaysSaveInCrumbleBar"; const char USE_DEFAULT_PUPPET[] = "UseDefaultQml2Puppet"; const char PUPPET_TOPLEVEL_BUILD_DIRECTORY[] = "PuppetToplevelBuildDirectory"; diff --git a/src/plugins/qmldesigner/qmldesignerconstants.h b/src/plugins/qmldesigner/qmldesignerconstants.h index 8dc2b947496..b2ed51cd874 100644 --- a/src/plugins/qmldesigner/qmldesignerconstants.h +++ b/src/plugins/qmldesigner/qmldesignerconstants.h @@ -66,6 +66,7 @@ const char EDIT3D_ORIENTATION[] = "QmlDesigner.Editor3D.OrientationToggle"; const char EDIT3D_EDIT_LIGHT[] = "QmlDesigner.Editor3D.EditLightToggle"; const char EDIT3D_EDIT_SHOW_GRID[] = "QmlDesigner.Editor3D.ToggleGrid"; const char EDIT3D_EDIT_SELECT_BACKGROUND_COLOR[] = "QmlDesigner.Editor3D.SelectBackgroundColor"; +const char EDIT3D_EDIT_SELECT_GRID_COLOR[] = "QmlDesigner.Editor3D.SelectGridColor"; const char EDIT3D_EDIT_RESET_BACKGROUND_COLOR[] = "QmlDesigner.Editor3D.ResetBackgroundColor"; const char EDIT3D_EDIT_SHOW_SELECTION_BOX[] = "QmlDesigner.Editor3D.ToggleSelectionBox"; const char EDIT3D_EDIT_SHOW_ICON_GIZMO[] = "QmlDesigner.Editor3D.ToggleIconGizmo"; diff --git a/src/plugins/qmldesigner/qmldesignerplugin.qbs b/src/plugins/qmldesigner/qmldesignerplugin.qbs index 5266a146a3d..be482a22ca6 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.qbs +++ b/src/plugins/qmldesigner/qmldesignerplugin.qbs @@ -530,6 +530,7 @@ Project { "debugview/debugviewwidget.ui", "edit3d/edit3dview.cpp", "edit3d/edit3dview.h", + "edit3d/edit3dviewconfig.h", "edit3d/backgroundcolorselection.cpp", "edit3d/backgroundcolorselection.h", "edit3d/edit3dwidget.cpp", From 9c3636af497f8bdb2745bf85cc0286c9c6675987 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Mon, 13 Jun 2022 14:51:27 +0300 Subject: [PATCH 21/96] QmlDesigner: Ensure materials render properly after puppet reset This is a workaround for quick3d issue QTBUG-103316, where material library materials for editor are properly initialized only if the first encountered View3D in the scene is also rendered first. Fixes: QDS-7084 Change-Id: I8bb6a8e6bfe2fcffddfe86f92157d386fdf4095d Reviewed-by: Reviewed-by: Thomas Hartmann --- .../qt5informationnodeinstanceserver.cpp | 42 ++++++++++++++++++- .../qt5informationnodeinstanceserver.h | 1 + 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp index d614901ca97..97a60b54059 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp @@ -848,6 +848,18 @@ void Qt5InformationNodeInstanceServer::updateActiveSceneToEditView3D(bool timerC m_activeSceneIdUpdateTimer.stop(); } + // We may have to substitute another scene to work around QTBUG-103316 + // The worked around issue is that if a material is used in multiple scenes, there is some + // kind of ownership for it in the first View3D that uses it, so if that view is not rendered + // first, the material will not be properly initialized for other views using it. + // To make materials work properly, we ensure that views are rendered at least once in the + // order they appear in the scene. + if (!m_priorityView3DsToRender.isEmpty()) { + QObject *sceneRoot = find3DSceneRoot(m_priorityView3DsToRender.first()); + if (sceneRoot) + activeSceneVar = objectToVariant(sceneRoot); + } + QMetaObject::invokeMethod(m_editView3DData.rootItem, "setActiveScene", Qt::QueuedConnection, Q_ARG(QVariant, activeSceneVar), Q_ARG(QVariant, QVariant::fromValue(sceneId))); @@ -1010,7 +1022,7 @@ void Qt5InformationNodeInstanceServer::doRender3DEditView() // If we have only one or no render queued, send the result to the creator side. // Otherwise, we'll hold on that until we have rendered all pending frames to ensure sent // results are correct. - if (m_need3DEditViewRender <= 1) { + if (m_priorityView3DsToRender.isEmpty() && m_need3DEditViewRender <= 1) { nodeInstanceClient()->handlePuppetToCreatorCommand({PuppetToCreatorCommand::Render3DView, QVariant::fromValue(imgContainer)}); #ifdef QUICK3D_PARTICLES_MODULE @@ -1021,6 +1033,25 @@ void Qt5InformationNodeInstanceServer::doRender3DEditView() #endif } + if (!m_priorityView3DsToRender.isEmpty()) { + static int tryCounter = 0; + QObject *sceneRoot = find3DSceneRoot(m_priorityView3DsToRender.first()); + bool needAnotherRender = false; + if (sceneRoot) { + // Active scene is updated asynchronously, so verify we are actually rendering + // the correct priority scene + QObject *activeScene = QQmlProperty::read(m_editView3DData.rootItem, "activeScene").value(); + needAnotherRender = activeScene != sceneRoot; + } + + if (!needAnotherRender || ++tryCounter > 10) { + m_priorityView3DsToRender.removeFirst(); + updateActiveSceneToEditView3D(); + tryCounter = 0; + } + ++m_need3DEditViewRender; + } + if (m_need3DEditViewRender > 0) { // We queue another render even if the requested render count was one, because another // render is needed to ensure gizmo geometries are properly updated. @@ -1057,6 +1088,13 @@ void Qt5InformationNodeInstanceServer::doRenderModelNodeImageView() { // This crashes on Qt 6.0.x due to QtQuick3D issue, so the preview generation is disabled #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) || QT_VERSION >= QT_VERSION_CHECK(6, 1, 0) + if (!m_priorityView3DsToRender.isEmpty()) { + // Postpone any preview renders until we have rendered the priority views to ensure + // materials in material library are properly initialized + m_renderModelNodeImageViewTimer.start(17); + return; + } + RequestModelNodePreviewImageCommand cmd = *m_modelNodePreviewImageCommands.begin(); ServerNodeInstance instance; if (cmd.renderItemId() >= 0) @@ -1574,6 +1612,8 @@ void Qt5InformationNodeInstanceServer::add3DViewPorts(const QList m_view3Ds; QMultiHash m_3DSceneMap; // key: scene root, value: node QObject *m_active3DView = nullptr; + QList m_priorityView3DsToRender; QObject *m_active3DScene = nullptr; QSet m_parentChangedSet; QList m_completedComponentList; From 221376aa3823df2d36dedaf2e1ab97231c0ffbde Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 16 Jun 2022 15:30:25 +0300 Subject: [PATCH 22/96] QmlDesigner: Reset puppet when material is added This is workaround for material rendering issues in quick3d when a material is shared by multiple windows. Fixes: QDS-7096 Fixes: QDS-7118 Change-Id: I64fe2e51c5dda8e238502e5d926b6938b7b0731a Reviewed-by: Thomas Hartmann --- .../materialbrowser/materialbrowsermodel.cpp | 5 ++++ .../materialbrowser/materialbrowsermodel.h | 1 + .../materialbrowser/materialbrowserview.cpp | 26 ++++++++++++++----- .../materialbrowser/materialbrowserview.h | 2 +- 4 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp index d0420163c3a..49f313534d1 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp @@ -120,6 +120,11 @@ void MaterialBrowserModel::setHasModelSelection(bool b) emit hasModelSelectionChanged(); } +QList MaterialBrowserModel::materials() const +{ + return m_materialList; +} + void MaterialBrowserModel::setSearchText(const QString &searchText) { QString lowerSearchText = searchText.toLower(); diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h index 32db357caeb..73e6b2f99c6 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h @@ -58,6 +58,7 @@ public: bool hasModelSelection() const; void setHasModelSelection(bool b); + QList materials() const; void setMaterials(const QList &materials, bool hasQuick3DImport); void removeMaterial(const ModelNode &material); void updateMaterialName(const ModelNode &material); diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp index 9d6072856e9..1af67d4fef7 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp @@ -97,10 +97,12 @@ void MaterialBrowserView::modelAttached(Model *model) m_widget->clearSearchFilter(); m_hasQuick3DImport = model->hasImport("QtQuick3D"); - QTimer::singleShot(0, this, &MaterialBrowserView::refreshModel); + QTimer::singleShot(0, this, [this]() { + refreshModel(true); + }); } -void MaterialBrowserView::refreshModel() +void MaterialBrowserView::refreshModel(bool updateImages) { ModelNode matLib = modelNodeForId(Constants::MATERIAL_LIB_ID); QList materials; @@ -115,8 +117,10 @@ void MaterialBrowserView::refreshModel() m_widget->materialBrowserModel()->setMaterials(materials, m_hasQuick3DImport); - for (const ModelNode &node : std::as_const(materials)) - model()->nodeInstanceView()->previewImageDataForGenericNode(node, {}); + if (updateImages) { + for (const ModelNode &node : std::as_const(materials)) + model()->nodeInstanceView()->previewImageDataForGenericNode(node, {}); + } } bool MaterialBrowserView::isMaterial(const ModelNode &node) const @@ -204,8 +208,9 @@ void MaterialBrowserView::nodeReparented(const ModelNode &node, bool matRemoved = oldParentNode.isValid() && oldParentNode.id() == Constants::MATERIAL_LIB_ID; if (matAdded || matRemoved) { - refreshModel(); - + if (matAdded) // Workaround to fix various material issues all likely caused by QTBUG-103316 + resetPuppet(); + refreshModel(!matAdded); int idx = m_widget->materialBrowserModel()->materialIndex(node); m_widget->materialBrowserModel()->selectMaterial(idx); } @@ -252,7 +257,7 @@ void MaterialBrowserView::importsChanged(const QList &addedImports, cons return; m_hasQuick3DImport = hasQuick3DImport; - refreshModel(); + refreshModel(true); } void MaterialBrowserView::customNotification(const AbstractView *view, const QString &identifier, @@ -267,6 +272,13 @@ void MaterialBrowserView::customNotification(const AbstractView *view, const QSt int idx = m_widget->materialBrowserModel()->materialIndex(nodeList.first()); if (idx != -1) m_widget->materialBrowserModel()->selectMaterial(idx); + } else if (identifier == "reset QmlPuppet") { + // Little delay is needed to allow puppet reset to actually be done, as it is async as well + QTimer::singleShot(200, this, [this]() { + const QList materials = m_widget->materialBrowserModel()->materials(); + for (const ModelNode &node : materials) + model()->nodeInstanceView()->previewImageDataForGenericNode(node, {}); + }); } } diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h index e140eede136..c637efa49e1 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h @@ -62,7 +62,7 @@ public: const QList &nodeList, const QList &data) override; private: - void refreshModel(); + void refreshModel(bool updateImages); bool isMaterial(const ModelNode &node) const; QPointer m_widget; From 568004e12182458b44222cc53a545611992eba02 Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Tue, 7 Jun 2022 21:19:44 +0300 Subject: [PATCH 23/96] QmlDesigner: Detect asset drag'n'drop support based on property type Handle property support for asset drag based on property type rather than name in order to support properties with any name (like lightProbe). Change-Id: I20fd422119db96aebd505b47888c97f0d94bf7f9 Reviewed-by: Reviewed-by: Miikka Heikkinen Reviewed-by: Thomas Hartmann --- .../components/materialeditor/materialeditorview.cpp | 7 ++++++- .../components/propertyeditor/propertyeditorvalue.cpp | 5 +++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp index 28c17d75611..ca76d459660 100644 --- a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp +++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp @@ -767,11 +767,16 @@ void MaterialEditorView::customNotification(const AbstractView *view, const QStr void QmlDesigner::MaterialEditorView::highlightSupportedProperties(bool highlight) { + if (!m_selectedMaterial.isValid()) + return; + DesignerPropertyMap &propMap = m_qmlBackEnd->backendValuesPropertyMap(); const QStringList propNames = propMap.keys(); + NodeMetaInfo metaInfo = m_selectedMaterial.metaInfo(); + QTC_ASSERT(metaInfo.isValid(), return); for (const QString &propName : propNames) { - if (propName.endsWith("Map")) { + if (metaInfo.propertyTypeName(propName.toLatin1()) == "QtQuick3D.Texture") { QObject *propEditorValObj = propMap.value(propName).value(); PropertyEditorValue *propEditorVal = qobject_cast(propEditorValObj); propEditorVal->setHasActiveDrag(highlight); diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp index 867fd9bd65b..fd568911abc 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp @@ -518,14 +518,15 @@ bool PropertyEditorValue::idListReplace(int idx, const QString &value) void PropertyEditorValue::commitDrop(const QString &path) { - if (m_modelNode.isSubclassOf("QtQuick3D.Material") && nameAsQString().endsWith("Map")) { + if (m_modelNode.isSubclassOf("QtQuick3D.Material") + && m_modelNode.metaInfo().propertyTypeName(m_name) == "QtQuick3D.Texture") { // create a texture node QmlDesigner::NodeMetaInfo metaInfo = m_modelNode.view()->model()->metaInfo("QtQuick3D.Texture"); QmlDesigner::ModelNode texture = m_modelNode.view()->createModelNode("QtQuick3D.Texture", metaInfo.majorVersion(), metaInfo.minorVersion()); texture.validId(); - modelNode().view()->rootModelNode().defaultNodeListProperty().reparentHere(texture); + m_modelNode.view()->rootModelNode().defaultNodeListProperty().reparentHere(texture); // TODO: group textures under 1 node (just like materials) // set texture source From d080e6331f3a75a28d2d3dd27ace853e7c51c9c0 Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Wed, 15 Jun 2022 16:54:31 +0300 Subject: [PATCH 24/96] QmlDesigner: Parse material library on model attach Parsing has to happen so material in an old project are correctly appearing in the material views. Using a timer to wait until it is ok to create the material editor node. Otherwise errors happen. Change-Id: I54b532211f8a865c5183fab0fd8c12e5f15b983a Reviewed-by: Reviewed-by: Miikka Heikkinen Reviewed-by: Thomas Hartmann --- .../materialeditor/materialeditorview.cpp | 14 ++++++++++++-- .../components/materialeditor/materialeditorview.h | 1 + 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp index ca76d459660..10cd12a7c7b 100644 --- a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp +++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp @@ -73,6 +73,13 @@ MaterialEditorView::MaterialEditorView(QWidget *parent) m_updateShortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_F7), m_stackedWidget); connect(m_updateShortcut, &QShortcut::activated, this, &MaterialEditorView::reloadQml); + m_ensureMatLibTimer.callOnTimeout([this] { + if (model() && model()->rewriterView() && !model()->rewriterView()->hasIncompleteTypeInformation()) { + materialLibraryNode(); // create the material library node + m_ensureMatLibTimer.stop(); + } + }); + m_stackedWidget->setStyleSheet(Theme::replaceCssColors( QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/stylesheet.css")))); m_stackedWidget->setMinimumWidth(250); @@ -524,6 +531,11 @@ void MaterialEditorView::modelAttached(Model *model) m_hasQuick3DImport = model->hasImport("QtQuick3D"); + // Creating the material library node on model attach causes errors as long as the type information + // not complete yet, so we keep checking until type info is complete. + if (m_hasQuick3DImport) + m_ensureMatLibTimer.start(500); + if (!m_setupCompleted) { reloadQml(); m_setupCompleted = true; @@ -537,8 +549,6 @@ void MaterialEditorView::modelAboutToBeDetached(Model *model) { AbstractView::modelAboutToBeDetached(model); m_qmlBackEnd->materialEditorTransaction()->end(); - - } void MaterialEditorView::propertiesRemoved(const QList &propertyList) diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h index d9c9e4c1ba1..ff734ed30b8 100644 --- a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h +++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h @@ -114,6 +114,7 @@ private: bool noValidSelection() const; ModelNode m_selectedMaterial; + QTimer m_ensureMatLibTimer; QShortcut *m_updateShortcut = nullptr; int m_timerId = 0; QStackedWidget *m_stackedWidget = nullptr; From 74a7e9f00caf6d4a49081ef0081bc99fa47377c5 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 17 Jun 2022 13:45:52 +0200 Subject: [PATCH 25/96] QmlDesigner: Fix test build Amends 50aadacb6e670. Change-Id: If6cd7a1fc4df380693f3c4deee8791ed9863672a Reviewed-by: Miikka Heikkinen --- .../qmldesigner/designercore/instances/nodeinstanceview.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp index 196faf2848e..3498e749266 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp @@ -90,12 +90,11 @@ #include #include #include +#include #endif #include -#include - #include #include From db8dbe25e0528d5e845be5c5f1ca44ec0a923f14 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Thu, 24 Feb 2022 16:55:19 +0100 Subject: [PATCH 26/96] QmlDesigner: Add a wizard for a ui.qml .qml file pair Task-number: QDS-5963 Change-Id: I16ee8361779f11ca2f24f35877869f3e83279d10 Reviewed-by: Thomas Hartmann --- .../files/qtuiquickform/file.qml.tpl | 5 + .../files/qtuiquickform/fileForm.ui.qml.tpl | 33 +++++ .../files/qtuiquickform/file_ui.png | Bin 0 -> 1084 bytes .../files/qtuiquickform/file_ui@2.png | Bin 0 -> 1879 bytes .../files/qtuiquickform/wizard.json | 132 ++++++++++++++++++ 5 files changed, 170 insertions(+) create mode 100644 share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/file.qml.tpl create mode 100644 share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/fileForm.ui.qml.tpl create mode 100644 share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/file_ui.png create mode 100644 share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/file_ui@2.png create mode 100644 share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/wizard.json diff --git a/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/file.qml.tpl b/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/file.qml.tpl new file mode 100644 index 00000000000..7bd94416c44 --- /dev/null +++ b/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/file.qml.tpl @@ -0,0 +1,5 @@ +import QtQuick 2.15 + +%{FormClass} { + button.onClicked: console.log("Button Pressed") +} diff --git a/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/fileForm.ui.qml.tpl b/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/fileForm.ui.qml.tpl new file mode 100644 index 00000000000..1fcbbe97566 --- /dev/null +++ b/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/fileForm.ui.qml.tpl @@ -0,0 +1,33 @@ +/* +This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only. +It is supposed to be strictly declarative and only uses a subset of QML. If you edit +this file manually, you might introduce QML code that is not supported by Qt Design Studio. +Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files. +*/ + +import QtQuick 2.15 +@if %{UseQtQuickControls2} +import QtQuick.Controls 2.15 +@endif +@if %{UseImport} +import %{ApplicationImport} +@endif + +%{RootItem} { +@if %{UseImport} + width: Constants.width + height: Constants.height +@else + width: 1024 + height: 768 +@endif + + property alias button: button + + Button { + id: button + x: 64 + y: 64 + text: qsTr("Button") + } +} diff --git a/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/file_ui.png b/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/file_ui.png new file mode 100644 index 0000000000000000000000000000000000000000..473a8430fe5642bbcd20f571c3815d8eb7e3fd66 GIT binary patch literal 1084 zcmeAS@N?(olHy`uVBq!ia0y~yU}$7uU`XI#28pCSbY);*YzXiPab;j&C@(Lc4+d}s zm`7!z91M^R1q&dohH#PH02hG>!nqJbN=ix~3^K^XganALn5d}e$jF$esD$|V174rA35=B_$?8q{2f(Q<9VC&z~O_5|WydGJpR3;NalU;NY;3 zknr&Eyu7@Ef`a0rqT=G>l9H0r($cch(z3F$^78V!y1MS}?!Lahi4!JFnlx$7oH=vn z&Yd@J-u(IV&%5eoGB7Y?l?3?(GcYnTF>`S7@(Tz`NGqu68W@>aSlW4c2ZTk(CnTk1 z6cm<}R#rDOHZ`}lwzYS3cK1%0GIjclnRAyeTe)iWx@|l595{6N$k_{*Z#;PN^x3=j zA3lBm{^RE_5cmxOfByXW^Y`!HfB*i?^_$bgz`(@l>EalYaqsQTo8gxoL>fM>*HDUb z4Y(s7z@fKeVUW2?m?_th*aJ%yn!1?GjNaX;zsr7firD$g^PbPT=DvUXOm%( z)}`zA^7fwXVhDGNb$qocP%NcqlS1+oR>{RWCnQoGmj{Z?F+bIG*)6i*k_NX@!z2a% z1fRESc>7Q5hlRa(`sc)%O$9}2zYWf9 zG8W!h#PaZQdc5kreS0fJrYTm~{&Iel_wwgzBbLYWRsZet(VeDq;%uG2!-g;KoKH5j zMtUxK(UgWvn?x16$h<9^pK=mPhK+^IV?^S^ID%BdArV9(Li%kbB+Aly|! zDTup3`Qi49oO2F<&_C6K3J$R*-x*A9iQHlGa4!}=;5WO8VS(1KKXR-V3Bd}P4Xf*q z$uh`>vF>J&S~gw&h*m?~>ZW3bH{32RDGIzBGS93^Si;tD%XY2$tnL4!#N@;TcfPBP zGd-Yq{%_gO4ZO8U(FS+J=9X{&H9IL*p=kNujcf^bul>E7 zUl+f7hxMxkQ}-4>`0cEJ_dm0G0h9U)frHCcW@*JvsIJoQocH9~jmX);A(I}6ykfY* zxPm!=J%j7q0-YTbg2Z%~1K1bvImj+hesP9*1&7{R_wWru4OR@L3?QZUjO?F<7Mk;X SjAUS7VDNPHb6Mw<&;$S}j|k@g literal 0 HcmV?d00001 diff --git a/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/file_ui@2.png b/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/file_ui@2.png new file mode 100644 index 0000000000000000000000000000000000000000..9cf67e875bdc95b48100b8a1ed489e75749d9f94 GIT binary patch literal 1879 zcmeAS@N?(olHy`uVBq!ia0y~yU}R!oU^u|R%)r2K7?A#>quWColK(NYcuaQ6K9^Wh5M42Ue8gp0!&1qB5VS+HSHk3&Qt zBwQu3`4A~mNr+LUrKNC<>FMckHbgciCI-TQTNfN092y)P77`K`8X6uN8W9#25gr~H z9v&GH5fu>;9TgQF9UT)D6%!pD6B82~9UT`F6CWEJ9~YOHkdU01n39x~nw*@Lnwp-L zmY$xTk)EEJk&&61nU$HDot2f7ot=}Dlbe&1mz$fHmzSTPUyz?)P*6}SJ7L0vDU&BpojP^e)Tz^_PoFVk z#;jSh=FFKhckbMI^XAQ;Kc9i=)?o$)hPIL*zhDMNMkZz!Ha0GPacLPj1w~~QHFYg* zU3~)+QwvLL8%Jk1cTYdRfZ&kO(6FfJn1sZXjLh7E;?nYp>bi!;=8o>Z{{9IQCrzF@ zZTj@tbLK5rv}noF<;z#BUb|uArcK+n@7sUi=&|D`PMtY-<;I-{kDfex{`&3v4<9~$ z{POktkDtGO|Nism&)1i=W_1srdfJXj9Llr$ZzzQ|d_n!xdgHGqSO#et)V#egG@L#RRF z#qQIr>KuX$3NLowWmV@874R3(Q<#_VeEUL6ojD2g?uU@l?B^Q6ar#i7A*6sE#JO@G3e*_o>jjzm70`a9oc(G{KBt)nO{p|RanBO{4(Zain_lx zY`T)7#maTZoE=_AzsgWyiC=mDvD1h4psj)ecS2sx-y!g4`ITM{j=Hc{|91$y$iLEm zQQ(N1gSqLr~FK*jNxpXT|L)%?ca#Y z-}4PV{=WXi7^0X-XaYlTLV0Cv)a)dmzmBXtj#mD&AC>;iPy`u;WGXt7)z3gFzo{{Z zb5Ey!)bELPE=3&2W~-`R`)jo~ie($luR>>;tt93TzZom%g*08g$J*$xQ`#C{uQN3vp4&Ke&C+>~1=mdWTCjVj=3D0bT=Om^aqjWA zeZJT2=_aLMJN@YoWcwGKT{b5#I(+>crRfRI#rbLLPp!#1zM$uJ$kQUulKDMz=T1u# z(VllUV^{V;7WtIexvvd>UjBOWu7A_F z<`bOfnRI74@bijFENB(Zc`KxJA+fuJY45t?1rEPWqih=QUC?(}kg}Ie;X+lJ_Wabf zY40veuHc0{ zD|%m9f1kyl!+NNZg%qq!$Gr-)%vN@FDfo3ZJ-GfpdFpLJfev1TdPirkhn!xrB}kdY z;0H zg&dS;+&{ypj+|HQm>gL0e{(z#sQJ;t?Ds&w!AU@Y!AU@+!BIei!BIe`!C}LWrObW; tY6|leLL6)ycQlkV*|4+-KT-a`Fu94}{9$XcGy?+zgQu&X%Q~loCICI9PY(b9 literal 0 HcmV?d00001 diff --git a/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/wizard.json b/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/wizard.json new file mode 100644 index 00000000000..26c628f4b31 --- /dev/null +++ b/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/wizard.json @@ -0,0 +1,132 @@ +{ + "version": 1, + "supportedProjectTypes": [ ], + "id": "Q.QtStudio.QmlUIForm.2", + "category": "B.StudioQtQuickFiles", + "trDescription": "Creates a UI file (.ui.qml) along with a matching QML file for implementation purposes.", + "trDisplayName": "QtQuick UI Form", + "trDisplayCategory": "Qt Quick Files", + "icon": "file_ui.png", + "platformIndependent": true, + + "enabled": "%{JS: value('Plugins').indexOf('QmlJSEditor') >= 0}", + "options" : [ + { "key": "QmlFile", "value": "%{Class}.%{JS: Util.preferredSuffix('text/x-qml')}" }, + { "key": "UiFile", "value": "%{FormClass}.%{JS: Util.preferredSuffix('application/x-qt.ui+qml')}" }, + { "key": "ApplicationImport", "value": "%{QmlProjectName} 1.0" }, + { "key": "RootItem", "value": "%{JS: %{RootItemCB}.RootItem}" }, + { "key": "UseImportDefault", "value": "%{JS: false}" }, + { "key": "UseQtQuickControls2Default", "value": "%{JS: true}" } + ], + "pages" : + [ + { + "trDisplayName": "Define Class", + "trShortTitle": "Details", + "typeId": "Fields", + "data" : + [ + { + "name": "Class", + "trDisplayName": "Component name:", + "mandatory": true, + "type": "LineEdit", + "data": { + "validator": "(?:[A-Z_][a-zA-Z_0-9]*|)", + "fixup": "%{JS: '%{INPUT}'.charAt(0).toUpperCase() + '%{INPUT}'.slice(1) }" + } + }, + { + "name": "Sp1", + "type": "Spacer", + "data": { "factor": 2 } + }, + { + "name": "FormClass", + "trDisplayName": "Component form name:", + "mandatory": true, + "type": "LineEdit", + "data": { + "validator": "(?:[A-Z_][a-zA-Z_0-9]*|)", + "fixup": "%{JS: '%{INPUT}'.charAt(0).toUpperCase() + '%{INPUT}'.slice(1) }", + "trText": "%{Class}Form" + } + }, + { + "name": "TargetPath", + "type": "PathChooser", + "trDisplayName": "Path:", + "mandatory": true, + "data": + { + "kind": "directory", + "basePath": "%{InitialPath}", + "path": "%{InitialPath}" + } + }, + { + "name": "RootItemCB", + "trDisplayName": "Root Item:", + "type": "ComboBox", + "data": + { + "index": 0, + "items": + [ + { + "trKey": "Item", + "value": + "({ + 'RootItem': 'Item' + })" + }, + { + "trKey": "Rectangle", + "value": + "({ + 'RootItem': 'Rectangle' + })" + } + ] + } + }, + { + "name": "UseImport", + "trDisplayName": "Use Application Import", + "type": "CheckBox", + "data": + { + "checked": "%{UseImportDefault}" + } + }, + { + "name": "UseQtQuickControls2", + "trDisplayName": "Use QtQuick Controls 2", + "type": "CheckBox", + "data": + { + "checked": "%{UseQtQuickControls2Default}" + } + } + ] + } + ], + "generators" : + [ + { + "typeId": "File", + "data": [ + { + "source": "file.qml.tpl", + "target": "%{TargetPath}/%{QmlFile}", + "openInEditor": true + }, + { + "source": "fileForm.ui.qml.tpl", + "target": "%{TargetPath}/%{UiFile}", + "openInEditor": true + } + ] + } + ] +} From 2de2a4808ac3bfc17c6f51d03050afd7909ba120 Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Tue, 21 Jun 2022 00:21:50 +0200 Subject: [PATCH 27/96] QmlDesigner: Fix FontComboBox drag'n'drop * Fix URL schema to also work under macOS * Avoid setting font name and further processing if error during font loading occurred Change-Id: I9d07a3daad8f7c8c464422b0cf3f94d61e4b231d Reviewed-by: Reviewed-by: Thomas Hartmann --- .../imports/HelperWidgets/FontComboBox.qml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontComboBox.qml index 8c05fa2f878..2f087c3b299 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontComboBox.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontComboBox.qml @@ -65,9 +65,11 @@ StudioControls.ComboBox { onDropped: function(drop) { drop.accepted = root.hasActiveHoverDrag - var fontLoader = root.createFontLoader("file:///" + dropArea.assetPath) - root.backendValue.value = fontLoader.name - root.currentIndex = root.find(root.backendValue.value) + var fontLoader = root.createFontLoader("file:" + dropArea.assetPath) + if (fontLoader.status === FontLoader.Ready) { + root.backendValue.value = fontLoader.name + root.currentIndex = root.find(root.backendValue.value) + } root.hasActiveHoverDrag = false root.backendValue.commitDrop(dropArea.assetPath) } From 281c5348944a1a32aae2582a7712ac98a6b00061 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Tue, 21 Jun 2022 14:16:01 +0200 Subject: [PATCH 28/96] QmlDesigner: Make inErrorState() private This method should be only for internal use, since it is different from errors.isEmpty(), because the rewriter is only inErrorState if parsing/rewriting fails, not if there is a semantic error. Change-Id: Ib021e5e80750a4edcb4661755e85e6880fd6617c Reviewed-by: Miikka Heikkinen --- .../qmldesigner/assetexporterplugin/assetexporterview.cpp | 2 +- .../components/componentcore/designeractionmanager.cpp | 2 +- .../designercore/imagecache/imagecachecollector.cpp | 4 ++-- src/plugins/qmldesigner/designercore/include/rewriterview.h | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/plugins/qmldesigner/assetexporterplugin/assetexporterview.cpp b/src/plugins/qmldesigner/assetexporterplugin/assetexporterview.cpp index 81dc1ce486c..a565b464450 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/assetexporterview.cpp +++ b/src/plugins/qmldesigner/assetexporterplugin/assetexporterview.cpp @@ -81,7 +81,7 @@ bool AssetExporterView::saveQmlFile(QString *error) const void AssetExporterView::modelAttached(Model *model) { - if (model->rewriterView() && model->rewriterView()->inErrorState()) + if (model->rewriterView() && !model->rewriterView()->errors().isEmpty()) setState(LoadState::QmlErrorState); AbstractView::modelAttached(model); diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp index 7f5649ea5f6..a0bd7a23896 100644 --- a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp +++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp @@ -513,7 +513,7 @@ public: ->currentModel(); if (currentModel->rewriterView() - && currentModel->rewriterView()->inErrorState()) { + && !currentModel->rewriterView()->errors().isEmpty()) { throw DocumentError{}; } diff --git a/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp b/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp index 429ca328afd..0a225d1ab09 100644 --- a/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp +++ b/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp @@ -96,11 +96,11 @@ void ImageCacheCollector::start(Utils::SmallStringView name, model->setRewriterView(&rewriterView); - bool is3DRoot = !rewriterView.inErrorState() + bool is3DRoot = rewriterView.errors().isEmpty() && (rewriterView.rootModelNode().isSubclassOf("QtQuick3D.Node") || rewriterView.rootModelNode().isSubclassOf("QtQuick3D.Material")); - if (rewriterView.inErrorState() || (!rewriterView.rootModelNode().metaInfo().isGraphicalItem() + if (!rewriterView.errors().isEmpty() || (!rewriterView.rootModelNode().metaInfo().isGraphicalItem() && !is3DRoot)) { if (abortCallback) abortCallback(ImageCache::AbortReason::Failed); diff --git a/src/plugins/qmldesigner/designercore/include/rewriterview.h b/src/plugins/qmldesigner/designercore/include/rewriterview.h index e3a4af0b758..4e099290cd0 100644 --- a/src/plugins/qmldesigner/designercore/include/rewriterview.h +++ b/src/plugins/qmldesigner/designercore/include/rewriterview.h @@ -127,7 +127,6 @@ public: void addError(const DocumentMessage &error); void enterErrorState(const QString &errorMessage); - bool inErrorState() const { return !m_rewritingErrorMessage.isEmpty(); } void leaveErrorState() { m_rewritingErrorMessage.clear(); } void resetToLastCorrectQml(); @@ -202,6 +201,7 @@ private: //variables void setupCanonicalHashes() const; void handleLibraryInfoUpdate(); void handleProjectUpdate(); + bool inErrorState() const { return !m_rewritingErrorMessage.isEmpty(); } TextModifier *m_textModifier = nullptr; int transactionLevel = 0; From 20bc8b8243ef24a4018096527ab2b0941767d056 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Mon, 13 Jun 2022 16:47:17 +0200 Subject: [PATCH 29/96] QmlDesigner: Install busy handler for every database access Even for pragma changes the statement can be getting busy. To prevent any exceptions in that case we set the busy handler directly after opening the database. Change-Id: Id10aab20d812d5224f8031fa895c396762858fdf Reviewed-by: Qt CI Bot Reviewed-by: Thomas Hartmann --- src/libs/sqlite/sqlitedatabase.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/sqlite/sqlitedatabase.cpp b/src/libs/sqlite/sqlitedatabase.cpp index 5e72d6660e3..96e6a87b8ac 100644 --- a/src/libs/sqlite/sqlitedatabase.cpp +++ b/src/libs/sqlite/sqlitedatabase.cpp @@ -93,12 +93,12 @@ void Database::activateLogging() void Database::open(LockingMode lockingMode) { m_databaseBackend.open(m_databaseFilePath, m_openMode); - m_databaseBackend.setLockingMode(lockingMode); - m_databaseBackend.setJournalMode(m_journalMode); if (m_busyTimeout > 0ms) m_databaseBackend.setBusyTimeout(m_busyTimeout); else m_databaseBackend.registerBusyHandler(); + m_databaseBackend.setLockingMode(lockingMode); + m_databaseBackend.setJournalMode(m_journalMode); registerTransactionStatements(); m_isOpen = true; } From 3dca62ac1e2f39bdc58dfd3f0f837cee4cb87d2c Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Mon, 13 Jun 2022 17:54:29 +0200 Subject: [PATCH 30/96] QmlDesigner: Fix crash for dangling target It can be that the target is a dangling pointer. Task-number: QDS-7134 Change-Id: I51b7c9109b0f9193c31ee645144e2a24d1244ba9 Reviewed-by: Reviewed-by: Thomas Hartmann --- src/plugins/qmldesigner/qmldesignerprojectmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp b/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp index 90e54ba65bb..366f1ef04e3 100644 --- a/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp +++ b/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp @@ -141,7 +141,7 @@ public: ImageCacheCollectorNullImageHandling::DontCaptureNullImage}; PreviewTimeStampProvider timeStampProvider; AsynchronousImageFactory factory; - ::ProjectExplorer::Target *activeTarget = nullptr; + QPointer<::ProjectExplorer::Target> activeTarget; }; QmlDesignerProjectManager::QmlDesignerProjectManager() From 53642c9a2206efbe94898e682365a7adcf239994 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Tue, 21 Jun 2022 15:19:07 +0200 Subject: [PATCH 31/96] QmlDesigner: There can be also document messages from the puppet We have to check if the rewriterView()->errors() are actually empty. Change-Id: Icbcc82aa9229078fd51c975e48de3e1f06c29f4d Reviewed-by: Miikka Heikkinen --- .../qmldesigner/components/formeditor/formeditorview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp index 6c6e67be81e..dc499c03b9b 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp +++ b/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp @@ -472,7 +472,7 @@ void FormEditorView::documentMessagesChanged(const QList &error if (!errors.isEmpty() && !model()->rewriterView()->hasIncompleteTypeInformation()) m_formEditorWidget->showErrorMessageBox(errors); - else + else if (rewriterView()->errors().isEmpty()) m_formEditorWidget->hideErrorMessageBox(); checkRootModelNode(); From 604342c3af64a423a9c60cae85d7dc5aafb8eb1b Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Fri, 17 Jun 2022 14:10:03 +0300 Subject: [PATCH 32/96] QmlDesigner: Add some delays to material browser refreshing Import change causes puppet to reset, so bit of delay is needed there before triggering material browser refresh. Also added similar delay to refresh done at model attach as it seems puppet reset can sometimes be triggered after attach as well. Fixes: QDS-7172 Change-Id: I47f7af54e55af074fb2b9e8cdb9e78fb051a16cc Reviewed-by: Mahmoud Badri Reviewed-by: Reviewed-by: Qt CI Bot --- .../materialbrowser/materialbrowserview.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp index 1af67d4fef7..c0e0f9ad3cb 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp @@ -97,7 +97,10 @@ void MaterialBrowserView::modelAttached(Model *model) m_widget->clearSearchFilter(); m_hasQuick3DImport = model->hasImport("QtQuick3D"); - QTimer::singleShot(0, this, [this]() { + + // Project load is already very busy and may even trigger puppet reset, so let's wait a moment + // before refreshing the model + QTimer::singleShot(1000, this, [this]() { refreshModel(true); }); } @@ -257,7 +260,17 @@ void MaterialBrowserView::importsChanged(const QList &addedImports, cons return; m_hasQuick3DImport = hasQuick3DImport; - refreshModel(true); + + if (m_hasQuick3DImport) { + // Import change will trigger puppet reset. + // However, it doesn't seem to trigger the notification about the reset, so wait here. + QTimer::singleShot(1000, this, [this]() { + refreshModel(true); + }); + } else { + // No quick3d import, so we can refresh immediately to clear the browser + refreshModel(true); + } } void MaterialBrowserView::customNotification(const AbstractView *view, const QString &identifier, From 62f34622df810ce0f036a08485630ececdc5f932 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Tue, 21 Jun 2022 11:14:22 +0300 Subject: [PATCH 33/96] QmlDesigner: Improve puppet reset handling in material browser Ensure just one reset call for cases where multiple materials are added at once, and detect reset completion from root instance completion notification instead of reset trigger notification, as it comes later and catches all puppet reset cases. Fixes: QDS-7119 Change-Id: I99baa718bd1c85b4581f07ce75193213110e8e96 Reviewed-by: Thomas Hartmann Reviewed-by: Reviewed-by: Mahmoud Badri --- .../materialbrowser/materialbrowserview.cpp | 40 ++++++++++--------- .../materialbrowser/materialbrowserview.h | 2 + 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp index c0e0f9ad3cb..2a06d5acbc4 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp @@ -211,8 +211,11 @@ void MaterialBrowserView::nodeReparented(const ModelNode &node, bool matRemoved = oldParentNode.isValid() && oldParentNode.id() == Constants::MATERIAL_LIB_ID; if (matAdded || matRemoved) { - if (matAdded) // Workaround to fix various material issues all likely caused by QTBUG-103316 + if (matAdded && !m_puppetResetPending) { + // Workaround to fix various material issues all likely caused by QTBUG-103316 resetPuppet(); + m_puppetResetPending = true; + } refreshModel(!matAdded); int idx = m_widget->materialBrowserModel()->materialIndex(node); m_widget->materialBrowserModel()->selectMaterial(idx); @@ -261,16 +264,8 @@ void MaterialBrowserView::importsChanged(const QList &addedImports, cons m_hasQuick3DImport = hasQuick3DImport; - if (m_hasQuick3DImport) { - // Import change will trigger puppet reset. - // However, it doesn't seem to trigger the notification about the reset, so wait here. - QTimer::singleShot(1000, this, [this]() { - refreshModel(true); - }); - } else { - // No quick3d import, so we can refresh immediately to clear the browser - refreshModel(true); - } + // Import change will trigger puppet reset, so we don't want to update previews immediately + refreshModel(false); } void MaterialBrowserView::customNotification(const AbstractView *view, const QString &identifier, @@ -285,13 +280,22 @@ void MaterialBrowserView::customNotification(const AbstractView *view, const QSt int idx = m_widget->materialBrowserModel()->materialIndex(nodeList.first()); if (idx != -1) m_widget->materialBrowserModel()->selectMaterial(idx); - } else if (identifier == "reset QmlPuppet") { - // Little delay is needed to allow puppet reset to actually be done, as it is async as well - QTimer::singleShot(200, this, [this]() { - const QList materials = m_widget->materialBrowserModel()->materials(); - for (const ModelNode &node : materials) - model()->nodeInstanceView()->previewImageDataForGenericNode(node, {}); - }); + } +} + +void MaterialBrowserView::instancesCompleted(const QVector &completedNodeList) +{ + for (const ModelNode &node : completedNodeList) { + // We use root node completion as indication of puppet reset + if (node.isRootNode()) { + m_puppetResetPending = false; + QTimer::singleShot(1000, this, [this]() { + const QList materials = m_widget->materialBrowserModel()->materials(); + for (const ModelNode &node : materials) + model()->nodeInstanceView()->previewImageDataForGenericNode(node, {}); + }); + break; + } } } diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h index c637efa49e1..503986a28ec 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h @@ -60,6 +60,7 @@ public: void importsChanged(const QList &addedImports, const QList &removedImports) override; void customNotification(const AbstractView *view, const QString &identifier, const QList &nodeList, const QList &data) override; + void instancesCompleted(const QVector &completedNodeList) override; private: void refreshModel(bool updateImages); @@ -68,6 +69,7 @@ private: QPointer m_widget; bool m_hasQuick3DImport = false; bool m_autoSelectModelMaterial = false; // TODO: wire this to some action + bool m_puppetResetPending = false; }; } // namespace QmlDesigner From 41986d794279c9a6db2e2893372707a3d5415b82 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Wed, 22 Jun 2022 12:19:57 +0300 Subject: [PATCH 34/96] QmlDesigner: Show IconButton tooltip also when button is disabled Fixes: QDS-7076 Change-Id: If412827e22c6f71a9f073d1c868dcdb325870c1d Reviewed-by: Mahmoud Badri --- .../imports/HelperWidgets/IconButton.qml | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/IconButton.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/IconButton.qml index 2fc10b18554..dcd4733134a 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/IconButton.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/IconButton.qml @@ -34,10 +34,10 @@ Rectangle { signal clicked() property alias icon: icon.text - property alias enabled: mouseArea.enabled property alias tooltip: toolTip.text property alias iconSize: icon.font.pixelSize + property bool enabled: true property int buttonSize: StudioTheme.Values.height property color normalColor: StudioTheme.Values.themeControlBackground property color hoverColor: StudioTheme.Values.themeControlBackgroundHover @@ -46,9 +46,10 @@ Rectangle { width: buttonSize height: buttonSize - color: mouseArea.pressed ? pressColor - : mouseArea.containsMouse ? hoverColor - : normalColor + color: !enabled ? normalColor + : mouseArea.pressed ? pressColor + : mouseArea.containsMouse ? hoverColor + : normalColor Behavior on color { ColorAnimation { @@ -71,7 +72,11 @@ Rectangle { anchors.fill: parent hoverEnabled: true - onClicked: root.clicked() + onClicked: { + // We need to keep mouse area enabled even when button is disabled to make tooltip work + if (root.enabled) + root.clicked() + } } ToolTip { From 359f4f176755c0504a4a6372835498f8faae3fb0 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Wed, 22 Jun 2022 12:48:25 +0300 Subject: [PATCH 35/96] QmlDesigner: Fix material editor/browser texts Fixes: QDS-7083 Change-Id: Ib4a5269e275c7811a5645bbff54e3b0ec95ec302 Reviewed-by: Mats Honkamaa Reviewed-by: Mahmoud Badri --- .../materialBrowserQmlSource/MaterialBrowser.qml | 8 +++++--- .../materialEditorQmlSources/EmptyMaterialEditorPane.qml | 5 +++-- .../materialEditorQmlSources/MaterialEditorToolBar.qml | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml index ab061e4289c..0419b945b9c 100644 --- a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml +++ b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml @@ -128,7 +128,7 @@ Item { StudioControls.MenuSeparator {} StudioControls.MenuItem { - text: qsTr("New Material") + text: qsTr("Create New Material") onTriggered: materialBrowserModel.addNewMaterial() } @@ -169,7 +169,8 @@ Item { } Text { - text: qsTr("No materials yet.\nClick '+' above to start.") + text: qsTr("There are no materials in this project.
Select '+' to create one.") + textFormat: Text.RichText color: StudioTheme.Values.themeTextColor font.pixelSize: StudioTheme.Values.mediumFontSize horizontalAlignment: Text.AlignHCenter @@ -179,7 +180,8 @@ Item { } Text { - text: qsTr("Add QtQuick3D module using the Components view to enable the Material Browser."); + text: qsTr("To use Material Browser, first add the QtQuick3D module in the Components view."); + textFormat: Text.RichText color: StudioTheme.Values.themeTextColor font.pixelSize: StudioTheme.Values.mediumFontSize topPadding: 30 diff --git a/share/qtcreator/qmldesigner/materialEditorQmlSources/EmptyMaterialEditorPane.qml b/share/qtcreator/qmldesigner/materialEditorQmlSources/EmptyMaterialEditorPane.qml index 80ec524e23e..a9e272b6d51 100644 --- a/share/qtcreator/qmldesigner/materialEditorQmlSources/EmptyMaterialEditorPane.qml +++ b/share/qtcreator/qmldesigner/materialEditorQmlSources/EmptyMaterialEditorPane.qml @@ -48,8 +48,9 @@ PropertyEditorPane { height: 150 Text { - text: hasQuick3DImport ? qsTr("No materials yet.\nClick '+' above to start.") - : qsTr("Add QtQuick3D module using the Components view to enable the Material Editor.") + text: hasQuick3DImport ? qsTr("There are no materials in this project.
Select '+' to create one.") + : qsTr("To use Material Editor, first add the QtQuick3D module in the Components view.") + textFormat: Text.RichText color: StudioTheme.Values.themeTextColor font.pixelSize: StudioTheme.Values.mediumFontSize horizontalAlignment: Text.AlignHCenter diff --git a/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorToolBar.qml b/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorToolBar.qml index c610df94c5e..80a8d9abbe9 100644 --- a/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorToolBar.qml +++ b/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorToolBar.qml @@ -63,7 +63,7 @@ Rectangle { buttonSize: root.height enabled: hasQuick3DImport onClicked: root.toolBarAction(ToolBarAction.AddNewMaterial) - tooltip: qsTr("Add a new material.") + tooltip: qsTr("Create new material.") } IconButton { From 2cb45cbb6b12048a1e7e02877a56d63a09e708ed Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Wed, 22 Jun 2022 14:43:43 +0300 Subject: [PATCH 36/96] QmlDesigner: Reduce number of preview requests from material editor Removed preview request call from setValue, as it is called in long loops during initial project load and added the calls outside those loops where they already weren't there. Fixes: QDS-7175 Change-Id: Ia83814a0de6fe801d954373dc8ce0e4920e8a6a6 Reviewed-by: Mahmoud Badri Reviewed-by: Thomas Hartmann --- .../components/materialeditor/materialeditorview.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp index 10cd12a7c7b..49cebb3dd4b 100644 --- a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp +++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp @@ -556,6 +556,7 @@ void MaterialEditorView::propertiesRemoved(const QList &proper if (noValidSelection()) return; + bool changed = false; for (const AbstractProperty &property : propertyList) { ModelNode node(property.parentModelNode()); @@ -564,8 +565,11 @@ void MaterialEditorView::propertiesRemoved(const QList &proper if (node == m_selectedMaterial || QmlObjectNode(m_selectedMaterial).propertyChangeForCurrentState() == node) { setValue(m_selectedMaterial, property.name(), QmlObjectNode(m_selectedMaterial).instanceValue(property.name())); + changed = true; } } + if (changed) + requestPreviewRender(); } void MaterialEditorView::variantPropertiesChanged(const QList &propertyList, PropertyChangeFlags /*propertyChange*/) @@ -670,6 +674,7 @@ void MaterialEditorView::instancePropertyChanged(const QList &propertyPair : propertyList) { const ModelNode modelNode = propertyPair.first; const QmlObjectNode qmlObjectNode(modelNode); @@ -681,8 +686,11 @@ void MaterialEditorView::instancePropertyChanged(const QListsetValue(qmlObjectNode, name, value); - requestPreviewRender(); m_locked = false; } From 092a1fc6a3b9668df3028b071d871f6f43f1e156 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Wed, 22 Jun 2022 14:32:02 +0200 Subject: [PATCH 37/96] QmlDesigner: Support reparenting to new nodes in transactions When we reparent to a new node that was created during the same transaction, then this node has no position. In this case we have to delete the reparented nodes and they will be created as part of the creation of the new node, since they are children. Change-Id: Icd1d02f29f529fc0f00809f7ecebf3eabfdc9a5c Reviewed-by: Miikka Heikkinen --- .../designercore/model/modeltotextmerger.cpp | 2 +- .../model/rewriteactioncompressor.cpp | 27 +++++++ .../model/rewriteactioncompressor.h | 7 +- .../qmldesigner/coretests/tst_testcore.cpp | 73 +++++++++++++++++++ .../qml/qmldesigner/coretests/tst_testcore.h | 1 + 5 files changed, 108 insertions(+), 2 deletions(-) diff --git a/src/plugins/qmldesigner/designercore/model/modeltotextmerger.cpp b/src/plugins/qmldesigner/designercore/model/modeltotextmerger.cpp index 5a4276a416f..14badab2bf6 100644 --- a/src/plugins/qmldesigner/designercore/model/modeltotextmerger.cpp +++ b/src/plugins/qmldesigner/designercore/model/modeltotextmerger.cpp @@ -222,7 +222,7 @@ void ModelToTextMerger::applyChanges() return; dumpRewriteActions(QStringLiteral("Before compression")); - RewriteActionCompressor compress(propertyOrder()); + RewriteActionCompressor compress(propertyOrder(), m_rewriterView->positionStorage()); compress(m_rewriteActions, m_rewriterView->textModifier()->tabSettings()); dumpRewriteActions(QStringLiteral("After compression")); diff --git a/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.cpp b/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.cpp index 24342002b38..c014bcd4d78 100644 --- a/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.cpp +++ b/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.cpp @@ -56,6 +56,7 @@ void RewriteActionCompressor::operator()(QList &actions, compressImports(actions); compressRereparentActions(actions); compressReparentIntoSamePropertyActions(actions); + compressReparentIntoNewPropertyActions(actions); compressPropertyActions(actions); compressAddEditRemoveNodeActions(actions); compressAddEditActions(actions, tabSettings); @@ -152,6 +153,32 @@ void RewriteActionCompressor::compressReparentIntoSamePropertyActions(QList &actions) const +{ + QList actionsToRemove; + + QList removeActions; + + for (int i = actions.size(); --i >= 0; ) { + RewriteAction *action = actions.at(i); + + if (ReparentNodeRewriteAction *reparentAction = action->asReparentNodeRewriteAction()) { + if (m_positionStore->nodeOffset(reparentAction->targetProperty().parentModelNode()) < 0) { + actionsToRemove.append(action); + + removeActions.append(new RemoveNodeRewriteAction(reparentAction->reparentedNode())); + } + } + } + + for (RewriteAction *action : qAsConst(actionsToRemove)) { + actions.removeOne(action); + delete action; + } + + actions.append(removeActions); +} + void RewriteActionCompressor::compressAddEditRemoveNodeActions(QList &actions) const { QList actionsToRemove; diff --git a/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.h b/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.h index 57139f98115..02c1e3ad48a 100644 --- a/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.h +++ b/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.h @@ -33,7 +33,10 @@ namespace Internal { class RewriteActionCompressor { public: - RewriteActionCompressor(const PropertyNameList &propertyOrder): m_propertyOrder(propertyOrder) {} + RewriteActionCompressor(const PropertyNameList &propertyOrder, ModelNodePositionStorage *positionStore) : + m_propertyOrder(propertyOrder), + m_positionStore(positionStore) + {} void operator()(QList &actions, const TextEditor::TabSettings &tabSettings) const; @@ -42,6 +45,7 @@ private: void compressRereparentActions(QList &actions) const; void compressReparentIntoSamePropertyActions(QList &actions) const; + void compressReparentIntoNewPropertyActions(QList &actions) const; void compressAddEditRemoveNodeActions(QList &actions) const; void compressPropertyActions(QList &actions) const; void compressAddEditActions(QList &actions, const TextEditor::TabSettings &tabSettings) const; @@ -49,6 +53,7 @@ private: private: PropertyNameList m_propertyOrder; + ModelNodePositionStorage *m_positionStore; }; } // namespace Internal diff --git a/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp b/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp index 26b8ddcf8e3..f6708d2c8f3 100644 --- a/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp +++ b/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp @@ -1152,6 +1152,79 @@ void tst_TestCore::testRewriterTransactionAddingAfterReparenting() } } +void tst_TestCore::testRewriterReparentToNewNode() +{ + const QLatin1String qmlString("\n" + "import QtQuick 2.0\n" + "\n" + "Item {\n" + " Item {}\n" + " Item {}\n" + " Item {}\n" + " Item {}\n" + "}\n"); + + QPlainTextEdit textEdit; + textEdit.setPlainText(qmlString); + NotIndentingTextEditModifier modifier(&textEdit); + + QScopedPointer model(Model::create("QtQuick.Rectangle")); + + QScopedPointer testRewriterView(new TestRewriterView(0, RewriterView::Amend)); + testRewriterView->setTextModifier(&modifier); + model->attachView(testRewriterView.data()); + + QVERIFY(testRewriterView->errors().isEmpty()); + + ModelNode rootModelNode = testRewriterView->rootModelNode(); + QVERIFY(rootModelNode.isValid()); + + const QList children = rootModelNode.directSubModelNodes(); + + ModelNode rectangle = testRewriterView->createModelNode("QtQuick.Rectangle", 2, 0); + rootModelNode.nodeListProperty("data").reparentHere(rectangle); + + rectangle.setIdWithoutRefactoring("newParent"); + + QVERIFY(rectangle.isValid()); + + for (const ModelNode &child : children) + rectangle.nodeListProperty("data").reparentHere(child); + + { + RewriterTransaction transaction = testRewriterView->beginRewriterTransaction("TEST"); + ModelNode rectangle = testRewriterView->createModelNode("QtQuick.Rectangle", 2, 0); + rootModelNode.nodeListProperty("data").reparentHere(rectangle); + + rectangle.setIdWithoutRefactoring("newParent2"); + + for (const ModelNode &child : children) + rectangle.nodeListProperty("data").reparentHere(child); + } + + QCOMPARE(testRewriterView->allModelNodes().count(), 7); + + const QLatin1String expectedOutcome("\nimport QtQuick 2.0\n\n" + "Item {\n\n" + " Rectangle {\n" + " id: newParent\n" + " }\n\n" + " Rectangle {\n" + " id: newParent2\n" + " Item {\n" + " }\n\n" + " Item {\n" + " }\n\n" + " Item {\n" + " }\n\n" + " Item {\n" + " }\n" + " }\n}\n"); + + + QCOMPARE(textEdit.toPlainText(), expectedOutcome); +} + void tst_TestCore::testRewriterForGradientMagic() { const QLatin1String qmlString("\n" diff --git a/tests/auto/qml/qmldesigner/coretests/tst_testcore.h b/tests/auto/qml/qmldesigner/coretests/tst_testcore.h index 9a8aeb6450b..5248763fef9 100644 --- a/tests/auto/qml/qmldesigner/coretests/tst_testcore.h +++ b/tests/auto/qml/qmldesigner/coretests/tst_testcore.h @@ -144,6 +144,7 @@ private slots: void testRewriterChangeImports(); void testRewriterUnicodeChars(); void testRewriterTransactionAddingAfterReparenting(); + void testRewriterReparentToNewNode(); // // unit tests QmlModelNodeFacade/QmlModelState From 9caa28754cb76e6ce5ec0e17ad85f3950e00fad2 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Wed, 22 Jun 2022 15:54:50 +0200 Subject: [PATCH 38/96] QmlDesigner: Use single transaction to move items into a layout Change-Id: Ic8eb3907d06843e7ad0d7b0117154b0b7a987808 Reviewed-by: Miikka Heikkinen --- .../components/componentcore/modelnodeoperations.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp index f4f85475280..11e052b1dd3 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp +++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp @@ -475,19 +475,16 @@ static void layoutHelperFunction(const SelectionContext &selectionContext, const QmlItemNode qmlItemNode = QmlItemNode(selectionContext.firstSelectedModelNode()); if (qmlItemNode.hasInstanceParentItem()) { - ModelNode layoutNode; - selectionContext.view()->executeInTransaction("DesignerActionManager|layoutHelperFunction1",[=, &layoutNode](){ + + selectionContext.view()->executeInTransaction("DesignerActionManager|layoutHelperFunction",[=](){ QmlItemNode parentNode = qmlItemNode.instanceParentItem(); NodeMetaInfo metaInfo = selectionContext.view()->model()->metaInfo(layoutType); - layoutNode = selectionContext.view()->createModelNode(layoutType, metaInfo.majorVersion(), metaInfo.minorVersion()); + const ModelNode layoutNode = selectionContext.view()->createModelNode(layoutType, metaInfo.majorVersion(), metaInfo.minorVersion()); reparentTo(layoutNode, parentNode); - }); - - selectionContext.view()->executeInTransaction("DesignerActionManager|layoutHelperFunction2",[=](){ QList sortedSelectedNodes = selectionContext.selectedModelNodes(); Utils::sort(sortedSelectedNodes, lessThan); From cc1bf95dc2d14d4fdce32bb87938108e55c5e63c Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Wed, 22 Jun 2022 14:46:27 +0300 Subject: [PATCH 39/96] QmlDesigner: Ensure material lib node exists on project launch In this commit material library node is created on model attach. A timer keeps monitoring until it is suitable to create the node. This will properly move materials into material library for projects created with previous QDS versions. Also removed unnecessary handling on new material dragging, as rewriter now works properly with material library creation. Fixes: QDS-7178 Change-Id: Idf6f41906e02bc064961d8de9841ba1644bd3552 Reviewed-by: Thomas Hartmann --- .../materialeditor/materialeditorview.cpp | 7 ++- .../navigator/navigatortreemodel.cpp | 11 ----- .../designercore/include/abstractview.h | 1 + .../designercore/model/abstractview.cpp | 45 +++++++++++-------- 4 files changed, 33 insertions(+), 31 deletions(-) diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp index 49cebb3dd4b..7ab7cc090c5 100644 --- a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp +++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp @@ -74,8 +74,11 @@ MaterialEditorView::MaterialEditorView(QWidget *parent) connect(m_updateShortcut, &QShortcut::activated, this, &MaterialEditorView::reloadQml); m_ensureMatLibTimer.callOnTimeout([this] { - if (model() && model()->rewriterView() && !model()->rewriterView()->hasIncompleteTypeInformation()) { - materialLibraryNode(); // create the material library node + if (model() && model()->rewriterView() && !model()->rewriterView()->hasIncompleteTypeInformation() + && model()->rewriterView()->errors().isEmpty()) { + executeInTransaction("MaterialEditorView::MaterialEditorView", [this] { + ensureMaterialLibraryNode(); + }); m_ensureMatLibTimer.stop(); } }); diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp index d610014d5bf..38c32f65cd8 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp @@ -697,17 +697,6 @@ void NavigatorTreeModel::handleItemLibraryItemDrop(const QMimeData *mimeData, in newQmlObjectNode.destroy(); return; } - // We can't have material initially parented if material library is created in this - // same transaction (rewriter will not allow it for some reason) - ModelNode matLib = m_view->modelNodeForId(Constants::MATERIAL_LIB_ID); - if (!matLib.isValid()) { - newQmlObjectNode.destroy(); - newQmlObjectNode = QmlItemNode::createQmlObjectNode( - m_view, itemLibraryEntry, QPointF(), NodeAbstractProperty(), false); - newModelNode = newQmlObjectNode.modelNode(); - if (!newModelNode.isValid()) - return; - } m_view->assignMaterialTo3dModel(targetNode, newModelNode); } diff --git a/src/plugins/qmldesigner/designercore/include/abstractview.h b/src/plugins/qmldesigner/designercore/include/abstractview.h index 18380aadb1a..2eecf8df5aa 100644 --- a/src/plugins/qmldesigner/designercore/include/abstractview.h +++ b/src/plugins/qmldesigner/designercore/include/abstractview.h @@ -259,6 +259,7 @@ public: void changeRootNodeType(const TypeName &type, int majorVersion, int minorVersion); + void ensureMaterialLibraryNode(); ModelNode materialLibraryNode(); void assignMaterialTo3dModel(const ModelNode &modelNode, const ModelNode &materialNode = {}); diff --git a/src/plugins/qmldesigner/designercore/model/abstractview.cpp b/src/plugins/qmldesigner/designercore/model/abstractview.cpp index 86dab970316..6826c9ed4dd 100644 --- a/src/plugins/qmldesigner/designercore/model/abstractview.cpp +++ b/src/plugins/qmldesigner/designercore/model/abstractview.cpp @@ -809,16 +809,14 @@ void AbstractView::changeRootNodeType(const TypeName &type, int majorVersion, in m_model.data()->d->changeRootNodeType(type, majorVersion, minorVersion); } -// Returns ModelNode for project's material library. -// If the material library doesn't exist yet, it is created and all existing materials are moved -// under material library. -// This function should be called only form inside a transaction, as it potentially does many -// changes to model. -ModelNode AbstractView::materialLibraryNode() +// Creates material library if it doesn't exist and moves any existing materials into it +// This function should be called only from inside a transaction, as it potentially does many +// changes to model, or undo stack should be cleared after the call. +void AbstractView::ensureMaterialLibraryNode() { ModelNode matLib = modelNodeForId(Constants::MATERIAL_LIB_ID); if (matLib.isValid()) - return matLib; + return; // Create material library node TypeName nodeType = rootModelNode().isSubclassOf("QtQuick3D.Node") ? "QtQuick3D.Node" @@ -830,20 +828,28 @@ ModelNode AbstractView::materialLibraryNode() rootModelNode().defaultNodeListProperty().reparentHere(matLib); const QList materials = rootModelNode().subModelNodesOfType("QtQuick3D.Material"); - if (materials.isEmpty()) - return matLib; + if (!materials.isEmpty()) { + // Move all materials to under material library node + for (const ModelNode &node : materials) { + // If material has no name, set name to id + QString matName = node.variantProperty("objectName").value().toString(); + if (matName.isEmpty()) { + VariantProperty objNameProp = node.variantProperty("objectName"); + objNameProp.setValue(node.id()); + } - // Move all materials to under material library node - for (const ModelNode &node : materials) { - // If material has no name, set name to id - QString matName = node.variantProperty("objectName").value().toString(); - if (matName.isEmpty()) { - VariantProperty objNameProp = node.variantProperty("objectName"); - objNameProp.setValue(node.id()); + matLib.defaultNodeListProperty().reparentHere(node); } - - matLib.defaultNodeListProperty().reparentHere(node); } +} + +// Returns ModelNode for project's material library. +ModelNode AbstractView::materialLibraryNode() +{ + ensureMaterialLibraryNode(); + + ModelNode matLib = modelNodeForId(Constants::MATERIAL_LIB_ID); + QTC_ASSERT(matLib.isValid(), return {}); return matLib; } @@ -859,6 +865,9 @@ void AbstractView::assignMaterialTo3dModel(const ModelNode &modelNode, const Mod QTC_ASSERT(modelNode.isValid() && modelNode.isSubclassOf("QtQuick3D.Model"), return); ModelNode matLib = materialLibraryNode(); + + QTC_ASSERT(matLib.isValid(), return); + ModelNode newMaterialNode; if (materialNode.isValid() && materialNode.isSubclassOf("QtQuick3D.Material")) { From b63675db6ece28e1a7f896f297724f4ebaf47f2e Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Wed, 22 Jun 2022 17:10:58 +0200 Subject: [PATCH 40/96] QmlDesigner: Show metainfo when node is created in debugview Change-Id: Id377b3e29f0a953a206dc3aa08008bb87f12bf0a Reviewed-by: Thomas Hartmann --- src/plugins/qmldesigner/components/debugview/debugview.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/components/debugview/debugview.cpp b/src/plugins/qmldesigner/components/debugview/debugview.cpp index be09b3864a4..831170d3026 100644 --- a/src/plugins/qmldesigner/components/debugview/debugview.cpp +++ b/src/plugins/qmldesigner/components/debugview/debugview.cpp @@ -110,9 +110,11 @@ void DebugView::nodeCreated(const ModelNode &createdNode) QString string; message.setString(&string); message << createdNode; + message << createdNode.majorVersion() << "." << createdNode.minorVersion(); message << createdNode.nodeSource(); - message << "MetaInfo " << createdNode.metaInfo().isValid(); + message << "MetaInfo " << createdNode.metaInfo().isValid() << " "; if (createdNode.metaInfo().isValid()) { + message << createdNode.metaInfo().majorVersion() << "." << createdNode.metaInfo().minorVersion(); message << createdNode.metaInfo().componentFileName(); } log("::nodeCreated:", message.readAll()); From 5fa46d665971bc0c7fbd2373400c5f2120ece922 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Wed, 22 Jun 2022 17:11:51 +0200 Subject: [PATCH 41/96] QmlDesigner: Add createModelNode without explicit versions This makes it easier to create properly versioned ModelNodes. Change-Id: I2a81021daa5e57af6740e447826124f1554a2c78 Reviewed-by: Thomas Hartmann --- .../qmldesigner/designercore/include/abstractview.h | 2 ++ .../qmldesigner/designercore/model/abstractview.cpp | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/src/plugins/qmldesigner/designercore/include/abstractview.h b/src/plugins/qmldesigner/designercore/include/abstractview.h index 2eecf8df5aa..6971f5f39ed 100644 --- a/src/plugins/qmldesigner/designercore/include/abstractview.h +++ b/src/plugins/qmldesigner/designercore/include/abstractview.h @@ -134,6 +134,8 @@ public: RewriterTransaction beginRewriterTransaction(const QByteArray &identifier); + ModelNode createModelNode(const TypeName &typeName); + ModelNode createModelNode(const TypeName &typeName, int majorVersion, int minorVersion, diff --git a/src/plugins/qmldesigner/designercore/model/abstractview.cpp b/src/plugins/qmldesigner/designercore/model/abstractview.cpp index 6826c9ed4dd..e728c61358f 100644 --- a/src/plugins/qmldesigner/designercore/model/abstractview.cpp +++ b/src/plugins/qmldesigner/designercore/model/abstractview.cpp @@ -31,6 +31,7 @@ #include "nodeinstanceview.h" #include #include +#include #include #include #include @@ -89,6 +90,12 @@ RewriterTransaction AbstractView::beginRewriterTransaction(const QByteArray &ide return RewriterTransaction(this, identifier); } +ModelNode AbstractView::createModelNode(const TypeName &typeName) +{ + const NodeMetaInfo metaInfo = model()->metaInfo(typeName); + return createModelNode(typeName, metaInfo.majorVersion(), metaInfo.minorVersion()); +} + ModelNode AbstractView::createModelNode(const TypeName &typeName, int majorVersion, int minorVersion, From a0d474f2defd3ac14ae118d5a7e3cc99b5aab9f6 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Wed, 22 Jun 2022 17:13:25 +0200 Subject: [PATCH 42/96] QmlDesigner: Create transitions with proper versions The versions were hard coded which leads to issues. Task-number: QDS-6760 Change-Id: I94c3599348b996bb700da636cd63e74ea4c02be6 Reviewed-by: Reviewed-by: Thomas Hartmann --- .../transitioneditor/transitioneditorview.cpp | 84 ++++++++++--------- 1 file changed, 44 insertions(+), 40 deletions(-) diff --git a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorview.cpp b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorview.cpp index f487cc18fb7..14c5eb6e953 100644 --- a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorview.cpp +++ b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorview.cpp @@ -251,50 +251,54 @@ ModelNode TransitionEditorView::addNewTransition() if (!idPropertyList.isEmpty()) { executeInTransaction( - " TransitionEditorView::addNewTransition", [&transition, idPropertyList, root, this]() { - transition = createModelNode("QtQuick.Transition", - 2, - 0, - {{ - "from", - "*", - }, - { - "to", - "*", - }}); - transition.setAuxiliaryData("transitionDuration", 2000); - transition.validId(); - root.nodeListProperty("transitions").reparentHere(transition); + " TransitionEditorView::addNewTransition", [&transition, idPropertyList, root, this]() { - for (auto it = idPropertyList.cbegin(); it != idPropertyList.cend(); ++it) { - ModelNode parallelAnimation = createModelNode("QtQuick.ParallelAnimation", - 2, - 12); - transition.defaultNodeAbstractProperty().reparentHere(parallelAnimation); - for (const QString &property : it.value()) { - ModelNode sequentialAnimation - = createModelNode("QtQuick.SequentialAnimation", 2, 12); - parallelAnimation.defaultNodeAbstractProperty().reparentHere( - sequentialAnimation); + const NodeMetaInfo transitionMetaInfo = model()->metaInfo("QtQuick.Transition"); + transition = createModelNode("QtQuick.Transition", + transitionMetaInfo.majorVersion(), + transitionMetaInfo.minorVersion(), + {{ + "from", + "*", + }, + { + "to", + "*", + }}); + transition.setAuxiliaryData("transitionDuration", 2000); + transition.validId(); + root.nodeListProperty("transitions").reparentHere(transition); - ModelNode pauseAnimation = createModelNode("QtQuick.PauseAnimation", - 2, - 12, - {{"duration", 50}}); - sequentialAnimation.defaultNodeAbstractProperty().reparentHere( - pauseAnimation); + for (auto it = idPropertyList.cbegin(); it != idPropertyList.cend(); ++it) { + ModelNode parallelAnimation = createModelNode("QtQuick.ParallelAnimation"); + transition.defaultNodeAbstractProperty().reparentHere(parallelAnimation); + for (const QString &property : it.value()) { + ModelNode sequentialAnimation + = createModelNode("QtQuick.SequentialAnimation"); + parallelAnimation.defaultNodeAbstractProperty().reparentHere( + sequentialAnimation); - ModelNode propertyAnimation = createModelNode("QtQuick.PropertyAnimation", - 2, - 12, - {{"property", property}, - {"duration", 150}}); - propertyAnimation.bindingProperty("target").setExpression(it.key()); - sequentialAnimation.defaultNodeAbstractProperty().reparentHere( - propertyAnimation); - } + const NodeMetaInfo pauseMetaInfo = model()->metaInfo("QtQuick.PauseAnimation"); + + ModelNode pauseAnimation = createModelNode("QtQuick.PauseAnimation", + pauseMetaInfo.majorVersion(), + pauseMetaInfo.minorVersion(), + {{"duration", 50}}); + sequentialAnimation.defaultNodeAbstractProperty().reparentHere( + pauseAnimation); + + const NodeMetaInfo propertyMetaInfo = model()->metaInfo("QtQuick.PauseAnimation"); + + ModelNode propertyAnimation = createModelNode("QtQuick.PropertyAnimation", + propertyMetaInfo.majorVersion(), + propertyMetaInfo.minorVersion(), + {{"property", property}, + {"duration", 150}}); + propertyAnimation.bindingProperty("target").setExpression(it.key()); + sequentialAnimation.defaultNodeAbstractProperty().reparentHere( + propertyAnimation); } + } }); } else { QString properties; From 5903d82c0b6356d1bb3460ed2b934ba2e87774ce Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Thu, 16 Jun 2022 12:29:50 +0200 Subject: [PATCH 43/96] QmlDesigner: Fix hover color for ButtonRow Use the default background color for ButtonRow buttons on global hover. This needs to be done to distinguish between hover and global hover on ButtonRow buttons as we unified the two colors as an attempt to make the UI a bit less noisy. Change-Id: I63f9c730367e9b906a772a63210c7ca548647352 Reviewed-by: Brook Cronin Reviewed-by: Reviewed-by: Thomas Hartmann --- .../imports/StudioControls/AbstractButton.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/AbstractButton.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/AbstractButton.qml index 577257de709..c594220d5e0 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/AbstractButton.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/AbstractButton.qml @@ -136,7 +136,7 @@ T.AbstractButton { when: myButton.globalHover && !myButton.hover && !myButton.pressed && myButton.enabled PropertyChanges { target: buttonBackground - color: StudioTheme.Values.themeControlBackgroundGlobalHover + color: StudioTheme.Values.themeControlBackground } }, State { From b3be9d9802850718c10b08602cf41dd109040c8f Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 23 Jun 2022 11:59:20 +0300 Subject: [PATCH 44/96] QmlDesigner: Tweak 3D asset import dialog layout On some font scalings, spinboxes were too tight, especially when there was just one row of options showing, so increased the row height and tweaked layout margins a bit. Fixes: QDS-7186 Change-Id: I0650ab976d96f27fc9cf606c4faa6fa2d7c5e8f4 Reviewed-by: Thomas Hartmann --- .../components/itemlibrary/itemlibraryassetimportdialog.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp index 0fe286a9982..dc29dab8c1b 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp @@ -74,7 +74,7 @@ static void addFormattedMessage(Utils::OutputFormatter *formatter, const QString formatter->plainTextEdit()->verticalScrollBar()->maximum()); } -static const int rowHeight = 28; +static const int rowHeight = 32; static const int checkBoxColWidth = 18; static const int labelMinWidth = 130; static const int controlMinWidth = 65; @@ -781,7 +781,7 @@ QGridLayout *ItemLibraryAssetImportDialog::createOptionsGrid( int &globalOptionsHeight = advanced ? m_advancedData.optionsHeight : m_simpleData.optionsHeight; globalOptionRows = qMax(globalOptionRows, optionRows); globalOptionsHeight = qMax(rowHeight * optionRows + 20, globalOptionsHeight); - layout->setContentsMargins(8, 8, 8, 0); + layout->setContentsMargins(8, 6, 8, 0); return layout; } From 7aaaccb2812d2eaa237861f914ef3fae3ba1dcee Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 23 Jun 2022 14:13:29 +0300 Subject: [PATCH 45/96] QmlDesigner: Remove duplicate assert This assert was redundant, leading to duplicate warnings if triggered. Change-Id: I59b6a7c17345a2ccba0d51ef50a303eec2026422 Reviewed-by: Mahmoud Badri --- src/plugins/qmldesigner/designercore/model/abstractview.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/designercore/model/abstractview.cpp b/src/plugins/qmldesigner/designercore/model/abstractview.cpp index e728c61358f..046572d7140 100644 --- a/src/plugins/qmldesigner/designercore/model/abstractview.cpp +++ b/src/plugins/qmldesigner/designercore/model/abstractview.cpp @@ -873,7 +873,8 @@ void AbstractView::assignMaterialTo3dModel(const ModelNode &modelNode, const Mod ModelNode matLib = materialLibraryNode(); - QTC_ASSERT(matLib.isValid(), return); + if (!matLib.isValid()) + return; ModelNode newMaterialNode; From 8a8a2f5c5558d02eb1efb5c5e33d18c7d6b7e35d Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 23 Jun 2022 14:20:56 +0300 Subject: [PATCH 46/96] QmlDesigner: Unify the background of 3D preview images Added 3D checkerboard floor on all 3D previews. Since shadows generally look bad for arbitrary 3D scenes, and would mostly be obscured by the model itself as we want the light mostly from the front, removed shadows also from the material preview to unify the previews. Qt5 had issues rendering the 3D floor texture, so used a static image there, as Qt5 only generates previews of one size. Fixes: QDS-7078 Change-Id: I74d094878ed01e6e531ad60df1f8d9d7cf415860 Reviewed-by: Reviewed-by: Mahmoud Badri --- .../qtcreator/qml/qmlpuppet/editor3d_qt5.qrc | 2 +- .../mockfiles/images/static_floor.png | Bin 0 -> 2685 bytes .../mockfiles/qt5/MaterialNodeView.qml | 24 ---------- .../mockfiles/qt5/ModelNode3DImageView.qml | 9 ++-- .../qmlpuppet/mockfiles/qt5/ModelNodeView.qml | 2 +- .../mockfiles/qt6/MaterialNodeView.qml | 23 --------- .../mockfiles/qt6/ModelNode3DImageView.qml | 44 ++++++++++++++++++ .../qmlpuppet/mockfiles/qt6/ModelNodeView.qml | 2 +- 8 files changed, 51 insertions(+), 55 deletions(-) create mode 100644 share/qtcreator/qml/qmlpuppet/mockfiles/images/static_floor.png diff --git a/share/qtcreator/qml/qmlpuppet/editor3d_qt5.qrc b/share/qtcreator/qml/qmlpuppet/editor3d_qt5.qrc index 7e023c127b7..bbe9a910db6 100644 --- a/share/qtcreator/qml/qmlpuppet/editor3d_qt5.qrc +++ b/share/qtcreator/qml/qmlpuppet/editor3d_qt5.qrc @@ -13,7 +13,7 @@ mockfiles/images/directional@2x.png mockfiles/images/point.png mockfiles/images/point@2x.png - mockfiles/images/floor_tex.png + mockfiles/images/static_floor.png mockfiles/images/spot.png mockfiles/images/spot@2x.png mockfiles/qt5/AdjustableArrow.qml diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/static_floor.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/static_floor.png new file mode 100644 index 0000000000000000000000000000000000000000..93073719f55f658c6dfcfb2a2f45e4839567a12b GIT binary patch literal 2685 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 Iol`;+0Psp60ssI2 literal 0 HcmV?d00001 diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/MaterialNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/MaterialNodeView.qml index c36d8c227c3..9fee06e0ad1 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/MaterialNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/MaterialNodeView.qml @@ -45,10 +45,6 @@ View3D { Node { DirectionalLight { - shadowMapQuality: Light.ShadowMapQualityMedium - shadowFilter: 20 - shadowFactor: 21 - castsShadow: true eulerRotation.x: -26 eulerRotation.y: -57 } @@ -68,25 +64,5 @@ View3D { source: "#Sphere" materials: previewMaterial } - - Model { - id: floorModel - source: "#Rectangle" - scale.y: 8 - scale.x: 8 - eulerRotation.x: -90 - materials: floorMaterial - DefaultMaterial { - id: floorMaterial - diffuseMap: floorTex - - Texture { - id: floorTex - source: "../images/floor_tex.png" - scaleU: floorModel.scale.x - scaleV: floorModel.scale.y - } - } - } } } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNode3DImageView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNode3DImageView.qml index a6d5c6b1db5..70b9dbc4d0e 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNode3DImageView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNode3DImageView.qml @@ -123,14 +123,13 @@ Item { anchors.fill: parent } - Rectangle { + // We can use static image in Qt5 as only small previews will be generated + Image { id: backgroundRect anchors.fill: parent z: -1 - gradient: Gradient { - GradientStop { position: 1.0; color: "#222222" } - GradientStop { position: 0.0; color: "#999999" } - } + source: "../images/static_floor.png" + fillMode: Image.Stretch } } } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNodeView.qml index b497b0419a1..82688bbef5a 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNodeView.qml @@ -70,7 +70,7 @@ View3D { materials: [ DefaultMaterial { - diffuseColor: "#4aee45" + diffuseColor: "#999999" } ] } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/MaterialNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/MaterialNodeView.qml index ed5cfea56f4..94051d5f6e6 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/MaterialNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/MaterialNodeView.qml @@ -45,10 +45,6 @@ View3D { Node { DirectionalLight { - shadowMapQuality: Light.ShadowMapQualityMedium - shadowFilter: 20 - shadowFactor: 21 - castsShadow: true eulerRotation.x: -26 eulerRotation.y: -57 } @@ -70,24 +66,5 @@ View3D { materials: previewMaterial } - Model { - id: floorModel - source: "#Rectangle" - scale.y: 8 - scale.x: 8 - eulerRotation.x: -90 - materials: floorMaterial - DefaultMaterial { - id: floorMaterial - diffuseMap: floorTex - - Texture { - id: floorTex - source: "../images/floor_tex.png" - scaleU: floorModel.scale.x - scaleV: floorModel.scale.y - } - } - } } } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNode3DImageView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNode3DImageView.qml index 5caac0047c4..031d01d65fb 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNode3DImageView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNode3DImageView.qml @@ -126,6 +126,50 @@ Item { GradientStop { position: 1.0; color: "#222222" } GradientStop { position: 0.0; color: "#999999" } } + + // Use View3D instead of static image to make background look good on all resolutions + View3D { + anchors.fill: parent + environment: sceneEnv + + SceneEnvironment { + id: sceneEnv + antialiasingMode: SceneEnvironment.MSAA + antialiasingQuality: SceneEnvironment.High + } + + DirectionalLight { + eulerRotation.x: -26 + eulerRotation.y: -57 + } + + PerspectiveCamera { + y: 125 + z: 120 + eulerRotation.x: -31 + clipNear: 1 + clipFar: 1000 + } + + Model { + id: floorModel + source: "#Rectangle" + scale.y: 8 + scale.x: 8 + eulerRotation.x: -90 + materials: floorMaterial + DefaultMaterial { + id: floorMaterial + diffuseMap: floorTex + Texture { + id: floorTex + source: "../images/floor_tex.png" + scaleU: floorModel.scale.x + scaleV: floorModel.scale.y + } + } + } + } } } } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml index 4da76ea097f..ea2e23837fd 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml @@ -70,7 +70,7 @@ View3D { materials: [ DefaultMaterial { - diffuseColor: "#4aee45" + diffuseColor: "#999999" } ] } From 93cd068d3e6cadb78f007975853828be35a4e1c6 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 23 Jun 2022 15:37:26 +0300 Subject: [PATCH 47/96] QmlDesigner: Create material library at import change There are still rewriter issues with Qt5, where component library templates for models contain materials, so create material library when quick3d import is added to ensure we never need to create it when models are added. Change-Id: I7006a39228d316dbfd84f49d19c025bb42b6765c Reviewed-by: Mahmoud Badri --- .../components/materialeditor/materialeditorview.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp index 7ab7cc090c5..8b3d6932741 100644 --- a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp +++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp @@ -718,6 +718,9 @@ void MaterialEditorView::importsChanged(const QList &addedImports, const m_hasQuick3DImport = model()->hasImport("QtQuick3D"); m_qmlBackEnd->contextObject()->setHasQuick3DImport(m_hasQuick3DImport); + if (m_hasQuick3DImport) + m_ensureMatLibTimer.start(500); + resetView(); } From 34491bdfc34e518b902c1dd2085ef64d8680e315 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Thu, 23 Jun 2022 16:20:39 +0200 Subject: [PATCH 48/96] QmlDesigner: Only remove node with position Extending the test case. Change-Id: I37255de763262e069c2f9d30b1ce584a0347fbcf Reviewed-by: Reviewed-by: Thomas Hartmann --- .../model/rewriteactioncompressor.cpp | 5 +++- .../qmldesigner/coretests/tst_testcore.cpp | 27 +++++++++++++++++-- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.cpp b/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.cpp index c014bcd4d78..0662da4e86a 100644 --- a/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.cpp +++ b/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.cpp @@ -166,7 +166,10 @@ void RewriteActionCompressor::compressReparentIntoNewPropertyActions(QListnodeOffset(reparentAction->targetProperty().parentModelNode()) < 0) { actionsToRemove.append(action); - removeActions.append(new RemoveNodeRewriteAction(reparentAction->reparentedNode())); + const ModelNode childNode = reparentAction->reparentedNode(); + + if (m_positionStore->nodeOffset(childNode) > 0) + removeActions.append(new RemoveNodeRewriteAction(childNode)); } } } diff --git a/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp b/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp index f6708d2c8f3..b6ff4903c43 100644 --- a/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp +++ b/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp @@ -1181,7 +1181,7 @@ void tst_TestCore::testRewriterReparentToNewNode() const QList children = rootModelNode.directSubModelNodes(); - ModelNode rectangle = testRewriterView->createModelNode("QtQuick.Rectangle", 2, 0); + ModelNode rectangle = testRewriterView->createModelNode("QtQuick.Rectangle"); rootModelNode.nodeListProperty("data").reparentHere(rectangle); rectangle.setIdWithoutRefactoring("newParent"); @@ -1193,7 +1193,7 @@ void tst_TestCore::testRewriterReparentToNewNode() { RewriterTransaction transaction = testRewriterView->beginRewriterTransaction("TEST"); - ModelNode rectangle = testRewriterView->createModelNode("QtQuick.Rectangle", 2, 0); + ModelNode rectangle = testRewriterView->createModelNode("QtQuick.Rectangle"); rootModelNode.nodeListProperty("data").reparentHere(rectangle); rectangle.setIdWithoutRefactoring("newParent2"); @@ -1223,6 +1223,29 @@ void tst_TestCore::testRewriterReparentToNewNode() QCOMPARE(textEdit.toPlainText(), expectedOutcome); + + rectangle.destroy(); + + QCOMPARE(testRewriterView->allModelNodes().count(), 6); + + { + RewriterTransaction transaction = testRewriterView->beginRewriterTransaction("TEST"); + + ModelNode newChild = testRewriterView->createModelNode("QtQuick.Rectangle"); + rootModelNode.nodeListProperty("data").reparentHere(newChild); + newChild.setIdWithoutRefactoring("newChild"); + ModelNode newParent = testRewriterView->createModelNode("QtQuick.Rectangle"); + rootModelNode.nodeListProperty("data").reparentHere(newParent); + + newParent.setIdWithoutRefactoring("newParent3"); + + for (const ModelNode &child : children) + newParent.nodeListProperty("data").reparentHere(child); + + newParent.nodeListProperty("data").reparentHere(newChild); + } + + QCOMPARE(testRewriterView->allModelNodes().count(), 8); } void tst_TestCore::testRewriterForGradientMagic() From 21ef02a016f7921fab8f72e3fcea2147bb2cd018 Mon Sep 17 00:00:00 2001 From: Brook Cronin Date: Fri, 24 Jun 2022 11:23:06 +0200 Subject: [PATCH 49/96] update fixed version of icon font Change-Id: Iedf945b3718d4df245e24ac1ba756b20f6ed9cf1 Reviewed-by: Thomas Hartmann --- .../imports/StudioTheme/icons.ttf | Bin 23272 -> 23512 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf index 5a3e99d4590b33cddc9812e0435c01e03ca491c6..cefd1d7d86696ac13a11199df9b1203d65947b94 100644 GIT binary patch delta 5139 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 From a627d43d39bc17e7144fda724cb41d944bded6a5 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Mon, 27 Jun 2022 11:07:32 +0300 Subject: [PATCH 50/96] QmlDesigner: Fix crash on mode change Added model pointer validity checks into a few places. Fixes: QDS-7191 Change-Id: I94beb134f4d9a0b1c7fc9dc87da1d02ad255beaa Reviewed-by: Thomas Hartmann --- .../components/materialbrowser/materialbrowserview.cpp | 2 ++ .../components/materialeditor/materialeditorview.cpp | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp index 2a06d5acbc4..2d02ba12768 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp @@ -290,6 +290,8 @@ void MaterialBrowserView::instancesCompleted(const QVector &completed if (node.isRootNode()) { m_puppetResetPending = false; QTimer::singleShot(1000, this, [this]() { + if (!model() || !model()->nodeInstanceView()) + return; const QList materials = m_widget->materialBrowserModel()->materials(); for (const ModelNode &node : materials) model()->nodeInstanceView()->previewImageDataForGenericNode(node, {}); diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp index 8b3d6932741..d86ef1463bf 100644 --- a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp +++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp @@ -416,6 +416,8 @@ void MaterialEditorView::handleToolBarAction(int action) } case MaterialEditorContextObject::AddNewMaterial: { + if (!model()) + break; executeInTransaction("MaterialEditorView:handleToolBarAction", [&] { NodeMetaInfo metaInfo = model()->metaInfo("QtQuick3D.DefaultMaterial"); ModelNode newMatNode = createModelNode("QtQuick3D.DefaultMaterial", metaInfo.majorVersion(), @@ -634,7 +636,7 @@ void MaterialEditorView::auxiliaryDataChanged(const ModelNode &node, const Prope // request render image for the selected material node void MaterialEditorView::requestPreviewRender() { - if (m_selectedMaterial.isValid()) + if (model() && model()->nodeInstanceView() && m_selectedMaterial.isValid()) model()->nodeInstanceView()->previewImageDataForGenericNode(m_selectedMaterial, {}); } @@ -740,6 +742,9 @@ void MaterialEditorView::duplicateMaterial(const ModelNode &material) { QTC_ASSERT(material.isValid(), return); + if (!model()) + return; + TypeName matType = material.type(); QmlObjectNode sourceMat(material); From 73af75fe68eb0af6ef396a8ef90693c8fdd0f8e6 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Tue, 28 Jun 2022 12:38:12 +0300 Subject: [PATCH 51/96] QmlDesigner: Fix crash in material browser Task-number: QDS-7191 Change-Id: I9542a227aeb3f462ff3572e9a07a7473f98bfa61 Reviewed-by: Thomas Hartmann --- .../components/materialbrowser/materialbrowserview.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp index 2d02ba12768..d85e8239c12 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp @@ -107,6 +107,9 @@ void MaterialBrowserView::modelAttached(Model *model) void MaterialBrowserView::refreshModel(bool updateImages) { + if (!model() || !model()->nodeInstanceView()) + return; + ModelNode matLib = modelNodeForId(Constants::MATERIAL_LIB_ID); QList materials; From ee40ed19e55a47dd109d1b7f4faf9a44ed97fc0f Mon Sep 17 00:00:00 2001 From: Mats Honkamaa Date: Wed, 22 Jun 2022 12:26:03 +0300 Subject: [PATCH 52/96] Doc: Update timeline documentation - Added a task topic for binding a timeline to a property. - Added topic on adding multilpe timelines. - Some changes to focus more on the task rather than function. - Other minor updates. Task-number: QDS-6879 Change-Id: Ibd99785d6a9ee70fc10b8e1395ef8aaf0e186ddc Reviewed-by: Mahmoud Badri Reviewed-by: Leena Miettinen --- .../images/timeline-bind-animation-state.png | Bin 0 -> 4262 bytes .../images/timeline-insert-keyframe.png | Bin 0 -> 8974 bytes .../timeline-per-property-recording.png | Bin 0 -> 6041 bytes .../timeline-settings-dialog-second.png | Bin 0 -> 16649 bytes .../images/timeline-settings-dialog.png | Bin 0 -> 14019 bytes .../timeline-settings-property-binding.png | Bin 0 -> 14993 bytes doc/qtdesignstudio/images/timeline-states.png | Bin 0 -> 12233 bytes .../qtquick-component-context-menu.qdocinc | 2 +- .../src/views/qtquick-timeline-view.qdoc | 14 +- .../src/views/qtquick-timeline.qdoc | 244 +++++++++++------- 10 files changed, 164 insertions(+), 96 deletions(-) create mode 100644 doc/qtdesignstudio/images/timeline-bind-animation-state.png create mode 100644 doc/qtdesignstudio/images/timeline-insert-keyframe.png create mode 100644 doc/qtdesignstudio/images/timeline-per-property-recording.png create mode 100644 doc/qtdesignstudio/images/timeline-settings-dialog-second.png create mode 100644 doc/qtdesignstudio/images/timeline-settings-dialog.png create mode 100644 doc/qtdesignstudio/images/timeline-settings-property-binding.png create mode 100644 doc/qtdesignstudio/images/timeline-states.png diff --git a/doc/qtdesignstudio/images/timeline-bind-animation-state.png b/doc/qtdesignstudio/images/timeline-bind-animation-state.png new file mode 100644 index 0000000000000000000000000000000000000000..7e65c85a30c231a8777fe2f7f39bb2b62eb51a89 GIT binary patch literal 4262 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 literal 0 HcmV?d00001 diff --git a/doc/qtdesignstudio/images/timeline-insert-keyframe.png b/doc/qtdesignstudio/images/timeline-insert-keyframe.png new file mode 100644 index 0000000000000000000000000000000000000000..c46a711806729498ecffc5883f41c5b06b39d404 GIT binary patch literal 8974 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 O7(8A5T-G@yGywoEr=n&6 literal 0 HcmV?d00001 diff --git a/doc/qtdesignstudio/images/timeline-settings-dialog-second.png b/doc/qtdesignstudio/images/timeline-settings-dialog-second.png new file mode 100644 index 0000000000000000000000000000000000000000..03cd0be3555d9ea6d40dfbf2d5dfc03bf8390d38 GIT binary patch literal 16649 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
k{yb?d)w3gvnA^W~91#{C~peo30W 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 literal 0 HcmV?d00001 diff --git a/doc/qtdesignstudio/images/timeline-states.png b/doc/qtdesignstudio/images/timeline-states.png new file mode 100644 index 0000000000000000000000000000000000000000..a1dc73e51eba60394b6aeff7228a0bbcbfb5f642 GIT binary patch literal 12233 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 \uicontrol {Insert Keyframe} for the property that you want to animate. + \image timeline-insert-keyframe.png \li In the \l Timeline view, select the \uicontrol {Per Property Recording} button to start recording property changes. - \li Check that the playhead is in frame 0 and enter the value of the + \image timeline-per-property-recording.png + \li Ensure that the playhead is in frame 0 and enter the value of the property in the field next to the property name on the timeline. Press \key Enter to save the value. \li Move the playhead to another frame on the timeline and specify @@ -148,11 +151,67 @@ \uicontrol {Per Property Recording} again to stop recording. \endlist + \section2 Binding a Timeline to a Property + + When you bind a timeline to a component property, the animation's + current frame is controlled by the value of the property. + + In this example, you bind the timeline to a slider component. + + With a timeline created and keyframe values set: + + \list 1 + \li From \uicontrol {Components}, drag a slider to + \uicontrol {Form Editor} or \uicontrol {Navigator}. + \li In \uicontrol {Navigator}, select \e slider and in + \uicontrol {Properties}, set: + \list + \li \uicontrol To to 1000. + \note The \uicontrol From and \uicontrol To values of the slider + should match the \uicontrol {Start Frame} and + \uicontrol {End Frame} values of the timeline if you want to + control the complete animation with the slider. + \endlist + \li In the \uicontrol {Timeline Settings} dialog, select + \inlineimage icons/minus.png + next to the \uicontrol {Animation Settings} tab to delete the + animation. If you have several animations, delete all. + \li In \uicontrol {Expression binding}, enter \c {slider.value}. + \image timeline-settings-property-binding.png + \endlist + + \section2 Binding Animations to States + + You can bind animations to states, this means that the animation will run + when you enter the state. + + To bind an animation to a state: + \list 1 + \li In the table at the bottom of the \uicontrol {Timeline Settings} + dialog lists: + \list + \li Double-click the value in the \uicontrol Timeline field and select + the timeline with the animation you want to bind to the state. + \li Double-click the value in the \uicontrol Animation field and + select the animation you want to bind to the state. + \image timeline-bind-animation-state.png + \endlist + \endlist + To bind a state to a certain keyframe in an animation without running the + animation, set the keyframe in the \uicontrol{Fixed Frame} field. + + \section1 Managing Keyframes + + \image studio-timeline-with-tracks.png "Timeline view" + + \section2 Editing Keyframes + To remove all the changes you recorded for a property, right-click the property name on the timeline and select \uicontrol {Remove Property}. To add keyframes to the keyframe track of a component at the current - position of the playhead, select \uicontrol {Add Keyframes at Current Frame}. + position of the playhead, right-click the component name on the timeline and + select \uicontrol {Add Keyframes at Current Frame}. Keyframes are marked on the timeline by using \l{keyframe_marker}{markers} of different colors and shapes, depending on whether they are active or @@ -162,7 +221,7 @@ \section2 Editing Keyframe Values To fine-tune the value of a keyframe, double-click a keyframe marker or - select \uicontrol {Edit Keyframe} in the context menu. + right-click it and select \uicontrol {Edit Keyframe} in the context menu. The \uicontrol {Edit Keyframe} dialog displays the name of the property you are animating and its current value at the frame specified in the @@ -173,27 +232,36 @@ \section2 Copying Keyframes You can copy the keyframes from the keyframe track for a component and - paste them to the keyframe track of another component. To copy all - keyframes from one track to another one, first right-click the component ID - and select \uicontrol {Copy All Keyframes} in the context menu. - Then right-click the other component ID, and select - \uicontrol {Paste Keyframes} in the context menu. + paste them to the keyframe track of another component. + + To copy all keyframes from one track to another one: + \list 1 + \li Right-click the component ID and select + \uicontrol {Copy All Keyframes} in the context menu. + \li Right-click the other component ID, and select + \uicontrol {Paste Keyframes} in the context menu. + \endlist \section2 Deleting Keyframes - To delete the selected keyframe, select \uicontrol {Delete Keyframe} in the - context menu. + To delete a keyframe, right-click it and select \uicontrol {Delete Keyframe} + in the context menu. - To delete all keyframes from the selected component, select + To delete all keyframes from the selected component, right-click the + component name in \uicontrol {Timeline} and select \uicontrol {Delete All Keyframes} in the context menu. \section1 Viewing the Animation - You can view the animation on the canvas by moving the playhead along the - timeline. + To preview your animation, do one of the following in the + \uicontrol{Timeline} view: + \list + \li Drag the playhead along the timeline. + \li Select \inlineimage icons/start_playback.png + button or press \key Space. + \endlist - To preview the animation, select the \uicontrol {Play (Space)} - button or press \key Space. To preview the whole UI, select the + To preview the whole UI, select the \inlineimage icons/live_preview.png (\uicontrol {Show Live Preview}) button on the canvas toolbar or press \key {Alt+P}. From 234958a47a6edcd17bae255411a5b0f0bbaea6c7 Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Mon, 27 Jun 2022 14:31:59 +0300 Subject: [PATCH 53/96] QmlDesigner: Enable drag-n-drop a material to a model in Navigator Fixes: QDS-6694 Change-Id: I2fb32052559b1d459cc8025e9f30368b0189e8ab Reviewed-by: Miikka Heikkinen Reviewed-by: Reviewed-by: Thomas Hartmann --- .../materialBrowserQmlSource/MaterialItem.qml | 7 +++-- .../materialbrowser/materialbrowserwidget.cpp | 28 +++++++++++++++++ .../materialbrowser/materialbrowserwidget.h | 4 +++ .../choosefrompropertylistdialog.cpp | 5 ++++ .../navigator/navigatortreemodel.cpp | 30 +++++++++++++++++++ .../components/navigator/navigatortreemodel.h | 1 + .../components/navigator/navigatorview.cpp | 9 ++++++ .../qmldesigner/qmldesignerconstants.h | 1 + 8 files changed, 83 insertions(+), 2 deletions(-) diff --git a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialItem.qml b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialItem.qml index 4eeb120b27c..640383d4e18 100644 --- a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialItem.qml +++ b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialItem.qml @@ -72,9 +72,12 @@ Rectangle { anchors.fill: parent acceptedButtons: Qt.LeftButton | Qt.RightButton - onClicked: (mouse) => { + onPressed: (mouse) => { materialBrowserModel.selectMaterial(index) - if (mouse.button === Qt.RightButton) + + if (mouse.button === Qt.LeftButton) + rootView.startDragMaterial(index, mapToGlobal(mouse.x, mouse.y)) + else if (mouse.button === Qt.RightButton) root.showContextMenu() } diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.cpp index 156add5d2da..3982d534546 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.cpp +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -103,6 +104,27 @@ bool MaterialBrowserWidget::eventFilter(QObject *obj, QEvent *event) if (event->type() == QEvent::FocusOut) { if (obj == m_quickWidget.data()) QMetaObject::invokeMethod(m_quickWidget->rootObject(), "closeContextMenu"); + } else if (event->type() == QMouseEvent::MouseMove) { + DesignDocument *document = QmlDesignerPlugin::instance()->currentDesignDocument(); + QTC_ASSERT(document, return false); + Model *model = document->currentModel(); + QTC_ASSERT(model, return false); + + if (m_materialToDrag.isValid()) { + QMouseEvent *me = static_cast(event); + if ((me->globalPos() - m_dragStartPoint).manhattanLength() > 10) { + QByteArray data; + QMimeData *mimeData = new QMimeData; + QDataStream stream(&data, QIODevice::WriteOnly); + stream << m_materialToDrag.internalId(); + mimeData->setData(Constants::MIME_TYPE_MATERIAL, data); + mimeData->removeFormat("text/plain"); + + model->startDrag(mimeData, m_previewImageProvider->requestPixmap( + QString::number(m_materialToDrag.internalId()), nullptr, {128, 128})); + m_materialToDrag = {}; + } + } } return QObject::eventFilter(obj, event); @@ -166,6 +188,12 @@ void MaterialBrowserWidget::handleSearchfilterChanged(const QString &filterText) } } +void MaterialBrowserWidget::startDragMaterial(int index, const QPointF &mousePos) +{ + m_materialToDrag = m_materialBrowserModel->materialAt(index); + m_dragStartPoint = mousePos.toPoint(); +} + QString MaterialBrowserWidget::qmlSourcesPath() { #ifdef SHARE_QML_PATH diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.h b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.h index f5f737007e7..30f9d05b509 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.h +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.h @@ -69,6 +69,7 @@ public: void updateMaterialPreview(const ModelNode &node, const QPixmap &pixmap); Q_INVOKABLE void handleSearchfilterChanged(const QString &filterText); + Q_INVOKABLE void startDragMaterial(int index, const QPointF &mousePos); QQuickWidget *quickWidget() const; @@ -86,6 +87,9 @@ private: PreviewImageProvider *m_previewImageProvider = nullptr; QString m_filterText; + + ModelNode m_materialToDrag; + QPoint m_dragStartPoint; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/navigator/choosefrompropertylistdialog.cpp b/src/plugins/qmldesigner/components/navigator/choosefrompropertylistdialog.cpp index 00987711c56..178f79e18a3 100644 --- a/src/plugins/qmldesigner/components/navigator/choosefrompropertylistdialog.cpp +++ b/src/plugins/qmldesigner/components/navigator/choosefrompropertylistdialog.cpp @@ -56,6 +56,8 @@ ChooseFromPropertyListFilter::ChooseFromPropertyListFilter(const NodeMetaInfo &i // ParticleAbstractShape3D // -> ParticleEmitter3D // -> Attractor3D + // Material + // -> Model const TypeName textureType = "QtQuick3D.Texture"; if (insertInfo.isSubclassOf(textureType)) { @@ -104,6 +106,9 @@ ChooseFromPropertyListFilter::ChooseFromPropertyListFilter(const NodeMetaInfo &i if (parentInfo.isSubclassOf("QtQuick3D.Particles3D.ParticleEmitter3D") || parentInfo.isSubclassOf("QtQuick3D.Particles3D.Attractor3D")) propertyList.append("shape"); + } else if (insertInfo.isSubclassOf("QtQuick3D.Material")) { + if (parentInfo.isSubclassOf("QtQuick3D.Particles3D.Model")) + propertyList.append("materials"); } } diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp index 38c32f65cd8..d347854f004 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp @@ -464,6 +464,7 @@ QStringList NavigatorTreeModel::mimeTypes() const { const static QStringList types({Constants::MIME_TYPE_MODELNODE_LIST, Constants::MIME_TYPE_ITEM_LIBRARY_INFO, + Constants::MIME_TYPE_MATERIAL, Constants::MIME_TYPE_ASSETS}); return types; @@ -559,6 +560,8 @@ bool NavigatorTreeModel::dropMimeData(const QMimeData *mimeData, if (dropModelIndex.model() == this) { if (mimeData->hasFormat(Constants::MIME_TYPE_ITEM_LIBRARY_INFO)) { handleItemLibraryItemDrop(mimeData, rowNumber, dropModelIndex); + } else if (mimeData->hasFormat(Constants::MIME_TYPE_MATERIAL)) { + handleMaterialDrop(mimeData, rowNumber, dropModelIndex); } else if (mimeData->hasFormat(Constants::MIME_TYPE_ASSETS)) { const QStringList assetsPaths = QString::fromUtf8(mimeData->data(Constants::MIME_TYPE_ASSETS)).split(','); NodeAbstractProperty targetProperty; @@ -779,6 +782,33 @@ void NavigatorTreeModel::handleItemLibraryItemDrop(const QMimeData *mimeData, in } } +void NavigatorTreeModel::handleMaterialDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex) +{ + QTC_ASSERT(m_view, return); + + const QModelIndex rowModelIndex = dropModelIndex.sibling(dropModelIndex.row(), 0); + int targetRowNumber = rowNumber; + NodeAbstractProperty targetProperty; + + bool foundTarget = findTargetProperty(rowModelIndex, this, &targetProperty, &targetRowNumber, "materials"); + if (!foundTarget) + return; + + ModelNode targetNode = targetProperty.parentModelNode(); + if (!targetNode.isSubclassOf("QtQuick3D.Model")) + return; + + QByteArray data = mimeData->data(Constants::MIME_TYPE_MATERIAL); + QDataStream stream(data); + qint32 internalId; + stream >> internalId; + ModelNode matNode = m_view->modelNodeForInternalId(internalId); + + m_view->executeInTransaction(__FUNCTION__, [&] { + m_view->assignMaterialTo3dModel(targetNode, matNode); + }); +} + ModelNode NavigatorTreeModel::handleItemLibraryImageDrop(const QString &imagePath, NodeAbstractProperty targetProperty, const QModelIndex &rowModelIndex, diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h index 96529816076..153491bfc14 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h +++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h @@ -115,6 +115,7 @@ private: int targetIndex, bool executeInTransaction = true); void handleInternalDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex); void handleItemLibraryItemDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex); + void handleMaterialDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex); ModelNode handleItemLibraryImageDrop(const QString &imagePath, NodeAbstractProperty targetProperty, const QModelIndex &rowModelIndex, bool &outMoveNodesAfter); ModelNode handleItemLibraryFontDrop(const QString &fontFamily, NodeAbstractProperty targetProperty, diff --git a/src/plugins/qmldesigner/components/navigator/navigatorview.cpp b/src/plugins/qmldesigner/components/navigator/navigatorview.cpp index 495982c6fc1..f8d5c884fbd 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatorview.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatorview.cpp @@ -276,6 +276,15 @@ void NavigatorView::dragStarted(QMimeData *mimeData) m_widget->setDragType(itemLibraryEntry.typeName()); m_widget->update(); + } else if (mimeData->hasFormat(Constants::MIME_TYPE_MATERIAL)) { + QByteArray data = mimeData->data(Constants::MIME_TYPE_MATERIAL); + QDataStream stream(data); + qint32 internalId; + stream >> internalId; + ModelNode matNode = modelNodeForInternalId(internalId); + + m_widget->setDragType(matNode.metaInfo().typeName()); + m_widget->update(); } } diff --git a/src/plugins/qmldesigner/qmldesignerconstants.h b/src/plugins/qmldesigner/qmldesignerconstants.h index b2ed51cd874..486faeaa267 100644 --- a/src/plugins/qmldesigner/qmldesignerconstants.h +++ b/src/plugins/qmldesigner/qmldesignerconstants.h @@ -92,6 +92,7 @@ const char MATERIAL_LIB_ID[] = "__materialLibrary__"; const char MIME_TYPE_ITEM_LIBRARY_INFO[] = "application/vnd.qtdesignstudio.itemlibraryinfo"; const char MIME_TYPE_ASSETS[] = "application/vnd.qtdesignstudio.assets"; +const char MIME_TYPE_MATERIAL[] = "application/vnd.qtdesignstudio.material"; const char MIME_TYPE_ASSET_IMAGE[] = "application/vnd.qtdesignstudio.asset.image"; const char MIME_TYPE_ASSET_FONT[] = "application/vnd.qtdesignstudio.asset.font"; const char MIME_TYPE_ASSET_SHADER[] = "application/vnd.qtdesignstudio.asset.shader"; From 46791275c3fa2822359cc6b838315c233b0e23ea Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Thu, 9 Jun 2022 14:56:21 +0200 Subject: [PATCH 54/96] Doc: Describe adjusting QML JS code line length Document the Line Length setting in Edit > Preferences > Qt Quick > Edit. Task-number: QTCREATORBUG-27560 Change-Id: I2e79e4d4e3d9e691170250711b3370014f40bf1c Reviewed-by: Eike Ziller --- ...eator-code-style-settings-edit-qtquick.png | Bin 16780 -> 14629 bytes .../src/editors/creator-code-indentation.qdoc | 13 ++++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/doc/qtcreator/images/qtcreator-code-style-settings-edit-qtquick.png b/doc/qtcreator/images/qtcreator-code-style-settings-edit-qtquick.png index 17dbf6bda252564904e1bd35b7dac3c2afe66daa..e0f5e44e7c943543aa3ffd27f981f9645f954799 100644 GIT binary patch literal 14629 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 Sz=(l?fx*+&&t;ucLK6VjwqxM{ literal 16780 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 QU|?YIboFyt=akR{0IhoO!2kdN diff --git a/doc/qtcreator/src/editors/creator-code-indentation.qdoc b/doc/qtcreator/src/editors/creator-code-indentation.qdoc index 6a0e93985a3..1816872a160 100644 --- a/doc/qtcreator/src/editors/creator-code-indentation.qdoc +++ b/doc/qtcreator/src/editors/creator-code-indentation.qdoc @@ -109,7 +109,7 @@ \image qtcreator-options-code-style-cpp.png "C++ Code Style options" \li Give a name to the settings and click \uicontrol OK. \li Click \uicontrol Edit to specify code style settings for the project. - \image qtcreator-code-style-settings-edit-cpp.png "Edit Code Style Settings dialog" + \image qtcreator-code-style-settings-edit-cpp.png "Edit Code Style dialog" \endlist You can specify how to: @@ -129,7 +129,7 @@ You can use the live preview to see how the options change the indentation. To specify different settings for a particular project, select - \uicontrol Projects > \uicontrol {Code Style Settings}. + \uicontrol Projects > \uicontrol {Code Style}. \include creator-clangformat.qdocinc clang format \endif @@ -146,14 +146,17 @@ \image qtcreator-options-code-style-qml.png "QML Code Style options" \li Give a name to the settings and click \uicontrol OK. \li Click \uicontrol Edit to specify code style settings for the project. - \image qtcreator-code-style-settings-edit-qtquick.png "Edit Code Style Settings dialog" + \image qtcreator-code-style-settings-edit-qtquick.png "Edit Code Style dialog" \endlist You can specify how to interpret the \key Tab key presses and how to align continuation lines. + In \uicontrol {Line length}, you can adjust the maximum line length for + code lines. + To specify different settings for a particular project, select - \uicontrol Projects > \uicontrol {Code Style Settings}. + \uicontrol Projects > \uicontrol {Code Style}. \if defined(qtcreator) \section1 Indenting Nim Files @@ -167,7 +170,7 @@ \image qtcreator-options-code-style-nim.png "Nim Code Style options" \li Give a name to the settings and click \uicontrol OK. \li Click \uicontrol Edit to specify code style settings for the project. - \image qtcreator-code-style-settings-edit-nim.png "Edit Code Style Settings dialog" + \image qtcreator-code-style-settings-edit-nim.png "Edit Code Style dialog" \endlist You can specify how to interpret the \key Tab key presses and how to align From 29bd1b025a3890a21737221b63b3d05b97e1f06c Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 28 Jun 2022 13:37:57 +0200 Subject: [PATCH 55/96] RemoteLinux: Translate manually provided gdbserver paths Similar issue as the one in the referenced task. Change-Id: I71d7c50d2e6192ec7d8dca0294e087f7c8d6361a Task-number: QTCREATORBUG-27752 Reviewed-by: Christian Kandeler Reviewed-by: --- .../remotelinux/genericlinuxdeviceconfigurationwidget.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp index ef5fcba0fd6..7c5d09faddb 100644 --- a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp +++ b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp @@ -130,7 +130,7 @@ void GenericLinuxDeviceConfigurationWidget::keyFileEditingFinished() void GenericLinuxDeviceConfigurationWidget::gdbServerEditingFinished() { - device()->setDebugServerPath(FilePath::fromString(m_ui->gdbServerLineEdit->text())); + device()->setDebugServerPath(device()->filePath(m_ui->gdbServerLineEdit->text())); } void GenericLinuxDeviceConfigurationWidget::handleFreePortsChanged() @@ -213,6 +213,7 @@ void GenericLinuxDeviceConfigurationWidget::initGui() m_ui->timeoutSpinBox->setValue(sshParams.timeout); m_ui->userLineEdit->setText(sshParams.userName()); m_ui->keyFileLineEdit->setFilePath(sshParams.privateKeyFile); - m_ui->gdbServerLineEdit->setText(device()->debugServerPath().toString()); + // FIXME: Use a remote executable line edit + m_ui->gdbServerLineEdit->setText(device()->debugServerPath().path()); updatePortsWarningLabel(); } From b1eadd3bc658a251daf51eb12e63d391ca251f8f Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 30 Jun 2022 07:47:09 +0200 Subject: [PATCH 56/96] Editor: hide "Hide mouse cursor while typing" option on mac The mouse cursor is hidden unconditionally in Qt, so do not give the impression that this can be disabled. Also we have a bunch of bug reports that claim that the cursor does not come back if the mouse is moved after typing. This might be caused by the double hide of Qt Creator, Qt and the moon phase. Fixes: QTCREATORBUG-27572 Change-Id: I11b39cac6cd8eb0717fca00d1812a4e052223f21 Reviewed-by: Eike Ziller --- src/plugins/texteditor/behaviorsettingswidget.cpp | 3 +++ src/plugins/texteditor/texteditor.cpp | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/plugins/texteditor/behaviorsettingswidget.cpp b/src/plugins/texteditor/behaviorsettingswidget.cpp index 4a4eae51c2c..409f80dfa7f 100644 --- a/src/plugins/texteditor/behaviorsettingswidget.cpp +++ b/src/plugins/texteditor/behaviorsettingswidget.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -122,6 +123,8 @@ BehaviorSettingsWidget::BehaviorSettingsWidget(QWidget *parent) this, &BehaviorSettingsWidget::slotBehaviorSettingsChanged); connect(d->m_ui.smartSelectionChanging, &QAbstractButton::clicked, this, &BehaviorSettingsWidget::slotBehaviorSettingsChanged); + + d->m_ui.mouseHiding->setVisible(!Utils::HostOsInfo::isMacHost()); } BehaviorSettingsWidget::~BehaviorSettingsWidget() diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 3aeb86bad2e..9a4b997ffc2 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -3375,7 +3375,7 @@ void TextEditorWidget::setMouseHidingEnabled(bool b) bool TextEditorWidget::mouseHidingEnabled() const { - return d->m_behaviorSettings.m_mouseHiding; + return Utils::HostOsInfo::isMacHost() ? false : d->m_behaviorSettings.m_mouseHiding; } void TextEditorWidget::setScrollWheelZoomingEnabled(bool b) From 7103432404fb6f76c38b51b8455736f42642127b Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 30 Jun 2022 08:58:11 +0200 Subject: [PATCH 57/96] Squish: Do not expect clang shipped by QC anymore MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I2f09835bde52aa2f0cd90def7f6d8d628736ff56 Reviewed-by: Robert Löhning --- .../tst_default_settings/test.py | 40 ------------------- 1 file changed, 40 deletions(-) diff --git a/tests/system/suite_general/tst_default_settings/test.py b/tests/system/suite_general/tst_default_settings/test.py index bf0d55c6895..88b2160e5ea 100644 --- a/tests/system/suite_general/tst_default_settings/test.py +++ b/tests/system/suite_general/tst_default_settings/test.py @@ -171,37 +171,6 @@ def __kitFunc__(it, foundQt, foundCompNames): details = details.replace("", "").replace("", "") test.warning("Detected error and/or warning: %s" % details) -def __extendExpectedCompilersWithInternalClang__(expected): - global appContext - # QC ships a clang itself - regex = '^(.*(qtcreator(.exe)?|Qt Creator))( .*)?$' # QC with optional arguments - qcPath = re.match(regex, appContext.commandLine) - if qcPath is None: - test.warning("Regular expression failed.") - else: - qcPath = qcPath.group(1) - if platform.system() == 'Darwin': - internalClang = os.path.join(qcPath, '..', '..', 'Resources') - elif platform.system() in ('Windows', 'Microsoft'): - internalClang = os.path.join(qcPath, '..') - else: - internalClang = os.path.join(qcPath, '..', '..', 'libexec', 'qtcreator') - internalClang = os.path.join(internalClang, 'clang', 'bin', 'clang') - if platform.system() in ('Microsoft', 'Windows'): - internalClang += '-cl.exe' - internalClang = os.path.abspath(internalClang) - if os.path.exists(internalClang): - if platform.system() in ('Microsoft', 'Windows'): - # just add a fuzzy comparable name - everything else is not worth the effort here - expected.append({'^Default LLVM \d{2} bit based on MSVC\d{4}$':''}) - else: - expected.append(internalClang) - else: - test.fail("QC package seems to be faulty - missing internal provided clang.\nIf this " - "is not a package, but a self-compiled QC, just copy the clang executable " - "located inside the LLVM_INSTALL_DIR/bin (used while building) to the " - "expected path.", "Expected '%s'" % internalClang) - def __getExpectedCompilers__(): # TODO: enhance this to distinguish between C and C++ compilers expected = [] @@ -219,8 +188,6 @@ def __getExpectedCompilers__(): if xcodeClang and os.path.exists(xcodeClang) and xcodeClang not in expected: expected.append(xcodeClang) - __extendExpectedCompilersWithInternalClang__(expected) - for compiler in compilers: compilerPath = which(compiler) if compilerPath: @@ -309,13 +276,6 @@ def __compareCompilers__(foundCompilers, expectedCompilers): if isString(currentExp): continue key = currentExp.keys()[0] - # special case for (fuzzy) regex comparison on Windows (internal LLVM) - if isWin and key.startswith('^') and key.endswith('$'): - if re.match(key, currentFound.keys()[0], flags): - test.verify(os.path.exists(currentFound.values()[0].rsplit(" ", 1)[0]), - "Verifying whether shipped clang got set up.") - foundExp = True - break # the regex .*? is used for the different possible version strings of the WinSDK # if it's present a regex will be validated otherwise simple string comparison if (((".*?" in key and re.match(key, currentFound.keys()[0], flags)) From d09081d07cef5b3ab06fe86e2530e13f8d5fed28 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 28 Jun 2022 11:07:01 +0200 Subject: [PATCH 58/96] CppEditor: Initialize pointer member with nullptr ... when generating missing Q_PROPERTY infos. Fixes: QTCREATORBUG-27770 Change-Id: I31d13ae6d6ed5b2be354097d48303d0cadfa253e Reviewed-by: Christian Kandeler --- src/plugins/cppeditor/cppquickfixes.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp index e61c0ce6aed..8469327414d 100644 --- a/src/plugins/cppeditor/cppquickfixes.cpp +++ b/src/plugins/cppeditor/cppquickfixes.cpp @@ -4189,9 +4189,12 @@ void GetterSetterRefactoringHelper::performGeneration(ExistingGetterSetterData d // member variable if (generateFlags & Flag::GenerateMemberVariable) { - const QString storageDeclaration = overview.prettyType(memberVariableType, - data.memberVariableName) - + QLatin1String(";\n"); + QString storageDeclaration = overview.prettyType(memberVariableType, data.memberVariableName); + if (memberVariableType->isPointerType() + && m_operation->semanticInfo().doc->translationUnit()->languageFeatures().cxx11Enabled) { + storageDeclaration.append(" = nullptr"); + } + storageDeclaration.append(";\n"); addHeaderCode(InsertionPointLocator::Private, storageDeclaration); } From 450f4abe745210d949c569926372858284f43ef7 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 30 Jun 2022 08:40:54 +0200 Subject: [PATCH 59/96] Squish: Adapt to changed ui MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ...and modified minimum requirements inside wizards. Change-Id: I32d2dea0dc0ccff273ebf32f5aa713829330eb01 Reviewed-by: Robert Löhning --- tests/system/objects.map | 2 +- .../system/suite_general/tst_create_proj_wizard/test.py | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/tests/system/objects.map b/tests/system/objects.map index 81120f94964..7922cacca2c 100644 --- a/tests/system/objects.map +++ b/tests/system/objects.map @@ -89,7 +89,7 @@ :JsonWizard_ProjectExplorer::JsonFieldPage {type='ProjectExplorer::JsonFieldPage' unnamed='1' visible='1' window=':New_ProjectExplorer::JsonWizard'} :Kits_QtVersion_QComboBox {container=':qt_tabwidget_stackedwidget_QWidget' leftWidget=':QtVersionLabel_KitPage' type='QComboBox' unnamed='1' visible='1'} :Locals and Expressions_Debugger::Internal::WatchTreeView {container=':Debugger.Docks.LocalsAndWatchersDockWidget.Inspector_QFrame' name='WatchWindow' type='Debugger::Internal::WatchTreeView' visible='1'} -:Minimal required Qt version:_QLabel {text='Minimal required Qt version:' type='QLabel' unnamed='1' visible='1' window=':New_ProjectExplorer::JsonWizard'} +:Minimal required Qt version:_QLabel {text='Minimum required Qt version:' type='QLabel' unnamed='1' visible='1' window=':New_ProjectExplorer::JsonWizard'} :New Text File.Add to project:_QLabel {name='projectLabel' text='Add to project:' type='QLabel' visible='1' window=':New_ProjectExplorer::JsonWizard'} :New Text File.nameLineEdit_Utils::FileNameValidatingLineEdit {name='nameLineEdit' type='Utils::FileNameValidatingLineEdit' visible='1' window=':New_ProjectExplorer::JsonWizard'} :New.comboBox_QComboBox {name='comboBox' type='QComboBox' visible='1' window=':New_Core::Internal::NewDialog'} diff --git a/tests/system/suite_general/tst_create_proj_wizard/test.py b/tests/system/suite_general/tst_create_proj_wizard/test.py index 38550a96aff..00bccc86259 100644 --- a/tests/system/suite_general/tst_create_proj_wizard/test.py +++ b/tests/system/suite_general/tst_create_proj_wizard/test.py @@ -55,14 +55,19 @@ def main(): # skip non-configurable if "Import" in category: continue + # FIXME + if "Qt for Python" in category: + continue mouseClick(waitForObjectItem(categoriesView, "Projects." + category)) templatesView = waitForObject("{name='templatesView' type='QListView' visible='1'}") # needed because categoriesView and templatesView using same model for template in dumpItems(templatesView.model(), templatesView.rootIndex()): template = template.replace(".", "\\.") + # FIXME this needs Qt6.2+ + if template == "Qt Quick 2 Extension Plugin": + continue # skip non-configurable - if (template not in ["Qt Quick UI Prototype", "Auto Test Project", "Qt Creator Plugin"] - and "Qt for Python - " not in template): # FIXME + if template not in ["Qt Quick UI Prototype", "Auto Test Project", "Qt Creator Plugin"]: availableProjectTypes.append({category:template}) safeClickButton("Cancel") for current in availableProjectTypes: From c294df1d3a36e351b18a018d1c8052d4e4a49dc2 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 30 Jun 2022 09:55:27 +0200 Subject: [PATCH 60/96] Squish: Skip a test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wizard nowadays expects a Qt version we do not provide by default. Change-Id: If0f2b3aa5755a549bd63fc258fd78b1a40337a8a Reviewed-by: Robert Löhning --- tests/system/suite_qtquick/tst_qtquick_creation4/test.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/system/suite_qtquick/tst_qtquick_creation4/test.py b/tests/system/suite_qtquick/tst_qtquick_creation4/test.py index 82d04ef8d3d..9408acaf7df 100644 --- a/tests/system/suite_qtquick/tst_qtquick_creation4/test.py +++ b/tests/system/suite_qtquick/tst_qtquick_creation4/test.py @@ -26,6 +26,10 @@ source("../../shared/qtcreator.py") def main(): + # FIXME + test.warning("Qt Quick 2 Extension Plugin needs Qt6.2+ nowadays.") + return + startQC() if not startedWithoutPluginError(): return From 3be472c8d298a50e0c858c87ef241417d8314d4e Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 30 Jun 2022 09:08:47 +0200 Subject: [PATCH 61/96] ProjectExplorer: Use FilePath for sysroots ... and reduce to the relevant part when passing to cmake. Task-number: QTCREATORBUG-27229 Change-Id: I7cde2ff04530caf439d6707c2c6d15a8e734ae0b Reviewed-by: Reviewed-by: Christian Kandeler --- src/plugins/baremetal/iarewtoolchain.cpp | 4 ++-- src/plugins/baremetal/keiltoolchain.cpp | 4 ++-- src/plugins/baremetal/sdcctoolchain.cpp | 2 +- .../compilationdatabasetests.cpp | 7 ++++--- .../compilationdatabaseutils.cpp | 5 +++-- .../compilationdatabaseutils.h | 6 ++---- .../compilationdbparser.cpp | 2 ++ src/plugins/cppeditor/cppmodelmanager.cpp | 2 +- src/plugins/projectexplorer/customtoolchain.cpp | 3 ++- src/plugins/projectexplorer/gcctoolchain.cpp | 12 ++++++------ src/plugins/projectexplorer/gcctoolchain.h | 4 ++-- src/plugins/projectexplorer/msvctoolchain.cpp | 2 +- src/plugins/projectexplorer/rawprojectpart.cpp | 5 ++--- src/plugins/projectexplorer/rawprojectpart.h | 6 +++--- src/plugins/projectexplorer/toolchain.h | 2 +- 15 files changed, 34 insertions(+), 32 deletions(-) diff --git a/src/plugins/baremetal/iarewtoolchain.cpp b/src/plugins/baremetal/iarewtoolchain.cpp index bc6d2757dfa..101a80f5317 100644 --- a/src/plugins/baremetal/iarewtoolchain.cpp +++ b/src/plugins/baremetal/iarewtoolchain.cpp @@ -347,10 +347,10 @@ ToolChain::BuiltInHeaderPathsRunner IarToolChain::createBuiltInHeaderPathsRunner HeaderPathsCache headerPaths = headerPathsCache(); return [env, compiler, headerPaths, languageId](const QStringList &flags, - const QString &fileName, + const FilePath &sysRoot, const QString &) { Q_UNUSED(flags) - Q_UNUSED(fileName) + Q_UNUSED(sysRoot) const HeaderPaths paths = dumpHeaderPaths(compiler, languageId, env); headerPaths->insert({}, paths); diff --git a/src/plugins/baremetal/keiltoolchain.cpp b/src/plugins/baremetal/keiltoolchain.cpp index 8b1d9683262..44e8737ac32 100644 --- a/src/plugins/baremetal/keiltoolchain.cpp +++ b/src/plugins/baremetal/keiltoolchain.cpp @@ -473,9 +473,9 @@ ToolChain::BuiltInHeaderPathsRunner KeilToolChain::createBuiltInHeaderPathsRunne const HeaderPathsCache headerPaths = headerPathsCache(); return [compiler, - headerPaths](const QStringList &flags, const QString &fileName, const QString &) { + headerPaths](const QStringList &flags, const FilePath &sysRoot, const QString &) { Q_UNUSED(flags) - Q_UNUSED(fileName) + Q_UNUSED(sysRoot) const HeaderPaths paths = dumpHeaderPaths(compiler); headerPaths->insert({}, paths); diff --git a/src/plugins/baremetal/sdcctoolchain.cpp b/src/plugins/baremetal/sdcctoolchain.cpp index bccd5a4c19d..9ed380f5c80 100644 --- a/src/plugins/baremetal/sdcctoolchain.cpp +++ b/src/plugins/baremetal/sdcctoolchain.cpp @@ -258,7 +258,7 @@ ToolChain::BuiltInHeaderPathsRunner SdccToolChain::createBuiltInHeaderPathsRunne const FilePath compiler = compilerCommand(); const Abi abi = targetAbi(); - return [env, compiler, abi](const QStringList &, const QString &, const QString &) { + return [env, compiler, abi](const QStringList &, const FilePath &, const QString &) { return dumpHeaderPaths(compiler, env, abi); }; } diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdatabasetests.cpp b/src/plugins/compilationdatabaseprojectmanager/compilationdatabasetests.cpp index 85a180e4e95..15651214bdc 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdatabasetests.cpp +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdatabasetests.cpp @@ -45,6 +45,7 @@ using namespace CppEditor; using namespace ProjectExplorer; +using namespace Utils; namespace CompilationDatabaseProjectManager { namespace Internal { @@ -124,7 +125,7 @@ public: QStringList flags; QString fileName; QString workingDir; - QString sysRoot; + FilePath sysRoot; }; } @@ -183,8 +184,8 @@ void CompilationDatabaseTests::testFilterArguments() {"RELATIVE_PLUGIN_PATH", "\"../lib/qtcreator/plugins\""}, {"QT_CREATOR", "1"}})); QCOMPARE(testData.fileKind, CppEditor::ProjectFile::Kind::CXXSource); - QCOMPARE(testData.sysRoot, HostOsInfo::isWindowsHost() ? QString("C:\\sysroot\\embedded") - : QString("/opt/sysroot/embedded")); + QCOMPARE(testData.sysRoot.toString(), HostOsInfo::isWindowsHost() ? QString("C:\\sysroot\\embedded") + : QString("/opt/sysroot/embedded")); } static QString kCmakeCommand diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.cpp b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.cpp index 632db825562..a60d2ed9141 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.cpp +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.cpp @@ -38,6 +38,7 @@ #include using namespace ProjectExplorer; +using namespace Utils; namespace CompilationDatabaseProjectManager { namespace Internal { @@ -102,7 +103,7 @@ void filteredFlags(const QString &fileName, HeaderPaths &headerPaths, Macros ¯os, CppEditor::ProjectFile::Kind &fileKind, - QString &sysRoot) + Utils::FilePath &sysRoot) { if (flags.empty()) return; @@ -192,7 +193,7 @@ void filteredFlags(const QString &fileName, if (flag.startsWith("--sysroot=")) { if (sysRoot.isEmpty()) - sysRoot = updatedPathFlag(flag.mid(10), workingDir); + sysRoot = FilePath::fromString(updatedPathFlag(flag.mid(10), workingDir)); continue; } diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.h b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.h index 3952b41c6b2..70a94382923 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.h +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.h @@ -25,10 +25,8 @@ #pragma once -#include "compilationdatabaseconstants.h" - #include -#include +#include #include #include @@ -65,7 +63,7 @@ void filteredFlags(const QString &fileName, QVector &headerPaths, QVector ¯os, CppEditor::ProjectFile::Kind &fileKind, - QString &sysRoot); + Utils::FilePath &sysRoot); QStringList splitCommandLine(QString commandLine, QSet &flagsCache); diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.cpp b/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.cpp index caeeddded9d..b31125fbb33 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.cpp +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.cpp @@ -25,6 +25,8 @@ #include "compilationdbparser.h" +#include "compilationdatabaseconstants.h" + #include #include #include diff --git a/src/plugins/cppeditor/cppmodelmanager.cpp b/src/plugins/cppeditor/cppmodelmanager.cpp index 6258c9355a7..39bcc5118c0 100644 --- a/src/plugins/cppeditor/cppmodelmanager.cpp +++ b/src/plugins/cppeditor/cppmodelmanager.cpp @@ -1533,7 +1533,7 @@ void CppModelManager::setupFallbackProjectPart() if (sysroot.isEmpty()) sysroot = Utils::FilePath::fromString(defaultTc->sysRoot()); Utils::Environment env = defaultKit->buildEnvironment(); - tcInfo = ToolChainInfo(defaultTc, sysroot.toString(), env); + tcInfo = ToolChainInfo(defaultTc, sysroot, env); const auto macroInspectionWrapper = [runner = tcInfo.macroInspectionRunner]( const QStringList &flags) { ToolChain::MacroInspectionReport report = runner(flags); diff --git a/src/plugins/projectexplorer/customtoolchain.cpp b/src/plugins/projectexplorer/customtoolchain.cpp index 3b8b3a49380..8ed88ea7593 100644 --- a/src/plugins/projectexplorer/customtoolchain.cpp +++ b/src/plugins/projectexplorer/customtoolchain.cpp @@ -139,7 +139,8 @@ ToolChain::BuiltInHeaderPathsRunner CustomToolChain::createBuiltInHeaderPathsRun const HeaderPaths builtInHeaderPaths = m_builtInHeaderPaths; // This runner must be thread-safe! - return [builtInHeaderPaths](const QStringList &cxxFlags, const QString &, const QString &) { + return [builtInHeaderPaths](const QStringList &cxxFlags, const FilePath &sysRoot, const QString &) { + Q_UNUSED(sysRoot) HeaderPaths flagHeaderPaths; for (const QString &cxxFlag : cxxFlags) { if (cxxFlag.startsWith(QLatin1String("-I"))) diff --git a/src/plugins/projectexplorer/gcctoolchain.cpp b/src/plugins/projectexplorer/gcctoolchain.cpp index beb91799715..7c1e502c874 100644 --- a/src/plugins/projectexplorer/gcctoolchain.cpp +++ b/src/plugins/projectexplorer/gcctoolchain.cpp @@ -596,15 +596,15 @@ QStringList GccToolChain::includedFiles(const QStringList &flags, const QString } QStringList GccToolChain::gccPrepareArguments(const QStringList &flags, - const QString &sysRoot, + const FilePath &sysRoot, const QStringList &platformCodeGenFlags, - Utils::Id languageId, + Id languageId, OptionsReinterpreter reinterpretOptions) { QStringList arguments; const bool hasKitSysroot = !sysRoot.isEmpty(); if (hasKitSysroot) - arguments.append(QString::fromLatin1("--sysroot=%1").arg(sysRoot)); + arguments.append(QString("--sysroot=%1").arg(sysRoot.nativePath())); QStringList allFlags; allFlags << platformCodeGenFlags << flags; @@ -629,7 +629,7 @@ HeaderPaths GccToolChain::builtInHeaderPaths(const Utils::Environment &env, Utils::Id languageId, ExtraHeaderPathsFunction extraHeaderPathsFunction, const QStringList &flags, - const QString &sysRoot, + const Utils::FilePath &sysRoot, const QString &originalTargetTriple) { QStringList arguments = gccPrepareArguments(flags, @@ -677,7 +677,7 @@ ToolChain::BuiltInHeaderPathsRunner GccToolChain::createBuiltInHeaderPathsRunner headerCache = headerPathsCache(), languageId = language(), extraHeaderPathsFunction = m_extraHeaderPathsFunction](const QStringList &flags, - const QString &sysRoot, + const FilePath &sysRoot, const QString &) { return builtInHeaderPaths(fullEnv, compilerCommand, @@ -1712,7 +1712,7 @@ ToolChain::BuiltInHeaderPathsRunner ClangToolChain::createBuiltInHeaderPathsRunn headerCache = headerPathsCache(), languageId = language(), extraHeaderPathsFunction = m_extraHeaderPathsFunction](const QStringList &flags, - const QString &sysRoot, + const FilePath &sysRoot, const QString &target) { return builtInHeaderPaths(fullEnv, compilerCommand, diff --git a/src/plugins/projectexplorer/gcctoolchain.h b/src/plugins/projectexplorer/gcctoolchain.h index bad26674e23..980ea3fb8b7 100644 --- a/src/plugins/projectexplorer/gcctoolchain.h +++ b/src/plugins/projectexplorer/gcctoolchain.h @@ -151,7 +151,7 @@ protected: Utils::Id languageId, ExtraHeaderPathsFunction extraHeaderPathsFunction, const QStringList &flags, - const QString &sysRoot, + const Utils::FilePath &sysRoot, const QString &originalTargetTriple); static HeaderPaths gccHeaderPaths(const Utils::FilePath &gcc, @@ -175,7 +175,7 @@ protected: private: void updateSupportedAbis() const; static QStringList gccPrepareArguments(const QStringList &flags, - const QString &sysRoot, + const Utils::FilePath &sysRoot, const QStringList &platformCodeGenFlags, Utils::Id languageId, OptionsReinterpreter reinterpretOptions); diff --git a/src/plugins/projectexplorer/msvctoolchain.cpp b/src/plugins/projectexplorer/msvctoolchain.cpp index cd76162d402..7ab685bdfc9 100644 --- a/src/plugins/projectexplorer/msvctoolchain.cpp +++ b/src/plugins/projectexplorer/msvctoolchain.cpp @@ -1142,7 +1142,7 @@ ToolChain::BuiltInHeaderPathsRunner MsvcToolChain::createBuiltInHeaderPathsRunne Utils::Environment fullEnv = env; addToEnvironment(fullEnv); - return [this, fullEnv](const QStringList &, const QString &, const QString &) { + return [this, fullEnv](const QStringList &, const FilePath &, const QString &) { QMutexLocker locker(&m_headerPathsMutex); const auto envList = fullEnv.toStringList(); const auto it = m_headerPathsPerEnv.constFind(envList); diff --git a/src/plugins/projectexplorer/rawprojectpart.cpp b/src/plugins/projectexplorer/rawprojectpart.cpp index 35e96b75d87..b222610446d 100644 --- a/src/plugins/projectexplorer/rawprojectpart.cpp +++ b/src/plugins/projectexplorer/rawprojectpart.cpp @@ -29,7 +29,6 @@ #include "buildconfiguration.h" #include "kitinformation.h" #include "project.h" -#include "projectexplorerconstants.h" #include "target.h" #include @@ -165,7 +164,7 @@ KitInfo::KitInfo(Kit *kit) } // Sysroot - sysRootPath = SysRootKitAspect::sysRoot(kit).toString(); + sysRootPath = SysRootKitAspect::sysRoot(kit); } bool KitInfo::isValid() const @@ -174,7 +173,7 @@ bool KitInfo::isValid() const } ToolChainInfo::ToolChainInfo(const ToolChain *toolChain, - const QString &sysRootPath, + const Utils::FilePath &sysRootPath, const Utils::Environment &env) { if (toolChain) { diff --git a/src/plugins/projectexplorer/rawprojectpart.h b/src/plugins/projectexplorer/rawprojectpart.h index 3bf7d31b906..569e2fd8af9 100644 --- a/src/plugins/projectexplorer/rawprojectpart.h +++ b/src/plugins/projectexplorer/rawprojectpart.h @@ -138,7 +138,7 @@ public: Utils::QtMajorVersion projectPartQtVersion = Utils::QtMajorVersion::None; - QString sysRootPath; + Utils::FilePath sysRootPath; }; class PROJECTEXPLORER_EXPORT ToolChainInfo @@ -146,7 +146,7 @@ class PROJECTEXPLORER_EXPORT ToolChainInfo public: ToolChainInfo() = default; ToolChainInfo(const ProjectExplorer::ToolChain *toolChain, - const QString &sysRootPath, + const Utils::FilePath &sysRootPath, const Utils::Environment &env); bool isValid() const { return type.isValid(); } @@ -161,7 +161,7 @@ public: Utils::FilePath installDir; QStringList extraCodeModelFlags; - QString sysRootPath; // For headerPathsRunner. + Utils::FilePath sysRootPath; // For headerPathsRunner. ProjectExplorer::ToolChain::BuiltInHeaderPathsRunner headerPathsRunner; ProjectExplorer::ToolChain::MacroInspectionRunner macroInspectionRunner; }; diff --git a/src/plugins/projectexplorer/toolchain.h b/src/plugins/projectexplorer/toolchain.h index 6a3ced00535..1b6ed3e7a2b 100644 --- a/src/plugins/projectexplorer/toolchain.h +++ b/src/plugins/projectexplorer/toolchain.h @@ -147,7 +147,7 @@ public: // A BuiltInHeaderPathsRunner is created in the ui thread and runs in another thread. using BuiltInHeaderPathsRunner = std::function; + const QStringList &cxxflags, const Utils::FilePath &sysRoot, const QString &originalTargetTriple)>; virtual BuiltInHeaderPathsRunner createBuiltInHeaderPathsRunner(const Utils::Environment &env) const = 0; virtual void addToEnvironment(Utils::Environment &env) const = 0; virtual Utils::FilePath makeCommand(const Utils::Environment &env) const = 0; From 7cf96e12098104c80576dce20a3dc8d0a3ef18fd Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Tue, 28 Jun 2022 08:22:44 +0200 Subject: [PATCH 62/96] QmlDesigner: Add Control property specifics Task-number: QDS-6621 Change-Id: I4bded48e95688321796b8db311f6d4acc9c5e45a Reviewed-by: Reviewed-by: Thomas Hartmann --- .../QtQuick/Controls/ControlSpecifics.qml | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ControlSpecifics.qml diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ControlSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ControlSpecifics.qml new file mode 100644 index 00000000000..d692c7ae6e3 --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ControlSpecifics.qml @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.15 +import QtQuick.Layouts 1.15 +import HelperWidgets 2.0 +import QtQuickDesignerTheme 1.0 +import StudioTheme 1.0 as StudioTheme + +Column { + anchors.left: parent.left + anchors.right: parent.right + + ControlSection {} + + FontSection {} + + PaddingSection {} +} From 8a31be38e3bc203cc2f5a160f25b71ae40685fe0 Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Tue, 28 Jun 2022 15:20:30 +0200 Subject: [PATCH 63/96] QmlDesigner: Add InsetSection to Control specifics Change-Id: If85a1c985d1ad7b017e290dab9526b822395f19a Reviewed-by: Thomas Hartmann --- .../QtQuick/Controls/BusyIndicatorSpecifics.qml | 2 ++ .../QtQuick/Controls/ButtonSpecifics.qml | 2 ++ .../QtQuick/Controls/CheckBoxSpecifics.qml | 2 ++ .../QtQuick/Controls/CheckDelegateSpecifics.qml | 2 ++ .../QtQuick/Controls/ComboBoxSpecifics.qml | 2 ++ .../QtQuick/Controls/DelayButtonSpecifics.qml | 2 ++ .../QtQuick/Controls/DialSpecifics.qml | 2 ++ .../QtQuick/Controls/FrameSpecifics.qml | 2 ++ .../QtQuick/Controls/GroupBoxSpecifics.qml | 2 ++ .../QtQuick/Controls/InsetSection.qml | 4 ++-- .../QtQuick/Controls/ItemDelegateSpecifics.qml | 2 ++ .../QtQuick/Controls/PageIndicatorSpecifics.qml | 2 ++ .../QtQuick/Controls/PageSpecifics.qml | 2 ++ .../QtQuick/Controls/PaneSpecifics.qml | 2 ++ .../QtQuick/Controls/ProgressBarSpecifics.qml | 2 ++ .../QtQuick/Controls/RadioButtonSpecifics.qml | 2 ++ .../QtQuick/Controls/RadioDelegateSpecifics.qml | 2 ++ .../QtQuick/Controls/RangeSliderSpecifics.qml | 2 ++ .../QtQuick/Controls/RoundButtonSpecifics.qml | 2 ++ .../QtQuick/Controls/ScrollViewSpecifics.qml | 2 ++ .../QtQuick/Controls/SliderSpecifics.qml | 2 ++ .../QtQuick/Controls/SpinBoxSpecifics.qml | 2 ++ .../QtQuick/Controls/StackViewSpecifics.qml | 2 ++ .../QtQuick/Controls/SwipeDelegateSpecifics.qml | 2 ++ .../QtQuick/Controls/SwipeViewSpecifics.qml | 2 ++ .../QtQuick/Controls/SwitchDelegateSpecifics.qml | 2 ++ .../QtQuick/Controls/SwitchSpecifics.qml | 2 ++ .../QtQuick/Controls/TabBarSpecifics.qml | 2 ++ .../QtQuick/Controls/TabButtonSpecifics.qml | 2 ++ .../QtQuick/Controls/ToolBarSpecifics.qml | 2 ++ .../QtQuick/Controls/ToolButtonSpecifics.qml | 4 +++- .../QtQuick/Controls/ToolSeparatorSpecifics.qml | 2 ++ .../QtQuick/Controls/TumblerSpecifics.qml | 2 ++ 33 files changed, 67 insertions(+), 3 deletions(-) diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/BusyIndicatorSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/BusyIndicatorSpecifics.qml index 0a92222b578..6d025a77619 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/BusyIndicatorSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/BusyIndicatorSpecifics.qml @@ -70,4 +70,6 @@ Column { ControlSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ButtonSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ButtonSpecifics.qml index 6e57108f627..8f466925f56 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ButtonSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ButtonSpecifics.qml @@ -53,4 +53,6 @@ Column { FontSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/CheckBoxSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/CheckBoxSpecifics.qml index 80b27fabfdb..9c2245ea681 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/CheckBoxSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/CheckBoxSpecifics.qml @@ -52,4 +52,6 @@ Column { FontSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/CheckDelegateSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/CheckDelegateSpecifics.qml index 0f9e81c6969..59e525943a8 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/CheckDelegateSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/CheckDelegateSpecifics.qml @@ -54,4 +54,6 @@ Column { FontSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ComboBoxSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ComboBoxSpecifics.qml index debeeeaecf1..3e04a71fee6 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ComboBoxSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ComboBoxSpecifics.qml @@ -138,4 +138,6 @@ Column { FontSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/DelayButtonSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/DelayButtonSpecifics.qml index 995997af65a..67d6d347c6a 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/DelayButtonSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/DelayButtonSpecifics.qml @@ -81,4 +81,6 @@ Column { FontSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/DialSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/DialSpecifics.qml index e3fae4a024a..b1fc7b60319 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/DialSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/DialSpecifics.qml @@ -194,4 +194,6 @@ Column { ControlSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/FrameSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/FrameSpecifics.qml index 33b98e44814..201356811af 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/FrameSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/FrameSpecifics.qml @@ -50,6 +50,8 @@ Column { PaddingSection {} + InsetSection {} + FontSection { caption: qsTr("Font Inheritance") expanded: false diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/GroupBoxSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/GroupBoxSpecifics.qml index a8b5801fde1..5f811e08fda 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/GroupBoxSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/GroupBoxSpecifics.qml @@ -73,4 +73,6 @@ Column { FontSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/InsetSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/InsetSection.qml index 17e35771fef..b7d838e62b6 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/InsetSection.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/InsetSection.qml @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2022 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit. @@ -35,8 +35,8 @@ ****************************************************************************/ import QtQuick 2.15 -import HelperWidgets 2.0 import QtQuick.Layouts 1.15 +import HelperWidgets 2.0 import StudioTheme 1.0 as StudioTheme Section { diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ItemDelegateSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ItemDelegateSpecifics.qml index 88f8dbf86b7..7e31c138735 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ItemDelegateSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ItemDelegateSpecifics.qml @@ -51,4 +51,6 @@ Column { FontSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/PageIndicatorSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/PageIndicatorSpecifics.qml index cda496c3d11..f951120b994 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/PageIndicatorSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/PageIndicatorSpecifics.qml @@ -106,4 +106,6 @@ Column { ControlSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/PageSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/PageSpecifics.qml index e3cac6ca29b..4b0745617fb 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/PageSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/PageSpecifics.qml @@ -118,4 +118,6 @@ Column { FontSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/PaneSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/PaneSpecifics.qml index dde8aab73d1..e61b880e5fc 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/PaneSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/PaneSpecifics.qml @@ -48,6 +48,8 @@ Column { PaddingSection {} + InsetSection {} + FontSection { caption: qsTr("Font Inheritance") expanded: false diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ProgressBarSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ProgressBarSpecifics.qml index 205df61e8bf..4acec20e119 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ProgressBarSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ProgressBarSpecifics.qml @@ -129,4 +129,6 @@ Column { ControlSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RadioButtonSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RadioButtonSpecifics.qml index 8c54760a8a6..c7f756ee6b5 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RadioButtonSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RadioButtonSpecifics.qml @@ -49,4 +49,6 @@ Column { FontSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RadioDelegateSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RadioDelegateSpecifics.qml index 31e32eeed7a..fa414f5b91b 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RadioDelegateSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RadioDelegateSpecifics.qml @@ -53,4 +53,6 @@ Column { FontSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RangeSliderSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RangeSliderSpecifics.qml index 430a7b49987..c3737bf6ebe 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RangeSliderSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RangeSliderSpecifics.qml @@ -213,4 +213,6 @@ Column { ControlSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RoundButtonSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RoundButtonSpecifics.qml index b3d316321cc..e7603f6aaae 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RoundButtonSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RoundButtonSpecifics.qml @@ -103,4 +103,6 @@ Column { FontSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ScrollViewSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ScrollViewSpecifics.qml index a38ea1ce220..53f4effcc52 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ScrollViewSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ScrollViewSpecifics.qml @@ -98,6 +98,8 @@ Column { PaddingSection {} + InsetSection {} + FontSection { caption: qsTr("Font Inheritance") expanded: false diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SliderSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SliderSpecifics.qml index f3ff89f91ec..8b04f8c1a26 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SliderSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SliderSpecifics.qml @@ -197,4 +197,6 @@ Column { ControlSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SpinBoxSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SpinBoxSpecifics.qml index 01322a57ba2..83486e7f14b 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SpinBoxSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SpinBoxSpecifics.qml @@ -158,4 +158,6 @@ Column { FontSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/StackViewSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/StackViewSpecifics.qml index 3f8bb535cf5..7f70792e96f 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/StackViewSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/StackViewSpecifics.qml @@ -46,6 +46,8 @@ Column { PaddingSection {} + InsetSection {} + FontSection { caption: qsTr("Font Inheritance") expanded: false diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwipeDelegateSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwipeDelegateSpecifics.qml index ec3156bd556..7f585e52f66 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwipeDelegateSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwipeDelegateSpecifics.qml @@ -51,4 +51,6 @@ Column { FontSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwipeViewSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwipeViewSpecifics.qml index aab4f96a29e..f12353e6512 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwipeViewSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwipeViewSpecifics.qml @@ -89,6 +89,8 @@ Column { PaddingSection {} + InsetSection {} + FontSection { caption: qsTr("Font Inheritance") expanded: false diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwitchDelegateSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwitchDelegateSpecifics.qml index b5805ef74c9..3dbc5315a47 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwitchDelegateSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwitchDelegateSpecifics.qml @@ -49,4 +49,6 @@ Column { ControlSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwitchSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwitchSpecifics.qml index b8814131f0e..4ac438eed6f 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwitchSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwitchSpecifics.qml @@ -49,4 +49,6 @@ Column { FontSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TabBarSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TabBarSpecifics.qml index ad67f2b0b8c..e58a8abf71e 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TabBarSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TabBarSpecifics.qml @@ -122,4 +122,6 @@ Column { FontSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TabButtonSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TabButtonSpecifics.qml index 8c54760a8a6..c7f756ee6b5 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TabButtonSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TabButtonSpecifics.qml @@ -49,4 +49,6 @@ Column { FontSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ToolBarSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ToolBarSpecifics.qml index 445c3bc256b..3bd62e1acbf 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ToolBarSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ToolBarSpecifics.qml @@ -73,6 +73,8 @@ Column { PaddingSection {} + InsetSection {} + FontSection { caption: qsTr("Font Inheritance") expanded: false diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ToolButtonSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ToolButtonSpecifics.qml index 923f78e9c37..8a0deb1f197 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ToolButtonSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ToolButtonSpecifics.qml @@ -46,9 +46,11 @@ Column { AbstractButtonSection {} - ControlSection { } + ControlSection {} FontSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ToolSeparatorSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ToolSeparatorSpecifics.qml index 53345e711a5..34e74c87ae3 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ToolSeparatorSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ToolSeparatorSpecifics.qml @@ -70,4 +70,6 @@ Column { ControlSection {} PaddingSection {} + + InsetSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TumblerSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TumblerSpecifics.qml index 487cd148606..5769a040070 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TumblerSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TumblerSpecifics.qml @@ -106,4 +106,6 @@ Column { FontSection {} PaddingSection {} + + InsetSection {} } From d6f5644e709f6b856026f61324dc61d6e8a8dc79 Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Tue, 28 Jun 2022 15:21:10 +0200 Subject: [PATCH 64/96] QmlDesigner: Fix ControlLabel elide Change-Id: Ib5d838c2da8f964d825c8611c8fe0b13a95d88d9 Reviewed-by: Thomas Hartmann --- .../QtQuick/Controls/DelayButtonSpecifics.qml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/DelayButtonSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/DelayButtonSpecifics.qml index 67d6d347c6a..b8141ec9c5d 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/DelayButtonSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/DelayButtonSpecifics.qml @@ -67,7 +67,10 @@ Column { Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } - ControlLabel { text: "ms" } + ControlLabel { + text: "ms" + elide: Text.ElideNone + } ExpandingSpacer {} } From 4972b8fad6ca3bbece6e9d04356c4f8acd1d323a Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Tue, 28 Jun 2022 17:29:28 +0200 Subject: [PATCH 65/96] QmlDesigner: Add icon section to AbstractButton * Add icon section to all property editor specifics related to AbstractButton * Add icon as a banned property for MCU * Fix disable state in FilterComboBox * Add QQuickIcon as a special type in node meta info Change-Id: I77595337a049952ab030210d90bc1a11327cf79c Reviewed-by: Reviewed-by: Thomas Hartmann --- .../Controls/AbstractButtonSection.qml | 61 ++++++- .../QtQuick/Controls/ButtonSpecifics.qml | 2 + .../QtQuick/Controls/CheckBoxSpecifics.qml | 2 + .../Controls/CheckDelegateSpecifics.qml | 2 + .../QtQuick/Controls/DelayButtonSpecifics.qml | 2 + .../QtQuick/Controls/IconSection.qml | 156 ++++++++++++++++++ .../Controls/ItemDelegateSpecifics.qml | 2 + .../QtQuick/Controls/RadioButtonSpecifics.qml | 2 + .../Controls/RadioDelegateSpecifics.qml | 2 + .../QtQuick/Controls/RoundButtonSpecifics.qml | 2 + .../Controls/SwipeDelegateSpecifics.qml | 2 + .../Controls/SwitchDelegateSpecifics.qml | 2 + .../QtQuick/Controls/SwitchSpecifics.qml | 2 + .../QtQuick/Controls/TabButtonSpecifics.qml | 2 + .../QtQuick/Controls/ToolButtonSpecifics.qml | 2 + .../imports/StudioControls/FilterComboBox.qml | 4 +- share/qtcreator/qmldesigner/qt4mcu/qul-22.qml | 2 +- .../designercore/metainfo/nodemetainfo.cpp | 6 +- 18 files changed, 250 insertions(+), 5 deletions(-) create mode 100644 share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/IconSection.qml diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/AbstractButtonSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/AbstractButtonSection.qml index 54cf89cf255..208632d8c04 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/AbstractButtonSection.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/AbstractButtonSection.qml @@ -75,7 +75,7 @@ Section { + StudioTheme.Values.actionIndicatorWidth width: implicitWidth backendValue: backendValues.display - model: [ "IconOnly", "TextOnly", "TextBesideIcon" ] + model: [ "IconOnly", "TextOnly", "TextBesideIcon", "TextUnderIcon" ] scope: "AbstractButton" enabled: backendValue.isAvailable } @@ -140,6 +140,7 @@ Section { SecondColumnLayout { CheckBox { + id: autoRepeat text: backendValues.autoRepeat.valueToString implicitWidth: StudioTheme.Values.twoControlColumnWidth + StudioTheme.Values.actionIndicatorWidth @@ -148,5 +149,63 @@ Section { ExpandingSpacer {} } + + PropertyLabel { + text: qsTr("Repeat delay") + tooltip: qsTr("Initial delay of auto-repetition in milliseconds.") + enabled: autoRepeat.checked + } + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + width: implicitWidth + minimumValue: 0 + maximumValue: 9999999 + decimals: 0 + backendValue: backendValues.autoRepeatDelay + enabled: autoRepeat.checked + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + text: "ms" + elide: Text.ElideNone + enabled: autoRepeat.checked + } + + ExpandingSpacer {} + } + + PropertyLabel { + text: qsTr("Repeat interval") + tooltip: qsTr("Interval of auto-repetition in milliseconds.") + enabled: autoRepeat.checked + } + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + width: implicitWidth + minimumValue: 0 + maximumValue: 9999999 + decimals: 0 + backendValue: backendValues.autoRepeatInterval + enabled: autoRepeat.checked + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + text: "ms" + elide: Text.ElideNone + enabled: autoRepeat.checked + } + + ExpandingSpacer {} + } } } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ButtonSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ButtonSpecifics.qml index 8f466925f56..8f155958453 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ButtonSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ButtonSpecifics.qml @@ -48,6 +48,8 @@ Column { AbstractButtonSection {} + IconSection {} + ControlSection {} FontSection {} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/CheckBoxSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/CheckBoxSpecifics.qml index 9c2245ea681..3280065a3e2 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/CheckBoxSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/CheckBoxSpecifics.qml @@ -47,6 +47,8 @@ Column { AbstractButtonSection {} + IconSection {} + ControlSection {} FontSection {} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/CheckDelegateSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/CheckDelegateSpecifics.qml index 59e525943a8..3b79e7bc811 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/CheckDelegateSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/CheckDelegateSpecifics.qml @@ -49,6 +49,8 @@ Column { AbstractButtonSection {} + IconSection {} + ControlSection {} FontSection {} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/DelayButtonSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/DelayButtonSpecifics.qml index b8141ec9c5d..8e3fda088fa 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/DelayButtonSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/DelayButtonSpecifics.qml @@ -79,6 +79,8 @@ Column { AbstractButtonSection {} + IconSection {} + ControlSection {} FontSection {} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/IconSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/IconSection.qml new file mode 100644 index 00000000000..a487223608b --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/IconSection.qml @@ -0,0 +1,156 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.15 +import QtQuick.Layouts 1.15 +import HelperWidgets 2.0 +import StudioTheme 1.0 as StudioTheme + +Section { + id: root + + property bool blockedByContext: backendValues.display.enumeration === "TextOnly" + + caption: qsTr("Icon") + width: parent.width + + SectionLayout { + // We deliberately kept the "name" property out as it is only properly supported by linux + // based operating systems out of the box. + + PropertyLabel { + text: qsTr("Source") + blockedByTemplate: !backendValues.icon_source.isAvailable + enabled: !root.blockedByContext + } + + SecondColumnLayout { + UrlChooser { + backendValue: backendValues.icon_source + enabled: backendValues.icon_source.isAvailable && !root.blockedByContext + } + + ExpandingSpacer {} + } + + PropertyLabel { + text: qsTr("Color") + blockedByTemplate: !backendValues.icon_color.isAvailable + enabled: !root.blockedByContext + } + + ColorEditor { + backendValue: backendValues.icon_color + supportGradient: false + enabled: backendValues.icon_color.isAvailable && !root.blockedByContext + } + + PropertyLabel { + text: qsTr("Size") + blockedByTemplate: !backendValues.icon_width.isAvailable + enabled: !root.blockedByContext + } + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + backendValue: backendValues.icon_width + maximumValue: 0xffff + minimumValue: 0 + decimals: 0 + enabled: backendValues.icon_width.isAvailable && !root.blockedByContext + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + //: The width of the object + text: qsTr("W", "width") + tooltip: qsTr("Width") + enabled: backendValues.icon_width.isAvailable && !root.blockedByContext + } + + Spacer { implicitWidth: StudioTheme.Values.controlGap } + + SpinBox { + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + backendValue: backendValues.icon_height + maximumValue: 0xffff + minimumValue: 0 + decimals: 0 + enabled: backendValues.icon_height.isAvailable && !root.blockedByContext + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + //: The height of the object + text: qsTr("H", "height") + tooltip: qsTr("Height") + enabled: backendValues.icon_height.isAvailable && !root.blockedByContext + } +/* + TODO QDS-4836 + Spacer { implicitWidth: StudioTheme.Values.controlGap } + + LinkIndicator2D {} +*/ + ExpandingSpacer {} + } + + PropertyLabel { + text: qsTr("Cache") + tooltip: qsTr("Whether the icon should be cached.") + blockedByTemplate: !backendValues.icon_cache.isAvailable + enabled: !root.blockedByContext + } + + SecondColumnLayout { + CheckBox { + text: backendValues.icon_cache.valueToString + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + backendValue: backendValues.icon_cache + enabled: backendValues.icon_cache.isAvailable && !root.blockedByContext + } + + ExpandingSpacer {} + } + + } +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ItemDelegateSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ItemDelegateSpecifics.qml index 7e31c138735..a3ab1a1a8aa 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ItemDelegateSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ItemDelegateSpecifics.qml @@ -46,6 +46,8 @@ Column { AbstractButtonSection {} + IconSection {} + ControlSection {} FontSection {} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RadioButtonSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RadioButtonSpecifics.qml index c7f756ee6b5..7573c4a8496 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RadioButtonSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RadioButtonSpecifics.qml @@ -44,6 +44,8 @@ Column { AbstractButtonSection {} + IconSection {} + ControlSection {} FontSection {} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RadioDelegateSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RadioDelegateSpecifics.qml index fa414f5b91b..341f6d73694 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RadioDelegateSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RadioDelegateSpecifics.qml @@ -48,6 +48,8 @@ Column { AbstractButtonSection {} + IconSection {} + ControlSection {} FontSection {} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RoundButtonSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RoundButtonSpecifics.qml index e7603f6aaae..e2b38a3b04d 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RoundButtonSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RoundButtonSpecifics.qml @@ -98,6 +98,8 @@ Column { AbstractButtonSection {} + IconSection {} + ControlSection {} FontSection {} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwipeDelegateSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwipeDelegateSpecifics.qml index 7f585e52f66..e888c6500bd 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwipeDelegateSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwipeDelegateSpecifics.qml @@ -46,6 +46,8 @@ Column { AbstractButtonSection {} + IconSection {} + ControlSection {} FontSection {} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwitchDelegateSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwitchDelegateSpecifics.qml index 3dbc5315a47..8f5b4d00008 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwitchDelegateSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwitchDelegateSpecifics.qml @@ -46,6 +46,8 @@ Column { AbstractButtonSection {} + IconSection {} + ControlSection {} PaddingSection {} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwitchSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwitchSpecifics.qml index 4ac438eed6f..77487cf28bc 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwitchSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwitchSpecifics.qml @@ -44,6 +44,8 @@ Column { AbstractButtonSection {} + IconSection {} + ControlSection {} FontSection {} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TabButtonSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TabButtonSpecifics.qml index c7f756ee6b5..7573c4a8496 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TabButtonSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TabButtonSpecifics.qml @@ -44,6 +44,8 @@ Column { AbstractButtonSection {} + IconSection {} + ControlSection {} FontSection {} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ToolButtonSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ToolButtonSpecifics.qml index 8a0deb1f197..7e9e2ada89a 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ToolButtonSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ToolButtonSpecifics.qml @@ -46,6 +46,8 @@ Column { AbstractButtonSection {} + IconSection {} + ControlSection {} FontSection {} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/FilterComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/FilterComboBox.qml index 30142652ab3..008713a4e1c 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/FilterComboBox.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/FilterComboBox.qml @@ -65,7 +65,8 @@ Item { property alias actionIndicator: actionIndicator // This property is used to indicate the global hover state - property bool hover: actionIndicator.hover || textInput.hover || checkIndicator.hover + property bool hover: (actionIndicator.hover || textInput.hover || checkIndicator.hover) + && root.enabled property alias edit: textInput.edit property alias open: popup.visible @@ -514,6 +515,7 @@ Item { PropertyChanges { target: textInputBackground color: StudioTheme.Values.themeControlBackgroundDisabled + border.color: StudioTheme.Values.themeControlOutlineDisabled } PropertyChanges { target: textInput diff --git a/share/qtcreator/qmldesigner/qt4mcu/qul-22.qml b/share/qtcreator/qmldesigner/qt4mcu/qul-22.qml index a539a0aeb25..93682263778 100644 --- a/share/qtcreator/qmldesigner/qt4mcu/qul-22.qml +++ b/share/qtcreator/qmldesigner/qt4mcu/qul-22.qml @@ -165,7 +165,7 @@ VersionData { } QtQuick.Controls.AbstractButton { - bannedProperties: ["display", "autoExclusive"] + bannedProperties: ["display", "autoExclusive", "icon"] } QtQuick.Controls.ProgressBar { diff --git a/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp b/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp index a980dc458f4..634c9aa64b6 100644 --- a/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp +++ b/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp @@ -363,7 +363,8 @@ static inline bool isValueType(const TypeName &type) "vector2d", "vector3d", "vector4d", - "font"}); + "font", + "QQuickIcon"}); return objectValuesList.contains(type); } @@ -380,7 +381,8 @@ static inline bool isValueType(const QString &type) "vector2d", "vector3d", "vector4d", - "font"}); + "font", + "QQuickIcon"}); return objectValuesList.contains(type); } From 4c5b67ff4a3b25a6d0999d4cc4abadcc3e1fc9f2 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Thu, 30 Jun 2022 11:05:25 +0200 Subject: [PATCH 66/96] QmlProject: Use correct family name for Titillium Web MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I50b0aa0741520117bf79700eecd7167c57673166 Reviewed-by: Henning Gründl --- .../qmldesigner/landingpage/imports/LandingPage/Values.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/qtcreator/qmldesigner/landingpage/imports/LandingPage/Values.qml b/share/qtcreator/qmldesigner/landingpage/imports/LandingPage/Values.qml index 89f71e78d37..de4ea147c07 100644 --- a/share/qtcreator/qmldesigner/landingpage/imports/LandingPage/Values.qml +++ b/share/qtcreator/qmldesigner/landingpage/imports/LandingPage/Values.qml @@ -29,7 +29,7 @@ import QtQuick 2.15 QtObject { id: values - property string baseFont: "TitilliumWeb" + property string baseFont: "Titillium Web" property real scaleFactor: 1.0 property real checkBoxSize: Math.round(26 * values.scaleFactor) From 7899fd6fc4eeb8e06a805e6fc2faca18ca05e028 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 30 Jun 2022 10:13:16 +0200 Subject: [PATCH 67/96] Core: fix opening multiple broken Files Fixes: QTCREATORBUG-27777 Change-Id: Ia606fe3b8a72ff32478002e3b3f672a4821fe115 Reviewed-by: Eike Ziller --- src/plugins/coreplugin/editormanager/editorview.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/plugins/coreplugin/editormanager/editorview.cpp b/src/plugins/coreplugin/editormanager/editorview.cpp index fcfef3d1f57..a8ee45501dc 100644 --- a/src/plugins/coreplugin/editormanager/editorview.cpp +++ b/src/plugins/coreplugin/editormanager/editorview.cpp @@ -407,8 +407,7 @@ void EditorView::openDroppedFiles(const QList &files) }; auto openEntry = [&](const DropSupport::FileSpec &spec) { if (first) { - first = false; - EditorManagerPrivate::openEditorAt(this, specToLink(spec)); + first = !EditorManagerPrivate::openEditorAt(this, specToLink(spec)); } else if (spec.column != -1 || spec.line != -1) { EditorManagerPrivate::openEditorAt(this, specToLink(spec), From 2f18256633fd7709b92deef7cfdd1a8c60f26a62 Mon Sep 17 00:00:00 2001 From: Artem Sokolovskii Date: Tue, 28 Jun 2022 16:17:02 +0200 Subject: [PATCH 68/96] Clangformat: Brings back some of checkboxes Brought back checkboxes: format while typing, format on save. Brought back format while typing feature. Global checkboxes will be hidden in project settings, and visible for global. Change-Id: I193cf9e13b10de22091edb5fe04aef957dd74586 Reviewed-by: Christian Kandeler Reviewed-by: Eike Ziller --- .../clangformat/clangformatbaseindenter.cpp | 2 +- .../clangformat/clangformatbaseindenter.h | 1 + .../clangformat/clangformatconfigwidget.cpp | 46 ++++++++++++++++++- .../clangformat/clangformatconfigwidget.h | 1 + .../clangformat/clangformatconfigwidget.ui | 18 +++++++- .../clangformat/clangformatconstants.h | 2 + .../clangformat/clangformatindenter.cpp | 8 +++- src/plugins/clangformat/clangformatindenter.h | 1 + .../clangformat/clangformatsettings.cpp | 34 +++++++++++--- src/plugins/clangformat/clangformatsettings.h | 10 +++- .../clangformat/tests/clangformat-test.cpp | 1 + 11 files changed, 111 insertions(+), 13 deletions(-) diff --git a/src/plugins/clangformat/clangformatbaseindenter.cpp b/src/plugins/clangformat/clangformatbaseindenter.cpp index b9ee78b50ef..22b55170a6f 100644 --- a/src/plugins/clangformat/clangformatbaseindenter.cpp +++ b/src/plugins/clangformat/clangformatbaseindenter.cpp @@ -594,7 +594,7 @@ Utils::Text::Replacements ClangFormatBaseIndenter::indentsFor(QTextBlock startBl const QByteArray buffer = m_doc->toPlainText().toUtf8(); ReplacementsToKeep replacementsToKeep = ReplacementsToKeep::OnlyIndent; - if (formatCodeInsteadOfIndent() + if (formatWhileTyping() && (cursorPositionInEditor == -1 || cursorPositionInEditor >= startBlockPosition) && (typedChar == ';' || typedChar == '}')) { // Format before current position only in case the cursor is inside the indented block. diff --git a/src/plugins/clangformat/clangformatbaseindenter.h b/src/plugins/clangformat/clangformatbaseindenter.h index bcfd4ca4a47..0b96451aca0 100644 --- a/src/plugins/clangformat/clangformatbaseindenter.h +++ b/src/plugins/clangformat/clangformatbaseindenter.h @@ -72,6 +72,7 @@ public: protected: virtual bool formatCodeInsteadOfIndent() const { return false; } + virtual bool formatWhileTyping() const { return false; } virtual int lastSaveRevision() const { return 0; } private: diff --git a/src/plugins/clangformat/clangformatconfigwidget.cpp b/src/plugins/clangformat/clangformatconfigwidget.cpp index ddf0415ef49..e3e7629065b 100644 --- a/src/plugins/clangformat/clangformatconfigwidget.cpp +++ b/src/plugins/clangformat/clangformatconfigwidget.cpp @@ -85,6 +85,7 @@ ClangFormatConfigWidget::ClangFormatConfigWidget(TextEditor::ICodeStylePreferenc initChecksAndPreview(!codeStyle->isReadOnly()); initOverrideCheckBox(); + initCheckBoxes(); initIndentationOrFormattingCombobox(); showOrHideWidgets(); @@ -128,6 +129,45 @@ void ClangFormatConfigWidget::initChecksAndPreview(bool enabled) m_preview->textDocument()->indenter()->setFileName(fileName); } +void ClangFormatConfigWidget::initCheckBoxes() +{ + if (m_project) { + m_ui->formatOnSave->hide(); + m_ui->formatWhileTyping->hide(); + return; + } + + m_ui->formatOnSave->show(); + m_ui->formatWhileTyping->show(); + + auto setEnableCheckBoxes = [this](int index) { + bool isFormatting = index == static_cast(ClangFormatSettings::Mode::Formatting); + + m_ui->formatOnSave->setEnabled(isFormatting); + m_ui->formatWhileTyping->setEnabled(isFormatting); + }; + setEnableCheckBoxes(m_ui->indentingOrFormatting->currentIndex()); + connect(m_ui->indentingOrFormatting, QOverload::of(&QComboBox::currentIndexChanged), + this, setEnableCheckBoxes); + + m_ui->formatOnSave->setChecked(ClangFormatSettings::instance().formatOnSave()); + m_ui->formatWhileTyping->setChecked(ClangFormatSettings::instance().formatWhileTyping()); + + connect(m_ui->formatOnSave, &QCheckBox::toggled, + this, [](bool checked) { + ClangFormatSettings &settings = ClangFormatSettings::instance(); + settings.setFormatOnSave(checked); + settings.write(); + }); + + connect(m_ui->formatWhileTyping, &QCheckBox::toggled, + this, [](bool checked) { + ClangFormatSettings &settings = ClangFormatSettings::instance(); + settings.setFormatWhileTyping(checked); + settings.write(); + }); +} + void ClangFormatConfigWidget::initOverrideCheckBox() { if (m_project) { @@ -190,7 +230,9 @@ void ClangFormatConfigWidget::initIndentationOrFormattingCombobox() m_ui->indentingOrFormatting->setCurrentIndex( static_cast(ClangFormatSettings::instance().mode())); - m_ui->indentingOrFormatting->show(); + const bool isGlobal = !m_project; + m_ui->indentingOrFormatting->setVisible(isGlobal); + m_ui->formattingModeLabel->setVisible(isGlobal); connect(m_ui->indentingOrFormatting, QOverload::of(&QComboBox::currentIndexChanged), this, [](int index) { @@ -219,6 +261,7 @@ void ClangFormatConfigWidget::showOrHideWidgets() if (!m_ui->overrideDefault->isChecked() && m_project) { // Show the fallback configuration only globally. + m_ui->fallbackConfig->hide(); m_checksScrollArea->hide(); m_preview->hide(); m_ui->verticalLayout->addStretch(1); @@ -226,6 +269,7 @@ void ClangFormatConfigWidget::showOrHideWidgets() } createStyleFileIfNeeded(!m_project); + m_ui->fallbackConfig->show(); m_checksScrollArea->show(); m_preview->show(); diff --git a/src/plugins/clangformat/clangformatconfigwidget.h b/src/plugins/clangformat/clangformatconfigwidget.h index 52a5a94bc18..3b6f2aa1634 100644 --- a/src/plugins/clangformat/clangformatconfigwidget.h +++ b/src/plugins/clangformat/clangformatconfigwidget.h @@ -65,6 +65,7 @@ private: void showOrHideWidgets(); void initChecksAndPreview(bool enabled); void initOverrideCheckBox(); + void initCheckBoxes(); void connectChecks(); void fillTable(); diff --git a/src/plugins/clangformat/clangformatconfigwidget.ui b/src/plugins/clangformat/clangformatconfigwidget.ui index 814f558ca8a..a0a042c273e 100644 --- a/src/plugins/clangformat/clangformatconfigwidget.ui +++ b/src/plugins/clangformat/clangformatconfigwidget.ui @@ -27,7 +27,7 @@ 8 - + @@ -39,7 +39,7 @@ - + Qt::Horizontal @@ -53,6 +53,20 @@ + + + + Format while typing + + + + + + + Format edited code on file save + + + diff --git a/src/plugins/clangformat/clangformatconstants.h b/src/plugins/clangformat/clangformatconstants.h index 74e84efa170..cb201665da9 100644 --- a/src/plugins/clangformat/clangformatconstants.h +++ b/src/plugins/clangformat/clangformatconstants.h @@ -32,6 +32,8 @@ static const char SETTINGS_FILE_ALT_NAME[] = "_clang-format"; static const char SAMPLE_FILE_NAME[] = "test.cpp"; static const char SETTINGS_ID[] = "ClangFormat"; static const char OVERRIDE_FILE_ID[] = "ClangFormat.OverrideFile"; +static const char FORMAT_CODE_ON_SAVE_ID[] = "ClangFormat.FormatCodeOnSave"; +static const char FORMAT_WHILE_TYPING_ID[] = "ClangFormat.FormatWhileTyping"; static const char MODE_ID[] = "ClangFormat.Mode"; static const char OPEN_CURRENT_CONFIG_ID[] = "ClangFormat.OpenCurrentConfig"; } // namespace Constants diff --git a/src/plugins/clangformat/clangformatindenter.cpp b/src/plugins/clangformat/clangformatindenter.cpp index 6f7bb32ca8e..4d7273024ec 100644 --- a/src/plugins/clangformat/clangformatindenter.cpp +++ b/src/plugins/clangformat/clangformatindenter.cpp @@ -114,7 +114,13 @@ int ClangFormatIndenter::lastSaveRevision() const bool ClangFormatIndenter::formatOnSave() const { - return !isBeautifierOnSaveActivated() && formatCodeInsteadOfIndent(); + return ClangFormatSettings::instance().formatOnSave() && !isBeautifierOnSaveActivated() + && formatCodeInsteadOfIndent(); +} + +bool ClangFormatIndenter::formatWhileTyping() const +{ + return ClangFormatSettings::instance().formatWhileTyping() && formatCodeInsteadOfIndent(); } } // namespace ClangFormat diff --git a/src/plugins/clangformat/clangformatindenter.h b/src/plugins/clangformat/clangformatindenter.h index 83f0b912f68..9e1a65fb3d4 100644 --- a/src/plugins/clangformat/clangformatindenter.h +++ b/src/plugins/clangformat/clangformatindenter.h @@ -40,6 +40,7 @@ public: private: bool formatCodeInsteadOfIndent() const override; + bool formatWhileTyping() const override; int lastSaveRevision() const override; }; diff --git a/src/plugins/clangformat/clangformatsettings.cpp b/src/plugins/clangformat/clangformatsettings.cpp index 2326f7b8ce1..7ab17c00418 100644 --- a/src/plugins/clangformat/clangformatsettings.cpp +++ b/src/plugins/clangformat/clangformatsettings.cpp @@ -30,8 +30,6 @@ namespace ClangFormat { static const char FORMAT_CODE_INSTEAD_OF_INDENT_ID[] = "ClangFormat.FormatCodeInsteadOfIndent"; -static const char FORMAT_CODE_ON_SAVE_ID[] = "ClangFormat.FormatCodeOnSave"; -static const char FORMAT_WHILE_TYPING_ID[] = "ClangFormat.FormatWhileTyping"; ClangFormatSettings &ClangFormatSettings::instance() { @@ -45,15 +43,15 @@ ClangFormatSettings::ClangFormatSettings() settings->beginGroup(QLatin1String(Constants::SETTINGS_ID)); m_overrideDefaultFile = settings->value(QLatin1String(Constants::OVERRIDE_FILE_ID), false) .toBool(); + m_formatWhileTyping = settings->value(QLatin1String(Constants::FORMAT_WHILE_TYPING_ID), false) + .toBool(); + m_formatOnSave = settings->value(QLatin1String(Constants::FORMAT_CODE_ON_SAVE_ID), false) + .toBool(); // Convert old settings to new ones. New settings were added to QtC 8.0 bool isOldFormattingOn - = settings->value(QLatin1String(FORMAT_CODE_INSTEAD_OF_INDENT_ID), false).toBool() - || settings->value(QLatin1String(FORMAT_CODE_ON_SAVE_ID), false).toBool(); - + = settings->value(QLatin1String(FORMAT_CODE_INSTEAD_OF_INDENT_ID), false).toBool(); Core::ICore::settings()->remove(QLatin1String(FORMAT_CODE_INSTEAD_OF_INDENT_ID)); - Core::ICore::settings()->remove(QLatin1String(FORMAT_CODE_ON_SAVE_ID)); - Core::ICore::settings()->remove(QLatin1String(FORMAT_WHILE_TYPING_ID)); if (isOldFormattingOn) { settings->setValue(QLatin1String(Constants::MODE_ID), @@ -72,6 +70,8 @@ void ClangFormatSettings::write() const QSettings *settings = Core::ICore::settings(); settings->beginGroup(QLatin1String(Constants::SETTINGS_ID)); settings->setValue(QLatin1String(Constants::OVERRIDE_FILE_ID), m_overrideDefaultFile); + settings->setValue(QLatin1String(Constants::FORMAT_WHILE_TYPING_ID), m_formatWhileTyping); + settings->setValue(QLatin1String(Constants::FORMAT_CODE_ON_SAVE_ID), m_formatOnSave); settings->setValue(QLatin1String(Constants::MODE_ID), static_cast(m_mode)); settings->endGroup(); } @@ -86,6 +86,26 @@ bool ClangFormatSettings::overrideDefaultFile() const return m_overrideDefaultFile; } +void ClangFormatSettings::setFormatWhileTyping(bool enable) +{ + m_formatWhileTyping = enable; +} + +bool ClangFormatSettings::formatWhileTyping() const +{ + return m_formatWhileTyping; +} + +void ClangFormatSettings::setFormatOnSave(bool enable) +{ + m_formatOnSave = enable; +} + +bool ClangFormatSettings::formatOnSave() const +{ + return m_formatOnSave; +} + void ClangFormatSettings::setMode(Mode mode) { m_mode = mode; diff --git a/src/plugins/clangformat/clangformatsettings.h b/src/plugins/clangformat/clangformatsettings.h index 88b37d393e2..685dc042e8c 100644 --- a/src/plugins/clangformat/clangformatsettings.h +++ b/src/plugins/clangformat/clangformatsettings.h @@ -49,9 +49,17 @@ public: void setMode(Mode mode); Mode mode() const; + void setFormatWhileTyping(bool enable); + bool formatWhileTyping() const; + + void setFormatOnSave(bool enable); + bool formatOnSave() const; + private: - bool m_overrideDefaultFile = false; Mode m_mode; + bool m_overrideDefaultFile = false; + bool m_formatWhileTyping = false; + bool m_formatOnSave = false; }; } // namespace ClangFormat diff --git a/src/plugins/clangformat/tests/clangformat-test.cpp b/src/plugins/clangformat/tests/clangformat-test.cpp index 174a3d11705..0493eeca97a 100644 --- a/src/plugins/clangformat/tests/clangformat-test.cpp +++ b/src/plugins/clangformat/tests/clangformat-test.cpp @@ -53,6 +53,7 @@ public: private: bool formatCodeInsteadOfIndent() const override { return true; } + bool formatWhileTyping() const override { return true; } }; ClangFormatTest::ClangFormatTest() From 2d82f2173d63958af06594b31b0f99299a625805 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 17 May 2022 10:07:27 +0200 Subject: [PATCH 69/96] Ssh: Use DeviceShell in LinuxDevice Change-Id: I165f888dbb1e7072c35ec88ce5fd8a7ae4562139 Reviewed-by: Jarek Kobus --- src/libs/utils/deviceshell.h | 3 +- src/plugins/docker/dockerdevice.cpp | 5 +- src/plugins/remotelinux/linuxdevice.cpp | 129 ++++++------------------ 3 files changed, 36 insertions(+), 101 deletions(-) diff --git a/src/libs/utils/deviceshell.h b/src/libs/utils/deviceshell.h index d25746ddf12..5f285103c86 100644 --- a/src/libs/utils/deviceshell.h +++ b/src/libs/utils/deviceshell.h @@ -64,6 +64,8 @@ public: DeviceShell(); virtual ~DeviceShell(); + bool start(); + bool runInShell(const CommandLine &cmd, const QByteArray &stdInData = {}); RunResult outputForRunInShell(const CommandLine &cmd, const QByteArray &stdInData = {}); @@ -76,7 +78,6 @@ protected: virtual void startupFailed(const CommandLine &cmdLine); RunResult run(const CommandLine &cmd, const QByteArray &stdInData = {}); - bool start(); void close(); private: diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index 04f1a1ab043..2b7b671ef09 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -109,7 +109,6 @@ public: ContainerShell(const QString &containerId) : m_containerId(containerId) { - start(); } private: @@ -464,9 +463,7 @@ void DockerDevicePrivate::startContainer() "or restart Qt Creator.")); }); - if (m_shell->state() != DeviceShell::State::Succeeded) { - m_shell.reset(); - DockerApi::recheckDockerDaemon(); + if (!m_shell->start()) { qCWarning(dockerDeviceLog) << "Container shell failed to start"; } } diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index 69910f01315..0ec48a41fe9 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -46,6 +46,7 @@ #include #include +#include #include #include #include @@ -380,7 +381,6 @@ public: bool setupShell(); bool runInShell(const CommandLine &cmd, const QByteArray &data = {}); - QByteArray outputForRunInShell(const QString &cmd); QByteArray outputForRunInShell(const CommandLine &cmd); void attachToSharedConnection(SshConnectionHandle *connectionHandle, const SshParameters &sshParameters); @@ -734,7 +734,7 @@ void SshProcessInterfacePrivate::doStart() CommandLine SshProcessInterfacePrivate::fullLocalCommandLine() const { - Utils::CommandLine cmd{SshSettings::sshFilePath()}; + CommandLine cmd{SshSettings::sshFilePath()}; if (!m_sshParameters.x11DisplayName.isEmpty()) cmd.addArg("-X"); @@ -769,6 +769,25 @@ static SshParameters displayless(const SshParameters &sshParameters) class ShellThreadHandler : public QObject { + class LinuxDeviceShell : public DeviceShell + { + public: + LinuxDeviceShell(const CommandLine &cmdLine) + : m_cmdLine(cmdLine) + { + } + + private: + void setupShellProcess(QtcProcess *shellProcess) override + { + SshParameters::setupSshEnvironment(shellProcess); + shellProcess->setCommand(m_cmdLine); + } + + private: + const CommandLine m_cmdLine; + }; + public: ~ShellThreadHandler() { @@ -778,10 +797,6 @@ public: void closeShell() { - if (m_shell && m_shell->isRunning()) { - m_shell->write("exit\n"); - m_shell->waitForFinished(-1); - } m_shell.reset(); } @@ -790,9 +805,6 @@ public: { closeShell(); setSshParameters(parameters); - m_shell.reset(new QtcProcess); - - SshParameters::setupSshEnvironment(m_shell.get()); const FilePath sshPath = SshSettings::sshFilePath(); CommandLine cmd { sshPath }; @@ -801,93 +813,23 @@ public: << m_displaylessSshParameters.host()); cmd.addArg("/bin/sh"); - m_shell->setCommand(cmd); - m_shell->setProcessMode(ProcessMode::Writer); - m_shell->setWriteData("echo\n"); - m_shell->start(); - - auto failed = [this] { - closeShell(); - qCDebug(linuxDeviceLog) << "Failed to connect to" << m_displaylessSshParameters.host(); - return false; - }; - - QDeadlineTimer timer(30000); - if (!m_shell->waitForStarted(timer.remainingTime())) - return failed(); - - while (true) { - if (!m_shell->waitForReadyRead(timer.remainingTime())) - return failed(); - - const QByteArray output = m_shell->readAllStandardOutput(); - if (output == "\n") - break; // expected output from echo - if (output.size() > 0) - return failed(); // other unidentified output - - // In case of trying to run a shell using SSH_ASKPASS, it may happen - // that we receive ready read signal but for error channel, while output - // channel still is empty. In this case we wait in loop until the user - // provides the right password, otherwise we timeout after 30 seconds. - } - return true; + m_shell.reset(new LinuxDeviceShell(cmd)); + connect(m_shell.get(), &DeviceShell::done, this, [this] { m_shell.reset(); }); + return m_shell->start(); } // Call me with shell mutex locked bool runInShell(const CommandLine &cmd, const QByteArray &data = {}) { QTC_ASSERT(m_shell, return false); - QTC_CHECK(m_shell->readAllStandardOutput().isNull()); // clean possible left-overs - QTC_CHECK(m_shell->readAllStandardError().isNull()); // clean possible left-overs - - QString prefix; - if (!data.isEmpty()) - prefix = "echo '" + QString::fromUtf8(data.toBase64()) + "' | base64 -d | "; - const QString suffix = " > /dev/null 2>&1\necho $?\n"; - const QString command = prefix + cmd.toUserOutput() + suffix; - - m_shell->write(command); - DEBUG("RUN1 " << cmd.toUserOutput()); - m_shell->waitForReadyRead(); - const QByteArray output = m_shell->readAllStandardOutput(); - DEBUG("GOT1 " << output); - bool ok = false; - const int result = output.toInt(&ok); - LOG("Run command in shell:" << cmd.toUserOutput() << "result: " << output << " ==>" << result); - QTC_ASSERT(ok, return false); - return !result; + return m_shell->runInShell(cmd, data); } // Call me with shell mutex locked - QByteArray outputForRunInShell(const QString &cmd) + QByteArray outputForRunInShell(const CommandLine &cmd) { QTC_ASSERT(m_shell, return {}); - QTC_CHECK(m_shell->readAllStandardOutput().isNull()); // clean possible left-overs - QTC_CHECK(m_shell->readAllStandardError().isNull()); // clean possible left-overs - auto cleanup = qScopeGuard([this] { m_shell->readAllStandardOutput(); }); // clean on assert - - const QString suffix = " 2> /dev/null \necho $? 1>&2\n"; - const QString command = cmd + suffix; - - m_shell->write(command); - DEBUG("RUN2 " << cmd.toUserOutput()); - - while (true) { - m_shell->waitForReadyRead(); - const QByteArray error = m_shell->readAllStandardError(); - if (!error.isNull()) { - bool ok = false; - const int result = error.toInt(&ok); - QTC_ASSERT(ok, return {}); - QTC_ASSERT(!result, return {}); - break; - } - } - const QByteArray output = m_shell->readAllStandardOutput(); - DEBUG("GOT2 " << output); - LOG("Run command in shell:" << cmd << "output size:" << output.size()); - return output; + return m_shell->outputForRunInShell(cmd).stdOut; } void setSshParameters(const SshParameters &sshParameters) @@ -970,7 +912,7 @@ private: mutable QMutex m_mutex; SshParameters m_displaylessSshParameters; QList m_connections; - std::unique_ptr m_shell; + std::unique_ptr m_shell; }; // LinuxDevice @@ -1089,7 +1031,7 @@ public: private: void start() override { m_reader.start(); } void readerFinished() { emit finished(m_reader.remoteEnvironment(), true); } - void readerError() { emit finished(Utils::Environment(), false); } + void readerError() { emit finished(Environment(), false); } Internal::RemoteLinuxEnvironmentReader m_reader; }; @@ -1172,7 +1114,7 @@ bool LinuxDevicePrivate::runInShell(const CommandLine &cmd, const QByteArray &da return ret; } -QByteArray LinuxDevicePrivate::outputForRunInShell(const QString &cmd) +QByteArray LinuxDevicePrivate::outputForRunInShell(const CommandLine &cmd) { QMutexLocker locker(&m_shellMutex); DEBUG(cmd); @@ -1185,11 +1127,6 @@ QByteArray LinuxDevicePrivate::outputForRunInShell(const QString &cmd) return ret; } -QByteArray LinuxDevicePrivate::outputForRunInShell(const CommandLine &cmd) -{ - return outputForRunInShell(cmd.toUserOutput()); -} - void LinuxDevicePrivate::attachToSharedConnection(SshConnectionHandle *connectionHandle, const SshParameters &sshParameters) { @@ -1337,7 +1274,7 @@ qint64 LinuxDevice::bytesAvailable(const FilePath &filePath) const CommandLine cmd("df", {"-k"}); cmd.addArg(filePath.path()); cmd.addArgs("|tail -n 1 |sed 's/ */ /g'|cut -d ' ' -f 4", CommandLine::Raw); - const QByteArray output = d->outputForRunInShell(cmd.toUserOutput()); + const QByteArray output = d->outputForRunInShell(cmd); bool ok = false; const qint64 size = output.toLongLong(&ok); if (ok) @@ -1365,7 +1302,7 @@ QFileDevice::Permissions LinuxDevice::permissions(const FilePath &filePath) cons return perm; } -bool LinuxDevice::setPermissions(const Utils::FilePath &filePath, QFileDevice::Permissions permissions) const +bool LinuxDevice::setPermissions(const FilePath &filePath, QFileDevice::Permissions permissions) const { QTC_ASSERT(handlesFile(filePath), return false); const int flags = int(permissions); @@ -1394,7 +1331,7 @@ QByteArray LinuxDevice::fileContents(const FilePath &filePath, qint64 limit, qin CommandLine cmd(FilePath::fromString("dd"), args, CommandLine::Raw); const QByteArray output = d->outputForRunInShell(cmd); - DEBUG(output << output << QByteArray::fromHex(output)); + DEBUG(output << QByteArray::fromHex(output)); return output; } From 3cda0116084033380bf88f95569d599a5335fe52 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Tue, 28 Jun 2022 15:04:05 +0300 Subject: [PATCH 70/96] QmlDesigner: Only notify possible and used import changes when needed Fixes: QDS-7193 Change-Id: I5d24392c0550c9c5506ee64af329883a52554fe3 Reviewed-by: Thomas Hartmann --- src/plugins/qmldesigner/designercore/model/model.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/plugins/qmldesigner/designercore/model/model.cpp b/src/plugins/qmldesigner/designercore/model/model.cpp index 4e38fb3cfb3..0e9e8b8a5d8 100644 --- a/src/plugins/qmldesigner/designercore/model/model.cpp +++ b/src/plugins/qmldesigner/designercore/model/model.cpp @@ -1390,14 +1390,18 @@ void Model::changeImports(const QList &importsToBeAdded, void Model::setPossibleImports(const QList &possibleImports) { - d->m_possibleImportList = possibleImports; - d->notifyPossibleImportsChanged(possibleImports); + if (d->m_possibleImportList != possibleImports) { + d->m_possibleImportList = possibleImports; + d->notifyPossibleImportsChanged(possibleImports); + } } void Model::setUsedImports(const QList &usedImports) { - d->m_usedImportList = usedImports; - d->notifyUsedImportsChanged(usedImports); + if (d->m_usedImportList != usedImports) { + d->m_usedImportList = usedImports; + d->notifyUsedImportsChanged(usedImports); + } } static bool compareVersions(const QString &version1, const QString &version2, bool allowHigherVersion) From e661135d134224a67dc1e00eabd5e1e0741607cd Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Tue, 28 Jun 2022 15:47:59 +0300 Subject: [PATCH 71/96] QmlDesigner: Remove QML Image level caching of items that can change Icons generated for components can change if the component is edited, so don't cache them locally at Image level. Also increased the compression timeout for component library updates as 200ms can sometimes be too short during project load. Fixes: QDS-7068 Change-Id: I98a0920c4237a1147e9fb5da834e1dc235ae28f5 Reviewed-by: Thomas Hartmann --- .../qmldesigner/itemLibraryQmlSources/ItemDelegate.qml | 4 ++++ .../qmldesigner/components/itemlibrary/itemlibrarywidget.cpp | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml index 130ec2aff68..e19b13fc0fb 100644 --- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml +++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml @@ -59,6 +59,10 @@ Item { width: itemLibraryIconWidth // to be set in Qml context height: itemLibraryIconHeight // to be set in Qml context source: itemLibraryIconPath // to be set by model + + // Icons generated for components can change if the component is edited, + // so don't cache them locally at Image level. + cache: itemComponentSource === "" } Text { diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp index e6f2b2825e5..c4c2c7ab3df 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp @@ -147,7 +147,7 @@ ItemLibraryWidget::ItemLibraryWidget(AsynchronousImageCache &imageCache) , m_itemsWidget(new QQuickWidget(this)) , m_imageCache{imageCache} { - m_compressionTimer.setInterval(200); + m_compressionTimer.setInterval(1000); m_compressionTimer.setSingleShot(true); ItemLibraryModel::registerQmlTypes(); From 88956d1e9baa10273305c1f31d8a54c5755ead31 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 30 Jun 2022 11:42:30 +0200 Subject: [PATCH 72/96] CppEditor: Try to find clangd include path more generically Linux distributions can get creative with the location of the clang headers. So if we find a clang executable alongside clangd, ask it for the base directory and try the hardcoded paths only as a fallback. Fixes: QTCREATORBUG-27760 Change-Id: I9480b170df05598255c01be44be4b0312d0929f8 Reviewed-by: David Schulz --- .../cppeditor/cppcodemodelsettings.cpp | 49 ++++++++++++++++--- 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/src/plugins/cppeditor/cppcodemodelsettings.cpp b/src/plugins/cppeditor/cppcodemodelsettings.cpp index 69f61e2e549..ccf3c9a4df7 100644 --- a/src/plugins/cppeditor/cppcodemodelsettings.cpp +++ b/src/plugins/cppeditor/cppcodemodelsettings.cpp @@ -314,16 +314,38 @@ QVersionNumber ClangdSettings::clangdVersion(const FilePath &clangdFilePath) return it->second; } -FilePath ClangdSettings::clangdIncludePath() const +static FilePath getClangHeadersPathFromClang(const FilePath &clangdFilePath) { - QTC_ASSERT(useClangd(), return {}); - FilePath clangdPath = clangdFilePath(); - QTC_ASSERT(!clangdPath.isEmpty() && clangdPath.exists(), return {}); - const QVersionNumber version = clangdVersion(); + const FilePath clangFilePath = clangdFilePath.absolutePath().pathAppended("clang") + .withExecutableSuffix(); + if (!clangFilePath.exists()) + return {}; + QtcProcess clang; + clang.setCommand({clangFilePath, {"-print-resource-dir"}}); + clang.start(); + if (!clang.waitForFinished()) + return {}; + const FilePath resourceDir = FilePath::fromUserInput(QString::fromLocal8Bit( + clang.readAllStandardOutput().trimmed())); + if (resourceDir.isEmpty() || !resourceDir.exists()) + return {}; + const FilePath includeDir = resourceDir.pathAppended("include"); + if (!includeDir.exists()) + return {}; + return includeDir; +} + +static FilePath getClangHeadersPath(const FilePath &clangdFilePath) +{ + const FilePath headersPath = getClangHeadersPathFromClang(clangdFilePath); + if (!headersPath.isEmpty()) + return headersPath; + + const QVersionNumber version = ClangdSettings::clangdVersion(clangdFilePath); QTC_ASSERT(!version.isNull(), return {}); static const QStringList libDirs{"lib", "lib64"}; for (const QString &libDir : libDirs) { - const FilePath includePath = clangdPath.absolutePath().parentDir().pathAppended(libDir) + const FilePath includePath = clangdFilePath.absolutePath().parentDir().pathAppended(libDir) .pathAppended("clang").pathAppended(version.toString()).pathAppended("include"); if (includePath.exists()) return includePath; @@ -332,6 +354,21 @@ FilePath ClangdSettings::clangdIncludePath() const return {}; } +FilePath ClangdSettings::clangdIncludePath() const +{ + QTC_ASSERT(useClangd(), return {}); + FilePath clangdPath = clangdFilePath(); + QTC_ASSERT(!clangdPath.isEmpty() && clangdPath.exists(), return {}); + static QHash headersPathCache; + const auto it = headersPathCache.constFind(clangdPath); + if (it != headersPathCache.constEnd()) + return *it; + const FilePath headersPath = getClangHeadersPath(clangdPath); + if (!headersPath.isEmpty()) + headersPathCache.insert(clangdPath, headersPath); + return headersPath; +} + FilePath ClangdSettings::clangdUserConfigFilePath() { return FilePath::fromString( From a3997cc05fd5a88ae47ddf37c23b01137485b793 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 30 Jun 2022 11:33:51 +0200 Subject: [PATCH 73/96] README: Update recommended LLVM version Change-Id: Ia7699ca9cd0045036f6034fd55c44264a0b53451 Reviewed-by: Christian Kandeler --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 55ce5919e68..4ecf9f0aeb9 100644 --- a/README.md +++ b/README.md @@ -43,10 +43,10 @@ Prerequisites: * Debugging Tools for Windows (optional, for MSVC debugging support with CDB) * On Mac OS X: latest Xcode * On Linux: GCC 7 or later -* LLVM/Clang 10 or later (optional, LLVM/Clang 13 is recommended. +* LLVM/Clang 10 or later (optional, LLVM/Clang 14 is recommended. See [instructions](#getting-llvmclang-for-the-clang-code-model) on how to get LLVM. - The ClangFormat, ClangPchManager and ClangRefactoring use the LLVM C++ API. + The ClangFormat plugin uses the LLVM C++ API. Since the LLVM C++ API provides no compatibility guarantee, if later versions don't compile we don't support that version.) * CMake @@ -149,8 +149,8 @@ like Qt and LLVM, additionally run ## Getting LLVM/Clang for the Clang Code Model -The Clang Code Model depends on the LLVM/Clang libraries. The currently -recommended LLVM/Clang version is 13.0. +The Clang code model uses `Clangd` and the ClangFormat plugin depends on the +LLVM/Clang libraries. The currently recommended LLVM/Clang version is 14.0. ### Prebuilt LLVM/Clang packages From 03fc7c69f1426139c35acedc511dd9027e7884f0 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Thu, 30 Jun 2022 14:42:37 +0200 Subject: [PATCH 74/96] Doc: Describe "Ignore files greater than" check box ...in clangd preferences. Task-number: QTCREATORBUG-27560 Change-Id: I3865eec1f374666f03eff3e8d092a95c59f56e7d Reviewed-by: Christian Kandeler --- .../src/editors/creator-only/creator-clang-codemodel.qdoc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/qtcreator/src/editors/creator-only/creator-clang-codemodel.qdoc b/doc/qtcreator/src/editors/creator-only/creator-clang-codemodel.qdoc index 60706a70c84..f4ee40a9bf3 100644 --- a/doc/qtcreator/src/editors/creator-only/creator-clang-codemodel.qdoc +++ b/doc/qtcreator/src/editors/creator-only/creator-clang-codemodel.qdoc @@ -176,6 +176,9 @@ \li In \uicontrol {Document update threshold}, specify the amount of time \QC waits before sending document changes to the server. If the document changes again while waiting, this timeout is reset. + \li Select \uicontrol {Ignore files greater than} to make parsing faster + by ignoring big files. Specify the maximum size of files to parse in + the field next to the check box. \li The \uicontrol {Diagnostic Configuration} field shows the Clang checks to perform. Click the value of the field to open the \uicontrol {Diagnostic Configurations} dialog, where you can From 6063f5c89cb11b0a094985d21e00435bd6695682 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 1 Jul 2022 09:22:44 +0200 Subject: [PATCH 75/96] Fix mnemonic conflict between Edit > Preferences and Paste Change-Id: Ib9a991c960c694338a1f75148a1715f669caaa45 Reviewed-by: Orgad Shaneh --- src/plugins/coreplugin/mainwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/coreplugin/mainwindow.cpp b/src/plugins/coreplugin/mainwindow.cpp index 4bd44b5dddc..65249726b04 100644 --- a/src/plugins/coreplugin/mainwindow.cpp +++ b/src/plugins/coreplugin/mainwindow.cpp @@ -720,7 +720,7 @@ void MainWindow::registerDefaultActions() medit->appendGroup(Constants::G_EDIT_PREFERENCES); medit->addSeparator(Constants::G_EDIT_PREFERENCES); - m_optionsAction = new QAction(tr("&Preferences..."), this); + m_optionsAction = new QAction(tr("Pr&eferences..."), this); m_optionsAction->setMenuRole(QAction::PreferencesRole); cmd = ActionManager::registerAction(m_optionsAction, Constants::OPTIONS); cmd->setDefaultKeySequence(QKeySequence::Preferences); From cd86b048cdc88059e703f03f2240ffd9c92ee800 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 30 Jun 2022 11:03:34 +0200 Subject: [PATCH 76/96] kitdetector: Fix detection on macOS On macOS calling clang sometimes produces some output to stderr. This would be captured by "runGcc" when detecting the triplet, which would then show up in the preferences and had negative effects on abi detection later on. To work around this, we only capture the first line of output. On macOS the auto detection code incorrectly assumed that if the architecture is different it would not be able to run on the host. This is not true if the Host is Arm, and the target is x86. Change-Id: I3cd151dc6ad83142fb9643ba7b03a155e754c6d0 Reviewed-by: Eike Ziller --- src/plugins/projectexplorer/gcctoolchain.cpp | 9 ++++----- src/plugins/projectexplorer/kitmanager.cpp | 13 ++++++++++++- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/plugins/projectexplorer/gcctoolchain.cpp b/src/plugins/projectexplorer/gcctoolchain.cpp index 7c1e502c874..c05ed4f42fc 100644 --- a/src/plugins/projectexplorer/gcctoolchain.cpp +++ b/src/plugins/projectexplorer/gcctoolchain.cpp @@ -277,7 +277,7 @@ static GccToolChain::DetectedAbisResult guessGccAbi(const FilePath &path, QStringList arguments = extraArgs; arguments << "-dumpmachine"; - QString machine = QString::fromLocal8Bit(runGcc(path, arguments, env)).trimmed(); + QString machine = QString::fromUtf8(runGcc(path, arguments, env)).trimmed().section('\n', 0, 0, QString::SectionSkipEmpty); if (machine.isEmpty()) { // ICC does not implement the -dumpmachine option on macOS. if (HostOsInfo::isMacHost() && (path.fileName() == "icc" || path.fileName() == "icpc")) @@ -293,7 +293,7 @@ static QString gccVersion(const FilePath &path, { QStringList arguments = extraArgs; arguments << "-dumpversion"; - return QString::fromLocal8Bit(runGcc(path, arguments, env)).trimmed(); + return QString::fromUtf8(runGcc(path, arguments, env)).trimmed(); } static FilePath gccInstallDir(const FilePath &compiler, @@ -302,7 +302,7 @@ static FilePath gccInstallDir(const FilePath &compiler, { QStringList arguments = extraArgs; arguments << "-print-search-dirs"; - QString output = QString::fromLocal8Bit(runGcc(compiler, arguments, env)).trimmed(); + QString output = QString::fromUtf8(runGcc(compiler, arguments, env)).trimmed(); // Expected output looks like this: // install: /usr/lib/gcc/x86_64-linux-gnu/7/ // ... @@ -1449,8 +1449,7 @@ void GccToolChainConfigWidget::handleCompilerCommandChange() Abis abiList; if (!path.isEmpty()) { - QFileInfo fi(path.toFileInfo()); - haveCompiler = fi.isExecutable() && fi.isFile(); + haveCompiler = path.isExecutableFile(); } if (haveCompiler) { Environment env = path.deviceEnvironment(); diff --git a/src/plugins/projectexplorer/kitmanager.cpp b/src/plugins/projectexplorer/kitmanager.cpp index 05a362bd3f7..93bfe31ae43 100644 --- a/src/plugins/projectexplorer/kitmanager.cpp +++ b/src/plugins/projectexplorer/kitmanager.cpp @@ -309,7 +309,18 @@ void KitManager::restoreKits() } static const auto isHostKit = [](const Kit *kit) { - return kitMatchesAbiList(kit, {Abi::hostAbi()}); + const Abi hostAbi = Abi::hostAbi(); + if (HostOsInfo::isMacHost() && hostAbi.architecture() == Abi::ArmArchitecture) { + const Abi x86Abi(Abi::X86Architecture, + hostAbi.os(), + hostAbi.osFlavor(), + hostAbi.binaryFormat(), + hostAbi.wordWidth()); + + return kitMatchesAbiList(kit, {hostAbi, x86Abi}); + } + + return kitMatchesAbiList(kit, {hostAbi}); }; static const auto deviceTypeForKit = [](const Kit *kit) { From f27eb9466927b558d57d5cb949bd4b4160bc3618 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Thu, 30 Jun 2022 14:10:57 +0200 Subject: [PATCH 77/96] Android: Deduplicate identical ABI conversion code ...and use Utils::transform instead of a loop. Change-Id: Ie4127f5e1e8408a544bb7b44ceae3091a21d2644 Reviewed-by: Reviewed-by: Assam Boudjelthia --- src/plugins/android/androidqtversion.cpp | 39 ++---------------------- 1 file changed, 2 insertions(+), 37 deletions(-) diff --git a/src/plugins/android/androidqtversion.cpp b/src/plugins/android/androidqtversion.cpp index fc8dd9f41ca..fa57b05c44d 100644 --- a/src/plugins/android/androidqtversion.cpp +++ b/src/plugins/android/androidqtversion.cpp @@ -28,6 +28,7 @@ #include "androidconfigurations.h" #include "androidmanager.h" +#include > #include #include @@ -95,43 +96,7 @@ bool AndroidQtVersion::supportsMultipleQtAbis() const Abis AndroidQtVersion::detectQtAbis() const { - auto androidAbi2Abi = [](const QString &androidAbi) { - if (androidAbi == ProjectExplorer::Constants::ANDROID_ABI_ARM64_V8A) { - return Abi{Abi::Architecture::ArmArchitecture, - Abi::OS::LinuxOS, - Abi::OSFlavor::AndroidLinuxFlavor, - Abi::BinaryFormat::ElfFormat, - 64, androidAbi}; - } else if (androidAbi == ProjectExplorer::Constants::ANDROID_ABI_ARMEABI_V7A) { - return Abi{Abi::Architecture::ArmArchitecture, - Abi::OS::LinuxOS, - Abi::OSFlavor::AndroidLinuxFlavor, - Abi::BinaryFormat::ElfFormat, - 32, androidAbi}; - } else if (androidAbi == ProjectExplorer::Constants::ANDROID_ABI_X86_64) { - return Abi{Abi::Architecture::X86Architecture, - Abi::OS::LinuxOS, - Abi::OSFlavor::AndroidLinuxFlavor, - Abi::BinaryFormat::ElfFormat, - 64, androidAbi}; - } else if (androidAbi == ProjectExplorer::Constants::ANDROID_ABI_X86) { - return Abi{Abi::Architecture::X86Architecture, - Abi::OS::LinuxOS, - Abi::OSFlavor::AndroidLinuxFlavor, - Abi::BinaryFormat::ElfFormat, - 32, androidAbi}; - } else { - return Abi{Abi::Architecture::UnknownArchitecture, - Abi::OS::LinuxOS, - Abi::OSFlavor::AndroidLinuxFlavor, - Abi::BinaryFormat::ElfFormat, - 0, androidAbi}; - } - }; - Abis abis; - for (const auto &abi : androidAbis()) - abis << androidAbi2Abi(abi); - return abis; + return Utils::transform(androidAbis(), &AndroidManager::androidAbi2Abi); } void AndroidQtVersion::addToEnvironment(const Kit *k, Utils::Environment &env) const From a85fa172c236607c28e09a68c133553ef2d0681d Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 30 Jun 2022 13:46:00 +0200 Subject: [PATCH 78/96] DesignModeContext: Don't leak context on shutdown Make passed widget a parent of the context. Fixes: QTCREATORBUG-27570 Change-Id: Ifbc9db8d5b3fb95566e2c6b83df9c10d02f7c0e5 Reviewed-by: Eike Ziller --- src/plugins/qmlprojectmanager/qdslandingpage.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/qmlprojectmanager/qdslandingpage.h b/src/plugins/qmlprojectmanager/qdslandingpage.h index 3447a2bf915..7162705021e 100644 --- a/src/plugins/qmlprojectmanager/qdslandingpage.h +++ b/src/plugins/qmlprojectmanager/qdslandingpage.h @@ -39,7 +39,7 @@ class DesignModeContext : public Core::IContext Q_OBJECT public: - DesignModeContext(QWidget *widget) { setWidget(widget); } + DesignModeContext(QWidget *widget) : Core::IContext(widget) { setWidget(widget); } }; class QdsLandingPageWidget : public QWidget From 662cc3ca0665e97c24d3f9c046982d6e46f2dd20 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 1 Jul 2022 11:12:59 +0200 Subject: [PATCH 79/96] Squish: Adapt to changed UI text Change-Id: I02d178646ef04893f8d839b2a30085798f1c5fa7 Reviewed-by: hjk --- tests/system/suite_editors/tst_edit_externally/test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/system/suite_editors/tst_edit_externally/test.py b/tests/system/suite_editors/tst_edit_externally/test.py index d0fd4a643e8..4bf6c2bf790 100644 --- a/tests/system/suite_editors/tst_edit_externally/test.py +++ b/tests/system/suite_editors/tst_edit_externally/test.py @@ -48,7 +48,7 @@ def main(): mBox = ("{text?='The file * has been changed on disk. Do you want to reload it?' " "type='QMessageBox' unnamed='1' visible='1'}") popupText = ("

The file %s has been changed on disk. Do you want to reload it?

" - "

The default behavior can be set in Tools > Options > Environment > System.

") + "

The default behavior can be set in Edit > Preferences > Environment > System.

") formerContent = None for i, currentFile in enumerate(files): From 88080612bcec6ba0f41841e87498d46f35f82fa3 Mon Sep 17 00:00:00 2001 From: Tim Jenssen Date: Fri, 1 Jul 2022 11:03:46 +0200 Subject: [PATCH 80/96] tst_qml_testcore: fix spelling Change-Id: I76345be2a8837c4371abf2f4a4695d1edebf2770 Reviewed-by: Thomas Hartmann --- tests/auto/qml/qmldesigner/coretests/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/qml/qmldesigner/coretests/CMakeLists.txt b/tests/auto/qml/qmldesigner/coretests/CMakeLists.txt index 06fb53602c5..253c91e4b72 100644 --- a/tests/auto/qml/qmldesigner/coretests/CMakeLists.txt +++ b/tests/auto/qml/qmldesigner/coretests/CMakeLists.txt @@ -1,5 +1,5 @@ add_qtc_test(tst_qml_testcore - CONDITION TARGET QmlProjectManaer + CONDITION TARGET QmlProjectManager DEFINES QT_CREATOR QMLDESIGNER_TEST From a920bbf59fb071af2e6bfb306dec07bb8ba94924 Mon Sep 17 00:00:00 2001 From: Tim Jenssen Date: Fri, 1 Jul 2022 11:04:31 +0200 Subject: [PATCH 81/96] qmldesigner tests: remove unnecessary defines Change-Id: I1363e7e2ac174b51236644dd37fe184e711e96d3 Reviewed-by: Thomas Hartmann --- src/plugins/qmldesigner/qmldesignercore.cmake | 2 -- tests/auto/qml/qmldesigner/wizard/CMakeLists.txt | 1 - 2 files changed, 3 deletions(-) diff --git a/src/plugins/qmldesigner/qmldesignercore.cmake b/src/plugins/qmldesigner/qmldesignercore.cmake index 46e30173a3b..51d3d8794bf 100644 --- a/src/plugins/qmldesigner/qmldesignercore.cmake +++ b/src/plugins/qmldesigner/qmldesignercore.cmake @@ -27,8 +27,6 @@ function(extend_with_qmldesigner_core target_name) QmlProjectManager QtSupport TextEditor - DEFINES - TEST_EXPORTS INCLUDES ${CMAKE_CURRENT_FUNCTION_LIST_DIR} ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/components diff --git a/tests/auto/qml/qmldesigner/wizard/CMakeLists.txt b/tests/auto/qml/qmldesigner/wizard/CMakeLists.txt index a2965b22f1b..9a50fab71be 100644 --- a/tests/auto/qml/qmldesigner/wizard/CMakeLists.txt +++ b/tests/auto/qml/qmldesigner/wizard/CMakeLists.txt @@ -8,7 +8,6 @@ add_qtc_test(tst_qml_wizard DEPENDS Core Utils StudioWelcome ProjectExplorer QmlDesigner Googletest DEFINES QT_CREATOR - QMLDESIGNER_TEST IDE_PLUGIN_PATH="${PROJECT_BINARY_DIR}/${IDE_PLUGIN_PATH}" IDE_DATA_PATH="${PROJECT_BINARY_DIR}/${IDE_DATA_PATH}" TESTSRCDIR="${CMAKE_CURRENT_SOURCE_DIR}" From bde34f33db6065230565253c3aa3905c2e398a8a Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Fri, 1 Jul 2022 09:40:15 +0200 Subject: [PATCH 82/96] Doc: Fix Language Client Inspector Memory Usage screenshot Also fix the menu item name. Task-number: QTCREATORBUG-27560 Change-Id: Iade8169b00c8f0e96ac7c1087035d84fd4453b96 Reviewed-by: Reviewed-by: David Schulz --- ...or-language-client-inspector-memory-usage.png | Bin 0 -> 8506 bytes .../creator-only/creator-language-server.qdoc | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 doc/qtcreator/images/qtcreator-language-client-inspector-memory-usage.png diff --git a/doc/qtcreator/images/qtcreator-language-client-inspector-memory-usage.png b/doc/qtcreator/images/qtcreator-language-client-inspector-memory-usage.png new file mode 100644 index 0000000000000000000000000000000000000000..862c88d17e3b852fca6ce65d15771b8559de0a12 GIT binary patch literal 8506 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 \uicontrol {Debug \QC} > \uicontrol {Inspect Language Client}. + > \uicontrol {Debug \QC} > \uicontrol {Inspect Language Clients}. \image qtcreator-language-client-inspector-log.png "Language Client Inspector dialog" @@ -201,7 +201,7 @@ For a clangd server, you can inspect the total amount of memory used by a particular component in \uicontrol {Memory Usage}. - \image qtcreator-language-client-inspector-capabilities.png "Language Client Inspector Capabilities tab" + \image qtcreator-language-client-inspector-memory-usage.png "Language Client Inspector Memory Usage tab" \section1 Reporting Issues From 750c50a00f49f1bf9919d47a7d9c3c3da35a815d Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Thu, 30 Jun 2022 16:46:21 +0200 Subject: [PATCH 83/96] Doc: Describe copying an image as a data URL in Image Viewer Task-number: QTCREATORBUG-27560 Change-Id: I2a09e938b556b9998003a2c6732f0174c5c7091a Reviewed-by: Reviewed-by: Eike Ziller --- doc/qtcreator/src/user-interface/creator-ui.qdoc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/qtcreator/src/user-interface/creator-ui.qdoc b/doc/qtcreator/src/user-interface/creator-ui.qdoc index be69ff17d54..ffde43b7b1b 100644 --- a/doc/qtcreator/src/user-interface/creator-ui.qdoc +++ b/doc/qtcreator/src/user-interface/creator-ui.qdoc @@ -220,6 +220,9 @@ \li Export SVG images to pixmaps + \li Copy an image as a data URL, which enables you to include it in web + pages as if it were an external resource + \li Switch between background and outline modes \li Zoom in and out From 2364761c8e68b116186d3e48edb5e9213f43afed Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Thu, 9 Jun 2022 17:07:23 +0200 Subject: [PATCH 84/96] Doc: Document new Python language server options Task-number: QTCREATORBUG-27560 Change-Id: I659f9ef11b25363126ca387c2844bdddfa33f284 Reviewed-by: David Schulz --- ...qtcreator-language-client-options-java.png | Bin 7749 -> 6835 bytes .../qtcreator-language-client-options.png | Bin 10533 -> 0 bytes ...tcreator-language-server-generic-stdio.png | Bin 0 -> 10203 bytes .../images/qtcreator-python-advanced.png | Bin 0 -> 11773 bytes .../images/qtcreator-python-plugins.png | Bin 0 -> 5699 bytes doc/qtcreator/src/android/androiddev.qdoc | 4 +- .../creator-only/creator-language-server.qdoc | 58 ++++++++++++------ 7 files changed, 40 insertions(+), 22 deletions(-) delete mode 100644 doc/qtcreator/images/qtcreator-language-client-options.png create mode 100644 doc/qtcreator/images/qtcreator-language-server-generic-stdio.png create mode 100644 doc/qtcreator/images/qtcreator-python-advanced.png create mode 100644 doc/qtcreator/images/qtcreator-python-plugins.png diff --git a/doc/qtcreator/images/qtcreator-language-client-options-java.png b/doc/qtcreator/images/qtcreator-language-client-options-java.png index d70df4dd4773da7cff2d9037be04ad4ccefc0b84..592d7d2f5a3ae76e677ef71f02476d2a2dbbef18 100644 GIT binary patch literal 6835 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 Jmvv4FO#lm>_RatR literal 7749 zcmeAS@N?(olHy`uVBq!ia0y~yU`k|QU=-nCVqjo+GokD=1A`oor;B4q#jUq<@8(N~ zSG9kx|B;mHxM@z>^|C*a2b``KrJkCYbIQ#u;t6x6_SZ#Igj{ZR|2QSRvr$E-%e83% z_mf2nCU7?8Fta#DNpLbXat1B%D30HfT6{I;{rv~~K3ATb(?4^eN0;-bpAQ>-`OeqO zQMBa0Z|wYP<<6ZurOor!tXsG4s`aMUO>;MG-Mo2oI)`G*gon>H1hUq$+?RFYLlE!s!xI4$PQ{)5 zn_w~N$ix-_r(IilM+<*#Q2f7R$yX%R58>nmC9ePm{Z zL8gGD{>&*6TQ~IXH2_(kk|R4)tZwDoEiBQy9-1gu-M*o2S*W7eGQqHTiQ%R4 zc5SQj;in-d7KE`gFdQ#lA`{X_rOF3hSGv1JOvuDrl$eQxHq| z{a1*t(rgcgwysN&OO_TjtefnUuySe0=_ae9&9NqnqmCA3Y*2Ey5|1!>|18n(;Vn6X z>2tR5h|f3^v}gC5Zww8}?2AsEbCRMeBaTG`5XcXsyM|Fih^=+UD` z=J#tp|9n2*{_`1QQJIx{7Rf#e);+5CWtGNW*{VRz3&~;g4Uid$q-7tqYM#&$}|W-uv@TE0dq$^6L{@w{G=rKJlw=`R4umWJ{jLn`&CW zITHLB33^>A?NjULv6?l*YgR>w#~`v zJ2UsN_6okakC)!Md3i&bPQ-%ZHCt2u7+;-t*XaJ-l=9R#oos%F%dbvcy?V9#?{Z12 z^^*5)ajD+CvV6(*x0>SZlj7YB)x6BJt72dO{rx?4!PbizA;0I&eG?`0H){5mP2#yf z40m!JGdz{yJqJ^Y^{9}zaTxXHXuYkJJfmWt@gG>8!u<{ zUdzx;Udv!nB+-|XmAvAjK~`}~U&*q4eLeL&8$RV&!_%~+(KeM!*7Ak^r{m01O=ToP?nl1)8{PKz3^#*;f%~cVwed5W zJj~f2oVYpt{{{Q?wm*Jrl`b)nKJkiyVZoGzR-0aP^?k7u7X5D~wmyoX;i6ShYUK?oPJ9i|7JIG4o?v!)a?oK>*|JWy;hpUhK|NC;U`QP@G zfYXvj@BjZ$IoZGdqaRy?aLJQ9ckaA-^XBX8>rY=-Y70xfoK+IA%hKLHKHL3Py)?J` zIlCVVXRrKtkpKPO^VX6Ke&;3%8Mcc=ELXF-bTG;B+M$Wx?jJieF;Vd6Wq$2Fjf@E{ zeJaYuDKGCI(<;54eSi7k3HR$we}7Vc|M$z2kH442e#-Td$u#Y|RWq%ptjzwmi}w3R zn)XY$FHV1U+v)zEtVN~^w7M@{`@Ly%;f`I$@Be>!a`OM`H@BGoedD>u#L%~9sq*SS zxob{+jkj`LGhvm-lP^F1W)+LBRSF5&bmqgJgl98S9%|3;%{KC|juMuvhE-Q!W-|INZWm9Ku)3CdJuuhl%a#Hs85 z+4#?kZdJ&>%(ydO`7LXeY^2>A$!l|yEZiT*xc{k6xTE)il|jbxY@g2G+YzeMH$FMH zJyZQ#-LH=y{a1?4$*oycU{V&=e(qz?+nkID>t)IN`&g}xN7**dfB%2NI@_3i=}S!R z3nueV*~ZRrVB*)3l#ln16@^atH6gQT(L2u-Eq`20V_xPg)_>bsX4`jnM+%E+`CVVL zHNXD$_nQ{Z$}T^*y1(Puv8b)RTh{&h*fUqEdchW3hKB1Ci%jfle|<@*|L$xR@%nw; zkAG&@B=&4r#XFg=E{>t$p|z2 zqqzTjZSEpv*(rHm>DdoYd{mcpv_1F!@Ko=b}xHnE-DqzWM3n2yuw}&Ur6in2=I}2orL0n%DRtn&;48ad)*z6 ztkW;{+IZf? zd8X;rzq%jqgcZlzd*19_?qOWLYah$=#myZh!XSk!WM}R)Q1|;^a(Lpm#b7r)I+3Iw z;#Iu<^380u@~Fm;dfmTm7thR+v!CKqY-_c^{&k}=BSV5nU&!Lcr>5fCMGUEecCj& z=n3FjUd)||!6DTB+}X2d&z+0gU$^&S#u}fDCE1r8Uq1Wu#|C8hs=g^5mP-y;nO>a8 zC&n%0&cyJ*17tdbJ18^`OaytLK&6j`fk6gjJ04*fPKE~MLXgq}6ItAu7#R9MVGa^v zV0hpm!^yy40WzMTa32c;$XW_q!hkRU?C1iOgA*CRjw8(_>s7$ME>vM)=u-g&gu9Xx z@%})v3lx+xoyrJv0mq5E5LqsPL<`t2AOjkdPi~amxq0(ucMioA zA!YXpmmAX&EmMs4DG5zkNW)nXszZ1}YrOoK{l6F)7``;ico#llahn(Q&(Dg%Vg8AY zBB)92$x&X0356doJ#FWgulsP2onQW6Sl(j~nUlMd4E~(2|1WOMm~f}^_uISsZ{GNE zbm!+!>+c+!XfdgrwU4Eta$P$iq|iG zH=)sb)5hv6yv1KKcAgi%xz^qNuYQWeiMG>ylqE&wqLsa)>np;Avw;yOC;LSJmY2Gl>e8L6!yxmGT9@)WfJ>i%Pq@hW$d1@ z?asv0yQ7YlYOg!MXFet8(Cswo{mQc5)>T_>`>Aa;KdYp_CiQFUk8P*sX`8F=4}FvA3n9n>WRxhhxnX%vrhs@76n>$tCS{cJnS>ac4e!D`ul84Rzdo9a9oV~m~Zq0OM;lodDmWNLIRkFA?-2at#(9wxywaZdo zu76nLrM*^gwa>~ObM8#e6YVQ>PYS-(+pBB7E9RPNm%WqnolCn2J-#GpsPimv`N{RmGCj!`JaR~FCaJ5}D=j^siQ|}%tzMhe} zTX&_}={1=;%PZDRDxN$|P_}IQu9zDjqxHG{?Ti2M|JVGV7JTmi;r;qCf1g%Z7|D6O zeRg*Gi%ZW>WQc99NLjP>#>9=KTb%1FxB_hQ^qHUb{a)sbl?yM<-leI3) z(~eziI^FJ9*8Hk7ZjrUUvFSmf(@)=e?9uRXo$~#E*XRF#`~F;9bd*KCr-1&v|9|U` z%sO){sx|%JuenlIM%Je#ZW~FZ_v%-DwYnrV_2|Sn_q=VNukXxB`F>Pj*ZD0Mz00MO zT}-m_x0UoQKIXjO)`{G*R=;gE$EDWp+@pNp=JaSTy`P2sLfOpQT0wD8F@4hce?QO1 z|2|&)`~IBYclUFiFMeH0#3iWWjyD&&oE9uH^;8_*A*9cD+_!3er0vzPmi9R-p_DB zy-1~yD`?Z6J$G`E}6Z!D5Y5cUhdqzYEIJIl+F3CYH!(_xsUhB#fn8Tf+4#P_fC}I-Cf0JUS)eH zz1B11%_*U|pTCtnIcpwwFLd_J?}-~H>gc>n3$I_aCe;0WvPJCsWp^iPS^KVio$-Cz z-Gt4tAB-++3of;W%{l7TVKJu+n282J5u8yIYrr; z{rj8S7Mmt%6h4_CD=B;7>cou2x$H0|@CmE`SNkp-S!MBPNo}C9+_wH0DT{T= zhySij($BsZU$>gSEPZn8)~%&ok@w%1e7pYm_H9S=8-2^)uz#vK zJ$HrUr~$ijn~Yg_&k-fKD_=*ltYCS)BeBSe#XpV)18Sszc0By z@#IR8-BG7j&D@f9s{T)S@Rf~+Eq=W|9B|WX^WtrRN2c^_jXEB-wmhCdV`;UiulAay@%7?~_g&{*JeRaLR3oDJ z@T#5R-RTy$_Sei;KKnOqzesOWbam*C`BMMi9J6-%Z!+!n>b~WhUbv)L39Ys}Jo7ng zOz@of>XZ1=cPKwMF_^&Oz zD5}`o^x9-U`HUsAzZNVBQ&GDXyy?nnx6PAOp7yP=^Lx5xs zDZw%Bx7d97j{I!ik^J!GgoKZ5x94t3*C|+Hczw0peeo;)cJ8Mxm8}&FOrAU^_VoKX zYvMYyvqP1{Wu|+da=dPM%kV{3#*RtKSFi2+9rtr{n%&)>3;BMp)SR{V(CNhwY7_S# z>is@t($cU~(z#rArdihRtJP$4vtFIJP(1M`m#n0vp;&5Buy8`wsXIySQ>!e3^w~pG zHMhG=TB&q5*W+cx>e`l1{Im8(RkSwM?zzyd_}x&|e!=zq%6Ipf`^>D_cWwO|Pd<&m z)|c+h@5|lHcjTz`X3%iMm4qla5sObRF1CGcNy>BmmQgcxm&<+rUC-Yv{ko~eX5W$@}@p=Sm-5^=eCi@-4TwGbZUM+Lt_&$=<3T zbLo`wcT?-Woifp{OH*vRi}RoNt=(C8`cGua>g<<2J1=j%7Cduui`1eLUe{+`uAh%C zzG@P<`OU6*U8moloVf4cr4rYj;YU}y`uFZ`URUn&?&-sNtz!SK=Rx{A@8-$hY75T2 zax7xK(pN?2^^arKEwY|^7Xxu};$KmebuF)?*%vY@$qIg&|L*CBkH^bS9*_7vOZIQHYMAPliE}?qQa;2WliBZ8=~rd> zYf*gT%G^nxXUSgQ5PD~Nh3>C^Th=jZ?p%<0vsUf=j!#b3z8Rgy-%Gh;U%6fXl-$2e z?d@utGp9Y@?0drY>(l+Z%r|m3y*HOntp9m#Z^Vx*3lRScj?cFWA!Q&@^z^I4jkn_F8~|NZsV zZSh8$R1geI*}mG#!~(dj8zGb8?C;U&JjZ6<8c4 zIAAxCcRa&ZR_0zvBG!}tI0sQ&)$s%A&YgWdck#yxIk zQvkTV4(iXOh_3th>a2NvX{yit^UQaCY`n+MaJc-*TWKNX=B<{P^qIv$6L#RzK-m(#Im9?Y?g9+SpYyzW((~ueaT| zSGJ`2ZN;fNg{RGTI;B*ux>T9x$@}#$YuSECdey?L1^4A^mdxH-uq3ju^}F%vj+{fc z@2xshv?Mum?%ur$wL(#8i#JT&CvZRPX7STy5{vxIZU;w7NsDcXiPg)RZ}aMJ$%BF? zPRYtzs_Sk3&)%}>&)Lu6slT>9zweWE);#{NcIN*-Zbjvfr~S*jILo%)cXhzpPa(D< z`u1_9QRhy5dl4;q|Jpy(>v`)mVnTK>o^-yc6_S3IuPQ9PG&uLkvA>UW1G{@~WmG%Z zbsVYvlGAomEkOBPT$xyS`h-bVX5!wN7V~Ra zMDbRpyC;9XJr{Os>(LeK*R7~s-^as$(=Atp{Y!6Kquw*;scZZ6pP(dm=g zwOj2)p|dp0mh3FM-gPK#6IbLKHIMX<;^h~1S{1wAa@+O2`Ktcjvrb#j7HngeaCTp} zZe84(8EG0Dmet*!H|g#>wrFwvJl2Ox)+*eXq-mu1FI>%~{fh3@2!E^E1rzhG9mecl z{F!{EsLHDDNM26P&WlekecL;)|B7v*Pf6d_TgR*7jrSUyn#lWvhKR8cm+oClz>kuF;~hWtaAbUW+-u zYo5y8^7CS5Wph14WA$?HfBt!5^Sz7Lee9R^UGd}kbv#N|-RSJbu)Rt;1xu=3Hxdq)8%U}&N^+)^rmJ(!iQ@=UBtHA&r=pZ zr?-6iqCGn|&a{>C?^%Cy=c96mOKV=4THlJutMe+e_1?rA=e}$G&A@c7Sk*Om9lyW& z@&!{iqyrcRyuIauJO+J4vL`4<@(zC1WFbLPyWM~^OD zy7Z*jl9GU3nsbkW#y=LUQhxsISz3Df`uP3#GEBnMKz)$~CB=1ha-h-)RK&rDwdA5F zSZsQC^XAQ)$}JQADY*;rEr$+Ew16fvRayk_&B;NPLMdW&BtHku=(XJVS-)gM-tXIb T`d=9s7#KWV{an^LB{Ts5|DA-! diff --git a/doc/qtcreator/images/qtcreator-language-client-options.png b/doc/qtcreator/images/qtcreator-language-client-options.png deleted file mode 100644 index 0ae18ec4e413612eb6f1f1338c0003dfac829068..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10533 zcmeAS@N?(olHy`uVBq!ia0y~yU`k|QV07SMVqjpX?za(QV9EaktaqI2e?0)H+ zbLaoHO-a7eyf4G%TZYLl)&ON?Ukxwgpv|Tedt3LmO;#13wc&PKH1iRsri`s>D+XIw=>#|dm}{ zL*(3<7!K4}U)qtD^76t|xkOd6xk31L{4on339xU9@TJq%X?()@2CthD)e}8AO zyV)-paCqK{&fgoV=$@CCcZzL4F9U-?wU*g6E(Qhz&gbXn*Q+1D^6>5)YfF$h(=JYY znZJGJ=lJtGXEZ1?GC=HL0J*S0$$j5+h*(sgi1k0;LyO(}K_U6z#F>d+6PBqJf($S1pZDi_px;`N*{5D{D5hj8=Vk^>a9SIdZ6bA>yX(!YHwn9zixw}rVth(}jemA& zi$IgI?~-QKe-q@RcJI4zg6~w`sdIXL%I0QfDbfWhiY;f(O*G=$xpix4F6V^1Q|8LP zI`Q&P+-psXPpjkqzFI!N?$_P-b>*x2{+xB!|M#@r|JiamCl1SG_fr8+j4Xo6Hs6^T z|KpH&+_^~2r*C9`p3+|b=g)Kd{~$fDudVHr&HTmVF630OlxyALCT;8O)|KHd3 z^}lc5kK0+a^vcA}6?I?Q4|dNus9*Q()BJyL+UsjRUhMzGWdG~UQF;5{UtG_!|w5!@6XRj z+&sI=YSY!MrF-3W`n${7)&2^Rt9x#JU$QKI^_IK(J!!TR+fBagjB+vSWRMYk+U?=_ zmLXW(D`Dr-l9Q9_p5)tUMF*^ZbWY#JEVYj(EMnW6e!I;gc`}UKpRGxWN!;e~^Wmq{ z!cGM#ol3vY&u70{9@Y2fnEAeoW)s@GADp-zSN(Rm{ol-2N6(%;>u>k-$@Kkyo~~ZM z&#FmzYj}^E-SwbXhnz&8Ufw9am5KXIl*)#X7R{s2CWod-KR%(qg=_ht2b8j zZ0~^t@td!FUVpvSp6yZTbYhX^r+a&=r!PPF&2fMIhP~3fPvUK}Crm!~^|{Z~+2;9m z9}cqD&sGrr6kw~mJM!Viu%G``F{>#b3v;S^mF@m-(;q zbe}M_e94Dv(fLc8YQDXRw0dE6Dk6J9YX8ztH{I)Xz9t<^SQdCbqi@T)hf}}sH9uZ@ z?CRwm?<0Z|3)YmL_>sQOcK?#S);Avp#mR)t6WA2d7m_ri!|lx;H=C`(-kTE7om~Fc zGXG4Ax$vBsn`U1vTk_%E?)Rr0viHWxzb!AjvRCEVUbCOM`o}&bmx=o%%(%G!f9i_J zxt2e9jc%QCb_-bhJMYSdSMTk$*KJ6MEDpFLlYP~B>#_E>O&c$#^xn(ROyoAV!vznjk4#Dmln@VJiKIc)HH!6W#_&*$KorqN`5!5m}{Tq z?Z4^viT|hP@twD{O)+2n{KUz+%XNJm<*%-lMN)3pk}c^vL|8ugAD)HuqDH=lRJW zf2p-hSZN*fPhrZRqV7LmJC2Gid9&cnvNvxYSzP*gJA&18OI7pZb8k;>Pl@_^#$xT_ z8lJ~1PFBwoFxsdb9v*&_*F5je1pT{rBLh;dr?97*U%z%u?8wA__m3T#_?7{x}j+3%=gx-lR%S-=nM_3rWbCG+0y<)Yn)3R3{D;kvB|K+Y( zn3w(SQ{suZ?ApcmET{dC-F+jq&Ek^woGC9;7SBCCch|+e-p}7WpE_f!Xl~-gO;yXx z7ifh_zP`&L))#*L^~pW|?{UjEKKjISPpC<`@JWnS(UkqYrbYkt=PQSu2vsS1wbd

} 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

vwO`$#1{k9VnRS93rCnUb?R5 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 literal 0 HcmV?d00001 diff --git a/doc/qtcreator/images/qtcreator-python-advanced.png b/doc/qtcreator/images/qtcreator-python-advanced.png new file mode 100644 index 0000000000000000000000000000000000000000..eea49d610cf68e1ce053ccc7a5825f75baadf300 GIT binary patch literal 11773 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 M>FVdQ&MBb@0D>a`ssI20 literal 0 HcmV?d00001 diff --git a/doc/qtcreator/images/qtcreator-python-plugins.png b/doc/qtcreator/images/qtcreator-python-plugins.png new file mode 100644 index 0000000000000000000000000000000000000000..c2ba0b05a17d485bb51d0450fde148378a0ccb41 GIT binary patch literal 5699 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 GLK6U8p~idw literal 0 HcmV?d00001 diff --git a/doc/qtcreator/src/android/androiddev.qdoc b/doc/qtcreator/src/android/androiddev.qdoc index 86797263481..bc736490c68 100644 --- a/doc/qtcreator/src/android/androiddev.qdoc +++ b/doc/qtcreator/src/android/androiddev.qdoc @@ -50,8 +50,8 @@ architectures (ABIs) installed as one. To enable helpful code editing features for Java, such as code completion, - highlighting, function tooltips, and navigating in code, specify settings - for a \l{Specifying Java Language Server Settings}{Java language server}. + highlighting, function tooltips, and navigating in code, add a + \l{Java Language Server}{Java language server}. The Android Debug Bridge (adb) command line tool is integrated to \QC to enable you to deploy applications to connected Android devices, to run diff --git a/doc/qtcreator/src/editors/creator-only/creator-language-server.qdoc b/doc/qtcreator/src/editors/creator-only/creator-language-server.qdoc index 2786828c40e..384707adae4 100644 --- a/doc/qtcreator/src/editors/creator-only/creator-language-server.qdoc +++ b/doc/qtcreator/src/editors/creator-only/creator-language-server.qdoc @@ -79,33 +79,31 @@ \section1 Specifying Settings for Language Clients - You can add a generic generic stdIO language server for Python, for example. - For \l{Connecting Android Devices}{Android development}, you can add a Java - language server. + \QC supports adding a Java language server for + \l{Connecting Android Devices}{Android development}. A Python language + server is added by default and you can edit its preferences. + For other languages, you can add generic stdIO language servers. - \section2 Adding Language Servers - - To view a list of language servers, select \uicontrol Edit > - \uicontrol Preferences > \uicontrol {Language Client} (or - \uicontrol {Qt Creator} > \uicontrol Preferences > - \uicontrol {Language Client} > on \macos). - - \image qtcreator-language-client-options.png "Language client options page" + To add language servers, select \uicontrol Edit > \uicontrol Preferences > + \uicontrol {Language Client} > \uicontrol Add (or \uicontrol {Qt Creator} > + \uicontrol Preferences > \uicontrol {Language Client} > \uicontrol Add + on \macos). To enable a language server, select the check box next to the language - server name and specify settings for the server. + server name and set server preferences. To remove language servers from the list, select \uicontrol Delete. - \section2 Specifying Generic Settings + \section2 Generic StdIO Language Server To add a generic language server: \list 1 \li Select \uicontrol Edit > \uicontrol Preferences > \uicontrol {Language Client} > \uicontrol Add > - \uicontrol {New Generic StdIO Language Server} + \uicontrol {Generic StdIO Language Server} to add a generic language server. + \image qtcreator-language-server-generic-stdio.png \li In the \uicontrol Name field, enter a name for the language server. Select the \inlineimage icons/replace.png (\uicontrol {Variables}) button to use a variable for the server @@ -119,8 +117,9 @@ with a matching MIME type is opened. \l{Viewing Output} {General Messages} displays information about the connection to the language server. - \li In the \uicontrol Initialization field, you can add language server - specific JSON attributes to pass to an \c initialize request. + \li In the \uicontrol {Initialization options} field, you can add + language server specific JSON attributes to pass to an \c initialize + request. \li In the \uicontrol Executable field, enter the path to the language server executable. \li In the \uicontrol Arguments field, enter any required command line @@ -128,15 +127,15 @@ arguments. \endlist - \section2 Specifying Java Language Server Settings + \section2 Java Language Server To add a Java language server: \list 1 \li Select \uicontrol Edit > \uicontrol Preferences > \uicontrol {Language Client} > \uicontrol Add > - \uicontrol {New Java Language Server} to add a Java language server. - \image qtcreator-language-client-options-java.png "Java language server options" + \uicontrol {Java Language Server} to add a Java language server. + \image qtcreator-language-client-options-java.png "Java language server preferences" \li In the \uicontrol Name field, enter a name for the language server. Select the \inlineimage icons/replace.png (\uicontrol {Variables}) button to use a variable for the server @@ -146,6 +145,25 @@ the Java language server \c .jar file. \endlist + \section2 Python Language Server + + To set preferences for Python language servers: + + \list 1 + \li Select \uicontrol Edit > \uicontrol Preferences > + \uicontrol Python > \uicontrol {Language Server Configuration} to + select the Python language server plugins to use. + \image qtcreator-python-plugins.png "Python Language Server Configuration" + \li Select \uicontrol Advanced to configure the plugins. + \image qtcreator-python-advanced.png "Python language server plugin configuration" + \endlist + + For a complete list of configuration options, see + \l{https://github.com/python-lsp/python-lsp-server/blob/develop/CONFIGURATION.md} + {Python Language Server Configuration}. + + To disable the Python language server, deselect + \uicontrol {Use Python Language Server}. \section1 Supported Locator Filters @@ -205,7 +223,7 @@ \section1 Reporting Issues - The language service client has been mostly tested with Python and Java. + The language server client has been mostly tested with Python and Java. If problems arise when you try them or some other language, please select \uicontrol Help > \uicontrol {Report Bug} to report them in the \l{https://bugreports.qt.io/}{Qt Project Bug Tracker}. The reports From 47b91831428c21b6de03178ab8ecfb46b4b45138 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Thu, 30 Jun 2022 15:30:55 +0200 Subject: [PATCH 85/96] Doc: Describe new Python options - Installing PySide6 and Python language server when prompted - Python Interpreter preferences Task-number: QTCREATORBUG-27560 Change-Id: I62f5aae381821bb0e81dffe76de61a8ec057d190 Reviewed-by: David Schulz --- .../images/qtcreator-python-interpreters.png | Bin 0 -> 4987 bytes .../src/python/creator-python-project.qdocinc | 15 +++++++++++++++ 2 files changed, 15 insertions(+) create mode 100644 doc/qtcreator/images/qtcreator-python-interpreters.png diff --git a/doc/qtcreator/images/qtcreator-python-interpreters.png b/doc/qtcreator/images/qtcreator-python-interpreters.png new file mode 100644 index 0000000000000000000000000000000000000000..546adb1b2d363d45314b1cfb5be49ae42fb03489 GIT binary patch literal 4987 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 literal 0 HcmV?d00001 diff --git a/doc/qtcreator/src/python/creator-python-project.qdocinc b/doc/qtcreator/src/python/creator-python-project.qdocinc index 1409b7d840b..3e9bbb83047 100644 --- a/doc/qtcreator/src/python/creator-python-project.qdocinc +++ b/doc/qtcreator/src/python/creator-python-project.qdocinc @@ -33,6 +33,21 @@ to gain access to individual Qt modules, such as \l {Qt Core}, \l {Qt GUI}, and \l {Qt Widgets}. + If you have not installed PySide6, \QC prompts you to install it after + the project is created. Further, it prompts you to install the + \l {Python Language Server}{Python language server} that provides services + such as code completion and annotations. Select \uicontrol Install to install + PySide6 and the language server. + + To view and manage the available Python interpreters, select \uicontrol Edit + > \uicontrol Preferences > \uicontrol Python > \uicontrol Interpreters. + + \image qtcreator-python-interpreters.png "Python Interpreters in Preferences" + + You can add and remove interpreters and clean up references to interpreters + that have been uninstalled, but still appear in the list. In addition, you + can set the interpreter to use by default. + The Qt for Python Application wizards generate a \c {.pyproject} file that lists the files in the Python project and a \c {.py} file that contains some boilerplate code. In addition, the widget based UI wizard creates a From 765f5a2018817247ff60329fc2408d0d7c68fc34 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Thu, 30 Jun 2022 15:10:47 +0200 Subject: [PATCH 86/96] Doc: Describe "Display file line ending" option ...in Preferences > Text Editor > Display. Task-number: QTCREATORBUG-27560 Change-Id: Ic5c7b9fc46c421c2266bca8b7f7a67c68a585cac Reviewed-by: Eike Ziller --- doc/qtcreator/src/editors/creator-coding-edit-mode.qdoc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/qtcreator/src/editors/creator-coding-edit-mode.qdoc b/doc/qtcreator/src/editors/creator-coding-edit-mode.qdoc index f034fde0bed..c4b8d14873e 100644 --- a/doc/qtcreator/src/editors/creator-coding-edit-mode.qdoc +++ b/doc/qtcreator/src/editors/creator-coding-edit-mode.qdoc @@ -125,7 +125,9 @@ \section2 Selecting Line Ending Style To switch between Windows line endings (CRLF) and Unix line endings (LF), - select the ending style on the editor toolbar (6). + select the ending style on the editor toolbar (6). To hide this field, + select \uicontrol Edit > \uicontrol Preferences > \uicontrol {Text Editor} + > \uicontrol Display, and deselect \uicontrol {Display file line ending}. To set the line endings to use for all projects by default, select \uicontrol Edit > \uicontrol Preferences > \uicontrol {Text Editor} > From 98984ec3ba0241b4cbc893cc2aeef8feaca8bc21 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Fri, 3 Jun 2022 15:46:44 +0200 Subject: [PATCH 87/96] Doc: Describe the GitLab plugin Fixes: QTCREATORBUG-27559 Change-Id: Ifd04888628c7d87a2348deb906f9dfad609c6163 Reviewed-by: Christian Stenger --- .../qtcreator-gitlab-clone-repository.png | Bin 0 -> 7551 bytes ...tcreator-gitlab-preferences-add-server.png | Bin 0 -> 4901 bytes .../qtcreator-gitlab-preferences-project.png | Bin 0 -> 7631 bytes .../images/qtcreator-gitlab-preferences.png | Bin 0 -> 9334 bytes .../images/qtcreator-gitlab-project-list.png | Bin 0 -> 18577 bytes doc/qtcreator/src/qtcreator-toc.qdoc | 1 + .../vcs/creator-only/creator-vcs-gitlab.qdoc | 146 ++++++++++++++++++ .../creator-only/creator-vcs-mercurial.qdoc | 2 +- .../src/vcs/creator-only/creator-vcs.qdoc | 7 +- doc/qtcreator/src/vcs/creator-vcs-git.qdoc | 2 +- 10 files changed, 155 insertions(+), 3 deletions(-) create mode 100644 doc/qtcreator/images/qtcreator-gitlab-clone-repository.png create mode 100644 doc/qtcreator/images/qtcreator-gitlab-preferences-add-server.png create mode 100644 doc/qtcreator/images/qtcreator-gitlab-preferences-project.png create mode 100644 doc/qtcreator/images/qtcreator-gitlab-preferences.png create mode 100644 doc/qtcreator/images/qtcreator-gitlab-project-list.png create mode 100644 doc/qtcreator/src/vcs/creator-only/creator-vcs-gitlab.qdoc diff --git a/doc/qtcreator/images/qtcreator-gitlab-clone-repository.png b/doc/qtcreator/images/qtcreator-gitlab-clone-repository.png new file mode 100644 index 0000000000000000000000000000000000000000..35194c4e4f2578da8b6fa862a42cb077e7d64612 GIT binary patch literal 7551 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 QFfcH9y85}Sb4q9e0H}s?n*aa+ literal 0 HcmV?d00001 diff --git a/doc/qtcreator/images/qtcreator-gitlab-preferences-project.png b/doc/qtcreator/images/qtcreator-gitlab-preferences-project.png new file mode 100644 index 0000000000000000000000000000000000000000..835434f5c35635fe1b78a2d8f858ce25cf2bc8f0 GIT binary patch literal 7631 zcmeAS@N?(olHy`uVBq!ia0y~yV0_BJz_6KviGhK^;?v}81_s$_o-U3d6}R5b_0E@e z-*$ZSIiu4zQ_X}=f9rY7P&j9{W7=d%g$|YIYnQ83Ch1Jf3EHGv&E_c3xg{}I_`tHB zk8UiFT0Pgl^NR|&zcBnK(|7GB%y)vX#@_wzA}eWt$SY%2W06@8gMUUQND`&A=eBCyslqiT%o|W0jM>mMWZb zSkK7tAmmF_Tv&FL=kzh9w@j@YSF!b3F7j;QYK zo9*$nHY47Pk)h%9>g%0)?W<(?9oEZAUn^|wjPsr~Pv^EC~|D{pFhmo1CCeJ@n(!fTgzynDCpX`GVB$-q#MSs!<7bMV8f*>9t3Uw!|nbN}1v z-SUrqOL{Xf?6_04_HDj~k@d^FvnJe=PkXiX5{u`CZ2K0ylj~JC3NtY@#4$4<5nrSj z7#QG$-mbX+@^(KSH1pe~e?0h0ih*H+JSgE*@iH(lfCx~aGk^#z#vG`;_4y$7Jm=ljNE7@K3gl> z-il@VUAZZ%E}c5bb87yT4`EjS0#|j(pOLFyU^e&4=Z9~kCtl9rW?(qCJ?^;lHS>Q) zzpcZ~J;fd~M@C;hQnCE@rp;@zR@c0|oviruSnR{w$$IAA31+wes zzpZL3ZC`A?!RTKc)aAT>Y3rUSmE!-qcEn}pDvB^LJpcP!G3KJsMU&LP+x(v2zPf9sia zFf%Y*yS~`rS7`Q|I^;YE&W)fv$N(Z2al!g6uJ{1 z!vxlonRkh&HLh8r>dmU$T>U%oEDSwTCgz!KPU{;NUH{D8&Cn3YT*d3N_uj1d9sCRu zrWtu)nX9+1-TA}BkZ@(ePR_k-U2*JJZ@sx=1LohH9T(0IDn$N?6ukUe_4=!4MbU<* zr-K*kyq}*Q`gPCbQ2xh1tCwoM-NNv5mh=SnbMuVNH@)!qYP6|YI=KD#yuJMXaryBc zd)s#OuZs(BdUfW_odpj!FHKuAIcol%b>CuQ5??=XIk$K&-=SN94|C2+SG@i=(P*~z ztojvxlUKi0e^TUFEL_DavUl0~O26}G_-3VxTsymJUYxDPOSvmmdg}sgUzE+W^k+|e zd!k_5Gu~ZadnOvq(w}k*9VvZ`?jrA)3 zL=Ghi#LlfLoU$aq?_*}@f2l2p7XK~GczWVR>B^X$=C+faE;sjwZm&Gx9PG(+*l%v? zVhh`sC4N6v*4KPEStJ@(lxQ!*9$^J->b~LYSY#2vpVM7lvS5xo^H9B*l;QSZ1uZqvR7xl z)p~c;P0KyK`{{X!%NN8|_Gw-yFjGI8Qa5c{_&@JSe{bLBuv#W!EPeLuysx+ZxKy3h zJ8E>cWw!bxjmaj_M`f#QFIAmYGUAG#rM^&T%|@-lz=WGBr2$i%^cRKbxirdpeU7(& zT6*l&8QoQ{t8_z`&fiq2@#doS(d9`=iTt*q>%G#rEw@!Voc39Mck&9qtXrw8?rL?% zal5aKo$P-6T6uW=+IyS%mfl^OwmZmu%fwTcZ#w;qmGlWdoA*qHslU?JYn%6)-&eAa z|C*IqvRdhqw(h#SHAic=*mwS&aPj)W?iKmrdZSSX49noyjHd zBD1Fvem)D1_}ON5oPVqNdgbOi$Gys_Vg8Y!i$tTjIJ0-(3-*5-zIc}O+Z|@*p^IG8 za%`>EZTjEzlIQ>JT!FV<=Q?*Udv5;goq5pbc~}4c%bF`|=yvM<%|$=wCTB_4?wxJf z?(n(Iu*o$dD(c_U>+vt+!`WudUcTu1pNg9Q5pO0qtalGz|ML2&J9Br52PZxZ@AH2x zGHbn-jp3U&s+CW?&m~(1>Mgwz{H*BWy4lOu{ZeiUkF|8QHC-DT{O#7BPPwYAou_h^ z{gnDUJ2W&Ueec;@OCO(`m(+awe_8sha|^9_-$(v_XK0kXX0P7WTU$$xNUZERCw69j zvd`s<=50pt+Oy2ROpwztF=yXbzxHkWl3TK#X7Q=X_D|-#FzwzS;jptx%}|QV_Lcj3 z)49H1&sl7}>gl~WL+N5q*7d2JYV(V38m$p6Z!KB$?OO2LER(&~Z}W^YQ~6)ajC{YV zu>R$ayYF6Tz29*mtIwQghlZuAvEF{W?o#CPv)i8O*k0PJzBNxbqnE|oT}S!p+nkGk zERTg4`M+OQ&++QqGo5B5gN(dK&!rm|UFSD5Q+t1BYd})}_1)LJZ4a~Vz7nol{eFtn zmdo8o?(N?2d()MAx$KpW{cGwkL>B*>Xk;B^^8bTQd8)?#H+yU(LOp zC#}`&_a}4r_}*SxccbPe@BO!aJiBgnpU|7Wu>VxYgoW0-TU?En`wKB^LqW4=gsYI z+*o3NxTe04lfl61!kQ&JD_QODa|pfIxO&^xy#@7xU|$@0U(K{D?s9$&6GM;Gh3te^ zU$6Z+RLgK+1+t;+0ZoH5HE)7_F_S{)!FrWF??-y_K7iHHQ-kojF?EdeI z{`&Th@uAzd&tAUMrcy0lX60E?rC+N*gcuyQ{A+mORPoEN*IrNl@FZdN`ybjt{=J{} z)z6btm!CM}>VzM2_N=p9AdAG5;PXJ2N@Ecw3RSl?>)yBjVCth+W#J@D)`wHI2VCo&`C zlz+eS*ni>f%Fl0dX0bUZS3do1o`3Jpw{L5CmImyaHu>4J1z)T@AF}_}-PmoA8N+)x zEcEUj0qxX@MO*gg-_E}%cBN?do?AOMtqMJ-rEA%&A)%t{C)J&uU3_X@k3h-h(<^Ns zh1^Jfx%jK!VLra-;}eTR9^ajNHdXrmio%@t0VY#UO|8Cctm&il^ZtcAxq_98j7QoUA1U$|IDL*k9kjhzV+;O`Av~p{han8D%w^?Yu*)0{>#;*xh<${tE zJzPE7T&z07cdtto4&S+9Wi007chCyc|V>eu#ptnI+_M&g<+15KVzL-pz_Q9=q zVs3BQlZ`!pT&8{vEmz*5prfn%|I_RBU)F0gpFJCV`SphvFCyN!-e9@7{(6;{<6ghn zi%s{O8sp`=tj9ar(<2*RKjMgde`}7 zuUY4UX}&R`#YIiwcV&E^ylM(`zBOm7sMi&r)G0e(Z7S*B>Lr}IZr{cIefMU5%a%N# z+Vt$%%eCuYF1R$Qe9PA7weRaZ=FE5z=(yLfjNwXe(+!5#S+n#rd*8QbRP+5?+dt>G z;-$TfrdcA}rRVRIf3)rFZuvzoOocllChg#PDrj9VI6Z^w;b+aFHO~^O>=U{?Ro`aK zUX>n{=(zV;^y8;DR$U3%zDLVxP0F@c`n$K6-ip1s=gc3^`;1?9HN>?q{5y44{GK1? zvx2_{-e+VxnZ2?0x0k_PF@yUlUDJzhN$<2+{zL6+;Oh?_)eFVj*6H7y8UH;@Xzlj) zHNV@p_IvJ+(v2>>T(NfZv)^v(bL;lryRoOZT&tB+_Hwd}p4?`|r=6i_Y(5cbHtbbL71FJi&SE7tDDHE@5ZvDZb7$`Q*2C zUnfo8Tb}qmb!C8{`{ldgs>?%t0@yE{S`l1#b1%hj$Ot)!Nrzf6Z^E zruKfupFe$TEzNVM-+5ECS1;tqxo4;Ie&lWcUv*CZ%>U`PnH!#|efecFvF*|X=@UrNvAWiSw0v+mNGJ(ZuIN&Kr*o**f`+v|Hl)f-5cBQ}W_G%`@k z4C?uUJ3(Lq)CmIjgbY;n?koFiRlAcVev{$}{^aZHcFUCh{`PkLzF)7nYq;u8WNzQL zqxZvWd!~b_*RyBoZqKXt+}~6B`=PQ!okHr)wAltK*Y5xM9A6NUANTj!?E1RI$vG|Y z|2SAKWPb}T;5RdS+5h!kd<@eQ_D{z|Z-?Lf|9tiO2P^9Kc=5UX_$u7UP<6IWJ0Lf^ z`r$vN4u$-PdVX%(>xTpXR!o)Y`0!etiSdioJcBRQjSemG>mSaaxA)b>>>uj>EKDy- zO%k^~6Mxst@u@9({lgXa_P)B7U11u|!t}y)w!zg~VtAl zj|0QrG-0(B*V3Lpb7ZMJy!3iOh<#k?OVd5GjF}j}M9nrhZ~gG(!D%A4(d+%Uh_EWx z%e^UmwxUZ^Wd7vqTkBR8JwLhpdiKG~$ECeL_XYD7mahC_;BWT&>eXA9m;bN)wPA}z zL1RML-{+YwA^Y$8)yo@ydUEk~`g`ZM#hs8&?hRw69+F%1^NyXmroU>&0D&h{e0Vly$8>8 z#6v>l%hdBPXGWeg?%I}C8a5{_$YlTW9s5^BeO7s6!WI8A6# zM#kL#SN`+&9JQw#56*0ld44JTMp!-IY0ew+SMIiuV=aiZMe74c=5Scj?pD z9JPrK_0peV8`LK0U;Ko3dYpIPuZ4R)7t|&mvv|t>`rx^9!AaSF_dU&8m*Zc4%HCtD z{nVmOIZrJ|PI%q9%&@Nd%8Bz=*MYpW zYeHOiObtAO{6SC=Sq-EMYR89yuSqH3Jy7S)y4 z7KAQ+y>+j3;M^R&r9XdP%T|ojcGOu}wzn*G_x^oTHQx8EwG0cJR55X8=lYPJ*N)Z1 z>^w2YOyy#C967&Q0<4go! zi`@A7V#ld}+(xgr%oN;U?Q}PN>UN8XdK=FENlCe}?)Y(NaPQl)d9Rs$?wnIE(~`=z z-MTjU)~}{_KGpwTuKdZqb?&K6C$`1Z1w|F6U(3DL{d`++($Y^A&pD5unSVpL`s&i_ zlfru+a!)#%y~m_CXi3H9-mP-F-%1Q$oI7w$`0cR_-kn^}a;}SmGP)Yi->#XvgTGsp zcFhi-S`Bva$yp(-1kbCvkw^uC#|KF*4TbSA@yMBtC`pc6WpF4Qh1g*}s*IO%bZp*Xj zw^Mbd&YLpr?#!vl*5I29vv z`q;*ht9e)AcE4K@pSphSt!FE}UbC9_&)stS?v)~|&QDvuUkW=R?YGxY*7eN)fZLT{ zW&}si?iHSHE}#F`V7Y8H-4jQxmQ*z$g$vh&LNu{H)iZ97I&Fo9#h5Z{`GO_^ti*TEtLfv z*57Q2tlwa0Sjmn>&M?^IG51*Z#oxE-T zyzf8PM#ukuEMEYs*?zrVZ~y;KaZ9{C$n>6#8&{XuFLyU^sQchE^}PLl*X|?wA2fd` zE{{Aa^)TFoi4j!WA_kkmRW5>nSH9pH7}Qg2xP0yPtHfW&Bl_Zfo~$lO`ma&{EM|h_ zoQ{`t9CI8Pg3-kBYb0-}4V`wT_r@kpIq2#qX*aN6)?A+06XKM?X|l`ny;6 zFRPi$0=`FIz5MpglWt|xXYEHPq#v=o^7@AC*7ye}^&6-h_t3NfgS?br+u+^7} zL#HcQ{eH7xt3`CN4BK-*?yh6Uc&9r|uK9lDZ(W{8P`B`J{icUI_s%zbRsXAhLmdCv z3*2k2=S+P#SL?#-%NJkYdu6k|>a2)yq+~#3?o@*iqhz_N+FMm;LH(OV5%x=;_erR) z45>2Zob@I0rNM-6(Kosr_NACQ+uq3UbYJJG94(=5=)>%C>f*nB&#E$27nL=JiZ0Dy z`+P)UWx*xe+%xZPteSN}K4&S9xzViRzV54^uU+iS30NL;VbZq3EnH`9<#$clyu-3- zmUBq?%j8_Pc~|FWF3M0U-1Lt3>g{(I3t9K%CGJZw`~B72J^oB#d0&SK%gLzQ&*}wr zXRWj?F*ANv9G3dBB5vi$oD8MxZ!hJ}=`8JAY3T6n=j-k#Z>+QVe=DBJSn2)g$@Z12 zZa6=2jYyGLsQK3TmietURl0i)l&QxSB}+|^I#acTw=9Vv)y}H#&61o~A=ljk-&|Ol z=256zHlZT=q%}i$=(^wAZe>4L+hL}6)MovcKq-zweq-a^uTO^FF>cy6U1Qpuc?V9H zY$3tj~ZUV! zQ`y=qHye4cRD3mi#?N2bJ<0a(rJt(n{QNeXZ-$)Ar`6j|1e|^wzJKOzow7CSbJy8e zZPGs&#C)m3C`Nx>Sk#}qlYN;<&qX4mbG_1wzd7x#*U+z?YIAJglG?~8U-ry&H}qkd zywA!^O#EAwQMdRk9yh=G2dSsll}f(&T=ubyn`N_i`JTjQk`qlPxqkWecm3>J&677@ zyI$KDzD|nmN;AaeQV%2Dmv~={`K`EZEC1T=%XZPc zA6}Ho+@E;rLgDI3&-B+pI#0dk?nmo^Li|D>T z7L&`4{WQt7Is0|PzGciWfBP(By!Us)ip)&)CmXJA%I$l8<@E~A&pTD__k@ybNl%3i>wGY) zd~dl~WQf##{+GpjK3#cma#`LB>u=6IGp9zLGGm?e$W=+JID>8J^-opzO2bXe@8-U* ze3A9*$Ah3nF;%krUm4Cna(S-u@852Jr7KQ_h1^QYDwxOnVoUI}v#DEG1)SBq$7J~M z^1Uy!@;BN%e)MI}#N!pR&u@Jp#@@#b4A(v9n%E$|5K>r21(;H28ujaQ3IQ)Wg=E2!+{mG6Tj^FV^j4>fq{YH!fU~+uPYMkch)(HFfi=3 s+x|KmB$|yp%Lbk;!&mwhF#f22eteyi@nfwt1_lNOPgg&ebxsLQ0H!)LTL1t6 literal 0 HcmV?d00001 diff --git a/doc/qtcreator/images/qtcreator-gitlab-preferences.png b/doc/qtcreator/images/qtcreator-gitlab-preferences.png new file mode 100644 index 0000000000000000000000000000000000000000..459d5d60ccb6ad7b915998f7fa7d157c92b4fffa GIT binary patch literal 9334 zcmeAS@N?(olHy`uVBq!ia0y~yV7$Y?z$n4N#=yYv?Us8u1A~gKr;B4q#jUqy_QDKV}e>>tRNKAX$@BJ<0cFAroG&bKcwd;YGj`h(qNTjK-eQ-bbSzJB{& zlR?5RKW_K3eZP-MztaErNk5%$<#p+}zZvNa=KGop7~Rxwm*?LNlK=l_p_Q%f%F98O zWglKCf35odK5wP@{hG<&*iI&Njyob;+`+^B(A&GIK&`)O%X{`PSDR1xuMWeYp46w)FR6>*D4s z;jjK4linQrU+H?W*lmSXll5crf0Qn3eSOvcm1Y0WW*cXjxu2GbfdB@$R zRGoMJ+Z}U0GKYEPX&cV+xXZOE2=8!b26aLLbdQh6fzsH5PgfcPUS;O8CR+w+8VHOb=dB; zw*=Sj(kg$pJ!Egv?RP<@LeqJZYgPA(|)-4W~JBH{hQIhH0Q6;5v#ANG2J2AXP2!?@VoQ`h0y=@lo~otyfo{@2`F= zH+TNd+X*6vwzB-1y#AAD+OF2svZwoxs=T&4Bz$$}+~5Bf^zX}gY`grIcwXq$=-jI- zzAB%|6n>}u_0?3}Z5NNeVQGopVw3z#H2>FUe=fBm{A6S~BEPpOzUQBI?kjL{=DNTn=*GiO;0lj7WM#gg|P z^6P0fJTlK9#Nytjo%8&^y-d8aQvadb_iWo!U&AW?cr4i!^84k(S+{rJlb7o)XqI@L ztI=sVE5A=6^*L+t2?LJ}nc~MibLan+lzF~(^}KGOcB|Tdp5|!>zlptkVN}?)(YdBK z+UD-#)F=NspK&RhZLFDhh3&D}y0pLRe0tojw}^<`*irttzgODG@5ZsX#M7N-6RUT4 z_GW5No|&>~ozGdTzMn3odCv{M7qHu~?>5}x%fH<3@XLp4o@VU@*}iXMd~eyk;M~od z&hNeB)`i$LzQMN?Hp(_HnHlfrnH%3?BfP)k#l�xogfxMp&_hWvU&$Ve}=-x@?W@ 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 UF~z+d3=9kmp00i_>zopr0G@}!VE_OC literal 0 HcmV?d00001 diff --git a/doc/qtcreator/src/qtcreator-toc.qdoc b/doc/qtcreator/src/qtcreator-toc.qdoc index ffdc1f1f039..b401e05bffa 100644 --- a/doc/qtcreator/src/qtcreator-toc.qdoc +++ b/doc/qtcreator/src/qtcreator-toc.qdoc @@ -69,6 +69,7 @@ \li \l{Using ClearCase} \li \l{Using CVS} \li \l{Using Git} + \li \l{Using GitLab} \li \l{Using Mercurial} \li \l{Using Perforce} \li \l{Using Subversion} diff --git a/doc/qtcreator/src/vcs/creator-only/creator-vcs-gitlab.qdoc b/doc/qtcreator/src/vcs/creator-only/creator-vcs-gitlab.qdoc new file mode 100644 index 00000000000..7c4e9589a48 --- /dev/null +++ b/doc/qtcreator/src/vcs/creator-only/creator-vcs-gitlab.qdoc @@ -0,0 +1,146 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Creator documentation. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** +****************************************************************************/ + +/*! + \previouspage creator-vcs-git.html + \page creator-vcs-gitlab.html + \nextpage creator-vcs-mercurial.html + + \title Using GitLab + + GitLab is a DevOps tool developed by GitLab. You can clone projects from + GitLab servers and use \l{Using Git}{Git} to manage your local and remote + repositories. + + To enable the experimental GitLab plugin, select \uicontrol Help > + \uicontrol {About Plugins} > \uicontrol {Version Control} > + \uicontrol GitLab. Then select \uicontrol {Restart Now} to + restart \QC and load the plugin. + + To use GitLab, you must create a connection to the GitLab server and clone + the projects you want to work on. You can also link previously cloned + projects to GitLab in the project settings. This enables you to receive + event notifications in the \l {Viewing Output}{Version Control} pane. + + \section1 Connecting to GitLab Servers + + To connect to a GitLab server, you need to specify the server host name and + port number, as well as an access token that you create in GitLab for \QC. + The permission scope of the token must be at least \c read_api or \c api. + + To specify connections to GitLab servers, select \uicontrol Edit > + \uicontrol Preferences > \uicontrol {Version Control} > \uicontrol GitLab: + + \image qtcreator-gitlab-preferences.png + + To add GitLab servers: + + \list 1 + \li Select \uicontrol Add to open the \uicontrol {Add Server} dialog: + \image qtcreator-gitlab-preferences-add-server.png + \li In \uicontrol Host, enter the host name of the GitLab server. + \li In \uicontrol Description, enter a free-form text that is displayed + in the GitLab settings of a linked project. + \li In \uicontrol {Access token}, enter the access token you created for + \QC in the GitLab server, in \uicontrol Preferences > + \uicontrol {Access Tokens}. + \li In \uicontrol Port, enter a port number. + \li Deselect the \uicontrol HTTPS check box to use an HTTP connection + instead of a secure connection. + \li Select \uicontrol Add to create the connection. + \endlist + + In the \uicontrol GitLab tab, \uicontrol curl displays the path to the + \c curl tool used for HTTP connections. You can specify another path to + use another instance of the tool than the one found by \QC. + + To edit the selected connection, select \uicontrol Edit. + + To remove the selected connection, select \uicontrol Remove. + + \section1 Cloning Projects + + You can clone projects from the connected GitLab servers. \QC reads your + user name and ID from the access token and displays the available projects + in each server. You can search for a particular project or browse projects + in the list. + + To clone projects from GitLab: + + \list 1 + \li Select \uicontrol Tools > \uicontrol GitLab to view a list of + connected GitLab servers and available projects in each server: + \image qtcreator-gitlab-project-list.png + \li In \uicontrol Remote, select a GitLab server. + \li In \uicontrol Projects, select the project to clone. + \li Select \uicontrol Clone to open the \uicontrol {Clone Repository} + dialog: + \image qtcreator-gitlab-clone-repository.png + \li In \uicontrol Repository, specify the URL of the repository. + \li In \uicontrol Path, specify the path where to clone the repository. + \li In \uicontrol Directory, specify the name of the directory for the + cloned repository. + \li Select the \uicontrol Recursive check box to also clone submodules + of the repository. + \li Select \uicontrol Clone to clone the project to the specified + directory. + \endlist + + \QC automatically opens the project. If the cloned project has several + project files (such as CMakeList.txt, .pro, and .qbs), \QC prompts you to + select the one to open. If it does not contain a project file that \QC can + open, select \uicontrol File > \uicontrol {New Project} > + \uicontrol {Import Project} > \uicontrol {Import Existing Project} to + import the project as a generic project. For more information, see + \l {Using Project Wizards}. + + \section1 Linking Projects with GitLab + + Link a project with a GitLab token to receive notifications on events, such + as merge requests, issues, or comments, in the \uicontrol {Version Control} + pane. The information is fetched every 15 minutes. Only events that occurred + after the last time you logged into GitLab are displayed when you open the + project for the first time. Subsequently, events that occurred after the last + successful fetch are listed. + + To link with GitLab: + + \list 1 + \li In the \uicontrol Projects mode, select \uicontrol {GitLab} to view + the GitLab settings for the currently active project: + \image qtcreator-gitlab-preferences-project.png + \li In \uicontrol Host, select the URL of the GitLab server. + \li In \uicontrol {Linked GitLab configuration}, select the GitLab + server settings to use. + \li Select \uicontrol {Link with GitLab} to receive event notifications + in the \uicontrol {Version Control} pane. + \endlist + + To test the connection to the host using the access token specified in the + GitLab configuration, select \uicontrol {Test Connection}. + + To stop the reception of event notifications, select + \uicontrol {Unlink from GitLab}. +*/ diff --git a/doc/qtcreator/src/vcs/creator-only/creator-vcs-mercurial.qdoc b/doc/qtcreator/src/vcs/creator-only/creator-vcs-mercurial.qdoc index 244cb995a8b..e4212947a7b 100644 --- a/doc/qtcreator/src/vcs/creator-only/creator-vcs-mercurial.qdoc +++ b/doc/qtcreator/src/vcs/creator-only/creator-vcs-mercurial.qdoc @@ -30,7 +30,7 @@ // ********************************************************************** /*! - \previouspage creator-vcs-git.html + \previouspage creator-vcs-gitlab.html \page creator-vcs-mercurial.html \nextpage creator-vcs-perforce.html diff --git a/doc/qtcreator/src/vcs/creator-only/creator-vcs.qdoc b/doc/qtcreator/src/vcs/creator-only/creator-vcs.qdoc index 3555b137d82..27869401a4d 100644 --- a/doc/qtcreator/src/vcs/creator-only/creator-vcs.qdoc +++ b/doc/qtcreator/src/vcs/creator-only/creator-vcs.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2020 The Qt Company Ltd. +** Copyright (C) 2022 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Creator documentation. @@ -72,6 +72,10 @@ \li Git version 1.9.0, or later Gerrit version 2.6, or later + \row + \li \l{Using GitLab}{GitLab} + \li \l{http://gitlab.com/} + \li Experimental \row \li \l{Using Mercurial}{Mercurial} \li \l{http://mercurial.selenic.com/} @@ -124,6 +128,7 @@ \li \l{https://doc.qt.io/qtcreator/creator-vcs-fossil.html} {Qt Creator Fossil Plugin Manual} \li \l{Using Git} + \li \l{Using GitLab} \li \l{Using Mercurial} \li \l{Using Perforce} \li \l{Using Subversion} diff --git a/doc/qtcreator/src/vcs/creator-vcs-git.qdoc b/doc/qtcreator/src/vcs/creator-vcs-git.qdoc index e4ced3102b0..bb1e08c611e 100644 --- a/doc/qtcreator/src/vcs/creator-vcs-git.qdoc +++ b/doc/qtcreator/src/vcs/creator-vcs-git.qdoc @@ -36,7 +36,7 @@ \nextpage studio-porting-projects.html \else \previouspage creator-vcs-cvs.html - \nextpage creator-vcs-mercurial.html + \nextpage creator-vcs-gitlab.html \endif \title Using Git From f587a0b1862d277b063296b56f6614d1d92343f1 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 30 Jun 2022 09:52:13 +0200 Subject: [PATCH 88/96] ProjectExplorer: set correct task type Change-Id: I56f9e66cde30d5ebb182f0badc4e1cb134237fe8 Reviewed-by: Christian Stenger --- src/plugins/projectexplorer/msvcparser.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/plugins/projectexplorer/msvcparser.cpp b/src/plugins/projectexplorer/msvcparser.cpp index d4530a58324..890b4a4e532 100644 --- a/src/plugins/projectexplorer/msvcparser.cpp +++ b/src/plugins/projectexplorer/msvcparser.cpp @@ -69,16 +69,19 @@ using namespace ProjectExplorer; // nmake/jom messages. static Task handleNmakeJomMessage(const QString &line) { + Task::TaskType type = Task::Unknown; int matchLength = 0; - if (line.startsWith("Error:")) + if (line.startsWith("Error:")) { matchLength = 6; - else if (line.startsWith("Warning:")) + type = Task::Error; + } else if (line.startsWith("Warning:")) { matchLength = 8; - - if (!matchLength) + type = Task::Warning; + } else { return {}; + } - CompileTask task(Task::Error, line.mid(matchLength).trimmed()); + CompileTask task(type, line.mid(matchLength).trimmed()); task.details << line; return std::move(task); } From 93ed9157b1d91de53ef76ecf58bfd96b8e466f8f Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 1 Jul 2022 11:08:02 +0200 Subject: [PATCH 89/96] Update change log for Qt Creator 8 Change-Id: I94bfe43d61388d23c0feecd4eabe67c173c7aee6 Reviewed-by: Leena Miettinen --- dist/changes-8.0.0.md | 55 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/dist/changes-8.0.0.md b/dist/changes-8.0.0.md index 87bf811f3df..35675b2281f 100644 --- a/dist/changes-8.0.0.md +++ b/dist/changes-8.0.0.md @@ -10,6 +10,11 @@ the public Git repository. For example: git clone git://code.qt.io/qt-creator/qt-creator.git git log --cherry-pick --pretty=oneline origin/7.0..v8.0.0 +General +------- + +* Moved `Tools > Options` to `Edit > Preferences` + Help ---- @@ -20,24 +25,38 @@ Editing * Added shortcut for adding next search match to multi-selection * Added warning when editing generated file (QTCREATORBUG-27173) -* Added option for hiding line ending information +* Added option for hiding line ending information `Text Editor > Display > + Display file line ending` * Fixed updating of annotations (QTCREATORBUG-26812) * Fixed that whitespace was not selected on double-click (QTCREATORBUG-24607) * Fixed `Rewrap Paragraph` when indenting with tabs (QTCREATORBUG-27602) +* Fixed code folding marker visibility after `Open in New Window` + (QTCREATORBUG-27748) ### C++ * Removed `libclang` based code model * Fixed that `Generate Setter and Getter` generated non-static methods for static pointer types (QTCREATORBUG-27547) +* Fixed `Add Local Declaration` for class templates (QTCREATORBUG-26004) +* Fixed that `Follow Symbol Under Cursor` could jump to new location even after + the user started doing other things (QTCREATORBUG-20878) +* Fixed that macros were highlighted as preprocessor statements + (QTCREATORBUG-23548) +* Fixed initialization of pointer variables when generating member for + `Q_PROPERTY` (QTCREATORBUG-27770) * Clangd * Increased minimum `Clangd` version to 14 + * Added warning and disabling of `Clangd` by default on machines with low + memory (QTCREATORBUG-19297) * Improved performance of `compile_commands.json` creation * Replaced some refactoring actions by the ones from `Clangd` * Added desugaring of types and warning about unused includes * Added option for ignoring big files * Added information on parent function to `Find References With Access Type` (QTCREATORBUG-27550) + * Added warning icon and deprecation tag to completion items for deprecated + API (QTCREATORBUG-2325) * Worked around `Clangd` highlighting issue (QTCREATORBUG-27601) * Fixed `Follow Symbol Under Cursor` for template types (QTCREATORBUG-27524) * Fixed that issues from other files could be shown in `Issues` @@ -47,7 +66,7 @@ Editing * Fixed that UI files with same name could confuse code model (QTCREATORBUG-27584) * clang-format - * Simplified options dialog + * Fixed cursor position when undoing formatting (QTCREATORBUG-27608) ### QML @@ -55,6 +74,10 @@ Editing (QTCREATORBUG-23411) * Fixed handling of JavaScript string templates (QTCREATORBUG-21869) * Fixed formatting issue with nullish coalescing operator (QTCREATORBUG-27344) +* Fixed that `Follow Symbol Under Cursor` could open file from build directory + instead of source directory (QTCREATORBUG-27173) +* Fixed member lookup for items with same name in different modules + (QTCREATORBUG-26714) ### Python @@ -70,6 +93,8 @@ Editing ### Language Server Protocol * Improved performance for large server responses +* Added support for dragging in `Outline` (QTCREATORBUG-27502) +* Fixed order of outline items (QTCREATORBUG-4346) * Fixed semantic highlighting after server reset * Fixed that semantic update was delayed by `Document update threshold` even after saving @@ -80,6 +105,10 @@ Editing * Added button for copying image as data URL +### FakeVim + +* Partially implemented multi repeat command `:g, :v` + Projects -------- @@ -97,12 +126,20 @@ Projects * Removed hardcoded `QT_QML_DEBUG` from wizard created project files * Fixed issue when reconfiguring with `QML debugging and profiling` option enabled +* Fixed missing path to `ninja` for `ExternalProject_Add` (QTCREATORBUG-27495) +* Fixed that headers were wrongly classified as `C` code if `qt_add_qml_module` + is used (QTCREATORBUG-27117) + +### Compilation Database + +* Fixed wrong removal of command line options (QTCREATORBUG-22949) Debugging --------- * Switched fallback Qt version for debug information to Qt 6.2 * Added pretty printer for `QAnyStringView` +* Added workaround for LLDB on Ubuntu 22.04 Analyzer -------- @@ -143,6 +180,8 @@ Platforms * Removed support for Universal Windows Platform (UWP) * Added auto-detection for MSVC ARM toolchain and debugger * Fixed ABI detection on ARM Windows +* Fixed ABI detection of static Qt (QTCREATORBUG-27735) +* Fixed interrupting remote CDB processes (QTCREATORBUG-21657) ### macOS @@ -156,9 +195,14 @@ Platforms * Aligned platform names with Android Studio (QTCREATORBUG-27161) * Fixed issues with newer SDK tools (QTCREATORBUG-27174) +### iOS + +* Improved consecutive deployment speed (QTCREATORBUG-24371) + ### Remote Linux * Switched to `echo` for testing connection +* Fixed deployment of multiple directories with `rsync` ### Docker @@ -178,6 +222,7 @@ Credits for these changes go to: -------------------------------- Aaron Barany Adam Treat +Aleksei German Alesandro Portale Alessandro Portale Alexander Akulich @@ -187,6 +232,8 @@ Andre Hartmann André Pönitz Artem Sokolovskii Assam Boudjelthia +Bartlomiej Moskal +BogDan Vatra Christiaan Janssen Christian Kandeler Christian Stenger @@ -201,16 +248,20 @@ Evgeny Shtanov Fawzi Mohamed Henning Gruendl Ihor Ivlev +Ippei Sugita Jaroslaw Kobus Knud Dollereder Leena Miettinen +Mahmoud Badri Marcus Tillmanns +Mats Honkamaa Maximilian Goldstein Miikka Heikkinen Orgad Shaneh Piotr Mućko Rafael Roquetto Robert Löhning +Samuel Ghinet Sergey Morozov Tapani Mattila Tasuku Suzuki From caed14b22dffe337f55c01ff1460fde07841b82b Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 30 Jun 2022 15:26:47 +0200 Subject: [PATCH 90/96] Fix pluginspec test for Windows release builds Used a wrong name for the plugin library Change-Id: Ic1cff07387b660a641c2f43bfb913bd8b8668c5c Reviewed-by: Christian Stenger --- tests/auto/extensionsystem/pluginspec/testplugin/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/extensionsystem/pluginspec/testplugin/CMakeLists.txt b/tests/auto/extensionsystem/pluginspec/testplugin/CMakeLists.txt index a77550fa468..bd701ac2433 100644 --- a/tests/auto/extensionsystem/pluginspec/testplugin/CMakeLists.txt +++ b/tests/auto/extensionsystem/pluginspec/testplugin/CMakeLists.txt @@ -4,7 +4,7 @@ if(APPLE) elseif(UNIX) set(plugin_output_name "libtest") else() - set(plugin_output_name "testd") + set(plugin_output_name "test$<$:d>") endif() file(RELATIVE_PATH TEST_PLUGIN_PATH ${QtCreator_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}) From b29ca1e345ae5358faac872f1d90469f69879e1f Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 1 Jul 2022 09:42:53 +0200 Subject: [PATCH 91/96] ProjectExplorer: Drop encoding roundtrip in gcc detection Change-Id: I6fb407465f634287edeba59fe6427ddb0299112f Reviewed-by: Qt CI Bot Reviewed-by: Christian Stenger --- src/plugins/projectexplorer/gcctoolchain.cpp | 34 ++++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/plugins/projectexplorer/gcctoolchain.cpp b/src/plugins/projectexplorer/gcctoolchain.cpp index c05ed4f42fc..ee0a0e3e363 100644 --- a/src/plugins/projectexplorer/gcctoolchain.cpp +++ b/src/plugins/projectexplorer/gcctoolchain.cpp @@ -126,18 +126,18 @@ using namespace Internal; // Helpers: // -------------------------------------------------------------------------- -static const char compilerPlatformCodeGenFlagsKeyC[] = "ProjectExplorer.GccToolChain.PlatformCodeGenFlags"; -static const char compilerPlatformLinkerFlagsKeyC[] = "ProjectExplorer.GccToolChain.PlatformLinkerFlags"; -static const char targetAbiKeyC[] = "ProjectExplorer.GccToolChain.TargetAbi"; -static const char originalTargetTripleKeyC[] = "ProjectExplorer.GccToolChain.OriginalTargetTriple"; -static const char supportedAbisKeyC[] = "ProjectExplorer.GccToolChain.SupportedAbis"; -static const char parentToolChainIdKeyC[] = "ProjectExplorer.ClangToolChain.ParentToolChainId"; -static const char binaryRegexp[] = "(?:^|-|\\b)(?:gcc|g\\+\\+|clang(?:\\+\\+)?)(?:-([\\d.]+))?$"; +const char compilerPlatformCodeGenFlagsKeyC[] = "ProjectExplorer.GccToolChain.PlatformCodeGenFlags"; +const char compilerPlatformLinkerFlagsKeyC[] = "ProjectExplorer.GccToolChain.PlatformLinkerFlags"; +const char targetAbiKeyC[] = "ProjectExplorer.GccToolChain.TargetAbi"; +const char originalTargetTripleKeyC[] = "ProjectExplorer.GccToolChain.OriginalTargetTriple"; +const char supportedAbisKeyC[] = "ProjectExplorer.GccToolChain.SupportedAbis"; +const char parentToolChainIdKeyC[] = "ProjectExplorer.ClangToolChain.ParentToolChainId"; +const char binaryRegexp[] = "(?:^|-|\\b)(?:gcc|g\\+\\+|clang(?:\\+\\+)?)(?:-([\\d.]+))?$"; -static QByteArray runGcc(const FilePath &gcc, const QStringList &arguments, const Environment &env) +static QString runGcc(const FilePath &gcc, const QStringList &arguments, const Environment &env) { if (!gcc.isExecutableFile()) - return QByteArray(); + return {}; QtcProcess cpp; Environment environment(env); @@ -150,11 +150,11 @@ static QByteArray runGcc(const FilePath &gcc, const QStringList &arguments, cons if (cpp.result() != ProcessResult::FinishedWithSuccess || cpp.exitCode() != 0) { Core::MessageManager::writeFlashing({"Compiler feature detection failure!", cpp.exitMessage(), - QString::fromUtf8(cpp.allRawOutput())}); - return QByteArray(); + cpp.allOutput()}); + return {}; } - return cpp.allOutput().toUtf8(); + return cpp.allOutput(); } static ProjectExplorer::Macros gccPredefinedMacros(const FilePath &gcc, @@ -164,7 +164,7 @@ static ProjectExplorer::Macros gccPredefinedMacros(const FilePath &gcc, QStringList arguments = args; arguments << "-"; - ProjectExplorer::Macros predefinedMacros = Macro::toMacros(runGcc(gcc, arguments, env)); + ProjectExplorer::Macros predefinedMacros = Macro::toMacros(runGcc(gcc, arguments, env).toUtf8()); // Sanity check in case we get an error message instead of real output: QTC_CHECK(predefinedMacros.isEmpty() || predefinedMacros.front().type == ProjectExplorer::MacroType::Define); @@ -189,7 +189,7 @@ HeaderPaths GccToolChain::gccHeaderPaths(const FilePath &gcc, { HeaderPaths builtInHeaderPaths; QByteArray line; - QByteArray data = runGcc(gcc, arguments, env); + QByteArray data = runGcc(gcc, arguments, env).toUtf8(); QBuffer cpp(&data); cpp.open(QIODevice::ReadOnly); while (cpp.canReadLine()) { @@ -277,7 +277,7 @@ static GccToolChain::DetectedAbisResult guessGccAbi(const FilePath &path, QStringList arguments = extraArgs; arguments << "-dumpmachine"; - QString machine = QString::fromUtf8(runGcc(path, arguments, env)).trimmed().section('\n', 0, 0, QString::SectionSkipEmpty); + QString machine = runGcc(path, arguments, env).trimmed().section('\n', 0, 0, QString::SectionSkipEmpty); if (machine.isEmpty()) { // ICC does not implement the -dumpmachine option on macOS. if (HostOsInfo::isMacHost() && (path.fileName() == "icc" || path.fileName() == "icpc")) @@ -293,7 +293,7 @@ static QString gccVersion(const FilePath &path, { QStringList arguments = extraArgs; arguments << "-dumpversion"; - return QString::fromUtf8(runGcc(path, arguments, env)).trimmed(); + return runGcc(path, arguments, env).trimmed(); } static FilePath gccInstallDir(const FilePath &compiler, @@ -302,7 +302,7 @@ static FilePath gccInstallDir(const FilePath &compiler, { QStringList arguments = extraArgs; arguments << "-print-search-dirs"; - QString output = QString::fromUtf8(runGcc(compiler, arguments, env)).trimmed(); + QString output = runGcc(compiler, arguments, env).trimmed(); // Expected output looks like this: // install: /usr/lib/gcc/x86_64-linux-gnu/7/ // ... From 8a83938886b33af8f8eb734eaac24e48c4395021 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Fri, 1 Jul 2022 11:24:19 +0200 Subject: [PATCH 92/96] Android: Fix OS-specific parsing in parseDependenciesJson The Linux-specific sdk_essential_packages should not be installed if on Windows. Change-Id: I6b13a131785c7a76a35abf282dacdf915781e6d1 Reviewed-by: Assam Boudjelthia Reviewed-by: --- src/plugins/android/androidconfigurations.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index 63c3ee7c7b0..c4942aee3ff 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -336,7 +336,7 @@ void AndroidConfig::parseDependenciesJson() if (HostOsInfo::isWindowsHost()) appendEssentialsFromArray(commonEssentials[WindowsOsKey].toArray()); - if (HostOsInfo::isMacHost()) + else if (HostOsInfo::isMacHost()) appendEssentialsFromArray(commonEssentials[macOsKey].toArray()); else appendEssentialsFromArray(commonEssentials[LinuxOsKey].toArray()); From b5a34902d0258e7cdc839205020bbd41fc8d87e6 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Fri, 1 Jul 2022 09:36:05 +0200 Subject: [PATCH 93/96] QmlDesigner: Remove QTC_ASSERT This crashes if edit3DWidget() is null and we check below. Change-Id: If993b73461fb442fb6d668ba9fc15c46ea763a11 Reviewed-by: Thomas Hartmann --- src/plugins/qmldesigner/components/edit3d/edit3dview.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp index 383af0aa91e..cc6058782ed 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp @@ -210,8 +210,6 @@ void Edit3DView::modelAttached(Model *model) void Edit3DView::modelAboutToBeDetached(Model *model) { - QTC_ASSERT(edit3DWidget()->canvas(), return); - // Hide the canvas when model is detached (i.e. changing documents) if (edit3DWidget() && edit3DWidget()->canvas()) { m_canvasCache.insert(model, edit3DWidget()->canvas()->renderImage()); From 5a9a6804eeae5d2b3e75c739b0f65781657f9d34 Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Fri, 1 Jul 2022 11:35:09 +0300 Subject: [PATCH 94/96] QmlDesigner: Implement drag-n-drop materials to the 3D Editor Fixes: QDS-7011 Change-Id: Id6e4aea2c19561ea861507480636ae2358ece067 Reviewed-by: Miikka Heikkinen Reviewed-by: Thomas Hartmann --- .../commands/puppettocreatorcommand.h | 1 + .../qmlpuppet/commands/view3dactioncommand.h | 3 ++- .../qt5informationnodeinstanceserver.cpp | 26 +++++++++++++++++++ .../components/edit3d/edit3dview.cpp | 15 +++++++++++ .../components/edit3d/edit3dview.h | 5 ++-- .../components/edit3d/edit3dwidget.cpp | 18 ++++++++++++- .../designercore/include/abstractview.h | 2 ++ .../instances/nodeinstanceview.cpp | 4 +++ .../designercore/model/abstractview.cpp | 9 +++++++ .../qmldesigner/designercore/model/model.cpp | 5 ++++ .../qmldesigner/designercore/model/model_p.h | 1 + 11 files changed, 85 insertions(+), 4 deletions(-) diff --git a/share/qtcreator/qml/qmlpuppet/commands/puppettocreatorcommand.h b/share/qtcreator/qml/qmlpuppet/commands/puppettocreatorcommand.h index cfe4529ba1b..95ca0d3ce25 100644 --- a/share/qtcreator/qml/qmlpuppet/commands/puppettocreatorcommand.h +++ b/share/qtcreator/qml/qmlpuppet/commands/puppettocreatorcommand.h @@ -40,6 +40,7 @@ public: ActiveSceneChanged, RenderModelNodePreviewImage, Import3DSupport, + ModelAtPos, None }; PuppetToCreatorCommand(Type type, const QVariant &data); diff --git a/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h b/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h index a1dc133032e..13d39739437 100644 --- a/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h +++ b/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h @@ -59,9 +59,10 @@ public: SelectBackgroundColor, SelectGridColor, ResetBackgroundColor, + GetModelAtPos }; - explicit View3DActionCommand(Type type, const QVariant &value); + View3DActionCommand(Type type, const QVariant &value); View3DActionCommand() = default; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp index 0d351214561..4448e2cee1f 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp @@ -2319,6 +2319,32 @@ void Qt5InformationNodeInstanceServer::view3DAction(const View3DActionCommand &c m_particleAnimationDriver->setSeekerPosition(static_cast(command).position()); break; #endif +#ifdef QUICK3D_MODULE + case View3DActionCommand::GetModelAtPos: { + // pick a Quick3DModel at view position + auto helper = qobject_cast(m_3dHelper); + if (!helper) + return; + + QQmlProperty editViewProp(m_editView3DData.rootItem, "editView", context()); + QObject *obj = qvariant_cast(editViewProp.read()); + QQuick3DViewport *editView = qobject_cast(obj); + + QPointF pos = command.value().toPointF(); + QQuick3DModel *hitModel = helper->pickViewAt(editView, pos.x(), pos.y()).objectHit(); + + // filter out picks of models created dynamically or inside components + QQuick3DModel *resolvedPick = qobject_cast(helper->resolvePick(hitModel)); + + if (resolvedPick) { + ServerNodeInstance instance = instanceForObject(resolvedPick); + nodeInstanceClient()->handlePuppetToCreatorCommand( + {PuppetToCreatorCommand::ModelAtPos, QVariant(instance.instanceId())}); + } + return; + } +#endif + default: break; } diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp index cc6058782ed..bcce905b4fa 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp @@ -239,6 +239,16 @@ void Edit3DView::customNotification(const AbstractView *view, const QString &ide resetPuppet(); } +void Edit3DView::modelAtPosReady(const ModelNode &modelNode) +{ + if (!m_droppedMaterial.isValid() || !modelNode.isValid()) + return; + + executeInTransaction(__FUNCTION__, [&] { + assignMaterialTo3dModel(modelNode, m_droppedMaterial); + }); +} + void Edit3DView::sendInputEvent(QInputEvent *e) const { if (nodeInstanceView()) @@ -605,5 +615,10 @@ void Edit3DView::addQuick3DImport() tr("Could not add QtQuick3D import to project.")); } +void Edit3DView::dropMaterial(const ModelNode &matNode, const QPointF &pos) +{ + m_droppedMaterial = matNode; + QmlDesignerPlugin::instance()->viewManager().nodeInstanceView()->view3DAction({View3DActionCommand::GetModelAtPos, pos}); } +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.h b/src/plugins/qmldesigner/components/edit3d/edit3dview.h index b817c20d1a4..4d96a7549f3 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dview.h +++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.h @@ -64,6 +64,7 @@ public: void modelAboutToBeDetached(Model *model) override; void importsChanged(const QList &addedImports, const QList &removedImports) override; void customNotification(const AbstractView *view, const QString &identifier, const QList &nodeList, const QList &data) override; + void modelAtPosReady(const ModelNode &modelNode) override; void sendInputEvent(QInputEvent *e) const; void edit3DViewResized(const QSize &size) const; @@ -78,8 +79,7 @@ public: void setSeeker(SeekerSlider *slider); void addQuick3DImport(); - -protected: + void dropMaterial(const ModelNode &matNode, const QPointF &pos); private: void createEdit3DWidget(); @@ -118,6 +118,7 @@ private: SeekerSlider *m_seeker = nullptr; int particlemode; ModelCache m_canvasCache; + ModelNode m_droppedMaterial; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp index afa05dd67e2..a6672b9f164 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp @@ -242,12 +242,28 @@ void Edit3DWidget::dragEnterEvent(QDragEnterEvent *dragEnterEvent) { const DesignerActionManager &actionManager = QmlDesignerPlugin::instance() ->viewManager().designerActionManager(); - if (actionManager.externalDragHasSupportedAssets(dragEnterEvent->mimeData())) + if (actionManager.externalDragHasSupportedAssets(dragEnterEvent->mimeData()) + || dragEnterEvent->mimeData()->hasFormat(Constants::MIME_TYPE_MATERIAL)) { dragEnterEvent->acceptProposedAction(); + } } void Edit3DWidget::dropEvent(QDropEvent *dropEvent) { + // handle dropping materials + if (dropEvent->mimeData()->hasFormat(Constants::MIME_TYPE_MATERIAL)) { + QByteArray data = dropEvent->mimeData()->data(Constants::MIME_TYPE_MATERIAL); + QDataStream stream(data); + qint32 internalId; + stream >> internalId; + ModelNode matNode = m_view->modelNodeForInternalId(internalId); + + if (matNode.isValid()) + m_view->dropMaterial(matNode, dropEvent->position()); + return; + } + + // handle dropping external assets const DesignerActionManager &actionManager = QmlDesignerPlugin::instance() ->viewManager().designerActionManager(); QHash addedAssets = actionManager.handleExternalAssetsDrop(dropEvent->mimeData()); diff --git a/src/plugins/qmldesigner/designercore/include/abstractview.h b/src/plugins/qmldesigner/designercore/include/abstractview.h index 890b5c0e9cf..3c4eca04413 100644 --- a/src/plugins/qmldesigner/designercore/include/abstractview.h +++ b/src/plugins/qmldesigner/designercore/include/abstractview.h @@ -165,6 +165,7 @@ public: void emitUpdateActiveScene3D(const QVariantMap &sceneState); void emitModelNodelPreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap); void emitImport3DSupportChanged(const QVariantMap &supportMap); + void emitModelAtPosResult(const ModelNode &modelNode); void sendTokenToInstances(const QString &token, int number, const QVector &nodeVector); @@ -229,6 +230,7 @@ public: virtual void renderImage3DChanged(const QImage &image); virtual void updateActiveScene3D(const QVariantMap &sceneState); virtual void updateImport3DSupport(const QVariantMap &supportMap); + virtual void modelAtPosReady(const ModelNode &modelNode); virtual void modelNodePreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap); virtual void dragStarted(QMimeData *mimeData); diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp index 6a7ad61276d..f92df89a9db 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp @@ -1691,6 +1691,10 @@ void NodeInstanceView::handlePuppetToCreatorCommand(const PuppetToCreatorCommand } else if (command.type() == PuppetToCreatorCommand::Import3DSupport) { const QVariantMap supportMap = qvariant_cast(command.data()); emitImport3DSupportChanged(supportMap); + } else if (command.type() == PuppetToCreatorCommand::ModelAtPos) { + ModelNode modelNode = modelNodeForInternalId(command.data().toUInt()); + if (modelNode.isValid()) + emitModelAtPosResult(modelNode); } } diff --git a/src/plugins/qmldesigner/designercore/model/abstractview.cpp b/src/plugins/qmldesigner/designercore/model/abstractview.cpp index 23c018f7cb3..310dcdcdab1 100644 --- a/src/plugins/qmldesigner/designercore/model/abstractview.cpp +++ b/src/plugins/qmldesigner/designercore/model/abstractview.cpp @@ -403,6 +403,9 @@ void AbstractView::updateImport3DSupport(const QVariantMap & /*supportMap*/) { } +// a Quick3DModel that is picked at the requested position in the 3D Editor +void AbstractView::modelAtPosReady(const ModelNode & /*modelNode*/) {} + void AbstractView::modelNodePreviewPixmapChanged(const ModelNode & /*node*/, const QPixmap & /*pixmap*/) { } @@ -794,6 +797,12 @@ void AbstractView::emitImport3DSupportChanged(const QVariantMap &supportMap) model()->d->notifyImport3DSupportChanged(supportMap); } +void AbstractView::emitModelAtPosResult(const ModelNode &modelNode) +{ + if (model()) + model()->d->notifyModelAtPosResult(modelNode); +} + void AbstractView::emitRewriterEndTransaction() { if (model()) diff --git a/src/plugins/qmldesigner/designercore/model/model.cpp b/src/plugins/qmldesigner/designercore/model/model.cpp index bd92ac643fb..772149a33d9 100644 --- a/src/plugins/qmldesigner/designercore/model/model.cpp +++ b/src/plugins/qmldesigner/designercore/model/model.cpp @@ -589,6 +589,11 @@ void ModelPrivate::notifyImport3DSupportChanged(const QVariantMap &supportMap) notifyInstanceChanges([&](AbstractView *view) { view->updateImport3DSupport(supportMap); }); } +void ModelPrivate::notifyModelAtPosResult(const ModelNode &modelNode) +{ + notifyInstanceChanges([&](AbstractView *view) { view->modelAtPosReady(modelNode); }); +} + void ModelPrivate::notifyDragStarted(QMimeData *mimeData) { notifyInstanceChanges([&](AbstractView *view) { view->dragStarted(mimeData); }); diff --git a/src/plugins/qmldesigner/designercore/model/model_p.h b/src/plugins/qmldesigner/designercore/model/model_p.h index 09595670534..c6ed24f681f 100644 --- a/src/plugins/qmldesigner/designercore/model/model_p.h +++ b/src/plugins/qmldesigner/designercore/model/model_p.h @@ -182,6 +182,7 @@ public: void notifyUpdateActiveScene3D(const QVariantMap &sceneState); void notifyModelNodePreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap); void notifyImport3DSupportChanged(const QVariantMap &supportMap); + void notifyModelAtPosResult(const ModelNode &modelNode); void notifyDragStarted(QMimeData *mimeData); void notifyDragEnded(); From 866f16adb1aaff5c8e2d4a61625dc480e432cd0d Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Fri, 1 Jul 2022 17:03:45 +0200 Subject: [PATCH 95/96] QmlDesigner: Fix TextEditorView::reformatFile * Updating the document only if it actually changed * Using the text cursor of the widget * We can rely on the widget to exist * Simplify how the cursor is restored Task-number: QDS-6410 Change-Id: Idaa384533f12b9b7ad7078bcdc37c1afaf651662 Reviewed-by: Qt CI Bot Reviewed-by: Reviewed-by: Thomas Hartmann --- .../components/texteditor/texteditorview.cpp | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/plugins/qmldesigner/components/texteditor/texteditorview.cpp b/src/plugins/qmldesigner/components/texteditor/texteditorview.cpp index efec8afd9c7..077a6e14c36 100644 --- a/src/plugins/qmldesigner/components/texteditor/texteditorview.cpp +++ b/src/plugins/qmldesigner/components/texteditor/texteditorview.cpp @@ -52,6 +52,7 @@ #include #include #include +#include #include #include @@ -258,12 +259,7 @@ void TextEditorView::gotoCursorPosition(int line, int column) void TextEditorView::reformatFile() { - int oldLine = -1; - - if (m_widget) - oldLine = m_widget->currentLine(); - - QByteArray editorState = m_widget->textEditor()->saveState(); + QTC_ASSERT(!m_widget.isNull(), return); auto document = qobject_cast(Core::EditorManager::currentDocument()); @@ -292,16 +288,21 @@ void TextEditorView::reformatFile() return; const QString &newText = QmlJS::reformat(currentDocument); - QTextCursor tc(document->document()); + if (currentDocument->source() == newText) + return; + + QTextCursor tc = m_widget->textEditor()->textCursor(); + int pos = m_widget->textEditor()->textCursor().position(); Utils::ChangeSet changeSet; changeSet.replace(0, document->plainText().length(), newText); + + tc.beginEditBlock(); changeSet.apply(&tc); + tc.setPosition(pos); + tc.endEditBlock(); - m_widget->textEditor()->restoreState(editorState); - - if (m_widget) - m_widget->gotoCursorPosition(oldLine, 0); + m_widget->textEditor()->setTextCursor(tc); } } From 4180e1b84f43cc39119e003457f76be518588107 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Sun, 3 Jul 2022 10:40:38 +0300 Subject: [PATCH 96/96] CodeAssist: Fix Coverity issues * Initialize m_reason in IAssistProposal. * Remove superfluous null validations. Change-Id: Icb9b7a7a98db719540586142e30be75f37a4ab92 Reviewed-by: Reviewed-by: David Schulz --- src/plugins/texteditor/codeassist/codeassistant.cpp | 4 ++-- src/plugins/texteditor/codeassist/iassistproposal.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/texteditor/codeassist/codeassistant.cpp b/src/plugins/texteditor/codeassist/codeassistant.cpp index 50b5626ca76..22c937ac1c8 100644 --- a/src/plugins/texteditor/codeassist/codeassistant.cpp +++ b/src/plugins/texteditor/codeassist/codeassistant.cpp @@ -270,13 +270,13 @@ void CodeAssistantPrivate::requestProposal(AssistReason reason, if (processor != m_asyncProcessor) return; invalidateCurrentRequestData(); - if (processor && processor->needsRestart() && m_receivedContentWhileWaiting) { + if (processor->needsRestart() && m_receivedContentWhileWaiting) { delete newProposal; m_receivedContentWhileWaiting = false; requestProposal(reason, m_assistKind, m_requestProvider); } else { displayProposal(newProposal, reason); - if (processor && processor->running()) + if (processor->running()) m_asyncProcessor = processor; else emit q->finished(); diff --git a/src/plugins/texteditor/codeassist/iassistproposal.h b/src/plugins/texteditor/codeassist/iassistproposal.h index 1393cbab835..feb92caf9f2 100644 --- a/src/plugins/texteditor/codeassist/iassistproposal.h +++ b/src/plugins/texteditor/codeassist/iassistproposal.h @@ -65,7 +65,7 @@ protected: int m_basePosition; bool m_isFragile = false; bool m_supportsPrefix = true; - AssistReason m_reason; + AssistReason m_reason = IdleEditor; }; } // TextEditor