diff options
author | Eike Ziller <[email protected]> | 2022-06-02 13:26:23 +0200 |
---|---|---|
committer | Eike Ziller <[email protected]> | 2022-06-02 13:26:23 +0200 |
commit | d7ba5a84b07113c9be4b2c318a3996fa910a799b (patch) | |
tree | b7b5632479c460a19810c3fd3c402b640eedc251 | |
parent | 1241761035d4441431bb69d3f9449a40ca63168f (diff) | |
parent | 5de18c67f0bfde653d290c7e3b32fda573630358 (diff) |
Merge remote-tracking branch 'origin/8.0'
Change-Id: I024823b6667947895eff7570286cc11ee09d3e1d
167 files changed, 2080 insertions, 1261 deletions
diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-creating.qdoc b/doc/qtcreator/src/projects/creator-only/creator-projects-creating.qdoc index c89efd5a465..6acd3667a1f 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-projects-creating.qdoc +++ b/doc/qtcreator/src/projects/creator-only/creator-projects-creating.qdoc @@ -122,20 +122,26 @@ to desktop, embedded, and mobile target platforms. \row \li {1,4} Application (Qt for Python) - \li Qt for Python - Empty + \li Empty Application \li Creates a \l{https://doc.qt.io/qtforpython/index.html} {Qt for Python} application that contains only the main code for a QApplication. \row - \li Qt for Python - Window + \li Empty Window \li Creates a Qt for Python application that contains an empty window. \row - \li Qt for Python - Window (UI file) + \li Window UI + \li Creates a Qt for Python application that contains an empty + window with a widget-based UI. Preferred approach that requires + you to generate a Python file from the .ui file, to import + it directly into your application. + \row + \li Window UI - Dynamic load \li Creates a Qt for Python application that contains an empty window with a widget-based UI. \row - \li Qt for Python - Qt Quick Application + \li Qt Quick Application - Empty \li Creates a Python project that contains an empty Qt Quick Application. \row diff --git a/share/qtcreator/qml/qmlpuppet/commands/createscenecommand.h b/share/qtcreator/qml/qmlpuppet/commands/createscenecommand.h index 1eb6ba5018d..c69d478875d 100644 --- a/share/qtcreator/qml/qmlpuppet/commands/createscenecommand.h +++ b/share/qtcreator/qml/qmlpuppet/commands/createscenecommand.h @@ -28,6 +28,8 @@ #include <QSize> #include <QUrl> #include <QVector> +#include <QList> +#include <QColor> #include <qmetatype.h> #include "instancecontainer.h" @@ -58,7 +60,8 @@ public: const QString &language, QSize captureImageMinimumSize, QSize captureImageMaximumSize, - qint32 stateInstanceId) + qint32 stateInstanceId, + const QList<QColor> &edit3dBackgroundColor) : instances(instanceContainer) , reparentInstances(reparentContainer) , ids(idVector) @@ -74,6 +77,7 @@ public: , captureImageMinimumSize(captureImageMinimumSize) , captureImageMaximumSize(captureImageMaximumSize) , stateInstanceId{stateInstanceId} + , edit3dBackgroundColor{edit3dBackgroundColor} {} friend QDataStream &operator<<(QDataStream &out, const CreateSceneCommand &command) @@ -93,6 +97,7 @@ public: out << command.stateInstanceId; out << command.captureImageMinimumSize; out << command.captureImageMaximumSize; + out << command.edit3dBackgroundColor; return out; } @@ -114,6 +119,7 @@ public: in >> command.stateInstanceId; in >> command.captureImageMinimumSize; in >> command.captureImageMaximumSize; + in >> command.edit3dBackgroundColor; return in; } @@ -134,6 +140,7 @@ public: QSize captureImageMinimumSize; QSize captureImageMaximumSize; qint32 stateInstanceId = 0; + QList<QColor> edit3dBackgroundColor; }; QDebug operator<<(QDebug debug, const CreateSceneCommand &command); diff --git a/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.cpp b/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.cpp index 211fe6d54bd..c32f7b0ffe9 100644 --- a/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.cpp +++ b/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.cpp @@ -30,24 +30,27 @@ namespace QmlDesigner { -View3DActionCommand::View3DActionCommand(Type type, bool enable) +View3DActionCommand::View3DActionCommand(Type type, const QVariant &value) : m_type(type) - , m_enabled(enable) - , m_position(0) + , m_value(value) { } View3DActionCommand::View3DActionCommand(int pos) : m_type(ParticlesSeek) - , m_enabled(true) - , m_position(pos) + , m_value(pos) { } bool View3DActionCommand::isEnabled() const { - return m_enabled; + return m_value.toBool(); +} + +QVariant View3DActionCommand::value() const +{ + return m_value; } View3DActionCommand::Type View3DActionCommand::type() const @@ -57,29 +60,32 @@ View3DActionCommand::Type View3DActionCommand::type() const int View3DActionCommand::position() const { - return m_position; + bool ok = false; + int result = m_value.toInt(&ok); + if (!ok) { + qWarning() << "View3DActionCommand: returning a position that is not int; command type = " + << m_type; + } + + return result; } QDataStream &operator<<(QDataStream &out, const View3DActionCommand &command) { - out << qint32(command.isEnabled()); + out << command.value(); out << qint32(command.type()); - out << qint32(command.position()); return out; } QDataStream &operator>>(QDataStream &in, View3DActionCommand &command) { - qint32 enabled; + QVariant value; qint32 type; - qint32 pos; - in >> enabled; + in >> value; in >> type; - in >> pos; - command.m_enabled = bool(enabled); + command.m_value = value; command.m_type = View3DActionCommand::Type(type); - command.m_position = pos; return in; } @@ -88,7 +94,7 @@ QDebug operator<<(QDebug debug, const View3DActionCommand &command) { return debug.nospace() << "View3DActionCommand(type: " << command.m_type << "," - << command.m_enabled << ")"; + << command.m_value << ")\n"; } } // namespace QmlDesigner diff --git a/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h b/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h index cb34c253f9e..cc3611df764 100644 --- a/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h +++ b/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h @@ -26,6 +26,7 @@ #pragma once #include <QMetaType> +#include <QVariant> namespace QmlDesigner { @@ -55,20 +56,22 @@ public: ParticlesPlay, ParticlesRestart, ParticlesSeek, + SelectBackgroundColor, + ResetBackgroundColor, }; - explicit View3DActionCommand(Type type, bool enable); + explicit View3DActionCommand(Type type, const QVariant &value); View3DActionCommand() = default; bool isEnabled() const; + QVariant value() const; Type type() const; int position() const; private: Type m_type = Empty; - bool m_enabled = false; - int m_position = 0; + QVariant m_value; protected: View3DActionCommand(int pos); diff --git a/share/qtcreator/qml/qmlpuppet/editor3d_qt6.qrc b/share/qtcreator/qml/qmlpuppet/editor3d_qt6.qrc index e8d66548c32..05459423349 100644 --- a/share/qtcreator/qml/qmlpuppet/editor3d_qt6.qrc +++ b/share/qtcreator/qml/qmlpuppet/editor3d_qt6.qrc @@ -32,7 +32,6 @@ <file>mockfiles/qt6/FadeHandle.qml</file> <file>mockfiles/qt6/HelperGrid.qml</file> <file>mockfiles/qt6/IconGizmo.qml</file> - <file>mockfiles/qt6/IconRenderer3D.qml</file> <file>mockfiles/qt6/LightGizmo.qml</file> <file>mockfiles/qt6/LightIconGizmo.qml</file> <file>mockfiles/qt6/LightModel.qml</file> diff --git a/share/qtcreator/qml/qmlpuppet/interfaces/nodeinstanceserverinterface.cpp b/share/qtcreator/qml/qmlpuppet/interfaces/nodeinstanceserverinterface.cpp index 413906267ac..a8b3c319408 100644 --- a/share/qtcreator/qml/qmlpuppet/interfaces/nodeinstanceserverinterface.cpp +++ b/share/qtcreator/qml/qmlpuppet/interfaces/nodeinstanceserverinterface.cpp @@ -142,6 +142,7 @@ void NodeInstanceServerInterface::registerCommands() registerCommand<View3DActionCommand>("View3DActionCommand"); registerCommand<RequestModelNodePreviewImageCommand>("RequestModelNodePreviewImageCommand"); registerCommand<QPair<int, int>>("QPairIntInt"); + registerCommand<QList<QColor>>("QColorList"); registerCommand<ChangeLanguageCommand>("ChangeLanguageCommand"); registerCommand<ChangePreviewImageSizeCommand>("ChangePreviewImageSizeCommand"); registerCommand<CapturedDataCommand>("CapturedDataCommand"); diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/EditView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/EditView3D.qml index 904a062a623..9a95ca34b98 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/EditView3D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/EditView3D.qml @@ -45,6 +45,8 @@ Item { property bool usePerspective: true property bool globalOrientation: false property alias contentItem: contentItem + property color backgroundGradientColorStart: "#222222" + property color backgroundGradientColorEnd: "#999999" enum SelectionMode { Item, Group } enum TransformMode { Move, Rotate, Scale } @@ -212,6 +214,15 @@ Item { cameraControl.alignView(selectedNodes); } + function updateViewStates(viewStates) + { + if ("selectBackgroundColor" in viewStates) { + var color = viewStates.selectBackgroundColor + backgroundGradientColorStart = color[0]; + backgroundGradientColorEnd = color[1]; + } + } + // If resetToDefault is true, tool states not specifically set to anything will be reset to // their default state. function updateToolStates(toolStates, resetToDefault) @@ -329,6 +340,15 @@ Item { function handleObjectClicked(object, multi) { + if (object instanceof View3D) { + // View3D can be the resolved pick target in case the 3D editor is showing content + // of a component that has View3D as root. In that case locking is resolved on C++ side + // and we ignore multiselection. + selectObjects([]); + selectionChanged([object]); + return; + } + var clickedObject; // Click on locked object is treated same as click on empty space @@ -721,8 +741,8 @@ Item { anchors.fill: parent gradient: Gradient { - GradientStop { position: 1.0; color: "#222222" } - GradientStop { position: 0.0; color: "#999999" } + GradientStop { position: 1.0; color: backgroundGradientColorStart } + GradientStop { position: 0.0; color: backgroundGradientColorEnd } } MouseArea { @@ -740,7 +760,7 @@ Item { handleObjectClicked(_generalHelper.resolvePick(pickResult.objectHit), mouse.modifiers & Qt.ControlModifier); - if (pickResult.objectHit) { + if (pickResult.objectHit && pickResult.objectHit instanceof Node) { if (transformMode === EditView3D.TransformMode.Move) freeDraggerArea = moveGizmo.freeDraggerArea; else if (transformMode === EditView3D.TransformMode.Rotate) diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/MaterialNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/MaterialNodeView.qml index 06320524bf3..c36d8c227c3 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/MaterialNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/MaterialNodeView.qml @@ -32,7 +32,7 @@ View3D { property Material previewMaterial - function fitToViewPort() + function fitToViewPort(closeUp) { // No need to zoom this view, this is here just to avoid runtime warnings } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNode3DImageView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNode3DImageView.qml index de3e3ee431c..a6d5c6b1db5 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNode3DImageView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNode3DImageView.qml @@ -41,6 +41,8 @@ Item { property var modelViewComponent property var nodeViewComponent + property bool closeUp: false + function destroyView() { previewObject = null; @@ -96,7 +98,15 @@ Item { function fitToViewPort() { - view.fitToViewPort(); + view.fitToViewPort(closeUp); + } + + // Enables/disables icon mode. When in icon mode, camera is zoomed bit closer to reduce margins + // and the background is removed, in order to generate a preview suitable for library icons. + function setIconMode(enable) + { + closeUp = enable; + backgroundRect.visible = !enable; } View3D { @@ -108,10 +118,15 @@ Item { id: contentItem anchors.fill: parent - Rectangle { + Item { id: viewRect anchors.fill: parent + } + Rectangle { + id: backgroundRect + anchors.fill: parent + z: -1 gradient: Gradient { GradientStop { position: 1.0; color: "#222222" } GradientStop { position: 0.0; color: "#999999" } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNodeView.qml index e61a9a8fb25..5c8b9e1cd72 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNodeView.qml @@ -34,11 +34,11 @@ View3D { property Model sourceModel - function fitToViewPort() + function fitToViewPort(closeUp) { // The magic number is the distance from camera default pos to origin - _generalHelper.calculateNodeBoundsAndFocusCamera(theCamera, importScene, root, - 1040); + _generalHelper.calculateNodeBoundsAndFocusCamera(theCamera, sourceModel, root, + 1040, closeUp); } SceneEnvironment { diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/NodeNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/NodeNodeView.qml index 91008abb251..e8931719d7f 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/NodeNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/NodeNodeView.qml @@ -32,11 +32,11 @@ View3D { environment: sceneEnv camera: theCamera - function fitToViewPort() + function fitToViewPort(closeUp) { // The magic number is the distance from camera default pos to origin _generalHelper.calculateNodeBoundsAndFocusCamera(theCamera, importScene, root, - 1040); + 1040, closeUp); } SceneEnvironment { diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditView3D.qml index 25297f8fc67..228154a9a49 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditView3D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditView3D.qml @@ -46,6 +46,8 @@ Item { property bool usePerspective: true property bool globalOrientation: false property alias contentItem: contentItem + property color backgroundGradientColorStart: "#222222" + property color backgroundGradientColorEnd: "#999999" enum SelectionMode { Item, Group } enum TransformMode { Move, Rotate, Scale } @@ -206,6 +208,15 @@ Item { cameraControl.alignView(selectedNodes); } + function updateViewStates(viewStates) + { + if ("selectBackgroundColor" in viewStates) { + var color = viewStates.selectBackgroundColor + backgroundGradientColorStart = color[0]; + backgroundGradientColorEnd = color[1]; + } + } + // If resetToDefault is true, tool states not specifically set to anything will be reset to // their default state. function updateToolStates(toolStates, resetToDefault) @@ -329,6 +340,15 @@ Item { function handleObjectClicked(object, multi) { + if (object instanceof View3D) { + // View3D can be the resolved pick target in case the 3D editor is showing content + // of a component that has View3D as root. In that case locking is resolved on C++ side + // and we ignore multiselection. + selectObjects([]); + selectionChanged([object]); + return; + } + var clickedObject; // Click on locked object is treated same as click on empty space @@ -866,8 +886,8 @@ Item { anchors.fill: parent gradient: Gradient { - GradientStop { position: 1.0; color: "#222222" } - GradientStop { position: 0.0; color: "#999999" } + GradientStop { position: 1.0; color: backgroundGradientColorStart } + GradientStop { position: 0.0; color: backgroundGradientColorEnd } } MouseArea { @@ -892,7 +912,7 @@ Item { handleObjectClicked(resolvedResult, mouse.modifiers & Qt.ControlModifier); - if (pickResult.objectHit) { + if (pickResult.objectHit && pickResult.objectHit instanceof Node) { if (transformMode === EditView3D.TransformMode.Move) freeDraggerArea = moveGizmo.freeDraggerArea; else if (transformMode === EditView3D.TransformMode.Rotate) diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/IconRenderer3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/IconRenderer3D.qml deleted file mode 100644 index 623bf21cdec..00000000000 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/IconRenderer3D.qml +++ /dev/null @@ -1,88 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 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. -** -****************************************************************************/ - -import QtQuick 6.0 -import QtQuick3D 6.0 - -Item { - id: viewRoot - width: 1024 - height: 1024 - visible: true - - property alias view3D: view3D - property alias camPos: viewCamera.position - - function setSceneToBox() - { - selectionBox.targetNode = view3D.importScene; - } - - function fitAndHideBox() - { - cameraControl.focusObject(selectionBox.model, viewCamera.eulerRotation, true, true); - if (cameraControl._zoomFactor < 0.1) - view3D.importScene.scale = view3D.importScene.scale.times(10); - if (cameraControl._zoomFactor > 10) - view3D.importScene.scale = view3D.importScene.scale.times(0.1); - - selectionBox.visible = false; - } - - View3D { - id: view3D - camera: viewCamera - environment: sceneEnv - - SceneEnvironment { - id: sceneEnv - antialiasingMode: SceneEnvironment.MSAA - antialiasingQuality: SceneEnvironment.VeryHigh - } - - PerspectiveCamera { - id: viewCamera - position: Qt.vector3d(-200, 200, 200) - eulerRotation: Qt.vector3d(-45, -45, 0) - } - - DirectionalLight { - rotation: viewCamera.rotation - } - - SelectionBox { - id: selectionBox - view3D: view3D - geometryName: "SB" - } - - EditCameraController { - id: cameraControl - camera: view3D.camera - view3d: view3D - ignoreToolState: true - } - } -} diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/MaterialNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/MaterialNodeView.qml index aae5891e082..ed5cfea56f4 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/MaterialNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/MaterialNodeView.qml @@ -32,7 +32,7 @@ View3D { property Material previewMaterial - function fitToViewPort() + function fitToViewPort(closeUp) { // No need to zoom this view, this is here just to avoid runtime warnings } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNode3DImageView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNode3DImageView.qml index 4bd07e57d12..5caac0047c4 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNode3DImageView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNode3DImageView.qml @@ -41,6 +41,8 @@ Item { property var modelViewComponent property var nodeViewComponent + property bool closeUp: false + function destroyView() { previewObject = null; @@ -96,17 +98,30 @@ Item { function fitToViewPort() { - view.fitToViewPort(); + view.fitToViewPort(closeUp); + } + + // Enables/disables icon mode. When in icon mode, camera is zoomed bit closer to reduce margins + // and the background is removed, in order to generate a preview suitable for library icons. + function setIconMode(enable) + { + closeUp = enable; + backgroundRect.visible = !enable; } Item { id: contentItem anchors.fill: parent - Rectangle { + Item { id: viewRect anchors.fill: parent + } + Rectangle { + id: backgroundRect + anchors.fill: parent + z: -1 gradient: Gradient { GradientStop { position: 1.0; color: "#222222" } GradientStop { position: 0.0; color: "#999999" } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml index 19b3c4c35d7..1762e3c9a4d 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml @@ -34,11 +34,11 @@ View3D { property Model sourceModel - function fitToViewPort() + function fitToViewPort(closeUp) { // The magic number is the distance from camera default pos to origin _generalHelper.calculateNodeBoundsAndFocusCamera(theCamera, sourceModel, root, - 1040); + 1040, closeUp); } SceneEnvironment { diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/NodeNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/NodeNodeView.qml index a48eb665191..7bbfbf281ac 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/NodeNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/NodeNodeView.qml @@ -32,11 +32,11 @@ View3D { environment: sceneEnv camera: theCamera - function fitToViewPort() + function fitToViewPort(closeUp) { // The magic number is the distance from camera default pos to origin _generalHelper.calculateNodeBoundsAndFocusCamera(theCamera, importScene, root, - 1040); + 1040, closeUp); } SceneEnvironment { diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp index 3b774c3f4a6..dd21622b5dc 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp @@ -308,7 +308,7 @@ QVector4D GeneralHelper::focusNodesToCamera(QQuick3DCamera *camera, float defaul // and recalculating bounds for every frame is not a problem. void GeneralHelper::calculateNodeBoundsAndFocusCamera( QQuick3DCamera *camera, QQuick3DNode *node, QQuick3DViewport *viewPort, - float defaultLookAtDistance) + float defaultLookAtDistance, bool closeUp) { QVector3D minBounds; QVector3D maxBounds; @@ -317,7 +317,9 @@ void GeneralHelper::calculateNodeBoundsAndFocusCamera( QVector3D extents = maxBounds - minBounds; QVector3D lookAt = minBounds + (extents / 2.f); - float maxExtent = qMax(extents.x(), qMax(extents.y(), extents.z())); + float maxExtent = qSqrt(qreal(extents.x()) * qreal(extents.x()) + + qreal(extents.y()) * qreal(extents.y()) + + qreal(extents.z()) * qreal(extents.z())); // Reset camera position to default zoom QMatrix4x4 m = camera->sceneTransform(); @@ -328,9 +330,27 @@ void GeneralHelper::calculateNodeBoundsAndFocusCamera( camera->setPosition(lookAt + newLookVector); - float newZoomFactor = maxExtent / 725.f; // Divisor taken from focusNodesToCamera function + // CloseUp divisor is used for icon generation, where we can allow some extreme models to go + // slightly out of bounds for better results generally. The other divisor is used for other + // previews, where the image is larger to begin with and we would also like some margin + // between preview edge and the rendered model, so we can be more conservative with the zoom. + // The divisor values are empirically selected to provide nice result. + float divisor = closeUp ? 1250.f : 1050.f; + float newZoomFactor = maxExtent / divisor; zoomCamera(viewPort, camera, 0, defaultLookAtDistance, lookAt, newZoomFactor, false); + + if (auto perspectiveCamera = qobject_cast<QQuick3DPerspectiveCamera *>(camera)) { + // Fix camera near/far clips in case we are dealing with extreme zooms + const float cameraDist = qAbs((camera->position() - lookAt).length()); + const float minDist = cameraDist - (maxExtent / 2.f); + const float maxDist = cameraDist + (maxExtent / 2.f); + if (minDist < perspectiveCamera->clipNear() || maxDist > perspectiveCamera->clipFar()) { + perspectiveCamera->setClipNear(minDist * 0.99); + perspectiveCamera->setClipFar(maxDist * 1.01); + } + + } } // Aligns any cameras found in nodes list to a camera. @@ -418,15 +438,15 @@ QQuick3DPickResult GeneralHelper::pickViewAt(QQuick3DViewport *view, float posX, return QQuick3DPickResult(); } -QQuick3DNode *GeneralHelper::resolvePick(QQuick3DNode *pickNode) +QObject *GeneralHelper::resolvePick(QQuick3DNode *pickNode) { if (pickNode) { - // Check if the picked node actually specifies another node as the pick target + // Check if the picked node actually specifies another object as the pick target QVariant componentVar = pickNode->property("_pickTarget"); if (componentVar.isValid()) { - auto componentNode = componentVar.value<QQuick3DNode *>(); - if (componentNode) - return componentNode; + auto componentObj = componentVar.value<QObject *>(); + if (componentObj) + return componentObj; } } return pickNode; @@ -823,12 +843,13 @@ bool GeneralHelper::getBounds(QQuick3DViewport *view3D, QQuick3DNode *node, QVec if (auto childNode = qobject_cast<QQuick3DNode *>(child)) { QVector3D newMinBounds = minBounds; QVector3D newMaxBounds = maxBounds; - hasModel = getBounds(view3D, childNode, newMinBounds, newMaxBounds, true); + bool childHasModel = getBounds(view3D, childNode, newMinBounds, newMaxBounds, true); // Ignore any subtrees that do not have Model in them as we don't need those // for visual bounds calculations - if (hasModel) { + if (childHasModel) { minBoundsVec << newMinBounds; maxBoundsVec << newMaxBounds; + hasModel = true; } } } diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h index 562848c7720..5bb1fa1662f 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h @@ -77,7 +77,7 @@ public: bool closeUp = false); Q_INVOKABLE void calculateNodeBoundsAndFocusCamera(QQuick3DCamera *camera, QQuick3DNode *node, QQuick3DViewport *viewPort, - float defaultLookAtDistance); + float defaultLookAtDistance, bool closeUp); Q_INVOKABLE void alignCameras(QQuick3DCamera *camera, const QVariant &nodes); Q_INVOKABLE QVector3D alignView(QQuick3DCamera *camera, const QVariant &nodes, const QVector3D &lookAtPoint); @@ -85,7 +85,7 @@ public: Q_INVOKABLE void delayedPropertySet(QObject *obj, int delay, const QString &property, const QVariant& value); Q_INVOKABLE QQuick3DPickResult pickViewAt(QQuick3DViewport *view, float posX, float posY); - Q_INVOKABLE QQuick3DNode *resolvePick(QQuick3DNode *pickNode); + Q_INVOKABLE QObject *resolvePick(QQuick3DNode *pickNode); Q_INVOKABLE bool isLocked(QQuick3DNode *node) const; Q_INVOKABLE bool isHidden(QQuick3DNode *node) const; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/import3d/import3d.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/import3d/import3d.cpp index 5f448b90da5..1f24aaca8f8 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/import3d/import3d.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/import3d/import3d.cpp @@ -77,9 +77,8 @@ void import3D(const QString &sourceAsset, const QString &outDir, const QString & } } - // Allow little time for file operations to finish - QTimer::singleShot(2000, nullptr, []() { - qApp->exit(0); + QTimer::singleShot(0, nullptr, []() { + qApp->quit(); }); } diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp index 8400c3d4474..41c67f70b68 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp @@ -1561,6 +1561,10 @@ void NodeInstanceServer::handleInstanceHidden(const ServerNodeInstance &/*instan { } +void NodeInstanceServer::handlePickTarget(const ServerNodeInstance &/*instance*/) +{ +} + void NodeInstanceServer::setupState(qint32 stateInstanceId) { if (hasInstanceForId(stateInstanceId)) { diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h index ba51f5e5888..42f345ee4e5 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h @@ -226,6 +226,7 @@ public: virtual void handleInstanceLocked(const ServerNodeInstance &instance, bool enable, bool checkAncestors); virtual void handleInstanceHidden(const ServerNodeInstance &instance, bool enable, bool checkAncestors); + virtual void handlePickTarget(const ServerNodeInstance &instance); virtual QImage grabWindow() = 0; virtual QImage grabItem(QQuickItem *item) = 0; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp index 8059a240a6c..c6acc5e5f9d 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp @@ -553,7 +553,18 @@ void Qt5InformationNodeInstanceServer::handleSelectionChanged(const QVariant &ob auto obj = object.value<QObject *>(); if (obj) { ServerNodeInstance instance = instanceForObject(obj); - instanceList << instance; + // If instance is a View3D, make sure it is not locked + bool locked = false; + if (instance.isSubclassOf("QQuick3DViewport")) { + locked = instance.internalInstance()->isLockedInEditor(); + auto parentInst = instance.parent(); + while (!locked && parentInst.isValid()) { + locked = parentInst.internalInstance()->isLockedInEditor(); + parentInst = parentInst.parent(); + } + } + if (!locked) + instanceList << instance; #ifdef QUICK3D_PARTICLES_MODULE if (!skipSystemDeselect) { auto particleSystem = parentParticleSystem(instance.internalObject()); @@ -1452,8 +1463,9 @@ void Qt5InformationNodeInstanceServer::handleSelectionChangeTimeout() void Qt5InformationNodeInstanceServer::handleDynamicAddObjectTimeout() { -#ifdef QUICK3D_MODULE for (auto obj : std::as_const(m_dynamicObjectConstructors)) { +#if QT_VERSION < QT_VERSION_CHECK(6, 2, 1) +#ifdef QUICK3D_MODULE auto handleHiding = [this](QQuick3DNode *node) -> bool { if (node && hasInstanceForObject(node)) { ServerNodeInstance instance = instanceForObject(node); @@ -1468,8 +1480,22 @@ void Qt5InformationNodeInstanceServer::handleDynamicAddObjectTimeout() if (auto pickTarget = obj->property("_pickTarget").value<QQuick3DNode *>()) handleHiding(pickTarget); } - } #endif +#else + auto handlePicking = [this](QObject *object) -> bool { + if (object && hasInstanceForObject(object)) { + ServerNodeInstance instance = instanceForObject(object); + handlePickTarget(instance); + return true; + } + return false; + }; + if (!handlePicking(obj)) { + if (auto pickTarget = obj->property("_pickTarget").value<QObject *>()) + handlePicking(pickTarget); + } +#endif + } m_dynamicObjectConstructors.clear(); } @@ -1932,6 +1958,12 @@ void Qt5InformationNodeInstanceServer::createScene(const CreateSceneCommand &com #ifdef IMPORT_QUICK3D_ASSETS QTimer::singleShot(0, this, &Qt5InformationNodeInstanceServer::resolveImportSupport); #endif + + if (!command.edit3dBackgroundColor.isEmpty()) { + View3DActionCommand backgroundColorCommand(View3DActionCommand::SelectBackgroundColor, + QVariant::fromValue(command.edit3dBackgroundColor)); + view3DAction(backgroundColorCommand); + } } void Qt5InformationNodeInstanceServer::sendChildrenChangedCommand(const QList<ServerNodeInstance> &childList) @@ -2147,18 +2179,19 @@ void Qt5InformationNodeInstanceServer::view3DAction(const View3DActionCommand &c if (!m_editView3DSetupDone) return; - QVariantMap updatedState; + QVariantMap updatedToolState; + QVariantMap updatedViewState; int renderCount = 1; switch (command.type()) { case View3DActionCommand::MoveTool: - updatedState.insert("transformMode", 0); + updatedToolState.insert("transformMode", 0); break; case View3DActionCommand::RotateTool: - updatedState.insert("transformMode", 1); + updatedToolState.insert("transformMode", 1); break; case View3DActionCommand::ScaleTool: - updatedState.insert("transformMode", 2); + updatedToolState.insert("transformMode", 2); break; case View3DActionCommand::FitToView: QMetaObject::invokeMethod(m_editView3DData.rootItem, "fitToView"); @@ -2170,38 +2203,42 @@ void Qt5InformationNodeInstanceServer::view3DAction(const View3DActionCommand &c QMetaObject::invokeMethod(m_editView3DData.rootItem, "alignViewToCamera"); break; case View3DActionCommand::SelectionModeToggle: - updatedState.insert("selectionMode", command.isEnabled() ? 1 : 0); + updatedToolState.insert("selectionMode", command.isEnabled() ? 1 : 0); break; case View3DActionCommand::CameraToggle: - updatedState.insert("usePerspective", command.isEnabled()); + updatedToolState.insert("usePerspective", command.isEnabled()); // It can take a couple frames to properly update icon gizmo positions renderCount = 2; break; case View3DActionCommand::OrientationToggle: - updatedState.insert("globalOrientation", command.isEnabled()); + updatedToolState.insert("globalOrientation", command.isEnabled()); break; case View3DActionCommand::EditLightToggle: - updatedState.insert("showEditLight", command.isEnabled()); + updatedToolState.insert("showEditLight", command.isEnabled()); break; case View3DActionCommand::ShowGrid: - updatedState.insert("showGrid", command.isEnabled()); + updatedToolState.insert("showGrid", command.isEnabled()); break; case View3DActionCommand::ShowSelectionBox: - updatedState.insert("showSelectionBox", command.isEnabled()); + updatedToolState.insert("showSelectionBox", command.isEnabled()); break; case View3DActionCommand::ShowIconGizmo: - updatedState.insert("showIconGizmo", command.isEnabled()); + updatedToolState.insert("showIconGizmo", command.isEnabled()); break; case View3DActionCommand::ShowCameraFrustum: - updatedState.insert("showCameraFrustum", command.isEnabled()); + updatedToolState.insert("showCameraFrustum", command.isEnabled()); + break; + case View3DActionCommand::SelectBackgroundColor: { + updatedViewState.insert("selectBackgroundColor", command.value()); break; + } #ifdef QUICK3D_PARTICLES_MODULE case View3DActionCommand::ShowParticleEmitter: - updatedState.insert("showParticleEmitter", command.isEnabled()); + updatedToolState.insert("showParticleEmitter", command.isEnabled()); break; case View3DActionCommand::ParticlesPlay: m_particleAnimationPlaying = command.isEnabled(); - updatedState.insert("particlePlay", command.isEnabled()); + updatedToolState.insert("particlePlay", command.isEnabled()); if (m_particleAnimationPlaying) { m_particleAnimationDriver->play(); m_particleAnimationDriver->setSeekerEnabled(false); @@ -2227,12 +2264,17 @@ void Qt5InformationNodeInstanceServer::view3DAction(const View3DActionCommand &c break; } - if (!updatedState.isEmpty()) { + if (!updatedToolState.isEmpty()) { QMetaObject::invokeMethod(m_editView3DData.rootItem, "updateToolStates", - Q_ARG(QVariant, updatedState), + Q_ARG(QVariant, updatedToolState), Q_ARG(QVariant, QVariant::fromValue(false))); } + if (!updatedViewState.isEmpty()) { + QMetaObject::invokeMethod(m_editView3DData.rootItem, "updateViewStates", + Q_ARG(QVariant, updatedViewState)); + } + render3DEditView(renderCount); } @@ -2332,9 +2374,9 @@ void Qt5InformationNodeInstanceServer::handleInstanceLocked(const ServerNodeInst } } #else - Q_UNUSED(instance); - Q_UNUSED(enable); - Q_UNUSED(checkAncestors); + Q_UNUSED(instance) + Q_UNUSED(enable) + Q_UNUSED(checkAncestors) #endif } @@ -2388,6 +2430,7 @@ void Qt5InformationNodeInstanceServer::handleInstanceHidden(const ServerNodeInst // Don't override explicit hide in children handleInstanceHidden(quick3dInstance, edit3dHidden || isInstanceHidden, false); } else { +#if QT_VERSION < QT_VERSION_CHECK(6, 2, 1) // Children of components do not have instances, but will still need to be pickable std::function<void(QQuick3DNode *)> checkChildren; checkChildren = [&](QQuick3DNode *checkNode) { @@ -2402,9 +2445,7 @@ void Qt5InformationNodeInstanceServer::handleInstanceHidden(const ServerNodeInst value = QVariant::fromValue(node); // Specify the actual pick target with dynamic property checkModel->setProperty("_pickTarget", value); -#if QT_VERSION < QT_VERSION_CHECK(6, 2, 1) checkModel->setPickable(!edit3dHidden); -#endif } else { auto checkRepeater = qobject_cast<QQuick3DRepeater *>(checkNode); auto checkLoader = qobject_cast<QQuick3DLoader *>(checkNode); @@ -2436,13 +2477,102 @@ void Qt5InformationNodeInstanceServer::handleInstanceHidden(const ServerNodeInst }; if (auto childNode = qobject_cast<QQuick3DNode *>(childItem)) checkChildren(childNode); +#endif } } } #else - Q_UNUSED(instance); - Q_UNUSED(enable); - Q_UNUSED(checkAncestors); + Q_UNUSED(instance) + Q_UNUSED(enable) + Q_UNUSED(checkAncestors) +#endif +} + +void Qt5InformationNodeInstanceServer::handlePickTarget(const ServerNodeInstance &instance) +{ +#if defined(QUICK3D_MODULE) && (QT_VERSION >= QT_VERSION_CHECK(6, 2, 1)) + // Picking is dependent on hidden status prior to global picking support (<6.2.1), so it is + // handled in handleInstanceHidden() method in those builds + + if (!ViewConfig::isQuick3DMode()) + return; + + QObject *obj = instance.internalObject(); + QList<QQuick3DObject *> childItems; + if (auto node = qobject_cast<QQuick3DNode *>(obj)) { + childItems = node->childItems(); + } else if (auto view = qobject_cast<QQuick3DViewport *>(obj)) { + // We only need to handle views that are components + // View is a component if its scene is not an instance and scene has node children that + // have no instances + QQuick3DNode *node = view->scene(); + if (node) { + if (hasInstanceForObject(node)) + return; + childItems = node->childItems(); + bool allHaveInstance = true; + for (const auto &childItem : childItems) { + if (qobject_cast<QQuick3DNode *>(childItem) && !hasInstanceForObject(childItem)) { + allHaveInstance = false; + break; + } + } + if (allHaveInstance) + return; + } + } else { + return; + } + + for (auto childItem : qAsConst(childItems)) { + if (!hasInstanceForObject(childItem)) { + // Children of components do not have instances, but will still need to be pickable + // and redirect their pick to the component + std::function<void(QQuick3DNode *)> checkChildren; + checkChildren = [&](QQuick3DNode *checkNode) { + const auto childItems = checkNode->childItems(); + for (auto child : childItems) { + if (auto childNode = qobject_cast<QQuick3DNode *>(child)) + checkChildren(childNode); + } + if (auto checkModel = qobject_cast<QQuick3DModel *>(checkNode)) { + // Specify the actual pick target with dynamic property + checkModel->setProperty("_pickTarget", QVariant::fromValue(obj)); + } else { + auto checkRepeater = qobject_cast<QQuick3DRepeater *>(checkNode); + auto checkLoader = qobject_cast<QQuick3DLoader *>(checkNode); +#if defined(QUICK3D_ASSET_UTILS_MODULE) + auto checkRunLoader = qobject_cast<QQuick3DRuntimeLoader *>(checkNode); + if (checkRepeater || checkLoader || checkRunLoader) { +#else + if (checkRepeater || checkLoader) { +#endif + // Repeaters/loaders may not yet have created their children, so we set + // _pickTarget on them and connect the notifier. + if (checkNode->property("_pickTarget").isNull()) { + if (checkRepeater) { + QObject::connect(checkRepeater, &QQuick3DRepeater::objectAdded, + this, &Qt5InformationNodeInstanceServer::handleDynamicAddObject); +#if defined(QUICK3D_ASSET_UTILS_MODULE) + } else if (checkRunLoader) { + QObject::connect(checkRunLoader, &QQuick3DRuntimeLoader::statusChanged, + this, &Qt5InformationNodeInstanceServer::handleDynamicAddObject); +#endif + } else { + QObject::connect(checkLoader, &QQuick3DLoader::loaded, + this, &Qt5InformationNodeInstanceServer::handleDynamicAddObject); + } + } + checkNode->setProperty("_pickTarget", QVariant::fromValue(obj)); + } + } + }; + if (auto childNode = qobject_cast<QQuick3DNode *>(childItem)) + checkChildren(childNode); + } + } +#else + Q_UNUSED(instance) #endif } diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h index b6375076b66..291b2c3eecd 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h @@ -80,6 +80,7 @@ public: void handleInstanceLocked(const ServerNodeInstance &instance, bool enable, bool checkAncestors) override; void handleInstanceHidden(const ServerNodeInstance &instance, bool enable, bool checkAncestors) override; + void handlePickTarget(const ServerNodeInstance &instance) override; bool isInformationServer() const override; void handleDynamicAddObject(); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3drenderablenodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3drenderablenodeinstance.cpp index 589f57cb5f1..cae64ad04c1 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3drenderablenodeinstance.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3drenderablenodeinstance.cpp @@ -57,6 +57,9 @@ void Quick3DRenderableNodeInstance::initialize(const ObjectNodeInstance::Pointer // In case this is the scene root, we need to create a dummy View3D for the scene // in preview puppets if (instanceId() == 0 && (!nodeInstanceServer()->isInformationServer())) { + nodeInstanceServer()->quickWindow()->setDefaultAlphaBuffer(true); + nodeInstanceServer()->quickWindow()->setColor(Qt::transparent); + auto helper = new QmlDesigner::Internal::GeneralHelper(); engine()->rootContext()->setContextProperty("_generalHelper", helper); @@ -199,6 +202,14 @@ QQuickItem *Quick3DRenderableNodeInstance::contentItem() const return m_dummyRootView; } +void Quick3DRenderableNodeInstance::setPropertyVariant(const PropertyName &name, + const QVariant &value) +{ + if (m_dummyRootView && name == "isLibraryIcon") + QMetaObject::invokeMethod(m_dummyRootView, "setIconMode", Q_ARG(QVariant, value)); + ObjectNodeInstance::setPropertyVariant(name, value); +} + Qt5NodeInstanceServer *Quick3DRenderableNodeInstance::qt5NodeInstanceServer() const { return qobject_cast<Qt5NodeInstanceServer *>(nodeInstanceServer()); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3drenderablenodeinstance.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3drenderablenodeinstance.h index ae03cb1b90f..208144cb52f 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3drenderablenodeinstance.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3drenderablenodeinstance.h @@ -52,6 +52,7 @@ public: QList<ServerNodeInstance> stateInstances() const override; QQuickItem *contentItem() const override; + void setPropertyVariant(const PropertyName &name, const QVariant &value) override; protected: explicit Quick3DRenderableNodeInstance(QObject *node); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp index a4fdde97ec2..2f4be3e8e9b 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp @@ -323,8 +323,12 @@ ServerNodeInstance ServerNodeInstance::create(NodeInstanceServer *nodeInstanceSe instance.internalInstance()->initialize(instance.m_nodeInstance, instanceContainer.metaFlags()); +#if QT_VERSION < QT_VERSION_CHECK(6, 2, 1) // Handle hidden state to initialize pickable state nodeInstanceServer->handleInstanceHidden(instance, false, false); +#else + nodeInstanceServer->handlePickTarget(instance); +#endif return instance; } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComboBox.qml index 48ec9fa470a..b9d9f323169 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComboBox.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComboBox.qml @@ -41,6 +41,8 @@ StudioControls.ComboBox { onModelChanged: colorLogic.invalidate() + hasActiveDrag: comboBox.backendValue !== undefined && comboBox.backendValue.hasActiveDrag + // This is available in all editors. onValueTypeChanged: { @@ -83,16 +85,15 @@ StudioControls.ComboBox { onEntered: (drag) => { dropArea.assetPath = drag.getDataAsString(drag.keys[0]).split(",")[0] - - drag.accepted = comboBox.backendValue !== undefined && comboBox.backendValue.isSupportedDrop(dropArea.assetPath) - comboBox.hasActiveDrag = drag.accepted + drag.accepted = comboBox.backendValue !== undefined && comboBox.backendValue.hasActiveDrag + comboBox.hasActiveHoverDrag = drag.accepted } - onExited: comboBox.hasActiveDrag = false + onExited: comboBox.hasActiveHoverDrag = false onDropped: { comboBox.backendValue.commitDrop(dropArea.assetPath) - comboBox.hasActiveDrag = false + comboBox.hasActiveHoverDrag = false } } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBox.qml index fbd4f530626..70cbdf000ec 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBox.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBox.qml @@ -39,7 +39,8 @@ T.ComboBox { && myComboBox.enabled property bool edit: myComboBox.activeFocus && myComboBox.editable property bool open: comboBoxPopup.opened - property bool hasActiveDrag: false + property bool hasActiveDrag: false // an item that can be dropped on the combobox is being dragged + property bool hasActiveHoverDrag: false // an item that can be dropped on the combobox is being hovered on the combobox property bool dirty: false // user modification flag @@ -49,6 +50,9 @@ T.ComboBox { property alias textInput: comboBoxInput + property int borderWidth: myComboBox.hasActiveHoverDrag ? StudioTheme.Values.borderHover + : StudioTheme.Values.border + signal compressedActivated(int index, int reason) enum ActivatedReason { EditingFinished, Other } @@ -57,7 +61,7 @@ T.ComboBox { height: StudioTheme.Values.defaultControlHeight leftPadding: actionIndicator.width - rightPadding: popupIndicator.width + StudioTheme.Values.border + rightPadding: popupIndicator.width + myComboBox.borderWidth font.pixelSize: StudioTheme.Values.myFontSize wheelEnabled: false @@ -87,6 +91,7 @@ T.ComboBox { myControl: myComboBox text: myComboBox.editText + borderWidth: myComboBox.borderWidth onEditingFinished: { comboBoxInput.deselect() @@ -108,16 +113,16 @@ T.ComboBox { myControl: myComboBox myPopup: myComboBox.popup x: comboBoxInput.x + comboBoxInput.width - y: StudioTheme.Values.border - width: StudioTheme.Values.checkIndicatorWidth - StudioTheme.Values.border - height: StudioTheme.Values.checkIndicatorHeight - (StudioTheme.Values.border * 2) + y: myComboBox.borderWidth + width: StudioTheme.Values.checkIndicatorWidth - myComboBox.borderWidth + height: StudioTheme.Values.checkIndicatorHeight - myComboBox.borderWidth * 2 } background: Rectangle { id: comboBoxBackground color: StudioTheme.Values.themeControlBackground border.color: StudioTheme.Values.themeControlOutline - border.width: StudioTheme.Values.border + border.width: myComboBox.borderWidth x: actionIndicator.width width: myComboBox.width - actionIndicator.width height: myComboBox.height @@ -144,7 +149,7 @@ T.ComboBox { width: comboBoxPopup.width - comboBoxPopup.leftPadding - comboBoxPopup.rightPadding - (comboBoxPopupScrollBar.visible ? comboBoxPopupScrollBar.contentItem.implicitWidth + 2 : 0) // TODO Magic number - height: StudioTheme.Values.height - 2 * StudioTheme.Values.border + height: StudioTheme.Values.height - 2 * myComboBox.borderWidth padding: 0 enabled: model.enabled === undefined ? true : model.enabled @@ -198,9 +203,9 @@ T.ComboBox { popup: T.Popup { id: comboBoxPopup - x: actionIndicator.width + StudioTheme.Values.border + x: actionIndicator.width + myComboBox.borderWidth y: myComboBox.height - width: myComboBox.width - actionIndicator.width - (StudioTheme.Values.border * 2) + width: myComboBox.width - actionIndicator.width - myComboBox.borderWidth * 2 // TODO Setting the height on the popup solved the problem with the popup of height 0, // but it has the problem that it sometimes extend over the border of the actual window // and is then cut off. @@ -208,7 +213,7 @@ T.ComboBox { + comboBoxPopup.bottomPadding, myComboBox.Window.height - topMargin - bottomMargin, StudioTheme.Values.maxComboBoxPopupHeight) - padding: StudioTheme.Values.border + padding: myComboBox.borderWidth margins: 0 // If not defined margin will be -1 closePolicy: T.Popup.CloseOnPressOutside | T.Popup.CloseOnPressOutsideParent | T.Popup.CloseOnEscape | T.Popup.CloseOnReleaseOutside @@ -252,8 +257,9 @@ T.ComboBox { PropertyChanges { target: comboBoxBackground color: StudioTheme.Values.themeControlBackground - border.color: hasActiveDrag ? StudioTheme.Values.themeInteraction - : StudioTheme.Values.themeControlOutline + border.color: myComboBox.hasActiveDrag ? StudioTheme.Values.themeInteraction + : StudioTheme.Values.themeControlOutline + border.width: myComboBox.borderWidth } }, // This state is intended for ComboBoxes which aren't editable, but have focus e.g. via diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBoxInput.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBoxInput.qml index de7dcc1f8c3..c6b91dc1ad0 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBoxInput.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBoxInput.qml @@ -34,6 +34,7 @@ TextInput { property bool edit: textInput.activeFocus property bool hover: mouseArea.containsMouse && textInput.enabled + property int borderWidth: StudioTheme.Values.border z: 2 font: myControl.font @@ -55,11 +56,11 @@ TextInput { Rectangle { id: textInputBackground - x: StudioTheme.Values.border - y: StudioTheme.Values.border + x: textInput.borderWidth + y: textInput.borderWidth z: -1 width: textInput.width - height: StudioTheme.Values.height - (StudioTheme.Values.border * 2) + height: StudioTheme.Values.height - textInput.borderWidth * 2 color: StudioTheme.Values.themeControlBackground border.width: 0 } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Values.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Values.qml index 75d21a8e29b..d9bf43db746 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Values.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Values.qml @@ -86,6 +86,7 @@ QtObject { property real marginTopBottom: 4 property real border: 1 + property real borderHover: 3 property real maxComboBoxPopupHeight: Math.round(300 * values.scaleFactor) property real maxTextAreaPopupHeight: Math.round(150 * values.scaleFactor) diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/wizard.json b/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/wizard.json index ae3719243e6..9d60367997a 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/wizard.json +++ b/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/wizard.json @@ -17,21 +17,23 @@ { "key": "ProjectPluginName", "value": "%{ProjectName}plugin" }, { "key": "ProjectPluginClassName", "value": "%{ProjectName}Plugin" }, { "key": "QmlProjectFileName", "value": "%{JS: Util.fileName('%{ProjectName}', 'qmlproject')}" }, + { "key": "IsQt6Project", "value": "%{JS: value('QtQuickVersion') !== '2.15' }" }, { "key": "ImportModuleName", "value": "%{ProjectName}" }, { "key": "UIClassName", "value": "Screen01" }, { "key": "UIClassFileName", "value": "%{JS: Util.fileName('%{UIClassName}', 'ui.qml')}" }, { "key": "QtQuickVersion", "value": "%{JS: %{TargetQtVersion}.TargetQuickVersion}" }, { "key": "QtQuickFeature", "value": "QtSupport.Wizards.FeatureQtQuick.%{QtQuickVersion}" }, - { "key": "QtQuickControlsStyle", "value": "%{JS: %{ControlsStyle}.QtQuickControlsStyle}" }, + { "key": "QtQuickControlsStyleInternalQt5", "value": "%{JS: %{ControlsStyle}.QtQuickControlsStyle}" }, + { "key": "QtQuickControlsStyleInternalQt6", "value": "%{JS: value('QtQuickControlsStyleInternalQt5') === 'Default' ? 'Basic' : value('QtQuickControlsStyleInternalQt5')}" }, + { "key": "QtQuickControlsStyle", "value": "%{JS: value('IsQt6Project') === 'true' ? value('QtQuickControlsStyleInternalQt6') : value('QtQuickControlsStyleInternalQt5')}" }, { "key": "QtQuickControlsStyleTheme", "value": "%{JS: %{ControlsStyle}.QtQuickControlsStyleTheme}" }, - { "key": "ApplicationImport", "value": "%{JS: value('QtQuickVersion') === '' ? '%{ImportModuleName}' : '%{ImportModuleName} 1.0'}" }, + { "key": "ApplicationImport", "value": "%{JS: value('IsQt6Project') === 'true' ? '%{ImportModuleName}' : '%{ImportModuleName} 1.0'}" }, { "key": "UseStandardResolution", "value": "%{JS: value('CustomScreenWidth') === '' || value('CustomScreenHeight') === ''}" }, { "key": "ScreenWidth", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenWidth : value('CustomScreenWidth')}" }, { "key": "ScreenHeight", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenHeight : value('CustomScreenHeight')}" }, { "key": "UseVirtualKeyboardDefault", "value": "%{JS: false}" }, { "key": "QtQuick3DVersion", "value": "%{JS: %{TargetQtVersion}.TargetQuick3DVersion}" }, - { "key": "IsQt6Project", "value": "%{JS: value('QtQuickVersion') === '' }" }, - { "key": "ImportModuleVersion", "value": "%{JS: value('QtQuickVersion') === '' ? '' : '1.0'}" } + { "key": "ImportModuleVersion", "value": "%{JS: value('IsQt6Project') === 'true' ? '' : '1.0'}" } ], "pages": @@ -243,21 +245,24 @@ "trKey": "Qt 5", "value": "({ - 'TargetQuickVersion': '2.15' + 'TargetQuickVersion': '2.15', + 'TargetQuick3DVersion': '1.15' })" }, { "trKey": "Qt 6.2", "value": "({ - 'TargetQuickVersion': '6.2' + 'TargetQuickVersion': '6.2', + 'TargetQuick3DVersion': '6.2' })" }, { "trKey": "Qt 6.3", "value": "({ - 'TargetQuickVersion': '6.3' + 'TargetQuickVersion': '6.3', + 'TargetQuick3DVersion': '6.3' })" } ] diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/application/wizard.json b/share/qtcreator/qmldesigner/studio_templates/projects/application/wizard.json index 51acc18af26..3e7ef11beb7 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/application/wizard.json +++ b/share/qtcreator/qmldesigner/studio_templates/projects/application/wizard.json @@ -20,20 +20,20 @@ { "key": "ImportModuleName", "value": "%{ProjectName}" }, { "key": "UIClassName", "value": "Screen01" }, { "key": "UIClassFileName", "value": "%{JS: Util.fileName('%{UIClassName}', 'ui.qml')}" }, + { "key": "IsQt6Project", "value": "%{JS: value('QtQuickVersion') !== '2.15' }" }, { "key": "QtQuickVersion", "value": "%{JS: %{TargetQtVersion}.TargetQuickVersion}" }, { "key": "QtQuickFeature", "value": "QtSupport.Wizards.FeatureQtQuick.%{QtQuickVersion}" }, { "key": "QtQuickControlsStyleInternalQt5", "value": "%{JS: %{ControlsStyle}.QtQuickControlsStyle}" }, { "key": "QtQuickControlsStyleInternalQt6", "value": "%{JS: value('QtQuickControlsStyleInternalQt5') === 'Default' ? 'Basic' : value('QtQuickControlsStyleInternalQt5')}" }, - { "key": "QtQuickControlsStyle", "value": "%{JS: value('QtQuickVersion') === '' ? value('QtQuickControlsStyleInternalQt6') : value('QtQuickControlsStyleInternalQt5')}" }, + { "key": "QtQuickControlsStyle", "value": "%{JS: value('IsQt6Project') === 'true' ? value('QtQuickControlsStyleInternalQt6') : value('QtQuickControlsStyleInternalQt5')}" }, { "key": "QtQuickControlsStyleTheme", "value": "%{JS: %{ControlsStyle}.QtQuickControlsStyleTheme}" }, - { "key": "ApplicationImport", "value": "%{JS: value('QtQuickVersion') === '' ? '%{ImportModuleName}' : '%{ImportModuleName} 1.0'}" }, + { "key": "ApplicationImport", "value": "%{JS: value('IsQt6Project') === 'true' ? '%{ImportModuleName}' : '%{ImportModuleName} 1.0'}" }, { "key": "UseStandardResolution", "value": "%{JS: value('CustomScreenWidth') === '' || value('CustomScreenHeight') === ''}" }, { "key": "ScreenWidth", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenWidth : value('CustomScreenWidth')}" }, { "key": "ScreenHeight", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenHeight : value('CustomScreenHeight')}" }, { "key": "UseVirtualKeyboardDefault", "value": "%{JS: false}" }, - { "key": "IsQt6Project", "value": "%{JS: value('QtQuickVersion') === '' }" }, - { "key": "DefaultStyle", "value": "%{JS: value('QtQuickVersion') === '' ? 'Basic' : 'Default'}" }, - { "key": "ImportModuleVersion", "value": "%{JS: value('QtQuickVersion') === '' ? '' : '1.0'}" } + { "key": "DefaultStyle", "value": "%{JS: value('IsQt6Project') === 'true' ? 'Basic' : 'Default'}" }, + { "key": "ImportModuleVersion", "value": "%{JS: value('IsQt6Project') === 'true' ? '' : '1.0'}" } ], "pages": diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/desktop-launcher/wizard.json b/share/qtcreator/qmldesigner/studio_templates/projects/desktop-launcher/wizard.json index f687b2ce385..20a3baba9c7 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/desktop-launcher/wizard.json +++ b/share/qtcreator/qmldesigner/studio_templates/projects/desktop-launcher/wizard.json @@ -20,17 +20,19 @@ { "key": "ImportModuleName", "value": "%{ProjectName}" }, { "key": "UIClassName", "value": "Screen01" }, { "key": "UIClassFileName", "value": "%{JS: Util.fileName('%{UIClassName}', 'ui.qml')}" }, + { "key": "IsQt6Project", "value": "%{JS: value('QtQuickVersion') !== '2.15' }" }, { "key": "QtQuickVersion", "value": "%{JS: %{TargetQtVersion}.TargetQuickVersion}" }, { "key": "QtQuickFeature", "value": "QtSupport.Wizards.FeatureQtQuick.%{QtQuickVersion}" }, - { "key": "QtQuickControlsStyle", "value": "%{JS: %{ControlsStyle}.QtQuickControlsStyle}" }, + { "key": "QtQuickControlsStyleInternalQt5", "value": "%{JS: %{ControlsStyle}.QtQuickControlsStyle}" }, + { "key": "QtQuickControlsStyleInternalQt6", "value": "%{JS: value('QtQuickControlsStyleInternalQt5') === 'Default' ? 'Basic' : value('QtQuickControlsStyleInternalQt5')}" }, + { "key": "QtQuickControlsStyle", "value": "%{JS: value('IsQt6Project') === 'true' ? value('QtQuickControlsStyleInternalQt6') : value('QtQuickControlsStyleInternalQt5')}" }, { "key": "QtQuickControlsStyleTheme", "value": "%{JS: %{ControlsStyle}.QtQuickControlsStyleTheme}" }, - { "key": "ApplicationImport", "value": "%{JS: value('QtQuickVersion') === '' ? '%{ImportModuleName}' : '%{ImportModuleName} 1.0'}" }, + { "key": "ApplicationImport", "value": "%{JS: value('IsQt6Project') === 'true' ? '%{ImportModuleName}' : '%{ImportModuleName} 1.0'}" }, { "key": "UseStandardResolution", "value": "%{JS: value('CustomScreenWidth') === '' || value('CustomScreenHeight') === ''}" }, { "key": "ScreenWidth", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenWidth : value('CustomScreenWidth')}" }, { "key": "ScreenHeight", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenHeight : value('CustomScreenHeight')}" }, { "key": "UseVirtualKeyboardDefault", "value": "%{JS: false}" }, - { "key": "IsQt6Project", "value": "%{JS: value('QtQuickVersion') === '' }" }, - { "key": "ImportModuleVersion", "value": "%{JS: value('QtQuickVersion') === '' ? '' : '1.0'}" } + { "key": "ImportModuleVersion", "value": "%{JS: value('IsQt6Project') === 'true' ? '' : '1.0'}" } ], "pages": @@ -236,7 +238,6 @@ { "index": 1, "items": - "items": [ { "trKey": "Qt 5", diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/mobile-scroll/wizard.json b/share/qtcreator/qmldesigner/studio_templates/projects/mobile-scroll/wizard.json index d12fc38bdc4..3117c7e0544 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/mobile-scroll/wizard.json +++ b/share/qtcreator/qmldesigner/studio_templates/projects/mobile-scroll/wizard.json @@ -18,19 +18,19 @@ { "key": "ProjectPluginClassName", "value": "%{ProjectName}Plugin" }, { "key": "QmlProjectFileName", "value": "%{JS: Util.fileName('%{ProjectName}', 'qmlproject')}" }, { "key": "ImportModuleName", "value": "%{ProjectName}" }, - { "key": "UIClassName", "value": "Screen01" }, - { "key": "UIClassFileName", "value": "%{JS: Util.fileName('%{UIClassName}', 'ui.qml')}" }, + { "key": "IsQt6Project", "value": "%{JS: value('QtQuickVersion') !== '2.15' }" }, { "key": "QtQuickVersion", "value": "%{JS: %{TargetQtVersion}.TargetQuickVersion}" }, { "key": "QtQuickFeature", "value": "QtSupport.Wizards.FeatureQtQuick.%{QtQuickVersion}" }, - { "key": "QtQuickControlsStyle", "value": "%{JS: %{ControlsStyle}.QtQuickControlsStyle}" }, + { "key": "QtQuickControlsStyleInternalQt5", "value": "%{JS: %{ControlsStyle}.QtQuickControlsStyle}" }, + { "key": "QtQuickControlsStyleInternalQt6", "value": "%{JS: value('QtQuickControlsStyleInternalQt5') === 'Default' ? 'Basic' : value('QtQuickControlsStyleInternalQt5')}" }, + { "key": "QtQuickControlsStyle", "value": "%{JS: value('IsQt6Project') === 'true' ? value('QtQuickControlsStyleInternalQt6') : value('QtQuickControlsStyleInternalQt5')}" }, { "key": "QtQuickControlsStyleTheme", "value": "%{JS: %{ControlsStyle}.QtQuickControlsStyleTheme}" }, - { "key": "ApplicationImport", "value": "%{JS: value('QtQuickVersion') === '' ? '%{ImportModuleName}' : '%{ImportModuleName} 1.0'}" }, + { "key": "ApplicationImport", "value": "%{JS: value('IsQt6Project') === 'true' ? '%{ImportModuleName}' : '%{ImportModuleName} 1.0'}" }, { "key": "UseStandardResolution", "value": "%{JS: value('CustomScreenWidth') === '' || value('CustomScreenHeight') === ''}" }, { "key": "ScreenWidth", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenWidth : value('CustomScreenWidth')}" }, { "key": "ScreenHeight", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenHeight : value('CustomScreenHeight')}" }, { "key": "UseVirtualKeyboard", "value": "%{JS: false}" }, - { "key": "IsQt6Project", "value": "%{JS: value('QtQuickVersion') === '' }" }, - { "key": "ImportModuleVersion", "value": "%{JS: value('QtQuickVersion') === '' ? '' : '1.0'}" } + { "key": "ImportModuleVersion", "value": "%{JS: value('IsQt6Project') === 'true' ? '' : '1.0'}" } ], "pages": diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/mobile-stack/wizard.json b/share/qtcreator/qmldesigner/studio_templates/projects/mobile-stack/wizard.json index 1b76c290359..cb083e84f4b 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/mobile-stack/wizard.json +++ b/share/qtcreator/qmldesigner/studio_templates/projects/mobile-stack/wizard.json @@ -18,17 +18,19 @@ { "key": "ProjectPluginClassName", "value": "%{ProjectName}Plugin" }, { "key": "QmlProjectFileName", "value": "%{JS: Util.fileName('%{ProjectName}', 'qmlproject')}" }, { "key": "ImportModuleName", "value": "%{ProjectName}" }, + { "key": "IsQt6Project", "value": "%{JS: value('QtQuickVersion') !== '2.15' }" }, { "key": "QtQuickVersion", "value": "%{JS: %{TargetQtVersion}.TargetQuickVersion}" }, { "key": "QtQuickFeature", "value": "QtSupport.Wizards.FeatureQtQuick.%{QtQuickVersion}" }, - { "key": "QtQuickControlsStyle", "value": "%{JS: %{ControlsStyle}.QtQuickControlsStyle}" }, + { "key": "QtQuickControlsStyleInternalQt5", "value": "%{JS: %{ControlsStyle}.QtQuickControlsStyle}" }, + { "key": "QtQuickControlsStyleInternalQt6", "value": "%{JS: value('QtQuickControlsStyleInternalQt5') === 'Default' ? 'Basic' : value('QtQuickControlsStyleInternalQt5')}" }, + { "key": "QtQuickControlsStyle", "value": "%{JS: value('IsQt6Project') === 'true' ? value('QtQuickControlsStyleInternalQt6') : value('QtQuickControlsStyleInternalQt5')}" }, { "key": "QtQuickControlsStyleTheme", "value": "%{JS: %{ControlsStyle}.QtQuickControlsStyleTheme}" }, - { "key": "ApplicationImport", "value": "%{JS: value('QtQuickVersion') === '' ? '%{ImportModuleName}' : '%{ImportModuleName} 1.0'}" }, + { "key": "ApplicationImport", "value": "%{JS: value('IsQt6Project') === 'true' ? '%{ImportModuleName}' : '%{ImportModuleName} 1.0'}" }, { "key": "UseStandardResolution", "value": "%{JS: value('CustomScreenWidth') === '' || value('CustomScreenHeight') === ''}" }, { "key": "ScreenWidth", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenWidth : value('CustomScreenWidth')}" }, { "key": "ScreenHeight", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenHeight : value('CustomScreenHeight')}" }, { "key": "UseVirtualKeyboard", "value": "%{JS: false}" }, - { "key": "IsQt6Project", "value": "%{JS: value('QtQuickVersion') === '' }" }, - { "key": "ImportModuleVersion", "value": "%{JS: value('QtQuickVersion') === '' ? '' : '1.0'}" } + { "key": "ImportModuleVersion", "value": "%{JS: value('IsQt6Project') === 'true' ? '' : '1.0'}" } ], "pages": diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/mobile-swipe/wizard.json b/share/qtcreator/qmldesigner/studio_templates/projects/mobile-swipe/wizard.json index 19e5865fb83..1c1137afddb 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/mobile-swipe/wizard.json +++ b/share/qtcreator/qmldesigner/studio_templates/projects/mobile-swipe/wizard.json @@ -18,17 +18,19 @@ { "key": "ProjectPluginClassName", "value": "%{ProjectName}Plugin" }, { "key": "QmlProjectFileName", "value": "%{JS: Util.fileName('%{ProjectName}', 'qmlproject')}" }, { "key": "ImportModuleName", "value": "%{ProjectName}" }, + { "key": "IsQt6Project", "value": "%{JS: value('QtQuickVersion') !== '2.15' }" }, { "key": "QtQuickVersion", "value": "%{JS: %{TargetQtVersion}.TargetQuickVersion}" }, { "key": "QtQuickFeature", "value": "QtSupport.Wizards.FeatureQtQuick.%{QtQuickVersion}" }, - { "key": "QtQuickControlsStyle", "value": "%{JS: %{ControlsStyle}.QtQuickControlsStyle}" }, + { "key": "QtQuickControlsStyleInternalQt5", "value": "%{JS: %{ControlsStyle}.QtQuickControlsStyle}" }, + { "key": "QtQuickControlsStyleInternalQt6", "value": "%{JS: value('QtQuickControlsStyleInternalQt5') === 'Default' ? 'Basic' : value('QtQuickControlsStyleInternalQt5')}" }, + { "key": "QtQuickControlsStyle", "value": "%{JS: value('IsQt6Project') === 'true' ? value('QtQuickControlsStyleInternalQt6') : value('QtQuickControlsStyleInternalQt5')}" }, { "key": "QtQuickControlsStyleTheme", "value": "%{JS: %{ControlsStyle}.QtQuickControlsStyleTheme}" }, - { "key": "ApplicationImport", "value": "%{JS: value('QtQuickVersion') === '' ? '%{ImportModuleName}' : '%{ImportModuleName} 1.0'}" }, + { "key": "ApplicationImport", "value": "%{JS: value('IsQt6Project') === 'true' ? '%{ImportModuleName}' : '%{ImportModuleName} 1.0'}" }, { "key": "UseStandardResolution", "value": "%{JS: value('CustomScreenWidth') === '' || value('CustomScreenHeight') === ''}" }, { "key": "ScreenWidth", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenWidth : value('CustomScreenWidth')}" }, { "key": "ScreenHeight", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenHeight : value('CustomScreenHeight')}" }, { "key": "UseVirtualKeyboard", "value": "%{JS: false}" }, - { "key": "IsQt6Project", "value": "%{JS: value('QtQuickVersion') === '' }" }, - { "key": "ImportModuleVersion", "value": "%{JS: value('QtQuickVersion') === '' ? '' : '1.0'}" } + { "key": "ImportModuleVersion", "value": "%{JS: value('IsQt6Project') === 'true' ? '' : '1.0'}" } ], "pages": diff --git a/share/qtcreator/templates/wizards/classes/python/wizard.json b/share/qtcreator/templates/wizards/classes/python/wizard.json index 7a86aa341e5..d42d8f0ab52 100644 --- a/share/qtcreator/templates/wizards/classes/python/wizard.json +++ b/share/qtcreator/templates/wizards/classes/python/wizard.json @@ -38,7 +38,7 @@ "type": "ComboBox", "data": { - "items": ["<None>", "PySide2", "PySide6", "PyQt5"] + "items": ["<None>", "PySide6", "PySide2", "PyQt6", "PyQt5"] } }, { diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/empty/wizard.json b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/empty/wizard.json index 268fc6bd9e6..7a032fc0f11 100644 --- a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/empty/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/empty/wizard.json @@ -4,7 +4,7 @@ "id": "F.QtForPythonApplicationEmpty", "category": "F.ApplicationPySide", "trDescription": "Creates a Qt for Python application that contains only the main code for a QApplication.", - "trDisplayName": "Qt for Python - Empty", + "trDisplayName": "Empty Application", "trDisplayCategory": "Application (Qt for Python)", "icon": "icon.png", "iconKind": "Themed", diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main_empty.py b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main_empty.py index ec9a1ffa718..e8a45b363c0 100644 --- a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main_empty.py +++ b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main_empty.py @@ -4,6 +4,10 @@ from %{PySideVersion}.QtWidgets import QApplication if __name__ == "__main__": - app = QApplication([]) + app = QApplication(sys.argv) # ... +@if '%{PySideVersion}' === 'PySide6' + sys.exit(app.exec()) +@else sys.exit(app.exec_()) +@endif diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main_mainwindow.py b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main_mainwindow.py index b0afe88e987..102840cc298 100644 --- a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main_mainwindow.py +++ b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main_mainwindow.py @@ -16,12 +16,9 @@ class %{Class}(%{BaseCB}): @else class %{Class}: @endif - def __init__(self): -@if '%{BaseCB}' === 'QWidget' - QWidget.__init__(self) -@endif -@if '%{BaseCB}' === 'QMainWindow' - QMainWindow.__init__(self) + def __init__(self, parent=None): +@if '%{BaseCB}' === 'QWidget' || '%{BaseCB}' === 'QMainWindow' + super().__init__(parent) @endif @if '%{BaseCB}' === '' pass # call __init__(self) of the custom base class here @@ -36,4 +33,8 @@ if __name__ == "__main__": @else window.show() @endif +@if '%{PySideVersion}' === 'PySide6' + sys.exit(app.exec()) +@else sys.exit(app.exec_()) +@endif diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main_qtquick.py b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main_qtquick.py index 2bb159fd05c..2c410825c8b 100644 --- a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main_qtquick.py +++ b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main_qtquick.py @@ -1,7 +1,6 @@ # This Python file uses the following encoding: utf-8 -import os -from pathlib import Path import sys +from pathlib import Path from %{PySideVersion}.QtGui import QGuiApplication from %{PySideVersion}.QtQml import QQmlApplicationEngine @@ -10,7 +9,16 @@ from %{PySideVersion}.QtQml import QQmlApplicationEngine if __name__ == "__main__": app = QGuiApplication(sys.argv) engine = QQmlApplicationEngine() - engine.load(os.fspath(Path(__file__).resolve().parent / "%{QmlFileName}")) + qml_file = Path(__file__).resolve().parent / "%{QmlFileName}" +@if '%{PySideVersion}' === 'PySide6' + engine.load(qml_file) +@else + engine.load(str(qml_file)) +@endif if not engine.rootObjects(): sys.exit(-1) +@if '%{PySideVersion}' === 'PySide6' + sys.exit(app.exec()) +@else sys.exit(app.exec_()) +@endif diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main_widget.py b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main_widget.py index e00ab451e5d..02b7ab79115 100644 --- a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main_widget.py +++ b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main_widget.py @@ -21,21 +21,29 @@ class %{Class}(%{BaseCB}): @else class %{Class}: @endif - def __init__(self): - super(%{Class}, self).__init__() + def __init__(self, parent=None): + super().__init__(parent) self.load_ui() def load_ui(self): loader = QUiLoader() - path = os.fspath(Path(__file__).resolve().parent / "form.ui") + path = Path(__file__).resolve().parent / "form.ui" +@if '%{PySideVersion}' === 'PySide6' ui_file = QFile(path) +@else + ui_file = QFile(str(path)) +@endif ui_file.open(QFile.ReadOnly) loader.load(ui_file, self) ui_file.close() if __name__ == "__main__": - app = QApplication([]) + app = QApplication(sys.argv) widget = %{Class}() widget.show() +@if '%{PySideVersion}' === 'PySide6' + sys.exit(app.exec()) +@else sys.exit(app.exec_()) +@endif diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main_widget_gen.py b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main_widget_gen.py new file mode 100644 index 00000000000..bd7d4fa807d --- /dev/null +++ b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main_widget_gen.py @@ -0,0 +1,39 @@ +# This Python file uses the following encoding: utf-8 +import sys + +@if '%{BaseCB}' === 'QWidget' +from %{PySideVersion}.QtWidgets import QApplication, QWidget +@endif +@if '%{BaseCB}' === 'QMainWindow' +from %{PySideVersion}.QtWidgets import QApplication, QMainWindow +@endif +@if '%{BaseCB}' === 'QDialog' +from %{PySideVersion}.QtWidgets import QApplication, QDialog +@endif + +# Important: +# You need to run the following command to generate the ui_form.py file +# pyside6-uic form.ui -o ui_form.py, or +# pyside2-uic form.ui -o ui_form.py +from ui_form import Ui_%{Class} + +@if '%{BaseCB}' +class %{Class}(%{BaseCB}): +@else +class %{Class}: +@endif + def __init__(self, parent=None): + super().__init__(parent) + self.ui = Ui_%{Class}() + self.ui.setupUi(self) + + +if __name__ == "__main__": + app = QApplication(sys.argv) + widget = %{Class}() + widget.show() +@if '%{PySideVersion}' === 'PySide6' + sys.exit(app.exec()) +@else + sys.exit(app.exec_()) +@endif diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/mainwindow/wizard.json b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/mainwindow/wizard.json index a16b7fd900a..1e19a607f71 100644 --- a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/mainwindow/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/mainwindow/wizard.json @@ -4,7 +4,7 @@ "id": "F.QtForPythonApplicationWindow", "category": "F.ApplicationPySide", "trDescription": "Creates a Qt for Python application that contains an empty window.", - "trDisplayName": "Qt for Python - Window", + "trDisplayName": "Empty Window", "trDisplayCategory": "Application (Qt for Python)", "icon": "../icons/icon.png", "iconKind": "Themed", diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/qtquickapplication/wizard.json b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/qtquickapplication/wizard.json index 268367d1f6f..68051e52f78 100644 --- a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/qtquickapplication/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/qtquickapplication/wizard.json @@ -4,7 +4,7 @@ "id": "F.QtQuickQtForPythonApplicationEmpty", "category": "F.ApplicationPySide", "trDescription": "Creates a Qt Quick application that contains an empty window.", - "trDisplayName": "Qt for Python - Qt Quick Application - Empty", + "trDisplayName": "Qt Quick Application - Empty", "trDisplayCategory": "Application (Qt for Python)", "icon": "../icons/icon.png", "iconKind": "Themed", diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/widget/wizard.json b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/widget/wizard.json index 6a068d5fd3c..6b2bd45565f 100644 --- a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/widget/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/widget/wizard.json @@ -3,8 +3,8 @@ "supportedProjectTypes": [ "PythonProject" ], "id": "F.QtForPythonApplicationWindowWidget", "category": "F.ApplicationPySide", - "trDescription": "Creates a Qt for Python application that includes a Qt Designer-based widget (ui file)", - "trDisplayName": "Qt for Python - Window (UI file)", + "trDescription": "Creates a Qt for Python application that includes a Qt Designer-based widget (.ui file) - Load the forms dynamically/at runtime", + "trDisplayName": "Window UI - Dynamic load", "trDisplayCategory": "Application (Qt for Python)", "icon": "../icons/icon.png", "iconKind": "Themed", diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/widget_gen/main.pyproject b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/widget_gen/main.pyproject new file mode 100644 index 00000000000..64c2987a8fb --- /dev/null +++ b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/widget_gen/main.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["%{SrcFileName}", "form.ui"] +} diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/widget_gen/wizard.json b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/widget_gen/wizard.json new file mode 100644 index 00000000000..1a2bcec74b4 --- /dev/null +++ b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/widget_gen/wizard.json @@ -0,0 +1,110 @@ +{ + "version": 1, + "supportedProjectTypes": [ "PythonProject" ], + "id": "F.QtForPythonApplicationWindowWidgetGen", + "category": "F.ApplicationPySide", + "trDescription": "Creates a Qt for Python application that includes a Qt Designer-based widget (ui file) - Requires .ui to Python conversion", + "trDisplayName": "Window UI", + "trDisplayCategory": "Application (Qt for Python)", + "icon": "../icons/icon.png", + "iconKind": "Themed", + "enabled": "%{JS: value('Plugins').indexOf('Python') >= 0}", + + "options": + [ + { "key": "SrcFileName", "value": "%{MainFileName}" }, + { "key": "PyProjectFile", "value": "%{ProjectFileName}" } + ], + + "pages": + [ + { + "trDisplayName": "Project Location", + "trShortTitle": "Location", + "typeId": "Project", + "name": "ProjectPath" + }, + { + "trDisplayName": "Define Class", + "trShortTitle": "Details", + "typeId": "Fields", + "data" : + [ + { + "name": "PySideVersion", + "trDisplayName": "PySide version:", + "type": "ComboBox", + "data": { "items": [ "PySide2", "PySide6" ] } + }, + { + "name": "Class", + "trDisplayName": "Class name:", + "mandatory": true, + "type": "LineEdit", + "data": + { + "validator": "(?:(?:[a-zA-Z_][a-zA-Z_0-9]*::)*[a-zA-Z_][a-zA-Z_0-9]*|)", + "trText": "%{JS: value('BaseCB') ? value('BaseCB').slice(1) : 'MyClass'}" + } + + }, + { + "name": "BaseCB", + "trDisplayName": "Base class:", + "type": "ComboBox", + "data": + { + "items": [ "QWidget", "QDialog", "QMainWindow" ] + } + }, + { + "name": "MainFileName", + "type": "LineEdit", + "trDisplayName": "Source file:", + "mandatory": true, + "data": { "trText": "%{JS: Cpp.classToFileName(value('Class'), Util.preferredSuffix('text/x-python'))}" } + }, + { + "name": "ProjectFileName", + "type": "LineEdit", + "trDisplayName": "Project file:", + "mandatory": true, + "data": { "trText": "%{JS: Util.fileName('%{ProjectName}', 'pyproject')}" } + } + ] + }, + { + "trDisplayName": "Project Management", + "trShortTitle": "Summary", + "typeId": "Summary" + } + ], + "generators": + [ + { + "typeId": "File", + "data": + [ + { + "source": "main.pyproject", + "target": "%{PyProjectFile}", + "openAsProject": true + }, + { + "source": "../main_widget_gen.py", + "target": "%{SrcFileName}", + "openInEditor": true + }, + { + "source": "../main_widget.ui", + "target": "form.ui" + }, + { + "source": "../../git.ignore", + "target": ".gitignore", + "condition": "%{JS: !value('IsSubproject') && value('VersionControl') === 'G.Git'}" + } + ] + } + ] +} diff --git a/share/qtcreator/translations/qtcreator_cs.ts b/share/qtcreator/translations/qtcreator_cs.ts index 086b2dfea0b..b7e0efc99e3 100644 --- a/share/qtcreator/translations/qtcreator_cs.ts +++ b/share/qtcreator/translations/qtcreator_cs.ts @@ -32121,16 +32121,16 @@ Spustil jste Qemu?</translation> <translation>Qt %1 (%2)</translation> </message> <message> - <source>%1 does not exist or is not executable</source> - <translation>Soubor %1 neexistuje nebo není spustitelný</translation> + <source>qmake does not exist or is not executable</source> + <translation>Soubor qmake neexistuje nebo není spustitelný</translation> </message> <message> <source>Qt version is not properly installed, please run make install</source> <translation>Verze Qt není správně nainstalována. Proveďte, prosím, příkaz "make install"</translation> </message> <message> - <source>Could not determine the path to the binaries of the Qt installation, maybe the %1 path is wrong?</source> - <translation>Cestu ke spustitelným souborům instalace Qt se nepodařilo určit. Možná je cesta k %1 chybná?</translation> + <source>Could not determine the path to the binaries of the Qt installation, maybe the qmake path is wrong?</source> + <translation>Cestu ke spustitelným souborům instalace Qt se nepodařilo určit. Možná je cesta k qmake chybná?</translation> </message> <message> <source>The default mkspec symlink is broken.</source> diff --git a/share/qtcreator/translations/qtcreator_da.ts b/share/qtcreator/translations/qtcreator_da.ts index 21dd2fad82d..4cfd3841b60 100644 --- a/share/qtcreator/translations/qtcreator_da.ts +++ b/share/qtcreator/translations/qtcreator_da.ts @@ -35382,16 +35382,16 @@ For flere detaljer, se /etc/sysctl.d/10-ptrace.conf <translation>Ingen qmake-sti sat</translation> </message> <message> - <source>%1 does not exist or is not executable</source> - <translation>%1 findes ikke eller er ikke eksekverbar</translation> + <source>qmake does not exist or is not executable</source> + <translation>qmake findes ikke eller er ikke eksekverbar</translation> </message> <message> <source>Qt version is not properly installed, please run make install</source> <translation>Qt version er ikke ordentligt installeret, kør venligst make install</translation> </message> <message> - <source>Could not determine the path to the binaries of the Qt installation, maybe the %1 path is wrong?</source> - <translation>Kunne ikke beslutte stien til binærene af Qt installationen, måske er %1-stien forkert?</translation> + <source>Could not determine the path to the binaries of the Qt installation, maybe the qmake path is wrong?</source> + <translation>Kunne ikke beslutte stien til binærene af Qt installationen, måske er qmake-stien forkert?</translation> </message> <message> <source>The default mkspec symlink is broken.</source> diff --git a/share/qtcreator/translations/qtcreator_de.ts b/share/qtcreator/translations/qtcreator_de.ts index 49d5e966da9..8013bb9b20e 100644 --- a/share/qtcreator/translations/qtcreator_de.ts +++ b/share/qtcreator/translations/qtcreator_de.ts @@ -10113,8 +10113,8 @@ Dies ist unabhängig vom Wert der Eigenschaft "visible" in QML.</trans <translation>Es ist keine qmake-Pfad gesetzt</translation> </message> <message> - <source>%1 does not exist or is not executable</source> - <translation>Die %1-Datei existiert nicht oder ist nicht ausführbar</translation> + <source>qmake does not exist or is not executable</source> + <translation>Die qmake-Datei existiert nicht oder ist nicht ausführbar</translation> </message> <message> <source>Qt version has no name</source> @@ -10141,8 +10141,8 @@ Dies ist unabhängig vom Wert der Eigenschaft "visible" in QML.</trans <translation>Die Qt-Version ist nicht richtig installiert, führen Sie bitte make install aus</translation> </message> <message> - <source>Could not determine the path to the binaries of the Qt installation, maybe the %1 path is wrong?</source> - <translation>Der Pfad zu den ausführbaren Dateien der Qt-Installation konnte nicht bestimmt werden, möglicherweise ist der Pfad zu %1 falsch?</translation> + <source>Could not determine the path to the binaries of the Qt installation, maybe the qmake path is wrong?</source> + <translation>Der Pfad zu den ausführbaren Dateien der Qt-Installation konnte nicht bestimmt werden, möglicherweise ist der Pfad zu qmake falsch?</translation> </message> <message> <source>The default mkspec symlink is broken.</source> diff --git a/share/qtcreator/translations/qtcreator_fr.ts b/share/qtcreator/translations/qtcreator_fr.ts index 2e632c21390..ec42c365792 100644 --- a/share/qtcreator/translations/qtcreator_fr.ts +++ b/share/qtcreator/translations/qtcreator_fr.ts @@ -33604,8 +33604,8 @@ Nous allons essayer de travailler avec cela mais vous pourrez rencontrer des pro <translation>Chemin de qmake non spécifié</translation> </message> <message> - <source>%1 does not exist or is not executable</source> - <translation>%1 n'existe pas ou n'est pas exécutable</translation> + <source>qmake does not exist or is not executable</source> + <translation>qmake n'existe pas ou n'est pas exécutable</translation> </message> <message> <source>Qt version has no name</source> @@ -33633,8 +33633,8 @@ Nous allons essayer de travailler avec cela mais vous pourrez rencontrer des pro <translation>La version de Qt n'est pas correctement installée, veuillez exécuter make install</translation> </message> <message> - <source>Could not determine the path to the binaries of the Qt installation, maybe the %1 path is wrong?</source> - <translation>Impossible de déterminer le chemin vers les programmes de Qt, peut-être que le chemin vers %1 est faux ?</translation> + <source>Could not determine the path to the binaries of the Qt installation, maybe the qmake path is wrong?</source> + <translation>Impossible de déterminer le chemin vers les programmes de Qt, peut-être que le chemin vers qmake est faux ?</translation> </message> <message> <source>The default mkspec symlink is broken.</source> diff --git a/share/qtcreator/translations/qtcreator_hr.ts b/share/qtcreator/translations/qtcreator_hr.ts index c60ce6f3c59..e7a14f06a9c 100644 --- a/share/qtcreator/translations/qtcreator_hr.ts +++ b/share/qtcreator/translations/qtcreator_hr.ts @@ -41628,7 +41628,7 @@ Saving failed.</source> <translation type="unfinished"></translation> </message> <message> - <source>%1 does not exist or is not executable</source> + <source>qmake does not exist or is not executable</source> <translation type="unfinished"></translation> </message> <message> @@ -41636,7 +41636,7 @@ Saving failed.</source> <translation type="unfinished"></translation> </message> <message> - <source>Could not determine the path to the binaries of the Qt installation, maybe the %1 path is wrong?</source> + <source>Could not determine the path to the binaries of the Qt installation, maybe the qmake path is wrong?</source> <translation type="unfinished"></translation> </message> <message> diff --git a/share/qtcreator/translations/qtcreator_ja.ts b/share/qtcreator/translations/qtcreator_ja.ts index 017e3ebc611..c65ccab4138 100644 --- a/share/qtcreator/translations/qtcreator_ja.ts +++ b/share/qtcreator/translations/qtcreator_ja.ts @@ -26108,16 +26108,16 @@ Do you want to save the data first?</source> <translation>qmake のパスが設定されていません</translation> </message> <message> - <source>%1 does not exist or is not executable</source> - <translation>%1 が存在しないか実行可能ではありません</translation> + <source>qmake does not exist or is not executable</source> + <translation>qmake が存在しないか実行可能ではありません</translation> </message> <message> <source>Qt version is not properly installed, please run make install</source> <translation>Qt バージョンが正しくインストールされていません。make install を実行してください</translation> </message> <message> - <source>Could not determine the path to the binaries of the Qt installation, maybe the %1 path is wrong?</source> - <translation>Qt インストール先のパスが特定できませんでした。%1 のパスが間違っていませんか?</translation> + <source>Could not determine the path to the binaries of the Qt installation, maybe the qmake path is wrong?</source> + <translation>Qt インストール先のパスが特定できませんでした。qmake のパスが間違っていませんか?</translation> </message> <message> <source>The default mkspec symlink is broken.</source> diff --git a/share/qtcreator/translations/qtcreator_pl.ts b/share/qtcreator/translations/qtcreator_pl.ts index 288c0333976..4bd2dfddc49 100644 --- a/share/qtcreator/translations/qtcreator_pl.ts +++ b/share/qtcreator/translations/qtcreator_pl.ts @@ -12382,8 +12382,8 @@ Dla projektów CMake, upewnij się, że zmienna QML_IMPORT_PATH jest obecna w CM <translation>Nie ustawiono ścieżki do qmake</translation> </message> <message> - <source>%1 does not exist or is not executable</source> - <translation>Brak %1 lub nie jest on plikiem wykonywalnym</translation> + <source>qmake does not exist or is not executable</source> + <translation>Brak qmake lub nie jest on plikiem wykonywalnym</translation> </message> <message> <source>Qt version has no name</source> @@ -12410,8 +12410,8 @@ Dla projektów CMake, upewnij się, że zmienna QML_IMPORT_PATH jest obecna w CM <translation>Wersja Qt zainstalowana niepoprawnie, uruchom komendę: make install</translation> </message> <message> - <source>Could not determine the path to the binaries of the Qt installation, maybe the %1 path is wrong?</source> - <translation>Nie można określić ścieżki do plików binarnych instalacji Qt. Sprawdź ścieżkę do %1.</translation> + <source>Could not determine the path to the binaries of the Qt installation, maybe the qmake path is wrong?</source> + <translation>Nie można określić ścieżki do plików binarnych instalacji Qt. Sprawdź ścieżkę do qmake.</translation> </message> <message> <source>The default mkspec symlink is broken.</source> diff --git a/share/qtcreator/translations/qtcreator_ru.ts b/share/qtcreator/translations/qtcreator_ru.ts index 038c8b7d562..ca1e07984e3 100644 --- a/share/qtcreator/translations/qtcreator_ru.ts +++ b/share/qtcreator/translations/qtcreator_ru.ts @@ -45319,8 +45319,8 @@ For more details, see /etc/sysctl.d/10-ptrace.conf <translation>Путь к qmake не указан</translation> </message> <message> - <source>%1 does not exist or is not executable</source> - <translation>%1 отсутствует или не запускается</translation> + <source>qmake does not exist or is not executable</source> + <translation>qmake отсутствует или не запускается</translation> </message> <message> <source>Qt version has no name</source> @@ -45347,8 +45347,8 @@ For more details, see /etc/sysctl.d/10-ptrace.conf <translation>Профиль Qt не установлен, пожалуйста выполните make install</translation> </message> <message> - <source>Could not determine the path to the binaries of the Qt installation, maybe the %1 path is wrong?</source> - <translation>Не удалось определить путь к утилитам Qt. Может путь к %1 неверен?</translation> + <source>Could not determine the path to the binaries of the Qt installation, maybe the qmake path is wrong?</source> + <translation>Не удалось определить путь к утилитам Qt. Может путь к qmake неверен?</translation> </message> <message> <source>The default mkspec symlink is broken.</source> diff --git a/share/qtcreator/translations/qtcreator_sl.ts b/share/qtcreator/translations/qtcreator_sl.ts index ed9bf70dfb4..ca8f7d46bb3 100644 --- a/share/qtcreator/translations/qtcreator_sl.ts +++ b/share/qtcreator/translations/qtcreator_sl.ts @@ -21803,8 +21803,8 @@ Projekte programov QML izvede pregledovalnik QML in jih ni potrebno zgraditi.</t </message> <message> <location line="+58"/> - <source>%1 does not exist or is not executable</source> - <translation>Datoteka »%1« ne obstaja ali pa ni izvršljiva</translation> + <source>qmake does not exist or is not executable</source> + <translation>Datoteka »qmake« ne obstaja ali pa ni izvršljiva</translation> </message> <message> <location line="+2"/> @@ -21813,8 +21813,8 @@ Projekte programov QML izvede pregledovalnik QML in jih ni potrebno zgraditi.</t </message> <message> <location line="+2"/> - <source>Could not determine the path to the binaries of the Qt installation, maybe the %1 path is wrong?</source> - <translation>Ni bilo moč ugotoviti poti do programov namestitve Qt. Morda je pot do %1 napačna?</translation> + <source>Could not determine the path to the binaries of the Qt installation, maybe the qmake path is wrong?</source> + <translation>Ni bilo moč ugotoviti poti do programov namestitve Qt. Morda je pot do qmake napačna?</translation> </message> <message> <location line="+3"/> diff --git a/share/qtcreator/translations/qtcreator_uk.ts b/share/qtcreator/translations/qtcreator_uk.ts index b3c68dd579c..7ed2f44691f 100644 --- a/share/qtcreator/translations/qtcreator_uk.ts +++ b/share/qtcreator/translations/qtcreator_uk.ts @@ -22711,8 +22711,8 @@ For more details, see /etc/sysctl.d/10-ptrace.conf <translation>Шлях до qmake не задано</translation> </message> <message> - <source>%1 does not exist or is not executable</source> - <translation>%1 не існує або не є виконуваним модулем</translation> + <source>qmake does not exist or is not executable</source> + <translation>qmake не існує або не є виконуваним модулем</translation> </message> <message> <source>ABI detection failed: Make sure to use a matching compiler when building.</source> @@ -22763,8 +22763,8 @@ For more details, see /etc/sysctl.d/10-ptrace.conf <translation>Версія Qt не встановлена як слід, будь ласка, запустіть make install</translation> </message> <message> - <source>Could not determine the path to the binaries of the Qt installation, maybe the %1 path is wrong?</source> - <translation>Не вдалось визначити шлях до виконуваних модулів встановлення Qt, можливо, шлях до %1 помилковий?</translation> + <source>Could not determine the path to the binaries of the Qt installation, maybe the qmake path is wrong?</source> + <translation>Не вдалось визначити шлях до виконуваних модулів встановлення Qt, можливо, шлях до qmake помилковий?</translation> </message> <message> <source>The default mkspec symlink is broken.</source> diff --git a/share/qtcreator/translations/qtcreator_zh_CN.ts b/share/qtcreator/translations/qtcreator_zh_CN.ts index 64fa094ec3c..8e6d46bd95c 100644 --- a/share/qtcreator/translations/qtcreator_zh_CN.ts +++ b/share/qtcreator/translations/qtcreator_zh_CN.ts @@ -27948,8 +27948,8 @@ Did you start Qemu?</source> <translation>没有设置qmake路径</translation> </message> <message> - <source>%1 does not exist or is not executable</source> - <translation>%1不存在或者不可执行</translation> + <source>qmake does not exist or is not executable</source> + <translation>qmake不存在或者不可执行</translation> </message> <message> <source>Qt version has no name</source> @@ -27976,8 +27976,8 @@ Did you start Qemu?</source> <translation>Qt没有被正确安装,请运行make install</translation> </message> <message> - <source>Could not determine the path to the binaries of the Qt installation, maybe the %1 path is wrong?</source> - <translation>无法确定Qt安装的二进制所在的路径,或许%1的路径设置出现了错误?</translation> + <source>Could not determine the path to the binaries of the Qt installation, maybe the qmake path is wrong?</source> + <translation>无法确定Qt安装的二进制所在的路径,或许qmake的路径设置出现了错误?</translation> </message> <message> <source>The default mkspec symlink is broken.</source> diff --git a/share/qtcreator/translations/qtcreator_zh_TW.ts b/share/qtcreator/translations/qtcreator_zh_TW.ts index 3aa3e0d04ff..253df6a4499 100644 --- a/share/qtcreator/translations/qtcreator_zh_TW.ts +++ b/share/qtcreator/translations/qtcreator_zh_TW.ts @@ -15636,8 +15636,8 @@ Requires <b>Qt 4.7.4</b> or newer.</source> <translation>沒有設定 qmake 路徑</translation> </message> <message> - <source>%1 does not exist or is not executable</source> - <translation>%1 不存在或無法執行</translation> + <source>qmake does not exist or is not executable</source> + <translation>qmake 不存在或無法執行</translation> </message> <message> <source>Qt version has no name</source> @@ -15664,8 +15664,8 @@ Requires <b>Qt 4.7.4</b> or newer.</source> <translation>Qt 沒有被正確安裝,請執行 make install</translation> </message> <message> - <source>Could not determine the path to the binaries of the Qt installation, maybe the %1 path is wrong?</source> - <translation>無法決定 Qt 安裝版的路徑。也許是 %1 的路徑設定有錯誤?</translation> + <source>Could not determine the path to the binaries of the Qt installation, maybe the qmake path is wrong?</source> + <translation>無法決定 Qt 安裝版的路徑。也許是 qmake 的路徑設定有錯誤?</translation> </message> <message> <source>The default mkspec symlink is broken.</source> diff --git a/src/libs/utils/buildablehelperlibrary.cpp b/src/libs/utils/buildablehelperlibrary.cpp index 0ad53e52a73..c1030fd5e78 100644 --- a/src/libs/utils/buildablehelperlibrary.cpp +++ b/src/libs/utils/buildablehelperlibrary.cpp @@ -41,61 +41,7 @@ bool BuildableHelperLibrary::isQtChooser(const FilePath &filePath) return filePath.symLinkTarget().endsWith("/qtchooser"); } -static const QStringList &queryToolNames() -{ - static const QStringList names = {"qmake", "qtpaths"}; - return names; -} - -static bool isQueryTool(FilePath path) -{ - if (path.isEmpty()) - return false; - if (BuildableHelperLibrary::isQtChooser(path)) - path = BuildableHelperLibrary::qtChooserToQueryToolPath(path.symLinkTarget()); - if (!path.exists()) - return false; - QtcProcess proc; - proc.setCommand({path, {"-query"}}); - proc.runBlocking(); - if (proc.result() != ProcessResult::FinishedWithSuccess) - return false; - const QString output = proc.stdOut(); - // Exemplary output of "[qmake|qtpaths] -query": - // QT_SYSROOT:... - // QT_INSTALL_PREFIX:... - // [...] - // QT_VERSION:6.4.0 - return output.contains("QT_VERSION:"); -} - -static FilePath findQueryToolInDir(const FilePath &dir) -{ - if (dir.isEmpty()) - return {}; - - for (const QString &queryTool : queryToolNames()) { - FilePath queryToolPath = dir.pathAppended(queryTool).withExecutableSuffix(); - if (queryToolPath.exists()) { - if (isQueryTool(queryToolPath)) - return queryToolPath; - } - - // Prefer qmake-qt5 to qmake-qt4 by sorting the filenames in reverse order. - const FilePaths candidates = dir.dirEntries( - {BuildableHelperLibrary::possibleQtQueryTools(queryTool), QDir::Files}, - QDir::Name | QDir::Reversed); - for (const FilePath &candidate : candidates) { - if (candidate == queryToolPath) - continue; - if (isQueryTool(candidate)) - return candidate; - } - } - return {}; -} - -FilePath BuildableHelperLibrary::qtChooserToQueryToolPath(const FilePath &qtChooser) +FilePath BuildableHelperLibrary::qtChooserToQmakePath(const FilePath &qtChooser) { const QString toolDir = QLatin1String("QTTOOLDIR=\""); QtcProcess proc; @@ -105,10 +51,6 @@ FilePath BuildableHelperLibrary::qtChooserToQueryToolPath(const FilePath &qtChoo if (proc.result() != ProcessResult::FinishedWithSuccess) return {}; const QString output = proc.stdOut(); - // Exemplary output of "qtchooser -print-env": - // QT_SELECT="default" - // QTTOOLDIR="/usr/lib/qt5/bin" - // QTLIBDIR="/usr/lib/x86_64-linux-gnu" int pos = output.indexOf(toolDir); if (pos == -1) return {}; @@ -117,13 +59,44 @@ FilePath BuildableHelperLibrary::qtChooserToQueryToolPath(const FilePath &qtChoo if (end == -1) return {}; - FilePath queryToolPath = qtChooser; - for (const QString &queryTool : queryToolNames()) { - queryToolPath.setPath(output.mid(pos, end - pos) + "/" + queryTool); - if (queryToolPath.exists()) - return queryToolPath; + FilePath qmake = qtChooser; + qmake.setPath(output.mid(pos, end - pos) + "/qmake"); + return qmake; +} + +static bool isQmake(FilePath path) +{ + if (path.isEmpty()) + return false; + if (BuildableHelperLibrary::isQtChooser(path)) + path = BuildableHelperLibrary::qtChooserToQmakePath(path.symLinkTarget()); + if (!path.exists()) + return false; + return !BuildableHelperLibrary::qtVersionForQMake(path).isEmpty(); +} + +static FilePath findQmakeInDir(const FilePath &dir) +{ + if (dir.isEmpty()) + return {}; + + FilePath qmakePath = dir.pathAppended("qmake").withExecutableSuffix(); + if (qmakePath.exists()) { + if (isQmake(qmakePath)) + return qmakePath; + } + + // Prefer qmake-qt5 to qmake-qt4 by sorting the filenames in reverse order. + const FilePaths candidates = dir.dirEntries( + {BuildableHelperLibrary::possibleQMakeCommands(), QDir::Files}, + QDir::Name | QDir::Reversed); + for (const FilePath &candidate : candidates) { + if (candidate == qmakePath) + continue; + if (isQmake(candidate)) + return candidate; } - return queryToolPath; + return {}; } FilePath BuildableHelperLibrary::findSystemQt(const Environment &env) @@ -134,55 +107,86 @@ FilePath BuildableHelperLibrary::findSystemQt(const Environment &env) FilePaths BuildableHelperLibrary::findQtsInEnvironment(const Environment &env, int maxCount) { - FilePaths queryToolList; + FilePaths qmakeList; std::set<QString> canonicalEnvPaths; const FilePaths paths = env.path(); for (const FilePath &path : paths) { if (!canonicalEnvPaths.insert(path.toFileInfo().canonicalFilePath()).second) continue; - const FilePath queryTool = findQueryToolInDir(path); - if (queryTool.isEmpty()) + const FilePath qmake = findQmakeInDir(path); + if (qmake.isEmpty()) continue; - queryToolList << queryTool; - if (maxCount != -1 && queryToolList.size() == maxCount) + qmakeList << qmake; + if (maxCount != -1 && qmakeList.size() == maxCount) break; } - return queryToolList; + return qmakeList; +} + +QString BuildableHelperLibrary::qtVersionForQMake(const FilePath &qmakePath) +{ + if (qmakePath.isEmpty()) + return QString(); + + QtcProcess qmake; + qmake.setTimeoutS(5); + qmake.setCommand({qmakePath, {"--version"}}); + qmake.runBlocking(); + if (qmake.result() != ProcessResult::FinishedWithSuccess) { + qWarning() << qmake.exitMessage(); + return QString(); + } + + const QString output = qmake.allOutput(); + static const QRegularExpression regexp("(QMake version:?)[\\s]*([\\d.]*)", + QRegularExpression::CaseInsensitiveOption); + const QRegularExpressionMatch match = regexp.match(output); + const QString qmakeVersion = match.captured(2); + if (qmakeVersion.startsWith(QLatin1String("2.")) + || qmakeVersion.startsWith(QLatin1String("3."))) { + static const QRegularExpression regexp2("Using Qt version[\\s]*([\\d\\.]*)", + QRegularExpression::CaseInsensitiveOption); + const QRegularExpressionMatch match2 = regexp2.match(output); + const QString version = match2.captured(1); + return version; + } + return QString(); } -QString BuildableHelperLibrary::filterForQtQueryToolsFileDialog() +QString BuildableHelperLibrary::filterForQmakeFileDialog() { - QStringList toolFilters; - for (const QString &queryTool : queryToolNames()) { - for (const QString &tool: BuildableHelperLibrary::possibleQtQueryTools(queryTool)) { - QString toolFilter; - if (HostOsInfo::isMacHost()) - // work around QTBUG-7739 that prohibits filters that don't start with * - toolFilter += QLatin1Char('*'); - toolFilter += tool; - if (HostOsInfo::isAnyUnixHost() && !HostOsInfo::isMacHost()) - // kde bug, we need at least one wildcard character - // see QTCREATORBUG-7771 - toolFilter += QLatin1Char('*'); - toolFilters.append(toolFilter); - } + QString filter = QLatin1String("qmake ("); + const QStringList commands = possibleQMakeCommands(); + for (int i = 0; i < commands.size(); ++i) { + if (i) + filter += QLatin1Char(' '); + if (HostOsInfo::isMacHost()) + // work around QTBUG-7739 that prohibits filters that don't start with * + filter += QLatin1Char('*'); + filter += commands.at(i); + if (HostOsInfo::isAnyUnixHost() && !HostOsInfo::isMacHost()) + // kde bug, we need at least one wildcard character + // see QTCREATORBUG-7771 + filter += QLatin1Char('*'); } - return queryToolNames().join(", ") + " (" + toolFilters.join(" ") + ")"; + filter += QLatin1Char(')'); + return filter; } -QStringList BuildableHelperLibrary::possibleQtQueryTools(const QString &tool) + +QStringList BuildableHelperLibrary::possibleQMakeCommands() { - // On Windows it is "<queryTool>.exe" or "<queryTool>.bat" + // On Windows it is always "qmake.exe" // On Unix some distributions renamed qmake with a postfix to avoid clashes // On OS X, Qt 4 binary packages also has renamed qmake. There are also symbolic links that are - // named <tool>, but the file dialog always checks against resolved links (native Cocoa issue) - QStringList tools(HostOsInfo::withExecutableSuffix(tool + "*")); + // named "qmake", but the file dialog always checks against resolved links (native Cocoa issue) + QStringList commands(HostOsInfo::withExecutableSuffix("qmake*")); // Qt 6 CMake built targets, such as Android, are dependent on the host installation - // and use a script wrapper around the host queryTool executable + // and use a script wrapper around the host qmake executable if (HostOsInfo::isWindowsHost()) - tools.append(tool + "*.bat"); - return tools; + commands.append("qmake*.bat"); + return commands; } } // namespace Utils diff --git a/src/libs/utils/buildablehelperlibrary.h b/src/libs/utils/buildablehelperlibrary.h index 2b07ac009e9..8b47bef1012 100644 --- a/src/libs/utils/buildablehelperlibrary.h +++ b/src/libs/utils/buildablehelperlibrary.h @@ -45,11 +45,12 @@ public: static FilePath findSystemQt(const Environment &env); static FilePaths findQtsInEnvironment(const Environment &env, int maxCount = -1); static bool isQtChooser(const FilePath &filePath); - static FilePath qtChooserToQueryToolPath(const FilePath &path); - // returns something like qmake4, qmake, qmake-qt4, qtpaths - // or whatever distributions have chosen (used by QtVersion) - static QStringList possibleQtQueryTools(const QString &tool); - static QString filterForQtQueryToolsFileDialog(); + static FilePath qtChooserToQmakePath(const FilePath &path); + // return true if the qmake at qmakePath is a Qt (used by QtVersion) + static QString qtVersionForQMake(const FilePath &qmakePath); + // returns something like qmake4, qmake, qmake-qt4 or whatever distributions have chosen (used by QtVersion) + static QStringList possibleQMakeCommands(); + static QString filterForQmakeFileDialog(); }; } // Utils diff --git a/src/libs/utils/environment.cpp b/src/libs/utils/environment.cpp index 75f4ea6eecd..fa61313144f 100644 --- a/src/libs/utils/environment.cpp +++ b/src/libs/utils/environment.cpp @@ -40,10 +40,15 @@ Q_GLOBAL_STATIC_WITH_ARGS(Environment, staticSystemEnvironment, Q_GLOBAL_STATIC(QVector<EnvironmentProvider>, environmentProviders) +NameValueItems Environment::diff(const Environment &other, bool checkAppendPrepend) const +{ + return m_dict.diff(other.m_dict, checkAppendPrepend); +} + QProcessEnvironment Environment::toProcessEnvironment() const { QProcessEnvironment result; - for (auto it = m_values.constBegin(); it != m_values.constEnd(); ++it) { + for (auto it = m_dict.m_values.constBegin(); it != m_dict.m_values.constEnd(); ++it) { if (it.value().second) result.insert(it.key().name, expandedValueForKey(key(it))); } @@ -52,28 +57,28 @@ QProcessEnvironment Environment::toProcessEnvironment() const void Environment::appendOrSetPath(const FilePath &value) { - QTC_CHECK(value.osType() == m_osType); + QTC_CHECK(value.osType() == osType()); if (value.isEmpty()) return; appendOrSet("PATH", value.nativePath(), - QString(OsSpecificAspects::pathListSeparator(m_osType))); + QString(OsSpecificAspects::pathListSeparator(osType()))); } void Environment::prependOrSetPath(const FilePath &value) { - QTC_CHECK(value.osType() == m_osType); + QTC_CHECK(value.osType() == osType()); if (value.isEmpty()) return; prependOrSet("PATH", value.nativePath(), - QString(OsSpecificAspects::pathListSeparator(m_osType))); + QString(OsSpecificAspects::pathListSeparator(osType()))); } void Environment::appendOrSet(const QString &key, const QString &value, const QString &sep) { QTC_ASSERT(!key.contains('='), return ); - const auto it = findKey(key); - if (it == m_values.end()) { - m_values.insert(DictKey(key, nameCaseSensitivity()), qMakePair(value, true)); + const auto it = m_dict.findKey(key); + if (it == m_dict.m_values.end()) { + m_dict.m_values.insert(DictKey(key, m_dict.nameCaseSensitivity()), qMakePair(value, true)); } else { // Append unless it is already there const QString toAppend = sep + value; @@ -85,9 +90,9 @@ void Environment::appendOrSet(const QString &key, const QString &value, const QS void Environment::prependOrSet(const QString &key, const QString &value, const QString &sep) { QTC_ASSERT(!key.contains('='), return ); - const auto it = findKey(key); - if (it == m_values.end()) { - m_values.insert(DictKey(key, nameCaseSensitivity()), qMakePair(value, true)); + const auto it = m_dict.findKey(key); + if (it == m_dict.m_values.end()) { + m_dict.m_values.insert(DictKey(key, m_dict.nameCaseSensitivity()), qMakePair(value, true)); } else { // Prepend unless it is already there const QString toPrepend = value + sep; @@ -98,8 +103,8 @@ void Environment::prependOrSet(const QString &key, const QString &value, const Q void Environment::prependOrSetLibrarySearchPath(const FilePath &value) { - QTC_CHECK(value.osType() == m_osType); - switch (m_osType) { + QTC_CHECK(value.osType() == osType()); + switch (osType()) { case OsTypeWindows: { const QChar sep = ';'; prependOrSet("PATH", value.nativePath(), QString(sep)); @@ -137,8 +142,8 @@ Environment Environment::systemEnvironment() void Environment::setupEnglishOutput() { - set("LC_MESSAGES", "en_US.utf8"); - set("LANGUAGE", "en_US:en"); + m_dict.set("LC_MESSAGES", "en_US.utf8"); + m_dict.set("LANGUAGE", "en_US:en"); } static FilePath searchInDirectory(const QStringList &execs, @@ -166,7 +171,7 @@ QStringList Environment::appendExeExtensions(const QString &executable) const { QStringList execs(executable); const QFileInfo fi(executable); - if (m_osType == OsTypeWindows) { + if (osType() == OsTypeWindows) { // Check all the executable extensions on windows: // PATHEXT is only used if the executable has no extension if (fi.suffix().isEmpty()) { @@ -202,7 +207,7 @@ bool Environment::isSameExecutable(const QString &exe1, const QString &exe2) con QString Environment::expandedValueForKey(const QString &key) const { - return expandVariables(value(key)); + return expandVariables(m_dict.value(key)); } static FilePath searchInDirectoriesHelper(const Environment &env, @@ -308,7 +313,7 @@ FilePaths Environment::path() const FilePaths Environment::pathListValue(const QString &varName) const { const QStringList pathComponents = expandedValueForKey(varName).split( - OsSpecificAspects::pathListSeparator(m_osType), Qt::SkipEmptyParts); + OsSpecificAspects::pathListSeparator(osType()), Qt::SkipEmptyParts); return transform(pathComponents, &FilePath::fromUserInput); } @@ -333,12 +338,12 @@ QString Environment::expandVariables(const QString &input) const { QString result = input; - if (m_osType == OsTypeWindows) { + if (osType() == OsTypeWindows) { for (int vStart = -1, i = 0; i < result.length(); ) { if (result.at(i++) == '%') { if (vStart > 0) { - const auto it = findKey(result.mid(vStart, i - vStart - 1)); - if (it != m_values.constEnd()) { + const auto it = m_dict.findKey(result.mid(vStart, i - vStart - 1)); + if (it != m_dict.m_values.constEnd()) { result.replace(vStart - 1, i - vStart + 1, it->first); i = vStart - 1 + it->first.length(); vStart = -1; diff --git a/src/libs/utils/environment.h b/src/libs/utils/environment.h index 06ab65725c1..7aa42ab2ad9 100644 --- a/src/libs/utils/environment.h +++ b/src/libs/utils/environment.h @@ -40,13 +40,27 @@ QT_END_NAMESPACE namespace Utils { -class QTCREATOR_UTILS_EXPORT Environment final : public NameValueDictionary +class QTCREATOR_UTILS_EXPORT Environment final { public: - using NameValueDictionary::NameValueDictionary; + Environment() : m_dict(HostOsInfo::hostOs()) {} + explicit Environment(OsType osType) : m_dict(osType) {} + explicit Environment(const QStringList &env, OsType osType = HostOsInfo::hostOs()) + : m_dict(env, osType) {} + explicit Environment(const NameValuePairs &nameValues) : m_dict(nameValues) {} + explicit Environment(const NameValueDictionary &dict) : m_dict(dict) {} - static Environment systemEnvironment(); + QString value(const QString &key) const { return m_dict.value(key); } + bool hasKey(const QString &key) const { return m_dict.hasKey(key); } + + void set(const QString &key, const QString &value, bool enabled = true) { m_dict.set(key, value, enabled); } + void unset(const QString &key) { m_dict.unset(key); } + void modify(const NameValueItems &items) { m_dict.modify(items); } + int size() const { return m_dict.size(); } + void clear() { return m_dict.clear(); } + + QStringList toStringList() const { return m_dict.toStringList(); } QProcessEnvironment toProcessEnvironment() const; void appendOrSet(const QString &key, const QString &value, const QString &sep = QString()); @@ -81,8 +95,38 @@ public: FilePath expandVariables(const FilePath &input) const; QStringList expandVariables(const QStringList &input) const; + OsType osType() const { return m_dict.osType(); } + QString userName() const; + + using const_iterator = NameValueMap::const_iterator; // FIXME: avoid + NameValueDictionary toDictionary() const { return m_dict; } // FIXME: avoid + NameValueItems diff(const Environment &other, bool checkAppendPrepend = false) const; // FIXME: avoid + + QString key(const_iterator it) const { return m_dict.key(it); } // FIXME: avoid + QString value(const_iterator it) const { return m_dict.value(it); } // FIXME: avoid + bool isEnabled(const_iterator it) const { return m_dict.isEnabled(it); } // FIXME: avoid + + const_iterator constBegin() const { return m_dict.constBegin(); } // FIXME: avoid + const_iterator constEnd() const { return m_dict.constEnd(); } // FIXME: avoid + const_iterator constFind(const QString &name) const { return m_dict.constFind(name); } // FIXME: avoid + + friend bool operator!=(const Environment &first, const Environment &second) + { + return first.m_dict != second.m_dict; + } + + friend bool operator==(const Environment &first, const Environment &second) + { + return first.m_dict == second.m_dict; + } + + static Environment systemEnvironment(); + static void modifySystemEnvironment(const EnvironmentItems &list); // use with care!!! static void setSystemEnvironment(const Environment &environment); // don't use at all!!! + +private: + NameValueDictionary m_dict; }; class QTCREATOR_UTILS_EXPORT EnvironmentChange final diff --git a/src/libs/utils/environmentmodel.cpp b/src/libs/utils/environmentmodel.cpp index a5cb1b4958a..d7938a4fdae 100644 --- a/src/libs/utils/environmentmodel.cpp +++ b/src/libs/utils/environmentmodel.cpp @@ -28,12 +28,15 @@ #include "environment.h" namespace Utils { -const Environment &EnvironmentModel::baseEnvironment() const + +Environment EnvironmentModel::baseEnvironment() const { - return static_cast<const Environment &>(baseNameValueDictionary()); + return Environment(baseNameValueDictionary()); } + void EnvironmentModel::setBaseEnvironment(const Environment &env) { - setBaseNameValueDictionary(env); + setBaseNameValueDictionary(env.toDictionary()); } + } // namespace Utils diff --git a/src/libs/utils/environmentmodel.h b/src/libs/utils/environmentmodel.h index 5457bdb0497..b64518b6ae9 100644 --- a/src/libs/utils/environmentmodel.h +++ b/src/libs/utils/environmentmodel.h @@ -36,7 +36,7 @@ class QTCREATOR_UTILS_EXPORT EnvironmentModel : public NameValueModel Q_OBJECT public: - const Environment &baseEnvironment() const; + Environment baseEnvironment() const; void setBaseEnvironment(const Environment &env); }; diff --git a/src/libs/utils/launchersocket.cpp b/src/libs/utils/launchersocket.cpp index 4de1a778d83..1677fd892cc 100644 --- a/src/libs/utils/launchersocket.cpp +++ b/src/libs/utils/launchersocket.cpp @@ -67,10 +67,7 @@ public: , m_stdErr(stdErr) {} QByteArray stdOut() const { return m_stdOut; } QByteArray stdErr() const { return m_stdErr; } - void mergeWith(LauncherReadyReadSignal *newSignal) { - m_stdOut += newSignal->stdOut(); - m_stdErr += newSignal->stdErr(); - } + private: QByteArray m_stdOut; QByteArray m_stdErr; @@ -203,31 +200,6 @@ void CallerHandle::appendSignal(LauncherSignal *newSignal) QMutexLocker locker(&m_mutex); QTC_ASSERT(isCalledFromLaunchersThread(), return); - - // TODO: we might assert if the caller's state is proper, e.g. - // start signal can't appear if we are in Running or NotRunning state, - // or finish signal can't appear if we are in NotRunning or Starting state, - // or readyRead signal can't appear if we are in NotRunning or Starting state, - // or error signal can't appear if we are in NotRunning state - // or FailedToStart error signal can't appear if we are in Running state - // or other than FailedToStart error signal can't appear if we are in Starting state. - if (!m_signals.isEmpty()) { - LauncherSignal *lastSignal = m_signals.last(); - - QTC_ASSERT(lastSignal->signalType() != SignalType::Done, - qWarning() << "Buffering new signal for process" << m_command - << "while the last done() signal wasn't flushed yet."); - - // Merge ReadyRead signals into one. - if (lastSignal->signalType() == SignalType::ReadyRead - && newSignal->signalType() == SignalType::ReadyRead) { - LauncherReadyReadSignal *lastRead = static_cast<LauncherReadyReadSignal *>(lastSignal); - LauncherReadyReadSignal *newRead = static_cast<LauncherReadyReadSignal *>(newSignal); - lastRead->mergeWith(newRead); - delete newRead; - return; - } - } m_signals.append(newSignal); } diff --git a/src/libs/utils/namevaluedictionary.h b/src/libs/utils/namevaluedictionary.h index 30721915c67..7e302796705 100644 --- a/src/libs/utils/namevaluedictionary.h +++ b/src/libs/utils/namevaluedictionary.h @@ -101,6 +101,7 @@ public: } protected: + friend class Environment; NameValueMap::iterator findKey(const QString &key); const_iterator findKey(const QString &key) const; diff --git a/src/plugins/baremetal/baremetalrunconfiguration.cpp b/src/plugins/baremetal/baremetalrunconfiguration.cpp index f081520bebb..b8961d9476d 100644 --- a/src/plugins/baremetal/baremetalrunconfiguration.cpp +++ b/src/plugins/baremetal/baremetalrunconfiguration.cpp @@ -48,7 +48,7 @@ public: explicit BareMetalRunConfiguration(Target *target, Id id) : RunConfiguration(target, id) { - const auto exeAspect = addAspect<ExecutableAspect>(target); + const auto exeAspect = addAspect<ExecutableAspect>(target, ExecutableAspect::RunDevice); exeAspect->setDisplayStyle(StringAspect::LabelDisplay); exeAspect->setPlaceHolderText(tr("Unknown")); @@ -72,7 +72,7 @@ public: explicit BareMetalCustomRunConfiguration(Target *target, Id id) : RunConfiguration(target, id) { - const auto exeAspect = addAspect<ExecutableAspect>(target); + const auto exeAspect = addAspect<ExecutableAspect>(target, ExecutableAspect::RunDevice); exeAspect->setSettingsKey("BareMetal.CustomRunConfig.Executable"); exeAspect->setPlaceHolderText(tr("Unknown")); exeAspect->setDisplayStyle(StringAspect::PathChooserDisplay); diff --git a/src/plugins/boot2qt/qdbrunconfiguration.cpp b/src/plugins/boot2qt/qdbrunconfiguration.cpp index 98cae5734bc..2141384f6a6 100644 --- a/src/plugins/boot2qt/qdbrunconfiguration.cpp +++ b/src/plugins/boot2qt/qdbrunconfiguration.cpp @@ -87,7 +87,7 @@ private: QdbRunConfiguration::QdbRunConfiguration(Target *target, Id id) : RunConfiguration(target, id) { - auto exeAspect = addAspect<ExecutableAspect>(target); + auto exeAspect = addAspect<ExecutableAspect>(target, ExecutableAspect::RunDevice); exeAspect->setSettingsKey("QdbRunConfig.RemoteExecutable"); exeAspect->setLabelText(tr("Executable on device:")); exeAspect->setPlaceHolderText(tr("Remote path not set")); diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp index e56970d9598..b49c8fc3c7b 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp @@ -211,8 +211,7 @@ void ClangModelManagerSupport::startLocalRenaming(const CppEditor::CursorInEdito } void ClangModelManagerSupport::globalRename(const CppEditor::CursorInEditor &cursor, - CppEditor::UsagesCallback &&callback, - const QString &replacement) + const QString &replacement) { if (ClangdClient * const client = clientForFile(cursor.filePath()); client && client->isFullyIndexed()) { @@ -221,12 +220,10 @@ void ClangModelManagerSupport::globalRename(const CppEditor::CursorInEditor &cur client->findUsages(cursor.textDocument(), cursor.cursor(), replacement); return; } - CppModelManager::globalRename(cursor, std::move(callback), replacement, - CppModelManager::Backend::Builtin); + CppModelManager::globalRename(cursor, replacement, CppModelManager::Backend::Builtin); } -void ClangModelManagerSupport::findUsages(const CppEditor::CursorInEditor &cursor, - CppEditor::UsagesCallback &&callback) const +void ClangModelManagerSupport::findUsages(const CppEditor::CursorInEditor &cursor) const { if (ClangdClient * const client = clientForFile(cursor.filePath()); client && client->isFullyIndexed()) { @@ -236,7 +233,7 @@ void ClangModelManagerSupport::findUsages(const CppEditor::CursorInEditor &curso return; } - CppModelManager::findUsages(cursor, std::move(callback), CppModelManager::Backend::Builtin); + CppModelManager::findUsages(cursor, CppModelManager::Backend::Builtin); } void ClangModelManagerSupport::switchHeaderSource(const Utils::FilePath &filePath, bool inNextSplit) diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.h b/src/plugins/clangcodemodel/clangmodelmanagersupport.h index 4233f734b09..7604dd5cc59 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.h +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.h @@ -90,10 +90,8 @@ private: void startLocalRenaming(const CppEditor::CursorInEditor &data, const CppEditor::ProjectPart *projectPart, CppEditor::RenameCallback &&renameSymbolsCallback) override; - void globalRename(const CppEditor::CursorInEditor &cursor, CppEditor::UsagesCallback &&callback, - const QString &replacement) override; - void findUsages(const CppEditor::CursorInEditor &cursor, - CppEditor::UsagesCallback &&callback) const override; + void globalRename(const CppEditor::CursorInEditor &cursor, const QString &replacement) override; + void findUsages(const CppEditor::CursorInEditor &cursor) const override; void switchHeaderSource(const Utils::FilePath &filePath, bool inNextSplit) override; void onEditorOpened(Core::IEditor *editor); diff --git a/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp b/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp index 1c4112f882c..6c39ddef419 100644 --- a/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp +++ b/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp @@ -1196,7 +1196,7 @@ Tasks CMakeConfigurationKitAspect::validate(const Kit *k) const if (!version || !version->isValid()) { addWarning(tr("CMake configuration has a path to a qmake binary set, " "even though the kit has no valid Qt version.")); - } else if (qmakePath != version->queryToolFilePath() && isQt4) { + } else if (qmakePath != version->qmakeFilePath() && isQt4) { addWarning(tr("CMake configuration has a path to a qmake binary set " "that does not match the qmake binary path " "configured in the Qt version.")); diff --git a/src/plugins/coreplugin/actionmanager/actionmanager.cpp b/src/plugins/coreplugin/actionmanager/actionmanager.cpp index 3d1b5e696d8..b328bc3afd4 100644 --- a/src/plugins/coreplugin/actionmanager/actionmanager.cpp +++ b/src/plugins/coreplugin/actionmanager/actionmanager.cpp @@ -243,13 +243,13 @@ ActionContainer *ActionManager::createTouchBar(Id id, const QIcon &icon, const Q */ Command *ActionManager::registerAction(QAction *action, Id id, const Context &context, bool scriptable) { - Action *a = d->overridableAction(id); - if (a) { - a->addOverrideAction(action, context, scriptable); + Command *cmd = d->overridableAction(id); + if (cmd) { + cmd->d->addOverrideAction(action, context, scriptable); emit m_instance->commandListChanged(); emit m_instance->commandAdded(id); } - return a; + return cmd; } /*! @@ -301,11 +301,7 @@ ActionContainer *ActionManager::actionContainer(Id id) */ QList<Command *> ActionManager::commands() { - // transform list of Action into list of Command - QList<Command *> result; - for (Command *cmd : qAsConst(d->m_idCmdMap)) - result << cmd; - return result; + return d->m_idCmdMap.values(); } /*! @@ -318,21 +314,21 @@ QList<Command *> ActionManager::commands() */ void ActionManager::unregisterAction(QAction *action, Id id) { - Action *a = d->m_idCmdMap.value(id, nullptr); - if (!a) { + Command *cmd = d->m_idCmdMap.value(id, nullptr); + if (!cmd) { qWarning() << "unregisterAction: id" << id.name() << "is registered with a different command type."; return; } - a->removeOverrideAction(action); - if (a->isEmpty()) { + cmd->d->removeOverrideAction(action); + if (cmd->d->isEmpty()) { // clean up - ActionManagerPrivate::saveSettings(a); - ICore::mainWindow()->removeAction(a->action()); + ActionManagerPrivate::saveSettings(cmd); + ICore::mainWindow()->removeAction(cmd->action()); // ActionContainers listen to the commands' destroyed signals - delete a->action(); + delete cmd->action(); d->m_idCmdMap.remove(id); - delete a; + delete cmd; } emit m_instance->commandListChanged(); } @@ -421,7 +417,7 @@ void ActionManagerPrivate::setContext(const Context &context) m_context = context; const IdCmdMap::const_iterator cmdcend = m_idCmdMap.constEnd(); for (IdCmdMap::const_iterator it = m_idCmdMap.constBegin(); it != cmdcend; ++it) - it.value()->setCurrentContext(m_context); + it.value()->d->setCurrentContext(m_context); } bool ActionManagerPrivate::hasContext(const Context &context) const @@ -463,26 +459,29 @@ void ActionManagerPrivate::showShortcutPopup(const QString &shortcut) Utils::FadingIndicator::showText(window, shortcut); } -Action *ActionManagerPrivate::overridableAction(Id id) +Command *ActionManagerPrivate::overridableAction(Id id) { - Action *a = m_idCmdMap.value(id, nullptr); - if (!a) { - a = new Action(id); - m_idCmdMap.insert(id, a); - readUserSettings(id, a); - ICore::mainWindow()->addAction(a->action()); - a->action()->setObjectName(id.toString()); - a->action()->setShortcutContext(Qt::ApplicationShortcut); - a->setCurrentContext(m_context); + Command *cmd = m_idCmdMap.value(id, nullptr); + if (!cmd) { + cmd = new Command(id); + m_idCmdMap.insert(id, cmd); + readUserSettings(id, cmd); + ICore::mainWindow()->addAction(cmd->action()); + cmd->action()->setObjectName(id.toString()); + cmd->action()->setShortcutContext(Qt::ApplicationShortcut); + cmd->d->setCurrentContext(m_context); if (ActionManager::isPresentationModeEnabled()) - connect(a->action(), &QAction::triggered, this, &ActionManagerPrivate::actionTriggered); + connect(cmd->action(), + &QAction::triggered, + this, + &ActionManagerPrivate::actionTriggered); } - return a; + return cmd; } -void ActionManagerPrivate::readUserSettings(Id id, Action *cmd) +void ActionManagerPrivate::readUserSettings(Id id, Command *cmd) { QSettings *settings = ICore::settings(); settings->beginGroup(kKeyboardSettingsKeyV2); @@ -499,7 +498,7 @@ void ActionManagerPrivate::readUserSettings(Id id, Action *cmd) settings->endGroup(); } -void ActionManagerPrivate::saveSettings(Action *cmd) +void ActionManagerPrivate::saveSettings(Command *cmd) { const QString id = cmd->id().toString(); const QString settingsKey = QLatin1String(kKeyboardSettingsKeyV2) + '/' + id; diff --git a/src/plugins/coreplugin/actionmanager/actionmanager_p.h b/src/plugins/coreplugin/actionmanager/actionmanager_p.h index 9fdc96aef1a..9226b0380ad 100644 --- a/src/plugins/coreplugin/actionmanager/actionmanager_p.h +++ b/src/plugins/coreplugin/actionmanager/actionmanager_p.h @@ -25,8 +25,6 @@ #pragma once -#include <coreplugin/actionmanager/command_p.h> -#include <coreplugin/actionmanager/actioncontainer_p.h> #include <coreplugin/icontext.h> #include <QMap> @@ -36,9 +34,10 @@ namespace Core { +class Command; + namespace Internal { -class Action; class ActionContainerPrivate; class ActionManagerPrivate : public QObject @@ -46,7 +45,7 @@ class ActionManagerPrivate : public QObject Q_OBJECT public: - using IdCmdMap = QHash<Utils::Id, Action *>; + using IdCmdMap = QHash<Utils::Id, Command *>; using IdContainerMap = QHash<Utils::Id, ActionContainerPrivate *>; ~ActionManagerPrivate() override; @@ -55,13 +54,13 @@ public: bool hasContext(int context) const; void saveSettings(); - static void saveSettings(Action *cmd); + static void saveSettings(Command *cmd); static void showShortcutPopup(const QString &shortcut); bool hasContext(const Context &context) const; - Action *overridableAction(Utils::Id id); + Command *overridableAction(Utils::Id id); - static void readUserSettings(Utils::Id id, Action *cmd); + static void readUserSettings(Utils::Id id, Command *cmd); void containerDestroyed(); void actionTriggered(); diff --git a/src/plugins/coreplugin/actionmanager/command.cpp b/src/plugins/coreplugin/actionmanager/command.cpp index d41637eaba9..fe2b1c31e95 100644 --- a/src/plugins/coreplugin/actionmanager/command.cpp +++ b/src/plugins/coreplugin/actionmanager/command.cpp @@ -23,6 +23,7 @@ ** ****************************************************************************/ +#include "command.h" #include "command_p.h" #include <coreplugin/coreconstants.h> @@ -260,82 +261,92 @@ using namespace Utils; namespace Core { -namespace Internal { -Action::Action(Id id) - : m_attributes({}), - m_id(id), - m_action(new Utils::ProxyAction(this)) +Command::Command(Utils::Id id) + : d(new Internal::CommandPrivate(this)) +{ + d->m_id = id; +} + +Command::~Command() +{ + delete d; +} + +Internal::CommandPrivate::CommandPrivate(Command *parent) + : m_q(parent) + , m_attributes({}) + , m_action(new Utils::ProxyAction(this)) { m_action->setShortcutVisibleInToolTip(true); - connect(m_action, &QAction::changed, this, &Action::updateActiveState); + connect(m_action, &QAction::changed, this, &CommandPrivate::updateActiveState); } -Id Action::id() const +Id Command::id() const { - return m_id; + return d->m_id; } -void Action::setDefaultKeySequence(const QKeySequence &key) +void Command::setDefaultKeySequence(const QKeySequence &key) { - if (!m_isKeyInitialized) + if (!d->m_isKeyInitialized) setKeySequences({key}); - m_defaultKeys = {key}; + d->m_defaultKeys = {key}; } -void Action::setDefaultKeySequences(const QList<QKeySequence> &keys) +void Command::setDefaultKeySequences(const QList<QKeySequence> &keys) { - if (!m_isKeyInitialized) + if (!d->m_isKeyInitialized) setKeySequences(keys); - m_defaultKeys = keys; + d->m_defaultKeys = keys; } -QList<QKeySequence> Action::defaultKeySequences() const +QList<QKeySequence> Command::defaultKeySequences() const { - return m_defaultKeys; + return d->m_defaultKeys; } -QAction *Action::action() const +QAction *Command::action() const { - return m_action; + return d->m_action; } -QString Action::stringWithAppendedShortcut(const QString &str) const +QString Command::stringWithAppendedShortcut(const QString &str) const { return Utils::ProxyAction::stringWithAppendedShortcut(str, keySequence()); } -Context Action::context() const +Context Command::context() const { - return m_context; + return d->m_context; } -void Action::setKeySequences(const QList<QKeySequence> &keys) +void Command::setKeySequences(const QList<QKeySequence> &keys) { - m_isKeyInitialized = true; - m_action->setShortcuts(keys); + d->m_isKeyInitialized = true; + d->m_action->setShortcuts(keys); emit keySequenceChanged(); } -QList<QKeySequence> Action::keySequences() const +QList<QKeySequence> Command::keySequences() const { - return m_action->shortcuts(); + return d->m_action->shortcuts(); } -QKeySequence Action::keySequence() const +QKeySequence Command::keySequence() const { - return m_action->shortcut(); + return d->m_action->shortcut(); } -void Action::setDescription(const QString &text) +void Command::setDescription(const QString &text) { - m_defaultText = text; + d->m_defaultText = text; } -QString Action::description() const +QString Command::description() const { - if (!m_defaultText.isEmpty()) - return m_defaultText; + if (!d->m_defaultText.isEmpty()) + return d->m_defaultText; if (QAction *act = action()) { const QString text = Utils::stripAccelerator(act->text()); if (!text.isEmpty()) @@ -344,7 +355,7 @@ QString Action::description() const return id().toString(); } -void Action::setCurrentContext(const Context &context) +void Internal::CommandPrivate::setCurrentContext(const Context &context) { m_context = context; @@ -360,7 +371,7 @@ void Action::setCurrentContext(const Context &context) updateActiveState(); } -void Action::updateActiveState() +void Internal::CommandPrivate::updateActiveState() { setActive(m_action->isEnabled() && m_action->isVisible() && !m_action->isSeparator()); } @@ -377,7 +388,9 @@ static QString msgActionWarning(QAction *newAction, Id id, QAction *oldAction) return msg; } -void Action::addOverrideAction(QAction *action, const Context &context, bool scriptable) +void Internal::CommandPrivate::addOverrideAction(QAction *action, + const Context &context, + bool scriptable) { // disallow TextHeuristic menu role, because it doesn't work with translations, // e.g. QTCREATORBUG-13101 @@ -398,7 +411,7 @@ void Action::addOverrideAction(QAction *action, const Context &context, bool scr setCurrentContext(m_context); } -void Action::removeOverrideAction(QAction *action) +void Internal::CommandPrivate::removeOverrideAction(QAction *action) { QList<Id> toRemove; for (auto it = m_contextActionMap.cbegin(), end = m_contextActionMap.cend(); it != end; ++it) { @@ -410,125 +423,123 @@ void Action::removeOverrideAction(QAction *action) setCurrentContext(m_context); } -bool Action::isActive() const +bool Command::isActive() const { - return m_active; + return d->m_active; } -void Action::setActive(bool state) +void Internal::CommandPrivate::setActive(bool state) { if (state != m_active) { m_active = state; - emit activeStateChanged(); + emit m_q->activeStateChanged(); } } -bool Action::isEmpty() const +bool Internal::CommandPrivate::isEmpty() const { return m_contextActionMap.isEmpty(); } -bool Action::isScriptable() const +bool Command::isScriptable() const { - return std::find(m_scriptableMap.cbegin(), m_scriptableMap.cend(), true) != - m_scriptableMap.cend(); + return std::find(d->m_scriptableMap.cbegin(), d->m_scriptableMap.cend(), true) + != d->m_scriptableMap.cend(); } -bool Action::isScriptable(const Context &context) const +bool Command::isScriptable(const Context &context) const { - if (context == m_context && m_scriptableMap.contains(m_action->action())) - return m_scriptableMap.value(m_action->action()); + if (context == d->m_context && d->m_scriptableMap.contains(d->m_action->action())) + return d->m_scriptableMap.value(d->m_action->action()); for (int i = 0; i < context.size(); ++i) { - if (QAction *a = m_contextActionMap.value(context.at(i), nullptr)) { - if (m_scriptableMap.contains(a) && m_scriptableMap.value(a)) + if (QAction *a = d->m_contextActionMap.value(context.at(i), nullptr)) { + if (d->m_scriptableMap.contains(a) && d->m_scriptableMap.value(a)) return true; } } return false; } -void Action::setAttribute(CommandAttribute attr) +void Command::setAttribute(CommandAttribute attr) { - m_attributes |= attr; + d->m_attributes |= attr; switch (attr) { case Command::CA_Hide: - m_action->setAttribute(Utils::ProxyAction::Hide); + d->m_action->setAttribute(Utils::ProxyAction::Hide); break; case Command::CA_UpdateText: - m_action->setAttribute(Utils::ProxyAction::UpdateText); + d->m_action->setAttribute(Utils::ProxyAction::UpdateText); break; case Command::CA_UpdateIcon: - m_action->setAttribute(Utils::ProxyAction::UpdateIcon); + d->m_action->setAttribute(Utils::ProxyAction::UpdateIcon); break; case Command::CA_NonConfigurable: break; } } -void Action::removeAttribute(CommandAttribute attr) +void Command::removeAttribute(CommandAttribute attr) { - m_attributes &= ~attr; + d->m_attributes &= ~attr; switch (attr) { case Command::CA_Hide: - m_action->removeAttribute(Utils::ProxyAction::Hide); + d->m_action->removeAttribute(Utils::ProxyAction::Hide); break; case Command::CA_UpdateText: - m_action->removeAttribute(Utils::ProxyAction::UpdateText); + d->m_action->removeAttribute(Utils::ProxyAction::UpdateText); break; case Command::CA_UpdateIcon: - m_action->removeAttribute(Utils::ProxyAction::UpdateIcon); + d->m_action->removeAttribute(Utils::ProxyAction::UpdateIcon); break; case Command::CA_NonConfigurable: break; } } -bool Action::hasAttribute(Command::CommandAttribute attr) const +bool Command::hasAttribute(CommandAttribute attr) const { - return (m_attributes & attr); + return (d->m_attributes & attr); } -void Action::setTouchBarText(const QString &text) +void Command::setTouchBarText(const QString &text) { - m_touchBarText = text; + d->m_touchBarText = text; } -QString Action::touchBarText() const +QString Command::touchBarText() const { - return m_touchBarText; + return d->m_touchBarText; } -void Action::setTouchBarIcon(const QIcon &icon) +void Command::setTouchBarIcon(const QIcon &icon) { - m_touchBarIcon = icon; + d->m_touchBarIcon = icon; } -QIcon Action::touchBarIcon() const +QIcon Command::touchBarIcon() const { - return m_touchBarIcon; + return d->m_touchBarIcon; } -QAction *Action::touchBarAction() const +QAction *Command::touchBarAction() const { - if (!m_touchBarAction) { - m_touchBarAction = std::make_unique<Utils::ProxyAction>(); - m_touchBarAction->initialize(m_action); - m_touchBarAction->setIcon(m_touchBarIcon); - m_touchBarAction->setText(m_touchBarText); + if (!d->m_touchBarAction) { + d->m_touchBarAction = std::make_unique<Utils::ProxyAction>(); + d->m_touchBarAction->initialize(d->m_action); + d->m_touchBarAction->setIcon(d->m_touchBarIcon); + d->m_touchBarAction->setText(d->m_touchBarText); // the touch bar action should be hidden if the command is not valid for the context - m_touchBarAction->setAttribute(Utils::ProxyAction::Hide); - m_touchBarAction->setAction(m_action->action()); - connect(m_action, + d->m_touchBarAction->setAttribute(Utils::ProxyAction::Hide); + d->m_touchBarAction->setAction(d->m_action->action()); + connect(d->m_action, &Utils::ProxyAction::currentActionChanged, - m_touchBarAction.get(), + d->m_touchBarAction.get(), &Utils::ProxyAction::setAction); } - return m_touchBarAction.get(); + return d->m_touchBarAction.get(); } -} // namespace Internal - /*! Appends the main keyboard shortcut that is currently assigned to the action \a a to its tool tip. diff --git a/src/plugins/coreplugin/actionmanager/command.h b/src/plugins/coreplugin/actionmanager/command.h index 677a1308185..f2c89469f34 100644 --- a/src/plugins/coreplugin/actionmanager/command.h +++ b/src/plugins/coreplugin/actionmanager/command.h @@ -40,7 +40,12 @@ QT_END_NAMESPACE namespace Core { +namespace Internal { +class ActionManagerPrivate; +class CommandPrivate; +} // namespace Internal +class ActionManager; class Context; constexpr bool useMacShortcuts = Utils::HostOsInfo::isMacHost(); @@ -57,46 +62,56 @@ public: }; Q_DECLARE_FLAGS(CommandAttributes, CommandAttribute) - virtual void setDefaultKeySequence(const QKeySequence &key) = 0; - virtual void setDefaultKeySequences(const QList<QKeySequence> &keys) = 0; - virtual QList<QKeySequence> defaultKeySequences() const = 0; - virtual QList<QKeySequence> keySequences() const = 0; - virtual QKeySequence keySequence() const = 0; + ~Command(); + + void setDefaultKeySequence(const QKeySequence &key); + void setDefaultKeySequences(const QList<QKeySequence> &keys); + QList<QKeySequence> defaultKeySequences() const; + QList<QKeySequence> keySequences() const; + QKeySequence keySequence() const; // explicitly set the description (used e.g. in shortcut settings) // default is to use the action text for actions, or the whatsThis for shortcuts, // or, as a last fall back if these are empty, the command ID string // override the default e.g. if the text is context dependent and contains file names etc - virtual void setDescription(const QString &text) = 0; - virtual QString description() const = 0; + void setDescription(const QString &text); + QString description() const; - virtual Utils::Id id() const = 0; + Utils::Id id() const; - virtual QAction *action() const = 0; - virtual Context context() const = 0; + QAction *action() const; + Context context() const; - virtual void setAttribute(CommandAttribute attr) = 0; - virtual void removeAttribute(CommandAttribute attr) = 0; - virtual bool hasAttribute(CommandAttribute attr) const = 0; + void setAttribute(CommandAttribute attr); + void removeAttribute(CommandAttribute attr); + bool hasAttribute(CommandAttribute attr) const; - virtual bool isActive() const = 0; + bool isActive() const; - virtual void setKeySequences(const QList<QKeySequence> &keys) = 0; - virtual QString stringWithAppendedShortcut(const QString &str) const = 0; + void setKeySequences(const QList<QKeySequence> &keys); + QString stringWithAppendedShortcut(const QString &str) const; void augmentActionWithShortcutToolTip(QAction *action) const; static QToolButton *toolButtonWithAppendedShortcut(QAction *action, Command *cmd); - virtual bool isScriptable() const = 0; - virtual bool isScriptable(const Context &) const = 0; + bool isScriptable() const; + bool isScriptable(const Context &) const; - virtual void setTouchBarText(const QString &text) = 0; - virtual QString touchBarText() const = 0; - virtual void setTouchBarIcon(const QIcon &icon) = 0; - virtual QIcon touchBarIcon() const = 0; - virtual QAction *touchBarAction() const = 0; + void setTouchBarText(const QString &text); + QString touchBarText() const; + void setTouchBarIcon(const QIcon &icon); + QIcon touchBarIcon() const; + QAction *touchBarAction() const; signals: void keySequenceChanged(); void activeStateChanged(); + +private: + friend class ActionManager; + friend class Internal::ActionManagerPrivate; + + Command(Utils::Id id); + + Internal::CommandPrivate *d; }; } // namespace Core diff --git a/src/plugins/coreplugin/actionmanager/command_p.h b/src/plugins/coreplugin/actionmanager/command_p.h index 94f72ddfa1e..a0b412c1ee9 100644 --- a/src/plugins/coreplugin/actionmanager/command_p.h +++ b/src/plugins/coreplugin/actionmanager/command_p.h @@ -43,56 +43,24 @@ namespace Core { namespace Internal { -class Action : public Command +class CommandPrivate : public QObject { Q_OBJECT public: - Action(Utils::Id id); + CommandPrivate(Command *parent); - Utils::Id id() const override; - - void setDefaultKeySequence(const QKeySequence &key) override; - void setDefaultKeySequences(const QList<QKeySequence> &key) override; - QList<QKeySequence> defaultKeySequences() const override; - - void setKeySequences(const QList<QKeySequence> &keys) override; - QList<QKeySequence> keySequences() const override; - QKeySequence keySequence() const override; - - void setDescription(const QString &text) override; - QString description() const override; - - QAction *action() const override; - - QString stringWithAppendedShortcut(const QString &str) const override; - - Context context() const override; void setCurrentContext(const Context &context); - bool isActive() const override; void addOverrideAction(QAction *action, const Context &context, bool scriptable); void removeOverrideAction(QAction *action); bool isEmpty() const; - bool isScriptable() const override; - bool isScriptable(const Context &context) const override; - - void setAttribute(CommandAttribute attr) override; - void removeAttribute(CommandAttribute attr) override; - bool hasAttribute(CommandAttribute attr) const override; - - void setTouchBarText(const QString &text) override; - QString touchBarText() const override; - void setTouchBarIcon(const QIcon &icon) override; - QIcon touchBarIcon() const override; - QAction *touchBarAction() const override; - -private: void updateActiveState(); void setActive(bool state); + Command *m_q = nullptr; Context m_context; - CommandAttributes m_attributes; + Command::CommandAttributes m_attributes; Utils::Id m_id; QList<QKeySequence> m_defaultKeys; QString m_defaultText; diff --git a/src/plugins/coreplugin/actionmanager/commandsfile.cpp b/src/plugins/coreplugin/actionmanager/commandsfile.cpp index 340eb969de0..8d4964999be 100644 --- a/src/plugins/coreplugin/actionmanager/commandsfile.cpp +++ b/src/plugins/coreplugin/actionmanager/commandsfile.cpp @@ -24,7 +24,7 @@ ****************************************************************************/ #include "commandsfile.h" -#include "command_p.h" +#include "command.h" #include <coreplugin/dialogs/shortcutsettings.h> #include <coreplugin/icore.h> diff --git a/src/plugins/coreplugin/dialogs/shortcutsettings.cpp b/src/plugins/coreplugin/dialogs/shortcutsettings.cpp index 35e1deb2880..37f860926c4 100644 --- a/src/plugins/coreplugin/dialogs/shortcutsettings.cpp +++ b/src/plugins/coreplugin/dialogs/shortcutsettings.cpp @@ -29,7 +29,6 @@ #include <coreplugin/icore.h> #include <coreplugin/actionmanager/actionmanager.h> #include <coreplugin/actionmanager/command.h> -#include <coreplugin/actionmanager/command_p.h> #include <coreplugin/actionmanager/commandsfile.h> #include <utils/algorithm.h> @@ -38,15 +37,16 @@ #include <utils/qtcassert.h> #include <utils/theme/theme.h> -#include <QKeyEvent> +#include <QAction> +#include <QApplication> +#include <QDebug> #include <QFileDialog> #include <QGroupBox> #include <QHBoxLayout> +#include <QKeyEvent> #include <QLabel> #include <QLineEdit> #include <QTreeWidgetItem> -#include <QApplication> -#include <QDebug> using namespace Utils; diff --git a/src/plugins/coreplugin/mainwindow.cpp b/src/plugins/coreplugin/mainwindow.cpp index 7495949271c..1fa6d4be141 100644 --- a/src/plugins/coreplugin/mainwindow.cpp +++ b/src/plugins/coreplugin/mainwindow.cpp @@ -71,10 +71,12 @@ #include <utils/historycompleter.h> #include <utils/hostosinfo.h> #include <utils/mimeutils.h> +#include <utils/proxyaction.h> #include <utils/qtcassert.h> #include <utils/stringutils.h> #include <utils/stylehelper.h> #include <utils/theme/theme.h> +#include <utils/touchbar/touchbar.h> #include <utils/utilsicons.h> #include <QActionGroup> diff --git a/src/plugins/cppeditor/CMakeLists.txt b/src/plugins/cppeditor/CMakeLists.txt index b25ab9dab3a..a2f09056bbc 100644 --- a/src/plugins/cppeditor/CMakeLists.txt +++ b/src/plugins/cppeditor/CMakeLists.txt @@ -115,7 +115,6 @@ add_qtc_plugin(CppEditor symbolfinder.cpp symbolfinder.h symbolsfindfilter.cpp symbolsfindfilter.h typehierarchybuilder.cpp typehierarchybuilder.h - usages.h wrappablelineedit.cpp wrappablelineedit.h EXPLICIT_MOC cppquickfixsettingswidget.h diff --git a/src/plugins/cppeditor/cppbuiltinmodelmanagersupport.cpp b/src/plugins/cppeditor/cppbuiltinmodelmanagersupport.cpp index 4e2f442bebc..534861e0ea8 100644 --- a/src/plugins/cppeditor/cppbuiltinmodelmanagersupport.cpp +++ b/src/plugins/cppeditor/cppbuiltinmodelmanagersupport.cpp @@ -170,7 +170,6 @@ void BuiltinModelManagerSupport::startLocalRenaming(const CursorInEditor &data, } void BuiltinModelManagerSupport::globalRename(const CursorInEditor &data, - UsagesCallback &&, const QString &replacement) { CppModelManager *modelManager = CppModelManager::instance(); @@ -194,8 +193,7 @@ void BuiltinModelManagerSupport::globalRename(const CursorInEditor &data, } } -void BuiltinModelManagerSupport::findUsages(const CursorInEditor &data, - UsagesCallback &&) const +void BuiltinModelManagerSupport::findUsages(const CursorInEditor &data) const { CppModelManager *modelManager = CppModelManager::instance(); if (!modelManager) diff --git a/src/plugins/cppeditor/cppbuiltinmodelmanagersupport.h b/src/plugins/cppeditor/cppbuiltinmodelmanagersupport.h index c5b1406b8b3..91fd7abe70e 100644 --- a/src/plugins/cppeditor/cppbuiltinmodelmanagersupport.h +++ b/src/plugins/cppeditor/cppbuiltinmodelmanagersupport.h @@ -58,9 +58,8 @@ private: void startLocalRenaming(const CursorInEditor &data, const ProjectPart *projectPart, RenameCallback &&renameSymbolsCallback) override; - void globalRename(const CursorInEditor &data, UsagesCallback &&, - const QString &replacement) override; - void findUsages(const CursorInEditor &data, UsagesCallback &&) const override; + void globalRename(const CursorInEditor &data, const QString &replacement) override; + void findUsages(const CursorInEditor &data) const override; void switchHeaderSource(const Utils::FilePath &filePath, bool inNextSplit) override; QScopedPointer<CppCompletionAssistProvider> m_completionAssistProvider; diff --git a/src/plugins/cppeditor/cppeditor.qbs b/src/plugins/cppeditor/cppeditor.qbs index 523f81073b0..59037cfc1a9 100644 --- a/src/plugins/cppeditor/cppeditor.qbs +++ b/src/plugins/cppeditor/cppeditor.qbs @@ -246,7 +246,6 @@ QtcPlugin { "symbolsfindfilter.h", "typehierarchybuilder.cpp", "typehierarchybuilder.h", - "usages.h", "wrappablelineedit.cpp", // FIXME: Is this used? "wrappablelineedit.h", ] diff --git a/src/plugins/cppeditor/cppeditorwidget.cpp b/src/plugins/cppeditor/cppeditorwidget.cpp index 7c00340fd5c..f6409bdbd1c 100644 --- a/src/plugins/cppeditor/cppeditorwidget.cpp +++ b/src/plugins/cppeditor/cppeditorwidget.cpp @@ -714,76 +714,6 @@ static QTextDocument *getOpenDocument(const QString &path) return {}; } -static void addSearchResults(Usages usages, SearchResult &search, const QString &text) -{ - std::sort(usages.begin(), usages.end()); - - std::unique_ptr<QTextDocument> currentDocument; - QString lastPath; - - for (const Usage &usage : usages) { - QTextDocument *document = getOpenDocument(usage.path); - - if (!document) { - if (usage.path != lastPath) { - currentDocument = getCurrentDocument(usage.path); - lastPath = usage.path; - } - document = currentDocument.get(); - } - - const QString lineContent = getDocumentLine(document, usage.line); - - if (!lineContent.isEmpty()) { - Search::TextRange range{Search::TextPosition(usage.line, usage.column - 1), - Search::TextPosition(usage.line, usage.column + text.length() - 1)}; - SearchResultItem item; - item.setFilePath(FilePath::fromString(usage.path)); - item.setLineText(lineContent); - item.setMainRange(range); - item.setUseTextEditorFont(true); - search.addResult(item); - } - } -} - -static void findRenameCallback(CppEditorWidget *widget, - const QTextCursor &baseCursor, - const Usages &usages, - bool rename = false, - const QString &replacement = QString()) -{ - QTextCursor cursor = Utils::Text::wordStartCursor(baseCursor); - cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor); - const QString text = cursor.selectedText(); - SearchResultWindow::SearchMode mode = SearchResultWindow::SearchOnly; - if (rename) - mode = SearchResultWindow::SearchAndReplace; - SearchResult *search = SearchResultWindow::instance()->startNewSearch( - QObject::tr("C++ Usages:"), - QString(), - text, - mode, - SearchResultWindow::PreserveCaseDisabled, - QLatin1String("CppEditor")); - search->setTextToReplace(replacement); - search->setSearchAgainSupported(true); - QObject::connect(search, &SearchResult::replaceButtonClicked, &onReplaceUsagesClicked); - QObject::connect(search, &SearchResult::searchAgainRequested, - [widget, rename, replacement, baseCursor]() { - rename ? widget->renameUsages(replacement, baseCursor) : widget->findUsages(baseCursor); - }); - - addSearchResults(usages, *search, text); - - search->finishSearch(false); - QObject::connect(search, &SearchResult::activated, - [](const Core::SearchResultItem& item) { - Core::EditorManager::openEditorAtSearchResult(item); - }); - search->popup(); -} - void CppEditorWidget::findUsages() { findUsages(textCursor()); @@ -792,32 +722,18 @@ void CppEditorWidget::findUsages() void CppEditorWidget::findUsages(QTextCursor cursor) { // 'this' in cursorInEditor is never used (and must never be used) asynchronously. - const CursorInEditor cursorInEditor{cursor, textDocument()->filePath(), this, - textDocument()}; + const CursorInEditor cursorInEditor{cursor, textDocument()->filePath(), this, textDocument()}; QPointer<CppEditorWidget> cppEditorWidget = this; - d->m_modelManager->findUsages(cursorInEditor, - [=](const Usages &usages) { - if (!cppEditorWidget) - return; - findRenameCallback(cppEditorWidget.data(), cursor, usages); - }); + d->m_modelManager->findUsages(cursorInEditor); } void CppEditorWidget::renameUsages(const QString &replacement, QTextCursor cursor) { if (cursor.isNull()) cursor = textCursor(); - CursorInEditor cursorInEditor{cursor, textDocument()->filePath(), this, - textDocument()}; + CursorInEditor cursorInEditor{cursor, textDocument()->filePath(), this, textDocument()}; QPointer<CppEditorWidget> cppEditorWidget = this; - d->m_modelManager->globalRename(cursorInEditor, - [=](const Usages &usages) { - if (!cppEditorWidget) - return; - findRenameCallback(cppEditorWidget.data(), cursor, usages, - true, replacement); - }, - replacement); + d->m_modelManager->globalRename(cursorInEditor, replacement); } bool CppEditorWidget::selectBlockUp() diff --git a/src/plugins/cppeditor/cppmodelmanager.cpp b/src/plugins/cppeditor/cppmodelmanager.cpp index b1b93787980..f6ab5f7453d 100644 --- a/src/plugins/cppeditor/cppmodelmanager.cpp +++ b/src/plugins/cppeditor/cppmodelmanager.cpp @@ -316,17 +316,15 @@ void CppModelManager::startLocalRenaming(const CursorInEditor &data, ->startLocalRenaming(data, projectPart, std::move(renameSymbolsCallback)); } -void CppModelManager::globalRename(const CursorInEditor &data, UsagesCallback &&renameCallback, - const QString &replacement, Backend backend) +void CppModelManager::globalRename(const CursorInEditor &data, const QString &replacement, + Backend backend) { - instance()->modelManagerSupport(backend) - ->globalRename(data, std::move(renameCallback), replacement); + instance()->modelManagerSupport(backend)->globalRename(data, replacement); } -void CppModelManager::findUsages(const CursorInEditor &data, - UsagesCallback &&showUsagesCallback, Backend backend) +void CppModelManager::findUsages(const CursorInEditor &data, Backend backend) { - instance()->modelManagerSupport(backend)->findUsages(data, std::move(showUsagesCallback)); + instance()->modelManagerSupport(backend)->findUsages(data); } void CppModelManager::switchHeaderSource(bool inNextSplit, Backend backend) diff --git a/src/plugins/cppeditor/cppmodelmanager.h b/src/plugins/cppeditor/cppmodelmanager.h index da04a942612..a475c8e4f37 100644 --- a/src/plugins/cppeditor/cppmodelmanager.h +++ b/src/plugins/cppeditor/cppmodelmanager.h @@ -30,7 +30,6 @@ #include "cursorineditor.h" #include "projectinfo.h" #include "projectpart.h" -#include "usages.h" #include <cplusplus/cppmodelmanagerbase.h> #include <coreplugin/find/ifindfilter.h> @@ -179,10 +178,9 @@ public: static void startLocalRenaming(const CursorInEditor &data, const ProjectPart *projectPart, RenameCallback &&renameSymbolsCallback, Backend backend = Backend::Best); - static void globalRename(const CursorInEditor &data, UsagesCallback &&renameCallback, - const QString &replacement, Backend backend = Backend::Best); - static void findUsages(const CursorInEditor &data, UsagesCallback &&showUsagesCallback, - Backend backend = Backend::Best); + static void globalRename(const CursorInEditor &data, const QString &replacement, + Backend backend = Backend::Best); + static void findUsages(const CursorInEditor &data, Backend backend = Backend::Best); static void switchHeaderSource(bool inNextSplit, Backend backend = Backend::Best); static Core::ILocatorFilter *createAuxiliaryCurrentDocumentFilter(); diff --git a/src/plugins/cppeditor/cppmodelmanagersupport.h b/src/plugins/cppeditor/cppmodelmanagersupport.h index 1c789dc99c8..44fff4b4f65 100644 --- a/src/plugins/cppeditor/cppmodelmanagersupport.h +++ b/src/plugins/cppeditor/cppmodelmanagersupport.h @@ -27,7 +27,6 @@ #include "cppeditor_global.h" #include "cursorineditor.h" -#include "usages.h" #include <utils/link.h> @@ -73,11 +72,8 @@ public: virtual void startLocalRenaming(const CursorInEditor &data, const ProjectPart *projectPart, RenameCallback &&renameSymbolsCallback) = 0; - virtual void globalRename(const CursorInEditor &data, - UsagesCallback &&renameCallback, - const QString &replacement) = 0; - virtual void findUsages(const CursorInEditor &data, - UsagesCallback &&showUsagesCallback) const = 0; + virtual void globalRename(const CursorInEditor &data, const QString &replacement) = 0; + virtual void findUsages(const CursorInEditor &data) const = 0; virtual void switchHeaderSource(const Utils::FilePath &filePath, bool inNextSplit) = 0; }; diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp index 3d2469fd95a..c14fe66255c 100644 --- a/src/plugins/cppeditor/cppquickfixes.cpp +++ b/src/plugins/cppeditor/cppquickfixes.cpp @@ -8171,6 +8171,9 @@ private: void RemoveUsingNamespace::match(const CppQuickFixInterface &interface, QuickFixOperations &result) { + if (CppModelManager::usesClangd(interface.currentFile()->editor()->textDocument())) + return; + const QList<AST *> &path = interface.path(); // We expect something like // [0] TranslationUnitAST diff --git a/src/plugins/docker/kitdetector.cpp b/src/plugins/docker/kitdetector.cpp index 474322a6043..5e0c2e86598 100644 --- a/src/plugins/docker/kitdetector.cpp +++ b/src/plugins/docker/kitdetector.cpp @@ -214,10 +214,10 @@ QtVersions KitDetectorPrivate::autoDetectQtVersions() const QString error; const auto handleQmake = [this, &qtVersions, &error](const FilePath &qmake) { - if (QtVersion *qtVersion = QtVersionFactory::createQtVersionFromQueryToolPath(qmake, - false, - m_sharedId, - &error)) { + if (QtVersion *qtVersion = QtVersionFactory::createQtVersionFromQMakePath(qmake, + false, + m_sharedId, + &error)) { if (qtVersion->isValid()) { if (!Utils::anyOf(qtVersions, [qtVersion](QtVersion* other) { @@ -227,7 +227,7 @@ QtVersions KitDetectorPrivate::autoDetectQtVersions() const qtVersions.append(qtVersion); QtVersionManager::addVersion(qtVersion); emit q->logOutput( - tr("Found \"%1\"").arg(qtVersion->queryToolFilePath().toUserOutput())); + tr("Found \"%1\"").arg(qtVersion->qmakeFilePath().toUserOutput())); } } } diff --git a/src/plugins/ios/iosrunconfiguration.cpp b/src/plugins/ios/iosrunconfiguration.cpp index 9014d87184c..2636fe365b2 100644 --- a/src/plugins/ios/iosrunconfiguration.cpp +++ b/src/plugins/ios/iosrunconfiguration.cpp @@ -80,7 +80,7 @@ static IosDeviceType toIosDeviceType(const SimulatorInfo &device) IosRunConfiguration::IosRunConfiguration(Target *target, Id id) : RunConfiguration(target, id) { - auto executableAspect = addAspect<ExecutableAspect>(target); + auto executableAspect = addAspect<ExecutableAspect>(target, ExecutableAspect::RunDevice); executableAspect->setDisplayStyle(StringAspect::LabelDisplay); addAspect<ArgumentsAspect>(macroExpander()); diff --git a/src/plugins/languageclient/languageclientfunctionhint.cpp b/src/plugins/languageclient/languageclientfunctionhint.cpp index 319aad22338..1e0cd62cfe3 100644 --- a/src/plugins/languageclient/languageclientfunctionhint.cpp +++ b/src/plugins/languageclient/languageclientfunctionhint.cpp @@ -103,6 +103,7 @@ IAssistProposal *FunctionHintProcessor::perform(const AssistInterface *interface void FunctionHintProcessor::cancel() { + QTC_ASSERT(m_client, return); if (running()) { m_client->cancelRequest(*m_currentRequest); m_client->removeAssistProcessor(this); @@ -112,6 +113,7 @@ void FunctionHintProcessor::cancel() void FunctionHintProcessor::handleSignatureResponse(const SignatureHelpRequest::Response &response) { + QTC_ASSERT(m_client, setAsyncProposalAvailable(nullptr); return); m_currentRequest.reset(); if (auto error = response.error()) m_client->log(*error); diff --git a/src/plugins/languageclient/languageclientinterface.cpp b/src/plugins/languageclient/languageclientinterface.cpp index 5b09dd98f2c..49d0699a665 100644 --- a/src/plugins/languageclient/languageclientinterface.cpp +++ b/src/plugins/languageclient/languageclientinterface.cpp @@ -99,7 +99,9 @@ void BaseClientInterface::parseCurrentMessage() m_currentMessage = BaseMessage(); } -StdIOClientInterface::StdIOClientInterface() {} +StdIOClientInterface::StdIOClientInterface() + : m_env(Utils::Environment::systemEnvironment()) +{} StdIOClientInterface::~StdIOClientInterface() { @@ -124,6 +126,7 @@ void StdIOClientInterface::startImpl() connect(m_process, &QtcProcess::started, this, &StdIOClientInterface::started); m_process->setCommand(m_cmd); m_process->setWorkingDirectory(m_workingDirectory); + m_process->setEnvironment(m_env); m_process->start(); } @@ -137,6 +140,11 @@ void StdIOClientInterface::setWorkingDirectory(const FilePath &workingDirectory) m_workingDirectory = workingDirectory; } +void StdIOClientInterface::setEnvironment(const Utils::Environment &environment) +{ + m_env = environment; +} + void StdIOClientInterface::sendData(const QByteArray &data) { if (!m_process || m_process->state() != QProcess::Running) { diff --git a/src/plugins/languageclient/languageclientinterface.h b/src/plugins/languageclient/languageclientinterface.h index 75a7fbb1db1..083d7c3a675 100644 --- a/src/plugins/languageclient/languageclientinterface.h +++ b/src/plugins/languageclient/languageclientinterface.h @@ -29,6 +29,7 @@ #include <languageserverprotocol/jsonrpcmessages.h> +#include <utils/environment.h> #include <utils/qtcprocess.h> #include <QBuffer> @@ -84,12 +85,14 @@ public: // These functions only have an effect if they are called before start void setCommandLine(const Utils::CommandLine &cmd); void setWorkingDirectory(const Utils::FilePath &workingDirectory); + void setEnvironment(const Utils::Environment &environment); protected: void sendData(const QByteArray &data) final; Utils::CommandLine m_cmd; Utils::FilePath m_workingDirectory; Utils::QtcProcess *m_process = nullptr; + Utils::Environment m_env; private: void readError(); diff --git a/src/plugins/mesonprojectmanager/project/mesonrunconfiguration.cpp b/src/plugins/mesonprojectmanager/project/mesonrunconfiguration.cpp index 84f226ab6f7..bfc3b6ee0ea 100644 --- a/src/plugins/mesonprojectmanager/project/mesonrunconfiguration.cpp +++ b/src/plugins/mesonprojectmanager/project/mesonrunconfiguration.cpp @@ -36,31 +36,29 @@ #include <utils/environment.h> #include <utils/hostosinfo.h> +using namespace ProjectExplorer; + namespace MesonProjectManager { namespace Internal { -MesonRunConfiguration::MesonRunConfiguration(ProjectExplorer::Target *target, Utils::Id id) - : ProjectExplorer::RunConfiguration{target, id} +MesonRunConfiguration::MesonRunConfiguration(Target *target, Utils::Id id) + : RunConfiguration{target, id} { - auto envAspect = addAspect<ProjectExplorer::LocalEnvironmentAspect>(target); + auto envAspect = addAspect<LocalEnvironmentAspect>(target); - addAspect<ProjectExplorer::ExecutableAspect>(target); - addAspect<ProjectExplorer::ArgumentsAspect>(macroExpander()); - addAspect<ProjectExplorer::WorkingDirectoryAspect>(macroExpander(), envAspect); - addAspect<ProjectExplorer::TerminalAspect>(); + addAspect<ExecutableAspect>(target, ExecutableAspect::RunDevice); + addAspect<ArgumentsAspect>(macroExpander()); + addAspect<WorkingDirectoryAspect>(macroExpander(), envAspect); + addAspect<TerminalAspect>(); - auto libAspect = addAspect<ProjectExplorer::UseLibraryPathsAspect>(); - connect(libAspect, - &ProjectExplorer::UseLibraryPathsAspect::changed, - envAspect, - &ProjectExplorer::EnvironmentAspect::environmentChanged); + auto libAspect = addAspect<UseLibraryPathsAspect>(); + connect(libAspect, &UseLibraryPathsAspect::changed, + envAspect, &EnvironmentAspect::environmentChanged); if (Utils::HostOsInfo::isMacHost()) { - auto dyldAspect = addAspect<ProjectExplorer::UseDyldSuffixAspect>(); - connect(dyldAspect, - &ProjectExplorer::UseLibraryPathsAspect::changed, - envAspect, - &ProjectExplorer::EnvironmentAspect::environmentChanged); + auto dyldAspect = addAspect<UseDyldSuffixAspect>(); + connect(dyldAspect, &UseLibraryPathsAspect::changed, + envAspect, &EnvironmentAspect::environmentChanged); envAspect->addModifier([dyldAspect](Utils::Environment &env) { if (dyldAspect->value()) env.set(QLatin1String("DYLD_IMAGE_SUFFIX"), QLatin1String("_debug")); @@ -68,17 +66,14 @@ MesonRunConfiguration::MesonRunConfiguration(ProjectExplorer::Target *target, Ut } envAspect->addModifier([this, libAspect](Utils::Environment &env) { - ProjectExplorer::BuildTargetInfo bti = buildTargetInfo(); + BuildTargetInfo bti = buildTargetInfo(); if (bti.runEnvModifier) bti.runEnvModifier(env, libAspect->value()); }); setUpdater([this] { updateTargetInformation(); }); - connect(target, - &ProjectExplorer::Target::buildSystemUpdated, - this, - &ProjectExplorer::RunConfiguration::update); + connect(target, &Target::buildSystemUpdated, this, &RunConfiguration::update); } void MesonRunConfiguration::updateTargetInformation() @@ -86,13 +81,11 @@ void MesonRunConfiguration::updateTargetInformation() if (!activeBuildSystem()) return; - ProjectExplorer::BuildTargetInfo bti = buildTargetInfo(); - auto terminalAspect = aspect<ProjectExplorer::TerminalAspect>(); - terminalAspect->setUseTerminalHint(bti.usesTerminal); - aspect<ProjectExplorer::ExecutableAspect>()->setExecutable(bti.targetFilePath); - aspect<ProjectExplorer::WorkingDirectoryAspect>()->setDefaultWorkingDirectory( - bti.workingDirectory); - emit aspect<ProjectExplorer::LocalEnvironmentAspect>()->environmentChanged(); + BuildTargetInfo bti = buildTargetInfo(); + aspect<TerminalAspect>()->setUseTerminalHint(bti.usesTerminal); + aspect<ExecutableAspect>()->setExecutable(bti.targetFilePath); + aspect<WorkingDirectoryAspect>()->setDefaultWorkingDirectory(bti.workingDirectory); + emit aspect<LocalEnvironmentAspect>()->environmentChanged(); } MesonRunConfigurationFactory::MesonRunConfigurationFactory() diff --git a/src/plugins/nim/project/nimblerunconfiguration.cpp b/src/plugins/nim/project/nimblerunconfiguration.cpp index e88e2c11ad6..68d6d06b727 100644 --- a/src/plugins/nim/project/nimblerunconfiguration.cpp +++ b/src/plugins/nim/project/nimblerunconfiguration.cpp @@ -52,7 +52,7 @@ public: : RunConfiguration(target, id) { auto envAspect = addAspect<LocalEnvironmentAspect>(target); - addAspect<ExecutableAspect>(target); + addAspect<ExecutableAspect>(target, ExecutableAspect::RunDevice); addAspect<ArgumentsAspect>(macroExpander()); addAspect<WorkingDirectoryAspect>(macroExpander(), envAspect); addAspect<TerminalAspect>(); @@ -89,7 +89,8 @@ public: NimbleTestConfiguration(ProjectExplorer::Target *target, Utils::Id id) : RunConfiguration(target, id) { - addAspect<ExecutableAspect>(target)->setExecutable(Nim::nimblePathFromKit(target->kit())); + addAspect<ExecutableAspect>(target, ExecutableAspect::BuildDevice) + ->setExecutable(Nim::nimblePathFromKit(target->kit())); addAspect<ArgumentsAspect>(macroExpander())->setArguments("test"); addAspect<WorkingDirectoryAspect>(macroExpander(), nullptr) ->setDefaultWorkingDirectory(project()->projectDirectory()); diff --git a/src/plugins/nim/project/nimrunconfiguration.cpp b/src/plugins/nim/project/nimrunconfiguration.cpp index 925fac47736..af6fb6713f2 100644 --- a/src/plugins/nim/project/nimrunconfiguration.cpp +++ b/src/plugins/nim/project/nimrunconfiguration.cpp @@ -50,7 +50,7 @@ public: : RunConfiguration(target, id) { auto envAspect = addAspect<LocalEnvironmentAspect>(target); - addAspect<ExecutableAspect>(target); + addAspect<ExecutableAspect>(target, ExecutableAspect::RunDevice); addAspect<ArgumentsAspect>(macroExpander()); addAspect<WorkingDirectoryAspect>(macroExpander(), envAspect); addAspect<TerminalAspect>(); diff --git a/src/plugins/projectexplorer/customexecutablerunconfiguration.cpp b/src/plugins/projectexplorer/customexecutablerunconfiguration.cpp index cbd8705f6ff..936411a7f28 100644 --- a/src/plugins/projectexplorer/customexecutablerunconfiguration.cpp +++ b/src/plugins/projectexplorer/customexecutablerunconfiguration.cpp @@ -45,7 +45,7 @@ CustomExecutableRunConfiguration::CustomExecutableRunConfiguration(Target *targe { auto envAspect = addAspect<LocalEnvironmentAspect>(target); - auto exeAspect = addAspect<ExecutableAspect>(nullptr); // nullptr - to enforce host-only operation. + auto exeAspect = addAspect<ExecutableAspect>(target, ExecutableAspect::HostDevice); exeAspect->setSettingsKey("ProjectExplorer.CustomExecutableRunConfiguration.Executable"); exeAspect->setDisplayStyle(StringAspect::PathChooserDisplay); exeAspect->setHistoryCompleter("Qt.CustomExecutable.History"); diff --git a/src/plugins/projectexplorer/desktoprunconfiguration.cpp b/src/plugins/projectexplorer/desktoprunconfiguration.cpp index 663474afdc5..db39def1def 100644 --- a/src/plugins/projectexplorer/desktoprunconfiguration.cpp +++ b/src/plugins/projectexplorer/desktoprunconfiguration.cpp @@ -68,7 +68,7 @@ DesktopRunConfiguration::DesktopRunConfiguration(Target *target, Id id, Kind kin { auto envAspect = addAspect<LocalEnvironmentAspect>(target); - addAspect<ExecutableAspect>(target); + addAspect<ExecutableAspect>(target, ExecutableAspect::HostDevice); addAspect<ArgumentsAspect>(macroExpander()); addAspect<WorkingDirectoryAspect>(macroExpander(), envAspect); addAspect<TerminalAspect>(); diff --git a/src/plugins/projectexplorer/runconfigurationaspects.cpp b/src/plugins/projectexplorer/runconfigurationaspects.cpp index ab2e00e7440..eefe7ac4116 100644 --- a/src/plugins/projectexplorer/runconfigurationaspects.cpp +++ b/src/plugins/projectexplorer/runconfigurationaspects.cpp @@ -25,13 +25,12 @@ #include "runconfigurationaspects.h" +#include "devicesupport/devicemanager.h" #include "devicesupport/idevice.h" #include "environmentaspect.h" #include "kitinformation.h" -#include "project.h" #include "projectexplorer.h" #include "projectexplorersettings.h" -#include "runconfiguration.h" #include "target.h" #include <coreplugin/icore.h> @@ -514,8 +513,8 @@ void ArgumentsAspect::addToLayout(LayoutBuilder &builder) by the build system's parsing results with an optional manual override. */ -ExecutableAspect::ExecutableAspect(Target *target) - : m_target(target) +ExecutableAspect::ExecutableAspect(Target *target, ExecutionDeviceSelector selector) + : m_target(target), m_selector(selector) { setDisplayName(tr("Executable")); setId("ExecutableAspect"); @@ -534,9 +533,16 @@ ExecutableAspect::ExecutableAspect(Target *target) \internal */ -static IDevice::ConstPtr deviceForTarget(Target *target) +static IDevice::ConstPtr executionDevice(Target *target, + ExecutableAspect::ExecutionDeviceSelector selector) { - return target ? DeviceKitAspect::device(target->kit()) : IDevice::ConstPtr(); + if (target) { + if (selector == ExecutableAspect::RunDevice) + return DeviceKitAspect::device(target->kit()); + if (selector == ExecutableAspect::BuildDevice) + return BuildDeviceKitAspect::device(target->kit()); + } + return DeviceManager::defaultDesktopDevice(); } ExecutableAspect::~ExecutableAspect() @@ -547,7 +553,7 @@ ExecutableAspect::~ExecutableAspect() void ExecutableAspect::updateDevice() { - const IDevice::ConstPtr dev = deviceForTarget(m_target); + const IDevice::ConstPtr dev = executionDevice(m_target, m_selector); const OsType osType = dev ? dev->osType() : HostOsInfo::hostOs(); m_executable.setDisplayFilter([osType](const QString &pathName) { @@ -638,7 +644,7 @@ FilePath ExecutableAspect::executable() const ? m_alternativeExecutable->filePath() : m_executable.filePath(); - if (const IDevice::ConstPtr dev = deviceForTarget(m_target)) + if (const IDevice::ConstPtr dev = executionDevice(m_target, m_selector)) exe = dev->filePath(exe.path()); return exe; diff --git a/src/plugins/projectexplorer/runconfigurationaspects.h b/src/plugins/projectexplorer/runconfigurationaspects.h index 768d89a0430..f9524a3c6a1 100644 --- a/src/plugins/projectexplorer/runconfigurationaspects.h +++ b/src/plugins/projectexplorer/runconfigurationaspects.h @@ -175,7 +175,9 @@ class PROJECTEXPLORER_EXPORT ExecutableAspect : public Utils::BaseAspect Q_OBJECT public: - explicit ExecutableAspect(Target *target); // Uses device from target if non-null. + enum ExecutionDeviceSelector { HostDevice, BuildDevice, RunDevice }; + + explicit ExecutableAspect(Target *target, ExecutionDeviceSelector selector); ~ExecutableAspect() override; Utils::FilePath executable() const; @@ -207,6 +209,7 @@ private: Utils::StringAspect m_executable; Utils::StringAspect *m_alternativeExecutable = nullptr; Target *m_target = nullptr; + ExecutionDeviceSelector m_selector = RunDevice; }; class PROJECTEXPLORER_EXPORT SymbolFileAspect : public Utils::StringAspect diff --git a/src/plugins/python/CMakeLists.txt b/src/plugins/python/CMakeLists.txt index bd71f4fbb23..a508e14ddc8 100644 --- a/src/plugins/python/CMakeLists.txt +++ b/src/plugins/python/CMakeLists.txt @@ -5,6 +5,7 @@ add_qtc_plugin(Python pipsupport.cpp pipsupport.h pyside.cpp pyside.h pysidebuildconfiguration.cpp pysidebuildconfiguration.h + pysideuicextracompiler.cpp pysideuicextracompiler.h python.qrc pythonconstants.h pythoneditor.cpp pythoneditor.h diff --git a/src/plugins/python/pysideuicextracompiler.cpp b/src/plugins/python/pysideuicextracompiler.cpp new file mode 100644 index 00000000000..b8a2f99ecd9 --- /dev/null +++ b/src/plugins/python/pysideuicextracompiler.cpp @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** 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 "pysideuicextracompiler.h" + +#include <utils/qtcprocess.h> + +using namespace ProjectExplorer; + +namespace Python { +namespace Internal { + +PySideUicExtraCompiler::PySideUicExtraCompiler(const Utils::FilePath &pySideUic, + const Project *project, + const Utils::FilePath &source, + const Utils::FilePaths &targets, + QObject *parent) + : ProcessExtraCompiler(project, source, targets, parent) + , m_pySideUic(pySideUic) +{ +} + +Utils::FilePath PySideUicExtraCompiler::pySideUicPath() const +{ + return m_pySideUic; +} + +Utils::FilePath PySideUicExtraCompiler::command() const +{ + return m_pySideUic; +} + +FileNameToContentsHash PySideUicExtraCompiler::handleProcessFinished( + Utils::QtcProcess *process) +{ + FileNameToContentsHash result; + if (process->exitStatus() != QProcess::NormalExit && process->exitCode() != 0) + return result; + + const Utils::FilePaths targetList = targets(); + if (targetList.size() != 1) + return result; + // As far as I can discover in the UIC sources, it writes out local 8-bit encoding. The + // conversion below is to normalize both the encoding, and the line terminators. + result[targetList.first()] = QString::fromLocal8Bit(process->readAllStandardOutput()).toUtf8(); + return result; +} + +} // namespace Internal +} // namespace Python diff --git a/src/plugins/python/pysideuicextracompiler.h b/src/plugins/python/pysideuicextracompiler.h new file mode 100644 index 00000000000..202f2a5d71b --- /dev/null +++ b/src/plugins/python/pysideuicextracompiler.h @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** 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 <projectexplorer/extracompiler.h> + +namespace Python { +namespace Internal { + +class PySideUicExtraCompiler : public ProjectExplorer::ProcessExtraCompiler +{ +public: + PySideUicExtraCompiler(const Utils::FilePath &pySideUic, + const ProjectExplorer::Project *project, + const Utils::FilePath &source, + const Utils::FilePaths &targets, + QObject *parent = nullptr); + + Utils::FilePath pySideUicPath() const; + +private: + Utils::FilePath command() const override; + ProjectExplorer::FileNameToContentsHash handleProcessFinished( + Utils::QtcProcess *process) override; + + Utils::FilePath m_pySideUic; +}; + +} // namespace Internal +} // namespace Python diff --git a/src/plugins/python/python.qbs b/src/plugins/python/python.qbs index a19e9939e37..0f6de6c58e2 100644 --- a/src/plugins/python/python.qbs +++ b/src/plugins/python/python.qbs @@ -23,6 +23,8 @@ QtcPlugin { "pyside.h", "pysidebuildconfiguration.cpp", "pysidebuildconfiguration.h", + "pysideuicextracompiler.cpp", + "pysideuicextracompiler.h", "python.qrc", "pythonconstants.h", "pythoneditor.cpp", diff --git a/src/plugins/python/pythonlanguageclient.cpp b/src/plugins/python/pythonlanguageclient.cpp index bb9b7695434..9479fc0c1a1 100644 --- a/src/plugins/python/pythonlanguageclient.cpp +++ b/src/plugins/python/pythonlanguageclient.cpp @@ -26,18 +26,24 @@ #include "pythonlanguageclient.h" #include "pipsupport.h" +#include "pysideuicextracompiler.h" #include "pythonconstants.h" #include "pythonplugin.h" #include "pythonproject.h" +#include "pythonrunconfiguration.h" #include "pythonsettings.h" #include "pythonutils.h" #include <coreplugin/editormanager/editormanager.h> #include <coreplugin/icore.h> #include <coreplugin/progressmanager/progressmanager.h> +#include <languageclient/languageclientinterface.h> #include <languageclient/languageclientmanager.h> +#include <languageserverprotocol/textsynchronization.h> #include <languageserverprotocol/workspace.h> +#include <projectexplorer/extracompiler.h> #include <projectexplorer/session.h> +#include <projectexplorer/target.h> #include <texteditor/textdocument.h> #include <texteditor/texteditor.h> #include <utils/infobar.h> @@ -57,6 +63,7 @@ #include <QTimer> using namespace LanguageClient; +using namespace LanguageServerProtocol; using namespace ProjectExplorer; using namespace Utils; @@ -67,8 +74,9 @@ static constexpr char startPylsInfoBarId[] = "Python::StartPyls"; static constexpr char installPylsInfoBarId[] = "Python::InstallPyls"; static constexpr char enablePylsInfoBarId[] = "Python::EnablePyls"; -struct PythonLanguageServerState +class PythonLanguageServerState { +public: enum { CanNotBeInstalled, CanBeInstalled, @@ -454,35 +462,119 @@ void PyLSSettings::setInterpreter(const QString &interpreterId) m_executable = interpreter.command; } -class PyLSClient : public Client +class PyLSInterface : public StdIOClientInterface { public: - using Client::Client; - void openDocument(TextEditor::TextDocument *document) override + PyLSInterface() + : m_extraPythonPath("QtCreator-pyls-XXXXXX") { - using namespace LanguageServerProtocol; - if (reachable()) { - const FilePath documentPath = document->filePath(); - if (isSupportedDocument(document) && !pythonProjectForFile(documentPath)) { - const FilePath workspacePath = documentPath.parentDir(); - if (!extraWorkspaceDirs.contains(workspacePath)) { - WorkspaceFoldersChangeEvent event; - event.setAdded({WorkSpaceFolder(DocumentUri::fromFilePath(workspacePath), - workspacePath.fileName())}); - DidChangeWorkspaceFoldersParams params; - params.setEvent(event); - DidChangeWorkspaceFoldersNotification change(params); - sendMessage(change); - extraWorkspaceDirs.append(workspacePath); - } + Environment env = Environment::systemEnvironment(); + env.appendOrSet("PYTHONPATH", + m_extraPythonPath.path().toString(), + OsSpecificAspects::pathListSeparator(env.osType())); + setEnvironment(env); + } + TemporaryDirectory m_extraPythonPath; +}; + +BaseClientInterface *PyLSSettings::createInterfaceWithProject( + ProjectExplorer::Project *project) const +{ + auto interface = new PyLSInterface; + interface->setCommandLine(command()); + if (project) + interface->setWorkingDirectory(project->projectDirectory()); + return interface; +} + +PyLSClient::PyLSClient(BaseClientInterface *interface) + : Client(interface) + , m_extraCompilerOutputDir(static_cast<PyLSInterface *>(interface)->m_extraPythonPath.path()) +{ +} + +void PyLSClient::openDocument(TextEditor::TextDocument *document) +{ + using namespace LanguageServerProtocol; + if (reachable()) { + const FilePath documentPath = document->filePath(); + if (PythonProject *project = pythonProjectForFile(documentPath)) { + if (Target *target = project->activeTarget()) { + if (auto rc = qobject_cast<PythonRunConfiguration *>(target->activeRunConfiguration())) + updateExtraCompilers(project, rc->extraCompilers()); + } + } else if (isSupportedDocument(document)) { + const FilePath workspacePath = documentPath.parentDir(); + if (!m_extraWorkspaceDirs.contains(workspacePath)) { + WorkspaceFoldersChangeEvent event; + event.setAdded({WorkSpaceFolder(DocumentUri::fromFilePath(workspacePath), + workspacePath.fileName())}); + DidChangeWorkspaceFoldersParams params; + params.setEvent(event); + DidChangeWorkspaceFoldersNotification change(params); + sendMessage(change); + m_extraWorkspaceDirs.append(workspacePath); } } - Client::openDocument(document); } + Client::openDocument(document); +} -private: - FilePaths extraWorkspaceDirs; -}; +void PyLSClient::projectClosed(ProjectExplorer::Project *project) +{ + for (ProjectExplorer::ExtraCompiler *compiler : m_extraCompilers.value(project)) + closeExtraCompiler(compiler); + Client::projectClosed(project); +} + +void PyLSClient::updateExtraCompilers(ProjectExplorer::Project *project, + const QList<PySideUicExtraCompiler *> &extraCompilers) +{ + auto oldCompilers = m_extraCompilers.take(project); + for (PySideUicExtraCompiler *extraCompiler : extraCompilers) { + QTC_ASSERT(extraCompiler->targets().size() == 1 , continue); + int index = oldCompilers.indexOf(extraCompiler); + if (index < 0) { + m_extraCompilers[project] << extraCompiler; + connect(extraCompiler, + &ExtraCompiler::contentsChanged, + this, + [this, extraCompiler](const FilePath &file) { + updateExtraCompilerContents(extraCompiler, file); + }); + if (extraCompiler->isDirty()) + static_cast<ExtraCompiler *>(extraCompiler)->run(); + } else { + m_extraCompilers[project] << oldCompilers.takeAt(index); + } + } + for (ProjectExplorer::ExtraCompiler *compiler : oldCompilers) + closeExtraCompiler(compiler); +} + +void PyLSClient::updateExtraCompilerContents(ExtraCompiler *compiler, const FilePath &file) +{ + const QString text = QString::fromUtf8(compiler->content(file)); + const FilePath target = m_extraCompilerOutputDir.pathAppended(file.fileName()); + + target.writeFileContents(compiler->content(file)); +} + +void PyLSClient::closeExtraCompiler(ProjectExplorer::ExtraCompiler *compiler) +{ + const FilePath file = compiler->targets().first(); + m_extraCompilerOutputDir.pathAppended(file.fileName()).removeFile(); + compiler->disconnect(this); +} + +PyLSClient *PyLSClient::clientForPython(const FilePath &python) +{ + if (auto setting = PyLSConfigureAssistant::languageServerForPython(python)) { + if (auto client = LanguageClientManager::clientsForSetting(setting).value(0)) + return qobject_cast<PyLSClient *>(client); + } + return nullptr; +} Client *PyLSSettings::createClient(BaseClientInterface *interface) const { diff --git a/src/plugins/python/pythonlanguageclient.h b/src/plugins/python/pythonlanguageclient.h index 4109fd4a8cd..42319377412 100644 --- a/src/plugins/python/pythonlanguageclient.h +++ b/src/plugins/python/pythonlanguageclient.h @@ -26,18 +26,46 @@ #pragma once #include <utils/fileutils.h> +#include <utils/temporarydirectory.h> #include <languageclient/client.h> #include <languageclient/languageclientsettings.h> namespace Core { class IDocument; } -namespace LanguageClient { class Client; } +namespace ProjectExplorer { class ExtraCompiler; } namespace TextEditor { class TextDocument; } namespace Python { namespace Internal { -struct PythonLanguageServerState; +class PySideUicExtraCompiler; +class PythonLanguageServerState; + +class PyLSClient : public LanguageClient::Client +{ + Q_OBJECT +public: + explicit PyLSClient(LanguageClient::BaseClientInterface *interface); + + void openDocument(TextEditor::TextDocument *document) override; + void projectClosed(ProjectExplorer::Project *project) override; + + void updateExtraCompilers(ProjectExplorer::Project *project, + const QList<PySideUicExtraCompiler *> &extraCompilers); + + static PyLSClient *clientForPython(const Utils::FilePath &python); + +private: + void updateExtraCompilerContents(ProjectExplorer::ExtraCompiler *compiler, + const Utils::FilePath &file); + void closeExtraDoc(const Utils::FilePath &file); + void closeExtraCompiler(ProjectExplorer::ExtraCompiler *compiler); + + Utils::FilePaths m_extraWorkspaceDirs; + Utils::FilePath m_extraCompilerOutputDir; + + QHash<ProjectExplorer::Project *, QList<ProjectExplorer::ExtraCompiler *>> m_extraCompilers; +}; class PyLSSettings : public LanguageClient::StdIOSettings { @@ -56,6 +84,9 @@ public: LanguageClient::Client *createClient(LanguageClient::BaseClientInterface *interface) const final; private: + LanguageClient::BaseClientInterface *createInterfaceWithProject( + ProjectExplorer::Project *project) const override; + static QJsonObject defaultConfiguration(); QString m_interpreterId; diff --git a/src/plugins/python/pythonproject.cpp b/src/plugins/python/pythonproject.cpp index 5b915c8bc27..0ce064a55f2 100644 --- a/src/plugins/python/pythonproject.cpp +++ b/src/plugins/python/pythonproject.cpp @@ -242,7 +242,6 @@ static FileType getFileType(const FilePath &f) void PythonBuildSystem::triggerParsing() { ParseGuard guard = guardParsingRun(); - parse(); const QDir baseDir(projectDirectory().toString()); diff --git a/src/plugins/python/pythonrunconfiguration.cpp b/src/plugins/python/pythonrunconfiguration.cpp index 4c184bbdc19..fe4623dd8de 100644 --- a/src/plugins/python/pythonrunconfiguration.cpp +++ b/src/plugins/python/pythonrunconfiguration.cpp @@ -27,6 +27,7 @@ #include "pyside.h" #include "pysidebuildconfiguration.h" +#include "pysideuicextracompiler.h" #include "pythonconstants.h" #include "pythonlanguageclient.h" #include "pythonproject.h" @@ -137,13 +138,6 @@ private: //////////////////////////////////////////////////////////////// -class PythonRunConfiguration : public RunConfiguration -{ -public: - PythonRunConfiguration(Target *target, Id id); - void currentInterpreterChanged(); -}; - PythonRunConfiguration::PythonRunConfiguration(Target *target, Id id) : RunConfiguration(target, id) { @@ -202,6 +196,13 @@ PythonRunConfiguration::PythonRunConfiguration(Target *target, Id id) }); connect(target, &Target::buildSystemUpdated, this, &RunConfiguration::update); + connect(target, &Target::buildSystemUpdated, this, &PythonRunConfiguration::updateExtraCompilers); + currentInterpreterChanged(); +} + +PythonRunConfiguration::~PythonRunConfiguration() +{ + qDeleteAll(m_extraCompilers); } void PythonRunConfiguration::currentInterpreterChanged() @@ -210,6 +211,7 @@ void PythonRunConfiguration::currentInterpreterChanged() BuildStepList *buildSteps = target()->activeBuildConfiguration()->buildSteps(); Utils::FilePath pySideProjectPath; + m_pySideUicPath.clear(); const PipPackage pySide6Package("PySide6"); const PipPackageInfo info = pySide6Package.info(python); @@ -217,10 +219,18 @@ void PythonRunConfiguration::currentInterpreterChanged() if (file.fileName() == HostOsInfo::withExecutableSuffix("pyside6-project")) { pySideProjectPath = info.location.resolvePath(file); pySideProjectPath = pySideProjectPath.cleanPath(); - break; + if (!m_pySideUicPath.isEmpty()) + break; + } else if (file.fileName() == HostOsInfo::withExecutableSuffix("pyside6-uic")) { + m_pySideUicPath = info.location.resolvePath(file); + m_pySideUicPath = m_pySideUicPath.cleanPath(); + if (!pySideProjectPath.isEmpty()) + break; } } + updateExtraCompilers(); + if (auto pySideBuildStep = buildSteps->firstOfType<PySideBuildStep>()) pySideBuildStep->updatePySideProjectPath(pySideProjectPath); @@ -234,6 +244,48 @@ void PythonRunConfiguration::currentInterpreterChanged() } } +QList<PySideUicExtraCompiler *> PythonRunConfiguration::extraCompilers() const +{ + return m_extraCompilers; +} + +void PythonRunConfiguration::updateExtraCompilers() +{ + QList<PySideUicExtraCompiler *> oldCompilers = m_extraCompilers; + m_extraCompilers.clear(); + + if (m_pySideUicPath.isExecutableFile()) { + auto uiMatcher = [](const ProjectExplorer::Node *node) { + if (const ProjectExplorer::FileNode *fileNode = node->asFileNode()) + return fileNode->fileType() == ProjectExplorer::FileType::Form; + return false; + }; + const FilePaths uiFiles = project()->files(uiMatcher); + for (const FilePath &uiFile : uiFiles) { + Utils::FilePath generated = uiFile.parentDir(); + generated = generated.pathAppended("/ui_" + uiFile.baseName() + ".py"); + int index = Utils::indexOf(oldCompilers, [&](PySideUicExtraCompiler *oldCompiler) { + return oldCompiler->pySideUicPath() == m_pySideUicPath + && oldCompiler->project() == project() && oldCompiler->source() == uiFile + && oldCompiler->targets() == Utils::FilePaths{generated}; + }); + if (index < 0) { + m_extraCompilers << new PySideUicExtraCompiler(m_pySideUicPath, + project(), + uiFile, + {generated}, + this); + } else { + m_extraCompilers << oldCompilers.takeAt(index); + } + } + } + const FilePath python = aspect<InterpreterAspect>()->currentInterpreter().command; + if (auto client = PyLSClient::clientForPython(python)) + client->updateExtraCompilers(project(), m_extraCompilers); + qDeleteAll(oldCompilers); +} + PythonRunConfigurationFactory::PythonRunConfigurationFactory() { registerRunConfiguration<PythonRunConfiguration>(Constants::C_PYTHONRUNCONFIGURATION_ID); diff --git a/src/plugins/python/pythonrunconfiguration.h b/src/plugins/python/pythonrunconfiguration.h index ebe28a79818..5394896b948 100644 --- a/src/plugins/python/pythonrunconfiguration.h +++ b/src/plugins/python/pythonrunconfiguration.h @@ -31,6 +31,24 @@ namespace Python { namespace Internal { +class PySideUicExtraCompiler; + +class PythonRunConfiguration : public ProjectExplorer::RunConfiguration +{ + Q_OBJECT +public: + PythonRunConfiguration(ProjectExplorer::Target *target, Utils::Id id); + ~PythonRunConfiguration() override; + void currentInterpreterChanged(); + QList<PySideUicExtraCompiler *> extraCompilers() const; + +private: + void updateExtraCompilers(); + Utils::FilePath m_pySideUicPath; + + QList<PySideUicExtraCompiler *> m_extraCompilers; +}; + class PythonRunConfigurationFactory : public ProjectExplorer::RunConfigurationFactory { public: diff --git a/src/plugins/qbsprojectmanager/qbsprofilemanager.cpp b/src/plugins/qbsprojectmanager/qbsprofilemanager.cpp index 0fbfa346816..7909de1981e 100644 --- a/src/plugins/qbsprojectmanager/qbsprofilemanager.cpp +++ b/src/plugins/qbsprojectmanager/qbsprofilemanager.cpp @@ -181,7 +181,7 @@ void QbsProfileManager::addProfileFromKit(const ProjectExplorer::Kit *k) data = provider->properties(k, data); } if (const QtSupport::QtVersion * const qt = QtSupport::QtKitAspect::qtVersion(k)) - data.insert("moduleProviders.Qt.qmakeFilePaths", qt->queryToolFilePath().toString()); + data.insert("moduleProviders.Qt.qmakeFilePaths", qt->qmakeFilePath().toString()); if (QbsSettings::qbsVersion() < QVersionNumber({1, 20})) { const QString keyPrefix = "profiles." + name + "."; diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp index d292f1fb5a5..c77f468ae23 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp @@ -745,9 +745,6 @@ Tasks QmakeProject::projectIssues(const Kit *k) const result.append(createProjectTask(Task::TaskType::Error, tr("Qt version is invalid."))); if (!ToolChainKitAspect::cxxToolChain(k)) result.append(createProjectTask(Task::TaskType::Error, tr("No C++ compiler set in kit."))); - if (!qtFromKit->qmakeFilePath().isExecutableFile()) - result.append(createProjectTask(Task::TaskType::Error, - tr("Qmake was not found or is not executable."))); // A project can be considered part of more than one Qt version, for instance if it is an // example shipped via the installer. diff --git a/src/plugins/qmakeprojectmanager/qmakestep.cpp b/src/plugins/qmakeprojectmanager/qmakestep.cpp index 2444303cb4d..2502297ef00 100644 --- a/src/plugins/qmakeprojectmanager/qmakestep.cpp +++ b/src/plugins/qmakeprojectmanager/qmakestep.cpp @@ -103,8 +103,7 @@ QMakeStep::QMakeStep(BuildStepList *bsl, Id id) auto updateSummary = [this] { QtVersion *qtVersion = QtKitAspect::qtVersion(target()->kit()); if (!qtVersion) - return tr("<b>Query tool:</b> No Qt version set. " - "Cannot run neither qmake nor qtpaths."); + return tr("<b>qmake:</b> No Qt version set. Cannot run qmake."); const QString program = qtVersion->qmakeFilePath().fileName(); return tr("<b>qmake:</b> %1 %2").arg(program, project()->projectFilePath().fileName()); }; @@ -165,7 +164,7 @@ QString QMakeStep::allArguments(const QtVersion *v, ArgumentFlags flags) const QString args = ProcessArgs::joinArgs(arguments); // User arguments ProcessArgs::addArgs(&args, userArguments()); - for (const QString &arg : qAsConst(m_extraArgs)) + for (QString arg : qAsConst(m_extraArgs)) ProcessArgs::addArgs(&args, arg); return (flags & ArgumentFlag::Expand) ? bc->macroExpander()->expand(args) : args; } @@ -215,8 +214,7 @@ bool QMakeStep::init() else workingDirectory = qmakeBc->buildDirectory(); - m_qmakeCommand = - CommandLine{qtVersion->qmakeFilePath(), allArguments(qtVersion), CommandLine::Raw}; + m_qmakeCommand = CommandLine{qtVersion->qmakeFilePath(), allArguments(qtVersion), CommandLine::Raw}; m_runMakeQmake = (qtVersion->qtVersion() >= QtVersionNumber(5, 0 ,0)); // The Makefile is used by qmake and make on the build device, from that diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index eb6db977357..654da4d43a4 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -165,6 +165,7 @@ extend_qtc_plugin(QmlDesigner edit3dcanvas.cpp edit3dcanvas.h edit3dactions.cpp edit3dactions.h edit3dvisibilitytogglesmenu.cpp edit3dvisibilitytogglesmenu.h + backgroundcolorselection.cpp backgroundcolorselection.h edit3d.qrc ) diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp index 221f9ec0f4c..7cf91158d65 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp @@ -81,30 +81,20 @@ bool AssetsLibraryWidget::eventFilter(QObject *obj, QEvent *event) if (obj == m_assetsWidget.data()) QMetaObject::invokeMethod(m_assetsWidget->rootObject(), "handleViewFocusOut"); } else if (event->type() == QMouseEvent::MouseMove) { - if (!m_assetsToDrag.isEmpty()) { + if (!m_assetsToDrag.isEmpty() && !m_model.isNull()) { QMouseEvent *me = static_cast<QMouseEvent *>(event); if ((me->globalPos() - m_dragStartPoint).manhattanLength() > 10) { - auto drag = new QDrag(this); - drag->setPixmap(m_assetsIconProvider->requestPixmap(m_assetsToDrag[0], nullptr, {128, 128})); QMimeData *mimeData = new QMimeData; mimeData->setData(Constants::MIME_TYPE_ASSETS, m_assetsToDrag.join(',').toUtf8()); - drag->setMimeData(mimeData); - drag->exec(); - drag->deleteLater(); - + m_model->startDrag(mimeData, + m_assetsIconProvider->requestPixmap(m_assetsToDrag[0], nullptr, {128, 128})); m_assetsToDrag.clear(); } } } else if (event->type() == QMouseEvent::MouseButtonRelease) { m_assetsToDrag.clear(); - QWidget *view = QmlDesignerPlugin::instance()->viewManager().widget("Navigator"); - if (view) { - NavigatorWidget *navView = qobject_cast<NavigatorWidget *>(view); - if (navView) { - navView->setDragType(""); - navView->update(); - } - } + if (m_model) + m_model->endDrag(); } return QObject::eventFilter(obj, event); diff --git a/src/plugins/qmldesigner/components/edit3d/backgroundcolorselection.cpp b/src/plugins/qmldesigner/components/edit3d/backgroundcolorselection.cpp new file mode 100644 index 00000000000..76db41a177e --- /dev/null +++ b/src/plugins/qmldesigner/components/edit3d/backgroundcolorselection.cpp @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** 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 "backgroundcolorselection.h" + +#include <nodeinstanceview.h> +#include <utils/qtcassert.h> +#include <view3dactioncommand.h> +#include <qmldesignerplugin.h> + +using namespace QmlDesigner; + +namespace { +QList<QColor> readBackgroundColorConfiguration() +{ + QVariant var = QmlDesigner::DesignerSettings::getValue( + QmlDesigner::DesignerSettingsKey::EDIT3DVIEW_BACKGROUND_COLOR); + + if (!var.isValid()) + return {}; + + auto colorNameList = var.value<QList<QString>>(); + QTC_ASSERT(colorNameList.size() == 2, return {}); + + return {colorNameList[0], colorNameList[1]}; +} + +void setBackgroundColorConfiguration(const QList<QColor> &colorConfig) +{ + auto view = QmlDesignerPlugin::instance()->viewManager().nodeInstanceView(); + View3DActionCommand cmd(View3DActionCommand::SelectBackgroundColor, + QVariant::fromValue(colorConfig)); + view->view3DAction(cmd); +} + +void saveBackgroundColorConfiguration(const QList<QColor> &colorConfig) +{ + QList<QString> colorsSaved = {colorConfig[0].name(), colorConfig[1].name()}; + QmlDesigner::DesignerSettings::setValue( + QmlDesigner::DesignerSettingsKey::EDIT3DVIEW_BACKGROUND_COLOR, + QVariant::fromValue(colorsSaved)); +} + +} // namespace + +QColorDialog *BackgroundColorSelection::createDialog(QWidget *parent) +{ + auto dialog = new QColorDialog(parent); + + dialog->setModal(true); + dialog->setAttribute(Qt::WA_DeleteOnClose); + + const QList<QColor> oldColorConfig = readBackgroundColorConfiguration(); + + dialog->show(); + + QObject::connect(dialog, &QColorDialog::currentColorChanged, dialog, [](const QColor &color) { + setBackgroundColorConfiguration({color, color}); + }); + + QObject::connect(dialog, &QColorDialog::colorSelected, dialog, [](const QColor &color) { + saveBackgroundColorConfiguration({color, color}); + }); + + if (!oldColorConfig.isEmpty()) { + QObject::connect(dialog, &QColorDialog::rejected, dialog, [oldColorConfig]() { + setBackgroundColorConfiguration(oldColorConfig); + }); + } + + return dialog; +} + +void BackgroundColorSelection::showBackgroundColorSelectionWidget(QWidget *parent) +{ + if (m_dialog) + return; + + m_dialog = BackgroundColorSelection::createDialog(parent); + QTC_ASSERT(m_dialog, return); + + QObject::connect(m_dialog, &QWidget::destroyed, m_dialog, [&]() { + m_dialog = nullptr; + }); +} diff --git a/src/plugins/cppeditor/usages.h b/src/plugins/qmldesigner/components/edit3d/backgroundcolorselection.h index 684b571efce..d8832f40fda 100644 --- a/src/plugins/cppeditor/usages.h +++ b/src/plugins/qmldesigner/components/edit3d/backgroundcolorselection.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2022 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. @@ -25,45 +25,23 @@ #pragma once -#include <utils/smallstringview.h> +#include <QColorDialog> -#include <QString> - -#include <vector> -#include <functional> - -namespace CppEditor { - -class Usage +namespace QmlDesigner { +class BackgroundColorSelection : public QObject { + Q_OBJECT + public: - Usage() = default; - Usage(Utils::SmallStringView path, int line, int column) - : path(QString::fromUtf8(path.data(), int(path.size()))), - line(line), - column(column) + explicit BackgroundColorSelection(QObject *parent = nullptr) + : QObject{parent} {} - friend bool operator==(const Usage &first, const Usage &second) - { - return first.line == second.line - && first.column == second.column - && first.path == second.path; - } + static void showBackgroundColorSelectionWidget(QWidget *parent); - friend bool operator<(const Usage &first, const Usage &second) - { - return std::tie(first.path, first.line, first.column) - < std::tie(second.path, second.line, second.column); - } - -public: - QString path; - int line = 0; - int column = 0; +private: + static QColorDialog *createDialog(QWidget *parent); + inline static QColorDialog *m_dialog = nullptr; }; -using Usages = std::vector<Usage>; -using UsagesCallback = std::function<void(const Usages &usages)>; - -} // namespace CppEditor +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/edit3d/edit3d.qrc b/src/plugins/qmldesigner/components/edit3d/edit3d.qrc index bf042b645b2..5784ac0e446 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3d.qrc +++ b/src/plugins/qmldesigner/components/edit3d/edit3d.qrc @@ -44,5 +44,7 @@ <file>images/[email protected]</file> <file>images/align_view_on.png</file> <file>images/[email protected]</file> + <file>images/color_palette.png</file> + <file>images/[email protected]</file> </qresource> </RCC> diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dactions.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dactions.cpp index c5240a0cbd6..76343584c9c 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dactions.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dactions.cpp @@ -48,9 +48,10 @@ Edit3DActionTemplate::Edit3DActionTemplate(const QString &description, void Edit3DActionTemplate::actionTriggered(bool b) { - if (m_type != View3DActionCommand::Empty) { - QmlDesignerPlugin::instance()->viewManager().nodeInstanceView() - ->view3DAction(View3DActionCommand(m_type, b)); + if (m_type != View3DActionCommand::Empty && m_type != View3DActionCommand::SelectBackgroundColor) { + auto view = QmlDesignerPlugin::instance()->viewManager().nodeInstanceView(); + View3DActionCommand cmd(m_type, b); + view->view3DAction(cmd); } if (m_action) diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp index 5fccdbea9c5..eca26840aa4 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp @@ -42,6 +42,8 @@ #include <utils/qtcassert.h> #include <utils/utilsicons.h> +#include <backgroundcolorselection.h> + #include <QDebug> #include <QToolButton> @@ -336,6 +338,32 @@ void Edit3DView::createEdit3DActions() QKeySequence(Qt::Key_G), true, true, {}, {}, nullptr, QCoreApplication::translate("ShowGridAction", "Toggle the visibility of the helper grid.")); + SelectionContextOperation showBackgroundColorSelection = [this](const SelectionContext &) { + BackgroundColorSelection::showBackgroundColorSelectionWidget(edit3DWidget()); + }; + + m_backgroundColorSelectionAction = new Edit3DAction( + QmlDesigner::Constants::EDIT3D_EDIT_SELECT_BACKGROUND_COLOR, View3DActionCommand::SelectBackgroundColor, + QCoreApplication::translate("SelectBackgroundColorAction", "Select Background color"), + {}, false, false, {}, {}, showBackgroundColorSelection, + QCoreApplication::translate("SelectBackgroundColorAction", "Choose a color for the background.")); + + m_resetBackgroundColorAction = new Edit3DAction( + QmlDesigner::Constants::EDIT3D_EDIT_RESET_BACKGROUND_COLOR, View3DActionCommand::ResetBackgroundColor, + QCoreApplication::translate("ResetBackgroundColorAction", "Reset Background color"), + {}, false, false, {}, {}, [](const SelectionContext &) { + QList<QColor> colors = {QRgb(0x222222), QRgb(0x999999)}; + auto view = QmlDesignerPlugin::instance()->viewManager().nodeInstanceView(); + View3DActionCommand cmd(View3DActionCommand::SelectBackgroundColor, QVariant::fromValue(colors)); + view->view3DAction(cmd); + + QList<QString> colorsToSave = {colors[0].name(), colors[1].name()}; + QmlDesigner::DesignerSettings::setValue( + QmlDesigner::DesignerSettingsKey::EDIT3DVIEW_BACKGROUND_COLOR, + QVariant::fromValue(colorsToSave)); + }, + QCoreApplication::translate("ResetBackgroundColorAction", "Reset Background color to the default value.")); + m_showSelectionBoxAction = new Edit3DAction( QmlDesigner::Constants::EDIT3D_EDIT_SHOW_SELECTION_BOX, View3DActionCommand::ShowSelectionBox, QCoreApplication::translate("ShowSelectionBoxAction", "Show Selection Boxes"), @@ -438,6 +466,29 @@ void Edit3DView::createEdit3DActions() QKeySequence(), false, false, Utils::Icons::EYE_OPEN_TOOLBAR.icon(), {}, visibilityTogglesTrigger); + SelectionContextOperation backgroundColorActionsTrigger = [this](const SelectionContext &) { + if (!edit3DWidget()->backgroundColorMenu()) + return; + + QPoint pos; + const auto &actionWidgets = m_backgrondColorMenuAction->action()->associatedWidgets(); + for (auto actionWidget : actionWidgets) { + if (auto button = qobject_cast<QToolButton *>(actionWidget)) { + pos = button->mapToGlobal(QPoint(0, 0)); + break; + } + } + + edit3DWidget()->showBackgroundColorMenu(!edit3DWidget()->backgroundColorMenu()->isVisible(), + pos); + }; + + m_backgrondColorMenuAction = new Edit3DAction( + QmlDesigner::Constants::EDIT3D_BACKGROUND_COLOR_ACTIONS, View3DActionCommand::Empty, + QCoreApplication::translate("BackgroundColorMenuActions", "Background Color Actions"), + QKeySequence(), false, false, Icons::COLOR_PALETTE.icon(), + {}, backgroundColorActionsTrigger); + m_leftActions << m_selectionModeAction; m_leftActions << nullptr; // Null indicates separator m_leftActions << nullptr; // Second null after separator indicates an exclusive group @@ -455,6 +506,8 @@ void Edit3DView::createEdit3DActions() m_leftActions << m_alignViewAction; m_leftActions << nullptr; m_leftActions << m_visibilityTogglesAction; + m_leftActions << nullptr; + m_leftActions << m_backgrondColorMenuAction; m_rightActions << m_particleViewModeAction; m_rightActions << m_particlesPlayAction; @@ -467,6 +520,9 @@ void Edit3DView::createEdit3DActions() m_visibilityToggleActions << m_showIconGizmoAction; m_visibilityToggleActions << m_showCameraFrustumAction; m_visibilityToggleActions << m_showParticleEmitterAction; + + m_backgroundColorActions << m_backgroundColorSelectionAction; + m_backgroundColorActions << m_resetBackgroundColorAction; } QVector<Edit3DAction *> Edit3DView::leftActions() const @@ -484,6 +540,11 @@ QVector<Edit3DAction *> Edit3DView::visibilityToggleActions() const return m_visibilityToggleActions; } +QVector<Edit3DAction *> Edit3DView::backgroundColorActions() const +{ + return m_backgroundColorActions; +} + 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 40e21708734..e5cb2aba51b 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dview.h +++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.h @@ -74,6 +74,7 @@ public: QVector<Edit3DAction *> leftActions() const; QVector<Edit3DAction *> rightActions() const; QVector<Edit3DAction *> visibilityToggleActions() const; + QVector<Edit3DAction *> backgroundColorActions() const; void setSeeker(SeekerSlider *slider); void addQuick3DImport(); @@ -88,6 +89,7 @@ private: QVector<Edit3DAction *> m_leftActions; QVector<Edit3DAction *> m_rightActions; QVector<Edit3DAction *> m_visibilityToggleActions; + QVector<Edit3DAction *> m_backgroundColorActions; Edit3DAction *m_selectionModeAction = nullptr; Edit3DAction *m_moveToolAction = nullptr; Edit3DAction *m_rotateToolAction = nullptr; @@ -99,6 +101,8 @@ private: Edit3DAction *m_orientationModeAction = nullptr; Edit3DAction *m_editLightAction = nullptr; Edit3DAction *m_showGridAction = nullptr; + Edit3DAction *m_backgroundColorSelectionAction = nullptr; + Edit3DAction *m_resetBackgroundColorAction = nullptr; Edit3DAction *m_showSelectionBoxAction = nullptr; Edit3DAction *m_showIconGizmoAction = nullptr; Edit3DAction *m_showCameraFrustumAction = nullptr; @@ -108,6 +112,7 @@ private: Edit3DAction *m_particlesPlayAction = nullptr; Edit3DAction *m_particlesRestartAction = nullptr; Edit3DAction *m_visibilityTogglesAction = nullptr; + Edit3DAction *m_backgrondColorMenuAction = nullptr; SeekerSlider *m_seeker = nullptr; int particlemode; ModelCache<QImage> m_canvasCache; diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp index 72cb0ec21c8..6f685123cfd 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp @@ -141,6 +141,9 @@ Edit3DWidget::Edit3DWidget(Edit3DView *view) : m_visibilityTogglesMenu = new Edit3DVisibilityTogglesMenu(this); handleActions(view->visibilityToggleActions(), m_visibilityTogglesMenu, false); + m_backgroundColorMenu = new Edit3DVisibilityTogglesMenu(this); + handleActions(view->backgroundColorActions(), m_backgroundColorMenu, false); + view->setSeeker(seeker); seeker->setToolTip(QLatin1String("Seek particle system time when paused.")); @@ -201,6 +204,21 @@ void Edit3DWidget::showVisibilityTogglesMenu(bool show, const QPoint &pos) m_visibilityTogglesMenu->close(); } +QMenu *Edit3DWidget::backgroundColorMenu() const +{ + return m_backgroundColorMenu.data(); +} + +void Edit3DWidget::showBackgroundColorMenu(bool show, const QPoint &pos) +{ + if (m_backgroundColorMenu.isNull()) + return; + if (show) + m_backgroundColorMenu->popup(pos); + else + m_backgroundColorMenu->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 5a4ed48e28e..7d40fd54715 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h +++ b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h @@ -51,6 +51,9 @@ public: QMenu *visibilityTogglesMenu() const; void showVisibilityTogglesMenu(bool show, const QPoint &pos); + QMenu *backgroundColorMenu() const; + void showBackgroundColorMenu(bool show, const QPoint &pos); + protected: void dragEnterEvent(QDragEnterEvent *dragEnterEvent) override; void dropEvent(QDropEvent *dropEvent) override; @@ -65,6 +68,7 @@ private: QPointer<ToolBox> m_toolBox; Core::IContext *m_context = nullptr; QPointer<QMenu> m_visibilityTogglesMenu; + QPointer<QMenu> m_backgroundColorMenu; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/edit3d/images/color_palette.png b/src/plugins/qmldesigner/components/edit3d/images/color_palette.png Binary files differnew file mode 100644 index 00000000000..8d5035b3658 --- /dev/null +++ b/src/plugins/qmldesigner/components/edit3d/images/color_palette.png diff --git a/src/plugins/qmldesigner/components/edit3d/images/[email protected] b/src/plugins/qmldesigner/components/edit3d/images/[email protected] Binary files differnew file mode 100644 index 00000000000..4eebbce313c --- /dev/null +++ b/src/plugins/qmldesigner/components/edit3d/images/[email protected] diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp index 7e22efe016f..e3aae0cb7d5 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp @@ -401,7 +401,6 @@ void ItemLibraryAssetImporter::postParseQuick3DAsset(const ParseData &pd) qmlInfo.append(outDir.relativeFilePath(qmlIt.filePath())); qmlInfo.append('\n'); - // Generate item library icon for qml file based on root component QFile qmlFile(qmlIt.filePath()); if (qmlFile.open(QIODevice::ReadOnly)) { QString iconFileName = outDir.path() + '/' @@ -410,6 +409,8 @@ void ItemLibraryAssetImporter::postParseQuick3DAsset(const ParseData &pd) QString iconFileName2x = iconFileName + "@2x"; QByteArray content = qmlFile.readAll(); int braceIdx = content.indexOf('{'); + QString impVersionStr; + int impVersionMajor = -1; if (braceIdx != -1) { int nlIdx = content.lastIndexOf('\n', braceIdx); QByteArray rootItem = content.mid(nlIdx, braceIdx - nlIdx).trimmed(); @@ -423,8 +424,9 @@ void ItemLibraryAssetImporter::postParseQuick3DAsset(const ParseData &pd) out << "canBeDroppedInView3D: true" << Qt::endl; file.close(); - // Add quick3D import unless it is already added - if (m_requiredImports.first().url() != "QtQuick3D") { + // Assume that all assets import the same QtQuick3D version, + // since they are being imported with same kit + if (impVersionMajor == -1) { QByteArray import3dStr{"import QtQuick3D"}; int importIdx = content.indexOf(import3dStr); if (importIdx != -1 && importIdx < braceIdx) { @@ -433,15 +435,25 @@ void ItemLibraryAssetImporter::postParseQuick3DAsset(const ParseData &pd) QByteArray versionStr = content.mid(importIdx, nlIdx - importIdx).trimmed(); // There could be 'as abc' after version, so just take first part QList<QByteArray> parts = versionStr.split(' '); - QString impVersion; - if (parts.size() >= 1) - impVersion = QString::fromUtf8(parts[0]); - m_requiredImports.prepend(Import::createLibraryImport( - "QtQuick3D", impVersion)); + if (parts.size() >= 1) { + impVersionStr = QString::fromUtf8(parts[0]); + if (impVersionStr.isEmpty()) + impVersionMajor = 6; + else + impVersionMajor = impVersionStr.left(1).toInt(); + } } } + + // Add quick3D import unless it is already added + if (impVersionMajor > 0 + && m_requiredImports.first().url() != "QtQuick3D") { + m_requiredImports.prepend(Import::createLibraryImport( + "QtQuick3D", impVersionStr)); + } } - if (startIconProcess(24, iconFileName, qmlIt.filePath())) { + if (impVersionMajor > 0 && impVersionMajor < 6 + && startIconProcess(24, iconFileName, qmlIt.filePath())) { // Since icon is generated by external process, the file won't be // ready for asset gathering below, so assume its generation succeeds // and add it now. diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryiconimageprovider.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryiconimageprovider.cpp index e7dbbee0857..5144a5220fb 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryiconimageprovider.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryiconimageprovider.cpp @@ -92,7 +92,9 @@ QQuickImageResponse *ItemLibraryIconImageProvider::requestImageResponse(const QS } }, Qt::QueuedConnection); - }); + }, + "libIcon", + ImageCache::LibraryIconAuxiliaryData{true}); return response.release(); } diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp index 8af21584e3b..e94c5108b13 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp @@ -30,12 +30,6 @@ #include <asynchronousimagecache.h> #include <bindingproperty.h> #include <coreplugin/icore.h> -#include <imagecache/imagecachecollector.h> -#include <imagecache/imagecacheconnectionmanager.h> -#include <imagecache/imagecachefontcollector.h> -#include <imagecache/imagecachegenerator.h> -#include <imagecache/imagecachestorage.h> -#include <imagecache/timestampprovider.h> #include <import.h> #include <nodelistproperty.h> #include <projectexplorer/kit.h> @@ -44,7 +38,6 @@ #include <projectexplorer/target.h> #include <rewriterview.h> #include <sqlitedatabase.h> -#include <synchronousimagecache.h> #include <utils/algorithm.h> #include <qmldesignerplugin.h> #include <qmlitemnode.h> @@ -52,38 +45,9 @@ namespace QmlDesigner { -namespace { -ProjectExplorer::Target *activeTarget(ProjectExplorer::Project *project) -{ - if (project) - return project->activeTarget(); - - return {}; -} -} // namespace - -class ItemLibraryView::ImageCacheData -{ -public: - Sqlite::Database database{Utils::PathString{ - Core::ICore::cacheResourcePath("imagecache-v2.db").toString()}, - Sqlite::JournalMode::Wal, - Sqlite::LockingMode::Normal}; - ImageCacheStorage<Sqlite::Database> storage{database}; - ImageCacheConnectionManager connectionManager; - ImageCacheCollector collector{connectionManager, QSize{300, 300}, QSize{600, 600}}; - ImageCacheFontCollector fontCollector; - ImageCacheGenerator generator{collector, storage}; - ImageCacheGenerator fontGenerator{fontCollector, storage}; - TimeStampProvider timeStampProvider; - AsynchronousImageCache cache{storage, generator, timeStampProvider}; - AsynchronousImageCache asynchronousFontImageCache{storage, fontGenerator, timeStampProvider}; - SynchronousImageCache synchronousFontImageCache{storage, timeStampProvider, fontCollector}; -}; - -ItemLibraryView::ItemLibraryView(QObject* parent) - : AbstractView(parent) - +ItemLibraryView::ItemLibraryView(AsynchronousImageCache &imageCache) + : AbstractView() + , m_imageCache(imageCache) {} ItemLibraryView::~ItemLibraryView() @@ -97,11 +61,8 @@ bool ItemLibraryView::hasWidget() const WidgetInfo ItemLibraryView::widgetInfo() { - if (m_widget.isNull()) { - m_widget = new ItemLibraryWidget{imageCacheData()->cache, - imageCacheData()->asynchronousFontImageCache, - imageCacheData()->synchronousFontImageCache}; - } + if (m_widget.isNull()) + m_widget = new ItemLibraryWidget{m_imageCache}; return createWidgetInfo(m_widget.data(), "Components", WidgetInfo::LeftPane, 0, tr("Components")); } @@ -177,43 +138,6 @@ void ItemLibraryView::usedImportsChanged(const QList<Import> &usedImports) m_widget->updateUsedImports(usedImports); } -ItemLibraryView::ImageCacheData *ItemLibraryView::imageCacheData() -{ - std::call_once(imageCacheFlag, [this]() { - m_imageCacheData = std::make_unique<ImageCacheData>(); - auto setTargetInImageCache = - [imageCacheData = m_imageCacheData.get()](ProjectExplorer::Target *target) { - if (target == imageCacheData->collector.target()) - return; - - if (target) - imageCacheData->cache.clean(); - - imageCacheData->collector.setTarget(target); - }; - - if (auto project = ProjectExplorer::SessionManager::startupProject(); project) { - m_imageCacheData->collector.setTarget(project->activeTarget()); - connect(project, - &ProjectExplorer::Project::activeTargetChanged, - this, - setTargetInImageCache); - } - connect(ProjectExplorer::SessionManager::instance(), - &ProjectExplorer::SessionManager::startupProjectChanged, - this, - [=](ProjectExplorer::Project *project) { - setTargetInImageCache(activeTarget(project)); - }); - }); - return m_imageCacheData.get(); -} - -AsynchronousImageCache &ItemLibraryView::imageCache() -{ - return imageCacheData()->cache; -} - void ItemLibraryView::documentMessagesChanged(const QList<DocumentMessage> &errors, const QList<DocumentMessage> &) { if (m_hasErrors && errors.isEmpty()) diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.h index b7b91eaf3f8..4a0925064fb 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.h @@ -29,19 +29,16 @@ #include <QPointer> -#include <mutex> - namespace QmlDesigner { class ItemLibraryWidget; -class AsynchronousImageCache; class ItemLibraryView : public AbstractView { Q_OBJECT public: - ItemLibraryView(QObject* parent = nullptr); + ItemLibraryView(class AsynchronousImageCache &imageCache); ~ItemLibraryView() override; bool hasWidget() const override; @@ -58,17 +55,11 @@ public: void customNotification(const AbstractView *view, const QString &identifier, const QList<ModelNode> &nodeList, const QList<QVariant> &data) override; - AsynchronousImageCache &imageCache(); - protected: void updateImports(); private: - class ImageCacheData; - ImageCacheData *imageCacheData(); - - std::once_flag imageCacheFlag; - std::unique_ptr<ImageCacheData> m_imageCacheData; + AsynchronousImageCache &m_imageCache; QPointer<ItemLibraryWidget> m_widget; bool m_hasErrors = false; QVariantMap m_importableExtensions3DMap; diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp index 511ef37f196..75a564d7384 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp @@ -140,18 +140,13 @@ void ItemLibraryWidget::resizeEvent(QResizeEvent *event) isHorizontalLayout = event->size().width() >= HORIZONTAL_LAYOUT_WIDTH_LIMIT; } -ItemLibraryWidget::ItemLibraryWidget(AsynchronousImageCache &imageCache, - AsynchronousImageCache &asynchronousFontImageCache, - SynchronousImageCache &synchronousFontImageCache) +ItemLibraryWidget::ItemLibraryWidget(AsynchronousImageCache &imageCache) : m_itemIconSize(24, 24) - , m_fontImageCache(synchronousFontImageCache) , m_itemLibraryModel(new ItemLibraryModel(this)) , m_addModuleModel(new ItemLibraryAddImportModel(this)) , m_itemsWidget(new QQuickWidget(this)) , m_imageCache{imageCache} { - Q_UNUSED(asynchronousFontImageCache) - m_compressionTimer.setInterval(200); m_compressionTimer.setSingleShot(true); ItemLibraryModel::registerQmlTypes(); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h index a7f23180730..be905f181ae 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h @@ -56,7 +56,6 @@ class Model; class ItemLibraryModel; class ItemLibraryAddImportModel; class ItemLibraryResourceView; -class SynchronousImageCache; class AsynchronousImageCache; class ImageCacheCollector; @@ -67,9 +66,7 @@ class ItemLibraryWidget : public QFrame public: Q_PROPERTY(bool subCompEditMode READ subCompEditMode NOTIFY subCompEditModeChanged) - ItemLibraryWidget(AsynchronousImageCache &imageCache, - AsynchronousImageCache &asynchronousFontImageCache, - SynchronousImageCache &synchronousFontImageCache); + ItemLibraryWidget(AsynchronousImageCache &imageCache); ~ItemLibraryWidget(); void setItemLibraryInfo(ItemLibraryInfo *itemLibraryInfo); @@ -115,7 +112,6 @@ private: QTimer m_compressionTimer; QSize m_itemIconSize; - SynchronousImageCache &m_fontImageCache; QPointer<ItemLibraryInfo> m_itemLibraryInfo; QPointer<ItemLibraryModel> m_itemLibraryModel; diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp index 8257ae6857b..e2736068053 100644 --- a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp +++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp @@ -29,6 +29,7 @@ #include "materialeditorcontextobject.h" #include "propertyeditorvalue.h" #include "materialeditortransaction.h" +#include "assetslibrarywidget.h" #include <qmldesignerconstants.h> #include <qmltimeline.h> @@ -809,6 +810,39 @@ void MaterialEditorView::customNotification(const AbstractView *view, const QStr } } +void QmlDesigner::MaterialEditorView::highlightSupportedProperties(bool highlight) +{ + DesignerPropertyMap &propMap = m_qmlBackEnd->backendValuesPropertyMap(); + const QStringList propNames = propMap.keys(); + + for (const QString &propName : propNames) { + if (propName.endsWith("Map")) { + QObject *propEditorValObj = propMap.value(propName).value<QObject *>(); + PropertyEditorValue *propEditorVal = qobject_cast<PropertyEditorValue *>(propEditorValObj); + propEditorVal->setHasActiveDrag(highlight); + } + } +} + +void MaterialEditorView::dragStarted(QMimeData *mimeData) +{ + if (!mimeData->hasFormat(Constants::MIME_TYPE_ASSETS)) + return; + + const QString assetPath = QString::fromUtf8(mimeData->data(Constants::MIME_TYPE_ASSETS)).split(',')[0]; + QString assetType = AssetsLibraryWidget::getAssetTypeAndData(assetPath).first; + + if (assetType != Constants::MIME_TYPE_ASSET_IMAGE) // currently only image assets have dnd-supported properties + return; + + highlightSupportedProperties(); +} + +void MaterialEditorView::dragEnded() +{ + highlightSupportedProperties(false); +} + // from model to material editor void MaterialEditorView::setValue(const QmlObjectNode &qmlObjectNode, const PropertyName &name, const QVariant &value) { diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h index 8ab30a63f44..3e8632d26f6 100644 --- a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h +++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h @@ -73,6 +73,9 @@ public: void customNotification(const AbstractView *view, const QString &identifier, const QList<ModelNode> &nodeList, const QList<QVariant> &data) override; + void dragStarted(QMimeData *mimeData) override; + void dragEnded() override; + void changeValue(const QString &name); void changeExpression(const QString &name); void exportPropertyAsAlias(const QString &name); @@ -93,6 +96,7 @@ private: static QString materialEditorResourcesPath(); void reloadQml(); + void highlightSupportedProperties(bool highlight = true); QString generateIdFromName(const QString &name); void ensureMaterialLibraryNode(); diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp index ff131f28660..6ea079b6f16 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp @@ -274,6 +274,19 @@ bool PropertyEditorValue::isTranslated() const return false; } +bool PropertyEditorValue::hasActiveDrag() const +{ + return m_hasActiveDrag; +} + +void PropertyEditorValue::setHasActiveDrag(bool val) +{ + if (m_hasActiveDrag != val) { + m_hasActiveDrag = val; + emit hasActiveDragChanged(); + } +} + static bool isAllowedSubclassType(const QString &type, const QmlDesigner::NodeMetaInfo &metaInfo) { if (!metaInfo.isValid()) @@ -371,18 +384,6 @@ void PropertyEditorValue::setEnumeration(const QString &scope, const QString &na setValueWithEmit(QVariant::fromValue(newEnumeration)); } -bool PropertyEditorValue::isSupportedDrop(const QString &path) -{ - QString suffix = "*." + QFileInfo(path).suffix().toLower(); - - if (m_modelNode.isSubclassOf("QtQuick3D.Material") && nameAsQString().endsWith("Map")) - return QmlDesigner::AssetsLibraryModel::supportedImageSuffixes().contains(suffix); - - // TODO: handle support for other object properties dnd here (like image source) - - return false; -} - void PropertyEditorValue::exportPropertyAsAlias() { emit exportPropertyAsAliasRequested(nameAsQString()); diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.h b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.h index 2a2b09d5c8c..4ae156dc921 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.h +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.h @@ -82,6 +82,7 @@ class PropertyEditorValue : public QObject Q_PROPERTY(bool isBound READ isBound NOTIFY isBoundChanged FINAL) Q_PROPERTY(bool isValid READ isValid NOTIFY isValidChanged FINAL) Q_PROPERTY(bool isTranslated READ isTranslated NOTIFY expressionChanged FINAL) + Q_PROPERTY(bool hasActiveDrag READ hasActiveDrag WRITE setHasActiveDrag NOTIFY hasActiveDragChanged FINAL) Q_PROPERTY(bool isIdList READ isIdList NOTIFY expressionChanged FINAL) Q_PROPERTY(QStringList expressionAsList READ getExpressionAsList NOTIFY expressionChanged FINAL) @@ -117,6 +118,9 @@ public: bool isTranslated() const; + bool hasActiveDrag() const; + void setHasActiveDrag(bool val); + bool isAvailable() const; QmlDesigner::PropertyName name() const; @@ -148,7 +152,6 @@ public: public slots: void resetValue(); void setEnumeration(const QString &scope, const QString &name); - bool isSupportedDrop(const QString &path); signals: void valueChanged(const QString &name, const QVariant&); @@ -164,6 +167,7 @@ signals: void isBoundChanged(); void isValidChanged(); void isExplicitChanged(); + void hasActiveDragChanged(); private: QStringList generateStringList(const QString &string) const; @@ -176,6 +180,7 @@ private: bool m_isInSubState; bool m_isInModel; bool m_isBound; + bool m_hasActiveDrag = false; bool m_isValid; // if the property value belongs to a non-existing complexProperty it is invalid PropertyEditorNodeWrapper *m_complexNode; }; diff --git a/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp b/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp index 530724315a0..7890086bd5f 100644 --- a/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp +++ b/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp @@ -74,7 +74,7 @@ ImageCacheCollector::~ImageCacheCollector() = default; void ImageCacheCollector::start(Utils::SmallStringView name, Utils::SmallStringView state, - const ImageCache::AuxiliaryData &, + const ImageCache::AuxiliaryData &auxiliaryData, CaptureCallback captureCallback, AbortCallback abortCallback) { @@ -96,13 +96,22 @@ void ImageCacheCollector::start(Utils::SmallStringView name, model->setRewriterView(&rewriterView); + bool is3DRoot = !rewriterView.inErrorState() + && (rewriterView.rootModelNode().isSubclassOf("Quick3D.Node") + || rewriterView.rootModelNode().isSubclassOf("Quick3D.Material")); + if (rewriterView.inErrorState() || (!rewriterView.rootModelNode().metaInfo().isGraphicalItem() - && !rewriterView.rootModelNode().isSubclassOf("Quick3D.Node") )) { + && !is3DRoot)) { if (abortCallback) abortCallback(ImageCache::AbortReason::Failed); return; } + if (is3DRoot) { + if (auto libIcon = Utils::get_if<ImageCache::LibraryIconAuxiliaryData>(&auxiliaryData)) + rewriterView.rootModelNode().setAuxiliaryData("isLibraryIcon@NodeInstance", libIcon->enable); + } + ModelNode stateNode = rewriterView.modelNodeForId(QString{state}); if (stateNode.isValid()) diff --git a/src/plugins/qmldesigner/designercore/include/imagecacheauxiliarydata.h b/src/plugins/qmldesigner/designercore/include/imagecacheauxiliarydata.h index ae87681626a..61660271fc9 100644 --- a/src/plugins/qmldesigner/designercore/include/imagecacheauxiliarydata.h +++ b/src/plugins/qmldesigner/designercore/include/imagecacheauxiliarydata.h @@ -54,7 +54,16 @@ public: QString text; }; -using AuxiliaryData = Utils::variant<Utils::monostate, FontCollectorSizeAuxiliaryData, FontCollectorSizesAuxiliaryData>; +class LibraryIconAuxiliaryData +{ +public: + bool enable; +}; + +using AuxiliaryData = Utils::variant<Utils::monostate, + LibraryIconAuxiliaryData, + FontCollectorSizeAuxiliaryData, + FontCollectorSizesAuxiliaryData>; enum class AbortReason : char { Abort, Failed }; diff --git a/src/plugins/qmldesigner/designercore/include/model.h b/src/plugins/qmldesigner/designercore/include/model.h index 9a2bc14fe63..6b8dfab4314 100644 --- a/src/plugins/qmldesigner/designercore/include/model.h +++ b/src/plugins/qmldesigner/designercore/include/model.h @@ -35,6 +35,7 @@ #include <import.h> QT_BEGIN_NAMESPACE +class QPixmap; class QUrl; QT_END_NAMESPACE @@ -44,7 +45,7 @@ namespace Internal { class ModelPrivate; class WriteLocker; class NodeMetaInfoPrivate; -} //Internal +} // namespace Internal class AnchorLine; class ModelNode; @@ -130,7 +131,7 @@ public: QString generateNewId(const QString &prefixName) const; QString generateNewId(const QString &prefixName, const QString &fallbackPrefix) const; - void startDrag(QMimeData *mimeData, const QString iconPath = {}); + void startDrag(QMimeData *mimeData, const QPixmap &icon); void endDrag(); protected: @@ -140,4 +141,4 @@ private: Internal::ModelPrivate *d; }; -} +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/include/viewmanager.h b/src/plugins/qmldesigner/designercore/include/viewmanager.h index 04f25b84f81..dd77c07f459 100644 --- a/src/plugins/qmldesigner/designercore/include/viewmanager.h +++ b/src/plugins/qmldesigner/designercore/include/viewmanager.h @@ -47,12 +47,11 @@ class Edit3DView; namespace Internal { class DesignModeWidget; } class ViewManagerData; -class AsynchronousImageCache; class QMLDESIGNERCORE_EXPORT ViewManager { public: - ViewManager(); + ViewManager(class AsynchronousImageCache &imageCache); ~ViewManager(); void attachRewriterView(); @@ -107,8 +106,6 @@ public: void disableStandardViews(); void enableStandardViews(); - AsynchronousImageCache &imageCache(); - private: // functions Q_DISABLE_COPY(ViewManager) diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp index 68519490837..5eef5550da7 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp @@ -600,11 +600,9 @@ void NodeInstanceView::nodeReparented(const ModelNode &node, const NodeAbstractP // Reset puppet when particle emitter/affector is reparented to work around issue in // autodetecting the particle system it belongs to. QTBUG-101157 - // Reset is also needed when particle shapes are reparented. QTBUG-101882 - if (((node.isSubclassOf("QtQuick.Particles3D.ParticleEmitter3D") + if ((node.isSubclassOf("QtQuick.Particles3D.ParticleEmitter3D") || node.isSubclassOf("QtQuick.Particles3D.Affector3D")) - && node.property("system").toBindingProperty().expression().isEmpty()) - || node.isSubclassOf("QQuick3DParticleAbstractShape")) { + && node.property("system").toBindingProperty().expression().isEmpty()) { resetPuppet(); } } @@ -987,6 +985,17 @@ QList<ModelNode> filterNodesForSkipItems(const QList<ModelNode> &nodeList) return filteredNodeList; } +QList<QColor> readBackgroundColorConfiguration(const QVariant &var) +{ + if (!var.isValid()) + return {}; + + auto colorNameList = var.value<QList<QString>>(); + QTC_ASSERT(colorNameList.size() == 2, return {}); + + return {colorNameList[0], colorNameList[1]}; +} + CreateSceneCommand NodeInstanceView::createCreateSceneCommand() { QList<ModelNode> nodeList = allModelNodes(); @@ -1141,6 +1150,17 @@ CreateSceneCommand NodeInstanceView::createCreateSceneCommand() if (stateNode.isValid() && stateNode.metaInfo().isSubclassOf("QtQuick.State", 1, 0)) stateInstanceId = stateNode.internalId(); + auto value +#ifndef QMLDESIGNER_TEST + = QmlDesigner::DesignerSettings::getValue( + QmlDesigner::DesignerSettingsKey::EDIT3DVIEW_BACKGROUND_COLOR); +#else + = QColor(); +#endif + QList<QColor> edit3dBackgroundColor; + if (value.isValid()) + edit3dBackgroundColor = readBackgroundColorConfiguration(value); + return CreateSceneCommand( instanceContainerList, reparentContainerList, @@ -1161,7 +1181,8 @@ CreateSceneCommand NodeInstanceView::createCreateSceneCommand() lastUsedLanguage, m_captureImageMinimumSize, m_captureImageMaximumSize, - stateInstanceId); + stateInstanceId, + edit3dBackgroundColor); } ClearSceneCommand NodeInstanceView::createClearSceneCommand() const @@ -2190,9 +2211,8 @@ void NodeInstanceView::maybeResetOnPropertyChange(const PropertyName &name, cons { bool reset = false; if (flags & AbstractView::PropertiesAdded - && name == "model" && (node.isSubclassOf("QtQuick.Repeater") - || node.isSubclassOf("QtQuick3D.Repeater3D"))) { - // TODO: This is a workaround for QTBUG-97583 (2D) and QTBUG-97586 (3D): + && name == "model" && node.isSubclassOf("QtQuick.Repeater")) { + // TODO: This is a workaround for QTBUG-97583: // Reset puppet when repeater model is first added, if there is already a delegate if (node.hasProperty("delegate")) reset = true; diff --git a/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp b/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp index 6f511472057..38c88a1cee1 100644 --- a/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp +++ b/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp @@ -610,7 +610,7 @@ QString PuppetCreator::qmakeCommand() const { QtSupport::QtVersion *currentQtVersion = QtSupport::QtKitAspect::qtVersion(m_target->kit()); if (currentQtVersion) - return currentQtVersion->queryToolFilePath().toString(); + return currentQtVersion->qmakeFilePath().toString(); return QString(); } diff --git a/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp b/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp index 8ddf6d448d1..5ece130a573 100644 --- a/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp +++ b/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp @@ -452,10 +452,9 @@ void SubComponentManager::parseQuick3DAssetsItem(const QString &importUrl, const QString iconPath = qmlIt.fileInfo().absolutePath() + '/' + Constants::QUICK_3D_ASSET_ICON_DIR + '/' + name + Constants::QUICK_3D_ASSET_LIBRARY_ICON_SUFFIX; - if (!QFileInfo::exists(iconPath)) - iconPath = defaultIconPath; - itemLibraryEntry.setLibraryEntryIconPath(iconPath); - itemLibraryEntry.setTypeIcon(QIcon(iconPath)); + if (QFileInfo::exists(iconPath)) + itemLibraryEntry.setLibraryEntryIconPath(iconPath); + itemLibraryEntry.setTypeIcon(QIcon(defaultIconPath)); // load hints file if exists QFile hintsFile(qmlIt.fileInfo().absolutePath() + '/' + name + ".hints"); diff --git a/src/plugins/qmldesigner/designercore/model/model.cpp b/src/plugins/qmldesigner/designercore/model/model.cpp index d879271c0d4..4e38fb3cfb3 100644 --- a/src/plugins/qmldesigner/designercore/model/model.cpp +++ b/src/plugins/qmldesigner/designercore/model/model.cpp @@ -1510,12 +1510,12 @@ QString Model::generateNewId(const QString &prefixName, const QString &fallbackP return newId; } -void Model::startDrag(QMimeData *mimeData, const QString iconPath) +void Model::startDrag(QMimeData *mimeData, const QPixmap &icon) { d->notifyDragStarted(mimeData); auto drag = new QDrag(this); - drag->setPixmap(iconPath); + drag->setPixmap(icon); drag->setMimeData(mimeData); drag->exec(); drag->deleteLater(); diff --git a/src/plugins/qmldesigner/designercore/model/viewmanager.cpp b/src/plugins/qmldesigner/designercore/model/viewmanager.cpp index d72761c91a3..730bfbb0fb5 100644 --- a/src/plugins/qmldesigner/designercore/model/viewmanager.cpp +++ b/src/plugins/qmldesigner/designercore/model/viewmanager.cpp @@ -62,6 +62,10 @@ static Q_LOGGING_CATEGORY(viewBenchmark, "qtc.viewmanager.attach", QtWarningMsg) class ViewManagerData { public: + ViewManagerData(AsynchronousImageCache &imageCache) + : itemLibraryView(imageCache) + {} + InteractiveConnectionManager connectionManager; CapturingConnectionManager capturingConnectionManager; QmlModelState savedState; @@ -90,12 +94,13 @@ static CrumbleBar *crumbleBar() { return QmlDesignerPlugin::instance()->mainWidget()->crumbleBar(); } -ViewManager::ViewManager() - : d(std::make_unique<ViewManagerData>()) +ViewManager::ViewManager(AsynchronousImageCache &imageCache) + : d(std::make_unique<ViewManagerData>(imageCache)) { d->formEditorView.setGotoErrorCallback([this](int line, int column) { d->textEditorView.gotoCursorPosition(line, column); - if (Internal::DesignModeWidget *designModeWidget = QmlDesignerPlugin::instance()->mainWidget()) + if (Internal::DesignModeWidget *designModeWidget = QmlDesignerPlugin::instance() + ->mainWidget()) designModeWidget->showDockWidget("TextEditor"); }); } @@ -439,11 +444,6 @@ void ViewManager::enableStandardViews() attachViewsExceptRewriterAndComponetView(); } -AsynchronousImageCache &ViewManager::imageCache() -{ - return d->itemLibraryView.imageCache(); -} - void ViewManager::addView(std::unique_ptr<AbstractView> &&view) { d->additionalViews.push_back(std::move(view)); diff --git a/src/plugins/qmldesigner/designersettings.cpp b/src/plugins/qmldesigner/designersettings.cpp index aad91e06b48..9c1aec1b364 100644 --- a/src/plugins/qmldesigner/designersettings.cpp +++ b/src/plugins/qmldesigner/designersettings.cpp @@ -80,6 +80,7 @@ void DesignerSettings::fromSettings(QSettings *settings) restoreValue(settings, DesignerSettingsKey::ALWAYS_DESIGN_MODE, true); restoreValue(settings, DesignerSettingsKey::DISABLE_ITEM_LIBRARY_UPDATE_TIMER, false); restoreValue(settings, DesignerSettingsKey::ASK_BEFORE_DELETING_ASSET, true); + restoreValue(settings, DesignerSettingsKey::EDIT3DVIEW_BACKGROUND_COLOR, QList<QString>{"#222222", "#999999"}); settings->endGroup(); settings->endGroup(); diff --git a/src/plugins/qmldesigner/designersettings.h b/src/plugins/qmldesigner/designersettings.h index e3fd4470da0..8c249fc65e0 100644 --- a/src/plugins/qmldesigner/designersettings.h +++ b/src/plugins/qmldesigner/designersettings.h @@ -49,6 +49,7 @@ const char WARNING_FOR_QML_FILES_INSTEAD_OF_UIQML_FILES[] = "WarnAboutQmlFilesIn const char WARNING_FOR_DESIGNER_FEATURES_IN_EDITOR[] = "WarnAboutQtQuickDesignerFeaturesInCodeEditor"; const char SHOW_DEBUGVIEW[] = "ShowQtQuickDesignerDebugView"; const char ENABLE_DEBUGVIEW[] = "EnableQtQuickDesignerDebugView"; +const char EDIT3DVIEW_BACKGROUND_COLOR[] = "Edit3DViewBackgroundColor"; const char ALWAYS_SAVE_IN_CRUMBLEBAR[] = "AlwaysSaveInCrumbleBar"; const char USE_DEFAULT_PUPPET[] = "UseDefaultQml2Puppet"; const char PUPPET_TOPLEVEL_BUILD_DIRECTORY[] = "PuppetToplevelBuildDirectory"; diff --git a/src/plugins/qmldesigner/qmldesignerconstants.h b/src/plugins/qmldesigner/qmldesignerconstants.h index efefc381a1f..8dc2b947496 100644 --- a/src/plugins/qmldesigner/qmldesignerconstants.h +++ b/src/plugins/qmldesigner/qmldesignerconstants.h @@ -65,6 +65,8 @@ 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_SELECT_BACKGROUND_COLOR[] = "QmlDesigner.Editor3D.SelectBackgroundColor"; +const char EDIT3D_EDIT_RESET_BACKGROUND_COLOR[] = "QmlDesigner.Editor3D.ResetBackgroundColor"; const char EDIT3D_EDIT_SHOW_SELECTION_BOX[] = "QmlDesigner.Editor3D.ToggleSelectionBox"; const char EDIT3D_EDIT_SHOW_ICON_GIZMO[] = "QmlDesigner.Editor3D.ToggleIconGizmo"; const char EDIT3D_EDIT_SHOW_CAMERA_FRUSTUM[] = "QmlDesigner.Editor3D.ToggleCameraFrustum"; @@ -74,6 +76,7 @@ const char EDIT3D_PARTICLE_MODE[] = "QmlDesigner.Editor3D.ParticleViewModeTo 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 EDIT3D_BACKGROUND_COLOR_ACTIONS[] = "QmlDesigner.Editor3D.BackgroundColorActions"; const char QML_DESIGNER_SUBFOLDER[] = "/designer/"; diff --git a/src/plugins/qmldesigner/qmldesignericons.h b/src/plugins/qmldesigner/qmldesignericons.h index 75ec4ab2d3f..437e420a48e 100644 --- a/src/plugins/qmldesigner/qmldesignericons.h +++ b/src/plugins/qmldesigner/qmldesignericons.h @@ -91,6 +91,8 @@ const Utils::Icon EDIT3D_ALIGN_CAMERA_ON({ {":/edit3d/images/align_camera_on.png", Utils::Theme::IconsBaseColor}}); const Utils::Icon EDIT3D_ALIGN_VIEW_ON({ {":/edit3d/images/align_view_on.png", Utils::Theme::IconsBaseColor}}); +const Utils::Icon COLOR_PALETTE({ + {":/edit3d/images/color_palette.png", Utils::Theme::IconsBaseColor}}); } // Icons } // QmlDesigner diff --git a/src/plugins/qmldesigner/qmldesignerplugin.cpp b/src/plugins/qmldesigner/qmldesignerplugin.cpp index 6e0ccf5f399..1ce53ee8d71 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.cpp +++ b/src/plugins/qmldesigner/qmldesignerplugin.cpp @@ -135,7 +135,7 @@ class QmlDesignerPluginPrivate { public: QmlDesignerProjectManager projectManager; - ViewManager viewManager; + ViewManager viewManager{projectManager.asynchronousImageCache()}; DocumentManager documentManager; ShortCutManager shortCutManager; SettingsPage settingsPage; @@ -666,7 +666,7 @@ void QmlDesignerPlugin::emitUsageStatisticsHelpRequested(const QString &identifi AsynchronousImageCache &QmlDesignerPlugin::imageCache() { - return m_instance->d->viewManager.imageCache(); + return m_instance->d->projectManager.asynchronousImageCache(); } void QmlDesignerPlugin::registerPreviewImageProvider(QQmlEngine *engine) diff --git a/src/plugins/qmldesigner/qmldesignerplugin.qbs b/src/plugins/qmldesigner/qmldesignerplugin.qbs index b48f257c55c..375f9e82233 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.qbs +++ b/src/plugins/qmldesigner/qmldesignerplugin.qbs @@ -526,6 +526,8 @@ Project { "debugview/debugviewwidget.ui", "edit3d/edit3dview.cpp", "edit3d/edit3dview.h", + "edit3d/backgroundcolorselection.cpp", + "edit3d/backgroundcolorselection.h", "edit3d/edit3dwidget.cpp", "edit3d/edit3dwidget.h", "edit3d/edit3dcanvas.cpp", diff --git a/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp b/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp index 538c3939f2f..43070221bcf 100644 --- a/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp +++ b/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp @@ -44,6 +44,7 @@ #include <qtsupport/qtkitinformation.h> #include <asynchronousexplicitimagecache.h> +#include <asynchronousimagecache.h> #include <imagecache/asynchronousimagefactory.h> #include <imagecache/explicitimagecacheimageprovider.h> #include <imagecache/imagecachecollector.h> @@ -60,6 +61,14 @@ namespace QmlDesigner { namespace { +ProjectExplorer::Target *activeTarget(ProjectExplorer::Project *project) +{ + if (project) + return project->activeTarget(); + + return {}; +} + QString defaultImagePath() { return Core::ICore::resourcePath("qmldesigner/welcomepage/images/newThumbnail.png").toString(); @@ -89,7 +98,22 @@ public: } // namespace -class PreviewImageCacheData +class QmlDesignerProjectManager::ImageCacheData +{ +public: + Sqlite::Database database{Utils::PathString{ + Core::ICore::cacheResourcePath("imagecache-v2.db").toString()}, + Sqlite::JournalMode::Wal, + Sqlite::LockingMode::Normal}; + ImageCacheStorage<Sqlite::Database> storage{database}; + ImageCacheConnectionManager connectionManager; + ImageCacheCollector collector{connectionManager, QSize{300, 300}, QSize{600, 600}}; + ImageCacheGenerator generator{collector, storage}; + TimeStampProvider timeStampProvider; + AsynchronousImageCache asynchronousImageCache{storage, generator, timeStampProvider}; +}; + +class QmlDesignerProjectManager::PreviewImageCacheData { public: Sqlite::Database database{Utils::PathString{ @@ -100,7 +124,7 @@ public: AsynchronousExplicitImageCache cache{storage}; }; -class QmlDesignerProjectManagerProjectData +class QmlDesignerProjectManager::QmlDesignerProjectManagerProjectData { public: QmlDesignerProjectManagerProjectData(ImageCacheStorage<Sqlite::Database> &storage) @@ -117,7 +141,7 @@ public: }; QmlDesignerProjectManager::QmlDesignerProjectManager() - : m_imageCacheData{std::make_unique<PreviewImageCacheData>()} + : m_previewImageCacheData{std::make_unique<PreviewImageCacheData>()} { auto editorManager = ::Core::EditorManager::instance(); QObject::connect(editorManager, &::Core::EditorManager::editorOpened, [&](auto *editor) { @@ -145,12 +169,17 @@ QmlDesignerProjectManager::~QmlDesignerProjectManager() = default; void QmlDesignerProjectManager::registerPreviewImageProvider(QQmlEngine *engine) const { - auto imageProvider = std::make_unique<ExplicitImageCacheImageProvider>(m_imageCacheData->cache, + auto imageProvider = std::make_unique<ExplicitImageCacheImageProvider>(m_previewImageCacheData->cache, QImage{defaultImagePath()}); engine->addImageProvider("project_preview", imageProvider.release()); } +AsynchronousImageCache &QmlDesignerProjectManager::asynchronousImageCache() +{ + return imageCacheData()->asynchronousImageCache; +} + void QmlDesignerProjectManager::editorOpened(::Core::IEditor *) {} void QmlDesignerProjectManager::currentEditorChanged(::Core::IEditor *) @@ -171,7 +200,7 @@ void QmlDesignerProjectManager::editorsClosed(const QList<::Core::IEditor *> &) void QmlDesignerProjectManager::projectAdded(::ProjectExplorer::Project *project) { - m_projectData = std::make_unique<QmlDesignerProjectManagerProjectData>(m_imageCacheData->storage); + m_projectData = std::make_unique<QmlDesignerProjectManagerProjectData>(m_previewImageCacheData->storage); m_projectData->activeTarget = project->activeTarget(); } @@ -183,4 +212,36 @@ void QmlDesignerProjectManager::aboutToRemoveProject(::ProjectExplorer::Project void QmlDesignerProjectManager::projectRemoved(::ProjectExplorer::Project *) {} +QmlDesignerProjectManager::ImageCacheData *QmlDesignerProjectManager::imageCacheData() +{ + std::call_once(imageCacheFlag, [this]() { + m_imageCacheData = std::make_unique<ImageCacheData>(); + auto setTargetInImageCache = + [imageCacheData = m_imageCacheData.get()](ProjectExplorer::Target *target) { + if (target == imageCacheData->collector.target()) + return; + + if (target) + imageCacheData->asynchronousImageCache.clean(); + + imageCacheData->collector.setTarget(target); + }; + + if (auto project = ProjectExplorer::SessionManager::startupProject(); project) { + m_imageCacheData->collector.setTarget(project->activeTarget()); + QObject::connect(project, + &ProjectExplorer::Project::activeTargetChanged, + this, + setTargetInImageCache); + } + QObject::connect(ProjectExplorer::SessionManager::instance(), + &ProjectExplorer::SessionManager::startupProjectChanged, + this, + [=](ProjectExplorer::Project *project) { + setTargetInImageCache(activeTarget(project)); + }); + }); + return m_imageCacheData.get(); +} + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/qmldesignerprojectmanager.h b/src/plugins/qmldesigner/qmldesignerprojectmanager.h index 4b993ba74d2..6b94fa9e6f4 100644 --- a/src/plugins/qmldesigner/qmldesignerprojectmanager.h +++ b/src/plugins/qmldesigner/qmldesignerprojectmanager.h @@ -26,8 +26,10 @@ #pragma once #include <QList> +#include <QObject> #include <memory> +#include <mutex> QT_FORWARD_DECLARE_CLASS(QQmlEngine) @@ -42,17 +44,22 @@ class Target; namespace QmlDesigner { -class QmlDesignerProjectManagerProjectData; -class PreviewImageCacheData; - -class QmlDesignerProjectManager +class QmlDesignerProjectManager : public QObject { + Q_OBJECT + + class QmlDesignerProjectManagerProjectData; + class PreviewImageCacheData; + class ImageCacheData; + public: QmlDesignerProjectManager(); ~QmlDesignerProjectManager(); void registerPreviewImageProvider(QQmlEngine *engine) const; + class AsynchronousImageCache &asynchronousImageCache(); + private: void editorOpened(::Core::IEditor *editor); void currentEditorChanged(::Core::IEditor *); @@ -60,9 +67,12 @@ private: void projectAdded(::ProjectExplorer::Project *project); void aboutToRemoveProject(::ProjectExplorer::Project *project); void projectRemoved(::ProjectExplorer::Project *project); + ImageCacheData *imageCacheData(); private: - std::unique_ptr<PreviewImageCacheData> m_imageCacheData; + std::once_flag imageCacheFlag; + std::unique_ptr<ImageCacheData> m_imageCacheData; + std::unique_ptr<PreviewImageCacheData> m_previewImageCacheData; std::unique_ptr<QmlDesignerProjectManagerProjectData> m_projectData; }; } // namespace QmlDesigner diff --git a/src/plugins/qnx/qnxrunconfiguration.cpp b/src/plugins/qnx/qnxrunconfiguration.cpp index 39753f8afb4..927a9a94691 100644 --- a/src/plugins/qnx/qnxrunconfiguration.cpp +++ b/src/plugins/qnx/qnxrunconfiguration.cpp @@ -47,7 +47,7 @@ namespace Internal { QnxRunConfiguration::QnxRunConfiguration(Target *target, Id id) : RunConfiguration(target, id) { - auto exeAspect = addAspect<ExecutableAspect>(target); + auto exeAspect = addAspect<ExecutableAspect>(target, ExecutableAspect::RunDevice); exeAspect->setLabelText(tr("Executable on device:")); exeAspect->setPlaceHolderText(tr("Remote path not set")); exeAspect->makeOverridable("RemoteLinux.RunConfig.AlternateRemoteExecutable", diff --git a/src/plugins/qtsupport/baseqtversion.cpp b/src/plugins/qtsupport/baseqtversion.cpp index 324add0e7c6..1aafe1f575c 100644 --- a/src/plugins/qtsupport/baseqtversion.cpp +++ b/src/plugins/qtsupport/baseqtversion.cpp @@ -81,7 +81,6 @@ const char QTVERSIONAUTODETECTED[] = "isAutodetected"; const char QTVERSIONDETECTIONSOURCE[] = "autodetectionSource"; const char QTVERSION_OVERRIDE_FEATURES[] = "overrideFeatures"; const char QTVERSIONQMAKEPATH[] = "QMakePath"; -const char QTVERSIONQUERYTOOLPATH[] = "QueryToolPath"; const char QTVERSIONSOURCEPATH[] = "SourcePath"; const char QTVERSION_ABIS[] = "Abis"; @@ -188,19 +187,19 @@ public: FilePath findHostBinary(HostBinaries binary) const; void updateMkspec(); QHash<ProKey, ProString> versionInfo(); - static bool queryQtPaths(const FilePath &queryTool, - const Environment &env, - QHash<ProKey, ProString> *versionInfo, - QString *error = nullptr); + static bool queryQMakeVariables(const FilePath &binary, + const Environment &env, + QHash<ProKey, ProString> *versionInfo, + QString *error = nullptr); enum PropertyVariant { PropertyVariantDev, PropertyVariantGet, PropertyVariantSrc }; QString qmakeProperty(const QByteArray &name, PropertyVariant variant = PropertyVariantGet); static QString qmakeProperty(const QHash<ProKey, ProString> &versionInfo, const QByteArray &name, PropertyVariant variant = PropertyVariantGet); static FilePath mkspecDirectoryFromVersionInfo(const QHash<ProKey, ProString> &versionInfo, - const FilePath &queryTool); + const FilePath &qmakeCommand); static FilePath mkspecFromVersionInfo(const QHash<ProKey,ProString> &versionInfo, - const FilePath &queryTool); + const FilePath &qmakeCommand); static FilePath sourcePath(const QHash<ProKey,ProString> &versionInfo); void setId(int id); // used by the qtversionmanager for legacy restore // and by the qtoptionspage to replace Qt versions @@ -222,7 +221,7 @@ public: bool m_defaultConfigIsDebugAndRelease = true; bool m_frameworkBuild = false; bool m_versionInfoUpToDate = false; - bool m_queryToolIsExecutable = true; + bool m_qmakeIsExecutable = true; QString m_detectionSource; QSet<Utils::Id> m_overrideFeatures; @@ -234,7 +233,6 @@ public: QHash<ProKey, ProString> m_versionInfo; - FilePath m_queryTool; FilePath m_qmakeCommand; FilePath m_rccPath; @@ -348,12 +346,12 @@ QtVersion::~QtVersion() QString QtVersion::defaultUnexpandedDisplayName() const { QString location; - if (queryToolFilePath().isEmpty()) { + if (qmakeFilePath().isEmpty()) { location = QCoreApplication::translate("QtVersion", "<unknown>"); } else { // Deduce a description from '/foo/qt-folder/[qtbase]/bin/qmake' -> '/foo/qt-folder'. // '/usr' indicates System Qt 4.X on Linux. - for (FilePath dir = queryToolFilePath().parentDir(); !dir.isEmpty(); dir = dir.parentDir()) { + for (FilePath dir = qmakeFilePath().parentDir(); !dir.isEmpty(); dir = dir.parentDir()) { const QString dirName = dir.fileName(); if (dirName == "usr") { // System-installed Qt. location = QCoreApplication::translate("QtVersion", "System"); @@ -727,23 +725,20 @@ void QtVersion::fromMap(const QVariantMap &map) d->m_isAutodetected = map.value(QTVERSIONAUTODETECTED).toBool(); d->m_detectionSource = map.value(QTVERSIONDETECTIONSOURCE).toString(); d->m_overrideFeatures = Utils::Id::fromStringList(map.value(QTVERSION_OVERRIDE_FEATURES).toStringList()); - d->m_queryTool = FilePath::fromVariant(map.value(QTVERSIONQUERYTOOLPATH, - map.value(QTVERSIONQMAKEPATH))); - if (!d->m_queryTool.baseName().contains("qtpaths")) - d->m_qmakeCommand = d->m_queryTool; + d->m_qmakeCommand = FilePath::fromVariant(map.value(QTVERSIONQMAKEPATH)); - FilePath queryTool = d->m_queryTool; + FilePath qmake = d->m_qmakeCommand; // FIXME: Check this is still needed or whether ProcessArgs::splitArg handles it. - QString string = d->m_queryTool.path(); + QString string = d->m_qmakeCommand.path(); if (string.startsWith('~')) string.remove(0, 1).prepend(QDir::homePath()); - queryTool.setPath(string); - if (!d->m_queryTool.needsDevice()) { - if (BuildableHelperLibrary::isQtChooser(queryTool)) { + qmake.setPath(string); + if (!d->m_qmakeCommand.needsDevice()) { + if (BuildableHelperLibrary::isQtChooser(qmake)) { // we don't want to treat qtchooser as a normal qmake // see e.g. QTCREATORBUG-9841, also this lead to users changing what // qtchooser forwards too behind our backs, which will inadvertly lead to bugs - d->m_queryTool = BuildableHelperLibrary::qtChooserToQueryToolPath(queryTool); + d->m_qmakeCommand = BuildableHelperLibrary::qtChooserToQmakePath(qmake); } } @@ -774,7 +769,6 @@ QVariantMap QtVersion::toMap() const result.insert(QTVERSION_OVERRIDE_FEATURES, Utils::Id::toStringList(d->m_overrideFeatures)); result.insert(QTVERSIONQMAKEPATH, qmakeFilePath().toVariant()); - result.insert(QTVERSIONQUERYTOOLPATH, queryToolFilePath().toVariant()); return result; } @@ -785,8 +779,8 @@ bool QtVersion::isValid() const d->updateVersionInfo(); d->updateMkspec(); - return !queryToolFilePath().isEmpty() && d->m_data.installed && !binPath().isEmpty() - && !d->m_mkspecFullPath.isEmpty() && d->m_queryToolIsExecutable; + return !qmakeFilePath().isEmpty() && d->m_data.installed && !binPath().isEmpty() + && !d->m_mkspecFullPath.isEmpty() && d->m_qmakeIsExecutable; } QtVersion::Predicate QtVersion::isValidPredicate(const QtVersion::Predicate &predicate) @@ -800,18 +794,15 @@ QString QtVersion::invalidReason() const { if (displayName().isEmpty()) return QCoreApplication::translate("QtVersion", "Qt version has no name"); - if (queryToolFilePath().isEmpty()) - return QCoreApplication::translate("QtVersion", "No Qt query tool path set"); - if (!d->m_queryToolIsExecutable) - return QCoreApplication::translate("QtVersion", "%1 does not exist or is not executable") - .arg(queryToolFilePath().baseName()); + if (qmakeFilePath().isEmpty()) + return QCoreApplication::translate("QtVersion", "No qmake path set"); + if (!d->m_qmakeIsExecutable) + return QCoreApplication::translate("QtVersion", "qmake does not exist or is not executable"); if (!d->m_data.installed) return QCoreApplication::translate("QtVersion", "Qt version is not properly installed, please run make install"); if (binPath().isEmpty()) return QCoreApplication::translate("QtVersion", - "Could not determine the path to the binaries of the " - "Qt installation, maybe the %1 path is wrong?") - .arg(queryToolFilePath().baseName()); + "Could not determine the path to the binaries of the Qt installation, maybe the qmake path is wrong?"); if (d->m_mkspecUpToDate && d->m_mkspecFullPath.isEmpty()) return QCoreApplication::translate("QtVersion", "The default mkspec symlink is broken."); return QString(); @@ -829,20 +820,8 @@ QStringList QtVersion::warningReason() const return ret; } -FilePath QtVersion::queryToolFilePath() const -{ - return d->m_queryTool; -} - FilePath QtVersion::qmakeFilePath() const { - if (d->m_qmakeCommand.isEmpty() && d->m_queryTool.baseName().contains("qtpaths")) { - // TODO: might need a less lazy implementation - const FilePath qmake = - FilePath::fromString(d->m_queryTool.toString().replace("qtpaths", "qmake")); - if (qmake.exists()) - d->m_qmakeCommand = qmake; - } return d->m_qmakeCommand; } @@ -876,7 +855,7 @@ bool QtVersion::hasAbi(ProjectExplorer::Abi::OS os, ProjectExplorer::Abi::OSFlav bool QtVersion::equals(QtVersion *other) { - if (d->m_queryTool != other->d->m_queryTool) + if (d->m_qmakeCommand != other->d->m_qmakeCommand) return false; if (type() != other->type()) return false; @@ -954,15 +933,13 @@ QString QtVersion::toHtml(bool verbose) const str << "<td>" << abis.at(i).toString() << "</td></tr>"; } } - const OsType osType = d->m_queryTool.osType(); + const OsType osType = d->m_qmakeCommand.osType(); str << "<tr><td><b>" << QCoreApplication::translate("QtVersion", "Source:") << "</b></td><td>" << sourcePath().toUserOutput() << "</td></tr>"; str << "<tr><td><b>" << QCoreApplication::translate("QtVersion", "mkspec:") << "</b></td><td>" << QDir::toNativeSeparators(mkspec()) << "</td></tr>"; str << "<tr><td><b>" << QCoreApplication::translate("QtVersion", "qmake:") - << "</b></td><td>" << qmakeFilePath().toUserOutput() << "</td></tr>"; - str << "<tr><td><b>" << QCoreApplication::translate("QtVersion", "Query tool:") - << "</b></td><td>" << d->m_queryTool.toUserOutput() << "</td></tr>"; + << "</b></td><td>" << d->m_qmakeCommand.toUserOutput() << "</td></tr>"; ensureMkSpecParsed(); if (!mkspecPath().isEmpty()) { if (d->m_defaultConfigIsDebug || d->m_defaultConfigIsDebugAndRelease) { @@ -1187,13 +1164,13 @@ void QtVersionPrivate::updateMkspec() return; m_mkspecUpToDate = true; - m_mkspecFullPath = mkspecFromVersionInfo(versionInfo(), m_queryTool); + m_mkspecFullPath = mkspecFromVersionInfo(versionInfo(), m_qmakeCommand); m_mkspec = m_mkspecFullPath; if (m_mkspecFullPath.isEmpty()) return; - FilePath baseMkspecDir = mkspecDirectoryFromVersionInfo(versionInfo(), m_queryTool); + FilePath baseMkspecDir = mkspecDirectoryFromVersionInfo(versionInfo(), m_qmakeCommand); if (m_mkspec.isChildOf(baseMkspecDir)) { m_mkspec = m_mkspec.relativeChildPath(baseMkspecDir); @@ -1220,7 +1197,7 @@ void QtVersion::ensureMkSpecParsed() const QMakeVfs vfs; QMakeGlobals option; applyProperties(&option); - Environment env = d->m_queryTool.deviceEnvironment(); + Environment env = d->m_qmakeCommand.deviceEnvironment(); setupQmakeRunEnvironment(env); option.environment = env.toProcessEnvironment(); ProMessageHandler msgHandler(true); @@ -1333,7 +1310,7 @@ QtVersionNumber QtVersion::qtVersion() const void QtVersionPrivate::updateVersionInfo() { - if (m_versionInfoUpToDate || !m_queryToolIsExecutable || m_isUpdating) + if (m_versionInfoUpToDate || !m_qmakeIsExecutable || m_isUpdating) return; m_isUpdating = true; @@ -1344,16 +1321,16 @@ void QtVersionPrivate::updateVersionInfo() m_data.hasExamples = false; m_data.hasDocumentation = false; - if (!queryQtPaths(m_queryTool, q->qmakeRunEnvironment(), &m_versionInfo)) { - m_queryToolIsExecutable = false; + if (!queryQMakeVariables(m_qmakeCommand, q->qmakeRunEnvironment(), &m_versionInfo)) { + m_qmakeIsExecutable = false; qWarning("Cannot update Qt version information: %s cannot be run.", - qPrintable(m_queryTool.toString())); + qPrintable(m_qmakeCommand.toString())); return; } - m_queryToolIsExecutable = true; + m_qmakeIsExecutable = true; auto fileProperty = [this](const QByteArray &name) { - return FilePath::fromUserInput(qmakeProperty(name)).onDevice(m_queryTool); + return FilePath::fromUserInput(qmakeProperty(name)).onDevice(m_qmakeCommand); }; m_data.prefix = fileProperty("QT_INSTALL_PREFIX"); @@ -1408,8 +1385,8 @@ QHash<ProKey,ProString> QtVersionPrivate::versionInfo() } QString QtVersionPrivate::qmakeProperty(const QHash<ProKey, ProString> &versionInfo, - const QByteArray &name, - PropertyVariant variant) + const QByteArray &name, + PropertyVariant variant) { QString val = versionInfo .value(ProKey(QString::fromLatin1( @@ -1751,7 +1728,7 @@ void QtVersion::addToEnvironment(const Kit *k, Environment &env) const Environment QtVersion::qmakeRunEnvironment() const { - Environment env = d->m_queryTool.deviceEnvironment(); + Environment env = d->m_qmakeCommand.deviceEnvironment(); setupQmakeRunEnvironment(env); return env; } @@ -1779,7 +1756,7 @@ Tasks QtVersion::reportIssuesImpl(const QString &proFile, const QString &buildDi results.append(BuildSystemTask(Task::Error, msg)); } - FilePath qmake = queryToolFilePath(); + FilePath qmake = qmakeFilePath(); if (!qmake.isExecutableFile()) { //: %1: Path to qmake executable const QString msg = QCoreApplication::translate("QmakeProjectManager::QtVersion", @@ -1839,21 +1816,20 @@ static QByteArray runQmakeQuery(const FilePath &binary, const Environment &env, return process.readAllStandardOutput(); } -bool QtVersionPrivate::queryQtPaths(const FilePath &queryTool, const Environment &env, - QHash<ProKey, ProString> *versionInfo, QString *error) +bool QtVersionPrivate::queryQMakeVariables(const FilePath &binary, const Environment &env, + QHash<ProKey, ProString> *versionInfo, QString *error) { QString tmp; if (!error) error = &tmp; - if (!queryTool.isExecutableFile()) { - *error = QCoreApplication::translate("QtVersion", "\"%1\" is not an executable.") - .arg(queryTool.toUserOutput()); + if (!binary.isExecutableFile()) { + *error = QCoreApplication::translate("QtVersion", "qmake \"%1\" is not an executable.").arg(binary.toUserOutput()); return false; } QByteArray output; - output = runQmakeQuery(queryTool, env, error); + output = runQmakeQuery(binary, env, error); if (!output.contains("QMAKE_VERSION:")) { // Some setups pass error messages via stdout, fooling the logic below. @@ -1871,14 +1847,14 @@ bool QtVersionPrivate::queryQtPaths(const FilePath &queryTool, const Environment // Try running qmake with all kinds of tool chains set up in the environment. // This is required to make non-static qmakes work on windows where every tool chain // tries to be incompatible with any other. - const Abis abiList = Abi::abisOfBinary(queryTool); + const Abis abiList = Abi::abisOfBinary(binary); const Toolchains tcList = ToolChainManager::toolchains([&abiList](const ToolChain *t) { return abiList.contains(t->targetAbi()); }); for (ToolChain *tc : tcList) { Environment realEnv = env; tc->addToEnvironment(realEnv); - output = runQmakeQuery(queryTool, realEnv, error); + output = runQmakeQuery(binary, realEnv, error); if (error->isEmpty()) break; } @@ -1900,18 +1876,18 @@ QString QtVersionPrivate::qmakeProperty(const QByteArray &name, } FilePath QtVersionPrivate::mkspecDirectoryFromVersionInfo(const QHash<ProKey, ProString> &versionInfo, - const FilePath &queryTool) + const FilePath &qmakeCommand) { QString dataDir = qmakeProperty(versionInfo, "QT_HOST_DATA", PropertyVariantSrc); if (dataDir.isEmpty()) return FilePath(); - return FilePath::fromUserInput(dataDir + "/mkspecs").onDevice(queryTool); + return FilePath::fromUserInput(dataDir + "/mkspecs").onDevice(qmakeCommand); } FilePath QtVersionPrivate::mkspecFromVersionInfo(const QHash<ProKey, ProString> &versionInfo, - const FilePath &queryTool) + const FilePath &qmakeCommand) { - FilePath baseMkspecDir = mkspecDirectoryFromVersionInfo(versionInfo, queryTool); + FilePath baseMkspecDir = mkspecDirectoryFromVersionInfo(versionInfo, qmakeCommand); if (baseMkspecDir.isEmpty()) return FilePath(); @@ -2343,16 +2319,14 @@ void QtVersion::resetCache() const static QList<QtVersionFactory *> g_qtVersionFactories; -QtVersion *QtVersionFactory::createQtVersionFromQueryToolPath(const FilePath &queryTool, - bool isAutoDetected, - const QString &detectionSource, - QString *error) +QtVersion *QtVersionFactory::createQtVersionFromQMakePath + (const FilePath &qmakePath, bool isAutoDetected, const QString &detectionSource, QString *error) { QHash<ProKey, ProString> versionInfo; - const Environment env = queryTool.deviceEnvironment(); - if (!QtVersionPrivate::queryQtPaths(queryTool, env, &versionInfo, error)) + const Environment env = qmakePath.deviceEnvironment(); + if (!QtVersionPrivate::queryQMakeVariables(qmakePath, env, &versionInfo, error)) return nullptr; - FilePath mkspec = QtVersionPrivate::mkspecFromVersionInfo(versionInfo, queryTool); + FilePath mkspec = QtVersionPrivate::mkspecFromVersionInfo(versionInfo, qmakePath); QMakeVfs vfs; QMakeGlobals globals; @@ -2368,7 +2342,7 @@ QtVersion *QtVersionFactory::createQtVersionFromQueryToolPath(const FilePath &qu return l->m_priority > r->m_priority; }); - if (!queryTool.isExecutableFile()) + if (!qmakePath.isExecutableFile()) return nullptr; QtVersionFactory::SetupData setup; @@ -2381,8 +2355,8 @@ QtVersion *QtVersionFactory::createQtVersionFromQueryToolPath(const FilePath &qu QtVersion *ver = factory->create(); QTC_ASSERT(ver, continue); ver->d->m_id = QtVersionManager::getUniqueId(); - QTC_CHECK(ver->d->m_queryTool.isEmpty()); // Should only be used once. - ver->d->m_queryTool = queryTool; + QTC_CHECK(ver->d->m_qmakeCommand.isEmpty()); // Should only be used once. + ver->d->m_qmakeCommand = qmakePath; ver->d->m_detectionSource = detectionSource; ver->d->m_isAutodetected = isAutoDetected; ver->updateDefaultDisplayName(); @@ -2393,7 +2367,7 @@ QtVersion *QtVersionFactory::createQtVersionFromQueryToolPath(const FilePath &qu ProFileCacheManager::instance()->decRefCount(); if (error) { *error = QCoreApplication::translate("QtSupport::QtVersionFactory", - "No factory found for query tool \"%1\"").arg(queryTool.toUserOutput()); + "No factory found for qmake: \"%1\"").arg(qmakePath.toUserOutput()); } return nullptr; } diff --git a/src/plugins/qtsupport/baseqtversion.h b/src/plugins/qtsupport/baseqtversion.h index f0400bc99b5..269a6507168 100644 --- a/src/plugins/qtsupport/baseqtversion.h +++ b/src/plugins/qtsupport/baseqtversion.h @@ -150,8 +150,6 @@ public: bool hasDocs() const; bool hasDemos() const; - Utils::FilePath queryToolFilePath() const; - // former local functions Utils::FilePath qmakeFilePath() const; diff --git a/src/plugins/qtsupport/qtkitinformation.cpp b/src/plugins/qtsupport/qtkitinformation.cpp index 672ad493df4..43bbc07c1c3 100644 --- a/src/plugins/qtsupport/qtkitinformation.cpp +++ b/src/plugins/qtsupport/qtkitinformation.cpp @@ -324,11 +324,6 @@ void QtKitAspect::addToMacroExpander(Kit *kit, MacroExpander *expander) const QtVersion *version = qtVersion(kit); return version ? version->qmakeFilePath().path() : QString(); }); - expander->registerVariable("Qt:queryToolExecutable", tr("Path to the query tool executable"), - [kit]() -> QString { - QtVersion *version = qtVersion(kit); - return version ? version->queryToolFilePath().path() : QString(); - }); } Id QtKitAspect::id() diff --git a/src/plugins/qtsupport/qtoptionspage.cpp b/src/plugins/qtsupport/qtoptionspage.cpp index 06a8a6bbd52..c0049058abd 100644 --- a/src/plugins/qtsupport/qtoptionspage.cpp +++ b/src/plugins/qtsupport/qtoptionspage.cpp @@ -51,7 +51,6 @@ #include <utils/hostosinfo.h> #include <utils/pathchooser.h> #include <utils/qtcassert.h> -#include <utils/qtcprocess.h> #include <utils/runextensions.h> #include <utils/treemodel.h> #include <utils/utilsicons.h> @@ -112,7 +111,7 @@ public: if (column == 0) return m_version->displayName(); if (column == 1) - return m_version->queryToolFilePath().toUserOutput(); + return m_version->qmakeFilePath().toUserOutput(); } if (role == Qt::FontRole && m_changed) { @@ -129,8 +128,7 @@ public: "<dd>%2</dd>"; return QString("<dl style=\"white-space:pre\">" + row.arg(tr("Qt Version"), m_version->qtVersionString()) - + row.arg(tr("Location of the query tool"), - m_version->queryToolFilePath().toUserOutput()) + + row.arg(tr("Location of qmake"), m_version->qmakeFilePath().toUserOutput()) + "</dl>"); } @@ -602,42 +600,27 @@ QtOptionsPageWidget::~QtOptionsPageWidget() delete m_configurationWidget; } -static bool isIncompatibleQtPathsTool(const FilePath &tool) -{ - if (!tool.baseName().startsWith("qtpaths")) - return false; - QtcProcess process; - process.setTimeoutS(1); - process.setCommand({tool, {"-query"}}); - process.runBlocking(); - return process.result() != ProcessResult::FinishedWithSuccess; -} - void QtOptionsPageWidget::addQtDir() { - FilePath qtQueryTool = - FileUtils::getOpenFilePath(this, - tr("Select a qmake or qtpaths Executable"), - {}, - BuildableHelperLibrary::filterForQtQueryToolsFileDialog(), - 0, - QFileDialog::DontResolveSymlinks); - if (qtQueryTool.isEmpty()) + FilePath qtVersion = FileUtils::getOpenFilePath(this, + tr("Select a qmake Executable"), + {}, + BuildableHelperLibrary::filterForQmakeFileDialog(), + 0, + QFileDialog::DontResolveSymlinks); + if (qtVersion.isEmpty()) return; - if (isIncompatibleQtPathsTool(qtQueryTool)) - qtQueryTool = qtQueryTool.parentDir() / HostOsInfo::withExecutableSuffix("qmake"); - // should add all qt versions here ? - if (BuildableHelperLibrary::isQtChooser(qtQueryTool)) - qtQueryTool = BuildableHelperLibrary::qtChooserToQueryToolPath(qtQueryTool.symLinkTarget()); + if (BuildableHelperLibrary::isQtChooser(qtVersion)) + qtVersion = BuildableHelperLibrary::qtChooserToQmakePath(qtVersion.symLinkTarget()); - auto checkAlreadyExists = [qtQueryTool](TreeItem *parent) { + auto checkAlreadyExists = [qtVersion](TreeItem *parent) { for (int i = 0; i < parent->childCount(); ++i) { auto item = static_cast<QtVersionItem *>(parent->childAt(i)); - // Compare parent dirs, since it could be either qmake or qtpaths - if (item->version()->queryToolFilePath().parentDir() == qtQueryTool.parentDir()) + if (item->version()->qmakeFilePath() == qtVersion) { return std::make_pair(true, item->version()->displayName()); + } } return std::make_pair(false, QString()); }; @@ -657,8 +640,7 @@ void QtOptionsPageWidget::addQtDir() } QString error; - QtVersion *version = QtVersionFactory::createQtVersionFromQueryToolPath(qtQueryTool, false, - QString(), &error); + QtVersion *version = QtVersionFactory::createQtVersionFromQMakePath(qtVersion, false, QString(), &error); if (version) { auto item = new QtVersionItem(version); item->setIcon(version->isValid()? m_validVersionIcon : m_invalidVersionIcon); @@ -668,9 +650,8 @@ void QtOptionsPageWidget::addQtDir() m_versionUi.nameEdit->setFocus(); m_versionUi.nameEdit->selectAll(); } else { - QMessageBox::warning(this, tr("Not Executable"), - tr("The executable %1 could not be added: %2").arg( - qtQueryTool.toUserOutput()).arg(error)); + QMessageBox::warning(this, tr("Qmake Not Executable"), + tr("The qmake executable %1 could not be added: %2").arg(qtVersion.toUserOutput()).arg(error)); return; } updateCleanUpButton(); @@ -690,16 +671,16 @@ void QtOptionsPageWidget::removeQtDir() void QtOptionsPageWidget::editPath() { QtVersion *current = currentVersion(); - const FilePath queryTool = + FilePath qtVersion = FileUtils::getOpenFilePath(this, - tr("Select a qmake or qtpaths Executable"), - current->queryToolFilePath().absolutePath(), - BuildableHelperLibrary::filterForQtQueryToolsFileDialog(), + tr("Select a qmake Executable"), + current->qmakeFilePath().absolutePath(), + BuildableHelperLibrary::filterForQmakeFileDialog(), nullptr, QFileDialog::DontResolveSymlinks); - if (queryTool.isEmpty()) + if (qtVersion.isEmpty()) return; - QtVersion *version = QtVersionFactory::createQtVersionFromQueryToolPath(queryTool); + QtVersion *version = QtVersionFactory::createQtVersionFromQMakePath(qtVersion); if (!version) return; // Same type? then replace! @@ -787,7 +768,7 @@ void QtOptionsPageWidget::updateWidgets() QtVersion *version = currentVersion(); if (version) { m_versionUi.nameEdit->setText(version->unexpandedDisplayName()); - m_versionUi.queryToolPath->setText(version->queryToolFilePath().toUserOutput()); + m_versionUi.qmakePath->setText(version->qmakeFilePath().toUserOutput()); m_configurationWidget = version->createConfigurationWidget(); if (m_configurationWidget) { m_versionUi.formLayout->addRow(m_configurationWidget); @@ -797,7 +778,7 @@ void QtOptionsPageWidget::updateWidgets() } } else { m_versionUi.nameEdit->clear(); - m_versionUi.queryToolPath->clear(); + m_versionUi.qmakePath->clear(); } const bool enabled = version != nullptr; diff --git a/src/plugins/qtsupport/qtprojectimporter.cpp b/src/plugins/qtsupport/qtprojectimporter.cpp index fc44f3b7d37..9014aa71f08 100644 --- a/src/plugins/qtsupport/qtprojectimporter.cpp +++ b/src/plugins/qtsupport/qtprojectimporter.cpp @@ -57,7 +57,7 @@ QtProjectImporter::QtVersionData QtProjectImporter::findOrCreateQtVersion(const Utils::FilePath &qmakePath) const { QtVersionData result; - result.qt = QtVersionManager::version(Utils::equal(&QtVersion::queryToolFilePath, qmakePath)); + result.qt = QtVersionManager::version(Utils::equal(&QtVersion::qmakeFilePath, qmakePath)); if (result.qt) { // Check if version is a temporary qt const int qtId = result.qt->uniqueId(); @@ -67,7 +67,7 @@ QtProjectImporter::findOrCreateQtVersion(const Utils::FilePath &qmakePath) const // Create a new version if not found: // Do not use the canonical path here... - result.qt = QtVersionFactory::createQtVersionFromQueryToolPath(qmakePath); + result.qt = QtVersionFactory::createQtVersionFromQMakePath(qmakePath); result.isTemporary = true; if (result.qt) { UpdateGuard guard(*this); @@ -281,7 +281,7 @@ static QStringList additionalFilesToCopy(const QtVersion *qt) } else if (HostOsInfo::isWindowsHost()) { const QString release = QString("bin/Qt%1Core.dll").arg(major); const QString debug = QString("bin/Qt%1Cored.dll").arg(major); - const FilePath base = qt->queryToolFilePath().parentDir().parentDir(); + const FilePath base = qt->qmakeFilePath().parentDir().parentDir(); if (base.pathAppended(release).exists()) return {release}; if (base.pathAppended(debug).exists()) @@ -289,7 +289,7 @@ static QStringList additionalFilesToCopy(const QtVersion *qt) return {release}; } else if (HostOsInfo::isLinuxHost()) { const QString core = QString("lib/libQt%1Core.so.%1").arg(major); - const QDir base(qt->queryToolFilePath().parentDir().parentDir().pathAppended("lib").toString()); + const QDir base(qt->qmakeFilePath().parentDir().parentDir().pathAppended("lib").toString()); const QStringList icuLibs = Utils::transform(base.entryList({"libicu*.so.*"}), [](const QString &lib) { return QString("lib/" + lib); }); return QStringList(core) + icuLibs; } @@ -300,7 +300,7 @@ static QStringList additionalFilesToCopy(const QtVersion *qt) static Utils::FilePath setupQmake(const QtVersion *qt, const QString &path) { // This is a hack and only works with local, "standard" installations of Qt - const FilePath qmake = qt->queryToolFilePath().canonicalPath(); + const FilePath qmake = qt->qmakeFilePath().canonicalPath(); const QString qmakeFile = "bin/" + qmake.fileName(); const FilePath source = qmake.parentDir().parentDir(); const FilePath target = FilePath::fromString(path); diff --git a/src/plugins/qtsupport/qtversionfactory.h b/src/plugins/qtsupport/qtversionfactory.h index 96bf8e2088a..bc01ad7601a 100644 --- a/src/plugins/qtsupport/qtversionfactory.h +++ b/src/plugins/qtsupport/qtversionfactory.h @@ -51,7 +51,7 @@ public: /// the desktop factory claims to handle all paths int priority() const { return m_priority; } - static QtVersion *createQtVersionFromQueryToolPath(const Utils::FilePath &qmakePath, + static QtVersion *createQtVersionFromQMakePath(const Utils::FilePath &qmakePath, bool isAutoDetected = false, const QString &detectionSource = {}, QString *error = nullptr); diff --git a/src/plugins/qtsupport/qtversioninfo.ui b/src/plugins/qtsupport/qtversioninfo.ui index 815be818177..467e898a20e 100644 --- a/src/plugins/qtsupport/qtversioninfo.ui +++ b/src/plugins/qtsupport/qtversioninfo.ui @@ -39,14 +39,14 @@ <item row="1" column="0"> <widget class="QLabel" name="pathLabel"> <property name="text"> - <string>Query tool path:</string> + <string>qmake path:</string> </property> </widget> </item> <item row="1" column="1"> <layout class="QHBoxLayout" name="horizontalLayout"> <item> - <widget class="QLabel" name="queryToolPath"> + <widget class="QLabel" name="qmakePath"> <property name="sizePolicy"> <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> <horstretch>0</horstretch> diff --git a/src/plugins/qtsupport/qtversionmanager.cpp b/src/plugins/qtsupport/qtversionmanager.cpp index c5f00e96189..2ca6c3a1237 100644 --- a/src/plugins/qtsupport/qtversionmanager.cpp +++ b/src/plugins/qtsupport/qtversionmanager.cpp @@ -265,8 +265,7 @@ void QtVersionManager::updateFromInstaller(bool emitSignal) if (log().isDebugEnabled()) { qCDebug(log) << "======= Existing Qt versions ======="; for (QtVersion *version : qAsConst(m_versions)) { - qCDebug(log) << version->queryToolFilePath().toUserOutput() - << "id:" <<version->uniqueId(); + qCDebug(log) << version->qmakeFilePath().toUserOutput() << "id:"<<version->uniqueId(); qCDebug(log) << " autodetection source:" << version->detectionSource(); qCDebug(log) << ""; } @@ -342,8 +341,7 @@ void QtVersionManager::updateFromInstaller(bool emitSignal) if (log().isDebugEnabled()) { qCDebug(log) << "======= Before removing outdated sdk versions ======="; for (QtVersion *version : qAsConst(m_versions)) { - qCDebug(log) << version->queryToolFilePath().toUserOutput() - << "id:" << version->uniqueId(); + qCDebug(log) << version->qmakeFilePath().toUserOutput() << "id:" << version->uniqueId(); qCDebug(log) << " autodetection source:" << version->detectionSource(); qCDebug(log) << ""; } @@ -362,8 +360,7 @@ void QtVersionManager::updateFromInstaller(bool emitSignal) if (log().isDebugEnabled()) { qCDebug(log)<< "======= End result ======="; for (QtVersion *version : qAsConst(m_versions)) { - qCDebug(log) << version->queryToolFilePath().toUserOutput() - << "id:" << version->uniqueId(); + qCDebug(log) << version->qmakeFilePath().toUserOutput() << "id:" << version->uniqueId(); qCDebug(log) << " autodetection source:" << version->detectionSource(); qCDebug(log) << ""; } @@ -404,20 +401,14 @@ static QList<QByteArray> runQtChooser(const QString &qtchooser, const QStringLis } // Asks qtchooser for the qmake path of a given version -// TODO: Extend to qtpaths if qtchooser is also used for Qt 6 static QString qmakePath(const QString &qtchooser, const QString &version) { const QList<QByteArray> outputs = runQtChooser(qtchooser, {QStringLiteral("-qt=%1").arg(version), QStringLiteral("-print-env")}); - // Exemplary output of "qtchooser -qt=qt5-x86_64-linux-gnu -print-env": - // QT_SELECT="qt5-x86_64-linux-gnu" - // QTTOOLDIR="/usr/lib/qt5/bin" - // QTLIBDIR="/usr/lib/x86_64-linux-gnu" - const QByteArray qtToolDirPrefix("QTTOOLDIR=\""); for (const QByteArray &output : outputs) { - if (output.startsWith(qtToolDirPrefix)) { - QByteArray withoutVarName = output.mid(qtToolDirPrefix.size()); // remove QTTOOLDIR=" + if (output.startsWith("QTTOOLDIR=\"")) { + QByteArray withoutVarName = output.mid(11); // remove QTTOOLDIR=" withoutVarName.chop(1); // remove trailing quote return QStandardPaths::findExecutable(QStringLiteral("qmake"), QStringList() << QString::fromLocal8Bit(withoutVarName)); @@ -433,15 +424,6 @@ static FilePaths gatherQmakePathsFromQtChooser() return FilePaths(); const QList<QByteArray> versions = runQtChooser(qtchooser, QStringList("-l")); - // Exemplary output of "qtchooser -l": - // 4 - // 5 - // default - // qt4-x86_64-linux-gnu - // qt4 - // qt5-x86_64-linux-gnu - // qt5 - // "" QSet<FilePath> foundQMakes; for (const QByteArray &version : versions) { FilePath possibleQMake = FilePath::fromString( @@ -454,20 +436,19 @@ static FilePaths gatherQmakePathsFromQtChooser() static void findSystemQt() { - FilePaths systemQueryTools + FilePaths systemQMakes = BuildableHelperLibrary::findQtsInEnvironment(Environment::systemEnvironment()); - systemQueryTools.append(gatherQmakePathsFromQtChooser()); - for (const FilePath &queryToolPath : qAsConst(systemQueryTools)) { - if (BuildableHelperLibrary::isQtChooser(queryToolPath)) + systemQMakes.append(gatherQmakePathsFromQtChooser()); + for (const FilePath &qmakePath : qAsConst(systemQMakes)) { + if (BuildableHelperLibrary::isQtChooser(qmakePath)) continue; - const auto isSameQueryTool = [queryToolPath](const QtVersion *version) { + const auto isSameQmake = [qmakePath](const QtVersion *version) { return Environment::systemEnvironment(). - isSameExecutable(queryToolPath.toString(), - version->queryToolFilePath().toString()); + isSameExecutable(qmakePath.toString(), version->qmakeFilePath().toString()); }; - if (contains(m_versions, isSameQueryTool)) + if (contains(m_versions, isSameQmake)) continue; - QtVersion *version = QtVersionFactory::createQtVersionFromQueryToolPath(queryToolPath, + QtVersion *version = QtVersionFactory::createQtVersionFromQMakePath(qmakePath, false, "PATH"); if (version) diff --git a/src/plugins/remotelinux/makeinstallstep.cpp b/src/plugins/remotelinux/makeinstallstep.cpp index 90b292d47af..08a14ed7dab 100644 --- a/src/plugins/remotelinux/makeinstallstep.cpp +++ b/src/plugins/remotelinux/makeinstallstep.cpp @@ -67,7 +67,8 @@ MakeInstallStep::MakeInstallStep(BuildStepList *parent, Id id) : MakeStep(parent jobCountAspect()->setVisible(false); disabledForSubdirsAspect()->setVisible(false); - const auto makeAspect = addAspect<ExecutableAspect>(parent->target()); + const auto makeAspect = addAspect<ExecutableAspect>(parent->target(), + ExecutableAspect::BuildDevice); makeAspect->setId(MakeAspectId); makeAspect->setSettingsKey(MakeAspectId); makeAspect->setDisplayStyle(StringAspect::PathChooserDisplay); diff --git a/src/plugins/remotelinux/remotelinuxcustomrunconfiguration.cpp b/src/plugins/remotelinux/remotelinuxcustomrunconfiguration.cpp index fe704f0705b..38668ae1b54 100644 --- a/src/plugins/remotelinux/remotelinuxcustomrunconfiguration.cpp +++ b/src/plugins/remotelinux/remotelinuxcustomrunconfiguration.cpp @@ -59,7 +59,7 @@ RemoteLinuxCustomRunConfiguration::RemoteLinuxCustomRunConfiguration(Target *tar { auto envAspect = addAspect<RemoteLinuxEnvironmentAspect>(target); - auto exeAspect = addAspect<ExecutableAspect>(target); + auto exeAspect = addAspect<ExecutableAspect>(target, ExecutableAspect::RunDevice); exeAspect->setSettingsKey("RemoteLinux.CustomRunConfig.RemoteExecutable"); exeAspect->setLabelText(tr("Remote executable:")); exeAspect->setDisplayStyle(StringAspect::LineEditDisplay); diff --git a/src/plugins/remotelinux/remotelinuxrunconfiguration.cpp b/src/plugins/remotelinux/remotelinuxrunconfiguration.cpp index cc026da4db1..14f95365613 100644 --- a/src/plugins/remotelinux/remotelinuxrunconfiguration.cpp +++ b/src/plugins/remotelinux/remotelinuxrunconfiguration.cpp @@ -59,7 +59,7 @@ RemoteLinuxRunConfiguration::RemoteLinuxRunConfiguration(Target *target, Id id) { auto envAspect = addAspect<RemoteLinuxEnvironmentAspect>(target); - auto exeAspect = addAspect<ExecutableAspect>(target); + auto exeAspect = addAspect<ExecutableAspect>(target, ExecutableAspect::RunDevice); exeAspect->setLabelText(tr("Executable on device:")); exeAspect->setPlaceHolderText(tr("Remote path not set")); exeAspect->makeOverridable("RemoteLinux.RunConfig.AlternateRemoteExecutable", diff --git a/src/plugins/studiowelcome/examplecheckout.cpp b/src/plugins/studiowelcome/examplecheckout.cpp index b69c66db623..a5f69514db9 100644 --- a/src/plugins/studiowelcome/examplecheckout.cpp +++ b/src/plugins/studiowelcome/examplecheckout.cpp @@ -57,6 +57,12 @@ using namespace Utils; +static bool enableDownload() +{ + const QString lastQDSVersionEntry = "QML/Designer/EnableWelcomePageDownload"; + return Core::ICore::settings()->value(lastQDSVersionEntry, false).toBool(); +} + void ExampleCheckout::registerTypes() { static bool once = []() { @@ -186,6 +192,12 @@ bool FileDownloader::available() const void FileDownloader::probeUrl() { + if (!enableDownload()) { + m_available = false; + emit availableChanged(); + return; + } + auto request = QNetworkRequest(m_url); request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::UserVerifiedRedirectPolicy); @@ -448,6 +460,13 @@ DataModelDownloader::DataModelDownloader(QObject * /* parent */) void DataModelDownloader::start() { + + if (!enableDownload()) { + m_available = false; + emit availableChanged(); + return; + } + m_fileDownloader.setUrl(QUrl::fromUserInput( "https://download.qt.io/learning/examples/qtdesignstudio/dataImports.zip")); |