diff options
author | Eike Ziller <eike.ziller@qt.io> | 2020-03-23 09:35:54 +0100 |
---|---|---|
committer | Eike Ziller <eike.ziller@qt.io> | 2020-03-23 09:35:54 +0100 |
commit | ee2840d5b8d37979ece2126055baf4678df8b312 (patch) | |
tree | 5847c57c571e905d2e1a54ce3244de1d47ce6ecc | |
parent | 80a766a2cbffdedc975f6ed3ebe225bfcfb433d9 (diff) | |
parent | e3581a3961dd4298122a8ede9488af11f2acfa08 (diff) |
Merge remote-tracking branch 'origin/4.12'
Change-Id: Ic741fdedc168430e5be6cb1645d9329dbc7a6b08
28 files changed, 361 insertions, 187 deletions
diff --git a/.github/workflows/build_cmake.yml b/.github/workflows/build_cmake.yml index 5722143c04..f409216afb 100644 --- a/.github/workflows/build_cmake.yml +++ b/.github/workflows/build_cmake.yml @@ -333,7 +333,7 @@ jobs: -D WITH_TESTS=ON -D IDE_REVISION=TRUE -D IDE_REVISION_STR=$ENV{GITHUB_SHA} - -D IDE_REVISION_URL_STR=https://github.com/$ENV{GITHUB_REPOSITORY}/commits/$ENV{GITHUB_SHA} + -D IDE_REVISION_URL=https://github.com/$ENV{GITHUB_REPOSITORY}/commits/$ENV{GITHUB_SHA} RESULT_VARIABLE result COMMAND_ECHO STDOUT ) diff --git a/CMakeLists.txt b/CMakeLists.txt index cb79a450f0..9cf66c74aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,9 +8,9 @@ include(QtCreatorIDEBranding) set(IDE_REVISION FALSE CACHE BOOL "Marks the presence of IDE revision string.") set(IDE_REVISION_STR "" CACHE STRING "The IDE revision string.") -set(IDE_REVISION_URL_STR "" CACHE STRING "The IDE revision Url string.") +set(IDE_REVISION_URL "" CACHE STRING "The IDE revision Url string.") -mark_as_advanced(IDE_REVISION IDE_REVISION_STR IDE_REVISION_URL_STR) +mark_as_advanced(IDE_REVISION IDE_REVISION_STR IDE_REVISION_URL) project(QtCreator VERSION ${IDE_VERSION}) diff --git a/scripts/build.py b/scripts/build.py index ec50a21b8e..3c48136239 100755 --- a/scripts/build.py +++ b/scripts/build.py @@ -131,7 +131,7 @@ def build_qtcreator(args, paths): if ide_revision: cmake_args += ['-DIDE_REVISION=ON', '-DIDE_REVISION_STR=' + ide_revision, - '-DIDE_REVISION_URL_STR=https://code.qt.io/cgit/qt-creator/qt-creator.git/log/?id=' + ide_revision] + '-DIDE_REVISION_URL=https://code.qt.io/cgit/qt-creator/qt-creator.git/log/?id=' + ide_revision] common.check_print_call(cmake_args + [paths.src], paths.build) common.check_print_call(['cmake', '--build', '.'], paths.build) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/selectionboxgeometry.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/selectionboxgeometry.cpp index 8b6d0b1fde..621508c499 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/selectionboxgeometry.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/selectionboxgeometry.cpp @@ -95,9 +95,9 @@ void SelectionBoxGeometry::setTargetNode(QQuick3DNode *targetNode) if (auto model = qobject_cast<QQuick3DModel *>(m_targetNode)) { QObject::connect(model, &QQuick3DModel::sourceChanged, - this, &SelectionBoxGeometry::update, Qt::QueuedConnection); + this, &SelectionBoxGeometry::targetMeshUpdated, Qt::QueuedConnection); QObject::connect(model, &QQuick3DModel::geometryChanged, - this, &SelectionBoxGeometry::update, Qt::QueuedConnection); + this, &SelectionBoxGeometry::targetMeshUpdated, Qt::QueuedConnection); } if (m_targetNode) { QObject::connect(m_targetNode, &QQuick3DNode::parentChanged, @@ -132,6 +132,14 @@ void SelectionBoxGeometry::setView3D(QQuick3DViewport *view) QSSGRenderGraphObject *SelectionBoxGeometry::updateSpatialNode(QSSGRenderGraphObject *node) { + // If target node mesh has been updated, we need to defer updating the box geometry + // to the next frame to ensure target node geometry has been updated + if (m_meshUpdatePending) { + QTimer::singleShot(0, this, &SelectionBoxGeometry::update); + m_meshUpdatePending = false; + return node; + } + node = QQuick3DGeometry::updateSpatialNode(node); QSSGRenderGeometry *geometry = static_cast<QSSGRenderGeometry *>(node); @@ -163,10 +171,13 @@ QSSGRenderGraphObject *SelectionBoxGeometry::updateSpatialNode(QSSGRenderGraphOb rootRN->localTransform = m; rootRN->markDirty(QSSGRenderNode::TransformDirtyFlag::TransformNotDirty); rootRN->calculateGlobalVariables(); - m_asyncUpdatePending = false; - } else if (!m_asyncUpdatePending) { - m_asyncUpdatePending = true; + m_spatialNodeUpdatePending = false; + } else if (!m_spatialNodeUpdatePending) { + m_spatialNodeUpdatePending = true; // A necessary spatial node doesn't yet exist. Defer selection box creation one frame. + // Note: We don't share pending flag with target mesh update, which is checked and + // cleared at the beginning of this method, as there would be potential for an endless + // loop in case we can't ever resolve one of the spatial nodes. QTimer::singleShot(0, this, &SelectionBoxGeometry::update); return node; } @@ -376,6 +387,12 @@ void SelectionBoxGeometry::trackNodeChanges(QQuick3DNode *node) this, &SelectionBoxGeometry::update, Qt::QueuedConnection); } +void SelectionBoxGeometry::targetMeshUpdated() +{ + m_meshUpdatePending = true; + update(); +} + } } diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/selectionboxgeometry.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/selectionboxgeometry.h index a267a47585..6cf9a153c2 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/selectionboxgeometry.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/selectionboxgeometry.h @@ -74,6 +74,7 @@ private: void appendVertexData(const QMatrix4x4 &m, QByteArray &vertexData, QByteArray &indexData, const QVector3D &minBounds, const QVector3D &maxBounds); void trackNodeChanges(QQuick3DNode *node); + void targetMeshUpdated(); QQuick3DNode *m_targetNode = nullptr; QQuick3DViewport *m_view3D = nullptr; @@ -81,7 +82,8 @@ private: bool m_isEmpty = true; QVector<QMetaObject::Connection> m_connections; QSSGBounds3 m_bounds; - bool m_asyncUpdatePending = false; + bool m_spatialNodeUpdatePending = false; + bool m_meshUpdatePending = false; }; } diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp index e3d97db879..253147de02 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp @@ -1158,6 +1158,7 @@ void Qt5InformationNodeInstanceServer::inputEvent(const InputEventCommand &comma void Qt5InformationNodeInstanceServer::view3DAction(const View3DActionCommand &command) { QVariantMap updatedState; + int renderCount = 1; switch (command.type()) { case View3DActionCommand::MoveTool: @@ -1177,6 +1178,8 @@ void Qt5InformationNodeInstanceServer::view3DAction(const View3DActionCommand &c break; case View3DActionCommand::CameraToggle: updatedState.insert("usePerspective", command.isEnabled()); + // It can take a couple frames to properly update icon gizmo positions, so render 3 frames + renderCount = 3; break; case View3DActionCommand::OrientationToggle: updatedState.insert("globalOrientation", command.isEnabled()); @@ -1194,7 +1197,7 @@ void Qt5InformationNodeInstanceServer::view3DAction(const View3DActionCommand &c Q_ARG(QVariant, QVariant::fromValue(false))); } - render3DEditView(); + render3DEditView(renderCount); } void Qt5InformationNodeInstanceServer::changeAuxiliaryValues(const ChangeAuxiliaryCommand &command) diff --git a/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesDelegate.qml b/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesDelegate.qml index 135740c01d..1d1d65bed7 100644 --- a/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesDelegate.qml +++ b/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesDelegate.qml @@ -41,7 +41,7 @@ Rectangle { property string delegateWhenConditionString readonly property bool isDefaultState: isDefault - color: (isDefaultState || (isBaseState && !modelHasDefaultState)) ? Qt.lighter(baseColor, 1.5) : baseColor + color: baseColor border.color: Theme.qmlDesignerBorderColor() function autoComplete(text, pos, explicitComplete, filter) { @@ -81,7 +81,12 @@ Rectangle { width: 16 visible: !isBaseState - onClicked: root.deleteState(internalNodeId) + onClicked: { + if (isDefaultState) + statesEditorModel.resetDefaultState() + + root.deleteState(internalNodeId) + } } Image { @@ -155,7 +160,17 @@ Rectangle { anchors.leftMargin: 4 anchors.right: removeStateButton.left anchors.rightMargin: 4 - style: DesignerTextFieldStyle {} + style: DesignerTextFieldStyle { + background: Rectangle { + implicitWidth: 100 + implicitHeight: font.pixelSize + padding.top + padding.bottom + color: ((isBaseState && modelHasDefaultState) ? "transparent" + : Theme.color(Theme.FancyToolButtonSelectedColor)) + border.color: ((isBaseState && !modelHasDefaultState) || isDefaultState) ? "#ffd700" + : (isBaseState && modelHasDefaultState) ? "transparent" + : Theme.qmlDesignerBackgroundColorDarker() + } + } readOnly: isBaseState onActiveFocusChanged: { @@ -165,8 +180,6 @@ Rectangle { Component.onCompleted: { text = delegateStateName - if (isBaseState) - __panel.visible = false } property string oldValue @@ -184,7 +197,7 @@ Rectangle { Item { id: stateImageArea - anchors.topMargin: 4 + anchors.topMargin: 2 anchors.horizontalCenter: parent.horizontalCenter anchors.top: stateNameField.bottom diff --git a/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesList.qml b/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesList.qml index a1fce752bd..c512b7098a 100644 --- a/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesList.qml +++ b/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesList.qml @@ -41,7 +41,7 @@ FocusScope { property int delegateWidth: stateImageSize + 44 property int padding: 2 property int delegateHeight: root.height - padding * 2 + 1 - property int innerSpacing: -1 + property int innerSpacing: 0 property int currentStateInternalId : 0 property bool expanded: true diff --git a/src/app/app_version.h.cmakein b/src/app/app_version.h.cmakein index 6d69f0d5de..49abfc4ec8 100644 --- a/src/app/app_version.h.cmakein +++ b/src/app/app_version.h.cmakein @@ -45,7 +45,7 @@ const char IDE_CASED_ID[] = "${IDE_CASED_ID}"; const char IDE_VERSION_DISPLAY[] = "${IDE_VERSION_DISPLAY}"; const char IDE_VERSION_COMPAT[] = "${IDE_VERSION_COMPAT}"; const char IDE_REVISION_STR[] = "${IDE_REVISION_STR}"; -const char IDE_REVISION_URL_STR[] = "${IDE_REVISION_URL_STR}"; +const char IDE_REVISION_URL[] = "${IDE_REVISION_URL}"; // changes the path where the settings are saved to const char IDE_SETTINGSVARIANT_STR[] = "${IDE_SETTINGSVARIANT}"; diff --git a/src/app/app_version.h.in b/src/app/app_version.h.in index 4682d282ef..7a525bf211 100644 --- a/src/app/app_version.h.in +++ b/src/app/app_version.h.in @@ -56,11 +56,7 @@ const char IDE_REVISION_STR[] = STRINGIFY(IDE_REVISION); const char IDE_REVISION_STR[] = \"\"; #endif -#ifdef IDE_REVISION_URL -const char IDE_REVISION_URL_STR[] = STRINGIFY(IDE_REVISION_URL); -#else -const char IDE_REVISION_URL_STR[] = \"\"; -#endif +const char IDE_REVISION_URL[] = \"$${IDE_REVISION_URL}\"; // changes the path where the settings are saved to #ifdef IDE_SETTINGSVARIANT diff --git a/src/plugins/coreplugin/documentmanager.cpp b/src/plugins/coreplugin/documentmanager.cpp index 993c2244fb..f7a8340d9e 100644 --- a/src/plugins/coreplugin/documentmanager.cpp +++ b/src/plugins/coreplugin/documentmanager.cpp @@ -71,29 +71,47 @@ static Q_LOGGING_CATEGORY(log, "qtc.core.documentmanager", QtWarningMsg) /*! \class Core::DocumentManager - \mainclass + \ingroup mainclasses + \inmodule QtCreator \inheaderfile documentmanager.h - \brief The DocumentManager class manages a set of IDocument objects. - - The DocumentManager service monitors a set of IDocument objects. Plugins - should register files they work with at the service. The files the IDocument - objects point to will be monitored at filesystem level. If a file changes, - the status of the IDocument object - will be adjusted accordingly. Furthermore, on application exit the user will - be asked to save all modified files. + \brief The DocumentManager class manages a set of documents. + + The DocumentManager service monitors a set of IDocument objects. + + This section uses the following terminology: + + \list + \li A \e file means a collection of data stored on a disk under a name + (that is, the usual meaning of the term \e file in computing). + \li A \e document holds content open in Qt Creator. If it corresponds to a + file, it might differ from it, because it was modified. But a document + might not correspond to a file at all. For example, diff viewer + documents or Git blame or log records are created and displayed by + Qt Creator upon request. + \li An \a editor provides a view into a document that is actually visible + to the user and potentially allows editing the document. Multiple + editors can open views into the same document. + \endlist + + Plugins should register documents they work with at the document management + service. The files the IDocument objects point to will be monitored at + file system level. If a file changes on disk, the status of the IDocument + object will be adjusted accordingly. On application exit the user will be + asked to save all modified documents. Different IDocument objects in the set can point to the same file in the - filesystem. The monitoring for an IDocument can be blocked by - \c blockFileChange(), and enabled again by \c unblockFileChange(). + file system. The monitoring for an IDocument can be blocked by + using the \l Core::FileChangeBlocker class. The functions \c expectFileChange() and \c unexpectFileChange() mark a file change as expected. On expected file changes all IDocument objects are notified to reload themselves. - The DocumentManager service also provides two convenience functions for saving - files: \c saveModifiedFiles() and \c saveModifiedFilesSilently(). Both take a list - of FileInterfaces as an argument, and return the list of files which were - _not_ saved. + The DocumentManager service also provides convenience functions + for saving documents, such as \l saveModifiedDocuments() and + \l saveModifiedDocumentsSilently(). They present users with a + dialog that lists all modified documents and asks them which + documents should be saved. The service also manages the list of recent files to be shown to the user. @@ -315,9 +333,9 @@ static void addFileInfo(IDocument *document) } /*! - Adds a list of IDocument's to the collection. If \a addWatcher is true (the default), - the files are added to a file system watcher that notifies the file manager - about file changes. + Adds a list of \a documents to the collection. If \a addWatcher is \c true + (the default), the documents' files are added to a file system watcher that + notifies the document manager about file changes. */ void DocumentManager::addDocuments(const QList<IDocument *> &documents, bool addWatcher) { @@ -411,15 +429,17 @@ static void dump() */ /*! - Tells the file manager that a file has been renamed on disk from within \QC. + Tells the document manager that a file has been renamed from \a from to + \a to on disk from within \QC. Needs to be called right after the actual renaming on disk (that is, before - the file system - watcher can report the event during the next event loop run). \a from needs to be an absolute file path. + the file system watcher can report the event during the next event loop run). + + \a from needs to be an absolute file path. This will notify all IDocument objects pointing to that file of the rename - by calling \c IDocument::rename(), and update the cached time and permission - information to avoid annoying the user with "file has been removed" - popups. + by calling \l IDocument::setFilePath(), and update the cached time and + permission information to avoid annoying the user with \e {the file has + been removed} popups. */ void DocumentManager::renamedFile(const QString &from, const QString &to) { @@ -454,10 +474,9 @@ void DocumentManager::filePathChanged(const FilePath &oldName, const FilePath &n } /*! - Adds an IDocument object to the collection. If \a addWatcher is \c true - (the default), - the file is added to a file system watcher that notifies the file manager - about file changes. + Adds \a document to the collection. If \a addWatcher is \c true + (the default), the document's file is added to a file system watcher + that notifies the document manager about file changes. */ void DocumentManager::addDocument(IDocument *document, bool addWatcher) { @@ -473,10 +492,10 @@ void DocumentManager::documentDestroyed(QObject *obj) } /*! - Removes an IDocument object from the collection. + Removes \a document from the collection. - Returns \c true if the file specified by \a document had the \a addWatcher - argument to \a addDocument() set. + Returns \c true if the document had the \c addWatcher argument to + addDocument() set. */ bool DocumentManager::removeDocument(IDocument *document) { @@ -494,7 +513,7 @@ bool DocumentManager::removeDocument(IDocument *document) } /* Slot reacting on IDocument::changed. We need to check if the signal was sent - because the file was saved under different name. */ + because the document was saved under different name. */ void DocumentManager::checkForNewFileName() { auto document = qobject_cast<IDocument *>(sender()); @@ -528,8 +547,8 @@ QString DocumentManager::cleanAbsoluteFilePath(const QString &filePath, ResolveM /*! Returns a representation of \a filePath that can be used as a key for maps. - (A cleaned absolute file path in portable form, that is all lowercase - if the file system is case insensitive (in the host OS settings).) + It is a cleaned absolute file path in portable form, that is all lowercase + if the file system is case insensitive in the host OS settings. Resolves symlinks if \a resolveMode is ResolveLinks. */ QString DocumentManager::filePathKey(const QString &filePath, ResolveMode resolveMode) @@ -563,9 +582,9 @@ QList<IDocument *> DocumentManager::modifiedDocuments() } /*! - Any subsequent change to \a fileName is treated as an expected file change. + Treats any subsequent change to \a fileName as an expected file change. - \see DocumentManager::unexpectFileChange(const QString &fileName) + \sa unexpectFileChange() */ void DocumentManager::expectFileChange(const QString &fileName) { @@ -587,9 +606,9 @@ static void updateExpectedState(const QString &filePathKey) } /*! - Any changes to \a fileName are unexpected again. + Considers all changes to \a fileName unexpected again. - \see DocumentManager::expectFileChange(const QString &fileName) + \sa expectFileChange() */ void DocumentManager::unexpectFileChange(const QString &fileName) { @@ -808,7 +827,7 @@ QString DocumentManager::getSaveFileNameWithExtension(const QString &title, cons } /*! - Asks the user for a new file name (\gui {Save File As}) for \a document. + Asks the user for a new file name (\uicontrol {Save File As}) for \a document. */ QString DocumentManager::getSaveAsFileName(const IDocument *document) { @@ -842,15 +861,15 @@ QString DocumentManager::getSaveAsFileName(const IDocument *document) } /*! - Silently saves all documents and will return true if all modified documents were saved - successfully. + Silently saves all documents and returns \c true if all modified documents + are saved successfully. - This method will try to avoid showing dialogs to the user, but can do so anyway (e.g. if - a file is not writeable). + This method tries to avoid showing dialogs to the user, but can do so anyway + (e.g. if a file is not writeable). - \a Canceled will be set if the user canceled any of the dialogs that he interacted with. - \a FailedToClose will contain a list of documents that could not be saved if passed into the - method. + If users canceled any of the dialogs they interacted with, \a canceled + is set. If passed to the method, \a failedToClose returns a list of + documents that could not be saved. */ bool DocumentManager::saveAllModifiedDocumentsSilently(bool *canceled, QList<IDocument *> *failedToClose) @@ -859,14 +878,15 @@ bool DocumentManager::saveAllModifiedDocumentsSilently(bool *canceled, } /*! - Silently saves \a documents and will return true if all of them were saved successfully. + Silently saves \a documents and returns \c true if all of them were saved + successfully. - This method will try to avoid showing dialogs to the user, but can do so anyway (e.g. if - a file is not writeable). + This method tries to avoid showing dialogs to the user, but can do so anyway + (e.g. if a file is not writeable). - \a Canceled will be set if the user canceled any of the dialogs that he interacted with. - \a FailedToClose will contain a list of documents that could not be saved if passed into the - method. + If users canceled any of the dialogs they interacted with, \a canceled + is set. If passed to the method, \a failedToClose returns a list of + documents that could not be saved. */ bool DocumentManager::saveModifiedDocumentsSilently(const QList<IDocument *> &documents, bool *canceled, @@ -882,14 +902,15 @@ bool DocumentManager::saveModifiedDocumentsSilently(const QList<IDocument *> &do } /*! - Silently saves a \a document and will return true if it was saved successfully. + Silently saves \a document and returns \c true if it was saved successfully. - This method will try to avoid showing dialogs to the user, but can do so anyway (e.g. if - a file is not writeable). + This method tries to avoid showing dialogs to the user, but can do so anyway + (e.g. if a file is not writeable). + + If users canceled any of the dialogs they interacted with, \a canceled + is set. If passed to the method, \a failedToClose returns a list of + documents that could not be saved. - \a Canceled will be set if the user canceled any of the dialogs that he interacted with. - \a FailedToClose will contain a list of documents that could not be saved if passed into the - method. */ bool DocumentManager::saveModifiedDocumentSilently(IDocument *document, bool *canceled, QList<IDocument *> *failedToClose) @@ -898,17 +919,21 @@ bool DocumentManager::saveModifiedDocumentSilently(IDocument *document, bool *ca } /*! - Presents a dialog with all modified documents to the user and will ask him which of these - should be saved. + Presents a dialog with all modified documents to users and asks them which + of these should be saved. + + This method may show additional dialogs to the user, e.g. if a file is + not writeable. - This method may show additional dialogs to the user, e.g. if a file is not writeable). + The dialog text can be set using \a message. If users canceled any + of the dialogs they interacted with, \a canceled is set and the + method returns \c false. - The dialog text can be set using \a message. \a Canceled will be set if the user canceled any - of the dialogs that he interacted with (the method will also return false in this case). - The \a alwaysSaveMessage will show an additional checkbox asking in the dialog. The state of - this checkbox will be written into \a alwaysSave if set. - \a FailedToClose will contain a list of documents that could not be saved if passed into the - method. + The \a alwaysSaveMessage shows an additional checkbox in the dialog. + The state of this checkbox is written into \a alwaysSave if set. + + If passed to the method, \a failedToClose returns a list of + documents that could not be saved. */ bool DocumentManager::saveAllModifiedDocuments(const QString &message, bool *canceled, const QString &alwaysSaveMessage, bool *alwaysSave, @@ -919,16 +944,21 @@ bool DocumentManager::saveAllModifiedDocuments(const QString &message, bool *can } /*! - Presents a dialog with \a documents to the user and will ask him which of these should be saved. + Presents a dialog with \a documents to users and asks them which + of these should be saved. + + This method may show additional dialogs to the user, e.g. if a file is + not writeable. - This method may show additional dialogs to the user, e.g. if a file is not writeable). + The dialog text can be set using \a message. If users canceled any + of the dialogs they interacted with, \a canceled is set and the + method returns \c false. - The dialog text can be set using \a message. \a Canceled will be set if the user canceled any - of the dialogs that he interacted with (the method will also return false in this case). - The \a alwaysSaveMessage will show an additional checkbox asking in the dialog. The state of - this checkbox will be written into \a alwaysSave if set. - \a FailedToClose will contain a list of documents that could not be saved if passed into the - method. + The \a alwaysSaveMessage shows an additional checkbox in the dialog. + The state of this checkbox is written into \a alwaysSave if set. + + If passed to the method, \a failedToClose returns a list of + documents that could not be saved. */ bool DocumentManager::saveModifiedDocuments(const QList<IDocument *> &documents, const QString &message, bool *canceled, @@ -940,17 +970,21 @@ bool DocumentManager::saveModifiedDocuments(const QList<IDocument *> &documents, } /*! - Presents a dialog with the one \a document to the user and will ask him whether he wants it - saved. + Presents a dialog with the \a document to users and asks them whether + it should be saved. + + This method may show additional dialogs to the user, e.g. if a file is + not writeable. - This method may show additional dialogs to the user, e.g. if the file is not writeable). + The dialog text can be set using \a message. If users canceled any + of the dialogs they interacted with, \a canceled is set and the + method returns \c false. - The dialog text can be set using \a message. \a Canceled will be set if the user canceled any - of the dialogs that he interacted with (the method will also return false in this case). - The \a alwaysSaveMessage will show an additional checkbox asking in the dialog. The state of - this checkbox will be written into \a alwaysSave if set. - \a FailedToClose will contain a list of documents that could not be saved if passed into the - method. + The \a alwaysSaveMessage shows an additional checkbox in the dialog. + The state of this checkbox is written into \a alwaysSave if set. + + If passed to the method, \a failedToClose returns a list of + documents that could not be saved. */ bool DocumentManager::saveModifiedDocument(IDocument *document, const QString &message, bool *canceled, const QString &alwaysSaveMessage, bool *alwaysSave, @@ -969,7 +1003,7 @@ void DocumentManager::showFilePropertiesDialog(const FilePath &filePath) /*! Asks the user for a set of file names to be opened. The \a filters and \a selectedFilter arguments are interpreted like in - \c QFileDialog::getOpenFileNames(). \a pathIn specifies a path to open the + QFileDialog::getOpenFileNames(). \a pathIn specifies a path to open the dialog in if that is not overridden by the user's policy. */ @@ -1259,7 +1293,7 @@ void DocumentManager::checkForReload() /*! Adds the \a fileName to the list of recent files. Associates the file to be reopened with the editor that has the specified \a editorId, if possible. - \a editorId defaults to the empty id, which lets \QC figure out + \a editorId defaults to the empty ID, which lets \QC figure out the best editor itself. */ void DocumentManager::addToRecentFiles(const QString &fileName, Id editorId) @@ -1346,12 +1380,11 @@ void readSettings() /*! - Returns the initial directory for a new file dialog. If there is - a current file, uses that, otherwise if there is a default location for - new files, uses that, otherwise uses the last visited directory. + Returns the initial directory for a new file dialog. If there is a current + document associated with a file, uses that. Or if there is a default location + for new files, uses that. Otherwise, uses the last visited directory. - \sa setFileDialogLastVisitedDirectory - \sa setDefaultLocationForNewFiles + \sa setFileDialogLastVisitedDirectory(), setDefaultLocationForNewFiles() */ QString DocumentManager::fileDialogInitialDirectory() @@ -1366,9 +1399,9 @@ QString DocumentManager::fileDialogInitialDirectory() /*! - Sets the default location for new files + Returns the default location for new files. - \sa fileDialogInitialDirectory + \sa fileDialogInitialDirectory() */ QString DocumentManager::defaultLocationForNewFiles() { @@ -1376,7 +1409,7 @@ QString DocumentManager::defaultLocationForNewFiles() } /*! - Returns the default location for new files + Sets the default \a location for new files. */ void DocumentManager::setDefaultLocationForNewFiles(const QString &location) { @@ -1387,7 +1420,7 @@ void DocumentManager::setDefaultLocationForNewFiles(const QString &location) Returns the directory for projects. Defaults to HOME. - \sa setProjectsDirectory, setUseProjectsDirectory + \sa setProjectsDirectory(), setUseProjectsDirectory() */ FilePath DocumentManager::projectsDirectory() @@ -1397,9 +1430,9 @@ FilePath DocumentManager::projectsDirectory() /*! - Sets the directory for projects. + Sets the \a directory for projects. - \sa projectsDirectory, useProjectsDirectory + \sa projectsDirectory(), useProjectsDirectory() */ void DocumentManager::setProjectsDirectory(const FilePath &directory) @@ -1415,7 +1448,7 @@ void DocumentManager::setProjectsDirectory(const FilePath &directory) Returns whether the directory for projects is to be used or whether the user chose to use the current directory. - \sa setProjectsDirectory, setUseProjectsDirectory + \sa setProjectsDirectory(), setUseProjectsDirectory() */ bool DocumentManager::useProjectsDirectory() @@ -1425,9 +1458,10 @@ bool DocumentManager::useProjectsDirectory() /*! - Sets whether the directory for projects is to be used. + Sets whether the directory for projects is to be used to + \a useProjectsDirectory. - \sa projectsDirectory, useProjectsDirectory + \sa projectsDirectory(), useProjectsDirectory() */ void DocumentManager::setUseProjectsDirectory(bool useProjectsDirectory) @@ -1439,7 +1473,7 @@ void DocumentManager::setUseProjectsDirectory(bool useProjectsDirectory) Returns the last visited directory of a file dialog. - \sa setFileDialogLastVisitedDirectory, fileDialogInitialDirectory + \sa setFileDialogLastVisitedDirectory(), fileDialogInitialDirectory() */ @@ -1450,10 +1484,10 @@ QString DocumentManager::fileDialogLastVisitedDirectory() /*! - Sets the last visited directory of a file dialog that will be remembered + Sets the last visited \a directory of a file dialog that will be remembered for the next one. - \sa fileDialogLastVisitedDirectory, fileDialogInitialDirectory + \sa fileDialogLastVisitedDirectory(), fileDialogInitialDirectory() */ @@ -1469,6 +1503,16 @@ void DocumentManager::notifyFilesChangedInternally(const QStringList &files) // -------------- FileChangeBlocker +/*! + \class Core::FileChangeBlocker + \inmodule QtCreator + \brief The FileChangeBlocker class blocks all change notifications to all + IDocument objects that match the given filename. + + Additionally, the class unblocks in the destructor. To also reload the + IDocument object in the destructor, set modifiedReload() to \c true. +*/ + FileChangeBlocker::FileChangeBlocker(const QString &fileName) : m_fileName(fileName) { diff --git a/src/plugins/coreplugin/documentmanager.h b/src/plugins/coreplugin/documentmanager.h index 92323efdc3..66ca54cd2e 100644 --- a/src/plugins/coreplugin/documentmanager.h +++ b/src/plugins/coreplugin/documentmanager.h @@ -167,12 +167,6 @@ private: friend class Core::Internal::DocumentManagerPrivate; }; -/*! The FileChangeBlocker blocks all change notifications to all IDocument * that - match the given filename. And unblocks in the destructor. - - To also reload the IDocument in the destructor class set modifiedReload to true - - */ class CORE_EXPORT FileChangeBlocker { public: diff --git a/src/plugins/coreplugin/versiondialog.cpp b/src/plugins/coreplugin/versiondialog.cpp index 3ef40cb819..3730a8b8c2 100644 --- a/src/plugins/coreplugin/versiondialog.cpp +++ b/src/plugins/coreplugin/versiondialog.cpp @@ -57,8 +57,7 @@ VersionDialog::VersionDialog(QWidget *parent) QString ideRev; #ifdef IDE_REVISION - //: This gets conditionally inserted as argument %8 into the description string. - const QString revUrl = QString::fromLatin1(Constants::IDE_REVISION_URL_STR); + const QString revUrl = QString::fromLatin1(Constants::IDE_REVISION_URL); const QString rev = QString::fromLatin1(Constants::IDE_REVISION_STR).left(10); ideRev = tr("<br/>From revision %1<br/>") .arg(revUrl.isEmpty() ? rev diff --git a/src/plugins/debugger/debuggerrunconfigurationaspect.cpp b/src/plugins/debugger/debuggerrunconfigurationaspect.cpp index 9317594fd9..076fd9723d 100644 --- a/src/plugins/debugger/debuggerrunconfigurationaspect.cpp +++ b/src/plugins/debugger/debuggerrunconfigurationaspect.cpp @@ -105,6 +105,7 @@ void DebuggerLanguageAspect::addToLayout(LayoutBuilder &builder) m_value = m_checkBox->isChecked() ? EnabledLanguage : DisabledLanguage; emit changed(); }); + builder.addItem(QString()); builder.addItem(m_checkBox.data()); if (!m_infoLabelText.isEmpty()) { diff --git a/src/plugins/nim/project/nimblebuildconfiguration.cpp b/src/plugins/nim/project/nimblebuildconfiguration.cpp index 10ef13bbce..6665191a2a 100644 --- a/src/plugins/nim/project/nimblebuildconfiguration.cpp +++ b/src/plugins/nim/project/nimblebuildconfiguration.cpp @@ -56,7 +56,7 @@ NimbleBuildConfiguration::NimbleBuildConfiguration(Target *target, Core::Id id) appendInitialBuildStep(Constants::C_NIMBLEBUILDSTEP_ID); setInitializer([this](const BuildInfo &info) { - m_buildType = info.buildType; + setBuildType(info.buildType); setBuildDirectory(project()->projectDirectory()); }); } @@ -79,6 +79,13 @@ QVariantMap NimbleBuildConfiguration::toMap() const return map; } +void NimbleBuildConfiguration::setBuildType(BuildConfiguration::BuildType buildType) +{ + if (buildType == m_buildType) + return; + m_buildType = buildType; + emit buildTypeChanged(); +} NimbleBuildConfigurationFactory::NimbleBuildConfigurationFactory() { diff --git a/src/plugins/nim/project/nimblebuildconfiguration.h b/src/plugins/nim/project/nimblebuildconfiguration.h index 2d3f0a93f3..3d52af523e 100644 --- a/src/plugins/nim/project/nimblebuildconfiguration.h +++ b/src/plugins/nim/project/nimblebuildconfiguration.h @@ -45,6 +45,8 @@ class NimbleBuildConfiguration : public ProjectExplorer::BuildConfiguration QVariantMap toMap() const override; private: + void setBuildType(BuildType buildType); + BuildType m_buildType; }; diff --git a/src/plugins/nim/project/nimblebuildstepwidget.cpp b/src/plugins/nim/project/nimblebuildstepwidget.cpp index ad841a4730..aa1981e7e2 100644 --- a/src/plugins/nim/project/nimblebuildstepwidget.cpp +++ b/src/plugins/nim/project/nimblebuildstepwidget.cpp @@ -49,7 +49,7 @@ NimbleBuildStepWidget::NimbleBuildStepWidget(NimbleBuildStep *bs) QObject::connect(ui->argumentsLineEdit, &QLineEdit::textEdited, bs, &NimbleBuildStep::setArguments); ui->resetButton->setIcon(Utils::Icons::RESET.icon()); - QObject::connect(ui->resetButton, &QToolButton::triggered, bs, &NimbleBuildStep::resetArguments); + QObject::connect(ui->resetButton, &QToolButton::clicked, bs, &NimbleBuildStep::resetArguments); } NimbleBuildStepWidget::~NimbleBuildStepWidget() diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp index 331897f08d..91aa006299 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp @@ -119,8 +119,10 @@ void Edit3DCanvas::dropEvent(QDropEvent *e) auto modelNode = QmlVisualNode::createQml3DNode(m_parent->view(), m_itemLibraryEntry, m_activeScene).modelNode(); - if (modelNode.isValid()) + if (modelNode.isValid()) { + e->accept(); m_parent->view()->setSelectedModelNode(modelNode); + } } } diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp index 5e203026d3..d06e1b299c 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp @@ -36,9 +36,10 @@ #include <qmldesignerconstants.h> #include <viewmanager.h> #include <qmldesignericons.h> +#include <designmodecontext.h> #include <utils/utilsicons.h> #include <coreplugin/icore.h> -#include <designmodecontext.h> +#include <coreplugin/messagebox.h> #include <QDebug> @@ -62,6 +63,20 @@ void Edit3DView::createEdit3DWidget() Core::ICore::addContextObject(editor3DContext); } +void Edit3DView::checkImports() +{ + bool has3dImport = false; + const QList<Import> imports = model()->imports(); + for (const auto &import : imports) { + if (import.url() == "QtQuick3D") { + has3dImport = true; + break; + } + } + + edit3DWidget()->showCanvas(has3dImport); +} + WidgetInfo Edit3DView::widgetInfo() { if (!m_edit3DWidget) @@ -130,13 +145,30 @@ void Edit3DView::updateActiveScene3D(const QVariantMap &sceneState) m_editLightAction->action()->setChecked(false); } +void Edit3DView::modelAttached(Model *model) +{ + AbstractView::modelAttached(model); + + checkImports(); +} + void Edit3DView::modelAboutToBeDetached(Model *model) { Q_UNUSED(model) - // Clear the image when model is detached (i.e. changing documents) - QImage emptyImage; - edit3DWidget()->canvas()->updateRenderImage(emptyImage); + // Hide the canvas when model is detached (i.e. changing documents) + edit3DWidget()->showCanvas(false); + + AbstractView::modelAboutToBeDetached(model); +} + +void Edit3DView::importsChanged(const QList<Import> &addedImports, + const QList<Import> &removedImports) +{ + Q_UNUSED(addedImports) + Q_UNUSED(removedImports) + + checkImports(); } void Edit3DView::sendInputEvent(QInputEvent *e) const @@ -163,54 +195,54 @@ void Edit3DView::createEdit3DActions() { m_selectionModeAction = new Edit3DAction( - "Edit3DSelectionModeToggle", View3DActionCommand::SelectionModeToggle, + QmlDesigner::Constants::EDIT3D_SELECTION_MODE, View3DActionCommand::SelectionModeToggle, QCoreApplication::translate("SelectionModeToggleAction", "Toggle Group/Single Selection Mode"), QKeySequence(Qt::Key_Q), true, false, Icons::EDIT3D_SELECTION_MODE_OFF.icon(), Icons::EDIT3D_SELECTION_MODE_ON.icon()); m_moveToolAction = new Edit3DAction( - "Edit3DMoveTool", View3DActionCommand::MoveTool, + QmlDesigner::Constants::EDIT3D_MOVE_TOOL, View3DActionCommand::MoveTool, QCoreApplication::translate("MoveToolAction", "Activate Move Tool"), QKeySequence(Qt::Key_W), true, true, Icons::EDIT3D_MOVE_TOOL_OFF.icon(), Icons::EDIT3D_MOVE_TOOL_ON.icon()); m_rotateToolAction = new Edit3DAction( - "Edit3DRotateTool", View3DActionCommand::RotateTool, + QmlDesigner::Constants::EDIT3D_ROTATE_TOOL, View3DActionCommand::RotateTool, QCoreApplication::translate("RotateToolAction", "Activate Rotate Tool"), QKeySequence(Qt::Key_E), true, false, Icons::EDIT3D_ROTATE_TOOL_OFF.icon(), Icons::EDIT3D_ROTATE_TOOL_ON.icon()); m_scaleToolAction = new Edit3DAction( - "Edit3DScaleTool", View3DActionCommand::ScaleTool, + QmlDesigner::Constants::EDIT3D_SCALE_TOOL, View3DActionCommand::ScaleTool, QCoreApplication::translate("ScaleToolAction", "Activate Scale Tool"), QKeySequence(Qt::Key_R), true, false, Icons::EDIT3D_SCALE_TOOL_OFF.icon(), Icons::EDIT3D_SCALE_TOOL_ON.icon()); m_fitAction = new Edit3DAction( - "Edit3DFitToView", View3DActionCommand::FitToView, + QmlDesigner::Constants::EDIT3D_FIT_SELECTED, View3DActionCommand::FitToView, QCoreApplication::translate("FitToViewAction", "Fit Selected Object to View"), QKeySequence(Qt::Key_F), false, false, Icons::EDIT3D_FIT_SELECTED_OFF.icon(), {}); m_cameraModeAction = new Edit3DAction( - "Edit3DCameraToggle", View3DActionCommand::CameraToggle, + QmlDesigner::Constants::EDIT3D_EDIT_CAMERA, View3DActionCommand::CameraToggle, QCoreApplication::translate("CameraToggleAction", "Toggle Perspective/Orthographic Edit Camera"), QKeySequence(Qt::Key_T), true, false, Icons::EDIT3D_EDIT_CAMERA_OFF.icon(), Icons::EDIT3D_EDIT_CAMERA_ON.icon()); m_orientationModeAction = new Edit3DAction( - "Edit3DOrientationToggle", View3DActionCommand::OrientationToggle, + QmlDesigner::Constants::EDIT3D_ORIENTATION, View3DActionCommand::OrientationToggle, QCoreApplication::translate("OrientationToggleAction", "Toggle Global/Local Orientation"), QKeySequence(Qt::Key_Y), true, false, Icons::EDIT3D_ORIENTATION_OFF.icon(), Icons::EDIT3D_ORIENTATION_ON.icon()); m_editLightAction = new Edit3DAction( - "Edit3DEditLightToggle", View3DActionCommand::EditLightToggle, + QmlDesigner::Constants::EDIT3D_EDIT_LIGHT, View3DActionCommand::EditLightToggle, QCoreApplication::translate("EditLightToggleAction", "Toggle Edit Light On/Off"), QKeySequence(Qt::Key_U), true, false, Icons::EDIT3D_LIGHT_OFF.icon(), Icons::EDIT3D_LIGHT_ON.icon()); @@ -221,7 +253,7 @@ void Edit3DView::createEdit3DActions() }; m_resetAction = new Edit3DAction( - "Edit3DResetView", View3DActionCommand::Empty, + QmlDesigner::Constants::EDIT3D_RESET_VIEW, View3DActionCommand::Empty, QCoreApplication::translate("ResetView", "Reset View"), QKeySequence(Qt::Key_P), false, false, Utils::Icons::RESET_TOOLBAR.icon(), {}, resetTrigger); @@ -240,20 +272,6 @@ void Edit3DView::createEdit3DActions() m_leftActions << m_editLightAction; m_rightActions << m_resetAction; - - // TODO: Registering actions to action manager causes conflicting shortcuts in form editor. - // Registration commented out until UX defines non-conflicting shortcuts. - // Also, actions creation needs to be somehow triggered before action manager registers - // actions to creator. -// DesignerActionManager &actionManager = QmlDesignerPlugin::instance()->designerActionManager(); -// for (auto action : qAsConst(m_leftActions)) { -// if (action) -// actionManager.addDesignerAction(action); -// } -// for (auto action : qAsConst(m_rightActions)) { -// if (action) -// actionManager.addDesignerAction(action); -// } } QVector<Edit3DAction *> Edit3DView::leftActions() const @@ -266,5 +284,21 @@ QVector<Edit3DAction *> Edit3DView::rightActions() const return m_rightActions; } +void Edit3DView::addQuick3DImport() +{ + const QList<Import> imports = model()->possibleImports(); + for (const auto &import : imports) { + if (import.url() == "QtQuick3D") { + model()->changeImports({import}, {}); + + // Subcomponent manager update needed to make item library entries appear + QmlDesignerPlugin::instance()->currentDesignDocument()->updateSubcomponentManager(); + return; + } + } + Core::AsynchronousMessageBox::warning(tr("Failed to Add Import"), + tr("Could not add QtQuick3D import to project.")); +} + } diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.h b/src/plugins/qmldesigner/components/edit3d/edit3dview.h index 8129879106..5835c89b32 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dview.h +++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.h @@ -55,7 +55,9 @@ public: void renderImage3DChanged(const QImage &img) override; void updateActiveScene3D(const QVariantMap &sceneState) override; + void modelAttached(Model *model) override; void modelAboutToBeDetached(Model *model) override; + void importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports) override; void sendInputEvent(QInputEvent *e) const; void edit3DViewResized(const QSize &size) const; @@ -66,10 +68,13 @@ public: QVector<Edit3DAction *> leftActions() const; QVector<Edit3DAction *> rightActions() const; + void addQuick3DImport(); + protected: private: void createEdit3DWidget(); + void checkImports(); QPointer<Edit3DWidget> m_edit3DWidget; QVector<Edit3DAction *> m_leftActions; diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp index 461613e476..9998bfc03d 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp @@ -33,6 +33,8 @@ #include "qmldesignerconstants.h" #include "viewmanager.h" +#include <coreplugin/actionmanager/actionmanager.h> +#include <coreplugin/actionmanager/command.h> #include <coreplugin/icore.h> #include <toolbox.h> #include <utils/utilsicons.h> @@ -62,7 +64,7 @@ Edit3DWidget::Edit3DWidget(Edit3DView *view) : // Iterate through view actions. A null action indicates a separator and a second null action // after separator indicates an exclusive group. - auto addActionsToToolBox = [this](const QVector<Edit3DAction *> &actions, bool left) { + auto addActionsToToolBox = [this, &context](const QVector<Edit3DAction *> &actions, bool left) { bool previousWasSeparator = true; QActionGroup *group = nullptr; for (auto action : actions) { @@ -75,6 +77,14 @@ Edit3DWidget::Edit3DWidget(Edit3DView *view) : else m_toolBox->addRightSideAction(action->action()); previousWasSeparator = false; + + // Register action as creator command to make it configurable + Core::Command *command = Core::ActionManager::registerAction( + action->action(), action->menuId().data(), context); + command->setDefaultKeySequence(action->action()->shortcut()); + command->augmentActionWithShortcutToolTip(action->action()); + // Clear action shortcut so it doesn't conflict with command's override action + action->action()->setShortcut({}); } else { if (previousWasSeparator) { group = new QActionGroup(this); @@ -89,14 +99,28 @@ Edit3DWidget::Edit3DWidget(Edit3DView *view) : } } } - }; addActionsToToolBox(view->leftActions(), true); addActionsToToolBox(view->rightActions(), false); + // Onboarding label contains instructions for new users how to get 3D content into the project + m_onboardingLabel = new QLabel(this); + QString labelText = + "No 3D import here yet!<br><br>" + "To create a 3D View you need to add the QtQuick3D import to your file.<br>" + "You can add the import via the QML Imports tab of the Library view, or alternatively click" + " <a href=\"#add_import\"><span style=\"text-decoration:none;color:%1\">here</span></a> " + "to add it straight away.<br><br>" + "If you want to import 3D assets from another tool, click on the \"Add New Assets...\" button in the Assets tab of the Library view."; + m_onboardingLabel->setText(labelText.arg(Utils::creatorTheme()->color(Utils::Theme::TextColorLink).name())); + m_onboardingLabel->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); + connect(m_onboardingLabel, &QLabel::linkActivated, this, &Edit3DWidget::linkActivated); + fillLayout->addWidget(m_onboardingLabel.data()); + // Canvas is used to render the actual edit 3d view m_canvas = new Edit3DCanvas(this); fillLayout->addWidget(m_canvas.data()); + showCanvas(false); } void Edit3DWidget::contextHelp(const Core::IContext::HelpCallback &callback) const @@ -107,6 +131,22 @@ void Edit3DWidget::contextHelp(const Core::IContext::HelpCallback &callback) con callback({}); } +void Edit3DWidget::showCanvas(bool show) +{ + if (!show) { + QImage emptyImage; + m_canvas->updateRenderImage(emptyImage); + } + m_canvas->setVisible(show); + m_onboardingLabel->setVisible(!show); +} + +void Edit3DWidget::linkActivated(const QString &link) +{ + if (m_view) + m_view->addQuick3DImport(); +} + Edit3DCanvas *Edit3DWidget::canvas() const { return m_canvas.data(); diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h index c5cea8836c..ca44a955f5 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h +++ b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h @@ -25,6 +25,7 @@ #pragma once #include <QtWidgets/qwidget.h> +#include <QtWidgets/qlabel.h> #include <QtCore/qpointer.h> #include <coreplugin/icontext.h> @@ -45,10 +46,15 @@ public: Edit3DView *view() const; void contextHelp(const Core::IContext::HelpCallback &callback) const; + void showCanvas(bool show); + private: + void linkActivated(const QString &link); + QPointer<Edit3DView> m_edit3DView; QPointer<Edit3DView> m_view; QPointer<Edit3DCanvas> m_canvas; + QPointer<QLabel> m_onboardingLabel; QPointer<ToolBox> m_toolBox; Core::IContext *m_context = nullptr; }; diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp index c9a98580a7..76cd389960 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp +++ b/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp @@ -77,8 +77,7 @@ FormEditorWidget::FormEditorWidget(FormEditorView *view) : auto layoutActionGroup = new QActionGroup(this); layoutActionGroup->setExclusive(true); - m_noSnappingAction = layoutActionGroup->addAction(tr("No snapping (T).")); - m_noSnappingAction->setShortcut(Qt::Key_T); + m_noSnappingAction = layoutActionGroup->addAction(tr("No snapping.")); m_noSnappingAction->setShortcutContext(Qt::WidgetWithChildrenShortcut); m_noSnappingAction->setCheckable(true); m_noSnappingAction->setChecked(true); diff --git a/src/plugins/qmldesigner/components/stateseditor/stateseditorview.cpp b/src/plugins/qmldesigner/components/stateseditor/stateseditorview.cpp index 9674624863..8a2ca50c15 100644 --- a/src/plugins/qmldesigner/components/stateseditor/stateseditorview.cpp +++ b/src/plugins/qmldesigner/components/stateseditor/stateseditorview.cpp @@ -253,7 +253,13 @@ void StatesEditorView::renameState(int internalNodeId, const QString &newName) // Jump to base state for the change QmlModelState oldState = currentState(); setCurrentState(baseState()); + const bool updateDefault = state.isDefault(); + state.setName(newName); + + if (updateDefault) + state.setAsDefault(); + setCurrentState(oldState); } } catch (const RewritingException &e) { diff --git a/src/plugins/qmldesigner/designercore/model/modelmerger.cpp b/src/plugins/qmldesigner/designercore/model/modelmerger.cpp index 8517f9cb82..4034faccde 100644 --- a/src/plugins/qmldesigner/designercore/model/modelmerger.cpp +++ b/src/plugins/qmldesigner/designercore/model/modelmerger.cpp @@ -38,6 +38,7 @@ #include <QUrl> #include <QDebug> +#include <QtCore/qregularexpression.h> namespace QmlDesigner { @@ -45,10 +46,13 @@ static ModelNode createNodeFromNode(const ModelNode &modelNode,const QHash<QStri static QString fixExpression(const QString &expression, const QHash<QString, QString> &idRenamingHash) { + const QString pattern("\\b%1\\b"); // Match only full ids QString newExpression = expression; - foreach (const QString &id, idRenamingHash.keys()) { - if (newExpression.contains(id)) - newExpression = newExpression.replace(id, idRenamingHash.value(id)); + const auto keys = idRenamingHash.keys(); + for (const QString &id : keys) { + QRegularExpression re(pattern.arg(id)); + if (newExpression.contains(re)) + newExpression = newExpression.replace(re, idRenamingHash.value(id)); } return newExpression; } diff --git a/src/plugins/qmldesigner/qmldesignerconstants.h b/src/plugins/qmldesigner/qmldesignerconstants.h index 132f31d2ff..b334dced8b 100644 --- a/src/plugins/qmldesigner/qmldesignerconstants.h +++ b/src/plugins/qmldesigner/qmldesignerconstants.h @@ -54,6 +54,15 @@ const char FORMEDITOR_SNAPPING[] = "QmlDesigner.FormEditor.Snapping"; const char FORMEDITOR_NO_SNAPPING[] = "QmlDesigner.FormEditor.NoSnapping"; const char FORMEDITOR_NO_SNAPPING_AND_ANCHORING[] = "QmlDesigner.FormEditor.NoSnappingAndAnchoring"; const char FORMEDITOR_NO_SHOW_BOUNDING_RECTANGLE[] = "QmlDesigner.FormEditor.ShowBoundingRectangle"; +const char EDIT3D_SELECTION_MODE[] = "QmlDesigner.Editor3D.SelectionModeToggle"; +const char EDIT3D_MOVE_TOOL[] = "QmlDesigner.Editor3D.MoveTool"; +const char EDIT3D_ROTATE_TOOL[] = "QmlDesigner.Editor3D.RotateTool"; +const char EDIT3D_SCALE_TOOL[] = "QmlDesigner.Editor3D.ScaleTool"; +const char EDIT3D_FIT_SELECTED[] = "QmlDesigner.Editor3D.FitSelected"; +const char EDIT3D_EDIT_CAMERA[] = "QmlDesigner.Editor3D.EditCameraToggle"; +const char EDIT3D_ORIENTATION[] = "QmlDesigner.Editor3D.OrientationToggle"; +const char EDIT3D_EDIT_LIGHT[] = "QmlDesigner.Editor3D.EditLightToggle"; +const char EDIT3D_RESET_VIEW[] = "QmlDesigner.Editor3D.ResetView"; const char QML_DESIGNER_SUBFOLDER[] = "/designer/"; const char QUICK_3D_ASSETS_FOLDER[] = "/Quick3DAssets"; diff --git a/src/plugins/vcsbase/vcsoutputformatter.cpp b/src/plugins/vcsbase/vcsoutputformatter.cpp index 4145bd0618..b6ad20304c 100644 --- a/src/plugins/vcsbase/vcsoutputformatter.cpp +++ b/src/plugins/vcsbase/vcsoutputformatter.cpp @@ -38,7 +38,8 @@ VcsOutputFormatter::VcsOutputFormatter() : m_regexp( "(https?://\\S*)" // https://codereview.org/c/1234 "|(v[0-9]+\\.[0-9]+\\.[0-9]+[\\-A-Za-z0-9]*)" // v0.1.2-beta3 - "|([0-9a-f]{6,}(?:\\.\\.[0-9a-f]{6,}|\\^)?)") // 789acf^ or 123abc..456cde + "|([0-9a-f]{6,}(?:\\.\\.[0-9a-f]{6,}" // 789acf or 123abc..456cde + "|\\^+|~\\d+)?)") // or 789acf^ or 123abc~99 { } diff --git a/tests/system/suite_CSUP/tst_CSUP01/test.py b/tests/system/suite_CSUP/tst_CSUP01/test.py index 39f959b212..d7d556721c 100644 --- a/tests/system/suite_CSUP/tst_CSUP01/test.py +++ b/tests/system/suite_CSUP/tst_CSUP01/test.py @@ -93,21 +93,11 @@ def main(): resetLine(editorWidget) lineWithFloat = "float fl = 2." type(editorWidget, lineWithFloat) - try: - waitForObject(":popupFrame_Proposal_QListView", 5000) - test.fail("Typing a float value triggered code completion") - except: - test.compare(str(lineUnderCursor(editorWidget)), " " + lineWithFloat, - "Typing a float value does not trigger code completion") + test.exception("waitForObject(':popupFrame_Proposal_QListView', 5000)", + "Does typing a float value trigger code completion?") triggerCompletion(editorWidget) - try: - waitForObject(":popupFrame_Proposal_QListView", 5000) - if useClang and JIRA.isBugStillOpen(16607): - test.xfail("User can trigger code completion manually in a float value") - else: - test.fail("User can trigger code completion manually in a float value") - except: - test.passes("User can't trigger code completion manually in a float value") + test.exception("waitForObject(':popupFrame_Proposal_QListView', 5000)", + "Can user trigger code completion manually in a float value?") # Step 5: From "Tools -> Options -> Text Editor -> Completion" select Activate completion Manually, # uncheck Autocomplete common prefix and press Apply and then Ok . Return to Edit mode. test.log("Step 5: Change Code Completion settings") |