From a117a558fe77fe63377e063c1424e8a66399fde2 Mon Sep 17 00:00:00 2001 From: Tapani Mattila Date: Tue, 18 Jan 2022 15:53:49 +0200 Subject: [PATCH 01/55] CMake generation: Streamline confirmation dialog Task-number: QDS-5991 Change-Id: I1cec8650703ca5de936739d1adbba77d0b64562e Reviewed-by: Reviewed-by: Qt CI Bot Reviewed-by: Thomas Hartmann --- .../qmldesigner/cmakegeneratordialog.cpp | 46 +++++++++++++------ .../qmldesigner/generatecmakelists.cpp | 2 - 2 files changed, 33 insertions(+), 15 deletions(-) diff --git a/src/plugins/qmldesigner/cmakegeneratordialog.cpp b/src/plugins/qmldesigner/cmakegeneratordialog.cpp index a972147051d..eb7a35f170c 100644 --- a/src/plugins/qmldesigner/cmakegeneratordialog.cpp +++ b/src/plugins/qmldesigner/cmakegeneratordialog.cpp @@ -28,6 +28,7 @@ #include "generatecmakelistsconstants.h" #include +#include #include #include @@ -50,17 +51,14 @@ CmakeGeneratorDialog::CmakeGeneratorDialog(const FilePath &rootDir, const FilePa m_model = new CMakeGeneratorDialogTreeModel(rootDir, files, this); - QVBoxLayout *layout = new QVBoxLayout(this); - setLayout(layout); + QVBoxLayout *dialogLayout = new QVBoxLayout(this); + dialogLayout->setSizeConstraint(QLayout::SetFixedSize); + setLayout(dialogLayout); - QDialogButtonBox *buttons = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); - - auto *okButton = buttons->button(QDialogButtonBox::Ok); - okButton->setDefault(true); - - connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept); - connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject); - connect(m_model, &CMakeGeneratorDialogTreeModel::checkedStateChanged, this, &CmakeGeneratorDialog::refreshNotificationText); + QWidget *advancedInnerWidget = new QWidget(this); + QVBoxLayout *advancedInnerLayout = new QVBoxLayout(advancedInnerWidget); + advancedInnerWidget->setLayout(advancedInnerLayout); + advancedInnerWidget->setMinimumHeight(640); QTreeView *tree = new QTreeView(this); tree->setModel(m_model); @@ -72,9 +70,31 @@ CmakeGeneratorDialog::CmakeGeneratorDialog(const FilePath &rootDir, const FilePa refreshNotificationText(); - layout->addWidget(tree, 2); - layout->addWidget(m_notifications, 1); - layout->addWidget(buttons); + advancedInnerLayout->addWidget(tree, 2); + advancedInnerLayout->addWidget(m_notifications, 1); + + DetailsWidget *advancedWidget = new DetailsWidget(this); + advancedWidget->setMinimumWidth(600); + advancedWidget->setWidget(advancedInnerWidget); + advancedWidget->setSummaryText(QCoreApplication::translate("QmlDesigner::GenerateCmake", + "Advanced Options")); + + QDialogButtonBox *buttons = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); + auto *okButton = buttons->button(QDialogButtonBox::Ok); + okButton->setDefault(true); + + connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject); + connect(m_model, &CMakeGeneratorDialogTreeModel::checkedStateChanged, this, &CmakeGeneratorDialog::refreshNotificationText); + + QLabel *mainLabel = new QLabel(QCoreApplication::translate("QmlDesigner::GenerateCmake", + "Start CMakeFiles.txt generation"), + this); + mainLabel->setMargin(50); + + dialogLayout->addWidget(mainLabel); + dialogLayout->addWidget(advancedWidget); + dialogLayout->addWidget(buttons); } FilePaths CmakeGeneratorDialog::getFilePaths() diff --git a/src/plugins/qmldesigner/generatecmakelists.cpp b/src/plugins/qmldesigner/generatecmakelists.cpp index 7609a31c15c..ed62fb7bb14 100644 --- a/src/plugins/qmldesigner/generatecmakelists.cpp +++ b/src/plugins/qmldesigner/generatecmakelists.cpp @@ -205,8 +205,6 @@ bool showConfirmationDialog(const Utils::FilePath &rootDir) files.append(file.filePath); CmakeGeneratorDialog dialog(rootDir, files); - dialog.setMinimumWidth(600); - dialog.setMinimumHeight(640); if (dialog.exec()) { Utils::FilePaths confirmedFiles = dialog.getFilePaths(); removeUnconfirmedQueuedFiles(confirmedFiles); From a89f6919d2f3a91367ce9a8b85128004f08aa9e2 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 27 Jan 2022 10:09:46 +0100 Subject: [PATCH 02/55] StudioWelcome: Only replace wizards when running as Design Studio Task-number: QTCREATORBUG-26936 Change-Id: I11c14bd916a7139fc4d133b8b3b8a79fa7770409 Reviewed-by: Thomas Hartmann --- src/plugins/studiowelcome/studiowelcomeplugin.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/studiowelcome/studiowelcomeplugin.cpp b/src/plugins/studiowelcome/studiowelcomeplugin.cpp index 53f6e25a7fc..5aea2a6a32d 100644 --- a/src/plugins/studiowelcome/studiowelcomeplugin.cpp +++ b/src/plugins/studiowelcome/studiowelcomeplugin.cpp @@ -581,7 +581,8 @@ void StudioWelcomePlugin::extensionsInitialized() Core::ModeManager::activateMode(m_welcomeMode->id()); // Enable QDS new project dialog - Core::ICore::setNewDialogFactory([](QWidget *parent) { return new QdsNewDialog(parent); }); + if (Core::ICore::settings()->value("QML/Designer/StandAloneMode", false).toBool()) + Core::ICore::setNewDialogFactory([](QWidget *parent) { return new QdsNewDialog(parent); }); if (showSplashScreen()) { connect(Core::ICore::instance(), &Core::ICore::coreOpened, this, [this] { From 35d32c9784355a694a84c9da6e886b75d4edc270 Mon Sep 17 00:00:00 2001 From: Aleksei German Date: Mon, 24 Jan 2022 11:22:35 +0100 Subject: [PATCH 03/55] QmlDesigner: Update for QUL metadata Task-Numbers: QDS-5867, QDS-5890 Change-Id: If27d947d88e34f8479796520dad2bee62a6d0ec9 Reviewed-by: Reviewed-by: Thomas Hartmann --- .../qtcreator/qmldesigner/qt4mcu/metadata.qml | 16 +- share/qtcreator/qmldesigner/qt4mcu/qul-14.qml | 3 +- share/qtcreator/qmldesigner/qt4mcu/qul-17.qml | 3 +- share/qtcreator/qmldesigner/qt4mcu/qul-18.qml | 9 +- share/qtcreator/qmldesigner/qt4mcu/qul-19.qml | 9 +- share/qtcreator/qmldesigner/qt4mcu/qul-20.qml | 221 ++++++++++++++++++ 6 files changed, 250 insertions(+), 11 deletions(-) create mode 100644 share/qtcreator/qmldesigner/qt4mcu/qul-20.qml diff --git a/share/qtcreator/qmldesigner/qt4mcu/metadata.qml b/share/qtcreator/qmldesigner/qt4mcu/metadata.qml index d26ef06fd56..ee889214065 100644 --- a/share/qtcreator/qmldesigner/qt4mcu/metadata.qml +++ b/share/qtcreator/qmldesigner/qt4mcu/metadata.qml @@ -27,29 +27,35 @@ Metadata { id: metadataFile - defaultVersion: v19 + defaultVersion: v20 VersionData { id: v14 - name: "QUL 1.4" + name: "Qt for MCUs 1.4" path: "qul-14.qml" } VersionData { id: v17 - name: "QUL 1.7" + name: "Qt for MCUs 1.7" path: "qul-17.qml" } VersionData { id: v18 - name: "QUL 1.8" + name: "Qt for MCUs 1.8" path: "qul-18.qml" } VersionData { id: v19 - name: "QUL 1.9" + name: "Qt for MCUs 1.9" path: "qul-19.qml" } + + VersionData { + id: v20 + name: "Qt for MCUs 2.0" + path: "qul-20.qml" + } } diff --git a/share/qtcreator/qmldesigner/qt4mcu/qul-14.qml b/share/qtcreator/qmldesigner/qt4mcu/qul-14.qml index 03110763f5b..56467f170f0 100644 --- a/share/qtcreator/qmldesigner/qt4mcu/qul-14.qml +++ b/share/qtcreator/qmldesigner/qt4mcu/qul-14.qml @@ -24,7 +24,7 @@ ****************************************************************************/ VersionData { - name: "QUL 1.4" + name: "Qt for MCUs 1.4" bannedItems: ["QtQuick.AnimatedImage", "QtQuick.FocusScope", @@ -34,6 +34,7 @@ VersionData { "QtQuick.Grid", "QtQuick.GridView", "QtQuick.PathView", + "QtQuick.Loader", "QtQuick.Controls", "QtQuick.Controls.BusyIndicator", "QtQuick.Controls.ButtonGroup", diff --git a/share/qtcreator/qmldesigner/qt4mcu/qul-17.qml b/share/qtcreator/qmldesigner/qt4mcu/qul-17.qml index 765c54bd9d7..190d9f398a4 100644 --- a/share/qtcreator/qmldesigner/qt4mcu/qul-17.qml +++ b/share/qtcreator/qmldesigner/qt4mcu/qul-17.qml @@ -24,7 +24,7 @@ ****************************************************************************/ VersionData { - name: "QUL 1.7" + name: "Qt for MCUs 1.7" bannedItems: ["QtQuick.AnimatedImage", "QtQuick.FocusScope", @@ -34,6 +34,7 @@ VersionData { "QtQuick.Grid", "QtQuick.GridView", "QtQuick.PathView", + "QtQuick.Loader", "QtQuick.Controls", "QtQuick.Controls.BusyIndicator", "QtQuick.Controls.ButtonGroup", diff --git a/share/qtcreator/qmldesigner/qt4mcu/qul-18.qml b/share/qtcreator/qmldesigner/qt4mcu/qul-18.qml index 4c0cf5d4b9f..dba879c9a10 100644 --- a/share/qtcreator/qmldesigner/qt4mcu/qul-18.qml +++ b/share/qtcreator/qmldesigner/qt4mcu/qul-18.qml @@ -24,7 +24,7 @@ ****************************************************************************/ VersionData { - name: "QUL 1.8" + name: "Qt for MCUs 1.8" bannedItems: ["QtQuick.AnimatedImage", "QtQuick.FocusScope", @@ -34,6 +34,7 @@ VersionData { "QtQuick.Grid", "QtQuick.GridView", "QtQuick.PathView", + "QtQuick.Loader", "QtQuick.Controls", "QtQuick.Controls.BusyIndicator", "QtQuick.Controls.ButtonGroup", @@ -63,7 +64,11 @@ VersionData { "QtQuick.Controls.TextArea", "QtQuick.Controls.TextField", "QtQuick.Controls.ToolSeparator", - "QtQuick.Controls.Tumbler"] + "QtQuick.Controls.Tumbler", + "QtQuick.Shapes.ConicalGradient", + "QtQuick.Shapes.LinearGradient", + "QtQuick.Shapes.RadialGradient", + "QtQuick.Shapes.ShapeGradient"] allowedImports: ["QtQuick", "QtQuick.Shapes", diff --git a/share/qtcreator/qmldesigner/qt4mcu/qul-19.qml b/share/qtcreator/qmldesigner/qt4mcu/qul-19.qml index be473bc8caf..55f720c45b7 100644 --- a/share/qtcreator/qmldesigner/qt4mcu/qul-19.qml +++ b/share/qtcreator/qmldesigner/qt4mcu/qul-19.qml @@ -24,7 +24,7 @@ ****************************************************************************/ VersionData { - name: "QUL 1.9" + name: "Qt for MCUs 1.9" bannedItems: ["QtQuick.AnimatedImage", "QtQuick.FocusScope", @@ -34,6 +34,7 @@ VersionData { "QtQuick.Grid", "QtQuick.GridView", "QtQuick.PathView", + "QtQuick.Loader", "QtQuick.Controls", "QtQuick.Controls.BusyIndicator", "QtQuick.Controls.ButtonGroup", @@ -63,7 +64,11 @@ VersionData { "QtQuick.Controls.TextArea", "QtQuick.Controls.TextField", "QtQuick.Controls.ToolSeparator", - "QtQuick.Controls.Tumbler"] + "QtQuick.Controls.Tumbler", + "QtQuick.Shapes.ConicalGradient", + "QtQuick.Shapes.LinearGradient", + "QtQuick.Shapes.RadialGradient", + "QtQuick.Shapes.ShapeGradient"] allowedImports: ["QtQuick", "QtQuick.Shapes", diff --git a/share/qtcreator/qmldesigner/qt4mcu/qul-20.qml b/share/qtcreator/qmldesigner/qt4mcu/qul-20.qml new file mode 100644 index 00000000000..d6b41cd0552 --- /dev/null +++ b/share/qtcreator/qmldesigner/qt4mcu/qul-20.qml @@ -0,0 +1,221 @@ +/**************************************************************************** +** +** Copyright (C) 2021 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. +** +****************************************************************************/ + +VersionData { + name: "Qt for MCUs 2.0" + + bannedItems: ["QtQuick.AnimatedImage", + "QtQuick.FocusScope", + "QtQuick.TextInput", + "QtQuick.TextEdit", + "QtQuick.Flow", + "QtQuick.Grid", + "QtQuick.GridView", + "QtQuick.PathView", + "QtQuick.Loader", + "QtQuick.Controls", + "QtQuick.Controls.BusyIndicator", + "QtQuick.Controls.ButtonGroup", + "QtQuick.Controls.CheckDelegate", + "QtQuick.Controls.Container", + "QtQuick.Controls.ComboBox", + "QtQuick.Controls.DelayButton", + "QtQuick.Controls.Frame", + "QtQuick.Controls.GroupBox", + "QtQuick.Controls.ItemDelegate", + "QtQuick.Controls.Label", + "QtQuick.Controls.Page", + "QtQuick.Controls.PageIndicator", + "QtQuick.Controls.Pane", + "QtQuick.Controls.RadioDelegate", + "QtQuick.Controls.RangeSlider", + "QtQuick.Controls.RoundButton", + "QtQuick.Controls.ScrollView", + "QtQuick.Controls.SpinBox", + "QtQuick.Controls.StackView", + "QtQuick.Controls.SwipeDelegate", + "QtQuick.Controls.SwitchDelegate", + "QtQuick.Controls.ToolBar", + "QtQuick.Controls.ToolButton", + "QtQuick.Controls.TabBar", + "QtQuick.Controls.TabButton", + "QtQuick.Controls.TextArea", + "QtQuick.Controls.TextField", + "QtQuick.Controls.ToolSeparator", + "QtQuick.Controls.Tumbler", + "QtQuick.Shapes.ConicalGradient", + "QtQuick.Shapes.LinearGradient", + "QtQuick.Shapes.RadialGradient", + "QtQuick.Shapes.ShapeGradient"] + + allowedImports: ["QtQuick", + "QtQuick.Shapes", + "QtQuick.Controls", + "QtQuick.Timeline", + "QtQuickUltralite.Extras", + "QtQuickUltralite.Layers"] + + bannedImports: ["FlowView"] + + //ComplexProperty is not a type, it's just a way to handle bigger props + ComplexProperty { + prefix: "font" + bannedProperties: ["wordSpacing", "letterSpacing", "hintingPreference", + "kerning", "preferShaping", "capitalization", + "strikeout", "underline", "styleName"] + } + + QtQuick.Item { + bannedProperties: ["layer", "opacity", "smooth", "antialiasing", + "baselineOffset", "focus", "activeFocusOnTab", + "rotation", "scale", "transformOrigin"] + } + + QtQuick.Rectangle { + bannedProperties: ["gradient", "border"] + } + + QtQuick.Flickable { + bannedProperties: ["boundsBehavior", "boundsMovement", "flickDeceleration", + "flickableDirection", "leftMargin", "rightMargin", "bottomMargin", "topMargin", + "originX", "originY", "pixelAligned", "pressDelay", "synchronousDrag"] + } + + QtQuick.MouseArea { + bannedProperties: ["propagateComposedEvents", "preventStealing", "cursorShape", + "scrollGestureEnabled", "drag", "acceptedButtons", "hoverEnabled"] + } + + QtQuick.Image { + allowChildren: false + allowedProperties: ["rotation", "scale", "transformOrigin"] + bannedProperties: ["mirror", "mipmap", "cache", "autoTransform", "asynchronous", + "sourceSize", "smooth"] + } + + QtQuick.BorderImage { + bannedProperties: ["asynchronous", "cache", "currentFrame", "frameCount", + "horizontalTileMode", "mirror", "progress", "smooth", "sourceSize", + "status", "verticalTileMode"] + } + + QtQuick.Text { + allowChildren: false + allowedProperties: ["rotation", "scale", "transformOrigin"] + bannedProperties: ["elide", "lineHeight", "lineHeightMode", "wrapMode", "style", + "styleColor", "minimumPointSize", "minimumPixelSize", + "fontSizeMode", "renderType", "renderTypeQuality", "textFormat", "maximumLineCount"] + } + + //Padding is not an actual item, but rather set of properties in Text + Padding { + bannedProperties: ["bottomPadding", "topPadding", "leftPadding", "rightPadding"] + } + + QtQuick.Column { + bannedProperties: ["bottomPadding", "leftPadding", "rightPadding", "topPadding"] + } + + QtQuick.Row { + bannedProperties: ["bottomPadding", "leftPadding", "rightPadding", "topPadding", + "effectiveLayoutDirection", "layoutDirection"] + } + + QtQuick.ListView { + bannedProperties: ["cacheBuffer", "highlightRangeMode", "highlightMoveDuration", + "highlightResizeDuration", "preferredHighlightBegin", "layoutDirection", + "preferredHighlightEnd", "highlightFollowsCurrentItem", "keyNavigationWraps", + "snapMode", "highlightMoveVelocity", "highlightResizeVelocity"] + } + + QtQuick.Animation { + bannedProperties: ["paused"] + } + + //Quick Controls2 Items and properties: + + QtQuick.Controls.Control { + bannedProperties: ["focusPolicy", "hoverEnabled", "wheelEnabled"] + } + + QtQuick.Controls.AbstractButton { + bannedProperties: ["display", "autoExclusive"] + } + + QtQuick.Controls.ProgressBar { + bannedProperties: ["indeterminate"] + } + + QtQuick.Controls.Slider { + bannedProperties: ["live", "snapMode", "touchDragThreshold"] + } + + //Path and Shapes related: + + QtQuick.Path { + bannedProperties: ["scale", "pathElements"] + } + + QtQuick.PathArc { + bannedProperties: ["relativeX", "relativeY"] + } + + QtQuick.PathLine { + bannedProperties: ["relativeX", "relativeY"] + } + + QtQuick.PathMove { + bannedProperties: ["relativeX", "relativeY"] + } + + QtQuick.PathQuad { + bannedProperties: ["relativeX", "relativeY", + "relativeControlX", "relativeControlY"] + } + + QtQuick.PathCubic { + bannedProperties: ["relativeX", "relativeY", + "relativeControl1X", "relativeControl1Y", + "relativeControl2X", "relativeControl2Y"] + } + + QtQuick.PathElement { + //nothing + } + + QtQuick.PathSvg { + //nothing + } + + QtQuick.Shapes.Shape { + bannedProperties: ["asynchronous", "containsMode", "data", + "renderType", "status", "vendorExtensionsEnabled"] + } + + QtQuick.Shapes.ShapePath { + bannedProperties: ["dashOffset", "dashPattern", + "fillGradient", "strokeStyle"] + } +} From 557489c3fcb930885f9129cdd76047de1852b4da Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Tue, 25 Jan 2022 15:31:32 +0200 Subject: [PATCH 04/55] QmlDesigner: Fix camera frustum initialization for Qt5 builds In Qt5 builds, we need additional async update at camera geometry initialization to ensure source camera is up to date and frustum mesh can be constructed. Fixes: QDS-6071 Change-Id: I41371ae66fde432b0fdf4b5fee6a0604d005bf63 Reviewed-by: Reviewed-by: Qt CI Bot Reviewed-by: Thomas Hartmann --- .../qmlpuppet/qml2puppet/editor3d/camerageometry.cpp | 10 ++++++++++ .../qml/qmlpuppet/qml2puppet/editor3d/camerageometry.h | 3 +++ 2 files changed, 13 insertions(+) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/camerageometry.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/camerageometry.cpp index 4260921a378..046dc486063 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/camerageometry.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/camerageometry.cpp @@ -142,6 +142,16 @@ void CameraGeometry::doUpdateGeometry() if (!QQuick3DObjectPrivate::get(m_camera)->spatialNode) { // Doing explicit viewport mapping forces cameraNode creation m_camera->mapToViewport({}, m_viewPortRect.width(), m_viewPortRect.height()); +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + if (!m_nodeCreationUpdateDone) { + // Post-node creation update is done only once to avoid infinite loop in case the node + // creation fails. + m_nodeCreationUpdateDone = true; + m_cameraUpdatePending = true; + update(); + return; + } +#endif } GeometryBase::doUpdateGeometry(); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/camerageometry.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/camerageometry.h index 5b4fa66fe46..c65b0d1798e 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/camerageometry.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/camerageometry.h @@ -67,6 +67,9 @@ private: QQuick3DCamera *m_camera = nullptr; QRectF m_viewPortRect; bool m_cameraUpdatePending = false; +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + bool m_nodeCreationUpdateDone = false; +#endif }; } From 4980f71dd5d800a69e38264a64f1d103d7c156ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20L=C3=B6hning?= Date: Fri, 29 Oct 2021 22:57:07 +0200 Subject: [PATCH 05/55] Squish: Update tests which use "Rename Symbol Under Cursor" When using this on open files, Creator used to make the changes but not save the file. Creator 6 now also saves the file unless it already contained other changes. Because the file is being saved immediately, "Save All" and "Revert to Saved" cannot be used in this situation anymore. Change-Id: I0b8a58d998c54ccceae6d178b2c7a6f6182c7ad0 Reviewed-by: Christian Stenger --- tests/system/suite_editors/tst_qml_editor/test.py | 1 - tests/system/suite_editors/tst_rename_macros/test.py | 5 +++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/system/suite_editors/tst_qml_editor/test.py b/tests/system/suite_editors/tst_qml_editor/test.py index c26207ea6ec..e75db758939 100644 --- a/tests/system/suite_editors/tst_qml_editor/test.py +++ b/tests/system/suite_editors/tst_qml_editor/test.py @@ -87,7 +87,6 @@ def testRenameId(): formerTxt = editor.plainText originalText = originalTexts.get(file).replace("mainView", "renamedView") test.compare(originalText,formerTxt, "Comparing %s" % file.replace("Core.","").replace("\\","")) - invokeMenuItem("File","Save All") def __invokeFindUsage__(filename, line, additionalKeyPresses, expectedCount): openDocument(focusDocumentPath % filename) diff --git a/tests/system/suite_editors/tst_rename_macros/test.py b/tests/system/suite_editors/tst_rename_macros/test.py index 491cc3bd200..f1111f8583c 100644 --- a/tests/system/suite_editors/tst_rename_macros/test.py +++ b/tests/system/suite_editors/tst_rename_macros/test.py @@ -46,6 +46,8 @@ def main(): expectedHeaderName=headerName) if not testRenameMacroAfterSourceMoving(): return + # save and exit + invokeMenuItem("File", "Save All") invokeMenuItem("File", "Exit") def testRenameMacroAfterSourceModification(): @@ -156,8 +158,7 @@ def revertChanges(files): simpleName = simpleFileName(f) if openDocument(f): try: - invokeMenuItem('File', 'Revert "%s" to Saved' % simpleName) - clickButton(waitForObject(":Revert to Saved.Proceed_QPushButton")) + invokeMenuItem('Edit', 'Undo') test.log("Reverted changes inside %s" % simpleName) except: test.warning("File '%s' cannot be reverted." % simpleName, From 7a8ca55f77b62017c011b2cb8b9ac7bf50be7daf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20L=C3=B6hning?= Date: Fri, 29 Oct 2021 14:38:35 +0200 Subject: [PATCH 06/55] Squish: Introduce helper function for checking for strings In Python3 type unicode is unavailable since it's implicit with "str". The new functions helps porting code. Change-Id: I5de0fa182acbbaf267ed51f66f658cb9c884f4c5 Reviewed-by: Christian Stenger --- tests/system/shared/editor_utils.py | 4 ++-- tests/system/shared/fs_utils.py | 4 ++-- tests/system/shared/project_explorer.py | 6 +++--- tests/system/shared/utils.py | 21 ++++++++++++------- .../tst_default_settings/test.py | 4 ++-- 5 files changed, 23 insertions(+), 16 deletions(-) diff --git a/tests/system/shared/editor_utils.py b/tests/system/shared/editor_utils.py index 9af13028486..bb6e8ba299d 100644 --- a/tests/system/shared/editor_utils.py +++ b/tests/system/shared/editor_utils.py @@ -37,7 +37,7 @@ def placeCursorToLine(editor, line, isRegex=False): return waitForObject(editor) isDarwin = platform.system() == 'Darwin' - if not isinstance(editor, (str, unicode)): + if not isString(editor): editor = objectMap.realName(editor) oldPosition = 0 jumpToFirstLine(getEditor()) @@ -120,7 +120,7 @@ def replaceEditorContent(editor, newcontent): type(editor, newcontent) def typeLines(editor, lines): - if isinstance(lines, (str, unicode)): + if isString(lines): lines = [lines] if isinstance(lines, (list, tuple)): for line in lines: diff --git a/tests/system/shared/fs_utils.py b/tests/system/shared/fs_utils.py index f36fbd7fbf2..ee24d6f0ca3 100644 --- a/tests/system/shared/fs_utils.py +++ b/tests/system/shared/fs_utils.py @@ -35,10 +35,10 @@ def changeFilePermissions(dirPath, readPerm, writePerm, excludeFileNames=None): permission |= stat.S_IWRITE if excludeFileNames == None: excludeFileNames = [] - elif isinstance(excludeFileNames, (str, unicode)): + elif isString(excludeFileNames): excludeFileNames = [excludeFileNames] if not isinstance(excludeFileNames, (tuple, list)): - test.warning("File names to exclude must be of type str, unicode, list, tuple or None - " + test.warning("File names to exclude must be of type str, list, tuple or None - " "ignoring parameter this time.") excludeFileNames = [] if not os.path.isdir(dirPath): diff --git a/tests/system/shared/project_explorer.py b/tests/system/shared/project_explorer.py index 587574ff0a5..a4abeb7a723 100644 --- a/tests/system/shared/project_explorer.py +++ b/tests/system/shared/project_explorer.py @@ -95,8 +95,8 @@ def setRunInTerminal(wantedKit, runInTerminal=True): switchViewTo(ViewConstants.EDIT) def __getTargetFromToolTip__(toolTip): - if toolTip == None or not isinstance(toolTip, (str, unicode)): - test.warning("Parameter toolTip must be of type str or unicode and can't be None!") + if toolTip == None or not isString(toolTip): + test.warning("Parameter toolTip must be of type str and can't be None!") return None pattern = re.compile(".*Kit:(.*)Deploy.*") target = pattern.match(toolTip) @@ -108,7 +108,7 @@ def __getTargetFromToolTip__(toolTip): def getExecutableAndTargetFromToolTip(toolTip): target = __getTargetFromToolTip__(toolTip) - if toolTip == None or not isinstance(toolTip, (str, unicode)): + if toolTip == None or not isString(toolTip): return None, target pattern = re.compile('.*Run:(.*) 2: + return isinstance(sth, str) + else: + return isinstance(sth, (str, unicode)) diff --git a/tests/system/suite_general/tst_default_settings/test.py b/tests/system/suite_general/tst_default_settings/test.py index 2cb40725b82..29c65425b09 100644 --- a/tests/system/suite_general/tst_default_settings/test.py +++ b/tests/system/suite_general/tst_default_settings/test.py @@ -306,7 +306,7 @@ def __compareCompilers__(foundCompilers, expectedCompilers): if isinstance(currentFound, dict): foundExp = False for currentExp in expectedCompilers: - if isinstance(currentExp, (str, unicode)): + if isString(currentExp): continue key = currentExp.keys()[0] # special case for (fuzzy) regex comparison on Windows (internal LLVM) @@ -353,7 +353,7 @@ def __compareDebuggers__(foundDebuggers, expectedDebuggers): def __lowerStrs__(iterable): for it in iterable: - if isinstance(it, (str, unicode)): + if isString(it): yield it.lower() else: yield it From 6073f3396cfece63a98f10dc46f9400d9e4f33dc Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Thu, 27 Jan 2022 08:46:55 +0100 Subject: [PATCH 07/55] QmlDesigner: Disable crashpad in the qml2puppet If the host proecess crashes then qml2puppet will also be shutdown. I suspect this can lead to crash reports of the host application not properly reported. Change-Id: Ic503874ce660db3311958ecd0718255a1cf3daea Reviewed-by: Thomas Hartmann --- share/qtcreator/qml/qmlpuppet/qml2puppet/qml2puppetmain.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/qml2puppetmain.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/qml2puppetmain.cpp index 4b3d047142e..d5371e4b5e4 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/qml2puppetmain.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/qml2puppetmain.cpp @@ -241,7 +241,7 @@ int internalMain(QGuiApplication *application) #endif #if defined(ENABLE_CRASHPAD) && defined(Q_OS_WIN) - startCrashpad(); + /* startCrashpad(); */ #endif new QmlDesigner::Qt5NodeInstanceClientProxy(application); From ff66f501f2d7478986c0547b4fca73ade49645f3 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Thu, 27 Jan 2022 12:36:21 +0100 Subject: [PATCH 08/55] CMakePM: Do not flush CMake parameters model on parsing complete The flush there was as a "hack" for the case: 1. failed initial configuration (CMAKE_GENERATOR as Ninja2) 2. successful configuration The current configuration would get current items with unexpanded values e.g.: QT_QMAKE_EXECUTABLE:STRING=%{Qt:qmakeExecutable} But flush also removed the expanded values of the selected initial parameters from CMakeBuildSystem::updateInitialCMakeExpandableVars This is useful when CMAKE_CXX_COMPILER changes or CMAKE_PROJECT_INCLUDE_BEFORE gets a new path to the new Qt Creator. Change-Id: I480ce141d043d8ba6001fa47a54b066762b6a128 Reviewed-by: Alessandro Portale --- .../cmakebuildconfiguration.cpp | 5 +- .../cmakeprojectmanager/configmodel.cpp | 87 +++++++++++-------- 2 files changed, 55 insertions(+), 37 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index d7ecacc0668..4a39dd9d3b8 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -365,7 +365,6 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc) } connect(bc->buildSystem(), &BuildSystem::parsingFinished, this, [this, stretcher] { - m_configModel->flush(); m_configModel->setConfiguration(m_buildConfiguration->configurationFromCMake()); m_configModel->setInitialParametersConfiguration( m_buildConfiguration->initialCMakeConfiguration()); @@ -1622,6 +1621,8 @@ void InitialCMakeArgumentsAspect::setAllValues(const QString &values, QStringLis arg.replace("-T", "-DCMAKE_GENERATOR_TOOLSET:STRING="); } m_cmakeConfiguration = CMakeConfig::fromArguments(arguments, additionalArguments); + for (CMakeConfigItem &ci : m_cmakeConfiguration) + ci.isInitial = true; // Display the unknown arguments in "Additional CMake parameters" const QString additionalArgumentsValue = ProcessArgs::joinArgs(additionalArguments); @@ -1631,6 +1632,8 @@ void InitialCMakeArgumentsAspect::setAllValues(const QString &values, QStringLis void InitialCMakeArgumentsAspect::setCMakeConfiguration(const CMakeConfig &config) { m_cmakeConfiguration = config; + for (CMakeConfigItem &ci : m_cmakeConfiguration) + ci.isInitial = true; } void InitialCMakeArgumentsAspect::fromMap(const QVariantMap &map) diff --git a/src/plugins/cmakeprojectmanager/configmodel.cpp b/src/plugins/cmakeprojectmanager/configmodel.cpp index aa74f3986b6..fe11f9367b5 100644 --- a/src/plugins/cmakeprojectmanager/configmodel.cpp +++ b/src/plugins/cmakeprojectmanager/configmodel.cpp @@ -272,46 +272,61 @@ void ConfigModel::setInitialParametersConfiguration(const CMakeConfig &config) void ConfigModel::setConfiguration(const QList &config) { - QList tmp = config; - auto newIt = tmp.constBegin(); - auto newEndIt = tmp.constEnd(); - auto oldIt = m_configuration.constBegin(); - auto oldEndIt = m_configuration.constEnd(); + auto mergeLists = [](const QList &oldList, + const QList &newList) -> QList { + auto newIt = newList.constBegin(); + auto newEndIt = newList.constEnd(); + auto oldIt = oldList.constBegin(); + auto oldEndIt = oldList.constEnd(); - QList result; - while (newIt != newEndIt && oldIt != oldEndIt) { - if (oldIt->isUnset) { - ++oldIt; - } else if (newIt->isHidden || newIt->isUnset) { - ++newIt; - } else if (newIt->key < oldIt->key) { - // Add new entry: - result << *newIt; - ++newIt; - } else if (newIt->key > oldIt->key) { - // Keep old user settings, but skip other entries: - if (oldIt->isUserChanged || oldIt->isUserNew) - result << InternalDataItem(*oldIt); - ++oldIt; - } else { - // merge old/new entry: - InternalDataItem item(*newIt); - item.newValue = (newIt->value != oldIt->newValue) ? oldIt->newValue : QString(); - item.isUserChanged = !item.newValue.isEmpty() && (item.newValue != item.value); - result << item; - ++newIt; - ++oldIt; + QList result; + while (newIt != newEndIt && oldIt != oldEndIt) { + if (oldIt->isUnset) { + ++oldIt; + } else if (newIt->isHidden || newIt->isUnset) { + ++newIt; + } else if (newIt->key < oldIt->key) { + // Add new entry: + result << *newIt; + ++newIt; + } else if (newIt->key > oldIt->key) { + // Keep old user settings, but skip other entries: + if (oldIt->isUserChanged || oldIt->isUserNew) + result << InternalDataItem(*oldIt); + ++oldIt; + } else { + // merge old/new entry: + InternalDataItem item(*newIt); + item.newValue = (newIt->value != oldIt->newValue) ? oldIt->newValue : QString(); + item.isUserChanged = !item.newValue.isEmpty() && (item.newValue != item.value); + result << item; + ++newIt; + ++oldIt; + } } - } - // Add remaining new entries: - for (; newIt != newEndIt; ++newIt) { - if (newIt->isHidden) - continue; - result << InternalDataItem(*newIt); - } + // Add remaining new entries: + for (; newIt != newEndIt; ++newIt) { + if (newIt->isHidden) + continue; + result << InternalDataItem(*newIt); + } - m_configuration = result; + return result; + }; + + auto isInitial = [](const InternalDataItem &i) { return i.isInitial; }; + + QList initialOld; + QList currentOld; + std::tie(initialOld, currentOld) = Utils::partition(m_configuration, isInitial); + + QList initialNew; + QList currentNew; + std::tie(initialNew, currentNew) = Utils::partition(config, isInitial); + + m_configuration = mergeLists(initialOld, initialNew); + m_configuration.append(mergeLists(currentOld, currentNew)); generateTree(); } From 3ac3b61727c527910939c192de28e9a844941195 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Fri, 28 Jan 2022 13:34:16 +0200 Subject: [PATCH 09/55] QmlDesigner: Ifdef nanotrace.h out if nanotrace lib is not included Nanotrace headers are not exported to build dir at all if the feature is disabled, so runtime puppet build can't find them. We have to ifdef out the header include and define the required macros as empty in puppet. Fixes: QDS-6107 Change-Id: I702c3ed5521d30ee0b253d035dea4ea00d00848f Reviewed-by: Mahmoud Badri Reviewed-by: Thomas Hartmann Reviewed-by: --- share/qtcreator/qml/qmlpuppet/commands/commands.pri | 2 ++ .../qml/qmlpuppet/instances/nodeinstanceclientproxy.cpp | 9 +++++++++ .../qml2puppet/instances/nodeinstanceserver.cpp | 6 ++++++ .../qml2puppet/instances/qt5nodeinstanceserver.cpp | 9 ++++++++- 4 files changed, 25 insertions(+), 1 deletion(-) diff --git a/share/qtcreator/qml/qmlpuppet/commands/commands.pri b/share/qtcreator/qml/qmlpuppet/commands/commands.pri index 2a0913f72b1..f63b9486f68 100644 --- a/share/qtcreator/qml/qmlpuppet/commands/commands.pri +++ b/share/qtcreator/qml/qmlpuppet/commands/commands.pri @@ -22,6 +22,7 @@ HEADERS += $$PWD/synchronizecommand.h \ \ $$PWD/clearscenecommand.h \ $$PWD/createinstancescommand.h \ $$PWD/informationchangedcommand.h \ + $$PWD/nanotracecommand.h \ $$PWD/pixmapchangedcommand.h \ $$PWD/removeinstancescommand.h \ $$PWD/removepropertiescommand.h \ @@ -54,6 +55,7 @@ SOURCES += $$PWD/synchronizecommand.cpp \ $$PWD/changestatecommand.cpp \ $$PWD/changevaluescommand.cpp \ $$PWD/informationchangedcommand.cpp \ + $$PWD/nanotracecommand.cpp \ $$PWD/removeinstancescommand.cpp \ $$PWD/removepropertiescommand.cpp \ $$PWD/reparentinstancescommand.cpp \ diff --git a/share/qtcreator/qml/qmlpuppet/instances/nodeinstanceclientproxy.cpp b/share/qtcreator/qml/qmlpuppet/instances/nodeinstanceclientproxy.cpp index c1ca741e179..b0ce8ce23eb 100644 --- a/share/qtcreator/qml/qmlpuppet/instances/nodeinstanceclientproxy.cpp +++ b/share/qtcreator/qml/qmlpuppet/instances/nodeinstanceclientproxy.cpp @@ -77,7 +77,16 @@ #include "view3dactioncommand.h" #include "requestmodelnodepreviewimagecommand.h" #include "nanotracecommand.h" + +// Nanotrace headers are not exported to build dir at all if the feature is disabled, so +// runtime puppet build can't find them. +#if NANOTRACE_ENABLED #include "nanotrace/nanotrace.h" +#else +#define NANOTRACE_INIT(process, thread, filepath) +#define NANOTRACE_SHUTDOWN() +#define NANOTRACE_SCOPE_ARGS(cat, name, ...) +#endif namespace QmlDesigner { diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp index 489c8b2b5c3..b37486f0481 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp @@ -72,7 +72,13 @@ #include #include +// Nanotrace headers are not exported to build dir at all if the feature is disabled, so +// runtime puppet build can't find them. +#if NANOTRACE_ENABLED #include "nanotrace/nanotrace.h" +#else +#define NANOTRACE_SCOPE(cat, name) +#endif #include #include diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp index a2627bee257..c97de4636aa 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp @@ -38,7 +38,14 @@ #include #include #include -#include + +// Nanotrace headers are not exported to build dir at all if the feature is disabled, so +// runtime puppet build can't find them. +#if NANOTRACE_ENABLED +#include "nanotrace/nanotrace.h" +#else +#define NANOTRACE_SCOPE(cat, name) +#endif #include #include From 0d3ef2489d9f229c99f3dbcfc58e6029c60fb4a1 Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Wed, 15 Dec 2021 11:56:24 +0200 Subject: [PATCH 10/55] QmlDesigner: Add some states view improvements - Added a gray border around unselected states. - States resize to fit view height. - States are centered vertically in the view. - Removed collapse option, auto collapse when space is small. - scroll bar always at the bottom. - Overshoot list ends. - Added margins around the states. - Add states button: make it small and docked to the bottom right. - Add states button doesnt take space from the view. Change-Id: I4fc96f4341a6e4a0c70509240b7aed9c7890ec4d Reviewed-by: Thomas Hartmann Reviewed-by: Miikka Heikkinen Reviewed-by: Samuel Ghinet Reviewed-by: --- .../statesEditorQmlSources/StatesDelegate.qml | 19 ++-- .../statesEditorQmlSources/StatesList.qml | 98 ++++++------------- .../stateseditor/stateseditorview.cpp | 22 +++-- .../stateseditor/stateseditorview.h | 2 - .../stateseditor/stateseditorwidget.cpp | 21 +--- .../stateseditor/stateseditorwidget.h | 3 - .../designercore/include/viewmanager.h | 2 - .../designercore/model/viewmanager.cpp | 5 - src/plugins/qmldesigner/designersettings.cpp | 1 - src/plugins/qmldesigner/designersettings.h | 1 - src/plugins/qmldesigner/shortcutmanager.cpp | 12 --- src/plugins/qmldesigner/shortcutmanager.h | 1 - 12 files changed, 54 insertions(+), 133 deletions(-) diff --git a/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesDelegate.qml b/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesDelegate.qml index 08a7bc7dc3d..a0477354734 100644 --- a/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesDelegate.qml +++ b/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesDelegate.qml @@ -33,11 +33,8 @@ import StudioTheme 1.0 as StudioTheme Rectangle { id: myRoot - color: baseColor - property bool isBaseState property bool isCurrentState - property color baseColor property string delegateStateName property string delegateStateImageSource property bool delegateHasWhenCondition @@ -47,14 +44,14 @@ Rectangle { property int bottomAreaHeight property int stateMargin property int previewMargin - property int columnSpacing readonly property bool isDefaultState: isDefault property int closeButtonMargin: 6 property int textFieldMargin: 4 - signal delegateInteraction + property int scrollBarH: 0 + property int listMargin: 0 function autoComplete(text, pos, explicitComplete, filter) { var stringList = statesEditorModel.autoComplete(text, pos, explicitComplete) @@ -65,14 +62,19 @@ Rectangle { return statesEditorModel.hasAnnotation(internalNodeId) } + color: isCurrentState ? StudioTheme.Values.themeInteraction + : StudioTheme.Values.themeControlBackgroundInteraction + anchors.verticalCenter: parent.verticalCenter + anchors.verticalCenterOffset: -.5 * (scrollBarH + listMargin) + MouseArea { id: mouseArea anchors.fill: parent + onClicked: { focus = true root.currentStateInternalId = internalNodeId contextMenu.dismiss() // close potentially open context menu - myRoot.delegateInteraction() } } @@ -89,7 +91,6 @@ Rectangle { visible: !isBaseState && isCurrentState onClicked: { - myRoot.delegateInteraction() if (isDefaultState) statesEditorModel.resetDefaultState() @@ -254,9 +255,8 @@ Rectangle { Rectangle { // separator width: column.width - height: myRoot.columnSpacing + height: 2 color: StudioTheme.Values.themeStateSeparator - visible: expanded } Rectangle { @@ -264,7 +264,6 @@ Rectangle { width: myRoot.width - 2 * myRoot.stateMargin height: myRoot.bottomAreaHeight color: StudioTheme.Values.themeStateBackground - visible: expanded Image { anchors.fill: stateImageBackground diff --git a/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesList.qml b/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesList.qml index 6f2dfbbf3d0..718bbb746f9 100644 --- a/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesList.qml +++ b/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesList.qml @@ -33,27 +33,24 @@ import StudioTheme 1.0 as StudioTheme FocusScope { id: root - property int delegateTopAreaHeight: StudioTheme.Values.height + 8 - property int delegateBottomAreaHeight: delegateHeight - 2 * delegateStateMargin - delegateTopAreaHeight - delegateColumnSpacing - property int delegateColumnSpacing: 2 - property int delegateStateMargin: 16 - property int delegatePreviewMargin: 10 - property int effectiveHeight: root.expanded ? Math.max(85, Math.min(287, root.height)) : 85 // height of the states area + readonly property int delegateTopAreaHeight: StudioTheme.Values.height + 8 + readonly property int delegateBottomAreaHeight: delegateHeight - 2 * delegateStateMargin - delegateTopAreaHeight - 2 + readonly property int delegateStateMargin: 16 + readonly property int delegatePreviewMargin: 10 + readonly property int effectiveHeight: root.height < 130 ? 89 : Math.min(root.height, 287) + + readonly property int scrollBarH: statesListView.ScrollBar.horizontal.scrollBarVisible ? StudioTheme.Values.scrollBarThickness : 0 + readonly property int listMargin: 10 + readonly property int delegateWidth: 264 + readonly property int delegateHeight: Math.max(effectiveHeight - scrollBarH - 2 * listMargin, 69) + readonly property int innerSpacing: 2 + + property int currentStateInternalId: 0 signal createNewState signal deleteState(int internalNodeId) signal duplicateCurrentState - property int padding: 2 - property int delegateWidth: 264 - property int delegateHeight: effectiveHeight - - StudioTheme.Values.scrollBarThickness - - 2 * (root.padding + StudioTheme.Values.border) - property int innerSpacing: 2 - property int currentStateInternalId: 0 - - property bool expanded: true - Connections { target: statesEditorModel function onChangedToState(n) { root.currentStateInternalId = n } @@ -65,69 +62,32 @@ FocusScope { color: StudioTheme.Values.themePanelBackground } - MouseArea { - anchors.fill: parent - acceptedButtons: Qt.LeftButton | Qt.RightButton - - onClicked: function(mouse) { - if (mouse.button === Qt.LeftButton) { - contextMenu.dismiss() - focus = true - } else if (mouse.button === Qt.RightButton) { - contextMenu.popup() - } - } - - StudioControls.Menu { - id: contextMenu - - StudioControls.MenuItem { - text: root.expanded ? qsTr("Collapse") : qsTr("Expand") - onTriggered: root.expanded = !root.expanded - } - } - } - AbstractButton { id: addStateButton - buttonIcon: root.expanded ? qsTr("Create New State") : StudioTheme.Constants.plus - iconFont: root.expanded ? StudioTheme.Constants.font : StudioTheme.Constants.iconFont - iconSize: root.expanded ? StudioTheme.Values.myFontSize : StudioTheme.Values.myIconFontSize - iconItalic: root.expanded + buttonIcon: StudioTheme.Constants.plus + iconFont: StudioTheme.Constants.iconFont + iconSize: StudioTheme.Values.myIconFontSize tooltip: qsTr("Add a new state.") visible: canAddNewStates anchors.right: parent.right - anchors.rightMargin: 8 - y: (Math.min(effectiveHeight, root.height) - height) / 2 - width: root.expanded ? 140 : 18 - height: root.expanded ? 60 : 18 + anchors.rightMargin: 4 + anchors.bottom: parent.bottom + anchors.bottomMargin: 4 + scrollBarH + width: 30 + height: 30 - onClicked: { - contextMenu.dismiss() - root.createNewState() - } - } - - Rectangle { // separator lines between state items - color: StudioTheme.Values.themeStateSeparator - x: root.padding - y: root.padding - width: statesListView.width - height: root.delegateHeight + onClicked: root.createNewState() } ListView { id: statesListView - boundsBehavior: Flickable.StopAtBounds clip: true - - x: root.padding - y: root.padding - width: Math.min(root.delegateWidth * statesListView.count + root.innerSpacing * (statesListView.count - 1), - root.width - addStateButton.width - root.padding - 16) // 16 = 2 * 8 (addStateButton margin) - height: root.delegateHeight + StudioTheme.Values.scrollBarThickness + anchors.fill: parent + anchors.topMargin: listMargin + anchors.leftMargin: listMargin + anchors.rightMargin: listMargin model: statesEditorModel orientation: ListView.Horizontal @@ -139,20 +99,18 @@ FocusScope { height: root.delegateHeight isBaseState: 0 === internalNodeId isCurrentState: root.currentStateInternalId === internalNodeId - baseColor: isCurrentState ? StudioTheme.Values.themeInteraction : background.color delegateStateName: stateName delegateStateImageSource: stateImageSource delegateHasWhenCondition: hasWhenCondition delegateWhenConditionString: whenConditionString - onDelegateInteraction: contextMenu.dismiss() - columnSpacing: root.delegateColumnSpacing topAreaHeight: root.delegateTopAreaHeight bottomAreaHeight: root.delegateBottomAreaHeight stateMargin: root.delegateStateMargin previewMargin: root.delegatePreviewMargin + scrollBarH: root.scrollBarH + listMargin: root.listMargin } - ScrollBar.horizontal: HorizontalScrollBar {} } } diff --git a/src/plugins/qmldesigner/components/stateseditor/stateseditorview.cpp b/src/plugins/qmldesigner/components/stateseditor/stateseditorview.cpp index 997852cfb25..cf1f3771412 100644 --- a/src/plugins/qmldesigner/components/stateseditor/stateseditorview.cpp +++ b/src/plugins/qmldesigner/components/stateseditor/stateseditorview.cpp @@ -85,12 +85,6 @@ void StatesEditorView::rootNodeTypeChanged(const QString &/*type*/, int /*majorV checkForStatesAvailability(); } -void StatesEditorView::toggleStatesViewExpanded() -{ - if (m_statesEditorWidget) - m_statesEditorWidget->toggleStatesViewExpanded(); -} - void StatesEditorView::removeState(int nodeId) { try { @@ -102,6 +96,22 @@ void StatesEditorView::removeState(int nodeId) if (modelState.isValid()) { QStringList lockedTargets; const auto propertyChanges = modelState.propertyChanges(); + + // confirm removing not empty states + if (!propertyChanges.isEmpty()) { + QMessageBox msgBox; + msgBox.setTextFormat(Qt::RichText); + msgBox.setIcon(QMessageBox::Question); + msgBox.setWindowTitle(tr("Remove State")); + msgBox.setText(tr("This state is not empty. Are you sure you want to remove it?")); + msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel); + msgBox.setDefaultButton(QMessageBox::Yes); + + if (msgBox.exec() == QMessageBox::Cancel) + return; + } + + // confirm removing states with locked targets for (const QmlPropertyChanges &change : propertyChanges) { const ModelNode target = change.target(); QTC_ASSERT(target.isValid(), continue); diff --git a/src/plugins/qmldesigner/components/stateseditor/stateseditorview.h b/src/plugins/qmldesigner/components/stateseditor/stateseditorview.h index 1ac7a6f39fa..71a82711eaa 100644 --- a/src/plugins/qmldesigner/components/stateseditor/stateseditorview.h +++ b/src/plugins/qmldesigner/components/stateseditor/stateseditorview.h @@ -87,8 +87,6 @@ public: void rootNodeTypeChanged(const QString &type, int majorVersion, int minorVersion) override; - void toggleStatesViewExpanded(); - public slots: void synchonizeCurrentStateFromWidget(); void createNewState(); diff --git a/src/plugins/qmldesigner/components/stateseditor/stateseditorwidget.cpp b/src/plugins/qmldesigner/components/stateseditor/stateseditorwidget.cpp index 4701a4079eb..b7b391944ad 100644 --- a/src/plugins/qmldesigner/components/stateseditor/stateseditorwidget.cpp +++ b/src/plugins/qmldesigner/components/stateseditor/stateseditorwidget.cpp @@ -133,13 +133,6 @@ QString StatesEditorWidget::qmlSourcesPath() return Core::ICore::resourcePath("qmldesigner/statesEditorQmlSources").toString(); } -void StatesEditorWidget::toggleStatesViewExpanded() -{ - QTC_ASSERT(rootObject(), return); - bool expanded = rootObject()->property("expanded").toBool(); - rootObject()->setProperty("expanded", !expanded); -} - void StatesEditorWidget::showEvent(QShowEvent *event) { QQuickWidget::showEvent(event); @@ -168,18 +161,6 @@ void StatesEditorWidget::reloadQmlSource() connect(rootObject(), SIGNAL(createNewState()), m_statesEditorView.data(), SLOT(createNewState())); connect(rootObject(), SIGNAL(deleteState(int)), m_statesEditorView.data(), SLOT(removeState(int))); m_statesEditorView.data()->synchonizeCurrentStateFromWidget(); - - if (!DesignerSettings::getValue(DesignerSettingsKey::STATESEDITOR_EXPANDED).toBool()) - toggleStatesViewExpanded(); - - connect(rootObject(), SIGNAL(expandedChanged()), this, SLOT(handleExpandedChanged())); } -void StatesEditorWidget::handleExpandedChanged() -{ - QTC_ASSERT(rootObject(), return); - - bool expanded = rootObject()->property("expanded").toBool(); - DesignerSettings::setValue(DesignerSettingsKey::STATESEDITOR_EXPANDED, expanded); -} -} +} // QmlDesigner diff --git a/src/plugins/qmldesigner/components/stateseditor/stateseditorwidget.h b/src/plugins/qmldesigner/components/stateseditor/stateseditorwidget.h index e4e9668abb0..b613e600c44 100644 --- a/src/plugins/qmldesigner/components/stateseditor/stateseditorwidget.h +++ b/src/plugins/qmldesigner/components/stateseditor/stateseditorwidget.h @@ -57,14 +57,11 @@ public: static QString qmlSourcesPath(); - void toggleStatesViewExpanded(); - protected: void showEvent(QShowEvent *) override; private: void reloadQmlSource(); - Q_SLOT void handleExpandedChanged(); private: QPointer m_statesEditorView; diff --git a/src/plugins/qmldesigner/designercore/include/viewmanager.h b/src/plugins/qmldesigner/designercore/include/viewmanager.h index af4bf8bb24f..114c143e6af 100644 --- a/src/plugins/qmldesigner/designercore/include/viewmanager.h +++ b/src/plugins/qmldesigner/designercore/include/viewmanager.h @@ -94,8 +94,6 @@ public: DesignerActionManager &designerActionManager(); const DesignerActionManager &designerActionManager() const; - void toggleStatesViewExpanded(); - void qmlJSEditorContextHelp(const Core::IContext::HelpCallback &callback) const; DesignDocument *currentDesignDocument() const; diff --git a/src/plugins/qmldesigner/designercore/model/viewmanager.cpp b/src/plugins/qmldesigner/designercore/model/viewmanager.cpp index c20ecf4b61d..01e5f3e4c65 100644 --- a/src/plugins/qmldesigner/designercore/model/viewmanager.cpp +++ b/src/plugins/qmldesigner/designercore/model/viewmanager.cpp @@ -405,11 +405,6 @@ const DesignerActionManager &ViewManager::designerActionManager() const return d->designerActionManagerView.designerActionManager(); } -void ViewManager::toggleStatesViewExpanded() -{ - d->statesEditorView.toggleStatesViewExpanded(); -} - void ViewManager::qmlJSEditorContextHelp(const Core::IContext::HelpCallback &callback) const { d->textEditorView.qmlJSEditorContextHelp(callback); diff --git a/src/plugins/qmldesigner/designersettings.cpp b/src/plugins/qmldesigner/designersettings.cpp index 08788ca5bef..8ecaaa6edd9 100644 --- a/src/plugins/qmldesigner/designersettings.cpp +++ b/src/plugins/qmldesigner/designersettings.cpp @@ -72,7 +72,6 @@ void DesignerSettings::fromSettings(QSettings *settings) restoreValue(settings, DesignerSettingsKey::FORWARD_PUPPET_OUTPUT, QString()); restoreValue(settings, DesignerSettingsKey::REFORMAT_UI_QML_FILES, true); restoreValue(settings, DesignerSettingsKey::IGNORE_DEVICE_PIXEL_RATIO, false); - restoreValue(settings, DesignerSettingsKey::STATESEDITOR_EXPANDED, true); restoreValue(settings, DesignerSettingsKey::NAVIGATOR_SHOW_ONLY_VISIBLE_ITEMS, true); restoreValue(settings, DesignerSettingsKey::NAVIGATOR_REVERSE_ITEM_ORDER, false); restoreValue(settings, DesignerSettingsKey::STANDALONE_MODE, false); diff --git a/src/plugins/qmldesigner/designersettings.h b/src/plugins/qmldesigner/designersettings.h index 0afb86d6dd6..bb25e2e04c9 100644 --- a/src/plugins/qmldesigner/designersettings.h +++ b/src/plugins/qmldesigner/designersettings.h @@ -60,7 +60,6 @@ const char ENABLE_MODEL_EXCEPTION_OUTPUT[] = "WarnException"; const char PUPPET_KILL_TIMEOUT[] = "PuppetKillTimeout"; const char DEBUG_PUPPET[] = "DebugPuppet"; const char FORWARD_PUPPET_OUTPUT[] = "ForwardPuppetOutput"; -const char STATESEDITOR_EXPANDED[] = "StatesEditorExpanded"; const char NAVIGATOR_SHOW_ONLY_VISIBLE_ITEMS[] = "NavigatorShowOnlyVisibleItems"; const char NAVIGATOR_REVERSE_ITEM_ORDER[] = "NavigatorReverseItemOrder"; const char REFORMAT_UI_QML_FILES[] = "ReformatUiQmlFiles"; /* These settings are not exposed in ui. */ diff --git a/src/plugins/qmldesigner/shortcutmanager.cpp b/src/plugins/qmldesigner/shortcutmanager.cpp index 25d1c27c471..e82e7a04c01 100644 --- a/src/plugins/qmldesigner/shortcutmanager.cpp +++ b/src/plugins/qmldesigner/shortcutmanager.cpp @@ -69,7 +69,6 @@ ShortCutManager::ShortCutManager() m_copyAction(tr("&Copy")), m_pasteAction(tr("&Paste")), m_selectAllAction(tr("Select &All")), - m_collapseExpandStatesAction(tr("Toggle States")), m_escapeAction(this) { @@ -97,10 +96,6 @@ void ShortCutManager::registerActions(const Core::Context &qmlDesignerMainContex connect(&m_selectAllAction,&QAction::triggered, this, &ShortCutManager::selectAll); - connect(&m_collapseExpandStatesAction, &QAction::triggered, [] { - QmlDesignerPlugin::instance()->viewManager().toggleStatesViewExpanded(); - }); - // Revert to saved Core::EditorManager *em = Core::EditorManager::instance(); Core::ActionManager::registerAction(&m_revertToSavedAction,Core::Constants::REVERTTOSAVED, qmlDesignerMainContext); @@ -188,13 +183,6 @@ void ShortCutManager::registerActions(const Core::Context &qmlDesignerMainContex command->setDefaultKeySequence(QKeySequence::SelectAll); editMenu->addAction(command, Core::Constants::G_EDIT_SELECTALL); - Core::ActionContainer *viewsMenu = Core::ActionManager::actionContainer(Core::Constants::M_VIEW_VIEWS); - - command = Core::ActionManager::registerAction(&m_collapseExpandStatesAction, Constants::TOGGLE_STATES_EDITOR, qmlDesignerMainContext); - command->setAttribute(Core::Command::CA_Hide); - command->setDefaultKeySequence(QKeySequence("Ctrl+Alt+s")); - viewsMenu->addAction(command); - /* Registering disabled action for Escape, because Qt Quick does not support shortcut overrides. */ command = Core::ActionManager::registerAction(&m_escapeAction, Core::Constants::S_RETURNTOEDITOR, qmlDesignerMainContext); command->setDefaultKeySequence(QKeySequence(Qt::Key_Escape)); diff --git a/src/plugins/qmldesigner/shortcutmanager.h b/src/plugins/qmldesigner/shortcutmanager.h index 6e5b5ec23bd..4bc4ae5f848 100644 --- a/src/plugins/qmldesigner/shortcutmanager.h +++ b/src/plugins/qmldesigner/shortcutmanager.h @@ -83,7 +83,6 @@ private: QAction m_copyAction; QAction m_pasteAction; QAction m_selectAllAction; - QAction m_collapseExpandStatesAction; QAction m_escapeAction; }; From d5eab1135940531914cdd6a98f5b75efd56c7920 Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Fri, 21 Jan 2022 13:34:16 +0200 Subject: [PATCH 11/55] QmlDesigner/StateEditor: Improve adding new states - Added a big add button at the end of the states list. - Small add states button jumps in (bottom right) when the big button is out of the view. - View scrolls to the end when a new slide is added. Task-number: QDS-5973 Change-Id: Ida96bd663cc0caf32889638fbf4ac9f617916368 Reviewed-by: Miikka Heikkinen Reviewed-by: Thomas Hartmann --- .../statesEditorQmlSources/StatesDelegate.qml | 3 - .../statesEditorQmlSources/StatesList.qml | 105 ++++++++++++++---- .../stateseditor/stateseditormodel.cpp | 45 ++++---- .../stateseditor/stateseditormodel.h | 3 +- 4 files changed, 110 insertions(+), 46 deletions(-) diff --git a/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesDelegate.qml b/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesDelegate.qml index a0477354734..7d0aa14cfd6 100644 --- a/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesDelegate.qml +++ b/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesDelegate.qml @@ -64,9 +64,6 @@ Rectangle { color: isCurrentState ? StudioTheme.Values.themeInteraction : StudioTheme.Values.themeControlBackgroundInteraction - anchors.verticalCenter: parent.verticalCenter - anchors.verticalCenterOffset: -.5 * (scrollBarH + listMargin) - MouseArea { id: mouseArea anchors.fill: parent diff --git a/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesList.qml b/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesList.qml index 718bbb746f9..ef2cbdf62f7 100644 --- a/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesList.qml +++ b/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesList.qml @@ -26,6 +26,7 @@ import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuickDesignerTheme 1.0 +import Qt.labs.qmlmodels 1.0 import HelperWidgets 2.0 import StudioControls 1.0 as StudioControls import StudioTheme 1.0 as StudioTheme @@ -73,9 +74,16 @@ FocusScope { anchors.right: parent.right anchors.rightMargin: 4 anchors.bottom: parent.bottom - anchors.bottomMargin: 4 + scrollBarH - width: 30 - height: 30 + anchors.bottomMargin: statesListView.contentWidth - statesListView.contentX - root.delegateWidth / 2 > statesListView.width ? scrollBarH + 5 : -35 + width: 35 + height: 35 + + Behavior on anchors.bottomMargin { + PropertyAnimation { + duration: 700 + easing.type: Easing.InOutBack + } + } onClicked: root.createNewState() } @@ -93,24 +101,81 @@ FocusScope { orientation: ListView.Horizontal spacing: root.innerSpacing - delegate: StatesDelegate { - id: statesDelegate - width: root.delegateWidth - height: root.delegateHeight - isBaseState: 0 === internalNodeId - isCurrentState: root.currentStateInternalId === internalNodeId - delegateStateName: stateName - delegateStateImageSource: stateImageSource - delegateHasWhenCondition: hasWhenCondition - delegateWhenConditionString: whenConditionString - - topAreaHeight: root.delegateTopAreaHeight - bottomAreaHeight: root.delegateBottomAreaHeight - stateMargin: root.delegateStateMargin - previewMargin: root.delegatePreviewMargin - scrollBarH: root.scrollBarH - listMargin: root.listMargin + property int prevCount: 0 + onCountChanged: { + if (count > prevCount) + Qt.callLater(statesListView.positionViewAtEnd) + prevCount = count } + + delegate: DelegateChooser { + role: "type" + + DelegateChoice { + roleValue: "state" + + StatesDelegate { + width: root.delegateWidth + height: root.delegateHeight + anchors.verticalCenter: parent ? parent.verticalCenter : undefined + anchors.verticalCenterOffset: -.5 * (scrollBarH + listMargin) + isBaseState: 0 === internalNodeId + isCurrentState: root.currentStateInternalId === internalNodeId + delegateStateName: stateName + delegateStateImageSource: stateImageSource + delegateHasWhenCondition: hasWhenCondition + delegateWhenConditionString: whenConditionString + + topAreaHeight: root.delegateTopAreaHeight + bottomAreaHeight: root.delegateBottomAreaHeight + stateMargin: root.delegateStateMargin + previewMargin: root.delegatePreviewMargin + scrollBarH: root.scrollBarH + listMargin: root.listMargin + } + } + + DelegateChoice { + roleValue: "add" + + Rectangle { + visible: canAddNewStates + + width: root.delegateWidth + height: root.delegateHeight + anchors.verticalCenter: parent ? parent.verticalCenter : undefined + anchors.verticalCenterOffset: -.5 * (scrollBarH + listMargin) + color: Qt.lighter(StudioTheme.Values.themeControlBackgroundInteraction, addState.containsMouse ? 1.5 : 1) + + ToolTip.text: qsTr("Add a new state.") + ToolTip.visible: addState.containsMouse + ToolTip.delay: 1000 + + Rectangle { // inner rect + width: parent.width - 30 + height: parent.height - 30 + anchors.centerIn: parent + color: StudioTheme.Values.themeStateBackground + } + + Text { + text: "+" + anchors.centerIn: parent + anchors.verticalCenterOffset: -5 + font.pixelSize: parent.height * .5 + color: Qt.lighter(StudioTheme.Values.themeControlBackgroundInteraction, addState.containsMouse ? 1.5 : 1) + } + + MouseArea { + id: addState + hoverEnabled: true + anchors.fill: parent + onClicked: root.createNewState() + } + } + } + } + ScrollBar.horizontal: HorizontalScrollBar {} } } diff --git a/src/plugins/qmldesigner/components/stateseditor/stateseditormodel.cpp b/src/plugins/qmldesigner/components/stateseditor/stateseditormodel.cpp index 1828317a9e8..2d96d01a9dc 100644 --- a/src/plugins/qmldesigner/components/stateseditor/stateseditormodel.cpp +++ b/src/plugins/qmldesigner/components/stateseditor/stateseditormodel.cpp @@ -53,7 +53,6 @@ StatesEditorModel::StatesEditorModel(StatesEditorView *view) { } - int StatesEditorModel::count() const { return rowCount(); @@ -64,9 +63,8 @@ QModelIndex StatesEditorModel::index(int row, int column, const QModelIndex &par if (m_statesEditorView.isNull()) return {}; - int internalNodeId = 0; - if (row > 0) + if (row > 0 && row < rowCount() - 1) // first and last rows are base state, add state internalNodeId = m_statesEditorView->rootModelNode().nodeListProperty("states").at(row - 1).internalId(); return hasIndex(row, column, parent) ? createIndex(row, column, internalNodeId) : QModelIndex(); @@ -78,9 +76,9 @@ int StatesEditorModel::rowCount(const QModelIndex &parent) const return 0; if (!m_statesEditorView->rootModelNode().hasNodeListProperty("states")) - return 1; + return 2; // base state + add new state - return m_statesEditorView->rootModelNode().nodeListProperty("states").count() + 1; + return m_statesEditorView->rootModelNode().nodeListProperty("states").count() + 2; // 2 = base state + add new state } void StatesEditorModel::reset() @@ -101,16 +99,16 @@ QVariant StatesEditorModel::data(const QModelIndex &index, int role) const switch (role) { case StateNameRole: { - if (index.row() == 0) { - return tr("base state", "Implicit default state"); - } else { - if (stateNode.hasVariantProperty("name")) - return stateNode.variantProperty("name").value(); - else - return QVariant(); - } - + if (index.row() == 0) { + return tr("base state", "Implicit default state"); + } else { + if (stateNode.hasVariantProperty("name")) + return stateNode.variantProperty("name").value(); + else + return QVariant(); } + } + case StateImageSourceRole: { static int randomNumber = 0; randomNumber++; @@ -119,9 +117,12 @@ QVariant StatesEditorModel::data(const QModelIndex &index, int role) const else return QString("image://qmldesigner_stateseditor/%1-%2").arg(index.internalId()).arg(randomNumber); } - case InternalNodeId: return index.internalId(); - case HasWhenCondition: return stateNode.isValid() && stateNode.hasProperty("when"); + case InternalNodeId: + return index.internalId(); + + case HasWhenCondition: + return stateNode.isValid() && stateNode.hasProperty("when"); case WhenConditionString: { if (stateNode.isValid() && stateNode.hasBindingProperty("when")) @@ -137,10 +138,11 @@ QVariant StatesEditorModel::data(const QModelIndex &index, int role) const return false; } - case ModelHasDefaultState: { + case ModelHasDefaultState: return hasDefaultState(); - } + case StateType: + return index.row() == rowCount() - 1 ? "add" : "state"; } return QVariant(); @@ -148,14 +150,15 @@ QVariant StatesEditorModel::data(const QModelIndex &index, int role) const QHash StatesEditorModel::roleNames() const { - static QHash roleNames{ + static QHash roleNames { {StateNameRole, "stateName"}, {StateImageSourceRole, "stateImageSource"}, {InternalNodeId, "internalNodeId"}, {HasWhenCondition, "hasWhenCondition"}, {WhenConditionString, "whenConditionString"}, {IsDefault, "isDefault"}, - {ModelHasDefaultState, "modelHasDefaultState"} + {ModelHasDefaultState, "modelHasDefaultState"}, + {StateType, "type"} }; return roleNames; } @@ -163,10 +166,8 @@ QHash StatesEditorModel::roleNames() const void StatesEditorModel::insertState(int stateIndex) { if (stateIndex >= 0) { - const int updateIndex = stateIndex + 1; beginInsertRows(QModelIndex(), updateIndex, updateIndex); - endInsertRows(); emit dataChanged(index(updateIndex, 0), index(updateIndex, 0)); diff --git a/src/plugins/qmldesigner/components/stateseditor/stateseditormodel.h b/src/plugins/qmldesigner/components/stateseditor/stateseditormodel.h index 65c1385e897..d467e4fceb1 100644 --- a/src/plugins/qmldesigner/components/stateseditor/stateseditormodel.h +++ b/src/plugins/qmldesigner/components/stateseditor/stateseditormodel.h @@ -44,7 +44,8 @@ class StatesEditorModel : public QAbstractListModel HasWhenCondition, WhenConditionString, IsDefault, - ModelHasDefaultState + ModelHasDefaultState, + StateType }; public: From f51928d43869d875771ad8fc6a5bb2956eaa8855 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 27 Jan 2022 11:04:39 +0100 Subject: [PATCH 12/55] Update perfparser submodule Change-Id: Ief0eb584f4fc9f8ff68fdc138e63fddfd7e1e697 Reviewed-by: Ulf Hermann Reviewed-by: --- src/tools/perfparser | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/perfparser b/src/tools/perfparser index 84180a4bbe9..d494f98900b 160000 --- a/src/tools/perfparser +++ b/src/tools/perfparser @@ -1 +1 @@ -Subproject commit 84180a4bbe9fad1426b6f6633b3d3b2f8d14d361 +Subproject commit d494f98900b2cd880ce3450074c69f708962804f From 9cbf0904db53d64ae9e1c33645ef113ed8038f89 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Thu, 27 Jan 2022 12:17:12 +0200 Subject: [PATCH 13/55] Clang: Remove redundant warning suppressions They are no longer needed with Clang 12. Change-Id: I964d53e6a106b38cd32a7f34bbad6e15e0dd7e48 Reviewed-by: Reviewed-by: Cristian Adam --- cmake/FindClang.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/FindClang.cmake b/cmake/FindClang.cmake index 2e36d9752a3..1133558dc76 100644 --- a/cmake/FindClang.cmake +++ b/cmake/FindClang.cmake @@ -2,7 +2,7 @@ find_package(Clang CONFIG) # silence a lot of warnings from building against llvm if(MSVC AND TARGET libclang) - target_compile_options(libclang INTERFACE /wd4100 /wd4141 /wd4146 /wd4244 /wd4267 /wd4291) + target_compile_options(libclang INTERFACE /wd4267) endif() option(CLANGTOOLING_LINK_CLANG_DYLIB "Force linking of Clang tooling against clang-cpp" NO) From d087fe424de7f60c2d16220aa94fb94bb9bfeb51 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Fri, 31 Dec 2021 21:01:46 +0100 Subject: [PATCH 14/55] Android: Set debugger sysroot also for recent Ndk versions Android debug support specifies the sysroot inside the used Ndk. Recent Ndk versions have a different folder structure which moved the sysroot location inside the Ndk to somewhere else. This change adds finding the sysroot in the new directory layout in case it cannot be found in the traditional location. Instead of Ndk version checks, this code uses FilePath::exists to see if the sysroot is valid. Fixes: QTCREATORBUG-26814 Change-Id: I37db3043e405b83168d7c80c522d31bc148e458c Reviewed-by: Assam Boudjelthia --- src/plugins/android/androidconfigurations.cpp | 2 +- src/plugins/android/androiddebugsupport.cpp | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index ca8e29eb383..a58ed30f19e 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -881,7 +881,7 @@ bool AndroidConfig::isValidNdk(const QString &ndkLocation) const const FilePath ndkPlatformsDir = ndkPath.pathAppended("platforms"); if (version.majorVersion() <= 22 && (!ndkPlatformsDir.exists() || ndkPlatformsDir.toString().contains(' '))) - return false; // TODO: Adapt code that assumes the presence of a "platforms" folder + return false; return true; } diff --git a/src/plugins/android/androiddebugsupport.cpp b/src/plugins/android/androiddebugsupport.cpp index ab7dd8d4301..c92ec6af462 100644 --- a/src/plugins/android/androiddebugsupport.cpp +++ b/src/plugins/android/androiddebugsupport.cpp @@ -168,14 +168,15 @@ void AndroidDebugSupport::start() const int minimumNdk = qt ? qt->minimumNDK() : 0; int sdkVersion = qMax(AndroidManager::minimumSDK(kit), minimumNdk); - // TODO find a way to use the new sysroot layout - // instead ~/android/ndk-bundle/platforms/android-29/arch-arm64 - // use ~/android/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64/sysroot if (qtVersion) { - Utils::FilePath sysRoot = AndroidConfigurations::currentConfig().ndkLocation(qtVersion) + const FilePath ndkLocation = + AndroidConfigurations::currentConfig().ndkLocation(qtVersion); + Utils::FilePath sysRoot = ndkLocation / "platforms" / QString("android-%1").arg(sdkVersion) - / devicePreferredAbi; + / devicePreferredAbi; // Legacy Ndk structure + if (!sysRoot.exists()) + sysRoot = AndroidConfig::toolchainPathFromNdk(ndkLocation) / "sysroot"; setSysRoot(sysRoot); qCDebug(androidDebugSupportLog) << "Sysroot: " << sysRoot; } From 49443d689e6ebac22ab756413ea1d6baac314dd4 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Tue, 25 Jan 2022 09:28:43 +0100 Subject: [PATCH 15/55] Android: Detect available Ndk platforms also for recent Ndk versions In order to detect the list of platforms that an Ndk installation supports, AndroidConfig::availableNdkPlatforms iterates through the directories of the Ndk. The directory structure of the Ndk changed in the recent versions. So that the detection that works with Ndk 19 does not work with Ndk 23. Also, the new directory structure is split up by Android ABI. And the lists of supported platforms differ between ABI. This change adds detection for the new structure, in case that the old implementation fails to return a list. It also adds an autotest that covers the old and new detection of supported platforms. Fixes: QTCREATORBUG-26772 Change-Id: I6e584963f51feca0bf90c7ed3a9fdb03cb5d39e6 Reviewed-by: Assam Boudjelthia --- src/plugins/android/CMakeLists.txt | 6 + src/plugins/android/android.qbs | 8 ++ src/plugins/android/android_tst.qrc | 71 ++++++++++++ src/plugins/android/androidconfigurations.cpp | 106 +++++++++++++++++- src/plugins/android/androidconfigurations.h | 3 +- src/plugins/android/androidplugin.h | 2 + 6 files changed, 190 insertions(+), 6 deletions(-) create mode 100644 src/plugins/android/android_tst.qrc diff --git a/src/plugins/android/CMakeLists.txt b/src/plugins/android/CMakeLists.txt index b87f7ad1d24..2f4b06f634a 100644 --- a/src/plugins/android/CMakeLists.txt +++ b/src/plugins/android/CMakeLists.txt @@ -54,3 +54,9 @@ add_qtc_plugin(Android splashscreencontainerwidget.cpp splashscreencontainerwidget.h splashscreenwidget.cpp splashscreenwidget.h ) + +extend_qtc_plugin(Android + CONDITION WITH_TESTS + SOURCES + android_tst.qrc +) diff --git a/src/plugins/android/android.qbs b/src/plugins/android/android.qbs index 08e69d9421c..9d655cad61a 100644 --- a/src/plugins/android/android.qbs +++ b/src/plugins/android/android.qbs @@ -120,5 +120,13 @@ Project { "splashscreenwidget.cpp", "splashscreenwidget.h" ] + + Group { + name: "Unit tests" + condition: qtc.testsEnabled + files: [ + "android_tst.qrc", + ] + } } } diff --git a/src/plugins/android/android_tst.qrc b/src/plugins/android/android_tst.qrc new file mode 100644 index 00000000000..2d557291176 --- /dev/null +++ b/src/plugins/android/android_tst.qrc @@ -0,0 +1,71 @@ + + + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + + diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index a58ed30f19e..ef3aa2d6053 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -77,6 +77,11 @@ #include #include +#ifdef WITH_TESTS +# include +# include "androidplugin.h" +#endif // WITH_TESTS + using namespace QtSupport; using namespace ProjectExplorer; using namespace Utils; @@ -368,11 +373,11 @@ void AndroidConfig::parseDependenciesJson() } } -QVector AndroidConfig::availableNdkPlatforms(const QtVersion *qtVersion) const +static QVector availableNdkPlatformsLegacy(const FilePath &ndkLocation) { QVector availableNdkPlatforms; - ndkLocation(qtVersion) + ndkLocation .pathAppended("platforms") .iterateDirectory( [&availableNdkPlatforms](const FilePath &filePath) { @@ -384,10 +389,43 @@ QVector AndroidConfig::availableNdkPlatforms(const QtVersion *qtVersion) co }, {{"android-*"}, QDir::Dirs}); - Utils::sort(availableNdkPlatforms, std::greater<>()); return availableNdkPlatforms; } +static QVector availableNdkPlatformsV21Plus(const FilePath &ndkLocation, const Abis &abis, + OsType hostOs) +{ + if (abis.isEmpty()) + return {}; + + const QString abi = AndroidConfig::toolsPrefix(abis.first()); + const FilePath libPath = + AndroidConfig::toolchainPathFromNdk(ndkLocation, hostOs) / "sysroot/usr/lib" / abi; + const QList dirEntries = libPath.dirEntries(QDir::Dirs | QDir::NoDotAndDotDot); + const QVector availableNdkPlatforms = + Utils::transform(dirEntries, [](const FilePath &path) { + return path.fileName().toInt(); }); + return availableNdkPlatforms; +} + +static QVector availableNdkPlatformsImpl(const FilePath &ndkLocation, const Abis &abis, + OsType hostOs) +{ + QVector result = availableNdkPlatformsLegacy(ndkLocation); + + if (result.isEmpty()) + result = availableNdkPlatformsV21Plus(ndkLocation, abis, hostOs); + + Utils::sort(result, std::greater<>()); + return result; +} + +QVector AndroidConfig::availableNdkPlatforms(const QtVersion *qtVersion) const +{ + return availableNdkPlatformsImpl(ndkLocation(qtVersion), qtVersion->qtAbis(), + HostOsInfo::hostOs()); +} + QStringList AndroidConfig::getCustomNdkList() const { return m_customNdkList; @@ -513,7 +551,7 @@ FilePath AndroidConfig::avdManagerToolPath() const return FilePath(); } -FilePath AndroidConfig::toolchainPathFromNdk(const FilePath &ndkLocation) +FilePath AndroidConfig::toolchainPathFromNdk(const FilePath &ndkLocation, OsType hostOs) { const FilePath tcPath = ndkLocation / "toolchains/"; FilePath toolchainPath; @@ -525,7 +563,7 @@ FilePath AndroidConfig::toolchainPathFromNdk(const FilePath &ndkLocation) // detect toolchain host QStringList hostPatterns; - switch (HostOsInfo::hostOs()) { + switch (hostOs) { case OsTypeLinux: hostPatterns << QLatin1String("linux*"); break; @@ -1641,4 +1679,62 @@ void AndroidConfigurations::updateAndroidDevice() AndroidConfigurations *AndroidConfigurations::m_instance = nullptr; +#ifdef WITH_TESTS +void AndroidPlugin::testAndroidConfigAvailableNdkPlatforms_data() +{ + QTest::addColumn("ndkPath"); + QTest::addColumn("abis"); + QTest::addColumn("hostOs"); + QTest::addColumn >("expectedPlatforms"); + + QTest::newRow("ndkLegacy") + << FilePath::fromUserInput(":/android/tst/ndk/19.2.5345600") + << Abis() + << OsTypeOther + << QVector{28, 27, 26, 24, 23, 22, 21, 19, 18, 17, 16}; + + const FilePath ndkV21Plus = FilePath::fromUserInput(":/android/tst/ndk/23.1.7779620"); + const QVector abis32Bit = {31, 30, 29, 28, 27, 26, 24, 23, 22, 21, 19, 18, 17, 16}; + const QVector abis64Bit = {31, 30, 29, 28, 27, 26, 24, 23, 22, 21}; + QTest::newRow("ndkV21Plus armeabi-v7a OsTypeWindows") + << ndkV21Plus + << Abis{AndroidManager::androidAbi2Abi( + ProjectExplorer::Constants::ANDROID_ABI_ARMEABI_V7A)} + << OsTypeWindows + << abis32Bit; + + QTest::newRow("ndkV21Plus arm64-v8a OsTypeLinux") + << ndkV21Plus + << Abis{AndroidManager::androidAbi2Abi( + ProjectExplorer::Constants::ANDROID_ABI_ARM64_V8A)} + << OsTypeLinux + << abis64Bit; + + QTest::newRow("ndkV21Plus x86 OsTypeMac") + << ndkV21Plus + << Abis{AndroidManager::androidAbi2Abi( + ProjectExplorer::Constants::ANDROID_ABI_X86)} + << OsTypeMac + << abis32Bit; + + QTest::newRow("ndkV21Plus x86_64 OsTypeWindows") + << ndkV21Plus + << Abis{AndroidManager::androidAbi2Abi( + ProjectExplorer::Constants::ANDROID_ABI_X86_64)} + << OsTypeWindows + << abis64Bit; +} + +void AndroidPlugin::testAndroidConfigAvailableNdkPlatforms() +{ + QFETCH(FilePath, ndkPath); + QFETCH(Abis, abis); + QFETCH(OsType, hostOs); + QFETCH(QVector, expectedPlatforms); + + const QVector foundPlatforms = availableNdkPlatformsImpl(ndkPath, abis, hostOs); + QCOMPARE(foundPlatforms, expectedPlatforms); +} +#endif // WITH_TESTS + } // namespace Android diff --git a/src/plugins/android/androidconfigurations.h b/src/plugins/android/androidconfigurations.h index c924a3f3173..07a0055ea09 100644 --- a/src/plugins/android/androidconfigurations.h +++ b/src/plugins/android/androidconfigurations.h @@ -135,7 +135,8 @@ public: Utils::FilePath avdManagerToolPath() const; Utils::FilePath toolchainPath(const QtSupport::QtVersion *qtVersion) const; - static Utils::FilePath toolchainPathFromNdk(const Utils::FilePath &ndkLocation); + static Utils::FilePath toolchainPathFromNdk(const Utils::FilePath &ndkLocation, + Utils::OsType hostOs = Utils::HostOsInfo::hostOs()); static Utils::FilePath clangPathFromNdk(const Utils::FilePath &ndkLocation); Utils::FilePath gdbPath(const ProjectExplorer::Abi &abi, const QtSupport::QtVersion *qtVersion) const; diff --git a/src/plugins/android/androidplugin.h b/src/plugins/android/androidplugin.h index d90449c3926..d4ad726cf05 100644 --- a/src/plugins/android/androidplugin.h +++ b/src/plugins/android/androidplugin.h @@ -48,6 +48,8 @@ class AndroidPlugin final : public ExtensionSystem::IPlugin private slots: void testAndroidSdkManagerProgressParser_data(); void testAndroidSdkManagerProgressParser(); + void testAndroidConfigAvailableNdkPlatforms_data(); + void testAndroidConfigAvailableNdkPlatforms(); #endif // WITH_TESTS }; From 36a2bffc54a05b3bb1200794778274bbccdc709b Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 28 Jan 2022 15:10:01 +0100 Subject: [PATCH 16/55] PE: Fix warning from QCssParser Change-Id: I28ccf4f8b6d102dc03b198c057ccf222bf0a5836 Reviewed-by: Alessandro Portale --- src/plugins/projectexplorer/miniprojecttargetselector.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/projectexplorer/miniprojecttargetselector.cpp b/src/plugins/projectexplorer/miniprojecttargetselector.cpp index 44fc5ae511a..6a4b2264880 100644 --- a/src/plugins/projectexplorer/miniprojecttargetselector.cpp +++ b/src/plugins/projectexplorer/miniprojecttargetselector.cpp @@ -1538,7 +1538,7 @@ void MiniProjectTargetSelector::updateSummary() activeTarget->activeRunConfiguration()->expandedDisplayName())); } else if (startupProject->needsConfiguration()) { summary = tr("" + "a:link {color: rgb(128, 128, 255);}" "The project %1 is not yet configured

" "You can configure it in the Projects mode
") .arg(startupProject->displayName()); From 330dfa7e84007d37083c12b3a71e1567f5608cc4 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 27 Jan 2022 11:30:25 +0100 Subject: [PATCH 17/55] ProjectExplorer: Use a QtcProcess member in DeviceProcess All derived class have one one way or the other. Mid-term plan would be to actually base DeviceProcess on QtcProcess and to potentially dissolve it completely later. Change-Id: Ie3bc48dcdc30bc2da5557ad26babf6959a3efa04 Reviewed-by: Jarek Kobus Reviewed-by: --- src/plugins/docker/dockerdevice.cpp | 50 ++++++++---------- .../devicesupport/desktopdeviceprocess.cpp | 43 ++++++++------- .../devicesupport/desktopdeviceprocess.h | 3 -- .../devicesupport/deviceprocess.cpp | 8 ++- .../devicesupport/deviceprocess.h | 11 +++- .../devicesupport/sshdeviceprocess.cpp | 52 +++++++++---------- 6 files changed, 85 insertions(+), 82 deletions(-) diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index a2284f50a81..a73c0b19995 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -107,7 +107,7 @@ public: void start(const Runnable &runnable) override; void interrupt() override; - void terminate() override { m_process.terminate(); } + void terminate() override { process()->terminate(); } void kill() override; QProcess::ProcessState state() const override; @@ -118,22 +118,18 @@ public: QByteArray readAllStandardOutput() override; QByteArray readAllStandardError() override; - qint64 write(const QByteArray &data) override { return m_process.write(data); } - -private: - QtcProcess m_process; + qint64 write(const QByteArray &data) override { return process()->write(data); } }; DockerDeviceProcess::DockerDeviceProcess(const QSharedPointer &device, - QObject *parent) - : DeviceProcess(device, parent) - , m_process(ProcessMode::Writer) + QObject *parent) + : DeviceProcess(device, ProcessMode::Writer, parent) { } void DockerDeviceProcess::start(const Runnable &runnable) { - QTC_ASSERT(m_process.state() == QProcess::NotRunning, return); + QTC_ASSERT(process()->state() == QProcess::NotRunning, return); DockerDevice::ConstPtr dockerDevice = qSharedPointerCast(device()); QTC_ASSERT(dockerDevice, return); @@ -146,65 +142,65 @@ void DockerDeviceProcess::start(const Runnable &runnable) MessageManager::writeDisrupting(QString::fromLocal8Bit(readAllStandardError())); }); - disconnect(&m_process); + disconnect(process()); CommandLine command = runnable.command; command.setExecutable( command.executable().withNewPath(dockerDevice->mapToDevicePath(command.executable()))); - m_process.setCommand(command); - m_process.setEnvironment(runnable.environment); - m_process.setWorkingDirectory(runnable.workingDirectory); - connect(&m_process, &QtcProcess::errorOccurred, this, &DeviceProcess::errorOccurred); - connect(&m_process, &QtcProcess::finished, this, &DeviceProcess::finished); - connect(&m_process, &QtcProcess::readyReadStandardOutput, + process()->setCommand(command); + process()->setEnvironment(runnable.environment); + process()->setWorkingDirectory(runnable.workingDirectory); + connect(process(), &QtcProcess::errorOccurred, this, &DeviceProcess::errorOccurred); + connect(process(), &QtcProcess::finished, this, &DeviceProcess::finished); + connect(process(), &QtcProcess::readyReadStandardOutput, this, &DeviceProcess::readyReadStandardOutput); - connect(&m_process, &QtcProcess::readyReadStandardError, + connect(process(), &QtcProcess::readyReadStandardError, this, &DeviceProcess::readyReadStandardError); - connect(&m_process, &QtcProcess::started, this, &DeviceProcess::started); + connect(process(), &QtcProcess::started, this, &DeviceProcess::started); LOG("Running process:" << command.toUserOutput() << "in" << runnable.workingDirectory.toUserOutput()); - dockerDevice->runProcess(m_process); + dockerDevice->runProcess(*process()); } void DockerDeviceProcess::interrupt() { - device()->signalOperation()->interruptProcess(m_process.processId()); + device()->signalOperation()->interruptProcess(process()->processId()); } void DockerDeviceProcess::kill() { - m_process.kill(); + process()->kill(); } QProcess::ProcessState DockerDeviceProcess::state() const { - return m_process.state(); + return process()->state(); } QProcess::ExitStatus DockerDeviceProcess::exitStatus() const { - return m_process.exitStatus(); + return process()->exitStatus(); } int DockerDeviceProcess::exitCode() const { - return m_process.exitCode(); + return process()->exitCode(); } QString DockerDeviceProcess::errorString() const { - return m_process.errorString(); + return process()->errorString(); } QByteArray DockerDeviceProcess::readAllStandardOutput() { - return m_process.readAllStandardOutput(); + return process()->readAllStandardOutput(); } QByteArray DockerDeviceProcess::readAllStandardError() { - return m_process.readAllStandardError(); + return process()->readAllStandardError(); } diff --git a/src/plugins/projectexplorer/devicesupport/desktopdeviceprocess.cpp b/src/plugins/projectexplorer/devicesupport/desktopdeviceprocess.cpp index 004eef0af51..c932244486f 100644 --- a/src/plugins/projectexplorer/devicesupport/desktopdeviceprocess.cpp +++ b/src/plugins/projectexplorer/devicesupport/desktopdeviceprocess.cpp @@ -39,76 +39,75 @@ namespace Internal { DesktopDeviceProcess::DesktopDeviceProcess(const QSharedPointer &device, QObject *parent) - : DeviceProcess(device, parent) - , m_process(ProcessMode::Writer) + : DeviceProcess(device, ProcessMode::Writer, parent) { - connect(&m_process, &QtcProcess::errorOccurred, this, &DeviceProcess::errorOccurred); - connect(&m_process, &QtcProcess::finished, this, &DeviceProcess::finished); - connect(&m_process, &QtcProcess::readyReadStandardOutput, + connect(process(), &QtcProcess::errorOccurred, this, &DeviceProcess::errorOccurred); + connect(process(), &QtcProcess::finished, this, &DeviceProcess::finished); + connect(process(), &QtcProcess::readyReadStandardOutput, this, &DeviceProcess::readyReadStandardOutput); - connect(&m_process, &QtcProcess::readyReadStandardError, + connect(process(), &QtcProcess::readyReadStandardError, this, &DeviceProcess::readyReadStandardError); - connect(&m_process, &QtcProcess::started, this, &DeviceProcess::started); + connect(process(), &QtcProcess::started, this, &DeviceProcess::started); } void DesktopDeviceProcess::start(const Runnable &runnable) { - QTC_ASSERT(m_process.state() == QProcess::NotRunning, return); + QTC_ASSERT(process()->state() == QProcess::NotRunning, return); if (runnable.environment.size()) - m_process.setEnvironment(runnable.environment); - m_process.setWorkingDirectory(runnable.workingDirectory); - m_process.setCommand(runnable.command); - m_process.start(); + process()->setEnvironment(runnable.environment); + process()->setWorkingDirectory(runnable.workingDirectory); + process()->setCommand(runnable.command); + process()->start(); } void DesktopDeviceProcess::interrupt() { - device()->signalOperation()->interruptProcess(m_process.processId()); + device()->signalOperation()->interruptProcess(process()->processId()); } void DesktopDeviceProcess::terminate() { - m_process.terminate(); + process()->terminate(); } void DesktopDeviceProcess::kill() { - m_process.kill(); + process()->kill(); } QProcess::ProcessState DesktopDeviceProcess::state() const { - return m_process.state(); + return process()->state(); } QProcess::ExitStatus DesktopDeviceProcess::exitStatus() const { - return m_process.exitStatus(); + return process()->exitStatus(); } int DesktopDeviceProcess::exitCode() const { - return m_process.exitCode(); + return process()->exitCode(); } QString DesktopDeviceProcess::errorString() const { - return m_process.errorString(); + return process()->errorString(); } QByteArray DesktopDeviceProcess::readAllStandardOutput() { - return m_process.readAllStandardOutput(); + return process()->readAllStandardOutput(); } QByteArray DesktopDeviceProcess::readAllStandardError() { - return m_process.readAllStandardError(); + return process()->readAllStandardError(); } qint64 DesktopDeviceProcess::write(const QByteArray &data) { - return m_process.write(data); + return process()->write(data); } } // namespace Internal diff --git a/src/plugins/projectexplorer/devicesupport/desktopdeviceprocess.h b/src/plugins/projectexplorer/devicesupport/desktopdeviceprocess.h index 72c3e962caa..6ecd1b5a1f2 100644 --- a/src/plugins/projectexplorer/devicesupport/desktopdeviceprocess.h +++ b/src/plugins/projectexplorer/devicesupport/desktopdeviceprocess.h @@ -53,9 +53,6 @@ public: QByteArray readAllStandardError() override; qint64 write(const QByteArray &data) override; - -private: - Utils::QtcProcess m_process; }; } // namespace Internal diff --git a/src/plugins/projectexplorer/devicesupport/deviceprocess.cpp b/src/plugins/projectexplorer/devicesupport/deviceprocess.cpp index 766e21cb999..b3f60fdf61b 100644 --- a/src/plugins/projectexplorer/devicesupport/deviceprocess.cpp +++ b/src/plugins/projectexplorer/devicesupport/deviceprocess.cpp @@ -30,10 +30,14 @@ #include #include +using namespace Utils; + namespace ProjectExplorer { -DeviceProcess::DeviceProcess(const IDevice::ConstPtr &device, QObject *parent) - : QObject(parent), m_device(device) +DeviceProcess::DeviceProcess(const IDevice::ConstPtr &device, + const QtcProcess::Setup &setup, + QObject *parent) + : QObject(parent), m_process(setup), m_device(device) { } diff --git a/src/plugins/projectexplorer/devicesupport/deviceprocess.h b/src/plugins/projectexplorer/devicesupport/deviceprocess.h index c097bc6d09b..9d411dc0ee4 100644 --- a/src/plugins/projectexplorer/devicesupport/deviceprocess.h +++ b/src/plugins/projectexplorer/devicesupport/deviceprocess.h @@ -27,8 +27,9 @@ #include "../projectexplorer_export.h" +#include + #include -#include #include #include @@ -68,10 +69,16 @@ signals: void readyReadStandardError(); protected: - explicit DeviceProcess(const QSharedPointer &device, QObject *parent = nullptr); + explicit DeviceProcess(const QSharedPointer &device, + const Utils::QtcProcess::Setup &setup, + QObject *parent = nullptr); + QSharedPointer device() const; + Utils::QtcProcess *process() { return &m_process; } + const Utils::QtcProcess *process() const { return &m_process; } private: + Utils::QtcProcess m_process; const QSharedPointer m_device; bool m_runInTerminal = false; }; diff --git a/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp b/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp index 6456cdacfb3..0b4b840cc78 100644 --- a/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp +++ b/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp @@ -48,12 +48,11 @@ enum class Signal { Interrupt, Terminate, Kill }; class SshDeviceProcess::SshDeviceProcessPrivate { public: - SshDeviceProcessPrivate(SshDeviceProcess *q) : q(q), consoleProcess(QtcProcess::TerminalOn) {} + SshDeviceProcessPrivate(SshDeviceProcess *q) : q(q) {} SshDeviceProcess * const q; QSsh::SshConnection *connection = nullptr; - QSsh::SshRemoteProcessPtr process; - QtcProcess consoleProcess; + QSsh::SshRemoteProcessPtr remoteProcess; Runnable runnable; QString errorMessage; QProcess::ExitStatus exitStatus = QProcess::NormalExit; @@ -74,7 +73,8 @@ public: }; SshDeviceProcess::SshDeviceProcess(const IDevice::ConstPtr &device, QObject *parent) - : DeviceProcess(device, parent), d(std::make_unique(this)) + : DeviceProcess(device, QtcProcess::TerminalOn, parent), + d(std::make_unique(this)) { connect(&d->killTimer, &QTimer::timeout, this, &SshDeviceProcess::handleKillOperationTimeout); } @@ -185,32 +185,32 @@ void SshDeviceProcess::handleConnected() QTC_ASSERT(d->state == SshDeviceProcessPrivate::Connecting, return); d->setState(SshDeviceProcessPrivate::Connected); - d->process = runInTerminal() && d->runnable.command.isEmpty() + d->remoteProcess = runInTerminal() && d->runnable.command.isEmpty() ? d->connection->createRemoteShell() : d->connection->createRemoteProcess(fullCommandLine(d->runnable)); const QString display = d->displayName(); if (!display.isEmpty()) - d->process->requestX11Forwarding(display); + d->remoteProcess->requestX11Forwarding(display); if (runInTerminal()) { - connect(&d->consoleProcess, &QtcProcess::errorOccurred, + connect(process(), &QtcProcess::errorOccurred, this, &DeviceProcess::errorOccurred); - connect(&d->consoleProcess, &QtcProcess::started, + connect(process(), &QtcProcess::started, this, &SshDeviceProcess::handleProcessStarted); - connect(&d->consoleProcess, &QtcProcess::finished, - this, [this] { handleProcessFinished(d->consoleProcess.errorString()); }); - d->consoleProcess.setAbortOnMetaChars(false); - d->consoleProcess.setCommand(d->process->fullLocalCommandLine(true)); - d->consoleProcess.start(); + connect(process(), &QtcProcess::finished, + this, [this] { handleProcessFinished(process()->errorString()); }); + process()->setAbortOnMetaChars(false); + process()->setCommand(d->remoteProcess->fullLocalCommandLine(true)); + process()->start(); } else { - connect(d->process.get(), &QSsh::SshRemoteProcess::started, + connect(d->remoteProcess.get(), &QSsh::SshRemoteProcess::started, this, &SshDeviceProcess::handleProcessStarted); - connect(d->process.get(), &QSsh::SshRemoteProcess::done, + connect(d->remoteProcess.get(), &QSsh::SshRemoteProcess::done, this, &SshDeviceProcess::handleProcessFinished); - connect(d->process.get(), &QSsh::SshRemoteProcess::readyReadStandardOutput, + connect(d->remoteProcess.get(), &QSsh::SshRemoteProcess::readyReadStandardOutput, this, &SshDeviceProcess::handleStdout); - connect(d->process.get(), &QSsh::SshRemoteProcess::readyReadStandardError, + connect(d->remoteProcess.get(), &QSsh::SshRemoteProcess::readyReadStandardError, this, &SshDeviceProcess::handleStderr); - d->process->start(); + d->remoteProcess->start(); } } @@ -251,7 +251,7 @@ void SshDeviceProcess::handleProcessStarted() void SshDeviceProcess::handleProcessFinished(const QString &error) { d->errorMessage = error; - d->exitCode = runInTerminal() ? d->consoleProcess.exitCode() : d->process->exitCode(); + d->exitCode = runInTerminal() ? process()->exitCode() : d->remoteProcess->exitCode(); if (d->killOperation && error.isEmpty()) d->errorMessage = tr("The process was ended forcefully."); d->setState(SshDeviceProcessPrivate::Inactive); @@ -260,7 +260,7 @@ void SshDeviceProcess::handleProcessFinished(const QString &error) void SshDeviceProcess::handleStdout() { - QByteArray output = d->process->readAllStandardOutput(); + QByteArray output = d->remoteProcess->readAllStandardOutput(); if (output.isEmpty()) return; d->stdOut += output; @@ -269,7 +269,7 @@ void SshDeviceProcess::handleStdout() void SshDeviceProcess::handleStderr() { - QByteArray output = d->process->readAllStandardError(); + QByteArray output = d->remoteProcess->readAllStandardError(); if (output.isEmpty()) return; d->stdErr += output; @@ -356,12 +356,12 @@ void SshDeviceProcess::SshDeviceProcessPrivate::setState(SshDeviceProcess::SshDe killOperation->disconnect(q); killOperation.clear(); if (q->runInTerminal()) - QMetaObject::invokeMethod(&consoleProcess, &QtcProcess::stopProcess, Qt::QueuedConnection); + QMetaObject::invokeMethod(q->process(), &QtcProcess::stopProcess, Qt::QueuedConnection); } killTimer.stop(); - consoleProcess.disconnect(); - if (process) - process->disconnect(q); + q->process()->disconnect(); + if (remoteProcess) + remoteProcess->disconnect(q); if (connection) { connection->disconnect(q); QSsh::SshConnectionManager::releaseConnection(connection); @@ -372,7 +372,7 @@ void SshDeviceProcess::SshDeviceProcessPrivate::setState(SshDeviceProcess::SshDe qint64 SshDeviceProcess::write(const QByteArray &data) { QTC_ASSERT(!runInTerminal(), return -1); - return d->process->write(data); + return d->remoteProcess->write(data); } } // namespace ProjectExplorer From 9ec997b37654894b027cf4bbd98ca8bba47171b5 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 27 Jan 2022 19:09:06 +0100 Subject: [PATCH 18/55] ProjectExplorer: Base DeviceProcess on QtcProcess ... instead of having a member. Change-Id: I75e8d7600eb17c7528fe9525d2e1aa871b282ad9 Reviewed-by: Jarek Kobus Reviewed-by: --- src/libs/utils/qtcprocess.h | 20 +++--- src/plugins/docker/dockerdevice.cpp | 70 ++----------------- .../devicesupport/desktopdeviceprocess.cpp | 64 ++--------------- .../devicesupport/desktopdeviceprocess.h | 12 ---- .../devicesupport/deviceprocess.cpp | 2 +- .../devicesupport/deviceprocess.h | 28 +------- .../devicesupport/sshdeviceprocess.cpp | 20 +++--- 7 files changed, 33 insertions(+), 183 deletions(-) diff --git a/src/libs/utils/qtcprocess.h b/src/libs/utils/qtcprocess.h index 592830041e1..eb2bff71331 100644 --- a/src/libs/utils/qtcprocess.h +++ b/src/libs/utils/qtcprocess.h @@ -126,8 +126,8 @@ public: void setAbortOnMetaChars(bool abort); void start(); - void terminate(); - void interrupt(); + virtual void terminate(); + virtual void interrupt(); static bool startDetached(const CommandLine &cmd, const FilePath &workingDirectory = {}, qint64 *pid = nullptr); @@ -175,7 +175,7 @@ public: QByteArray rawStdOut() const; - int exitCode() const; + virtual int exitCode() const; QString exitMessage(); @@ -195,10 +195,10 @@ public: void setProcessChannelMode(QProcess::ProcessChannelMode mode); QProcess::ProcessError error() const; - QProcess::ProcessState state() const; + virtual QProcess::ProcessState state() const; bool isRunning() const; // Short for state() == QProcess::Running. - QString errorString() const; + virtual QString errorString() const; void setErrorString(const QString &str); qint64 processId() const; @@ -207,14 +207,14 @@ public: bool waitForReadyRead(int msecs = 30000); bool waitForFinished(int msecs = 30000); - QByteArray readAllStandardOutput(); - QByteArray readAllStandardError(); + virtual QByteArray readAllStandardOutput(); + virtual QByteArray readAllStandardError(); - QProcess::ExitStatus exitStatus() const; + virtual QProcess::ExitStatus exitStatus() const; - void kill(); + virtual void kill(); - qint64 write(const QByteArray &input); + virtual qint64 write(const QByteArray &input); void close(); void setStandardInputFile(const QString &inputFile); diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index a73c0b19995..383f05e9c0d 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -105,20 +105,7 @@ public: ~DockerDeviceProcess() {} void start(const Runnable &runnable) override; - void interrupt() override; - void terminate() override { process()->terminate(); } - void kill() override; - - QProcess::ProcessState state() const override; - QProcess::ExitStatus exitStatus() const override; - int exitCode() const override; - QString errorString() const override; - - QByteArray readAllStandardOutput() override; - QByteArray readAllStandardError() override; - - qint64 write(const QByteArray &data) override { return process()->write(data); } }; DockerDeviceProcess::DockerDeviceProcess(const QSharedPointer &device, @@ -129,7 +116,7 @@ DockerDeviceProcess::DockerDeviceProcess(const QSharedPointer &de void DockerDeviceProcess::start(const Runnable &runnable) { - QTC_ASSERT(process()->state() == QProcess::NotRunning, return); + QTC_ASSERT(state() == QProcess::NotRunning, return); DockerDevice::ConstPtr dockerDevice = qSharedPointerCast(device()); QTC_ASSERT(dockerDevice, return); @@ -142,68 +129,23 @@ void DockerDeviceProcess::start(const Runnable &runnable) MessageManager::writeDisrupting(QString::fromLocal8Bit(readAllStandardError())); }); - disconnect(process()); - CommandLine command = runnable.command; command.setExecutable( command.executable().withNewPath(dockerDevice->mapToDevicePath(command.executable()))); - process()->setCommand(command); - process()->setEnvironment(runnable.environment); - process()->setWorkingDirectory(runnable.workingDirectory); - connect(process(), &QtcProcess::errorOccurred, this, &DeviceProcess::errorOccurred); - connect(process(), &QtcProcess::finished, this, &DeviceProcess::finished); - connect(process(), &QtcProcess::readyReadStandardOutput, - this, &DeviceProcess::readyReadStandardOutput); - connect(process(), &QtcProcess::readyReadStandardError, - this, &DeviceProcess::readyReadStandardError); - connect(process(), &QtcProcess::started, this, &DeviceProcess::started); + setCommand(command); + setEnvironment(runnable.environment); + setWorkingDirectory(runnable.workingDirectory); LOG("Running process:" << command.toUserOutput() << "in" << runnable.workingDirectory.toUserOutput()); - dockerDevice->runProcess(*process()); + dockerDevice->runProcess(*this); } void DockerDeviceProcess::interrupt() { - device()->signalOperation()->interruptProcess(process()->processId()); + device()->signalOperation()->interruptProcess(processId()); } -void DockerDeviceProcess::kill() -{ - process()->kill(); -} - -QProcess::ProcessState DockerDeviceProcess::state() const -{ - return process()->state(); -} - -QProcess::ExitStatus DockerDeviceProcess::exitStatus() const -{ - return process()->exitStatus(); -} - -int DockerDeviceProcess::exitCode() const -{ - return process()->exitCode(); -} - -QString DockerDeviceProcess::errorString() const -{ - return process()->errorString(); -} - -QByteArray DockerDeviceProcess::readAllStandardOutput() -{ - return process()->readAllStandardOutput(); -} - -QByteArray DockerDeviceProcess::readAllStandardError() -{ - return process()->readAllStandardError(); -} - - class DockerPortsGatheringMethod : public PortsGatheringMethod { Runnable runnable(QAbstractSocket::NetworkLayerProtocol protocol) const override diff --git a/src/plugins/projectexplorer/devicesupport/desktopdeviceprocess.cpp b/src/plugins/projectexplorer/devicesupport/desktopdeviceprocess.cpp index c932244486f..c2106967f77 100644 --- a/src/plugins/projectexplorer/devicesupport/desktopdeviceprocess.cpp +++ b/src/plugins/projectexplorer/devicesupport/desktopdeviceprocess.cpp @@ -41,73 +41,21 @@ DesktopDeviceProcess::DesktopDeviceProcess(const QSharedPointer & QObject *parent) : DeviceProcess(device, ProcessMode::Writer, parent) { - connect(process(), &QtcProcess::errorOccurred, this, &DeviceProcess::errorOccurred); - connect(process(), &QtcProcess::finished, this, &DeviceProcess::finished); - connect(process(), &QtcProcess::readyReadStandardOutput, - this, &DeviceProcess::readyReadStandardOutput); - connect(process(), &QtcProcess::readyReadStandardError, - this, &DeviceProcess::readyReadStandardError); - connect(process(), &QtcProcess::started, this, &DeviceProcess::started); } void DesktopDeviceProcess::start(const Runnable &runnable) { - QTC_ASSERT(process()->state() == QProcess::NotRunning, return); + QTC_ASSERT(state() == QProcess::NotRunning, return); if (runnable.environment.size()) - process()->setEnvironment(runnable.environment); - process()->setWorkingDirectory(runnable.workingDirectory); - process()->setCommand(runnable.command); - process()->start(); + setEnvironment(runnable.environment); + setWorkingDirectory(runnable.workingDirectory); + setCommand(runnable.command); + QtcProcess::start(); } void DesktopDeviceProcess::interrupt() { - device()->signalOperation()->interruptProcess(process()->processId()); -} - -void DesktopDeviceProcess::terminate() -{ - process()->terminate(); -} - -void DesktopDeviceProcess::kill() -{ - process()->kill(); -} - -QProcess::ProcessState DesktopDeviceProcess::state() const -{ - return process()->state(); -} - -QProcess::ExitStatus DesktopDeviceProcess::exitStatus() const -{ - return process()->exitStatus(); -} - -int DesktopDeviceProcess::exitCode() const -{ - return process()->exitCode(); -} - -QString DesktopDeviceProcess::errorString() const -{ - return process()->errorString(); -} - -QByteArray DesktopDeviceProcess::readAllStandardOutput() -{ - return process()->readAllStandardOutput(); -} - -QByteArray DesktopDeviceProcess::readAllStandardError() -{ - return process()->readAllStandardError(); -} - -qint64 DesktopDeviceProcess::write(const QByteArray &data) -{ - return process()->write(data); + device()->signalOperation()->interruptProcess(processId()); } } // namespace Internal diff --git a/src/plugins/projectexplorer/devicesupport/desktopdeviceprocess.h b/src/plugins/projectexplorer/devicesupport/desktopdeviceprocess.h index 6ecd1b5a1f2..ed926112a2d 100644 --- a/src/plugins/projectexplorer/devicesupport/desktopdeviceprocess.h +++ b/src/plugins/projectexplorer/devicesupport/desktopdeviceprocess.h @@ -41,18 +41,6 @@ public: void start(const Runnable &runnable) override; void interrupt() override; - void terminate() override; - void kill() override; - - QProcess::ProcessState state() const override; - QProcess::ExitStatus exitStatus() const override; - int exitCode() const override; - QString errorString() const override; - - QByteArray readAllStandardOutput() override; - QByteArray readAllStandardError() override; - - qint64 write(const QByteArray &data) override; }; } // namespace Internal diff --git a/src/plugins/projectexplorer/devicesupport/deviceprocess.cpp b/src/plugins/projectexplorer/devicesupport/deviceprocess.cpp index b3f60fdf61b..84c692e5a47 100644 --- a/src/plugins/projectexplorer/devicesupport/deviceprocess.cpp +++ b/src/plugins/projectexplorer/devicesupport/deviceprocess.cpp @@ -37,7 +37,7 @@ namespace ProjectExplorer { DeviceProcess::DeviceProcess(const IDevice::ConstPtr &device, const QtcProcess::Setup &setup, QObject *parent) - : QObject(parent), m_process(setup), m_device(device) + : QtcProcess(setup, parent), m_device(device) { } diff --git a/src/plugins/projectexplorer/devicesupport/deviceprocess.h b/src/plugins/projectexplorer/devicesupport/deviceprocess.h index 9d411dc0ee4..215b26879b4 100644 --- a/src/plugins/projectexplorer/devicesupport/deviceprocess.h +++ b/src/plugins/projectexplorer/devicesupport/deviceprocess.h @@ -29,7 +29,6 @@ #include -#include #include #include @@ -38,47 +37,24 @@ namespace ProjectExplorer { class IDevice; class Runnable; -class PROJECTEXPLORER_EXPORT DeviceProcess : public QObject +class PROJECTEXPLORER_EXPORT DeviceProcess : public Utils::QtcProcess { Q_OBJECT public: + using Utils::QtcProcess::start; virtual void start(const Runnable &runnable) = 0; - virtual void interrupt() = 0; - virtual void terminate() = 0; - virtual void kill() = 0; - - virtual QProcess::ProcessState state() const = 0; - virtual QProcess::ExitStatus exitStatus() const = 0; - virtual int exitCode() const = 0; - virtual QString errorString() const = 0; - - virtual QByteArray readAllStandardOutput() = 0; - virtual QByteArray readAllStandardError() = 0; - - virtual qint64 write(const QByteArray &data) = 0; void setRunInTerminal(bool term) { m_runInTerminal = term; } bool runInTerminal() const { return m_runInTerminal; } -signals: - void started(); - void finished(); - void errorOccurred(QProcess::ProcessError error); - - void readyReadStandardOutput(); - void readyReadStandardError(); - protected: explicit DeviceProcess(const QSharedPointer &device, const Utils::QtcProcess::Setup &setup, QObject *parent = nullptr); QSharedPointer device() const; - Utils::QtcProcess *process() { return &m_process; } - const Utils::QtcProcess *process() const { return &m_process; } private: - Utils::QtcProcess m_process; const QSharedPointer m_device; bool m_runInTerminal = false; }; diff --git a/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp b/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp index 0b4b840cc78..eb0b7b9584a 100644 --- a/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp +++ b/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp @@ -192,15 +192,11 @@ void SshDeviceProcess::handleConnected() if (!display.isEmpty()) d->remoteProcess->requestX11Forwarding(display); if (runInTerminal()) { - connect(process(), &QtcProcess::errorOccurred, - this, &DeviceProcess::errorOccurred); - connect(process(), &QtcProcess::started, - this, &SshDeviceProcess::handleProcessStarted); - connect(process(), &QtcProcess::finished, - this, [this] { handleProcessFinished(process()->errorString()); }); - process()->setAbortOnMetaChars(false); - process()->setCommand(d->remoteProcess->fullLocalCommandLine(true)); - process()->start(); + connect(this, &QtcProcess::finished, + this, [this] { handleProcessFinished(errorString()); }); + setAbortOnMetaChars(false); + setCommand(d->remoteProcess->fullLocalCommandLine(true)); + QtcProcess::start(); } else { connect(d->remoteProcess.get(), &QSsh::SshRemoteProcess::started, this, &SshDeviceProcess::handleProcessStarted); @@ -251,7 +247,7 @@ void SshDeviceProcess::handleProcessStarted() void SshDeviceProcess::handleProcessFinished(const QString &error) { d->errorMessage = error; - d->exitCode = runInTerminal() ? process()->exitCode() : d->remoteProcess->exitCode(); + d->exitCode = runInTerminal() ? QtcProcess::exitCode() : d->remoteProcess->exitCode(); if (d->killOperation && error.isEmpty()) d->errorMessage = tr("The process was ended forcefully."); d->setState(SshDeviceProcessPrivate::Inactive); @@ -356,10 +352,10 @@ void SshDeviceProcess::SshDeviceProcessPrivate::setState(SshDeviceProcess::SshDe killOperation->disconnect(q); killOperation.clear(); if (q->runInTerminal()) - QMetaObject::invokeMethod(q->process(), &QtcProcess::stopProcess, Qt::QueuedConnection); + QMetaObject::invokeMethod(q, &QtcProcess::stopProcess, Qt::QueuedConnection); } killTimer.stop(); - q->process()->disconnect(); + q->disconnect(); if (remoteProcess) remoteProcess->disconnect(q); if (connection) { From f529ec492cf9535838eb61a13a863a144ce0b7f6 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 26 Jan 2022 14:04:35 +0100 Subject: [PATCH 19/55] Debugger: Add dumper for qdump__boost__container__devector From https://lists.qt-project.org/pipermail/qt-creator/2021-August/008922.html Change-Id: I85fff706e7f90a8182a434316fed4b6a43958af6 Reviewed-by: Christian Stenger --- share/qtcreator/debugger/boosttypes.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/share/qtcreator/debugger/boosttypes.py b/share/qtcreator/debugger/boosttypes.py index c48f64167fa..4cd8409ff8c 100644 --- a/share/qtcreator/debugger/boosttypes.py +++ b/share/qtcreator/debugger/boosttypes.py @@ -185,3 +185,16 @@ def qdump__boost__variant(d, value): dummy, val = value.split('%is{%s}' % (max(4, alignment), realType.name)) d.putItem(val) d.putBetterType(value.type) + + +def qdump__boost__container__devector(d, value): + inner_type = value.type[0] + buffer = value["m_"]["buffer"].pointer() + front_idx = value["m_"]["front_idx"].integer() + back_idx = value["m_"]["back_idx"].integer() + start = buffer + (front_idx * inner_type.size()) + size = int(back_idx - front_idx) + if size > 0: + d.checkPointer(start) + d.putItemCount(size) + d.putPlotData(start, size, inner_type) From 773f8a5bbe8b5cdbdd103bd429510c4a8ca0f09a Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 28 Jan 2022 13:55:58 +0100 Subject: [PATCH 20/55] SshDeviceProcess: Don't buffer stdOut and stdErr It's already being buffered inside remoteProcess. Change-Id: I5fd90df600454563342aaf142d21df28a404d9ba Reviewed-by: hjk --- .../devicesupport/sshdeviceprocess.cpp | 32 +++---------------- .../devicesupport/sshdeviceprocess.h | 2 -- 2 files changed, 4 insertions(+), 30 deletions(-) diff --git a/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp b/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp index eb0b7b9584a..e496ffaa322 100644 --- a/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp +++ b/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp @@ -58,8 +58,6 @@ public: QProcess::ExitStatus exitStatus = QProcess::NormalExit; DeviceProcessSignalOperation::Ptr killOperation; QTimer killTimer; - QByteArray stdOut; - QByteArray stdErr; int exitCode = -1; enum State { Inactive, Connecting, Connected, ProcessRunning } state = Inactive; @@ -163,16 +161,12 @@ QString SshDeviceProcess::errorString() const QByteArray SshDeviceProcess::readAllStandardOutput() { - const QByteArray data = d->stdOut; - d->stdOut.clear(); - return data; + return d->remoteProcess.get() ? d->remoteProcess->readAllStandardOutput() : QByteArray(); } QByteArray SshDeviceProcess::readAllStandardError() { - const QByteArray data = d->stdErr; - d->stdErr.clear(); - return data; + return d->remoteProcess.get() ? d->remoteProcess->readAllStandardError() : QByteArray(); } qint64 SshDeviceProcess::processId() const @@ -203,9 +197,9 @@ void SshDeviceProcess::handleConnected() connect(d->remoteProcess.get(), &QSsh::SshRemoteProcess::done, this, &SshDeviceProcess::handleProcessFinished); connect(d->remoteProcess.get(), &QSsh::SshRemoteProcess::readyReadStandardOutput, - this, &SshDeviceProcess::handleStdout); + this, &QtcProcess::readyReadStandardOutput); connect(d->remoteProcess.get(), &QSsh::SshRemoteProcess::readyReadStandardError, - this, &SshDeviceProcess::handleStderr); + this, &QtcProcess::readyReadStandardError); d->remoteProcess->start(); } } @@ -254,24 +248,6 @@ void SshDeviceProcess::handleProcessFinished(const QString &error) emit finished(); } -void SshDeviceProcess::handleStdout() -{ - QByteArray output = d->remoteProcess->readAllStandardOutput(); - if (output.isEmpty()) - return; - d->stdOut += output; - emit readyReadStandardOutput(); -} - -void SshDeviceProcess::handleStderr() -{ - QByteArray output = d->remoteProcess->readAllStandardError(); - if (output.isEmpty()) - return; - d->stdErr += output; - emit readyReadStandardError(); -} - void SshDeviceProcess::handleKillOperationFinished(const QString &errorMessage) { QTC_ASSERT(d->state == SshDeviceProcessPrivate::ProcessRunning, return); diff --git a/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.h b/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.h index 8c1da7cf558..0980d530bcf 100644 --- a/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.h +++ b/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.h @@ -61,8 +61,6 @@ private: void handleDisconnected(); void handleProcessStarted(); void handleProcessFinished(const QString &error); - void handleStdout(); - void handleStderr(); void handleKillOperationFinished(const QString &errorMessage); void handleKillOperationTimeout(); From fd49c1d567693d721021f3ddab7776b9d554b05f Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 31 Jan 2022 08:03:37 +0100 Subject: [PATCH 21/55] Android: Compile fix for Qt 5 Amends 49443d689. Change-Id: Idadb794b85bebff9678b54f55f8b9822719a8d8a Reviewed-by: Christian Stenger Reviewed-by: Alessandro Portale --- src/plugins/android/androidconfigurations.cpp | 26 +++++++++---------- src/plugins/android/androidconfigurations.h | 5 +++- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index ef3aa2d6053..34383bad3a4 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -373,9 +373,9 @@ void AndroidConfig::parseDependenciesJson() } } -static QVector availableNdkPlatformsLegacy(const FilePath &ndkLocation) +static QList availableNdkPlatformsLegacy(const FilePath &ndkLocation) { - QVector availableNdkPlatforms; + QList availableNdkPlatforms; ndkLocation .pathAppended("platforms") @@ -392,7 +392,7 @@ static QVector availableNdkPlatformsLegacy(const FilePath &ndkLocation) return availableNdkPlatforms; } -static QVector availableNdkPlatformsV21Plus(const FilePath &ndkLocation, const Abis &abis, +static QList availableNdkPlatformsV21Plus(const FilePath &ndkLocation, const Abis &abis, OsType hostOs) { if (abis.isEmpty()) @@ -402,16 +402,16 @@ static QVector availableNdkPlatformsV21Plus(const FilePath &ndkLocation, co const FilePath libPath = AndroidConfig::toolchainPathFromNdk(ndkLocation, hostOs) / "sysroot/usr/lib" / abi; const QList dirEntries = libPath.dirEntries(QDir::Dirs | QDir::NoDotAndDotDot); - const QVector availableNdkPlatforms = + const QList availableNdkPlatforms = Utils::transform(dirEntries, [](const FilePath &path) { return path.fileName().toInt(); }); return availableNdkPlatforms; } -static QVector availableNdkPlatformsImpl(const FilePath &ndkLocation, const Abis &abis, +static QList availableNdkPlatformsImpl(const FilePath &ndkLocation, const Abis &abis, OsType hostOs) { - QVector result = availableNdkPlatformsLegacy(ndkLocation); + QList result = availableNdkPlatformsLegacy(ndkLocation); if (result.isEmpty()) result = availableNdkPlatformsV21Plus(ndkLocation, abis, hostOs); @@ -420,7 +420,7 @@ static QVector availableNdkPlatformsImpl(const FilePath &ndkLocation, const return result; } -QVector AndroidConfig::availableNdkPlatforms(const QtVersion *qtVersion) const +QList AndroidConfig::availableNdkPlatforms(const QtVersion *qtVersion) const { return availableNdkPlatformsImpl(ndkLocation(qtVersion), qtVersion->qtAbis(), HostOsInfo::hostOs()); @@ -1685,17 +1685,17 @@ void AndroidPlugin::testAndroidConfigAvailableNdkPlatforms_data() QTest::addColumn("ndkPath"); QTest::addColumn("abis"); QTest::addColumn("hostOs"); - QTest::addColumn >("expectedPlatforms"); + QTest::addColumn >("expectedPlatforms"); QTest::newRow("ndkLegacy") << FilePath::fromUserInput(":/android/tst/ndk/19.2.5345600") << Abis() << OsTypeOther - << QVector{28, 27, 26, 24, 23, 22, 21, 19, 18, 17, 16}; + << QList{28, 27, 26, 24, 23, 22, 21, 19, 18, 17, 16}; const FilePath ndkV21Plus = FilePath::fromUserInput(":/android/tst/ndk/23.1.7779620"); - const QVector abis32Bit = {31, 30, 29, 28, 27, 26, 24, 23, 22, 21, 19, 18, 17, 16}; - const QVector abis64Bit = {31, 30, 29, 28, 27, 26, 24, 23, 22, 21}; + const QList abis32Bit = {31, 30, 29, 28, 27, 26, 24, 23, 22, 21, 19, 18, 17, 16}; + const QList abis64Bit = {31, 30, 29, 28, 27, 26, 24, 23, 22, 21}; QTest::newRow("ndkV21Plus armeabi-v7a OsTypeWindows") << ndkV21Plus << Abis{AndroidManager::androidAbi2Abi( @@ -1730,9 +1730,9 @@ void AndroidPlugin::testAndroidConfigAvailableNdkPlatforms() QFETCH(FilePath, ndkPath); QFETCH(Abis, abis); QFETCH(OsType, hostOs); - QFETCH(QVector, expectedPlatforms); + QFETCH(QList, expectedPlatforms); - const QVector foundPlatforms = availableNdkPlatformsImpl(ndkPath, abis, hostOs); + const QList foundPlatforms = availableNdkPlatformsImpl(ndkPath, abis, hostOs); QCOMPARE(foundPlatforms, expectedPlatforms); } #endif // WITH_TESTS diff --git a/src/plugins/android/androidconfigurations.h b/src/plugins/android/androidconfigurations.h index 07a0055ea09..701e10190e9 100644 --- a/src/plugins/android/androidconfigurations.h +++ b/src/plugins/android/androidconfigurations.h @@ -190,7 +190,7 @@ private: void parseDependenciesJson(); - QVector availableNdkPlatforms(const QtSupport::QtVersion *qtVersion) const; + QList availableNdkPlatforms(const QtSupport::QtVersion *qtVersion) const; Utils::FilePath m_sdkLocation; QStringList m_sdkManagerToolArgs; @@ -249,3 +249,6 @@ private: }; } // namespace Android + +Q_DECLARE_METATYPE(ProjectExplorer::Abis) +Q_DECLARE_METATYPE(Utils::OsType) From d48a4bd60f8983e2e3d9fa5359128720aff521d2 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Fri, 21 Jan 2022 17:15:01 +0200 Subject: [PATCH 22/55] QmlDesigner: Add 3D editor visibility toggle actions Added toggle for showing selection boxes, camera frustums, and icon gizmos. Fixes: QDS-5954 Change-Id: I97e12a3a04b9a1a1af5851e382f36c58ee869f45 Reviewed-by: Reviewed-by: Qt CI Bot Reviewed-by: Thomas Hartmann --- .../qmlpuppet/commands/view3dactioncommand.h | 3 + .../qmlpuppet/mockfiles/qt5/CameraGizmo.qml | 9 +- .../qmlpuppet/mockfiles/qt5/EditView3D.qml | 34 ++++++- .../qml/qmlpuppet/mockfiles/qt5/IconGizmo.qml | 4 +- .../qmlpuppet/mockfiles/qt6/CameraGizmo.qml | 9 +- .../qmlpuppet/mockfiles/qt6/EditView3D.qml | 38 ++++++- .../qml/qmlpuppet/mockfiles/qt6/IconGizmo.qml | 4 +- .../qt5informationnodeinstanceserver.cpp | 9 ++ src/plugins/qmldesigner/CMakeLists.txt | 1 + .../qmldesigner/components/edit3d/edit3d.qrc | 4 - .../components/edit3d/edit3dactions.cpp | 7 +- .../components/edit3d/edit3dactions.h | 3 +- .../components/edit3d/edit3dview.cpp | 95 +++++++++++++++--- .../components/edit3d/edit3dview.h | 6 ++ .../edit3d/edit3dvisibilitytogglesmenu.cpp | 50 +++++++++ .../edit3d/edit3dvisibilitytogglesmenu.h | 44 ++++++++ .../components/edit3d/edit3dwidget.cpp | 70 +++++++++---- .../components/edit3d/edit3dwidget.h | 4 + .../components/edit3d/images/grid_off.png | Bin 221 -> 0 bytes .../components/edit3d/images/grid_off@2x.png | Bin 116 -> 0 bytes .../components/edit3d/images/grid_on.png | Bin 221 -> 0 bytes .../components/edit3d/images/grid_on@2x.png | Bin 116 -> 0 bytes .../qmldesigner/qmldesignerconstants.h | 4 + src/plugins/qmldesigner/qmldesignericons.h | 4 - src/plugins/qmldesigner/qmldesignerplugin.qbs | 2 + 25 files changed, 353 insertions(+), 51 deletions(-) create mode 100644 src/plugins/qmldesigner/components/edit3d/edit3dvisibilitytogglesmenu.cpp create mode 100644 src/plugins/qmldesigner/components/edit3d/edit3dvisibilitytogglesmenu.h delete mode 100644 src/plugins/qmldesigner/components/edit3d/images/grid_off.png delete mode 100644 src/plugins/qmldesigner/components/edit3d/images/grid_off@2x.png delete mode 100644 src/plugins/qmldesigner/components/edit3d/images/grid_on.png delete mode 100644 src/plugins/qmldesigner/components/edit3d/images/grid_on@2x.png diff --git a/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h b/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h index 43bd32e1a20..cb23b2c9ad5 100644 --- a/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h +++ b/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h @@ -47,6 +47,9 @@ public: OrientationToggle, EditLightToggle, ShowGrid, + ShowSelectionBox, + ShowIconGizmo, + ShowCameraFrustum, Edit3DParticleModeToggle, ParticlesPlay, ParticlesRestart, diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/CameraGizmo.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/CameraGizmo.qml index a108190ff7a..11976378d27 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/CameraGizmo.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/CameraGizmo.qml @@ -30,6 +30,7 @@ IconGizmo { id: cameraGizmo property Model frustumModel: null + property bool globalShowFrustum: false iconSource: "qrc:///qtquickplugin/mockfiles/images/editor_camera.png" @@ -46,8 +47,12 @@ IconGizmo { frustum.targetNode = targetNode; frustum.targetNode = Qt.binding(function() {return targetNode;}); - frustum.visible = visible || (targetNode && selected && activeScene === scene); - frustum.visible = Qt.binding(function() {return visible || (targetNode && selected && activeScene === scene);}); + frustum.visible = (canBeVisible && globalShowFrustum) + || (targetNode && selected && activeScene === scene); + frustum.visible = Qt.binding(function() { + return (canBeVisible && globalShowFrustum) + || (targetNode && selected && activeScene === scene); + }); } onActiveSceneChanged: { diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/EditView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/EditView3D.qml index 592e4ab72eb..0b15f190673 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/EditView3D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/EditView3D.qml @@ -39,6 +39,9 @@ Item { property bool showEditLight: false property bool showGrid: true + property bool showSelectionBox: true + property bool showIconGizmo: true + property bool showCameraFrustum: false property bool usePerspective: true property bool globalOrientation: false property alias contentItem: contentItem @@ -70,6 +73,9 @@ Item { onShowEditLightChanged: _generalHelper.storeToolState(sceneId, "showEditLight", showEditLight) onGlobalOrientationChanged: _generalHelper.storeToolState(sceneId, "globalOrientation", globalOrientation) onShowGridChanged: _generalHelper.storeToolState(sceneId, "showGrid", showGrid); + onShowSelectionBoxChanged: _generalHelper.storeToolState(sceneId, "showSelectionBox", showSelectionBox); + onShowIconGizmoChanged: _generalHelper.storeToolState(sceneId, "showIconGizmo", showIconGizmo); + onShowCameraFrustumChanged: _generalHelper.storeToolState(sceneId, "showCameraFrustum", showCameraFrustum); onSelectionModeChanged: _generalHelper.storeToolState(sceneId, "selectionMode", selectionMode); onTransformModeChanged: _generalHelper.storeToolState(sceneId, "transformMode", transformMode); @@ -220,6 +226,21 @@ Item { else if (resetToDefault) showGrid = true; + if ("showSelectionBox" in toolStates) + showSelectionBox = toolStates.showSelectionBox; + else if (resetToDefault) + showSelectionBox = true; + + if ("showIconGizmo" in toolStates) + showIconGizmo = toolStates.showIconGizmo; + else if (resetToDefault) + showIconGizmo = true; + + if ("showCameraFrustum" in toolStates) + showCameraFrustum = toolStates.showCameraFrustum; + else if (resetToDefault) + showCameraFrustum = false; + if ("usePerspective" in toolStates) usePerspective = toolStates.usePerspective; else if (resetToDefault) @@ -250,6 +271,9 @@ Item { { _generalHelper.storeToolState(sceneId, "showEditLight", showEditLight) _generalHelper.storeToolState(sceneId, "showGrid", showGrid) + _generalHelper.storeToolState(sceneId, "showSelectionBox", showSelectionBox) + _generalHelper.storeToolState(sceneId, "showIconGizmo", showIconGizmo) + _generalHelper.storeToolState(sceneId, "showCameraFrustum", showCameraFrustum) _generalHelper.storeToolState(sceneId, "usePerspective", usePerspective) _generalHelper.storeToolState(sceneId, "globalOrientation", globalOrientation) _generalHelper.storeToolState(sceneId, "selectionMode", selectionMode); @@ -273,6 +297,7 @@ Item { "geometryName": geometryName}); selectionBoxes[selectionBoxes.length] = box; box.view3D = Qt.binding(function() {return editView;}); + box.visible = Qt.binding(function() {return showSelectionBox;}); } } } @@ -373,11 +398,13 @@ Item { "selectedNodes": selectedNodes, "scene": scene, "activeScene": activeScene, "locked": _generalHelper.isLocked(obj), - "hidden": _generalHelper.isHidden(obj)}); + "hidden": _generalHelper.isHidden(obj), + "globalShow": showIconGizmo}); lightIconGizmos[lightIconGizmos.length] = gizmo; gizmo.clicked.connect(handleObjectClicked); gizmo.selectedNodes = Qt.binding(function() {return selectedNodes;}); gizmo.activeScene = Qt.binding(function() {return activeScene;}); + gizmo.globalShow = Qt.binding(function() {return showIconGizmo;}); } } @@ -416,12 +443,15 @@ Item { overlayView, {"view3D": overlayView, "targetNode": obj, "selectedNodes": selectedNodes, "scene": scene, "activeScene": activeScene, - "locked": _generalHelper.isLocked(obj), "hidden": _generalHelper.isHidden(obj)}); + "locked": _generalHelper.isLocked(obj), "hidden": _generalHelper.isHidden(obj), + "globalShow": showIconGizmo, "globalShowFrustum": showCameraFrustum}); cameraGizmos[cameraGizmos.length] = gizmo; gizmo.clicked.connect(handleObjectClicked); gizmo.selectedNodes = Qt.binding(function() {return selectedNodes;}); gizmo.activeScene = Qt.binding(function() {return activeScene;}); + gizmo.globalShow = Qt.binding(function() {return showIconGizmo;}); + gizmo.globalShowFrustum = Qt.binding(function() {return showCameraFrustum;}); frustum.viewPortRect = Qt.binding(function() {return viewPortRect;}); gizmo.connectFrustum(frustum); } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/IconGizmo.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/IconGizmo.qml index 24459e08d4f..3ee4776aa52 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/IconGizmo.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/IconGizmo.qml @@ -45,6 +45,8 @@ Item { property bool hasMouse: false property bool hidden: false property bool locked: false + property bool globalShow: true + property bool canBeVisible: activeScene === scene && !hidden && (targetNode ? targetNode.visible : false) property alias iconSource: iconImage.source @@ -55,7 +57,7 @@ Item { hasMouse = false; } - visible: activeScene === scene && !hidden && (targetNode ? targetNode.visible : false) + visible: canBeVisible && globalShow Overlay2D { id: iconOverlay diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/CameraGizmo.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/CameraGizmo.qml index 42a7bc7bfaa..872c30a3452 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/CameraGizmo.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/CameraGizmo.qml @@ -30,6 +30,7 @@ IconGizmo { id: cameraGizmo property Model frustumModel: null + property bool globalShowFrustum: false iconSource: "qrc:///qtquickplugin/mockfiles/images/editor_camera.png" @@ -46,8 +47,12 @@ IconGizmo { frustum.targetNode = targetNode; frustum.targetNode = Qt.binding(function() {return targetNode;}); - frustum.visible = visible || (targetNode && selected && activeScene === scene); - frustum.visible = Qt.binding(function() {return visible || (targetNode && selected && activeScene === scene);}); + frustum.visible = (canBeVisible && globalShowFrustum) + || (targetNode && selected && activeScene === scene); + frustum.visible = Qt.binding(function() { + return (canBeVisible && globalShowFrustum) + || (targetNode && selected && activeScene === scene); + }); } onActiveSceneChanged: { diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditView3D.qml index 944c42b653b..a1061ba672c 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditView3D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditView3D.qml @@ -39,6 +39,9 @@ Item { property bool showEditLight: false property bool showGrid: true + property bool showSelectionBox: true + property bool showIconGizmo: true + property bool showCameraFrustum: false property bool usePerspective: true property bool globalOrientation: false property alias contentItem: contentItem @@ -71,6 +74,9 @@ Item { onShowEditLightChanged: _generalHelper.storeToolState(sceneId, "showEditLight", showEditLight) onGlobalOrientationChanged: _generalHelper.storeToolState(sceneId, "globalOrientation", globalOrientation) onShowGridChanged: _generalHelper.storeToolState(sceneId, "showGrid", showGrid); + onShowSelectionBoxChanged: _generalHelper.storeToolState(sceneId, "showSelectionBox", showSelectionBox); + onShowIconGizmoChanged: _generalHelper.storeToolState(sceneId, "showIconGizmo", showIconGizmo); + onShowCameraFrustumChanged: _generalHelper.storeToolState(sceneId, "showCameraFrustum", showCameraFrustum); onSelectionModeChanged: _generalHelper.storeToolState(sceneId, "selectionMode", selectionMode); onTransformModeChanged: _generalHelper.storeToolState(sceneId, "transformMode", transformMode); @@ -211,6 +217,21 @@ Item { else if (resetToDefault) showGrid = true; + if ("showSelectionBox" in toolStates) + showSelectionBox = toolStates.showSelectionBox; + else if (resetToDefault) + showSelectionBox = true; + + if ("showIconGizmo" in toolStates) + showIconGizmo = toolStates.showIconGizmo; + else if (resetToDefault) + showIconGizmo = true; + + if ("showCameraFrustum" in toolStates) + showCameraFrustum = toolStates.showCameraFrustum; + else if (resetToDefault) + showCameraFrustum = false; + if ("usePerspective" in toolStates) usePerspective = toolStates.usePerspective; else if (resetToDefault) @@ -241,6 +262,9 @@ Item { { _generalHelper.storeToolState(sceneId, "showEditLight", showEditLight) _generalHelper.storeToolState(sceneId, "showGrid", showGrid) + _generalHelper.storeToolState(sceneId, "showSelectionBox", showSelectionBox) + _generalHelper.storeToolState(sceneId, "showIconGizmo", showIconGizmo) + _generalHelper.storeToolState(sceneId, "showCameraFrustum", showCameraFrustum) _generalHelper.storeToolState(sceneId, "usePerspective", usePerspective) _generalHelper.storeToolState(sceneId, "globalOrientation", globalOrientation) _generalHelper.storeToolState(sceneId, "selectionMode", selectionMode); @@ -264,6 +288,7 @@ Item { "geometryName": geometryName}); selectionBoxes[selectionBoxes.length] = box; box.view3D = Qt.binding(function() {return editView;}); + box.visible = Qt.binding(function() {return showSelectionBox;}); } } } @@ -364,11 +389,13 @@ Item { "selectedNodes": selectedNodes, "scene": scene, "activeScene": activeScene, "locked": _generalHelper.isLocked(obj), - "hidden": _generalHelper.isHidden(obj)}); + "hidden": _generalHelper.isHidden(obj), + "globalShow": showIconGizmo}); lightIconGizmos[lightIconGizmos.length] = gizmo; gizmo.clicked.connect(handleObjectClicked); gizmo.selectedNodes = Qt.binding(function() {return selectedNodes;}); gizmo.activeScene = Qt.binding(function() {return activeScene;}); + gizmo.globalShow = Qt.binding(function() {return showIconGizmo;}); } } @@ -407,12 +434,15 @@ Item { overlayView, {"view3D": overlayView, "targetNode": obj, "selectedNodes": selectedNodes, "scene": scene, "activeScene": activeScene, - "locked": _generalHelper.isLocked(obj), "hidden": _generalHelper.isHidden(obj)}); + "locked": _generalHelper.isLocked(obj), "hidden": _generalHelper.isHidden(obj), + "globalShow": showIconGizmo, "globalShowFrustum": showCameraFrustum}); cameraGizmos[cameraGizmos.length] = gizmo; gizmo.clicked.connect(handleObjectClicked); gizmo.selectedNodes = Qt.binding(function() {return selectedNodes;}); gizmo.activeScene = Qt.binding(function() {return activeScene;}); + gizmo.globalShow = Qt.binding(function() {return showIconGizmo;}); + gizmo.globalShowFrustum = Qt.binding(function() {return showCameraFrustum;}); frustum.viewPortRect = Qt.binding(function() {return viewPortRect;}); gizmo.connectFrustum(frustum); } @@ -449,11 +479,13 @@ Item { "selectedNodes": selectedNodes, "scene": scene, "activeScene": activeScene, "locked": _generalHelper.isLocked(obj), - "hidden": _generalHelper.isHidden(obj)}); + "hidden": _generalHelper.isHidden(obj), + "globalShow": showIconGizmo}); particleSystemIconGizmos[particleSystemIconGizmos.length] = gizmo; gizmo.clicked.connect(handleObjectClicked); gizmo.selectedNodes = Qt.binding(function() {return selectedNodes;}); gizmo.activeScene = Qt.binding(function() {return activeScene;}); + gizmo.globalShow = Qt.binding(function() {return showIconGizmo;}); } } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/IconGizmo.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/IconGizmo.qml index 03087b658a9..7752693d559 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/IconGizmo.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/IconGizmo.qml @@ -45,6 +45,8 @@ Item { property bool hasMouse: false property bool hidden: false property bool locked: false + property bool globalShow: true + property bool canBeVisible: activeScene === scene && !hidden && (targetNode ? targetNode.visible : false) property alias iconSource: iconImage.source @@ -55,7 +57,7 @@ Item { hasMouse = false; } - visible: activeScene === scene && !hidden && (targetNode ? targetNode.visible : false) + visible: canBeVisible && globalShow Overlay2D { id: iconOverlay diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp index b2a84ff53f3..afde832afcb 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp @@ -2116,6 +2116,15 @@ void Qt5InformationNodeInstanceServer::view3DAction(const View3DActionCommand &c case View3DActionCommand::ShowGrid: updatedState.insert("showGrid", command.isEnabled()); break; + case View3DActionCommand::ShowSelectionBox: + updatedState.insert("showSelectionBox", command.isEnabled()); + break; + case View3DActionCommand::ShowIconGizmo: + updatedState.insert("showIconGizmo", command.isEnabled()); + break; + case View3DActionCommand::ShowCameraFrustum: + updatedState.insert("showCameraFrustum", command.isEnabled()); + break; #ifdef QUICK3D_PARTICLES_MODULE case View3DActionCommand::ParticlesPlay: m_particleAnimationPlaying = command.isEnabled(); diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index fcf71902c8e..68532c1a534 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -158,6 +158,7 @@ extend_qtc_plugin(QmlDesigner edit3dwidget.cpp edit3dwidget.h edit3dcanvas.cpp edit3dcanvas.h edit3dactions.cpp edit3dactions.h + edit3dvisibilitytogglesmenu.cpp edit3dvisibilitytogglesmenu.h edit3d.qrc ) diff --git a/src/plugins/qmldesigner/components/edit3d/edit3d.qrc b/src/plugins/qmldesigner/components/edit3d/edit3d.qrc index bb1f6fd09c1..bf042b645b2 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3d.qrc +++ b/src/plugins/qmldesigner/components/edit3d/edit3d.qrc @@ -8,10 +8,6 @@ images/edit_light_off@2x.png images/edit_light_on.png images/edit_light_on@2x.png - images/grid_off.png - images/grid_off@2x.png - images/grid_on.png - images/grid_on@2x.png images/fit_selected.png images/fit_selected@2x.png images/move_off.png diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dactions.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dactions.cpp index e7838e720e8..c5240a0cbd6 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dactions.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dactions.cpp @@ -60,7 +60,7 @@ void Edit3DActionTemplate::actionTriggered(bool b) Edit3DAction::Edit3DAction(const QByteArray &menuId, View3DActionCommand::Type type, const QString &description, const QKeySequence &key, bool checkable, bool checked, const QIcon &iconOff, const QIcon &iconOn, - SelectionContextOperation selectionAction) + SelectionContextOperation selectionAction, const QString &toolTip) : AbstractAction(new Edit3DActionTemplate(description, selectionAction, type)) , m_menuId(menuId) { @@ -68,6 +68,11 @@ Edit3DAction::Edit3DAction(const QByteArray &menuId, View3DActionCommand::Type t action()->setShortcutContext(Qt::WidgetWithChildrenShortcut); action()->setCheckable(checkable); action()->setChecked(checked); + + // Description will be used as tooltip by default if no explicit tooltip is provided + if (!toolTip.isEmpty()) + action()->setToolTip(toolTip); + if (checkable) { QIcon onOffIcon; const auto onAvail = iconOn.availableSizes(); // Assume both icons have same sizes available diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dactions.h b/src/plugins/qmldesigner/components/edit3d/edit3dactions.h index 27b8fb7342d..ca95608629e 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dactions.h +++ b/src/plugins/qmldesigner/components/edit3d/edit3dactions.h @@ -54,7 +54,8 @@ public: Edit3DAction(const QByteArray &menuId, View3DActionCommand::Type type, const QString &description, const QKeySequence &key, bool checkable, bool checked, const QIcon &iconOff, const QIcon &iconOn, - SelectionContextOperation selectionAction = nullptr); + SelectionContextOperation selectionAction = nullptr, + const QString &toolTip = {}); QByteArray category() const override; diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp index 386f6a1137f..8e6d75efc37 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp @@ -42,6 +42,7 @@ #include #include +#include namespace QmlDesigner { @@ -113,14 +114,17 @@ void Edit3DView::renderImage3DChanged(const QImage &img) void Edit3DView::updateActiveScene3D(const QVariantMap &sceneState) { - const QString sceneKey = QStringLiteral("sceneInstanceId"); - const QString selectKey = QStringLiteral("selectionMode"); - const QString transformKey = QStringLiteral("transformMode"); - const QString perspectiveKey = QStringLiteral("usePerspective"); - const QString orientationKey = QStringLiteral("globalOrientation"); - const QString editLightKey = QStringLiteral("showEditLight"); - const QString gridKey = QStringLiteral("showGrid"); - const QString particlesPlayKey = QStringLiteral("particlePlay"); + const QString sceneKey = QStringLiteral("sceneInstanceId"); + const QString selectKey = QStringLiteral("selectionMode"); + const QString transformKey = QStringLiteral("transformMode"); + const QString perspectiveKey = QStringLiteral("usePerspective"); + const QString orientationKey = QStringLiteral("globalOrientation"); + const QString editLightKey = QStringLiteral("showEditLight"); + const QString gridKey = QStringLiteral("showGrid"); + const QString selectionBoxKey = QStringLiteral("showSelectionBox"); + const QString iconGizmoKey = QStringLiteral("showIconGizmo"); + const QString cameraFrustumKey = QStringLiteral("showCameraFrustum"); + const QString particlesPlayKey = QStringLiteral("particlePlay"); if (sceneState.contains(sceneKey)) { qint32 newActiveScene = sceneState[sceneKey].value(); @@ -165,6 +169,21 @@ void Edit3DView::updateActiveScene3D(const QVariantMap &sceneState) else m_showGridAction->action()->setChecked(false); + if (sceneState.contains(selectionBoxKey)) + m_showSelectionBoxAction->action()->setChecked(sceneState[selectionBoxKey].toBool()); + else + m_showSelectionBoxAction->action()->setChecked(false); + + if (sceneState.contains(iconGizmoKey)) + m_showIconGizmoAction->action()->setChecked(sceneState[iconGizmoKey].toBool()); + else + m_showIconGizmoAction->action()->setChecked(false); + + if (sceneState.contains(cameraFrustumKey)) + m_showCameraFrustumAction->action()->setChecked(sceneState[cameraFrustumKey].toBool()); + else + m_showCameraFrustumAction->action()->setChecked(false); + if (sceneState.contains(particlesPlayKey)) m_particlesPlayAction->action()->setChecked(sceneState[particlesPlayKey].toBool()); else @@ -301,9 +320,27 @@ void Edit3DView::createEdit3DActions() m_showGridAction = new Edit3DAction( QmlDesigner::Constants::EDIT3D_EDIT_SHOW_GRID, View3DActionCommand::ShowGrid, - QCoreApplication::translate("ShowGridAction", "Toggle Grid Visibility"), - QKeySequence(Qt::Key_G), true, true, Icons::EDIT3D_GRID_OFF.icon(), - Icons::EDIT3D_GRID_ON.icon()); + QCoreApplication::translate("ShowGridAction", "Show Grid"), + QKeySequence(Qt::Key_G), true, true, {}, {}, nullptr, + QCoreApplication::translate("ShowGridAction", "Toggle the visibility of the helper grid.")); + + m_showSelectionBoxAction = new Edit3DAction( + QmlDesigner::Constants::EDIT3D_EDIT_SHOW_SELECTION_BOX, View3DActionCommand::ShowSelectionBox, + QCoreApplication::translate("ShowSelectionBoxAction", "Show Selection Boxes"), + QKeySequence(Qt::Key_S), true, true, {}, {}, nullptr, + QCoreApplication::translate("ShowSelectionBoxAction", "Toggle the visibility of selection boxes.")); + + m_showIconGizmoAction = new Edit3DAction( + QmlDesigner::Constants::EDIT3D_EDIT_SHOW_ICON_GIZMO, View3DActionCommand::ShowIconGizmo, + QCoreApplication::translate("ShowIconGizmoAction", "Show Icon Gizmos"), + QKeySequence(Qt::Key_I), true, true, {}, {}, nullptr, + QCoreApplication::translate("ShowIconGizmoAction", "Toggle the visibility of icon gizmos, such as light and camera icons.")); + + m_showCameraFrustumAction = new Edit3DAction( + QmlDesigner::Constants::EDIT3D_EDIT_SHOW_CAMERA_FRUSTUM, View3DActionCommand::ShowCameraFrustum, + QCoreApplication::translate("ShowCameraFrustumAction", "Always Show Camera Frustums"), + QKeySequence(Qt::Key_C), true, false, {}, {}, nullptr, + QCoreApplication::translate("ShowCameraFrustumAction", "Toggle between always showing the camera frustum visualization and only showing it when the camera is selected.")); SelectionContextOperation resetTrigger = [this](const SelectionContext &) { m_particlesPlayAction->action()->setEnabled(particlemode); @@ -360,6 +397,29 @@ void Edit3DView::createEdit3DActions() QKeySequence(Qt::Key_P), false, false, Utils::Icons::RESET_TOOLBAR.icon(), {}, resetTrigger); + SelectionContextOperation visibilityTogglesTrigger = [this](const SelectionContext &) { + if (!edit3DWidget()->visibilityTogglesMenu()) + return; + + QPoint pos; + const auto &actionWidgets = m_visibilityTogglesAction->action()->associatedWidgets(); + for (auto actionWidget : actionWidgets) { + if (auto button = qobject_cast(actionWidget)) { + pos = button->mapToGlobal(QPoint(0, 0)); + break; + } + } + + edit3DWidget()->showVisibilityTogglesMenu(!edit3DWidget()->visibilityTogglesMenu()->isVisible(), + pos); + }; + + m_visibilityTogglesAction = new Edit3DAction( + QmlDesigner::Constants::EDIT3D_VISIBILITY_TOGGLES, View3DActionCommand::Empty, + QCoreApplication::translate("VisibilityTogglesAction", "Visibility Toggles"), + QKeySequence(), false, false, Utils::Icons::EYE_OPEN_TOOLBAR.icon(), + {}, visibilityTogglesTrigger); + m_leftActions << m_selectionModeAction; m_leftActions << nullptr; // Null indicates separator m_leftActions << nullptr; // Second null after separator indicates an exclusive group @@ -372,16 +432,22 @@ void Edit3DView::createEdit3DActions() m_leftActions << m_cameraModeAction; m_leftActions << m_orientationModeAction; m_leftActions << m_editLightAction; - m_leftActions << m_showGridAction; m_leftActions << nullptr; m_leftActions << m_alignCamerasAction; m_leftActions << m_alignViewAction; + m_leftActions << nullptr; + m_leftActions << m_visibilityTogglesAction; m_rightActions << m_particleViewModeAction; m_rightActions << m_particlesPlayAction; m_rightActions << m_particlesRestartAction; m_rightActions << nullptr; m_rightActions << m_resetAction; + + m_visibilityToggleActions << m_showGridAction; + m_visibilityToggleActions << m_showSelectionBoxAction; + m_visibilityToggleActions << m_showIconGizmoAction; + m_visibilityToggleActions << m_showCameraFrustumAction; } QVector Edit3DView::leftActions() const @@ -394,6 +460,11 @@ QVector Edit3DView::rightActions() const return m_rightActions; } +QVector Edit3DView::visibilityToggleActions() const +{ + return m_visibilityToggleActions; +} + void Edit3DView::addQuick3DImport() { DesignDocument *document = QmlDesignerPlugin::instance()->currentDesignDocument(); diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.h b/src/plugins/qmldesigner/components/edit3d/edit3dview.h index a61f78301c0..721a69bfa2e 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dview.h +++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.h @@ -71,6 +71,7 @@ public: void createEdit3DActions(); QVector leftActions() const; QVector rightActions() const; + QVector visibilityToggleActions() const; void setSeeker(SeekerSlider *slider); void addQuick3DImport(); @@ -84,6 +85,7 @@ private: QPointer m_edit3DWidget; QVector m_leftActions; QVector m_rightActions; + QVector m_visibilityToggleActions; Edit3DAction *m_selectionModeAction = nullptr; Edit3DAction *m_moveToolAction = nullptr; Edit3DAction *m_rotateToolAction = nullptr; @@ -95,10 +97,14 @@ private: Edit3DAction *m_orientationModeAction = nullptr; Edit3DAction *m_editLightAction = nullptr; Edit3DAction *m_showGridAction = nullptr; + Edit3DAction *m_showSelectionBoxAction = nullptr; + Edit3DAction *m_showIconGizmoAction = nullptr; + Edit3DAction *m_showCameraFrustumAction = nullptr; Edit3DAction *m_resetAction = nullptr; Edit3DAction *m_particleViewModeAction = nullptr; Edit3DAction *m_particlesPlayAction = nullptr; Edit3DAction *m_particlesRestartAction = nullptr; + Edit3DAction *m_visibilityTogglesAction = nullptr; SeekerSlider *m_seeker = nullptr; int particlemode; }; diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dvisibilitytogglesmenu.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dvisibilitytogglesmenu.cpp new file mode 100644 index 00000000000..9769411e904 --- /dev/null +++ b/src/plugins/qmldesigner/components/edit3d/edit3dvisibilitytogglesmenu.cpp @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** 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 "edit3dvisibilitytogglesmenu.h" + +namespace QmlDesigner { + +Edit3DVisibilityTogglesMenu::Edit3DVisibilityTogglesMenu(QWidget *parent) : + QMenu(parent) +{ + setToolTipsVisible(true); +} + +void Edit3DVisibilityTogglesMenu::mouseReleaseEvent(QMouseEvent *e) +{ + QAction *action = activeAction(); + if (action && action->isEnabled()) { + // Prevent the menu from closing on click on any item + action->setEnabled(false); + QMenu::mouseReleaseEvent(e); + action->setEnabled(true); + action->trigger(); + } else { + QMenu::mouseReleaseEvent(e); + } +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dvisibilitytogglesmenu.h b/src/plugins/qmldesigner/components/edit3d/edit3dvisibilitytogglesmenu.h new file mode 100644 index 00000000000..1838068b0f3 --- /dev/null +++ b/src/plugins/qmldesigner/components/edit3d/edit3dvisibilitytogglesmenu.h @@ -0,0 +1,44 @@ +/**************************************************************************** +** +** 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 + +namespace QmlDesigner { + +class Edit3DVisibilityTogglesMenu : public QMenu +{ + Q_OBJECT + +public: + explicit Edit3DVisibilityTogglesMenu(QWidget *parent = nullptr); + +protected: + void mouseReleaseEvent(QMouseEvent *e) override; + +private: +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp index 06630e3a4de..d88cf612c15 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp @@ -28,6 +28,7 @@ #include "edit3dcanvas.h" #include "edit3dview.h" #include "edit3dwidget.h" +#include "edit3dvisibilitytogglesmenu.h" #include "metainfo.h" #include "qmldesignerconstants.h" #include "qmldesignerplugin.h" @@ -75,27 +76,37 @@ 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, &context](const QVector &actions, bool left) { + auto handleActions = [this, &context](const QVector &actions, QMenu *menu, bool left) { bool previousWasSeparator = true; QActionGroup *group = nullptr; for (auto action : actions) { if (action) { + QAction *a = action->action(); if (group) - group->addAction(action->action()); - addAction(action->action()); - if (left) - m_toolBox->addLeftSideAction(action->action()); - else - m_toolBox->addRightSideAction(action->action()); + group->addAction(a); + if (menu) { + menu->addAction(a); + } else { + addAction(a); + if (left) + m_toolBox->addLeftSideAction(a); + else + m_toolBox->addRightSideAction(a); + } previousWasSeparator = false; // Register action as creator command to make it configurable Core::Command *command = Core::ActionManager::registerAction( - action->action(), action->menuId().constData(), context); - command->setDefaultKeySequence(action->action()->shortcut()); - command->augmentActionWithShortcutToolTip(action->action()); + a, action->menuId().constData(), context); + command->setDefaultKeySequence(a->shortcut()); + // Menu actions will have custom tooltips + if (menu) + a->setToolTip(command->stringWithAppendedShortcut(a->toolTip())); + else + command->augmentActionWithShortcutToolTip(a); + // Clear action shortcut so it doesn't conflict with command's override action - action->action()->setShortcut({}); + a->setShortcut({}); } else { if (previousWasSeparator) { group = new QActionGroup(this); @@ -104,18 +115,26 @@ Edit3DWidget::Edit3DWidget(Edit3DView *view) : group = nullptr; auto separator = new QAction(this); separator->setSeparator(true); - addAction(separator); - if (left) - m_toolBox->addLeftSideAction(separator); - else - m_toolBox->addRightSideAction(separator); + if (menu) { + menu->addAction(separator); + } else { + addAction(separator); + if (left) + m_toolBox->addLeftSideAction(separator); + else + m_toolBox->addRightSideAction(separator); + } previousWasSeparator = true; } } } }; - addActionsToToolBox(view->leftActions(), true); - addActionsToToolBox(view->rightActions(), false); + + handleActions(view->leftActions(), nullptr, true); + handleActions(view->rightActions(), nullptr, false); + + m_visibilityTogglesMenu = new Edit3DVisibilityTogglesMenu(this); + handleActions(view->visibilityToggleActions(), m_visibilityTogglesMenu, false); view->setSeeker(seeker); seeker->setToolTip(QLatin1String("Seek particle system time when paused.")); @@ -162,6 +181,21 @@ void Edit3DWidget::showCanvas(bool show) m_onboardingLabel->setVisible(!show); } +QMenu *Edit3DWidget::visibilityTogglesMenu() const +{ + return m_visibilityTogglesMenu.data(); +} + +void Edit3DWidget::showVisibilityTogglesMenu(bool show, const QPoint &pos) +{ + if (m_visibilityTogglesMenu.isNull()) + return; + if (show) + m_visibilityTogglesMenu->popup(pos); + else + m_visibilityTogglesMenu->close(); +} + void Edit3DWidget::linkActivated(const QString &link) { Q_UNUSED(link) diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h index e7223ceb8c9..5a4ed48e28e 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h +++ b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -47,6 +48,8 @@ public: void contextHelp(const Core::IContext::HelpCallback &callback) const; void showCanvas(bool show); + QMenu *visibilityTogglesMenu() const; + void showVisibilityTogglesMenu(bool show, const QPoint &pos); protected: void dragEnterEvent(QDragEnterEvent *dragEnterEvent) override; @@ -61,6 +64,7 @@ private: QPointer m_onboardingLabel; QPointer m_toolBox; Core::IContext *m_context = nullptr; + QPointer m_visibilityTogglesMenu; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/edit3d/images/grid_off.png b/src/plugins/qmldesigner/components/edit3d/images/grid_off.png deleted file mode 100644 index 4c355f70a89ef21893e7394bbcf7c20ed38103e1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 221 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4rT@h1`S>QUC>lA|Ns9#SLwZ;fq{XkB*-uL*(Y5V zt|SHqhHy_8#}J9BrTw@04k&Oq2RgQ!|M|cEu3JH;-lWe?m(_F|qWKbX*z^A0)t)lP zQ&TM=+tE>YNBLovq;FhvWpt9xc=*`a9?=haz0`-ji-pzy=(Sh-3xEHSE>+`lJ~G4U RAp-*ggQu&X%Q~loCIETjTA2U< diff --git a/src/plugins/qmldesigner/components/edit3d/images/grid_off@2x.png b/src/plugins/qmldesigner/components/edit3d/images/grid_off@2x.png deleted file mode 100644 index 88db6b9badd42a1be2cd242ee91880b0ba93e306..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 116 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;ICT0c(20oEV=?n}EoB=)|u7xFK-@bkO|NnoA zXvtm%1_m`x7sn8ZsmT$ntUOB$#S9o2#krD2#RUWt0=&aDvK=%|?mF>Nlc7MauIYWD S4jTgl1B0ilpUXO@geCwxhaT4e diff --git a/src/plugins/qmldesigner/components/edit3d/images/grid_on.png b/src/plugins/qmldesigner/components/edit3d/images/grid_on.png deleted file mode 100644 index 4c355f70a89ef21893e7394bbcf7c20ed38103e1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 221 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4rT@h1`S>QUC>lA|Ns9#SLwZ;fq{XkB*-uL*(Y5V zt|SHqhHy_8#}J9BrTw@04k&Oq2RgQ!|M|cEu3JH;-lWe?m(_F|qWKbX*z^A0)t)lP zQ&TM=+tE>YNBLovq;FhvWpt9xc=*`a9?=haz0`-ji-pzy=(Sh-3xEHSE>+`lJ~G4U RAp-*ggQu&X%Q~loCIETjTA2U< diff --git a/src/plugins/qmldesigner/components/edit3d/images/grid_on@2x.png b/src/plugins/qmldesigner/components/edit3d/images/grid_on@2x.png deleted file mode 100644 index 88db6b9badd42a1be2cd242ee91880b0ba93e306..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 116 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;ICT0c(20oEV=?n}EoB=)|u7xFK-@bkO|NnoA zXvtm%1_m`x7sn8ZsmT$ntUOB$#S9o2#krD2#RUWt0=&aDvK=%|?mF>Nlc7MauIYWD S4jTgl1B0ilpUXO@geCwxhaT4e diff --git a/src/plugins/qmldesigner/qmldesignerconstants.h b/src/plugins/qmldesigner/qmldesignerconstants.h index 53edd711d5c..3830c9e8da8 100644 --- a/src/plugins/qmldesigner/qmldesignerconstants.h +++ b/src/plugins/qmldesigner/qmldesignerconstants.h @@ -65,10 +65,14 @@ 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_EDIT_SHOW_GRID[] = "QmlDesigner.Editor3D.ToggleGrid"; +const char EDIT3D_EDIT_SHOW_SELECTION_BOX[] = "QmlDesigner.Editor3D.ToggleSelectionBox"; +const char EDIT3D_EDIT_SHOW_ICON_GIZMO[] = "QmlDesigner.Editor3D.ToggleIconGizmo"; +const char EDIT3D_EDIT_SHOW_CAMERA_FRUSTUM[] = "QmlDesigner.Editor3D.ToggleCameraFrustum"; const char EDIT3D_RESET_VIEW[] = "QmlDesigner.Editor3D.ResetView"; const char EDIT3D_PARTICLE_MODE[] = "QmlDesigner.Editor3D.ParticleViewModeToggle"; const char EDIT3D_PARTICLES_PLAY[] = "QmlDesigner.Editor3D.ParticlesPlay"; const char EDIT3D_PARTICLES_RESTART[] = "QmlDesigner.Editor3D.ParticlesRestart"; +const char EDIT3D_VISIBILITY_TOGGLES[] = "QmlDesigner.Editor3D.VisibilityToggles"; const char QML_DESIGNER_SUBFOLDER[] = "/designer/"; diff --git a/src/plugins/qmldesigner/qmldesignericons.h b/src/plugins/qmldesigner/qmldesignericons.h index 3323ceb49a9..75ec4ab2d3f 100644 --- a/src/plugins/qmldesigner/qmldesignericons.h +++ b/src/plugins/qmldesigner/qmldesignericons.h @@ -61,10 +61,6 @@ const Utils::Icon EDIT3D_PARTICLE_PAUSE({ {":/edit3d/images/particles_pause.png", Utils::Theme::QmlDesigner_HighlightColor}}); const Utils::Icon EDIT3D_PARTICLE_RESTART({ {":/edit3d/images/particles_restart.png", Utils::Theme::QmlDesigner_HighlightColor}}); -const Utils::Icon EDIT3D_GRID_ON({ - {":/edit3d/images/grid_on.png", Utils::Theme::QmlDesigner_HighlightColor}}); -const Utils::Icon EDIT3D_GRID_OFF({ - {":/edit3d/images/grid_off.png", Utils::Theme::IconsBaseColor}}); const Utils::Icon EDIT3D_SELECTION_MODE_ON({ {":/edit3d/images/select_group.png", Utils::Theme::QmlDesigner_HighlightColor}}); const Utils::Icon EDIT3D_SELECTION_MODE_OFF({ diff --git a/src/plugins/qmldesigner/qmldesignerplugin.qbs b/src/plugins/qmldesigner/qmldesignerplugin.qbs index ff16d0de7e3..e8bd9e68a04 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.qbs +++ b/src/plugins/qmldesigner/qmldesignerplugin.qbs @@ -514,6 +514,8 @@ Project { "edit3d/edit3dcanvas.h", "edit3d/edit3dactions.cpp", "edit3d/edit3dactions.h", + "edit3d/edit3dvisibilitytogglesmenu.cpp", + "edit3d/edit3dvisibilitytogglesmenu.h", "edit3d/edit3d.qrc", "formeditor/abstractcustomtool.cpp", "formeditor/abstractcustomtool.h", From f7c9dac3a797543bf03abf95e8e773a9ca081358 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 28 Jan 2022 14:08:35 +0100 Subject: [PATCH 23/55] SshDeviceProcess: Don't store exitCode Change-Id: Id957dc7b0e71d0d1376716cb2b63c83d43cc1a14 Reviewed-by: Reviewed-by: hjk --- .../projectexplorer/devicesupport/sshdeviceprocess.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp b/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp index e496ffaa322..1386c7a630b 100644 --- a/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp +++ b/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp @@ -58,7 +58,6 @@ public: QProcess::ExitStatus exitStatus = QProcess::NormalExit; DeviceProcessSignalOperation::Ptr killOperation; QTimer killTimer; - int exitCode = -1; enum State { Inactive, Connecting, Connected, ProcessRunning } state = Inactive; void setState(State newState); @@ -89,7 +88,6 @@ void SshDeviceProcess::start(const Runnable &runnable) d->setState(SshDeviceProcessPrivate::Connecting); d->errorMessage.clear(); - d->exitCode = -1; d->exitStatus = QProcess::NormalExit; d->runnable = runnable; QSsh::SshConnectionParameters params = device()->sshParameters(); @@ -145,13 +143,13 @@ QProcess::ProcessState SshDeviceProcess::state() const QProcess::ExitStatus SshDeviceProcess::exitStatus() const { - return d->exitStatus == QProcess::NormalExit && d->exitCode != 255 + return d->exitStatus == QProcess::NormalExit && exitCode() != 255 ? QProcess::NormalExit : QProcess::CrashExit; } int SshDeviceProcess::exitCode() const { - return d->exitCode; + return runInTerminal() ? QtcProcess::exitCode() : d->remoteProcess->exitCode(); } QString SshDeviceProcess::errorString() const @@ -241,7 +239,6 @@ void SshDeviceProcess::handleProcessStarted() void SshDeviceProcess::handleProcessFinished(const QString &error) { d->errorMessage = error; - d->exitCode = runInTerminal() ? QtcProcess::exitCode() : d->remoteProcess->exitCode(); if (d->killOperation && error.isEmpty()) d->errorMessage = tr("The process was ended forcefully."); d->setState(SshDeviceProcessPrivate::Inactive); From 74ea443ebf323790ded2c43e7d469bed104000b6 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 31 Jan 2022 10:19:30 +0100 Subject: [PATCH 24/55] LinuxDeviceProcess: Remove unused setRcFilesToSource() Change-Id: Ica834cbecfa481a3a6c94519a9799c4b917d49a1 Reviewed-by: hjk --- src/plugins/remotelinux/linuxdeviceprocess.cpp | 15 ++------------- src/plugins/remotelinux/linuxdeviceprocess.h | 6 ------ 2 files changed, 2 insertions(+), 19 deletions(-) diff --git a/src/plugins/remotelinux/linuxdeviceprocess.cpp b/src/plugins/remotelinux/linuxdeviceprocess.cpp index 654e975afc3..4953c8e5aba 100644 --- a/src/plugins/remotelinux/linuxdeviceprocess.cpp +++ b/src/plugins/remotelinux/linuxdeviceprocess.cpp @@ -49,11 +49,6 @@ LinuxDeviceProcess::LinuxDeviceProcess(const QSharedPointer &device, QObject *parent = nullptr); - // Files to source before executing the command (if they exist). Overrides the default. - void setRcFilesToSource(const QStringList &filePaths); - QByteArray readAllStandardOutput() override; private: QString fullCommandLine(const ProjectExplorer::Runnable &) const override; qint64 processId() const override; - const QStringList rcFilesToSource() const; - - QStringList m_rcFilesToSource; QByteArray m_output; qint64 m_processId = 0; bool m_pidParsed = false; From 2ee739b3627751bc7e4a9eb25c8461842f163b8c Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Mon, 31 Jan 2022 14:32:05 +0200 Subject: [PATCH 25/55] Git: Fix bad access to temporary storage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit + limit the fix to cases with HOMESHARE. Change-Id: Ic108ab49eb3b64d5e1d302466c74610acc412175 Reviewed-by: Alessandro Portale Reviewed-by: André Hartmann --- src/plugins/git/gitclient.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index 91e441ca682..3a51e2c043b 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -2225,10 +2225,12 @@ Environment GitClient::processEnvironment() const environment.prependOrSetPath(FilePath::fromUserInput(gitPath)); if (HostOsInfo::isWindowsHost() && settings().winSetHomeEnvironment.value()) { QString homePath; - if (const char *homeDrive = qgetenv("HOMEDRIVE")) - homePath = QString::fromLocal8Bit(homeDrive) + QString::fromLocal8Bit(qgetenv("HOMEPATH")); - else + if (qEnvironmentVariableIsEmpty("HOMESHARE")) { homePath = QDir::toNativeSeparators(QDir::homePath()); + } else { + homePath = QString::fromLocal8Bit(qgetenv("HOMEDRIVE")) + + QString::fromLocal8Bit(qgetenv("HOMEPATH")); + } environment.set("HOME", homePath); } environment.set("GIT_EDITOR", m_disableEditor ? "true" : m_gitQtcEditor); From a77f5d41b4ecce61b52cc5a2e6b3cda78b0fe98b Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 27 Jan 2022 12:27:45 +0100 Subject: [PATCH 26/55] CppEditor: No longer refer to clangd as experimental in the UI Change-Id: Iadfbdf23a92ee551fff03f5eb5b8a1b2b15b0870 Reviewed-by: Reviewed-by: David Schulz --- .../src/editors/creator-only/creator-clang-codemodel.qdoc | 2 +- src/plugins/cppeditor/cppcodemodelsettingspage.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 0480cdeed66..377f50394f4 100644 --- a/doc/qtcreator/src/editors/creator-only/creator-clang-codemodel.qdoc +++ b/doc/qtcreator/src/editors/creator-only/creator-clang-codemodel.qdoc @@ -176,7 +176,7 @@ \list 1 \li Select \uicontrol Tools > \uicontrol Options > \uicontrol C++ > - \uicontrol Clangd > \uicontrol {Use clangd (EXPERIMENTAL)}. + \uicontrol Clangd > \uicontrol {Use clangd}. \image qtcreator-options-clangd.png "clangd options" \li In \uicontrol {Path to executable}, enter the path to clangd version 13, or later. diff --git a/src/plugins/cppeditor/cppcodemodelsettingspage.cpp b/src/plugins/cppeditor/cppcodemodelsettingspage.cpp index 187413c30b8..780ae671ccd 100644 --- a/src/plugins/cppeditor/cppcodemodelsettingspage.cpp +++ b/src/plugins/cppeditor/cppcodemodelsettingspage.cpp @@ -219,7 +219,7 @@ ClangdSettingsWidget::ClangdSettingsWidget(const ClangdSettings::Data &settingsD : d(new Private) { const ClangdSettings settings(settingsData); - d->useClangdCheckBox.setText(tr("Use clangd (EXPERIMENTAL)")); + d->useClangdCheckBox.setText(tr("Use clangd")); d->useClangdCheckBox.setChecked(settings.useClangd()); d->clangdChooser.setExpectedKind(Utils::PathChooser::ExistingCommand); d->clangdChooser.setFilePath(settings.clangdFilePath()); From 01f33fe4f1b83797845cbacacf2762fc4b63ce71 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Mon, 31 Jan 2022 15:42:56 +0200 Subject: [PATCH 27/55] QmlDesigner: Enable MSAA on edit3D view Change-Id: I792156d08378d025cb9dae9f3a8cb00439198a6d Reviewed-by: Jarko Vihriala Reviewed-by: Thomas Hartmann --- share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditView3D.qml | 7 +++++++ .../qtcreator/qml/qmlpuppet/mockfiles/qt6/SceneView3D.qml | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditView3D.qml index cd3ec158a4c..c61b787b04d 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditView3D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditView3D.qml @@ -823,6 +823,13 @@ Item { camera: viewRoot.usePerspective ? overlayPerspectiveCamera : overlayOrthoCamera importScene: overlayScene z: 2 + + environment: sceneEnv + SceneEnvironment { + id: sceneEnv + antialiasingMode: SceneEnvironment.MSAA + antialiasingQuality: SceneEnvironment.High + } } Overlay2D { diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/SceneView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/SceneView3D.qml index c75472096e7..e59392b1ee2 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/SceneView3D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/SceneView3D.qml @@ -50,6 +50,13 @@ View3D { thresPerc = (grid_thresholds[thresIdx] - cameraZoomFactor) / (grid_thresholds[thresIdx] - grid_thresholds[thresIdx - 1]); } + environment: sceneEnv + SceneEnvironment { + id: sceneEnv + antialiasingMode: SceneEnvironment.MSAA + antialiasingQuality: SceneEnvironment.High + } + Node { id: sceneHelpers From 25fa5540ea8601cdf5fe1e841d940aff8483ad3f Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Fri, 28 Jan 2022 16:12:23 +0200 Subject: [PATCH 28/55] QmlDesigner: Implement adding and removing asset folders Also corrected assets view margins and few relevants tweaks. Task-number: QDS-5795 Change-Id: Ieeb68584bcb261422f48ec1a865f510a00c251f5 Reviewed-by: Miikka Heikkinen Reviewed-by: Thomas Hartmann --- .../itemLibraryQmlSources/Assets.qml | 237 ++++++++++++++++-- .../imports/HelperWidgets/Section.qml | 2 +- .../itemlibraryassetsfilesmodel.cpp | 4 + .../itemlibrary/itemlibraryassetsfilesmodel.h | 3 +- .../itemlibrary/itemlibraryassetsmodel.cpp | 50 +++- .../itemlibrary/itemlibraryassetsmodel.h | 5 +- src/plugins/qmldesigner/documentmanager.cpp | 6 + 7 files changed, 288 insertions(+), 19 deletions(-) diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/Assets.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/Assets.qml index 8444a2c88f6..ab403d203b2 100644 --- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/Assets.qml +++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/Assets.qml @@ -36,7 +36,9 @@ Item { property var selectedAssets: ({}) property int allExpandedState: 0 - property string delFilePath: "" + property string contextFilePath: "" + property var contextDir: undefined + property bool isDirContextMenu: false DropArea { id: dropArea @@ -67,6 +69,19 @@ Item { } } + MouseArea { // right clicking the empty area of the view + anchors.fill: parent + acceptedButtons: Qt.RightButton + onClicked: { + if (!assetsModel.isEmpty) { + contextFilePath = "" + contextDir = assetsModel.rootDir() + isDirContextMenu = false + contextMenu.popup() + } + } + } + // called from C++ to close context menu on focus out function handleViewFocusOut() { @@ -75,9 +90,139 @@ Item { selectedAssetsChanged() } + Dialog { + id: newFolderDialog + + title: qsTr("Create new folder") + anchors.centerIn: parent + closePolicy: Popup.CloseOnEscape + modal: true + + contentItem: Column { + spacing: 2 + + Row { + Text { + text: qsTr("Folder Name: ") + anchors.verticalCenter: parent.verticalCenter + color: StudioTheme.Values.themeTextColor + } + + StudioControls.TextField { + id: folderName + + actionIndicator.visible: false + translationIndicator.visible: false + + Keys.onEnterPressed: btnCreate.onClicked() + Keys.onReturnPressed: btnCreate.onClicked() + } + } + + Text { + text: qsTr("Folder Name cannot be empty.") + color: "#ff0000" + anchors.right: parent.right + visible: folderName.text === "" + } + + Item { // spacer + width: 1 + height: 20 + } + + Row { + anchors.right: parent.right + + Button { + id: btnCreate + + text: qsTr("Create") + enabled: folderName.text !== "" + onClicked: { + assetsModel.addNewFolder(contextDir.dirPath + '/' + folderName.text) + newFolderDialog.accept() + } + } + + Button { + text: qsTr("Cancel") + onClicked: newFolderDialog.reject() + } + } + } + + onOpened: { + folderName.text = "New folder" + folderName.selectAll() + folderName.forceActiveFocus() + } + } + + Dialog { + id: confirmDeleteFolderDialog + + title: qsTr("Folder not empty") + anchors.centerIn: parent + closePolicy: Popup.CloseOnEscape + implicitWidth: 300 + modal: true + + contentItem: Column { + spacing: 20 + width: parent.width + + Text { + id: folderNotEmpty + + text: qsTr("Folder '%1' is not empty. Are you sure you want to delete it?") + .arg(contextDir ? contextDir.dirName : "") + color: StudioTheme.Values.themeTextColor + wrapMode: Text.WordWrap + width: confirmDeleteFolderDialog.width + leftPadding: 10 + rightPadding: 10 + + Keys.onEnterPressed: btnDelete.onClicked() + Keys.onReturnPressed: btnDelete.onClicked() + } + + Text { + text: qsTr("If the folder has assets in use, deleting it might cause the project to not work correctly.") + color: StudioTheme.Values.themeTextColor + wrapMode: Text.WordWrap + width: confirmDeleteFolderDialog.width + leftPadding: 10 + rightPadding: 10 + } + + Row { + anchors.right: parent.right + Button { + id: btnDelete + + text: qsTr("Delete") + + onClicked: { + assetsModel.deleteFolder(contextDir.dirPath) + confirmDeleteFolderDialog.accept() + } + } + + Button { + text: qsTr("Cancel") + onClicked: confirmDeleteFolderDialog.reject() + } + } + } + + onOpened: folderNotEmpty.forceActiveFocus() + } + ScrollView { // TODO: experiment using ListView instead of ScrollView + Column id: assetsView anchors.fill: parent + interactive: assetsView.verticalScrollBarVisible Item { StudioControls.Menu { @@ -86,7 +231,7 @@ Item { StudioControls.MenuItem { text: qsTr("Expand All") enabled: allExpandedState !== 1 - visible: !delFilePath + visible: isDirContextMenu height: visible ? implicitHeight : 0 onTriggered: assetsModel.toggleExpandAll(true) } @@ -94,22 +239,51 @@ Item { StudioControls.MenuItem { text: qsTr("Collapse All") enabled: allExpandedState !== 2 - visible: !delFilePath + visible: isDirContextMenu height: visible ? implicitHeight : 0 onTriggered: assetsModel.toggleExpandAll(false) } + StudioControls.MenuSeparator { + visible: isDirContextMenu + height: visible ? StudioTheme.Values.border : 0 + } + StudioControls.MenuItem { text: qsTr("Delete File") - visible: delFilePath + visible: contextFilePath height: visible ? implicitHeight : 0 - onTriggered: assetsModel.removeFile(delFilePath) + onTriggered: assetsModel.deleteFile(contextFilePath) + } + + StudioControls.MenuSeparator { + visible: contextFilePath + height: visible ? StudioTheme.Values.border : 0 + } + + StudioControls.MenuItem { + text: qsTr("New Folder") + onTriggered: newFolderDialog.open() + } + + StudioControls.MenuItem { + text: qsTr("Delete Folder") + visible: isDirContextMenu + height: visible ? implicitHeight : 0 + onTriggered: { + var dirEmpty = !(contextDir.dirsModel && contextDir.dirsModel.rowCount() > 0) + && !(contextDir.filesModel && contextDir.filesModel.rowCount() > 0); + + if (dirEmpty) + assetsModel.deleteFolder(contextDir.dirPath) + else + confirmDeleteFolderDialog.open() + } } } } Column { - spacing: 2 Repeater { model: assetsModel // context property delegate: dirSection @@ -120,31 +294,35 @@ Item { Section { width: assetsView.width - - (assetsView.verticalScrollBarVisible ? assetsView.verticalThickness : 0) + (assetsView.verticalScrollBarVisible ? assetsView.verticalThickness : 0) - 5 caption: dirName sectionHeight: 30 sectionFontSize: 15 - levelShift: 20 leftPadding: 0 + topPadding: dirDepth > 0 ? 5 : 0 + bottomPadding: 0 hideHeader: dirDepth === 0 - showLeftBorder: true + showLeftBorder: dirDepth > 0 expanded: dirExpanded - visible: dirVisible + visible: !assetsModel.isEmpty && dirVisible expandOnClick: false useDefaulContextMenu: false onToggleExpand: { dirExpanded = !dirExpanded } + onShowContextMenu: { - delFilePath = "" + contextFilePath = "" + contextDir = model + isDirContextMenu = true allExpandedState = assetsModel.getAllExpandedState() contextMenu.popup() } Column { spacing: 5 - leftPadding: 15 + leftPadding: 5 Repeater { model: dirsModel @@ -155,6 +333,25 @@ Item { model: filesModel delegate: fileSection } + + Text { + text: qsTr("Empty folder") + color: StudioTheme.Values.themeTextColorDisabled + font.pixelSize: 12 + visible: !(dirsModel && dirsModel.rowCount() > 0) + && !(filesModel && filesModel.rowCount() > 0) + + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.RightButton + onClicked: { + contextFilePath = "" + contextDir = model + isDirContextMenu = true + contextMenu.popup() + } + } + } } } } @@ -222,8 +419,11 @@ Item { if (currFileSelected) rootView.startDragAsset(selectedAssetsArr, mapToGlobal(mouse.x, mouse.y)) } else { - delFilePath = filePath + contextFilePath = filePath + contextDir = model.fileDir + tooltipBackend.hideTooltip() + isDirContextMenu = false contextMenu.popup() } } @@ -263,7 +463,7 @@ Item { // Placeholder when the assets panel is empty Column { id: colNoAssets - visible: assetsModel.isEmpty + visible: assetsModel.isEmpty && !rootView.searchActive spacing: 20 x: 20 @@ -307,4 +507,13 @@ Item { wrapMode: Text.WordWrap } } + + Text { + text: qsTr("No match found.") + x: 20 + y: 10 + color: StudioTheme.Values.themeTextColor + font.pixelSize: 12 + visible: assetsModel.isEmpty && rootView.searchActive + } } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml index 66f05462c3e..3f8a3311894 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml @@ -173,7 +173,7 @@ Item { id: leftBorder visible: false width: 1 - height: parent.height - 15 + height: parent.height - bottomPadding color: header.color } diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsfilesmodel.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsfilesmodel.cpp index 1140ba43d7e..271f330fd23 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsfilesmodel.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsfilesmodel.cpp @@ -34,6 +34,7 @@ ItemLibraryAssetsFilesModel::ItemLibraryAssetsFilesModel(QObject *parent) // add roles m_roleNames.insert(FileNameRole, "fileName"); m_roleNames.insert(FilePathRole, "filePath"); + m_roleNames.insert(FileDirRole, "fileDir"); } QVariant ItemLibraryAssetsFilesModel::data(const QModelIndex &index, int role) const @@ -49,6 +50,9 @@ QVariant ItemLibraryAssetsFilesModel::data(const QModelIndex &index, int role) c if (role == FilePathRole) return m_files[index.row()]; + if (role == FileDirRole) + return QVariant::fromValue(parent()); + qWarning() << Q_FUNC_INFO << "Invalid role requested: " << QString::number(role); return {}; } diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsfilesmodel.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsfilesmodel.h index 25577dce515..5b44878eefc 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsfilesmodel.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsfilesmodel.h @@ -44,7 +44,8 @@ public: private: enum Roles {FileNameRole = Qt::UserRole + 1, - FilePathRole}; + FilePathRole, + FileDirRole}; QStringList m_files; QHash m_roleNames; diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsmodel.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsmodel.cpp index a09391570d5..be9b3b9f25c 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsmodel.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsmodel.cpp @@ -99,7 +99,7 @@ void ItemLibraryAssetsModel::toggleExpandAll(bool expand) endResetModel(); } -void ItemLibraryAssetsModel::removeFile(const QString &filePath) +void ItemLibraryAssetsModel::deleteFile(const QString &filePath) { bool askBeforeDelete = DesignerSettings::getValue( DesignerSettingsKey::ASK_BEFORE_DELETING_ASSET).toBool(); @@ -134,6 +134,52 @@ void ItemLibraryAssetsModel::removeFile(const QString &filePath) } } +void ItemLibraryAssetsModel::addNewFolder(const QString &folderPath) +{ + QString iterPath = folderPath; + QRegularExpression rgx("\\d+$"); // matches a number at the end of a string + QDir dir{folderPath}; + + while (dir.exists()) { + // if the folder name ends with a number, increment it + QRegularExpressionMatch match = rgx.match(iterPath); + if (match.hasMatch()) { // ends with a number + QString numStr = match.captured(0); + int num = match.captured(0).toInt(); + + // get number of padding zeros, ex: for "005" = 2 + int nPaddingZeros = 0; + for (; nPaddingZeros < numStr.size() && numStr[nPaddingZeros] == '0'; ++nPaddingZeros); + + ++num; + + // if the incremented number's digits increased, decrease the padding zeros + if (std::fmod(std::log10(num), 1.0) == 0) + --nPaddingZeros; + + iterPath = folderPath.mid(0, match.capturedStart()) + + QString('0').repeated(nPaddingZeros) + + QString::number(num); + } else { + iterPath = folderPath + '1'; + } + + dir.setPath(iterPath); + } + + dir.mkpath(iterPath); +} + +void ItemLibraryAssetsModel::deleteFolder(const QString &folderPath) +{ + QDir{folderPath}.removeRecursively(); +} + +QObject *ItemLibraryAssetsModel::rootDir() const +{ + return m_assetsDir; +} + const QStringList &ItemLibraryAssetsModel::supportedImageSuffixes() { static QStringList retList; @@ -270,7 +316,7 @@ void ItemLibraryAssetsModel::setRootPath(const QString &path) isEmpty &= parseDirRecursive(assetsDir, currDepth + 1); } - if (isEmpty) + if (!m_searchText.isEmpty() && isEmpty) currAssetsDir->setDirVisible(false); return isEmpty; diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsmodel.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsmodel.h index f7621563492..e429605b9a6 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsmodel.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsmodel.h @@ -83,7 +83,10 @@ public: Q_INVOKABLE void toggleExpandAll(bool expand); Q_INVOKABLE DirExpandState getAllExpandedState() const; - Q_INVOKABLE void removeFile(const QString &filePath); + Q_INVOKABLE void deleteFile(const QString &filePath); + Q_INVOKABLE void addNewFolder(const QString &folderPath); + Q_INVOKABLE void deleteFolder(const QString &folderPath); + Q_INVOKABLE QObject *rootDir() const; signals: void isEmptyChanged(); diff --git a/src/plugins/qmldesigner/documentmanager.cpp b/src/plugins/qmldesigner/documentmanager.cpp index 84e1416eb04..d510193d0a3 100644 --- a/src/plugins/qmldesigner/documentmanager.cpp +++ b/src/plugins/qmldesigner/documentmanager.cpp @@ -504,8 +504,14 @@ bool DocumentManager::belongsToQmakeProject() Utils::FilePath DocumentManager::currentResourcePath() { Utils::FilePath resourcePath = currentProjectDirPath(); + if (resourcePath.isEmpty()) return currentFilePath().absolutePath(); + + FilePath contentFilePath = resourcePath.pathAppended("content"); + if (contentFilePath.exists()) + return contentFilePath; + return resourcePath; } From a7d3f9fdba5512d84b0c0db5e5439ecb247d1667 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Fri, 28 Jan 2022 15:41:32 +0100 Subject: [PATCH 29/55] CMakePM: Display current value in CMake settings as tooltip If you change the value of a CMake parameter in CMake settings the new value was not displayed in the tooltip, the old value was. Change-Id: Ie182ef42f8bf48651d170da8054d7f60f9080088 Reviewed-by: Reviewed-by: Alessandro Portale --- src/plugins/cmakeprojectmanager/configmodel.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/configmodel.cpp b/src/plugins/cmakeprojectmanager/configmodel.cpp index fe11f9367b5..15e2de1f021 100644 --- a/src/plugins/cmakeprojectmanager/configmodel.cpp +++ b/src/plugins/cmakeprojectmanager/configmodel.cpp @@ -526,10 +526,9 @@ QString ConfigModelTreeItem::toolTip() const tooltip << QCoreApplication::translate("CMakeProjectManager", "

Kit: %1

") .arg(dataItem->kitValue); - if (dataItem->value != dataItem->newValue) - tooltip << QCoreApplication::translate("CMakeProjectManager", - "

Initial Configuration: %1

") - .arg(dataItem->value); + tooltip << QCoreApplication::translate("CMakeProjectManager", + "

Initial Configuration: %1

") + .arg(dataItem->currentValue()); } else { if (!dataItem->initialValue.isEmpty()) tooltip << QCoreApplication::translate("CMakeProjectManager", @@ -537,10 +536,9 @@ QString ConfigModelTreeItem::toolTip() const .arg(dataItem->initialValue); if (dataItem->inCMakeCache) { - if (dataItem->value != dataItem->newValue) - tooltip << QCoreApplication::translate("CMakeProjectManager", - "

Current Configuration: %1

") - .arg(dataItem->value); + tooltip << QCoreApplication::translate("CMakeProjectManager", + "

Current Configuration: %1

") + .arg(dataItem->currentValue()); } else { tooltip << QCoreApplication::translate("CMakeProjectManager", "

Not in CMakeCache.txt

"); From 4a0c6f1e787c8ba2e1d46ecd155f3817ccc93802 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Str=C3=B8mme?= Date: Mon, 31 Jan 2022 14:17:12 +0100 Subject: [PATCH 30/55] Fix invalid usage of temporary data Make sure the return value stays valid in the scope we're using it in. Change-Id: Ifa8a7ef88c9189ba90f5adb699b284f381a59488 Reviewed-by: Miikka Heikkinen Reviewed-by: --- .../qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.cpp index a4e950b238b..cee091531a7 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.cpp @@ -729,7 +729,8 @@ void MouseArea3D::applyFreeRotation(QQuick3DNode *node, const QVector3D &startRo if (dragVector.length() < 0.001f) return; - const float *dataPtr(sceneTransform().data()); + const auto &transform = sceneTransform(); + const float *dataPtr(transform.data()); QVector3D xAxis = QVector3D(dataPtr[0], dataPtr[1], dataPtr[2]).normalized(); QVector3D yAxis = QVector3D(dataPtr[4], dataPtr[5], dataPtr[6]).normalized(); QVector3D finalAxis = (dragVector.x() * yAxis + dragVector.y() * xAxis); @@ -1029,7 +1030,8 @@ void MouseArea3D::setHovering(bool enable) QVector3D MouseArea3D::getNormal() const { - const float *dataPtr(sceneTransform().data()); + const auto &transform = sceneTransform(); + const float *dataPtr(transform.data()); return QVector3D(dataPtr[8], dataPtr[9], dataPtr[10]).normalized(); } From d5eed0480d94586519c53b47b1372dfdf23165a7 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Fri, 28 Jan 2022 16:44:05 +0100 Subject: [PATCH 31/55] CMakePM: Save initial configuration changes on "exit" Previously the changes to "Initial Configuration" would be done only after pressing "Re-configure with Initial Parameters". Now the settings are saved when the widget is closed: - a different kit is selected - a different build type is selected - project is closed - switch between build and run settings This way the changes are not lost. Change-Id: Ia2c1c10c59bfa101332066205f98684843266f94 Reviewed-by: Alessandro Portale --- src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index 4a39dd9d3b8..6be3d6e60bb 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -480,12 +480,14 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc) if (m_buildConfiguration->isEnabled()) setError(QString()); }); + connect(this, &QObject::destroyed, this, [this](const QObject *obj) { + updateInitialCMakeArguments(); + }); updateSelection(); updateConfigurationStateSelection(); } - void CMakeBuildSettingsWidget::batchEditConfiguration() { auto dialog = new QDialog(this); From e58f50df2a049b2588242fb58d575f955ec0b59d Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Sat, 29 Jan 2022 00:36:49 +0100 Subject: [PATCH 32/55] Android: Remove html code from tr-strings in keystore creation dialog MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change removes markup with its unthemed color values from translatable strings. Terminates error messages with a ".". Adjusts the message strings in the .ts files, accordingly. The error label is changed from QLabel to Utils::InfoLabel. Change-Id: Ifdd65de8d9e0ae311b494e70b9dc77ca0a3e4f46 Reviewed-by: Reviewed-by: Assam Boudjelthia Reviewed-by: Leena Miettinen Reviewed-by: Robert Löhning --- share/qtcreator/translations/qtcreator_cs.ts | 24 +++++++------- share/qtcreator/translations/qtcreator_da.ts | 24 +++++++------- share/qtcreator/translations/qtcreator_de.ts | 24 +++++++------- share/qtcreator/translations/qtcreator_fr.ts | 24 +++++++------- share/qtcreator/translations/qtcreator_hr.ts | 12 +++---- share/qtcreator/translations/qtcreator_ja.ts | 24 +++++++------- share/qtcreator/translations/qtcreator_pl.ts | 20 ++++++------ share/qtcreator/translations/qtcreator_ru.ts | 24 +++++++------- share/qtcreator/translations/qtcreator_uk.ts | 24 +++++++------- .../androidcreatekeystorecertificate.cpp | 31 ++++++++++++------- .../androidcreatekeystorecertificate.ui | 16 +++++----- 11 files changed, 128 insertions(+), 119 deletions(-) diff --git a/share/qtcreator/translations/qtcreator_cs.ts b/share/qtcreator/translations/qtcreator_cs.ts index f0ea6449907..b7e0efc99e3 100644 --- a/share/qtcreator/translations/qtcreator_cs.ts +++ b/share/qtcreator/translations/qtcreator_cs.ts @@ -54911,28 +54911,28 @@ Nainstalujte, prosím, jedno SDK s API verze alespoň %1. <span style=" color:#ff0000;">Heslo je OK</span> - <span style=" color:#ff0000;">Keystore password is too short</span> - <span style=" color:#ff0000;">Heslo k úložišti klíče je příliš krátké</span> + Keystore password is too short. + Heslo k úložišti klíče je příliš krátké. - <span style=" color:#ff0000;">Keystore passwords do not match</span> - <span style=" color:#ff0000;">Hesla k úložišti klíče neodpovídají</span> + Keystore passwords do not match. + Hesla k úložišti klíče neodpovídají. - <span style=" color:#ff0000;">Certificate password is too short</span> - <span style=" color:#ff0000;">Heslo k certifikátu je příliš krátké</span> + Certificate password is too short. + Heslo k certifikátu je příliš krátké. - <span style=" color:#ff0000;">Certificate passwords do not match</span> - <span style=" color:#ff0000;">Hesla k certifikátům neodpovídají</span> + Certificate passwords do not match. + Hesla k certifikátům neodpovídají. - <span style=" color:#ff0000;">Certificate alias is missing</span> - <span style=" color:#ff0000;">Alias certifikátu chybí</span> + Certificate alias is missing. + Alias certifikátu chybí. - <span style=" color:#ff0000;">Invalid country code</span> - <span style=" color:#ff0000;">Neplatné číslo země (mezinárodní předvolba)</span> + Invalid country code. + Neplatné číslo země (mezinárodní předvolba). Keystore file name diff --git a/share/qtcreator/translations/qtcreator_da.ts b/share/qtcreator/translations/qtcreator_da.ts index 41fd7c673ca..4cfd3841b60 100644 --- a/share/qtcreator/translations/qtcreator_da.ts +++ b/share/qtcreator/translations/qtcreator_da.ts @@ -268,28 +268,28 @@ Minimum API-niveauet krævet af kittet er %1. Android::Internal::AndroidCreateKeystoreCertificate - <span style=" color:#ff0000;">Keystore password is too short</span> - <span style=" color:#ff0000;">Keystore adgangskode er for kort</span> + Keystore password is too short. + Keystore adgangskode er for kort. - <span style=" color:#ff0000;">Keystore passwords do not match</span> - <span style=" color:#ff0000;">Keystore adgangskoder matcher ikke</span> + Keystore passwords do not match. + Keystore adgangskoder matcher ikke. - <span style=" color:#ff0000;">Certificate password is too short</span> - <span style=" color:#ff0000;">Certifikat adgangskode er for kort</span> + Certificate password is too short. + Certifikat adgangskode er for kort. - <span style=" color:#ff0000;">Certificate passwords do not match</span> - <span style=" color:#ff0000;">Certifikat adgangskoder matcher ikke</span> + Certificate passwords do not match. + Certifikat adgangskoder matcher ikke. - <span style=" color:#ff0000;">Certificate alias is missing</span> - <span style=" color:#ff0000;">Certifikat-alias mangler</span> + Certificate alias is missing. + Certifikat-alias mangler. - <span style=" color:#ff0000;">Invalid country code</span> - <span style=" color:#ff0000;">Ugyldig sprogkode</span> + Invalid country code. + Ugyldig sprogkode. Keystore Filename diff --git a/share/qtcreator/translations/qtcreator_de.ts b/share/qtcreator/translations/qtcreator_de.ts index 8eaec177f8d..dece10295e4 100644 --- a/share/qtcreator/translations/qtcreator_de.ts +++ b/share/qtcreator/translations/qtcreator_de.ts @@ -19510,28 +19510,28 @@ should a repository require SSH-authentication (see documentation on SSH and the Android::Internal::AndroidCreateKeystoreCertificate - <span style=" color:#ff0000;">Keystore password is too short</span> - <span style=" color:#ff0000;">Das Keystore-Passwort ist zu kurz</span> + Keystore password is too short. + Das Keystore-Passwort ist zu kurz. - <span style=" color:#ff0000;">Keystore passwords do not match</span> - <span style=" color:#ff0000;">Die Keystore-Passwörter stimmen nicht überein</span> + Keystore passwords do not match. + Die Keystore-Passwörter stimmen nicht überein. - <span style=" color:#ff0000;">Certificate password is too short</span> - <span style=" color:#ff0000;">Das Passwort des Zertifikats ist zu kurz</span> + Certificate password is too short. + Das Passwort des Zertifikats ist zu kurz. - <span style=" color:#ff0000;">Certificate passwords do not match</span> - <span style=" color:#ff0000;">Die Passwörter des Zertifikats stimmen nicht überein</span> + Certificate passwords do not match. + Die Passwörter des Zertifikats stimmen nicht überein. - <span style=" color:#ff0000;">Certificate alias is missing</span> - <span style=" color:#ff0000;">Der Alias des Zertifikats fehlt</span> + Certificate alias is missing. + Der Alias des Zertifikats fehlt. - <span style=" color:#ff0000;">Invalid country code</span> - <span style=" color:#ff0000;">Ungültiger Ländercode</span> + Invalid country code. + Ungültiger Ländercode. Keystore Filename diff --git a/share/qtcreator/translations/qtcreator_fr.ts b/share/qtcreator/translations/qtcreator_fr.ts index 95808e6d7b9..ec42c365792 100644 --- a/share/qtcreator/translations/qtcreator_fr.ts +++ b/share/qtcreator/translations/qtcreator_fr.ts @@ -60828,28 +60828,28 @@ Veuillez installer un SDK supérieur à la version %1. <span style=" color:#00ff00;">Mot de passe correct</span> - <span style=" color:#ff0000;">Keystore password is too short</span> - <span style=" color:#ff0000;">Le mot de passe du trousseau de clés est trop court</span> + Keystore password is too short. + Le mot de passe du trousseau de clés est trop court. - <span style=" color:#ff0000;">Keystore passwords do not match</span> - <span style=" color:#ff0000;">Les mots de passe du trousseau de clés ne correspondent pas</span> + Keystore passwords do not match. + Les mots de passe du trousseau de clés ne correspondent pas. - <span style=" color:#ff0000;">Certificate password is too short</span> - <span style=" color:#ff0000;">Le mot de passe du certificat est manquant</span> + Certificate password is too short. + Le mot de passe du certificat est manquant. - <span style=" color:#ff0000;">Certificate passwords do not match</span> - <span style=" color:#ff0000;">Les mots de passe du certificat ne correspondent pas</span> + Certificate passwords do not match. + Les mots de passe du certificat ne correspondent pas. - <span style=" color:#ff0000;">Certificate alias is missing</span> - <span style=" color:#ff0000;">L'alias du certificat est manquant</span> + Certificate alias is missing. + L'alias du certificat est manquant. - <span style=" color:#ff0000;">Invalid country code</span> - <span style=" color:#ff0000;">Le code de pays est invalide</span> + Invalid country code. + Le code de pays est invalide. Keystore file name diff --git a/share/qtcreator/translations/qtcreator_hr.ts b/share/qtcreator/translations/qtcreator_hr.ts index 405ef04c3d0..e7a14f06a9c 100644 --- a/share/qtcreator/translations/qtcreator_hr.ts +++ b/share/qtcreator/translations/qtcreator_hr.ts @@ -14265,27 +14265,27 @@ The minimum API level required by the kit is %1. Android::Internal::AndroidCreateKeystoreCertificate - <span style=" color:#ff0000;">Keystore password is too short</span> + Keystore password is too short. - <span style=" color:#ff0000;">Keystore passwords do not match</span> + Keystore passwords do not match. - <span style=" color:#ff0000;">Certificate password is too short</span> + Certificate password is too short. - <span style=" color:#ff0000;">Certificate passwords do not match</span> + Certificate passwords do not match. - <span style=" color:#ff0000;">Certificate alias is missing</span> + Certificate alias is missing. - <span style=" color:#ff0000;">Invalid country code</span> + Invalid country code. diff --git a/share/qtcreator/translations/qtcreator_ja.ts b/share/qtcreator/translations/qtcreator_ja.ts index 890908ed99a..c65ccab4138 100644 --- a/share/qtcreator/translations/qtcreator_ja.ts +++ b/share/qtcreator/translations/qtcreator_ja.ts @@ -9625,28 +9625,28 @@ with a password, which you can enter below. Android::Internal::AndroidCreateKeystoreCertificate - <span style=" color:#ff0000;">Keystore password is too short</span> - <span style=" color:#ff0000;">キーストアパスワードが短すぎます</span> + Keystore password is too short. + キーストアパスワードが短すぎます。 - <span style=" color:#ff0000;">Keystore passwords do not match</span> - <span style=" color:#ff0000;">キーストアパスワードが一致しません</span> + Keystore passwords do not match. + キーストアパスワードが一致しません。 - <span style=" color:#ff0000;">Certificate password is too short</span> - <span style=" color:#ff0000;">証明書のパスワードが短すぎます</span> + Certificate password is too short. + 証明書のパスワードが短すぎます。 - <span style=" color:#ff0000;">Certificate passwords do not match</span> - <span style=" color:#ff0000;">証明書のパスワードが一致しません</span> + Certificate passwords do not match. + 証明書のパスワードが一致しません。 - <span style=" color:#ff0000;">Certificate alias is missing</span> - <span style=" color:#ff0000;">証明書のエイリアスが見つかりません</span> + Certificate alias is missing. + 証明書のエイリアスが見つかりません。 - <span style=" color:#ff0000;">Invalid country code</span> - <span style=" color:#ff0000;">無効な国コードです</span> + Invalid country code. + 無効な国コードです。 Keystore file name diff --git a/share/qtcreator/translations/qtcreator_pl.ts b/share/qtcreator/translations/qtcreator_pl.ts index a088b92e294..4bd2dfddc49 100644 --- a/share/qtcreator/translations/qtcreator_pl.ts +++ b/share/qtcreator/translations/qtcreator_pl.ts @@ -21525,28 +21525,28 @@ Sprawdź dokumentację SSH i zmienną środowiskową SSH_ASKPASS. Android::Internal::AndroidCreateKeystoreCertificate - <span style=" color:#ff0000;">Keystore password is too short</span> + Keystore password is too short. - <span style=" color:#ff0000;">Keystore passwords do not match</span> + Keystore passwords do not match. - <span style=" color:#ff0000;">Certificate password is too short</span> - <span style=" color:#ff0000;">Hasło certyfikatu jest zbyt krótkie</span> + Certificate password is too short. + Hasło certyfikatu jest zbyt krótkie. - <span style=" color:#ff0000;">Certificate passwords do not match</span> - <span style=" color:#ff0000;">Hasła certyfikatu nie zgadzają się</span> + Certificate passwords do not match. + Hasła certyfikatu nie zgadzają się. - <span style=" color:#ff0000;">Certificate alias is missing</span> - <span style=" color:#ff0000;">Brak aliasu certyfikatu</span> + Certificate alias is missing. + Brak aliasu certyfikatu. - <span style=" color:#ff0000;">Invalid country code</span> - <span style=" color:#ff0000;">Niepoprawny kod kraju</span> + Invalid country code. + Niepoprawny kod kraju. Keystore Filename diff --git a/share/qtcreator/translations/qtcreator_ru.ts b/share/qtcreator/translations/qtcreator_ru.ts index 343f1c468e4..1305808ff41 100644 --- a/share/qtcreator/translations/qtcreator_ru.ts +++ b/share/qtcreator/translations/qtcreator_ru.ts @@ -887,28 +887,28 @@ The files in the Android package source directory are copied to the build direct Android::Internal::AndroidCreateKeystoreCertificate - <span style=" color:#ff0000;">Keystore password is too short</span> - <span style=" color:#ff0000;">Пароль связки ключей слишком короткий</span> + Keystore password is too short. + Пароль связки ключей слишком короткий. - <span style=" color:#ff0000;">Keystore passwords do not match</span> - <span style=" color:#ff0000;">Неверный пароль связки ключей</span> + Keystore passwords do not match. + Неверный пароль связки ключей. - <span style=" color:#ff0000;">Certificate password is too short</span> - <span style=" color:#ff0000;">Пароль сертификата слишком короткий</span> + Certificate password is too short. + Пароль сертификата слишком короткий. - <span style=" color:#ff0000;">Certificate passwords do not match</span> - <span style=" color:#ff0000;">Неверный пароль сертификата</span> + Certificate passwords do not match. + Неверный пароль сертификата. - <span style=" color:#ff0000;">Certificate alias is missing</span> - <span style=" color:#ff0000;">Отсутствует алиас сертификата</span> + Certificate alias is missing. + Отсутствует алиас сертификата. - <span style=" color:#ff0000;">Invalid country code</span> - <span style=" color:#ff0000;">Неверный код страны</span> + Invalid country code. + Неверный код страны. Keystore Filename diff --git a/share/qtcreator/translations/qtcreator_uk.ts b/share/qtcreator/translations/qtcreator_uk.ts index f7de935b70e..7ed2f44691f 100644 --- a/share/qtcreator/translations/qtcreator_uk.ts +++ b/share/qtcreator/translations/qtcreator_uk.ts @@ -32522,28 +32522,28 @@ Please install an SDK of at least API version %1. <span style=" color:#00ff00;">Пароль вдалий</span> - <span style=" color:#ff0000;">Keystore password is too short</span> - <span style=" color:#ff0000;">Пароль сховища ключів закороткий</span> + Keystore password is too short. + Пароль сховища ключів закороткий. - <span style=" color:#ff0000;">Keystore passwords do not match</span> - <span style=" color:#ff0000;">Паролі сховища ключів не співпадають</span> + Keystore passwords do not match. + Паролі сховища ключів не співпадають. - <span style=" color:#ff0000;">Certificate password is too short</span> - <span style=" color:#ff0000;">Пароль сертифіката закороткий</span> + Certificate password is too short. + Пароль сертифіката закороткий. - <span style=" color:#ff0000;">Certificate passwords do not match</span> - <span style=" color:#ff0000;">Паролі сертифіката не співпадають</span> + Certificate passwords do not match. + Паролі сертифіката не співпадають. - <span style=" color:#ff0000;">Certificate alias is missing</span> - <span style=" color:#ff0000;">Відсутній псевдонім сертифіката</span> + Certificate alias is missing. + Відсутній псевдонім сертифіката. - <span style=" color:#ff0000;">Invalid country code</span> - <span style=" color:#ff0000;">Неправильний код країни</span> + Invalid country code. + Неправильний код країни. Keystore file name diff --git a/src/plugins/android/androidcreatekeystorecertificate.cpp b/src/plugins/android/androidcreatekeystorecertificate.cpp index 42296720ed3..48c91c6bae8 100644 --- a/src/plugins/android/androidcreatekeystorecertificate.cpp +++ b/src/plugins/android/androidcreatekeystorecertificate.cpp @@ -42,6 +42,9 @@ AndroidCreateKeystoreCertificate::AndroidCreateKeystoreCertificate(QWidget *pare ui(new Ui::AndroidCreateKeystoreCertificate) { ui->setupUi(this); + ui->infoLabel->setType(InfoLabel::Error); + ui->infoLabel->hide(); + connect(ui->keystorePassLineEdit, &QLineEdit::textChanged, this, &AndroidCreateKeystoreCertificate::checkKeystorePassword); connect(ui->keystoreRetypePassLineEdit, &QLineEdit::textChanged, @@ -100,15 +103,17 @@ QString AndroidCreateKeystoreCertificate::certificatePassword() AndroidCreateKeystoreCertificate::PasswordStatus AndroidCreateKeystoreCertificate::checkKeystorePassword() { if (ui->keystorePassLineEdit->text().length() < 6) { - ui->infoLabel->setText(tr("Keystore password is too short")); + ui->infoLabel->show(); + ui->infoLabel->setText(tr("Keystore password is too short.")); return Invalid; } if (ui->keystorePassLineEdit->text() != ui->keystoreRetypePassLineEdit->text()) { - ui->infoLabel->setText(tr("Keystore passwords do not match")); - return NoMatch; + ui->infoLabel->show(); + ui->infoLabel->setText(tr("Keystore passwords do not match.")); + return NoMatch; } - ui->infoLabel->clear(); + ui->infoLabel->hide(); return Match; } @@ -118,37 +123,41 @@ AndroidCreateKeystoreCertificate::PasswordStatus AndroidCreateKeystoreCertificat return Match; if (ui->certificatePassLineEdit->text().length() < 6) { - ui->infoLabel->setText(tr("Certificate password is too short")); + ui->infoLabel->show(); + ui->infoLabel->setText(tr("Certificate password is too short.")); return Invalid; } if (ui->certificatePassLineEdit->text() != ui->certificateRetypePassLineEdit->text()) { - ui->infoLabel->setText(tr("Certificate passwords do not match")); + ui->infoLabel->show(); + ui->infoLabel->setText(tr("Certificate passwords do not match.")); return NoMatch; } - ui->infoLabel->clear(); + ui->infoLabel->hide(); return Match; } bool AndroidCreateKeystoreCertificate::checkCertificateAlias() { if (ui->certificateAliasLineEdit->text().length() == 0) { - ui->infoLabel->setText(tr("Certificate alias is missing")); + ui->infoLabel->show(); + ui->infoLabel->setText(tr("Certificate alias is missing.")); return false; } - ui->infoLabel->clear(); + ui->infoLabel->hide(); return true; } bool AndroidCreateKeystoreCertificate::checkCountryCode() { if (!ui->countryLineEdit->text().contains(QRegularExpression("[A-Z]{2}"))) { - ui->infoLabel->setText(tr("Invalid country code")); + ui->infoLabel->show(); + ui->infoLabel->setText(tr("Invalid country code.")); return false; } - ui->infoLabel->clear(); + ui->infoLabel->hide(); return true; } diff --git a/src/plugins/android/androidcreatekeystorecertificate.ui b/src/plugins/android/androidcreatekeystorecertificate.ui index 4c62e9e9414..639275329c1 100644 --- a/src/plugins/android/androidcreatekeystorecertificate.ui +++ b/src/plugins/android/androidcreatekeystorecertificate.ui @@ -299,17 +299,17 @@ - - - - - - Qt::AlignCenter - - + + + + Utils::InfoLabel + QLabel +
utils/infolabel.h
+
+
keystorePassLineEdit keystoreRetypePassLineEdit From fe0352669d5a5dcee768f8e198316fcf9a3ae4dd Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 31 Jan 2022 12:06:55 +0000 Subject: [PATCH 33/55] Revert "macOS: Fix Delete with Google Japanese IME" This reverts commit 5a3648c8956c74cc39ed37b8ee2a7d324b0dfc35. Reason for revert: breaks other shortcuts like shift+del to cut the current line under the cursor Change-Id: I5313c66df9dfa4283cc3f84ce9e7fd5464d0f73e Reviewed-by: Christian Kandeler --- src/plugins/texteditor/texteditor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index ae9b735367c..79228163cc5 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -2914,7 +2914,7 @@ bool TextEditorWidget::event(QEvent *e) && (ke->key() < Qt::Key_Escape)); d->m_maybeFakeTooltipEvent = false; } - break; + return true; } case QEvent::ApplicationPaletteChange: { // slight hack: ignore palette changes From 3ecfb5739cc3e9572578f7040e29928a9b9f25f4 Mon Sep 17 00:00:00 2001 From: Mats Honkamaa Date: Mon, 24 Jan 2022 15:13:59 +0200 Subject: [PATCH 34/55] Doc: Update all LoginUI tutorials Update all LoginUI tutorials and the documentation for them. Task-number: QDS-5915 Change-Id: I5a2665ca08ae3d167dfb5e937ee36c96f42ccd9a Reviewed-by: Leena Miettinen --- .../doc/images/loginui1-project-files.png | Bin 9602 -> 14664 bytes .../doc/images/loginui3-visibility.png | Bin 5281 -> 4079 bytes doc/qtdesignstudio/examples/doc/loginui1.qdoc | 53 ++++---- doc/qtdesignstudio/examples/doc/loginui2.qdoc | 12 +- doc/qtdesignstudio/examples/doc/loginui3.qdoc | 10 +- doc/qtdesignstudio/examples/doc/loginui4.qdoc | 22 ++-- .../loginui1/{ => content}/EntryField.ui.qml | 22 ++-- .../loginui1/{ => content}/PushButton.ui.qml | 29 +++-- .../loginui1/{ => content}/Screen01.ui.qml | 32 +++-- .../{ => content}/images/adventurePage.jpg | Bin .../images/qt_logo_green_128x128px.png | Bin 0 -> 1800 bytes .../images/qt_logo_green_128x128px.png | Bin 3517 -> 0 bytes .../imports/loginui1/EventListModel.qml | 41 +++++++ .../imports/loginui1/EventListSimulator.qml | 51 ++++++++ .../examples/loginui1/imports/loginui1/qmldir | 4 + .../examples/loginui1/loginui1.qml | 61 ---------- .../examples/loginui1/loginui1.qmlproject | 92 ++++++++++++-- .../examples/loginui1/qtquickcontrols2.conf | 6 - .../src/app_environment.h} | 23 ++-- .../loginui1/src/import_qml_plugins.h | 9 ++ .../examples/loginui1/src/main.cpp | 62 ++++++++++ .../examples/loginui2/Loginui2.qmlproject | 75 ++++++++++++ .../loginui2/{ => content}/Screen01.ui.qml | 23 ++-- .../loginui2/imports/loginui2/Constants.qml | 26 ---- .../examples/loginui2/imports/loginui2/qmldir | 2 - .../examples/loginui2/loginui2.qml | 61 ---------- .../examples/loginui2/loginui2.qmlproject | 47 -------- .../examples/loginui2/qtquickcontrols2.conf | 6 - .../examples/loginui3/Loginui3.qmlproject | 75 ++++++++++++ .../loginui3/{ => content}/Screen01.ui.qml | 24 ++-- .../loginui3/imports/loginui3/Constants.qml | 26 ---- .../examples/loginui3/imports/loginui3/qmldir | 2 - .../examples/loginui3/loginui3.qml | 61 ---------- .../examples/loginui3/loginui3.qmlproject | 47 -------- .../examples/loginui3/qtquickcontrols2.conf | 2 - .../examples/loginui4/Loginui4.qmlproject | 75 ++++++++++++ .../loginui4/{ => content}/Screen01.ui.qml | 114 +++++------------- .../loginui4/imports/loginui4/Constants.qml | 26 ---- .../examples/loginui4/imports/loginui4/qmldir | 2 - .../examples/loginui4/loginui4.qmlproject | 47 -------- .../examples/loginui4/qtquickcontrols2.conf | 2 - 41 files changed, 636 insertions(+), 636 deletions(-) rename doc/qtdesignstudio/examples/loginui1/{ => content}/EntryField.ui.qml (93%) rename doc/qtdesignstudio/examples/loginui1/{ => content}/PushButton.ui.qml (88%) rename doc/qtdesignstudio/examples/loginui1/{ => content}/Screen01.ui.qml (89%) rename doc/qtdesignstudio/examples/loginui1/{ => content}/images/adventurePage.jpg (100%) create mode 100644 doc/qtdesignstudio/examples/loginui1/content/images/qt_logo_green_128x128px.png delete mode 100644 doc/qtdesignstudio/examples/loginui1/images/qt_logo_green_128x128px.png create mode 100644 doc/qtdesignstudio/examples/loginui1/imports/loginui1/EventListModel.qml create mode 100644 doc/qtdesignstudio/examples/loginui1/imports/loginui1/EventListSimulator.qml delete mode 100644 doc/qtdesignstudio/examples/loginui1/loginui1.qml delete mode 100644 doc/qtdesignstudio/examples/loginui1/qtquickcontrols2.conf rename doc/qtdesignstudio/examples/{loginui4/loginui4.qml => loginui1/src/app_environment.h} (85%) create mode 100644 doc/qtdesignstudio/examples/loginui1/src/import_qml_plugins.h create mode 100644 doc/qtdesignstudio/examples/loginui1/src/main.cpp create mode 100644 doc/qtdesignstudio/examples/loginui2/Loginui2.qmlproject rename doc/qtdesignstudio/examples/loginui2/{ => content}/Screen01.ui.qml (92%) delete mode 100644 doc/qtdesignstudio/examples/loginui2/imports/loginui2/Constants.qml delete mode 100644 doc/qtdesignstudio/examples/loginui2/imports/loginui2/qmldir delete mode 100644 doc/qtdesignstudio/examples/loginui2/loginui2.qml delete mode 100644 doc/qtdesignstudio/examples/loginui2/loginui2.qmlproject delete mode 100644 doc/qtdesignstudio/examples/loginui2/qtquickcontrols2.conf create mode 100644 doc/qtdesignstudio/examples/loginui3/Loginui3.qmlproject rename doc/qtdesignstudio/examples/loginui3/{ => content}/Screen01.ui.qml (93%) delete mode 100644 doc/qtdesignstudio/examples/loginui3/imports/loginui3/Constants.qml delete mode 100644 doc/qtdesignstudio/examples/loginui3/imports/loginui3/qmldir delete mode 100644 doc/qtdesignstudio/examples/loginui3/loginui3.qml delete mode 100644 doc/qtdesignstudio/examples/loginui3/loginui3.qmlproject delete mode 100644 doc/qtdesignstudio/examples/loginui3/qtquickcontrols2.conf create mode 100644 doc/qtdesignstudio/examples/loginui4/Loginui4.qmlproject rename doc/qtdesignstudio/examples/loginui4/{ => content}/Screen01.ui.qml (53%) delete mode 100644 doc/qtdesignstudio/examples/loginui4/imports/loginui4/Constants.qml delete mode 100644 doc/qtdesignstudio/examples/loginui4/imports/loginui4/qmldir delete mode 100644 doc/qtdesignstudio/examples/loginui4/loginui4.qmlproject delete mode 100644 doc/qtdesignstudio/examples/loginui4/qtquickcontrols2.conf diff --git a/doc/qtdesignstudio/examples/doc/images/loginui1-project-files.png b/doc/qtdesignstudio/examples/doc/images/loginui1-project-files.png index 47ff9b4303234c50cc49d69d6249b558bbf925b7..7b7edd8fe1b2165fdb3f60168b7e127c3e91d42a 100644 GIT binary patch literal 14664 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 Q1_lNOPgg&ebxsLQ0GCteR{#J2 diff --git a/doc/qtdesignstudio/examples/doc/images/loginui3-visibility.png b/doc/qtdesignstudio/examples/doc/images/loginui3-visibility.png index 48bedc6a485146db3d57d906fe81366d7628211c..d43dbb61075d5192f9ebadb1443c207ec200f3ae 100644 GIT binary patch delta 4003 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 literal 5281 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 \uicontrol {New Project} > - \uicontrol General > \uicontrol {Qt Quick Application - Empty} > - \uicontrol Choose. - \li In the \uicontrol Name field, enter the project name: \e {loginui1}. - When naming your own projects, keep in mind that they cannot be - easily renamed later. - \li In the \uicontrol {Create in} field, enter the path to the folder - where you want to store the project files. You can move project - folders later without problems. - \li Select \uicontrol Next (or \uicontrol Continue on \macos) to - continue to the \uicontrol {Define Project Details} page. - \li In the \uicontrol {Screen resolution} field, select the initial - size of the UI. In this tutorial, we use the predefined size - \e {720 x 1280 (HD)} (portrait) instead of the default size - (landscape). You can easily change the screen size later in - \l Properties. - \li Select \uicontrol Finish (or \uicontrol Done on \macos) to create - the project. + \li Select \uicontrol File > \uicontrol {New Project}. + \li In the \uicontrol Presets tab, select \uicontrol General > + \uicontrol {Empty}. + \li In the \uicontrol Details tab: + \list + \li Enter \e Loginui1 as the name for the project. Keep in mind + that projects cannot be easily renamed later. + \li Select the path for the project files. You can move project + folders later. + \li Set \uicontrol Width to 720 and \uicontrol Height to 1280. + You can change the screen size later in \l Properties. + \endlist + \li Select \uicontrol Create to create the project. \endlist Your project should now look something like this in the \uicontrol Design @@ -92,7 +90,7 @@ \section2 Learn More - Projects and Files \QDS creates a set of boilerplate files and folders that you need to create - a UI. The files are listed in the \l Projects view. + a UI. The files are listed in the \l{File System} view. \image loginui1-project-files.png @@ -112,6 +110,9 @@ Specifically, if you export and import designs using \QB, your main file is most likely called something else. For more information, see \l {Exporting from Design Tools}. + \li The \e CMakeLists.txt project configuration file allowing you to + share your project as a fully working C++ application with + developers. \li The \e {qtquickcontrols2.conf} file specifies the selected \l {Styling Qt Quick Controls}{UI style} and some style-specific arguments. @@ -230,7 +231,7 @@ adds the following \e import statements to the UI files (.ui.qml) that it creates: - \quotefromfile loginui1/Screen01.ui.qml + \quotefromfile Loginui1/Content/Screen01.ui.qml \skipto import \printuntil Controls @@ -333,7 +334,7 @@ To be able to use the functionality of the Button control, the wizard template adds the following \e import statements to the \e EntryField.ui.qml file: - \quotefromfile loginui1/EntryField.ui.qml + \quotefromfile Loginui1/Content/EntryField.ui.qml \skipto import \printuntil Controls @@ -364,7 +365,7 @@ to \e 100, to match the width of the tag line. \li In the \uicontrol Control section, deselect the \uicontrol Hover check box because we don't want the hover effect for the button. - \li Select the button background in \uicontrol Navigator to display its + \li Select \e buttonBackground in \uicontrol Navigator to display its properties in \uicontrol Properties. \li In \uicontrol Rectangle > \uicontrol {Fill color}, set the color to transparent light gray (\e #28e7e7e7) in \uicontrol Hex. You can @@ -372,7 +373,7 @@ \li In \uicontrol {Border Color}, select white (\e #ffffff). \li In \uicontrol Radius, enter \e 50 to give the button rounded corners. - \li Select the text component in \uicontrol Navigator to display its + \li Select \e textItem in \uicontrol Navigator to display its properties in \uicontrol Properties. \li In \uicontrol Character > \uicontrol Font, select \e {Titillium Web ExtraLight}. @@ -382,7 +383,7 @@ (\e #ffffff). \li In \uicontrol {Alignment H}, select the \uicontrol Left button to align the text horizontally to the left. - \li In the \uicontrol Padding section > \uicontrol Horizontal > + \li In \uicontrol Padding > \uicontrol Horizontal > \uicontrol Left, set the padding in the field between background border and text to \e 50. \image loginui1-text-properties-button.png "Text properties" @@ -450,13 +451,13 @@ to \e 100. \li In the \uicontrol Control section, deselect the \uicontrol Hover check box because we don't want the hover effect for the button. - \li Select the button background in \uicontrol Navigator to display its + \li Select \e buttonBackground in \uicontrol Navigator to display its properties in \uicontrol Properties. \li In \uicontrol Rectangle > \uicontrol {Border color}, select the green used in the logo (\e #41cd52). \li In \uicontrol Radius, enter \e 50 to give the button rounded corners. - \li Select the the text component in \uicontrol Navigator to display + \li Select \e textItem in \uicontrol Navigator to display its properties in \uicontrol Properties. \li In \uicontrol Character > \uicontrol Font, select \e {Titillium Web ExtraLight}. diff --git a/doc/qtdesignstudio/examples/doc/loginui2.qdoc b/doc/qtdesignstudio/examples/doc/loginui2.qdoc index bcf557825d7..c2ca170552e 100644 --- a/doc/qtdesignstudio/examples/doc/loginui2.qdoc +++ b/doc/qtdesignstudio/examples/doc/loginui2.qdoc @@ -24,7 +24,7 @@ ****************************************************************************/ /*! - \example loginui2 + \example Loginui2 \ingroup gstutorials \previouspage {Log In UI - Components} \nextpage {Log In UI - States} @@ -45,7 +45,12 @@ their proper places when you resize the UI on the desktop or on devices with different screen sizes, you will use anchors and positioners. - These instructions build on \l {Log In UI - Components}. + The starting point for this tutorial is the completed + \l{Log In UI - Components} project. You can download the project from + \l{https://git.qt.io/public-demos/qtdesign-studio/-/tree/master/tutorial%20projects/Loginui1}{here}. + + Additionally, you can download the completed project of this tutorial from + \l{https://git.qt.io/public-demos/qtdesign-studio/-/tree/master/tutorial%20projects/Loginui2}{here}. The \e {Learn More} sections provide additional information about the task at hand. @@ -79,6 +84,9 @@ anchor button to anchor \e adventurePage to its parent in the \uicontrol Target field. This attaches the background image to the rectangle on all sides. + Note: Selecting the anchor button should automatically select the + four buttons on the left side of it. If it doesn't, refresh + \uicontrol{Form Editor}. \image loginui2-layout.png "Layout properties" \li Select \e qt_logo_green_128x128px in \l Navigator. \li In \uicontrol Properties > \uicontrol Layout, select the diff --git a/doc/qtdesignstudio/examples/doc/loginui3.qdoc b/doc/qtdesignstudio/examples/doc/loginui3.qdoc index 34730dfc425..999215d90b1 100644 --- a/doc/qtdesignstudio/examples/doc/loginui3.qdoc +++ b/doc/qtdesignstudio/examples/doc/loginui3.qdoc @@ -46,12 +46,12 @@ login page, you will use \e states to show and hide UI components as necessary when a user selects the \e {Create Account} button. - These instructions build on: + The starting point for this tutorial is the completed + \l{Log In UI - Positioning} project. You can download the project from + \l{https://git.qt.io/public-demos/qtdesign-studio/-/tree/master/tutorial%20projects/Loginui2}{here}. - \list - \li \l {Log In UI - Components} - \li \l {Log In UI - Positioning} - \endlist + Additionally, you can download the completed project of this tutorial from + \l{https://git.qt.io/public-demos/qtdesign-studio/-/tree/master/tutorial%20projects/Loginui3}{here}. The \e {Learn More} sections provide additional information relevant to the task at hand. diff --git a/doc/qtdesignstudio/examples/doc/loginui4.qdoc b/doc/qtdesignstudio/examples/doc/loginui4.qdoc index a601d8aa8ec..a6a1ad77d4a 100644 --- a/doc/qtdesignstudio/examples/doc/loginui4.qdoc +++ b/doc/qtdesignstudio/examples/doc/loginui4.qdoc @@ -46,13 +46,13 @@ \l{Creating Timeline Animations}{timeline animations} that you bind to states. - These instructions build on: + The starting point for this tutorial is the completed + \l{Log In UI - States} project. You can download the project from + \l{https://git.qt.io/public-demos/qtdesign-studio/-/tree/master/tutorial%20projects/Loginui3}{here}. + + Additionally, you can download the completed project of this tutorial from + \l{https://git.qt.io/public-demos/qtdesign-studio/-/tree/master/tutorial%20projects/Loginui4}{here}. - \list - \li \l {Log In UI - Components} - \li \l {Log In UI - Positioning} - \li \l {Log In UI - States} - \endlist The \e {Learn More} sections provide additional information relevant to the task at hand. @@ -94,7 +94,7 @@ \li Select \inlineimage icons/navigator-arrowup.png to move \e username below \e tagLine in \uicontrol Navigator to preserve the \l{Arranging Components}{component hierarchy}. - \li Repeat for \e password and \e repeatPassword. + \li Repeat step 3 and 4 for \e password and \e repeatPassword. \li Select \e fields in \uicontrol Navigator and press \key Delete to delete it. \li Select \e username in \uicontrol Navigator to display its properties @@ -196,8 +196,8 @@ to save your changes. \endlist - When you move the playhead along the timeline, you can see how the login - button fades out while the repeat password field fades in. + When you move the playhead along the timeline, you can see how the create + account button fades out while the repeat password field fades in. You will now animate the top anchor margin of the repeat password field to make it appear to slide down from the password field. @@ -219,7 +219,7 @@ frame 0, and select the record button for the \e anchors.topMargin property of \e repeatPassword. \li In the field next to the property, set a negative value for the - top anchor margin, -40, to place \e repeatPassword on top of + top anchor margin, -100, to place \e repeatPassword on top of \e password. \li Move the playhead to frame 1000 and change the top anchor margin to 20, so that, combined with the change in the \uicontrol Opacity @@ -312,7 +312,7 @@ the following \e import statement to the UI files where it uses the components: - \quotefromfile loginui4/Screen01.ui.qml + \quotefromfile Loginui4/Content/Screen01.ui.qml \skipto QtQuick.Timeline \printuntil 1.0 diff --git a/doc/qtdesignstudio/examples/loginui1/EntryField.ui.qml b/doc/qtdesignstudio/examples/loginui1/content/EntryField.ui.qml similarity index 93% rename from doc/qtdesignstudio/examples/loginui1/EntryField.ui.qml rename to doc/qtdesignstudio/examples/loginui1/content/EntryField.ui.qml index 4232d16445b..02b4ce8d183 100644 --- a/doc/qtdesignstudio/examples/loginui1/EntryField.ui.qml +++ b/doc/qtdesignstudio/examples/loginui1/content/EntryField.ui.qml @@ -1,8 +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 the examples of the Qt Design Studio. @@ -49,6 +47,7 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ + import QtQuick 2.15 import QtQuick.Controls 2.12 @@ -100,13 +99,16 @@ Button { when: !control.down PropertyChanges { - target: textItem - font.family: "Titillium Web ExtraLight" + target: buttonBackground + color: "#00000000" + border.color: "#ffffff" } PropertyChanges { - target: buttonBackground - color: "#28e7e7e7" + target: textItem + color: "#ffffff" + font.pixelSize: 34 + font.family: "Titillium Web ExtraLight" } }, State { @@ -115,12 +117,14 @@ Button { PropertyChanges { target: textItem color: "#ffffff" + border.color: "#ffffff" + font.family: "Titillium Web ExtraLight" } PropertyChanges { target: buttonBackground - color: "#e7e7e7" - border.color: "#ffffff" + color: "#28e7e7e7" + border.color: "#00000000" } } ] diff --git a/doc/qtdesignstudio/examples/loginui1/PushButton.ui.qml b/doc/qtdesignstudio/examples/loginui1/content/PushButton.ui.qml similarity index 88% rename from doc/qtdesignstudio/examples/loginui1/PushButton.ui.qml rename to doc/qtdesignstudio/examples/loginui1/content/PushButton.ui.qml index 3a0871f4fc8..cfd617703c8 100644 --- a/doc/qtdesignstudio/examples/loginui1/PushButton.ui.qml +++ b/doc/qtdesignstudio/examples/loginui1/content/PushButton.ui.qml @@ -1,8 +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 the examples of the Qt Design Studio. @@ -49,6 +47,7 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ + import QtQuick 2.15 import QtQuick.Controls 2.12 @@ -68,6 +67,7 @@ Button { text: "My Button" hoverEnabled: false + enabled: true background: buttonBackground Rectangle { @@ -83,6 +83,8 @@ Button { contentItem: textItem Text { id: textItem + width: 500 + height: 100 text: control.text font.pixelSize: 34 @@ -101,6 +103,14 @@ Button { PropertyChanges { target: buttonBackground color: "#00000000" + border.color: "#41cd52" + } + + PropertyChanges { + target: textItem + color: "#41cd52" + font.pixelSize: 34 + font.family: "Titillium Web ExtraLight" } }, State { @@ -108,20 +118,17 @@ Button { when: control.down PropertyChanges { target: textItem - color: "#ffffff" + color: "#41cd52" + border.color: "#41cd52" + font.pixelSize: 34 + font.family: "Titillium Web ExtraLight" } PropertyChanges { target: buttonBackground color: "#41cd52" - border.color: "#00000000" + border.color: "#41cd52" } } ] } - -/*##^## -Designer { - D{i:0;height:100;width:500} -} -##^##*/ diff --git a/doc/qtdesignstudio/examples/loginui1/Screen01.ui.qml b/doc/qtdesignstudio/examples/loginui1/content/Screen01.ui.qml similarity index 89% rename from doc/qtdesignstudio/examples/loginui1/Screen01.ui.qml rename to doc/qtdesignstudio/examples/loginui1/content/Screen01.ui.qml index 9fbbf7fb090..de16a1ba014 100644 --- a/doc/qtdesignstudio/examples/loginui1/Screen01.ui.qml +++ b/doc/qtdesignstudio/examples/loginui1/content/Screen01.ui.qml @@ -1,8 +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 the examples of the Qt Design Studio. @@ -49,9 +47,10 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ + import QtQuick import QtQuick.Controls -import loginui1 1.0 +import Loginui1 Rectangle { width: Constants.width @@ -70,47 +69,44 @@ Rectangle { Image { id: qt_logo_green_128x128px x: 296 - y: 40 + y: 0 source: "images/qt_logo_green_128x128px.png" fillMode: Image.PreserveAspectFit } Text { - id: tagLine - width: 541 - height: 78 color: "#ffffff" text: qsTr("Are you ready to explore?") font.pixelSize: 50 font.family: "Titillium Web ExtraLight" - anchors.verticalCenterOffset: -391 - anchors.horizontalCenterOffset: 18 + anchors.verticalCenterOffset: -430 + anchors.horizontalCenterOffset: 0 anchors.centerIn: parent } EntryField { id: username - x: 128 + x: 110 y: 470 - text: "Username or Email" + text: qsTr("Username or Email") } EntryField { id: password - x: 128 + x: 110 y: 590 text: qsTr("Password") } PushButton { id: login - x: 102 - y: 966 + x: 101 + y: 944 text: qsTr("Continue") } PushButton { - id: createAccount - x: 102 + id: creteAccount + x: 101 y: 1088 text: qsTr("Create Account") } @@ -118,7 +114,7 @@ Rectangle { /*##^## Designer { - D{i:0;formeditorZoom:0.33} + D{i:0;formeditorZoom:0.5}D{i:1}D{i:2}D{i:3}D{i:4}D{i:5}D{i:6}D{i:7} } ##^##*/ diff --git a/doc/qtdesignstudio/examples/loginui1/images/adventurePage.jpg b/doc/qtdesignstudio/examples/loginui1/content/images/adventurePage.jpg similarity index 100% rename from doc/qtdesignstudio/examples/loginui1/images/adventurePage.jpg rename to doc/qtdesignstudio/examples/loginui1/content/images/adventurePage.jpg diff --git a/doc/qtdesignstudio/examples/loginui1/content/images/qt_logo_green_128x128px.png b/doc/qtdesignstudio/examples/loginui1/content/images/qt_logo_green_128x128px.png new file mode 100644 index 0000000000000000000000000000000000000000..2f3c7550774d2f13b980232cb5dfd5391e031e2f GIT binary patch literal 1800 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 +void set_qt_environment() +{ + qputenv("QT_AUTO_SCREEN_SCALE_FACTOR", "1"); + qputenv("QT_ENABLE_HIGHDPI_SCALING", "0"); + qputenv("QT_LOGGING_RULES", "qt.qml.connections=false"); + qputenv("QT_QUICK_CONTROLS_CONF", ":/qtquickcontrols2.conf"); } diff --git a/doc/qtdesignstudio/examples/loginui1/src/import_qml_plugins.h b/doc/qtdesignstudio/examples/loginui1/src/import_qml_plugins.h new file mode 100644 index 00000000000..18e0e769915 --- /dev/null +++ b/doc/qtdesignstudio/examples/loginui1/src/import_qml_plugins.h @@ -0,0 +1,9 @@ +/* + * This file is automatically generated by Qt Design Studio. + * Do not change. +*/ + +#include + +Q_IMPORT_QML_PLUGIN(contentPlugin) +Q_IMPORT_QML_PLUGIN(Loginui1Plugin) diff --git a/doc/qtdesignstudio/examples/loginui1/src/main.cpp b/doc/qtdesignstudio/examples/loginui1/src/main.cpp new file mode 100644 index 00000000000..aaf18173a1a --- /dev/null +++ b/doc/qtdesignstudio/examples/loginui1/src/main.cpp @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Quick Studio Components. +** +** $QT_BEGIN_LICENSE:GPL$ +** 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 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** 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. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include "app_environment.h" +#include "import_qml_plugins.h" + +int main(int argc, char *argv[]) +{ + set_qt_environment(); + + QGuiApplication app(argc, argv); + + QQmlApplicationEngine engine; + const QUrl url(u"qrc:Main/main.qml"_qs); + QObject::connect( + &engine, &QQmlApplicationEngine::objectCreated, &app, + [url](QObject *obj, const QUrl &objUrl) { + if (!obj && url == objUrl) + QCoreApplication::exit(-1); + }, + Qt::QueuedConnection); + + engine.addImportPath(QCoreApplication::applicationDirPath() + "/qml"); + engine.addImportPath(":/"); + + engine.load(url); + + if (engine.rootObjects().isEmpty()) { + return -1; + } + + return app.exec(); +} diff --git a/doc/qtdesignstudio/examples/loginui2/Loginui2.qmlproject b/doc/qtdesignstudio/examples/loginui2/Loginui2.qmlproject new file mode 100644 index 00000000000..467ccd3c545 --- /dev/null +++ b/doc/qtdesignstudio/examples/loginui2/Loginui2.qmlproject @@ -0,0 +1,75 @@ +import QmlProject + +Project { + mainFile: "content/App.qml" + + /* Include .qml, .js, and image files from current directory and subdirectories */ + QmlFiles { + directory: "content" + } + + JavaScriptFiles { + directory: "content" + } + + ImageFiles { + directory: "content" + } + + Files { + filter: "*.conf" + files: ["qtquickcontrols2.conf"] + } + + Files { + filter: "qmldir" + directory: "." + } + + Files { + filter: "*.ttf;*.otf" + } + + Files { + filter: "*.wav;*.mp3" + } + + Files { + filter: "*.mp4" + } + + Files { + filter: "*.glsl;*.glslv;*.glslf;*.vsh;*.fsh;*.vert;*.frag" + } + + Files { + filter: "*.mesh" + directory: "asset_imports" + } + + Environment { + QT_QUICK_CONTROLS_CONF: "qtquickcontrols2.conf" + QT_AUTO_SCREEN_SCALE_FACTOR: "1" + QT_LOGGING_RULES: "qt.qml.connections=false" + QT_ENABLE_HIGHDPI_SCALING: "0" + /* Useful for debugging + QSG_VISUALIZE=batches + QSG_VISUALIZE=clip + QSG_VISUALIZE=changes + QSG_VISUALIZE=overdraw + */ + } + + qt6Project: true + + /* List of plugin directories passed to QML runtime */ + importPaths: [ "imports", "asset_imports" ] + + /* Required for deployment */ + targetDirectory: "/opt/Loginui1" + + qdsVersion: "3.0" + + /* If any modules the project imports require widgets (e.g. QtCharts), widgetApp must be true */ + widgetApp: true +} diff --git a/doc/qtdesignstudio/examples/loginui2/Screen01.ui.qml b/doc/qtdesignstudio/examples/loginui2/content/Screen01.ui.qml similarity index 92% rename from doc/qtdesignstudio/examples/loginui2/Screen01.ui.qml rename to doc/qtdesignstudio/examples/loginui2/content/Screen01.ui.qml index 6466b19bd06..c806c43034a 100644 --- a/doc/qtdesignstudio/examples/loginui2/Screen01.ui.qml +++ b/doc/qtdesignstudio/examples/loginui2/content/Screen01.ui.qml @@ -1,8 +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 the examples of the Qt Design Studio. @@ -49,9 +47,10 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ + import QtQuick import QtQuick.Controls -import loginui2 1.0 +import Loginui1 Rectangle { id: rectangle @@ -69,7 +68,6 @@ Rectangle { Image { id: qt_logo_green_128x128px - x: 296 anchors.top: parent.top source: "images/qt_logo_green_128x128px.png" anchors.horizontalCenter: parent.horizontalCenter @@ -78,8 +76,6 @@ Rectangle { } Text { id: tagLine - width: 541 - height: 78 color: "#ffffff" text: qsTr("Are you ready to explore?") anchors.top: qt_logo_green_128x128px.bottom @@ -87,11 +83,11 @@ Rectangle { anchors.topMargin: 40 anchors.horizontalCenter: parent.horizontalCenter font.family: "Titillium Web ExtraLight" + anchors.horizontalCenterOffset: 0 } Column { id: fields - x: 128 anchors.top: tagLine.bottom anchors.horizontalCenter: parent.horizontalCenter anchors.topMargin: 170 @@ -99,7 +95,7 @@ Rectangle { EntryField { id: username - text: "Username or Email" + text: qsTr("Username or Email") } EntryField { @@ -110,11 +106,10 @@ Rectangle { Column { id: buttons - x: 102 - y: 966 + y: 944 anchors.bottom: parent.bottom anchors.horizontalCenter: parent.horizontalCenter - anchors.bottomMargin: 100 + anchors.bottomMargin: 50 spacing: 20 PushButton { @@ -123,7 +118,7 @@ Rectangle { } PushButton { - id: createAccount + id: creteAccount text: qsTr("Create Account") } } @@ -131,7 +126,7 @@ Rectangle { /*##^## Designer { - D{i:0;formeditorZoom:0.5}D{i:1}D{i:2}D{i:4} + D{i:0;formeditorZoom:0.66}D{i:1}D{i:2}D{i:3}D{i:5}D{i:6}D{i:4}D{i:8}D{i:9}D{i:7} } ##^##*/ diff --git a/doc/qtdesignstudio/examples/loginui2/imports/loginui2/Constants.qml b/doc/qtdesignstudio/examples/loginui2/imports/loginui2/Constants.qml deleted file mode 100644 index 6fef815fa14..00000000000 --- a/doc/qtdesignstudio/examples/loginui2/imports/loginui2/Constants.qml +++ /dev/null @@ -1,26 +0,0 @@ -pragma Singleton -import QtQuick - -QtObject { - readonly property int width: 720 - readonly property int height: 1280 - - property alias fontDirectory: directoryFontLoader.fontDirectory - property alias relativeFontDirectory: directoryFontLoader.relativeFontDirectory - - /* Edit this comment to add your custom font */ - readonly property font font: Qt.font({ - family: Qt.application.font.family, - pixelSize: Qt.application.font.pixelSize - }) - readonly property font largeFont: Qt.font({ - family: Qt.application.font.family, - pixelSize: Qt.application.font.pixelSize * 1.6 - }) - - readonly property color backgroundColor: "#c2c2c2" - - property DirectoryFontLoader directoryFontLoader: DirectoryFontLoader { - id: directoryFontLoader - } -} diff --git a/doc/qtdesignstudio/examples/loginui2/imports/loginui2/qmldir b/doc/qtdesignstudio/examples/loginui2/imports/loginui2/qmldir deleted file mode 100644 index 69846237302..00000000000 --- a/doc/qtdesignstudio/examples/loginui2/imports/loginui2/qmldir +++ /dev/null @@ -1,2 +0,0 @@ -singleton Constants 1.0 Constants.qml -EventListSimulator 1.0 EventListSimulator.qml diff --git a/doc/qtdesignstudio/examples/loginui2/loginui2.qml b/doc/qtdesignstudio/examples/loginui2/loginui2.qml deleted file mode 100644 index 127e947a1c5..00000000000 --- a/doc/qtdesignstudio/examples/loginui2/loginui2.qml +++ /dev/null @@ -1,61 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the examples of the Qt Design Studio. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick -import loginui2 1.0 - -Item { - width: Constants.width - height: Constants.height - - Screen01 { - } - -} diff --git a/doc/qtdesignstudio/examples/loginui2/loginui2.qmlproject b/doc/qtdesignstudio/examples/loginui2/loginui2.qmlproject deleted file mode 100644 index 7d9e775731f..00000000000 --- a/doc/qtdesignstudio/examples/loginui2/loginui2.qmlproject +++ /dev/null @@ -1,47 +0,0 @@ -/* File generated by Qt Creator */ - -import QmlProject 1.1 - -Project { - mainFile: "loginui2.qml" - - /* Include .qml, .js, and image files from current directory and subdirectories */ - QmlFiles { - directory: "." - } - - JavaScriptFiles { - directory: "." - } - - ImageFiles { - directory: "." - } - - Files { - filter: "*.conf" - files: ["qtquickcontrols2.conf"] - } - - Files { - filter: "qmldir" - directory: "." - } - - Files { - filter: "*.ttf;*.otf" - } - - Environment { - QT_QUICK_CONTROLS_CONF: "qtquickcontrols2.conf" - QT_AUTO_SCREEN_SCALE_FACTOR: "1" - } - - qt6Project: true - - /* List of plugin directories passed to QML runtime */ - importPaths: [ "imports", "asset_imports" ] - - /* Required for deployment */ - targetDirectory: "/opt/loginui1" -} diff --git a/doc/qtdesignstudio/examples/loginui2/qtquickcontrols2.conf b/doc/qtdesignstudio/examples/loginui2/qtquickcontrols2.conf deleted file mode 100644 index 75b2cb8fffb..00000000000 --- a/doc/qtdesignstudio/examples/loginui2/qtquickcontrols2.conf +++ /dev/null @@ -1,6 +0,0 @@ -; This file can be edited to change the style of the application -; Read "Qt Quick Controls 2 Configuration File" for details: -; http://doc.qt.io/qt-5/qtquickcontrols2-configuration.html - -[Controls] -Style=Default diff --git a/doc/qtdesignstudio/examples/loginui3/Loginui3.qmlproject b/doc/qtdesignstudio/examples/loginui3/Loginui3.qmlproject new file mode 100644 index 00000000000..467ccd3c545 --- /dev/null +++ b/doc/qtdesignstudio/examples/loginui3/Loginui3.qmlproject @@ -0,0 +1,75 @@ +import QmlProject + +Project { + mainFile: "content/App.qml" + + /* Include .qml, .js, and image files from current directory and subdirectories */ + QmlFiles { + directory: "content" + } + + JavaScriptFiles { + directory: "content" + } + + ImageFiles { + directory: "content" + } + + Files { + filter: "*.conf" + files: ["qtquickcontrols2.conf"] + } + + Files { + filter: "qmldir" + directory: "." + } + + Files { + filter: "*.ttf;*.otf" + } + + Files { + filter: "*.wav;*.mp3" + } + + Files { + filter: "*.mp4" + } + + Files { + filter: "*.glsl;*.glslv;*.glslf;*.vsh;*.fsh;*.vert;*.frag" + } + + Files { + filter: "*.mesh" + directory: "asset_imports" + } + + Environment { + QT_QUICK_CONTROLS_CONF: "qtquickcontrols2.conf" + QT_AUTO_SCREEN_SCALE_FACTOR: "1" + QT_LOGGING_RULES: "qt.qml.connections=false" + QT_ENABLE_HIGHDPI_SCALING: "0" + /* Useful for debugging + QSG_VISUALIZE=batches + QSG_VISUALIZE=clip + QSG_VISUALIZE=changes + QSG_VISUALIZE=overdraw + */ + } + + qt6Project: true + + /* List of plugin directories passed to QML runtime */ + importPaths: [ "imports", "asset_imports" ] + + /* Required for deployment */ + targetDirectory: "/opt/Loginui1" + + qdsVersion: "3.0" + + /* If any modules the project imports require widgets (e.g. QtCharts), widgetApp must be true */ + widgetApp: true +} diff --git a/doc/qtdesignstudio/examples/loginui3/Screen01.ui.qml b/doc/qtdesignstudio/examples/loginui3/content/Screen01.ui.qml similarity index 93% rename from doc/qtdesignstudio/examples/loginui3/Screen01.ui.qml rename to doc/qtdesignstudio/examples/loginui3/content/Screen01.ui.qml index 28131577351..55bf71619d7 100644 --- a/doc/qtdesignstudio/examples/loginui3/Screen01.ui.qml +++ b/doc/qtdesignstudio/examples/loginui3/content/Screen01.ui.qml @@ -1,8 +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 the examples of the Qt Design Studio. @@ -49,9 +47,10 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ + import QtQuick import QtQuick.Controls -import loginui3 1.0 +import Loginui1 Rectangle { id: rectangle @@ -70,7 +69,6 @@ Rectangle { Image { id: qt_logo_green_128x128px - x: 296 anchors.top: parent.top source: "images/qt_logo_green_128x128px.png" anchors.horizontalCenter: parent.horizontalCenter @@ -79,8 +77,6 @@ Rectangle { } Text { id: tagLine - width: 541 - height: 78 color: "#ffffff" text: qsTr("Are you ready to explore?") anchors.top: qt_logo_green_128x128px.bottom @@ -88,11 +84,11 @@ Rectangle { anchors.topMargin: 40 anchors.horizontalCenter: parent.horizontalCenter font.family: "Titillium Web ExtraLight" + anchors.horizontalCenterOffset: 0 } Column { id: fields - x: 128 anchors.top: tagLine.bottom anchors.horizontalCenter: parent.horizontalCenter anchors.topMargin: 170 @@ -100,7 +96,7 @@ Rectangle { EntryField { id: username - text: "Username or Email" + text: qsTr("Username or Email") } EntryField { @@ -110,17 +106,16 @@ Rectangle { EntryField { id: repeatPassword - text: "Repeat Password" + text: qsTr("Repeat Password") } } Column { id: buttons - x: 102 - y: 966 + y: 944 anchors.bottom: parent.bottom anchors.horizontalCenter: parent.horizontalCenter - anchors.bottomMargin: 100 + anchors.bottomMargin: 50 spacing: 20 PushButton { @@ -160,7 +155,8 @@ Rectangle { /*##^## Designer { - D{i:0;formeditorZoom:0.5} + D{i:0;formeditorZoom:0.5}D{i:1}D{i:2}D{i:3}D{i:5}D{i:6}D{i:7}D{i:4}D{i:9}D{i:11}D{i:10} +D{i:8} } ##^##*/ diff --git a/doc/qtdesignstudio/examples/loginui3/imports/loginui3/Constants.qml b/doc/qtdesignstudio/examples/loginui3/imports/loginui3/Constants.qml deleted file mode 100644 index 6fef815fa14..00000000000 --- a/doc/qtdesignstudio/examples/loginui3/imports/loginui3/Constants.qml +++ /dev/null @@ -1,26 +0,0 @@ -pragma Singleton -import QtQuick - -QtObject { - readonly property int width: 720 - readonly property int height: 1280 - - property alias fontDirectory: directoryFontLoader.fontDirectory - property alias relativeFontDirectory: directoryFontLoader.relativeFontDirectory - - /* Edit this comment to add your custom font */ - readonly property font font: Qt.font({ - family: Qt.application.font.family, - pixelSize: Qt.application.font.pixelSize - }) - readonly property font largeFont: Qt.font({ - family: Qt.application.font.family, - pixelSize: Qt.application.font.pixelSize * 1.6 - }) - - readonly property color backgroundColor: "#c2c2c2" - - property DirectoryFontLoader directoryFontLoader: DirectoryFontLoader { - id: directoryFontLoader - } -} diff --git a/doc/qtdesignstudio/examples/loginui3/imports/loginui3/qmldir b/doc/qtdesignstudio/examples/loginui3/imports/loginui3/qmldir deleted file mode 100644 index 69846237302..00000000000 --- a/doc/qtdesignstudio/examples/loginui3/imports/loginui3/qmldir +++ /dev/null @@ -1,2 +0,0 @@ -singleton Constants 1.0 Constants.qml -EventListSimulator 1.0 EventListSimulator.qml diff --git a/doc/qtdesignstudio/examples/loginui3/loginui3.qml b/doc/qtdesignstudio/examples/loginui3/loginui3.qml deleted file mode 100644 index ea8b947d3ce..00000000000 --- a/doc/qtdesignstudio/examples/loginui3/loginui3.qml +++ /dev/null @@ -1,61 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the examples of the Qt Design Studio. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick -import loginui3 1.0 - -Item { - width: Constants.width - height: Constants.height - - Screen01 { - } - -} diff --git a/doc/qtdesignstudio/examples/loginui3/loginui3.qmlproject b/doc/qtdesignstudio/examples/loginui3/loginui3.qmlproject deleted file mode 100644 index 3015de6092e..00000000000 --- a/doc/qtdesignstudio/examples/loginui3/loginui3.qmlproject +++ /dev/null @@ -1,47 +0,0 @@ -/* File generated by Qt Creator */ - -import QmlProject 1.1 - -Project { - mainFile: "loginui3.qml" - - /* Include .qml, .js, and image files from current directory and subdirectories */ - QmlFiles { - directory: "." - } - - JavaScriptFiles { - directory: "." - } - - ImageFiles { - directory: "." - } - - Files { - filter: "*.conf" - files: ["qtquickcontrols2.conf"] - } - - Files { - filter: "qmldir" - directory: "." - } - - Files { - filter: "*.ttf;*.otf" - } - - Environment { - QT_QUICK_CONTROLS_CONF: "qtquickcontrols2.conf" - QT_AUTO_SCREEN_SCALE_FACTOR: "1" - } - - qt6Project: true - - /* List of plugin directories passed to QML runtime */ - importPaths: [ "imports", "asset_imports" ] - - /* Required for deployment */ - targetDirectory: "/opt/loginui1" -} diff --git a/doc/qtdesignstudio/examples/loginui3/qtquickcontrols2.conf b/doc/qtdesignstudio/examples/loginui3/qtquickcontrols2.conf deleted file mode 100644 index caace6db8e4..00000000000 --- a/doc/qtdesignstudio/examples/loginui3/qtquickcontrols2.conf +++ /dev/null @@ -1,2 +0,0 @@ -[Controls] -Style=Default diff --git a/doc/qtdesignstudio/examples/loginui4/Loginui4.qmlproject b/doc/qtdesignstudio/examples/loginui4/Loginui4.qmlproject new file mode 100644 index 00000000000..467ccd3c545 --- /dev/null +++ b/doc/qtdesignstudio/examples/loginui4/Loginui4.qmlproject @@ -0,0 +1,75 @@ +import QmlProject + +Project { + mainFile: "content/App.qml" + + /* Include .qml, .js, and image files from current directory and subdirectories */ + QmlFiles { + directory: "content" + } + + JavaScriptFiles { + directory: "content" + } + + ImageFiles { + directory: "content" + } + + Files { + filter: "*.conf" + files: ["qtquickcontrols2.conf"] + } + + Files { + filter: "qmldir" + directory: "." + } + + Files { + filter: "*.ttf;*.otf" + } + + Files { + filter: "*.wav;*.mp3" + } + + Files { + filter: "*.mp4" + } + + Files { + filter: "*.glsl;*.glslv;*.glslf;*.vsh;*.fsh;*.vert;*.frag" + } + + Files { + filter: "*.mesh" + directory: "asset_imports" + } + + Environment { + QT_QUICK_CONTROLS_CONF: "qtquickcontrols2.conf" + QT_AUTO_SCREEN_SCALE_FACTOR: "1" + QT_LOGGING_RULES: "qt.qml.connections=false" + QT_ENABLE_HIGHDPI_SCALING: "0" + /* Useful for debugging + QSG_VISUALIZE=batches + QSG_VISUALIZE=clip + QSG_VISUALIZE=changes + QSG_VISUALIZE=overdraw + */ + } + + qt6Project: true + + /* List of plugin directories passed to QML runtime */ + importPaths: [ "imports", "asset_imports" ] + + /* Required for deployment */ + targetDirectory: "/opt/Loginui1" + + qdsVersion: "3.0" + + /* If any modules the project imports require widgets (e.g. QtCharts), widgetApp must be true */ + widgetApp: true +} diff --git a/doc/qtdesignstudio/examples/loginui4/Screen01.ui.qml b/doc/qtdesignstudio/examples/loginui4/content/Screen01.ui.qml similarity index 53% rename from doc/qtdesignstudio/examples/loginui4/Screen01.ui.qml rename to doc/qtdesignstudio/examples/loginui4/content/Screen01.ui.qml index e919f39d82e..fa8377b980f 100644 --- a/doc/qtdesignstudio/examples/loginui4/Screen01.ui.qml +++ b/doc/qtdesignstudio/examples/loginui4/content/Screen01.ui.qml @@ -1,57 +1,6 @@ - - -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the examples of the Qt Design Studio. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ import QtQuick import QtQuick.Controls -import loginui4 1.0 +import Loginui1 import QtQuick.Timeline 1.0 Rectangle { @@ -71,7 +20,6 @@ Rectangle { Image { id: qt_logo_green_128x128px - x: 296 anchors.top: parent.top source: "images/qt_logo_green_128x128px.png" anchors.horizontalCenter: parent.horizontalCenter @@ -80,8 +28,6 @@ Rectangle { } Text { id: tagLine - width: 541 - height: 78 color: "#ffffff" text: qsTr("Are you ready to explore?") anchors.top: qt_logo_green_128x128px.bottom @@ -89,30 +35,29 @@ Rectangle { anchors.topMargin: 40 anchors.horizontalCenter: parent.horizontalCenter font.family: "Titillium Web ExtraLight" + anchors.horizontalCenterOffset: 0 } EntryField { id: username - x: 110 - text: "Username or Email" + text: qsTr("Username or Email") anchors.top: tagLine.bottom - anchors.topMargin: 170 anchors.horizontalCenter: parent.horizontalCenter + anchors.topMargin: 170 } EntryField { id: password - x: 110 text: qsTr("Password") anchors.top: username.bottom anchors.horizontalCenter: parent.horizontalCenter - anchors.topMargin: 20 + anchors.topMargin: 21 } EntryField { id: repeatPassword - x: 110 - text: "Repeat Password" + opacity: 0 + text: qsTr("Repeat Password") anchors.top: password.bottom anchors.horizontalCenter: parent.horizontalCenter anchors.topMargin: 20 @@ -120,11 +65,10 @@ Rectangle { Column { id: buttons - x: 102 - y: 966 + y: 944 anchors.bottom: parent.bottom anchors.horizontalCenter: parent.horizontalCenter - anchors.bottomMargin: 100 + anchors.bottomMargin: 50 spacing: 20 PushButton { @@ -148,70 +92,68 @@ Rectangle { animations: [ TimelineAnimation { id: toCreateAccountState + duration: 1000 running: false loops: 1 - duration: 1000 to: 1000 from: 0 } ] endFrame: 1000 - startFrame: 0 enabled: true + startFrame: 0 KeyframeGroup { target: repeatPassword property: "opacity" - Keyframe { - frame: 0 value: 0 + frame: 0 } Keyframe { - frame: 999 value: 1 + frame: 1000 } } KeyframeGroup { target: createAccount property: "opacity" + Keyframe { + value: 1 + frame: 0 + } Keyframe { - frame: 1000 value: 0 + frame: 1000 } } KeyframeGroup { target: repeatPassword property: "anchors.topMargin" - Keyframe { + value: -100 frame: 0 - value: -40 } Keyframe { - easing.bezierCurve: [0.39,0.575,0.565,1,1,1] - frame: 999 + value: -100 + frame: 4 + } + + Keyframe { + easing.bezierCurve: [0.39, 0.575, 0.565, 1, 1, 1] value: 20 + frame: 999 } } } states: [ State { name: "login" - - PropertyChanges { - target: timeline - enabled: true - } - - PropertyChanges { - target: toCreateAccountState - } }, State { name: "createAccount" @@ -231,6 +173,8 @@ Rectangle { /*##^## Designer { - D{i:0;formeditorZoom:0.5}D{i:6}D{i:9}D{i:11} + D{i:0;formeditorZoom:0.5}D{i:1}D{i:2}D{i:3}D{i:4}D{i:5}D{i:6}D{i:8}D{i:10}D{i:9}D{i:7} +D{i:11} } ##^##*/ + diff --git a/doc/qtdesignstudio/examples/loginui4/imports/loginui4/Constants.qml b/doc/qtdesignstudio/examples/loginui4/imports/loginui4/Constants.qml deleted file mode 100644 index 6fef815fa14..00000000000 --- a/doc/qtdesignstudio/examples/loginui4/imports/loginui4/Constants.qml +++ /dev/null @@ -1,26 +0,0 @@ -pragma Singleton -import QtQuick - -QtObject { - readonly property int width: 720 - readonly property int height: 1280 - - property alias fontDirectory: directoryFontLoader.fontDirectory - property alias relativeFontDirectory: directoryFontLoader.relativeFontDirectory - - /* Edit this comment to add your custom font */ - readonly property font font: Qt.font({ - family: Qt.application.font.family, - pixelSize: Qt.application.font.pixelSize - }) - readonly property font largeFont: Qt.font({ - family: Qt.application.font.family, - pixelSize: Qt.application.font.pixelSize * 1.6 - }) - - readonly property color backgroundColor: "#c2c2c2" - - property DirectoryFontLoader directoryFontLoader: DirectoryFontLoader { - id: directoryFontLoader - } -} diff --git a/doc/qtdesignstudio/examples/loginui4/imports/loginui4/qmldir b/doc/qtdesignstudio/examples/loginui4/imports/loginui4/qmldir deleted file mode 100644 index 69846237302..00000000000 --- a/doc/qtdesignstudio/examples/loginui4/imports/loginui4/qmldir +++ /dev/null @@ -1,2 +0,0 @@ -singleton Constants 1.0 Constants.qml -EventListSimulator 1.0 EventListSimulator.qml diff --git a/doc/qtdesignstudio/examples/loginui4/loginui4.qmlproject b/doc/qtdesignstudio/examples/loginui4/loginui4.qmlproject deleted file mode 100644 index 9bb93ec5dd2..00000000000 --- a/doc/qtdesignstudio/examples/loginui4/loginui4.qmlproject +++ /dev/null @@ -1,47 +0,0 @@ -/* File generated by Qt Creator */ - -import QmlProject 1.1 - -Project { - mainFile: "loginui4.qml" - - /* Include .qml, .js, and image files from current directory and subdirectories */ - QmlFiles { - directory: "." - } - - JavaScriptFiles { - directory: "." - } - - ImageFiles { - directory: "." - } - - Files { - filter: "*.conf" - files: ["qtquickcontrols2.conf"] - } - - Files { - filter: "qmldir" - directory: "." - } - - Files { - filter: "*.ttf;*.otf" - } - - Environment { - QT_QUICK_CONTROLS_CONF: "qtquickcontrols2.conf" - QT_AUTO_SCREEN_SCALE_FACTOR: "1" - } - - qt6Project: true - - /* List of plugin directories passed to QML runtime */ - importPaths: [ "imports", "asset_imports" ] - - /* Required for deployment */ - targetDirectory: "/opt/loginui4" -} diff --git a/doc/qtdesignstudio/examples/loginui4/qtquickcontrols2.conf b/doc/qtdesignstudio/examples/loginui4/qtquickcontrols2.conf deleted file mode 100644 index caace6db8e4..00000000000 --- a/doc/qtdesignstudio/examples/loginui4/qtquickcontrols2.conf +++ /dev/null @@ -1,2 +0,0 @@ -[Controls] -Style=Default From 749a9b27ec1d107779f28ac69a0a11bb24ff9a21 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Fri, 28 Jan 2022 11:06:12 +0100 Subject: [PATCH 35/55] Doc: Describe Language Client Inspector Users can inspect the communication between Qt Creator and language servers and view server capabilities. Task-number: QTCREATORBUG-26929 Change-Id: I9ad4518eea030ba70dda2f0b956b319b3682af0f Reviewed-by: Reviewed-by: David Schulz --- ...language-client-inspector-capabilities.png | Bin 0 -> 21943 bytes ...tcreator-language-client-inspector-log.png | Bin 0 -> 24909 bytes ...language-client-inspector-memory-usage.png | Bin 0 -> 10726 bytes .../creator-only/creator-language-server.qdoc | 49 +++++++++++++++++- .../external-resources.qdoc | 6 ++- 5 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 doc/qtcreator/images/qtcreator-language-client-inspector-capabilities.png create mode 100644 doc/qtcreator/images/qtcreator-language-client-inspector-log.png create mode 100644 doc/qtcreator/images/qtcreator-language-client-inspector-memory-usage.png diff --git a/doc/qtcreator/images/qtcreator-language-client-inspector-capabilities.png b/doc/qtcreator/images/qtcreator-language-client-inspector-capabilities.png new file mode 100644 index 0000000000000000000000000000000000000000..e2e12e3624a555ae49618bc775e8542d3f907e70 GIT binary patch literal 21943 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

9|)NB{m9JR#6xRKa}ReHMe0~I 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 literal 0 HcmV?d00001 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..92ab52d28b9df0882369f9567278b00981e13bf0 GIT binary patch literal 10726 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 HoD!M \uicontrol {Debug \QC} > \uicontrol {Inspect Language Client}. + + \image qtcreator-language-client-inspector-log.png "Language Client Inspector dialog" + + The dialog shows a list of running language servers. The value of the + \uicontrol {Startup behavior} field in the language server options + determines when the server is started. The information displayed depends on + the language server. + + \uicontrol Log displays additional information about the selected log entry. + You can see the \uicontrol {Content length} and \uicontrol {MIME type} of + a \uicontrol {Client Message} and \uicontrol {Server Message}, as well as + inspect the data sent between \QC and the language server. + + To remove old entries, select \uicontrol Clear. + + \section2 Capabilities + + In \uicontrol Capabilities, you can check whether a language server is + capable of a specific task. You cannot modify the server capabilities + in this dialog. + + You can view the \uicontrol Name, \uicontrol Value, and \uicontrol Type + of the capability. + + \image qtcreator-language-client-inspector-capabilities.png "Language Client Inspector Capabilities tab" + + For some language servers, \uicontrol {Dynamic Capabilities} lists the + \uicontrol Methods and \uicontrol Options available. + + \section2 Memory Usage + + 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" + \section1 Reporting Issues The language service client has been mostly tested with Python and Java. diff --git a/doc/qtcreator/src/external-resources/external-resources.qdoc b/doc/qtcreator/src/external-resources/external-resources.qdoc index dc3f15c4863..4bc40bc9d67 100644 --- a/doc/qtcreator/src/external-resources/external-resources.qdoc +++ b/doc/qtcreator/src/external-resources/external-resources.qdoc @@ -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 the documentation of the Qt Toolkit. @@ -141,3 +141,7 @@ \externalpage https://cmake.org/cmake/help/latest/prop_sf/HEADER_FILE_ONLY.html \title CMake: HEADER_FILE_ONLY */ +/*! + \externalpage https://microsoft.github.io/language-server-protocol/ + \title Language Server Protocol +*/ From 4a228ab7647261cda70a0ae0e184bd009867d191 Mon Sep 17 00:00:00 2001 From: Assam Boudjelthia Date: Tue, 7 Dec 2021 11:58:02 +0200 Subject: [PATCH 36/55] Android: Update Default Ndk version, build-tools, platforms versions NDK r22b is used in Qt 6 and on 5.15.9 onward. Also update the build-tools and platforms to a more recent version. Change-Id: Ia9829def010047af528ce704f769a40910093fba Reviewed-by: Alessandro Portale Reviewed-by: --- share/qtcreator/android/sdk_definitions.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/share/qtcreator/android/sdk_definitions.json b/share/qtcreator/android/sdk_definitions.json index f1545c2ad69..56ac6b4f47d 100644 --- a/share/qtcreator/android/sdk_definitions.json +++ b/share/qtcreator/android/sdk_definitions.json @@ -9,7 +9,7 @@ "mac_sha256": "2c3822db1c916655223e5ee8ce0fbf6b73d0b99012045c9dc8eaa6a5736c0c55" }, "sdk_essential_packages": { - "default": ["platform-tools", "platforms;android-30", "cmdline-tools;latest"], + "default": ["platform-tools", "platforms;android-31", "cmdline-tools;latest"], "linux": [], "mac": [], "windows": ["extras;google;usb_driver"] @@ -18,7 +18,12 @@ "specific_qt_versions": [ { "versions": ["default"], - "sdk_essential_packages": ["build-tools;30.0.2", "ndk;21.3.6528147"], + "sdk_essential_packages": ["build-tools;31.0.0", "ndk;22.1.7171670"], + "ndk_path": "ndk/22.1.7171670" + }, + { + "versions": ["5.15.[0-8]", "5.14.[0-2]", "5.13.2"], + "sdk_essential_packages": ["build-tools;31.0.0", "ndk;21.3.6528147"], "ndk_path": "ndk/21.3.6528147" }, { From ccb44a310cafc50eaf0cf0ee6614c1f8532e2c03 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Tue, 1 Feb 2022 08:36:54 +0100 Subject: [PATCH 37/55] QmlDesigner: Fix compile on macOS Amends 25fa5540ea8. Change-Id: I2a71e79b6a5f41196d559724da78f98d0af7cdeb Reviewed-by: Reviewed-by: Christian Stenger --- .../components/itemlibrary/itemlibraryassetsmodel.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsmodel.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsmodel.cpp index be9b3b9f25c..a04ff0f48f4 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsmodel.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsmodel.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include From ef003ba769925bed14b07e2a3e174a6c1addfac6 Mon Sep 17 00:00:00 2001 From: Assam Boudjelthia Date: Sun, 30 Jan 2022 11:37:39 +0200 Subject: [PATCH 38/55] Android: Simplify SDK setup process by minimizing number of dialogs SDK setup process currently downloads the SDK tools, then checks the mandatory packages, asks the user if they want to install them, then show a dialog with package details, then asks again whether the user wants to check the licenses. The following two steps are redundant because there's a dialog which guards the package installation and waits for user's input: * Asking the user if they want to install the mandatory packages * Asking the user if they want to verify the licenses Change-Id: If06c0adea9444107a149c3ec32be67061954d1bb Reviewed-by: Alessandro Portale --- .../android/androidsdkmanagerwidget.cpp | 34 +++++++------------ src/plugins/android/androidsdkmanagerwidget.h | 4 +-- src/plugins/android/androidsettingswidget.cpp | 11 ++---- 3 files changed, 18 insertions(+), 31 deletions(-) diff --git a/src/plugins/android/androidsdkmanagerwidget.cpp b/src/plugins/android/androidsdkmanagerwidget.cpp index 6d330960f79..be93c03f609 100644 --- a/src/plugins/android/androidsdkmanagerwidget.cpp +++ b/src/plugins/android/androidsdkmanagerwidget.cpp @@ -137,7 +137,7 @@ AndroidSdkManagerWidget::AndroidSdkManagerWidget(AndroidConfig &config, }); connect(m_ui->applySelectionButton, &QPushButton::clicked, - this, &AndroidSdkManagerWidget::onApplyButton); + this, [this]() { onApplyButton(); }); connect(m_ui->cancelButton, &QPushButton::clicked, this, &AndroidSdkManagerWidget::onCancel); connect(m_ui->optionsButton, &QPushButton::clicked, @@ -204,7 +204,7 @@ AndroidSdkManagerWidget::~AndroidSdkManagerWidget() delete m_ui; } -void AndroidSdkManagerWidget::installEssentials() +void AndroidSdkManagerWidget::installEssentials(const QString &extraMessage) { m_sdkModel->selectMissingEssentials(); if (!m_sdkModel->missingEssentials().isEmpty()) { @@ -215,16 +215,19 @@ void AndroidSdkManagerWidget::installEssentials() .arg(Core::Constants::IDE_DISPLAY_NAME) .arg(m_sdkModel->missingEssentials().join("\", \""))); } - onApplyButton(); + onApplyButton(extraMessage); } void AndroidSdkManagerWidget::beginLicenseCheck() { m_formatter->appendMessage(tr("Checking pending licenses...\n"), Utils::NormalMessageFormat); + m_formatter->appendMessage(tr("The installation of Android SDK packages may fail if the " + "respective licenses are not accepted.\n"), + Utils::LogMessageFormat); addPackageFuture(m_sdkManager->checkPendingLicenses()); } -void AndroidSdkManagerWidget::onApplyButton() +void AndroidSdkManagerWidget::onApplyButton(const QString &extraMessage) { QTC_ASSERT(m_currentView == PackageListing, return); @@ -246,10 +249,11 @@ void AndroidSdkManagerWidget::onApplyButton() installPackages << str; } + QString message = tr("%n Android SDK packages shall be updated.", "", packagesToUpdate.count()); + if (!extraMessage.isEmpty()) + message.prepend(extraMessage + "\n\n"); QMessageBox messageDlg(QMessageBox::Information, tr("Android SDK Changes"), - tr("%n Android SDK packages shall be updated.", - "", packagesToUpdate.count()), - QMessageBox::Ok | QMessageBox::Cancel, this); + message, QMessageBox::Ok | QMessageBox::Cancel, this); QString details; if (!uninstallPackages.isEmpty()) @@ -317,20 +321,8 @@ void AndroidSdkManagerWidget::onLicenseCheckResult(const AndroidSdkManager::Oper // No assertion was found. Looks like all license are accepted. Go Ahead. runPendingCommand(); } else { - // Assertion was found. Provide user workflow to accept licenses. - QString warningMessage = tr("Review Android SDK package licenses that have not been " - "accepted?\nNote that the installation and use of " - "Android SDK packages may fail if respective licenses are not " - "accepted."); - int userSelection = QMessageBox::question(this, tr("Android SDK Licenses"), warningMessage, - QMessageBox::Yes | QMessageBox::No); - if (userSelection == QMessageBox::Yes) { - // Run license workflow. - beginLicenseWorkflow(); - } else { - // User decided to go ahead anyways. - runPendingCommand(); - } + // Run license workflow. + beginLicenseWorkflow(); } } diff --git a/src/plugins/android/androidsdkmanagerwidget.h b/src/plugins/android/androidsdkmanagerwidget.h index 58be2ce7af2..5266290b109 100644 --- a/src/plugins/android/androidsdkmanagerwidget.h +++ b/src/plugins/android/androidsdkmanagerwidget.h @@ -80,7 +80,7 @@ public: QWidget *parent = nullptr); ~AndroidSdkManagerWidget() override; - void installEssentials(); + void installEssentials(const QString &extraMessage = {}); signals: void updatingSdk(); @@ -88,7 +88,7 @@ signals: void licenseWorkflowStarted(); private: - void onApplyButton(); + void onApplyButton(const QString &extraMessage = {}); void onUpdatePackages(); void onCancel(); void onOperationResult(int index); diff --git a/src/plugins/android/androidsettingswidget.cpp b/src/plugins/android/androidsettingswidget.cpp index fda3366a95f..e928023937a 100644 --- a/src/plugins/android/androidsettingswidget.cpp +++ b/src/plugins/android/androidsettingswidget.cpp @@ -544,14 +544,9 @@ void AndroidSettingsWidget::validateSdk() AllEssentialsInstalledRow}); m_androidConfig.setSdkFullyConfigured(sdkToolsOk && componentsOk); if (sdkToolsOk && !componentsOk) { - // Ask user to install essential SDK components. Works only for sdk tools version >= 26.0.0 - QString message = tr("Android SDK installation is missing necessary packages. Do you " - "want to install the missing packages?"); - auto userInput = QMessageBox::information(this, tr("Missing Android SDK Packages"), - message, QMessageBox::Yes | QMessageBox::No); - if (userInput == QMessageBox::Yes) { - m_sdkManagerWidget->installEssentials(); - } + m_sdkManagerWidget->installEssentials( + "Android SDK installation is missing necessary packages. " + "Do you want to install the missing packages?"); } updateNdkList(); From 2d0225d978d75668d872071b65c205cc4dec48ff Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 31 Jan 2022 17:59:00 +0100 Subject: [PATCH 39/55] ProjectExplorer: Fix re-run from the output pane Amends 18fdad280a. Change-Id: I6c21ad35282d008b70bdb1e0dbf06deaba5f9829 Reviewed-by: Reviewed-by: Jarek Kobus Reviewed-by: Christian Kandeler --- .../projectexplorer/applicationlauncher.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/plugins/projectexplorer/applicationlauncher.cpp b/src/plugins/projectexplorer/applicationlauncher.cpp index 475622c7038..b3dfc5a2161 100644 --- a/src/plugins/projectexplorer/applicationlauncher.cpp +++ b/src/plugins/projectexplorer/applicationlauncher.cpp @@ -100,7 +100,7 @@ public: bool m_runAsRoot = false; // Local - QtcProcess *m_localProcess = nullptr; + std::unique_ptr m_localProcess; bool m_useTerminal = false; QProcess::ProcessChannelMode m_processChannelMode; // Keep track whether we need to emit a finished signal @@ -334,27 +334,26 @@ void ApplicationLauncherPrivate::start(const Runnable &runnable, const IDevice:: m_isLocal = local; if (m_isLocal) { - QTC_ASSERT(!m_localProcess, return); const QtcProcess::TerminalMode terminalMode = m_useTerminal ? QtcProcess::TerminalOn : QtcProcess::TerminalOff; - m_localProcess = new QtcProcess(terminalMode, this); + m_localProcess.reset(new QtcProcess(terminalMode, this)); m_localProcess->setProcessChannelMode(m_processChannelMode); if (m_processChannelMode == QProcess::SeparateChannels) { - connect(m_localProcess, &QtcProcess::readyReadStandardError, + connect(m_localProcess.get(), &QtcProcess::readyReadStandardError, this, &ApplicationLauncherPrivate::readLocalStandardError); } if (!m_useTerminal) { - connect(m_localProcess, &QtcProcess::readyReadStandardOutput, + connect(m_localProcess.get(), &QtcProcess::readyReadStandardOutput, this, &ApplicationLauncherPrivate::readLocalStandardOutput); } - connect(m_localProcess, &QtcProcess::started, + connect(m_localProcess.get(), &QtcProcess::started, this, &ApplicationLauncherPrivate::handleProcessStarted); - connect(m_localProcess, &QtcProcess::finished, this, [this] { + connect(m_localProcess.get(), &QtcProcess::finished, this, [this] { localProcessDone(m_localProcess->exitCode(), m_localProcess->exitStatus()); }); - connect(m_localProcess, &QtcProcess::errorOccurred, + connect(m_localProcess.get(), &QtcProcess::errorOccurred, this, &ApplicationLauncherPrivate::localProcessError); From fe4156de433d22e8d98a714cd8f6743f4d5ba46f Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 31 Jan 2022 14:53:41 +0100 Subject: [PATCH 40/55] SshDeviceProcess: Fix handling finished() signal We can't disconnect all signals inside SshDeviceProcessPrivate::setState() since it will also disconnect all external slots from *this signals. The original intention was to just disconnect from finished() signal to *this slot. Currently there are two connections to finished() signal: one is internal and one external. In order to guarantee that the internal one is always invoked before the external one, we need to do the internal connection first - so we move the connection to the constructor. In addition we introduce the ignoreFinished flag. The true value means the connection is disconnected. So, instead of connecting and disconnecting dynamically we change the flag accordingly. In case when handleThisProcessFinished() was called we don't emit a finised() signal from handleProcessFinished() since this signal is going to be delivered for all other external slots anyway after handling of handleThisProcessFinished() finishes. Amends 9ec997b37654894b027cf4bbd98ca8bba47171b5 Change-Id: Iae12c10251de242391c03d185a0856f421b99fe4 Reviewed-by: Qt CI Bot Reviewed-by: Christian Kandeler --- .../devicesupport/sshdeviceprocess.cpp | 29 +++++++++++++++---- .../devicesupport/sshdeviceprocess.h | 4 ++- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp b/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp index 1386c7a630b..5d7d285e668 100644 --- a/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp +++ b/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp @@ -51,6 +51,7 @@ public: SshDeviceProcessPrivate(SshDeviceProcess *q) : q(q) {} SshDeviceProcess * const q; + bool ignoreFinished = true; QSsh::SshConnection *connection = nullptr; QSsh::SshRemoteProcessPtr remoteProcess; Runnable runnable; @@ -73,6 +74,7 @@ SshDeviceProcess::SshDeviceProcess(const IDevice::ConstPtr &device, QObject *par : DeviceProcess(device, QtcProcess::TerminalOn, parent), d(std::make_unique(this)) { + connect(this, &QtcProcess::finished, this, &SshDeviceProcess::handleThisProcessFinished); connect(&d->killTimer, &QTimer::timeout, this, &SshDeviceProcess::handleKillOperationTimeout); } @@ -184,8 +186,7 @@ void SshDeviceProcess::handleConnected() if (!display.isEmpty()) d->remoteProcess->requestX11Forwarding(display); if (runInTerminal()) { - connect(this, &QtcProcess::finished, - this, [this] { handleProcessFinished(errorString()); }); + d->ignoreFinished = false; setAbortOnMetaChars(false); setCommand(d->remoteProcess->fullLocalCommandLine(true)); QtcProcess::start(); @@ -193,7 +194,7 @@ void SshDeviceProcess::handleConnected() connect(d->remoteProcess.get(), &QSsh::SshRemoteProcess::started, this, &SshDeviceProcess::handleProcessStarted); connect(d->remoteProcess.get(), &QSsh::SshRemoteProcess::done, - this, &SshDeviceProcess::handleProcessFinished); + this, &SshDeviceProcess::handleRemoteProcessFinished); connect(d->remoteProcess.get(), &QSsh::SshRemoteProcess::readyReadStandardOutput, this, &QtcProcess::readyReadStandardOutput); connect(d->remoteProcess.get(), &QSsh::SshRemoteProcess::readyReadStandardError, @@ -236,13 +237,29 @@ void SshDeviceProcess::handleProcessStarted() emit started(); } -void SshDeviceProcess::handleProcessFinished(const QString &error) +void SshDeviceProcess::handleThisProcessFinished() +{ + if (d->ignoreFinished) + return; + // Hack: we rely on fact that this slot was called before any other external slot connected + // to finished() signal. That's why we don't emit finished() signal from inside + // handleProcessFinished() since this signal will reach all other external slots anyway. + handleProcessFinished(QtcProcess::errorString(), false); +} + +void SshDeviceProcess::handleRemoteProcessFinished(const QString &error) +{ + handleProcessFinished(error, true); +} + +void SshDeviceProcess::handleProcessFinished(const QString &error, bool emitFinished) { d->errorMessage = error; if (d->killOperation && error.isEmpty()) d->errorMessage = tr("The process was ended forcefully."); d->setState(SshDeviceProcessPrivate::Inactive); - emit finished(); + if (emitFinished) + emit finished(); } void SshDeviceProcess::handleKillOperationFinished(const QString &errorMessage) @@ -328,7 +345,7 @@ void SshDeviceProcess::SshDeviceProcessPrivate::setState(SshDeviceProcess::SshDe QMetaObject::invokeMethod(q, &QtcProcess::stopProcess, Qt::QueuedConnection); } killTimer.stop(); - q->disconnect(); + ignoreFinished = true; if (remoteProcess) remoteProcess->disconnect(q); if (connection) { diff --git a/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.h b/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.h index 0980d530bcf..11b5a92bc12 100644 --- a/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.h +++ b/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.h @@ -60,7 +60,9 @@ private: void handleConnectionError(); void handleDisconnected(); void handleProcessStarted(); - void handleProcessFinished(const QString &error); + void handleThisProcessFinished(); + void handleRemoteProcessFinished(const QString &error); + void handleProcessFinished(const QString &error, bool emitFinished); void handleKillOperationFinished(const QString &errorMessage); void handleKillOperationTimeout(); From 39d078700a24e4f91ec0b53106b1239656638d06 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 1 Feb 2022 09:28:44 +0100 Subject: [PATCH 41/55] Fix a warning about wrong RunControlState transition The warning was issued when re-running from output pane. According to RunControlState class description the transition from Stopped to Starting is a valid one. Change-Id: I264630dc1c23c359ff4e9d4a7a292b9b0c55ec5a Reviewed-by: Reviewed-by: Christian Kandeler --- src/plugins/projectexplorer/runcontrol.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp index 7da09f1a340..f0824ead6e0 100644 --- a/src/plugins/projectexplorer/runcontrol.cpp +++ b/src/plugins/projectexplorer/runcontrol.cpp @@ -1123,7 +1123,8 @@ bool RunControlPrivate::isAllowedTransition(RunControlState from, RunControlStat return to == RunControlState::Stopped || to == RunControlState::Finishing; case RunControlState::Stopped: - return to == RunControlState::Finishing; + return to == RunControlState::Starting + || to == RunControlState::Finishing; case RunControlState::Finishing: return to == RunControlState::Finished; case RunControlState::Finished: From 64dea33250dffc24c3a439c961e46577aeb48690 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Sun, 30 Jan 2022 23:15:37 +0100 Subject: [PATCH 42/55] Welcome: Fix scrolling in the sidebar Some items did not move when the sidebar got scrolled. This change assigns them the right parent widget, so that they also scroll correctly. Fixes: QTCREATORBUG-26956 Change-Id: I28c131ffaa867652a4d9e282566f7986a0df9383 Reviewed-by: Cristian Adam --- src/plugins/welcome/welcomeplugin.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/welcome/welcomeplugin.cpp b/src/plugins/welcome/welcomeplugin.cpp index 5299f36f6ce..ef4c969be66 100644 --- a/src/plugins/welcome/welcomeplugin.cpp +++ b/src/plugins/welcome/welcomeplugin.cpp @@ -288,7 +288,7 @@ public: newVBox->setSpacing(buttonSpacing / 3); vbox->addItem(newVBox); - auto newLabel = new QLabel(tr("New to Qt?"), this); + auto newLabel = new QLabel(tr("New to Qt?"), mainWidget); newLabel->setFont(brandFont()); newLabel->setAlignment(Qt::AlignHCenter); newVBox->addWidget(newLabel); @@ -461,7 +461,7 @@ void WelcomeMode::addPage(IWelcomePage *page) if (m_pluginList.at(idx)->priority() >= pagePriority) break; } - auto pageButton = new WelcomePageButton(m_sideArea); + auto pageButton = new WelcomePageButton(m_sideArea->widget()); auto pageId = page->id(); pageButton->setText(page->title()); pageButton->setActiveChecker([this, pageId] { return m_activePage == pageId; }); From 328886ed4dcf4d350e2f64cb68b4a7e359ad4b1d Mon Sep 17 00:00:00 2001 From: Assam Boudjelthia Date: Sun, 30 Jan 2022 16:38:03 +0200 Subject: [PATCH 43/55] Show Android api 32 as Android 12L Change-Id: I48122062de4ce3bc092089d73d7bbae5abced73b Reviewed-by: Alessandro Portale Reviewed-by: --- src/plugins/android/androidmanager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/android/androidmanager.cpp b/src/plugins/android/androidmanager.cpp index 5a4d2c2fe52..704deff6db1 100644 --- a/src/plugins/android/androidmanager.cpp +++ b/src/plugins/android/androidmanager.cpp @@ -515,6 +515,8 @@ QString AndroidManager::androidNameForApiLevel(int x) return QLatin1String("Android 11"); case 31: return QLatin1String("Android 12"); + case 32: + return QLatin1String("Android 12L"); default: return tr("Unknown Android version. API Level: %1").arg(x); } From 95627ce10f336d327d46e5f81e70b52ae82f7e6d Mon Sep 17 00:00:00 2001 From: Assam Boudjelthia Date: Sun, 30 Jan 2022 16:44:57 +0200 Subject: [PATCH 44/55] Set NDK list vertical size policy to maximum And remove the spacer under the NDK list buttons. Let the NDK list take less vertical space. Change-Id: I4bd8769c45ddfbaaf34257b964a534c85de0e2fd Reviewed-by: Alessandro Portale --- src/plugins/android/androidsettingswidget.ui | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/src/plugins/android/androidsettingswidget.ui b/src/plugins/android/androidsettingswidget.ui index 227f4a5b5da..1dd2d8779ac 100644 --- a/src/plugins/android/androidsettingswidget.ui +++ b/src/plugins/android/androidsettingswidget.ui @@ -69,19 +69,6 @@ - - - - Qt::Vertical - - - - 20 - 40 - - - - @@ -89,6 +76,12 @@ + + + 0 + 0 + + QAbstractScrollArea::AdjustToContents From dbfd226e851cd093fed1b127fb1e68208286f11e Mon Sep 17 00:00:00 2001 From: Katarina Behrens Date: Thu, 27 Jan 2022 14:58:00 +0100 Subject: [PATCH 45/55] Imageviewer: zoom in and out using fixed set of common-sense zoom values Previously scale factor for zoom in/out was calculated as $(currentScaleFactor)^1.2 This results in weird zoom levels such as 83.3% or 144%. Replace this approach with using pre-defined set of 'normal' zoom level values such as {25%, 50%, .. 100%, 150%, 200% .. }, similar to what most graphic editors do To find the nearest greater or lesser fixed zoom level for any given floating point scale factor I borrowed some code from qmldesigner/ timelinewidget I didn't know what to do with zooming using mouse wheel so I left the old code in place Change-Id: Id037ef99f89cce5e8dcd58bb9ad0e6f3c8536f36 Reviewed-by: Alessandro Portale Reviewed-by: Qt CI Bot Reviewed-by: --- src/plugins/imageviewer/imageview.cpp | 46 +++++++++++++++++++-------- 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/src/plugins/imageviewer/imageview.cpp b/src/plugins/imageviewer/imageview.cpp index c435666d15f..c5ef478e595 100644 --- a/src/plugins/imageviewer/imageview.cpp +++ b/src/plugins/imageviewer/imageview.cpp @@ -57,10 +57,31 @@ namespace ImageViewer { namespace Constants { const qreal DEFAULT_SCALE_FACTOR = 1.2; + const qreal zoomLevels[] = { 0.25, 0.5, 0.75, 1.0, 1.5, 2.0, 4.0, 8.0 }; } namespace Internal { +static qreal nextLevel(qreal currentLevel) +{ + auto iter = std::find_if(std::begin(Constants::zoomLevels), std::end(Constants::zoomLevels), [&](qreal val) { + return val > currentLevel; + }); + if (iter != std::end(Constants::zoomLevels)) + return *iter; + return currentLevel; +} + +static qreal previousLevel(qreal currentLevel) +{ + auto iter = std::find_if(std::rbegin(Constants::zoomLevels), std::rend(Constants::zoomLevels), [&](qreal val) { + return val < currentLevel; + }); + if (iter != std::rend(Constants::zoomLevels)) + return *iter; + return currentLevel; +} + ImageView::ImageView(ImageViewerFile *file) : m_file(file) { @@ -245,16 +266,7 @@ void ImageView::setViewOutline(bool enable) void ImageView::doScale(qreal factor) { - qreal currentScale = transform().m11(); - qreal newScale = currentScale * factor; - qreal actualFactor = factor; - // cap to 0.001 - 1000 - if (newScale > 1000) - actualFactor = 1000./currentScale; - else if (newScale < 0.001) - actualFactor = 0.001/currentScale; - - scale(actualFactor, actualFactor); + scale(factor, factor); emitScaleFactor(); if (auto pixmapItem = dynamic_cast(m_imageItem)) pixmapItem->setTransformationMode( @@ -264,18 +276,26 @@ void ImageView::doScale(qreal factor) void ImageView::wheelEvent(QWheelEvent *event) { qreal factor = qPow(Constants::DEFAULT_SCALE_FACTOR, event->angleDelta().y() / 240.0); - doScale(factor); + qreal currentScale = transform().m11(); + qreal newScale = currentScale * factor; + // cap to 0.001 - 1000 + qreal actualFactor = qBound(0.001, factor, 1000.0); + doScale(actualFactor); event->accept(); } void ImageView::zoomIn() { - doScale(Constants::DEFAULT_SCALE_FACTOR); + qreal nextZoomLevel = nextLevel(transform().m11()); + resetTransform(); + doScale(nextZoomLevel); } void ImageView::zoomOut() { - doScale(1. / Constants::DEFAULT_SCALE_FACTOR); + qreal previousZoomLevel = previousLevel(transform().m11()); + resetTransform(); + doScale(previousZoomLevel); } void ImageView::resetToOriginalSize() From dc825e11bdd7a9b17fb04052303029add4b63635 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Tue, 1 Feb 2022 12:38:38 +0100 Subject: [PATCH 46/55] CMakePM: Fix "Reset" on changed values in Settings Previously the reset button would only work on new items being removed. User changes on existing items would not be reverted. Change-Id: I8d9bde058487c9568bfb802f131a29ec32fc1f8c Reviewed-by: Alessandro Portale Reviewed-by: --- src/plugins/cmakeprojectmanager/configmodel.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/plugins/cmakeprojectmanager/configmodel.cpp b/src/plugins/cmakeprojectmanager/configmodel.cpp index 15e2de1f021..7b3378eb6af 100644 --- a/src/plugins/cmakeprojectmanager/configmodel.cpp +++ b/src/plugins/cmakeprojectmanager/configmodel.cpp @@ -298,6 +298,13 @@ void ConfigModel::setConfiguration(const QList &c // merge old/new entry: InternalDataItem item(*newIt); item.newValue = (newIt->value != oldIt->newValue) ? oldIt->newValue : QString(); + + // Do not mark as user changed when we have a reset + if (oldIt->isUserChanged && !oldIt->newValue.isEmpty() && + !newIt->isUserChanged && newIt->newValue.isEmpty() && + oldIt->value == newIt->value) + item.newValue.clear(); + item.isUserChanged = !item.newValue.isEmpty() && (item.newValue != item.value); result << item; ++newIt; From 9c8f46a1738b4a7627caefc501f71d365d1e6570 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Fri, 28 Jan 2022 18:16:23 +0100 Subject: [PATCH 47/55] CMakePM: Add "Appy Kit/Initial Configuration Value" context menu entry Now the "Initial Configuration" and "Current Configuration" displays in red the mismatches between kit / initial value and respectively initial and current configuration values. By having a "Apply Kit / Initial Configuration Value" context menu entry the user can resolve the mismatches if needed. Change-Id: I2e272821c3ba396cd8a6b7c81e1437cb3fd4bbad Reviewed-by: Reviewed-by: Alessandro Portale --- .../cmakebuildconfiguration.cpp | 24 +++++++++++++ .../cmakeprojectmanager/configmodel.cpp | 36 +++++++++++++++++++ src/plugins/cmakeprojectmanager/configmodel.h | 6 ++++ 3 files changed, 66 insertions(+) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index 6be3d6e60bb..02f596728dd 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -895,6 +895,30 @@ bool CMakeBuildSettingsWidget::eventFilter(QObject *target, QEvent *event) if ((action = createForceAction(ConfigModel::DataItem::STRING, idx))) menu->addAction(action); + menu->addSeparator(); + + auto applyKitOrInitialValue = new QAction(isInitialConfiguration() + ? tr("Apply Kit Value") + : tr("Apply Initial Configuration Value"), + this); + menu->addAction(applyKitOrInitialValue); + connect(applyKitOrInitialValue, &QAction::triggered, this, [this] { + const QModelIndexList selectedIndexes = m_configView->selectionModel()->selectedIndexes(); + + const QModelIndexList validIndexes = Utils::filtered(selectedIndexes, [](const QModelIndex &index) { + return index.isValid() && index.flags().testFlag(Qt::ItemIsSelectable); + }); + + for (const QModelIndex &index : validIndexes) { + if (isInitialConfiguration()) + m_configModel->applyKitValue(mapToSource(m_configView, index)); + else + m_configModel->applyInitialValue(mapToSource(m_configView, index)); + } + }); + + menu->addSeparator(); + auto copy = new QAction(tr("Copy"), this); menu->addAction(copy); connect(copy, &QAction::triggered, this, [this] { diff --git a/src/plugins/cmakeprojectmanager/configmodel.cpp b/src/plugins/cmakeprojectmanager/configmodel.cpp index 7b3378eb6af..af33564d5da 100644 --- a/src/plugins/cmakeprojectmanager/configmodel.cpp +++ b/src/plugins/cmakeprojectmanager/configmodel.cpp @@ -180,6 +180,42 @@ void ConfigModel::toggleUnsetFlag(const QModelIndex &idx) emit dataChanged(keyIdx, valueIdx); } +void ConfigModel::applyKitValue(const QModelIndex &idx) +{ + applyKitOrInitialValue(idx, KitOrInitial::Kit); +} + +void ConfigModel::applyInitialValue(const QModelIndex &idx) +{ + applyKitOrInitialValue(idx, KitOrInitial::Initial); +} + +void ConfigModel::applyKitOrInitialValue(const QModelIndex &idx, KitOrInitial ki) +{ + Utils::TreeItem *item = itemForIndex(idx); + auto cmti = dynamic_cast(item); + + QTC_ASSERT(cmti, return ); + + auto dataItem = cmti->dataItem; + const QString &kitOrInitialValue = ki == KitOrInitial::Kit ? dataItem->kitValue + : dataItem->initialValue; + + // Allow a different value when the user didn't change anything (don't mark the same value as new) + // But allow the same value (going back) when the user did a change + const bool canSetValue = (dataItem->value != kitOrInitialValue && !dataItem->isUserChanged) + || dataItem->isUserChanged; + + if (!kitOrInitialValue.isEmpty() && canSetValue) { + dataItem->newValue = kitOrInitialValue; + dataItem->isUserChanged = dataItem->value != kitOrInitialValue; + + const QModelIndex valueIdx = idx.sibling(idx.row(), 1); + const QModelIndex keyIdx = idx.sibling(idx.row(), 0); + emit dataChanged(keyIdx, valueIdx); + } +} + ConfigModel::DataItem ConfigModel::dataItemFromIndex(const QModelIndex &idx) { const QAbstractItemModel *m = idx.model(); diff --git a/src/plugins/cmakeprojectmanager/configmodel.h b/src/plugins/cmakeprojectmanager/configmodel.h index 87f37fcaed6..b50aea536a8 100644 --- a/src/plugins/cmakeprojectmanager/configmodel.h +++ b/src/plugins/cmakeprojectmanager/configmodel.h @@ -158,6 +158,9 @@ public: void toggleUnsetFlag(const QModelIndex &idx); + void applyKitValue(const QModelIndex &idx); + void applyInitialValue(const QModelIndex &idx); + static DataItem dataItemFromIndex(const QModelIndex &idx); QList configurationForCMake() const; @@ -166,6 +169,9 @@ public: void setMacroExpander(Utils::MacroExpander *newExpander); private: + enum class KitOrInitial { Kit, Initial }; + void applyKitOrInitialValue(const QModelIndex &idx, KitOrInitial ki); + class InternalDataItem : public DataItem { public: From 075ebb932ea59cd29d42f98952c8091c1f6862d0 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Tue, 1 Feb 2022 12:03:15 +0100 Subject: [PATCH 48/55] Modeltest: Fix shared files Replace deprecated and removed enums. Change-Id: I9c374fab7662f181be5fe613d39afff963318315 Reviewed-by: Christian Kandeler --- src/shared/modeltest/modeltest.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shared/modeltest/modeltest.cpp b/src/shared/modeltest/modeltest.cpp index 75000e9f3b9..c44b50ab34f 100644 --- a/src/shared/modeltest/modeltest.cpp +++ b/src/shared/modeltest/modeltest.cpp @@ -433,11 +433,11 @@ void ModelTest::data() } // General Purpose roles that should return a QColor - QVariant colorVariant = model->data(model->index(0, 0), Qt::BackgroundColorRole); + QVariant colorVariant = model->data(model->index(0, 0), Qt::BackgroundRole); if (colorVariant.isValid()) Q_ASSERT(colorVariant.canConvert(QVariant::Color)); - colorVariant = model->data(model->index(0, 0), Qt::TextColorRole); + colorVariant = model->data(model->index(0, 0), Qt::ForegroundRole); if (colorVariant.isValid()) Q_ASSERT(colorVariant.canConvert(QVariant::Color)); From f6061d4f1ae52f3d85175295ff5afe8f1b55aba5 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Tue, 1 Feb 2022 12:07:27 +0100 Subject: [PATCH 49/55] Manual test: Adapt to upstream change Change-Id: I4bb8b323535eaeb456d3cfcedaef0e67970cfe4e Reviewed-by: Christian Kandeler --- tests/manual/process/main.cpp | 3 ++- tests/manual/process/mainwindow.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/manual/process/main.cpp b/tests/manual/process/main.cpp index 78222ffbd41..86c7ca7788d 100644 --- a/tests/manual/process/main.cpp +++ b/tests/manual/process/main.cpp @@ -25,6 +25,7 @@ #include "mainwindow.h" +#include #include #include @@ -49,7 +50,7 @@ static int testSynchronous(const QString &cmd, const QStringList &args) std::fprintf(stdout, "testSynchronous %s %s\n", qPrintable(cmd), qPrintable(args.join(QLatin1Char(' ')))); Utils::QtcProcess p; - p.setCommand({cmd, args}); + p.setCommand({Utils::FilePath::fromString(cmd), args}); p.start(); if (!p.waitForStarted()) return -2; diff --git a/tests/manual/process/mainwindow.cpp b/tests/manual/process/mainwindow.cpp index 9f0c8d50279..ceb15e8a533 100644 --- a/tests/manual/process/mainwindow.cpp +++ b/tests/manual/process/mainwindow.cpp @@ -57,7 +57,7 @@ void MainWindow::test() qDebug() << "Async: " << cmd << args; process.setStdOutCallback([this](const QString &s) { append(s); }); process.setStdErrCallback([this](const QString &s) { append(s); }); - process.setCommand({cmd, args}); + process.setCommand({Utils::FilePath::fromString(cmd), args}); process.runBlocking(); qDebug() << process; } From c8b2e4fe1e52e7dc088af4491334f500993a06de Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Tue, 1 Feb 2022 12:11:46 +0100 Subject: [PATCH 50/55] Manual tests: Correct qtc_processlauncher location Change-Id: Ia3c550ae5cd0f2a6c75ec6d4fba230edf2a0bec8 Reviewed-by: Christian Kandeler --- tests/manual/ssh/sftpfsmodel/main.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/manual/ssh/sftpfsmodel/main.cpp b/tests/manual/ssh/sftpfsmodel/main.cpp index d1a7365dc20..15fa8535fac 100644 --- a/tests/manual/ssh/sftpfsmodel/main.cpp +++ b/tests/manual/ssh/sftpfsmodel/main.cpp @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -35,6 +36,8 @@ int main(int argc, char *argv[]) { QApplication app(argc, argv); + Utils::LauncherInterface::setPathToLauncher(qApp->applicationDirPath() + '/' + + QLatin1String(TEST_RELATIVE_LIBEXEC_PATH)); Utils::TemporaryDirectory::setMasterTemporaryDirectory(QDir::tempPath() + "/qtc-ssh-shelltest-XXXXXX"); SftpFsWindow w; From 3a9ce469281321399764da193661dff69deb00c1 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Tue, 1 Feb 2022 12:16:19 +0100 Subject: [PATCH 51/55] Simple test app: Fix location The location had been correct with qmake, but is wrong with qbs and cmake. Change-Id: I967f6db60e084dbc98548d61bb6eddbac4f7be24 Reviewed-by: Christian Kandeler --- tests/manual/debugger/simple/simple_test_app.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/manual/debugger/simple/simple_test_app.cpp b/tests/manual/debugger/simple/simple_test_app.cpp index 15ed0174182..072345c3fcf 100644 --- a/tests/manual/debugger/simple/simple_test_app.cpp +++ b/tests/manual/debugger/simple/simple_test_app.cpp @@ -2201,7 +2201,7 @@ namespace plugin { QLibrary lib(dir + "/libsimple_test_plugin.dylib"); #endif #ifdef Q_OS_WIN - QLibrary lib(dir + "/debug/simple_test_plugin.dll"); + QLibrary lib(dir + "/simple_test_plugin.dll"); #endif BREAK_HERE; // CheckType dir QString. From f95636a8203c7b6de6f166f9e0a0604f08bce239 Mon Sep 17 00:00:00 2001 From: Mats Honkamaa Date: Thu, 27 Jan 2022 15:09:26 +0200 Subject: [PATCH 52/55] Doc: Update multilanguage database docs Update reference docs and tutorial for the multilanguage database. Task-number: QDS-5966 Change-Id: I1aa3fa2fa8009bb0240ec787edbdc1589e87d5f1 Reviewed-by: Leena Miettinen --- .../doc/images/imported-translations.png | Bin 9763 -> 8725 bytes .../examples/doc/multilanguage.qdoc | 23 +++---- .../images/enable-multilanguage.png | Bin 6486 -> 0 bytes .../images/studio-translations-view.png | Bin 79896 -> 9687 bytes .../images/translation-tester.png | Bin 26029 -> 3862 bytes .../src/views/studio-translations.qdoc | 58 ++++++++++-------- 6 files changed, 40 insertions(+), 41 deletions(-) delete mode 100644 doc/qtdesignstudio/images/enable-multilanguage.png diff --git a/doc/qtdesignstudio/examples/doc/images/imported-translations.png b/doc/qtdesignstudio/examples/doc/images/imported-translations.png index 7609394b8e03e2856d2d5b9c61be81dfaa1f2202..1d30eb7be0233caa2f23c17549d084f8364f04bd 100644 GIT binary patch literal 8725 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 literal 9763 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 DGM@N1 diff --git a/doc/qtdesignstudio/examples/doc/multilanguage.qdoc b/doc/qtdesignstudio/examples/doc/multilanguage.qdoc index 27afb9d02b2..e749ab59675 100644 --- a/doc/qtdesignstudio/examples/doc/multilanguage.qdoc +++ b/doc/qtdesignstudio/examples/doc/multilanguage.qdoc @@ -39,8 +39,8 @@ translations from a JSON file. You need to download the starting project for this tutorial from - \l{https://git.qt.io/public-demos/qtdesign-studio/-/tree/master/examples/ - loginui2}{here} before you start. + \l{https://git.qt.io/public-demos/qtdesign-studio/-/tree/master/tutorial%20projects/multi-language%20tutorial/Loginui2}{here} + before you start. Download the project and open the \e loginui2.qmlproject file in \QDS to get started. @@ -48,8 +48,7 @@ This project consists of a login page with a couple of text elements. Additionally, you will use a JSON translation file in this tutorial. - Download it from \l{https://git.qt.io/public-demos/qtdesign-studio/-/tree/ - master/tutorial%20projects/multi-language}{here}. + Download it from \l{https://git.qt.io/public-demos/qtdesign-studio/-/tree/master/tutorial%20projects/multi-language}{here}. \section1 JSON Translation File @@ -133,10 +132,11 @@ First, you need to prepare your project for translation: \list 1 + \li In \uicontrol{Projects}, double-click \e{Screen01.ui.qml} to open it. \li All text strings that you want to translate need to be of \c qsTrId type. In this project the text strings are of \c qsTr type so you need to change them. Open \uicontrol{Text Editor}, find all five - occurrences of \c QsTr and replace them with \c{QsTrId}. For example, + occurrences of \c qsTr and replace them with \c{qsTrId}. For example, replace: \code text: qsTr("Qt Account") @@ -165,21 +165,14 @@ \li Go to \uicontrol View > \uicontrol Views and select \uicontrol Translations to open the \uicontrol Translations view. You can drag it to a workspace to dock it. - - When you open the \uicontrol Translations view for the first time, \QDS - prompts you to enable the multi-language database, select - \uicontrol{Yes}. - \image enable-multilanguage.png \li In \uicontrol Translations, select \inlineimage icons/select-languages.png . - - When you enable the multi-language database, an SQLite database named - \e translations.db is created in the project folder root. \li Select the languages that you want to support in your project, in this case \uicontrol{English - American English} and - \uicontrol{Swedish}. - \li Set \uicontrol English as primary language and select \uicontrol{OK}. + \uicontrol{Swedish - Svenska}. + \li Set \uicontrol{English - American English} as primary language and + select \uicontrol{Ok}. \li Select \inlineimage icons/import-json-translations.png and open the \e ml_translations.json file. Now you can see all your imported translations in the \uicontrol Translations view. diff --git a/doc/qtdesignstudio/images/enable-multilanguage.png b/doc/qtdesignstudio/images/enable-multilanguage.png deleted file mode 100644 index ebb528a81a2d10a6f7e7ff26cf92b735997f4418..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6486 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 Ul)QX_fq{X+)78&qol`;+01i3W#sB~S diff --git a/doc/qtdesignstudio/images/studio-translations-view.png b/doc/qtdesignstudio/images/studio-translations-view.png index 454e8ce2a233d9b16eae9447e8727f4ab19eac1f..d5a843d0df6450a2dafb916930892c3ba3fe4cf1 100644 GIT binary patch literal 9687 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Ⴥ_Qn_ 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 diff --git a/doc/qtdesignstudio/images/translation-tester.png b/doc/qtdesignstudio/images/translation-tester.png index 6b1e6f024dfced19c86a1d5530048fea152fe0e2..6a3f7441805a213a26572af579440e9dae33727e 100644 GIT binary patch literal 3862 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/i18n}. - \section1 Running the QML Translation Test + \section1 Running Translation Test for a Single Document - You can run the QML language test to find missing - and elided translations. Running the QML language test - is a quick way to check the translations in the application you have open in - \uicontrol{Form Editor} as it highlights errors in the UI. + You can run the translation test to find missing translations + and translations where the text exceeds the text element boundaries. Running + the test is a quick way to check the translations in the document you have + open in \uicontrol{Form Editor} as it highlights errors in the UI. - To run the QML translation test: + To run the test for the currently open document: \list 1 \li In the \uicontrol Translations view, select @@ -155,12 +157,11 @@ \li Select the tests to run and the highlight color for each test: \list - \li \uicontrol{Show Translation Warnings} highlights missing - translations. - \li \uicontrol{Show Found Translations} highlights all translations - that are correct. - \li \uicontrol{Show Elide Warnings} highlights all translations where - the text is too long to fit in the text object and therefore is elided. + \li \uicontrol{Success} highlights translations without any warnings. + \li \uicontrol{Missing translation} highlights translations that are + missing for one or more languages. + \li \uicontrol{Exceeds boundaries} highlights translations where + the text is too long to fit in the text object. \endlist \image translation-tester.png \li Select \uicontrol{Run Tests}. @@ -205,16 +206,21 @@ The report shows the type of error as well as line and column of the affected text element in the \e{ui.qml} file. - \section1 Running the Project Translation Test + \section1 Running Translation Test for Several Documents You can run the project translation test on several \e{.ui.qml} files at the same time. \QDS runs the same tests as during the - \l{Running the QML Translation Test}{QML Translation Test} and generates the - same test reports but does not highlight errors in the UI. + \l{Running Translation Test for a Single Document}{Translation Test} and + generates the same test reports but does not highlight errors in the UI. - To run the project translation test, select - \inlineimage icons/project-translation-test.png - in the \uicontrol Translations view. + To run the translation test for several documents: + \list 1 + \li Select + \inlineimage icons/project-translation-test.png + in the \uicontrol Translations view. + \li Select the files that you want to include in the test. + \li Select \uicontrol{Run Tests}. + \endlist \section1 Exporting Translations in Other Ways From a4b3085acb90652cc1fa867f8e0832e887f2bbfa Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Tue, 25 Jan 2022 14:17:55 +0100 Subject: [PATCH 53/55] Fix issues with "Select All" (search results) - the shortcut Alt+Return conflicts with "Trigger Refactoring Action" - display the shortcut in find toolbar button's tooltip - no need to repeat the default shortcut (it's the same Command) Change-Id: Ifd1e56ba091806901241bdca66c42a332574bc0c Reviewed-by: David Schulz --- src/plugins/coreplugin/find/findtoolbar.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/coreplugin/find/findtoolbar.cpp b/src/plugins/coreplugin/find/findtoolbar.cpp index 4a374fa742e..f7345f28c9c 100644 --- a/src/plugins/coreplugin/find/findtoolbar.cpp +++ b/src/plugins/coreplugin/find/findtoolbar.cpp @@ -224,12 +224,12 @@ FindToolBar::FindToolBar(CurrentDocumentFind *currentDocumentFind) m_selectAllAction = new QAction(tr("Select All"), this); cmd = ActionManager::registerAction(m_selectAllAction, Constants::FIND_SELECT_ALL); - cmd->setDefaultKeySequence(QKeySequence(tr("Alt+Return"))); + cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Alt+Return"))); mfind->addAction(cmd, Constants::G_FIND_ACTIONS); connect(m_selectAllAction, &QAction::triggered, this, &FindToolBar::selectAll); m_localSelectAllAction = new QAction(m_selectAllAction->text(), this); cmd = ActionManager::registerAction(m_localSelectAllAction, Constants::FIND_SELECT_ALL, findcontext); - cmd->setDefaultKeySequence(QKeySequence(tr("Alt+Return"))); + cmd->augmentActionWithShortcutToolTip(m_localSelectAllAction); connect(m_localSelectAllAction, &QAction::triggered, this, &FindToolBar::selectAll); m_ui.selectAllButton->setDefaultAction(m_localSelectAllAction); From 275dcc8f8aae242c2260454543cbaa51508dae0c Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Tue, 25 Jan 2022 15:35:14 +0100 Subject: [PATCH 54/55] File System view: Select root folder when clicking outside item If the shown items are not filling the whole view, there is some empty space at the bottom. Select the current root directory when the user click there. This avoids funny behavior. Without that change - select a file or subdirectory in a directory - collapse the parent directory - the selected file or subdirectory stays selected, but that is not visible - right-click into the empty space at the bottom - the context menu for the not-visibly selected item is shown - this is especially weird when e.g. choosing "New Folder" That is not an issue if the view fills the whole space, because then a visible item is selected when clicking. Change-Id: I0c65e091e659c20d7b384e96ecf69c36379ed936 Reviewed-by: David Schulz --- src/plugins/coreplugin/foldernavigationwidget.cpp | 15 +++++++++++++++ src/plugins/coreplugin/foldernavigationwidget.h | 2 ++ 2 files changed, 17 insertions(+) diff --git a/src/plugins/coreplugin/foldernavigationwidget.cpp b/src/plugins/coreplugin/foldernavigationwidget.cpp index 4726b3264a4..52cae412877 100644 --- a/src/plugins/coreplugin/foldernavigationwidget.cpp +++ b/src/plugins/coreplugin/foldernavigationwidget.cpp @@ -299,6 +299,7 @@ FolderNavigationWidget::FolderNavigationWidget(QWidget *parent) : QWidget(parent m_listView->setEditTriggers(QAbstractItemView::NoEditTriggers); m_listView->setDragEnabled(true); m_listView->setDragDropMode(QAbstractItemView::DragOnly); + m_listView->viewport()->installEventFilter(this); showOnlyFirstColumn(m_listView); setFocusProxy(m_listView); @@ -521,6 +522,20 @@ void FolderNavigationWidget::syncWithFilePath(const Utils::FilePath &filePath) selectFile(filePath); } +bool FolderNavigationWidget::eventFilter(QObject *obj, QEvent *event) +{ + if (obj == m_listView->viewport()) { + if (event->type() == QEvent::MouseButtonPress) { + // select the current root when clicking outside any other item + auto me = static_cast(event); + const QModelIndex index = m_listView->indexAt(me->pos()); + if (!index.isValid()) + m_listView->setCurrentIndex(m_listView->rootIndex()); + } + } + return false; +} + bool FolderNavigationWidget::autoSynchronization() const { return m_autoSync; diff --git a/src/plugins/coreplugin/foldernavigationwidget.h b/src/plugins/coreplugin/foldernavigationwidget.h index dbc3baec370..4cee261369a 100644 --- a/src/plugins/coreplugin/foldernavigationwidget.h +++ b/src/plugins/coreplugin/foldernavigationwidget.h @@ -130,6 +130,8 @@ public: void syncWithFilePath(const Utils::FilePath &filePath); + bool eventFilter(QObject *obj, QEvent *event) override; + protected: void contextMenuEvent(QContextMenuEvent *ev) override; From 1221552377a5fa63d2f5f4364397ebbcec7a27cf Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 28 Jan 2022 08:59:14 +0100 Subject: [PATCH 55/55] Require CMake 3.16 and remove workarounds CMake 3.16 is available on the major Linux distributions nowadays, so we can get rid of some workarounds. Change-Id: I32500375748f33c3e40fbd7a08824d823f817a8f Reviewed-by: Cristian Adam Reviewed-by: Qt CI Bot --- CMakeLists.txt | 15 +++----- cmake/QtCreatorAPI.cmake | 25 ++----------- cmake/QtCreatorAPIInternal.cmake | 35 ++----------------- share/qtcreator/translations/CMakeLists.txt | 22 ++++-------- src/libs/qtcreatorcdbext/CMakeLists.txt | 20 ++++------- src/tools/iostool/CMakeLists.txt | 6 +--- src/tools/sdktool/CMakeLists.txt | 2 +- src/tools/wininterrupt/CMakeLists.txt | 2 +- tests/auto/debugger/CMakeLists.txt | 2 +- .../testprojects/modulemapping/CMakeLists.txt | 2 +- tests/unit/CMakeLists.txt | 2 +- 11 files changed, 29 insertions(+), 104 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c226f78bdbb..c6f603c7981 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.10) +cmake_minimum_required(VERSION 3.16) ## Add paths to check for cmake modules: list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") @@ -138,15 +138,8 @@ endif() add_subdirectory(doc) -# TODO: Remove when cmake_minimum_required greater than 3.12 -if (CMAKE_VERSION VERSION_GREATER 3.12) - find_package(Python3 COMPONENTS Interpreter) - set(PYTHONINTERP_FOUND ${Python3_Interpreter_FOUND}) - set(PYTHON_EXECUTABLE ${Python3_EXECUTABLE}) -else() - find_package(PythonInterp) -endif() -if (NOT PYTHONINTERP_FOUND) +find_package(Python3 COMPONENTS Interpreter) +if (NOT Python3_Interpreter_FOUND) message("No python interpreter found, skipping \"Dependencies\" install component.") else() get_target_property(_qmake_binary Qt5::qmake IMPORTED_LOCATION) @@ -161,7 +154,7 @@ else() endif() install(CODE " execute_process(COMMAND - \"${PYTHON_EXECUTABLE}\" + \"${Python3_EXECUTABLE}\" \"${CMAKE_CURRENT_LIST_DIR}/scripts/deployqt.py\" ${_llvm_arg} ${_elfutils_arg} diff --git a/cmake/QtCreatorAPI.cmake b/cmake/QtCreatorAPI.cmake index 566f5883d46..194852d6b7f 100644 --- a/cmake/QtCreatorAPI.cmake +++ b/cmake/QtCreatorAPI.cmake @@ -155,20 +155,6 @@ function(add_qtc_library name) return() endif() - # TODO copied from extend_qtc_target. - # Instead require CMake 3.11 and use extend_qtc_target for setting SOURCES. - # Requiring cmake 3.11 is necessary because before that add_library requires - # at least one source file. - if (_arg_SOURCES_PREFIX) - foreach(source IN LISTS _arg_SOURCES) - list(APPEND prefixed_sources "${_arg_SOURCES_PREFIX}/${source}") - endforeach() - if (NOT IS_ABSOLUTE ${_arg_SOURCES_PREFIX}) - set(_arg_SOURCES_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/${_arg_SOURCES_PREFIX}") - endif() - set(_arg_SOURCES ${prefixed_sources}) - endif() - set(library_type SHARED) if (_arg_STATIC) set(library_type STATIC) @@ -177,16 +163,9 @@ function(add_qtc_library name) set(library_type OBJECT) endif() - add_library(${name} ${library_type} ${_arg_SOURCES}) + add_library(${name} ${library_type}) add_library(QtCreator::${name} ALIAS ${name}) - set_public_headers(${name} "${_arg_SOURCES}") - - # TODO remove, see above - if (_arg_SOURCES_PREFIX) - target_include_directories(${name} PRIVATE $) - endif() - if (${name} MATCHES "^[^0-9-]+$") string(TOUPPER "${name}_LIBRARY" EXPORT_SYMBOL) endif() @@ -201,6 +180,8 @@ function(add_qtc_library name) endif() extend_qtc_target(${name} + SOURCES_PREFIX ${_arg_SOURCES_PREFIX} + SOURCES ${_arg_SOURCES} INCLUDES ${_arg_INCLUDES} PUBLIC_INCLUDES ${_arg_PUBLIC_INCLUDES} DEFINES ${EXPORT_SYMBOL} ${default_defines_copy} ${_arg_DEFINES} ${TEST_DEFINES} diff --git a/cmake/QtCreatorAPIInternal.cmake b/cmake/QtCreatorAPIInternal.cmake index 7c16d1dd2eb..86fe1c0d939 100644 --- a/cmake/QtCreatorAPIInternal.cmake +++ b/cmake/QtCreatorAPIInternal.cmake @@ -1,5 +1,5 @@ if (CMAKE_VERSION VERSION_LESS 3.18) - if (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_VERSION VERSION_LESS 3.16) + if (CMAKE_CXX_COMPILER_ID STREQUAL GNU) set(BUILD_WITH_PCH OFF CACHE BOOL "" FORCE) endif() endif() @@ -183,31 +183,6 @@ function(update_cached_list name value) set("${name}" "${_tmp_list}" CACHE INTERNAL "*** Internal ***") endfunction() -function(separate_object_libraries libraries REGULAR_LIBS OBJECT_LIBS OBJECT_LIB_OBJECTS) - if (CMAKE_VERSION VERSION_LESS 3.14) - foreach(lib IN LISTS libraries) - if (TARGET ${lib}) - get_target_property(lib_type ${lib} TYPE) - if (lib_type STREQUAL "OBJECT_LIBRARY") - list(APPEND object_libs ${lib}) - list(APPEND object_libs_objects $) - else() - list(APPEND regular_libs ${lib}) - endif() - else() - list(APPEND regular_libs ${lib}) - endif() - set(${REGULAR_LIBS} ${regular_libs} PARENT_SCOPE) - set(${OBJECT_LIBS} ${object_libs} PARENT_SCOPE) - set(${OBJECT_LIB_OBJECTS} ${object_libs_objects} PARENT_SCOPE) - endforeach() - else() - set(${REGULAR_LIBS} ${libraries} PARENT_SCOPE) - unset(${OBJECT_LIBS} PARENT_SCOPE) - unset(${OBJECT_LIB_OBJECTS} PARENT_SCOPE) - endif() -endfunction(separate_object_libraries) - function(set_explicit_moc target_name file) unset(file_dependencies) if (file MATCHES "^.*plugin.h$") @@ -293,12 +268,8 @@ function(add_qtc_depends target_name) check_qtc_disabled_targets(${target_name} _arg_PRIVATE) check_qtc_disabled_targets(${target_name} _arg_PUBLIC) - separate_object_libraries("${_arg_PRIVATE}" - depends object_lib_depends object_lib_depends_objects) - separate_object_libraries("${_arg_PUBLIC}" - public_depends object_public_depends object_public_depends_objects) - - target_sources(${target_name} PRIVATE ${object_lib_depends_objects} ${object_public_depends_objects}) + set(depends "${_arg_PRIVATE}") + set(public_depends "${_arg_PUBLIC}") get_target_property(target_type ${target_name} TYPE) if (NOT target_type STREQUAL "OBJECT_LIBRARY") diff --git a/share/qtcreator/translations/CMakeLists.txt b/share/qtcreator/translations/CMakeLists.txt index 648f885b771..f32138e7791 100644 --- a/share/qtcreator/translations/CMakeLists.txt +++ b/share/qtcreator/translations/CMakeLists.txt @@ -1,27 +1,19 @@ set(languages cs da de fr hr ja pl ru sl uk zh_CN zh_TW) set(bad_languages hu) # Fix these before including them in languages! -# TODO: Remove when cmake_minimum_required greater than 3.12 -if (CMAKE_VERSION VERSION_GREATER 3.12) - find_package(Python3 COMPONENTS Interpreter) - set(PYTHONINTERP_FOUND ${Python3_Interpreter_FOUND}) - set(PYTHON_VERSION_STRING ${Python3_VERSION}) - set(PYTHON_EXECUTABLE ${Python3_EXECUTABLE}) -else() - find_package(PythonInterp) -endif() +find_package(Python3 COMPONENTS Interpreter) set(json_wizards_h "") set(custom_wizards_h "") set(externaltools_h "") set(snippets_h "") -if (NOT PYTHONINTERP_FOUND OR NOT PYTHON_VERSION_STRING VERSION_GREATER_EQUAL "3.0.0") - message(WARNING "No python3 interpreter found, skipping extraction of data from XML and JSON files.\n *** Please pass -DPYTHON_EXECUTABLE=/path/to/python3 to cmake.") +if (NOT Python3_Interpreter_FOUND) + message(WARNING "No python3 interpreter found, skipping extraction of data from XML and JSON files.\n *** Please pass -DPython3_EXECUTABLE=/path/to/python3 to cmake.") else() set(json_wizards_h "${CMAKE_CURRENT_BINARY_DIR}/jsonwizards_tr.h") add_custom_command(OUTPUT "${json_wizards_h}" - COMMAND "${PYTHON_EXECUTABLE}" + COMMAND "${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/extract-jsonwizards.py" "${PROJECT_SOURCE_DIR}/share/qtcreator/templates/wizards" "${json_wizards_h}" COMMENT Generate translation data from JSON wizards @@ -29,7 +21,7 @@ else() set(custom_wizards_h "${CMAKE_CURRENT_BINARY_DIR}/customwizards_tr.h") add_custom_command(OUTPUT "${custom_wizards_h}" - COMMAND "${PYTHON_EXECUTABLE}" + COMMAND "${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/extract-customwizards.py" "${PROJECT_SOURCE_DIR}/share/qtcreator/templates/wizards" "${custom_wizards_h}" COMMENT Generate translation data from XML wizards @@ -37,7 +29,7 @@ else() set(externaltools_h "${CMAKE_CURRENT_BINARY_DIR}/externaltools_tr.h") add_custom_command(OUTPUT "${externaltools_h}" - COMMAND "${PYTHON_EXECUTABLE}" + COMMAND "${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/extract-externaltools.py" "${PROJECT_SOURCE_DIR}/src/share/qtcreator/externaltools" "${externaltools_h}" COMMENT Generate translation data from external tools definitions @@ -45,7 +37,7 @@ else() set(snippets_h "${CMAKE_CURRENT_BINARY_DIR}/snippets_tr.h") add_custom_command(OUTPUT "${snippets_h}" - COMMAND "${PYTHON_EXECUTABLE}" + COMMAND "${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/extract-snippets.py" "${PROJECT_SOURCE_DIR}/share/qtcreator/snippets" "${snippets_h}" COMMENT Generate translation data from snippets definitions diff --git a/src/libs/qtcreatorcdbext/CMakeLists.txt b/src/libs/qtcreatorcdbext/CMakeLists.txt index 5b03103bc88..3797afd1cf2 100644 --- a/src/libs/qtcreatorcdbext/CMakeLists.txt +++ b/src/libs/qtcreatorcdbext/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.10) +cmake_minimum_required(VERSION 3.16) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake") @@ -60,17 +60,9 @@ add_qtc_library(qtcreatorcdbext qtc_library_enabled(_library_enabled qtcreatorcdbext) if (_library_enabled) - # TODO: Remove when cmake_minimum_required greater than 3.12 - if (CMAKE_VERSION VERSION_GREATER 3.12) - find_package(Python3 3.8 COMPONENTS Development) - set(PYTHONLIBS_FOUND ${Python3_Development_FOUND}) - set(PYTHON_LIBRARIES ${Python3_LIBRARIES}) - set(PYTHON_INCLUDE_DIR ${Python3_INCLUDE_DIRS}) - else() - find_package(PythonLibs 3.8) - endif() + find_package(Python3 3.8 COMPONENTS Development) - if (NOT ${PYTHONLIBS_FOUND}) + if (NOT ${Python3_Development_FOUND}) message(WARNING "PythonLibs (at least version 3.8) not found. qtcreatorcdbext will be built without Python support.") return() endif() @@ -80,7 +72,7 @@ if (_library_enabled) set(PythonRegex "^(.*)/(.*)/(python([0-9]+)_d)${CMAKE_IMPORT_LIBRARY_SUFFIX}$") endif() - foreach(lib IN LISTS PYTHON_LIBRARIES) + foreach(lib IN LISTS Python3_LIBRARIES) if (lib MATCHES ${PythonRegex}) if (CMAKE_BUILD_TYPE STREQUAL "Debug") set(PythonZipFileName "python${CMAKE_MATCH_4}_d.zip") @@ -105,8 +97,8 @@ if (_library_enabled) endif() extend_qtc_library(qtcreatorcdbext - DEPENDS "${PYTHON_LIBRARIES}" - INCLUDES "${PYTHON_INCLUDE_DIR}" + DEPENDS "${Python3_LIBRARIES}" + INCLUDES "${Python3_INCLUDE_DIRS}" DEFINES WITH_PYTHON=1 SOURCES pycdbextmodule.cpp pycdbextmodule.h diff --git a/src/tools/iostool/CMakeLists.txt b/src/tools/iostool/CMakeLists.txt index 230f5b91f43..e02bf7463d4 100644 --- a/src/tools/iostool/CMakeLists.txt +++ b/src/tools/iostool/CMakeLists.txt @@ -21,9 +21,5 @@ add_qtc_executable(iostool ) if (TARGET iostool) - if (CMAKE_VERSION VERSION_LESS 3.13) - target_link_libraries(iostool PRIVATE "-Wl,-sectcreate,__TEXT,__info_plist,${CMAKE_CURRENT_SOURCE_DIR}/Info.plist") - else() - target_link_options(iostool PRIVATE "-Wl,-sectcreate,__TEXT,__info_plist,${CMAKE_CURRENT_SOURCE_DIR}/Info.plist") - endif() + target_link_options(iostool PRIVATE "-Wl,-sectcreate,__TEXT,__info_plist,${CMAKE_CURRENT_SOURCE_DIR}/Info.plist") endif() diff --git a/src/tools/sdktool/CMakeLists.txt b/src/tools/sdktool/CMakeLists.txt index 486ec21d071..7726969b307 100644 --- a/src/tools/sdktool/CMakeLists.txt +++ b/src/tools/sdktool/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.10) +cmake_minimum_required(VERSION 3.16) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake") diff --git a/src/tools/wininterrupt/CMakeLists.txt b/src/tools/wininterrupt/CMakeLists.txt index b16e2e1e65b..4a41fa7b08f 100644 --- a/src/tools/wininterrupt/CMakeLists.txt +++ b/src/tools/wininterrupt/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.10) +cmake_minimum_required(VERSION 3.16) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake") diff --git a/tests/auto/debugger/CMakeLists.txt b/tests/auto/debugger/CMakeLists.txt index bde1800a637..5ab4c63f244 100644 --- a/tests/auto/debugger/CMakeLists.txt +++ b/tests/auto/debugger/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.10) +cmake_minimum_required(VERSION 3.16) if (NOT QT_CREATOR_API_DEFINED) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake") diff --git a/tests/manual/qml/testprojects/modulemapping/CMakeLists.txt b/tests/manual/qml/testprojects/modulemapping/CMakeLists.txt index a138dd3f98a..4160cc976c3 100644 --- a/tests/manual/qml/testprojects/modulemapping/CMakeLists.txt +++ b/tests/manual/qml/testprojects/modulemapping/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.13) +cmake_minimum_required(VERSION 3.16) project(test_project) add_executable(test_exe test.cc test.qml) diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index f6712030bdb..815b20fa182 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.10) +cmake_minimum_required(VERSION 3.16) if (NOT QT_CREATOR_API_DEFINED) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake")