From a850b1b866a5dfbaffdcf26fa7816c5a41305bbf Mon Sep 17 00:00:00 2001 From: Samuel Ghinet Date: Tue, 9 Nov 2021 18:58:15 +0200 Subject: [PATCH] Implement the New Project creation wizard for QDS Task-number: QDS-4490 Change-Id: Ie8073e8838ec14a7f11ad972acc6fca4456adf58 Reviewed-by: Alessandro Portale Reviewed-by: Qt CI Bot --- .../newprojectdialog/NewProjectDialog.qml | 192 ++++++++ .../newprojectdialog/image/style-basic.png | Bin 0 -> 10544 bytes .../newprojectdialog/image/style-default.png | Bin 0 -> 4603 bytes .../newprojectdialog/image/style-error.png | Bin 0 -> 1310 bytes .../newprojectdialog/image/style-fusion.png | Bin 0 -> 9161 bytes .../newprojectdialog/image/style-imagine.png | Bin 0 -> 10792 bytes .../newprojectdialog/image/style-macos.png | Bin 0 -> 4600 bytes .../image/style-material_dark.png | Bin 0 -> 9703 bytes .../image/style-material_light.png | Bin 0 -> 10683 bytes .../image/style-universal_dark.png | Bin 0 -> 9786 bytes .../image/style-universal_light.png | Bin 0 -> 10742 bytes .../image/style-universal_system.png | Bin 0 -> 9786 bytes .../imports/NewProjectDialog/Details.qml | 453 ++++++++++++++++++ .../imports/NewProjectDialog/DialogValues.qml | 83 ++++ .../NewProjectDialog/NewProjectView.qml | 198 ++++++++ .../imports/NewProjectDialog/Styles.qml | 183 +++++++ .../imports/NewProjectDialog/qmldir | 4 + .../imports/ProjectType/DefaultProject.qml | 48 ++ .../imports/ProjectType/qmldir | 1 + .../imports/StudioControls/Section.qml | 3 + src/plugins/CMakeLists.txt | 2 +- src/plugins/coreplugin/icore.cpp | 27 +- src/plugins/coreplugin/icore.h | 2 - src/plugins/coreplugin/mainwindow.cpp | 11 +- .../jsonwizard/jsonprojectpage.h | 3 +- src/plugins/studiowelcome/CMakeLists.txt | 10 +- src/plugins/studiowelcome/createproject.cpp | 77 +++ src/plugins/studiowelcome/createproject.h | 77 +++ .../newprojectdialogimageprovider.cpp | 99 ++++ .../newprojectdialogimageprovider.h | 50 ++ src/plugins/studiowelcome/newprojectmodel.cpp | 106 ++++ src/plugins/studiowelcome/newprojectmodel.h | 145 ++++++ src/plugins/studiowelcome/qdsnewdialog.cpp | 343 +++++++++++++ src/plugins/studiowelcome/qdsnewdialog.h | 170 +++++++ src/plugins/studiowelcome/screensizemodel.h | 111 +++++ src/plugins/studiowelcome/studiowelcome.pro | 10 + src/plugins/studiowelcome/studiowelcome.qbs | 10 + .../studiowelcome/studiowelcomeplugin.cpp | 5 + src/plugins/studiowelcome/stylemodel.cpp | 130 +++++ src/plugins/studiowelcome/stylemodel.h | 96 ++++ src/plugins/studiowelcome/wizardfactories.cpp | 113 +++++ src/plugins/studiowelcome/wizardfactories.h | 66 +++ src/plugins/studiowelcome/wizardhandler.cpp | 249 ++++++++++ src/plugins/studiowelcome/wizardhandler.h | 96 ++++ 44 files changed, 3164 insertions(+), 9 deletions(-) create mode 100644 share/qtcreator/qmldesigner/newprojectdialog/NewProjectDialog.qml create mode 100644 share/qtcreator/qmldesigner/newprojectdialog/image/style-basic.png create mode 100644 share/qtcreator/qmldesigner/newprojectdialog/image/style-default.png create mode 100644 share/qtcreator/qmldesigner/newprojectdialog/image/style-error.png create mode 100644 share/qtcreator/qmldesigner/newprojectdialog/image/style-fusion.png create mode 100644 share/qtcreator/qmldesigner/newprojectdialog/image/style-imagine.png create mode 100644 share/qtcreator/qmldesigner/newprojectdialog/image/style-macos.png create mode 100644 share/qtcreator/qmldesigner/newprojectdialog/image/style-material_dark.png create mode 100644 share/qtcreator/qmldesigner/newprojectdialog/image/style-material_light.png create mode 100644 share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_dark.png create mode 100644 share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_light.png create mode 100644 share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_system.png create mode 100644 share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Details.qml create mode 100644 share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/DialogValues.qml create mode 100644 share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/NewProjectView.qml create mode 100644 share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Styles.qml create mode 100644 share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/qmldir create mode 100644 share/qtcreator/qmldesigner/newprojectdialog/imports/ProjectType/DefaultProject.qml create mode 100644 share/qtcreator/qmldesigner/newprojectdialog/imports/ProjectType/qmldir create mode 100644 src/plugins/studiowelcome/createproject.cpp create mode 100644 src/plugins/studiowelcome/createproject.h create mode 100644 src/plugins/studiowelcome/newprojectdialogimageprovider.cpp create mode 100644 src/plugins/studiowelcome/newprojectdialogimageprovider.h create mode 100644 src/plugins/studiowelcome/newprojectmodel.cpp create mode 100644 src/plugins/studiowelcome/newprojectmodel.h create mode 100644 src/plugins/studiowelcome/qdsnewdialog.cpp create mode 100644 src/plugins/studiowelcome/qdsnewdialog.h create mode 100644 src/plugins/studiowelcome/screensizemodel.h create mode 100644 src/plugins/studiowelcome/stylemodel.cpp create mode 100644 src/plugins/studiowelcome/stylemodel.h create mode 100644 src/plugins/studiowelcome/wizardfactories.cpp create mode 100644 src/plugins/studiowelcome/wizardfactories.h create mode 100644 src/plugins/studiowelcome/wizardhandler.cpp create mode 100644 src/plugins/studiowelcome/wizardhandler.h diff --git a/share/qtcreator/qmldesigner/newprojectdialog/NewProjectDialog.qml b/share/qtcreator/qmldesigner/newprojectdialog/NewProjectDialog.qml new file mode 100644 index 00000000000..86234bf5bae --- /dev/null +++ b/share/qtcreator/qmldesigner/newprojectdialog/NewProjectDialog.qml @@ -0,0 +1,192 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +import QtQuick.Window + +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls +import StudioTheme as StudioTheme +import StudioControls as SC + +import NewProjectDialog + +Item { + width: DialogValues.dialogWidth + height: DialogValues.dialogHeight + + Rectangle { // the main dialog panel + anchors.fill: parent + color: DialogValues.darkPaneColor + + ColumnLayout { + anchors.fill: parent + + Layout.alignment: Qt.AlignHCenter + spacing: 0 + + Item { // Header Item + Layout.fillWidth: true + implicitHeight: 218 + + Column { + anchors.fill: parent + + Item { width: parent.width; height: 74 } // spacer + + Text { + text: qsTr("Welcome to Qt Design Studio. Let's Create Something Wonderful!") + font.pixelSize: 32 + width: parent.width + height: 47 + lineHeight: 49 + lineHeightMode: Text.FixedHeight + color: DialogValues.textColor + horizontalAlignment: Text.AlignHCenter + } + + Item { width: parent.width; height: 11 } // spacer + + Text { + width: parent.width + text: qsTr("Get started by selecting from Presets or start from empty screen. You may also include your design file.") + color: DialogValues.textColor + font.pixelSize: DialogValues.paneTitlePixelSize + lineHeight: DialogValues.paneTitleLineHeight + lineHeightMode: Text.FixedHeight + horizontalAlignment: Text.AlignHCenter + } + } + } // Header Item + + Item { // Content Item + Layout.fillWidth: true + Layout.fillHeight: true + + RowLayout { + x: 35 + width: parent.width - 70 + height: parent.height + spacing: 0 + + Rectangle { // Left pane + color: DialogValues.lightPaneColor + Layout.fillWidth: true + Layout.fillHeight: true + Layout.minimumWidth: 379 // figured out this number visually + Layout.minimumHeight: 326 // figured out this number visually + + Column { + x: DialogValues.defaultPadding // left padding + width: parent.width - DialogValues.defaultPadding * 2 // right padding + height: parent.height + + Text { + text: qsTr("Presets") + width: parent.width + font.weight: Font.DemiBold + font.pixelSize: DialogValues.paneTitlePixelSize + lineHeight: DialogValues.paneTitleLineHeight + lineHeightMode: Text.FixedHeight + color: DialogValues.textColor + } + + NewProjectView { + id: projectViewId + x: 10 // left padding + width: parent.width - 64 // right padding + height: DialogValues.projectViewHeight + loader: projectDetailsLoader + } + + Item { height: 5; width: parent.width } + + Text { + id: descriptionText + text: dialogBox.projectDescription + font.pixelSize: DialogValues.defaultPixelSize + lineHeight: DialogValues.defaultLineHeight + lineHeightMode: Text.FixedHeight + leftPadding: 14 + width: projectViewId.width + color: DialogValues.textColor + wrapMode: Text.WordWrap + maximumLineCount: 4 + elide: Text.ElideRight + } + } + } // Left pane + + Loader { + id: projectDetailsLoader + // we need to specify width because the loaded item needs to use parent sizes + width: DialogValues.loadedPanesWidth + Layout.fillHeight: true + source: "" + } + } // RowLayout + } //Content Item + + Item { // Footer + implicitHeight: DialogValues.footerHeight + implicitWidth: parent.width + RowLayout { + anchors.fill: parent + spacing: DialogValues.defaultPadding + + Item { Layout.fillWidth: true } + + SC.AbstractButton { + implicitWidth: DialogValues.dialogButtonWidth + width: DialogValues.dialogButtonWidth + visible: true + buttonIcon: qsTr("Cancel") + iconSize: DialogValues.defaultPixelSize + iconFont: StudioTheme.Constants.font + + onClicked: { + dialogBox.reject(); + } + } + + SC.AbstractButton { + implicitWidth: DialogValues.dialogButtonWidth + width: DialogValues.dialogButtonWidth + visible: true + buttonIcon: qsTr("Create") + iconSize: DialogValues.defaultPixelSize + enabled: dialogBox.fieldsValid + iconFont: StudioTheme.Constants.font + + onClicked: { + dialogBox.accept(); + } + } + Item { implicitWidth: 35 - DialogValues.defaultPadding } + } // RowLayout + } // Footer + } // ColumnLayout + } // Rectangle +} diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-basic.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-basic.png new file mode 100644 index 0000000000000000000000000000000000000000..53d03e476b4068441abae0a9422ae041e399d43c GIT binary patch literal 10544 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 literal 0 HcmV?d00001 diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-error.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-error.png new file mode 100644 index 0000000000000000000000000000000000000000..aeb03a574ed4dae6ea2122bb598c7806d20db008 GIT binary patch literal 1310 zcmeAS@N?(olHy`uVBq!ia0y~yU|7t+z;J_unSp^}L-^ti3=E7*0(?ST4}t*$0|O%? zBNG!7Gcz*_3kxeND;padJ3BiE2L~r7CpR}Y4-XG7FE2kozo4L?kdTnDu&{`Th^VNj zxVX54goKool(e+8jEsz|tgM`zoPvUaqN1X*va*VbimIxrnwpxHmX@}*wvLXDuCA`W zzP^EhfuW(Hk&%(Hv9XDXiK(fng@uKsrKPpCwVj=vgM)*kqob3Ple4q4o12@vySs;n zho`5fkB^V9udlzqe_&u>P*6}vNJwaCXhcLrWMpJiR8(|ybWBW4Y;0^|Vq#KKQgU)~ zYHDg)T3SX%Ms{{~etv#oVPR2GQE_o`X=!OiMMY(0WmQ#Gb#--peSKqNV^dR8b8~Y` zOG{f@TW4oyS65eecXv-uPj7E;e}Dgk2@@txoH%LHq{)*fPnj}h`t<2DX3Us5bLQ;X zv**m2Gk5OX`Sa&5Sg>H>!i9?$FJ7`_$swQBY1)oa$QS-W=a zx^?R|Y}l}IF1vhZu{TIuTbtax#U42@xQZh^?JpC_S~9H@h&VkcihraQVKnAEL~Me zNhvVmaoCskfFiMgUhQ7{&P#2-V)yIaR%1(Z=;d#|?b4~S#IW}9^Z+OA3CEu7yzlZd z(B<)THTI2mtr>qp9xFUMtF@qT!xV%?$ zR^ct%U9L%8X>+vAj&v-Nygyy?(MDgB$3-^;w6BYt*->>tp!=EVnHd&29Xpk|(tNf` zEc&7~!?5``@2)Dz}fBnH$bJX8bK>?L|rBb34o*=N>h#v!2p= zS@rNS?R64@;SP^8`iy&cwH6faJ>bk4_J z$0L~2bG}IQFOt0fw4!JEg`T-`i%Oa#gNM?XhWnf)^^+xo zr^Y3nlbN=$zTIe>)|A5J_0xA$bDplqZa1zopr04)tUg#Z8m literal 0 HcmV?d00001 diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-fusion.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-fusion.png new file mode 100644 index 0000000000000000000000000000000000000000..882256b30d48596d171bc48eb14b33d135a312d0 GIT binary patch literal 9161 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 DaLU~g literal 0 HcmV?d00001 diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-material_dark.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-material_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..53247a422fdd8c56355e7a2d5d616054de54e448 GIT binary patch literal 9703 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 M)78&qol`;+0E$dF2LJ#7 literal 0 HcmV?d00001 diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-material_light.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-material_light.png new file mode 100644 index 0000000000000000000000000000000000000000..63c6b7b79f0d38d099bd9d7132d63d9be9694af8 GIT binary patch literal 10683 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 C*%yca literal 0 HcmV?d00001 diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_dark.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..fc21300336ea48e5d43acc825a6e4563a780aac8 GIT binary patch literal 9786 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 literal 0 HcmV?d00001 diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_light.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_light.png new file mode 100644 index 0000000000000000000000000000000000000000..735219f0bb68983bf48e63d2d6ce57b33ddd3793 GIT binary patch literal 10742 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 literal 0 HcmV?d00001 diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_system.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_system.png new file mode 100644 index 0000000000000000000000000000000000000000..fc21300336ea48e5d43acc825a6e4563a780aac8 GIT binary patch literal 9786 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 literal 0 HcmV?d00001 diff --git a/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Details.qml b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Details.qml new file mode 100644 index 00000000000..c7ed3ec8d64 --- /dev/null +++ b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Details.qml @@ -0,0 +1,453 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +import QtQuick.Window +import QtQuick.Controls + +import QtQuick +import QtQuick.Layouts +import StudioControls as SC +import StudioTheme as StudioTheme + +Item { + width: DialogValues.detailsPaneWidth + + Component.onCompleted: { + dialogBox.detailsLoaded = true; + } + + Component.onDestruction: { + dialogBox.detailsLoaded = false; + } + + Rectangle { + color: DialogValues.darkPaneColor + anchors.fill: parent + + Item { + x: DialogValues.detailsPanePadding // left padding + width: parent.width - DialogValues.detailsPanePadding * 2 // right padding + + Column { + anchors.fill: parent + spacing: DialogValues.defaultPadding + + Text { + text: qsTr("Details") + width: parent.width; + font.weight: Font.DemiBold + font.pixelSize: DialogValues.paneTitlePixelSize + lineHeight: DialogValues.paneTitleLineHeight + lineHeightMode: Text.FixedHeight + color: DialogValues.textColor + } + + SC.TextField { + id: projectNameTextField + actionIndicatorVisible: false + translationIndicatorVisible: false + text: dialogBox.projectName + width: parent.width + color: DialogValues.textColor + selectByMouse: true + + font.pixelSize: DialogValues.paneTitlePixelSize + } + + Binding { + target: dialogBox + property: "projectName" + value: projectNameTextField.text + } + + Item { width: parent.width; height: DialogValues.narrowSpacing(11) } + + RowLayout { // Project location + width: parent.width + + SC.TextField { + Layout.fillWidth: true + id: projectLocationTextField + actionIndicatorVisible: false + translationIndicatorVisible: false + text: dialogBox.projectLocation + color: DialogValues.textColor + selectByMouse: true + font.pixelSize: DialogValues.defaultPixelSize + } + + Binding { + target: dialogBox + property: "projectLocation" + value: projectLocationTextField.text + } + + SC.AbstractButton { + implicitWidth: 30 + iconSize: 20 + visible: true + buttonIcon: "…" + iconFont: StudioTheme.Constants.font + + onClicked: { + var newLocation = dialogBox.chooseProjectLocation() + if (newLocation) + projectLocationTextField.text = newLocation + } + } // SC.AbstractButton + } // Project location RowLayout + + Item { width: parent.width; height: DialogValues.narrowSpacing(7) } + + RowLayout { // StatusMessage + width: parent.width + spacing: 0 + + Image { + id: statusIcon + asynchronous: false + } + + Text { + id: statusMessage + text: dialogBox.statusMessage + font.pixelSize: DialogValues.defaultPixelSize + lineHeight: DialogValues.defaultLineHeight + lineHeightMode: Text.FixedHeight + color: DialogValues.textColor + wrapMode: Text.Wrap + elide: Text.ElideRight + maximumLineCount: 3 + Layout.fillWidth: true + + states: [ + State { + name: "warning" + when: dialogBox.statusType === "warning" + PropertyChanges { + target: statusMessage + color: DialogValues.textWarning + } + PropertyChanges { + target: statusIcon + source: "image://newprojectdialog_library/status-warning" + } + }, + + State { + name: "error" + when: dialogBox.statusType === "error" + PropertyChanges { + target: statusMessage + color: DialogValues.textError + } + PropertyChanges { + target: statusIcon + source: "image://newprojectdialog_library/status-error" + } + } + ] + } // Text + } // RowLayout + + SC.CheckBox { + id: defaultLocationCheckbox + actionIndicatorVisible: false + text: qsTr("Use as default project location") + checked: false + font.pixelSize: DialogValues.defaultPixelSize + } + + Binding { + target: dialogBox + property: "saveAsDefaultLocation" + value: defaultLocationCheckbox.checked + } + + Rectangle { width: parent.width; height: 1; color: DialogValues.dividerlineColor } + + SC.ComboBox { // Screen Size ComboBox + id: screenSizeComboBox + actionIndicatorVisible: false + currentIndex: 1 + model: screenSizeModel + textRole: "display" + width: parent.width + font.pixelSize: DialogValues.defaultPixelSize + + onActivated: (index) => { + // NOTE: item 0 is activated when the screenSizeModel is reset + dialogBox.setScreenSizeIndex(index); + + var r = screenSizeModel.screenSizes(index); + widthTextField.text = r.width; + heightTextField.text = r.height; + } + + Connections { + target: screenSizeModel + function onModelReset() { + screenSizeComboBox.activated(screenSizeComboBox.currentIndex) + } + } + } // Screen Size ComboBox + + GridLayout { // orientation + width + height + width: parent.width + height: 85 + + columns: 4 + rows: 2 + + columnSpacing: 10 + rowSpacing: 10 + + // header items + Text { + text: qsTr("Width") + font.pixelSize: DialogValues.defaultPixelSize + lineHeight: DialogValues.defaultLineHeight + lineHeightMode: Text.FixedHeight + color: DialogValues.textColor + } + + Text { + text: qsTr("Height") + font.pixelSize: DialogValues.defaultPixelSize + lineHeight: DialogValues.defaultLineHeight + lineHeightMode: Text.FixedHeight + color: DialogValues.textColor + } + + Item { Layout.fillWidth: true } + + Text { + text: qsTr("Orientation") + font.pixelSize: DialogValues.defaultPixelSize + lineHeight: DialogValues.defaultLineHeight + lineHeightMode: Text.FixedHeight + color: DialogValues.textColor + } + + // content items + SC.TextField { + id: widthTextField + actionIndicatorVisible: false + translationIndicatorVisible: false + implicitWidth: 50 + color: DialogValues.textColor + selectByMouse: true + validator: IntValidator { bottom: 1; top: 100000; } + font.pixelSize: DialogValues.defaultPixelSize + + onTextChanged: { + var height = heightTextField.text ? parseInt(heightTextField.text) : 0 + var width = text ? parseInt(text) : 0 + + if (width >= height) + orientationButton.setHorizontal() + else + orientationButton.setVertical() + } + } // Width Text Field + + Binding { + target: dialogBox + property: "customWidth" + value: widthTextField.text + } + + SC.TextField { + id: heightTextField + actionIndicatorVisible: false + translationIndicatorVisible: false + implicitWidth: 50 + color: DialogValues.textColor + selectByMouse: true + validator: IntValidator { bottom: 1; top: 100000; } + font.pixelSize: DialogValues.defaultPixelSize + + onTextChanged: { + var height = text ? parseInt(text) : 0 + var width = widthTextField.text ? parseInt(widthTextField.text) : 0 + + if (width >= height) + orientationButton.setHorizontal() + else + orientationButton.setVertical() + } + } // Height Text Field + + Binding { + target: dialogBox + property: "customHeight" + value: heightTextField.text + } + + Item { Layout.fillWidth: true } + + Button { + id: orientationButton + implicitWidth: 100 + implicitHeight: 50 + + checked: false + hoverEnabled: false + background: Rectangle { + width: parent.width + height: parent.height + color: "transparent" + + Row { + Item { + width: orientationButton.width / 2 + height: orientationButton.height + Rectangle { + id: horizontalBar + color: "white" + width: parent.width + height: orientationButton.height / 2 + anchors.verticalCenter: parent.verticalCenter + } + } + + Item { + width: orientationButton.width / 4 + height: orientationButton.height + } + + Rectangle { + id: verticalBar + width: orientationButton.width / 4 + height: orientationButton.height + color: "white" + } + } + } + + onClicked: { + if (widthTextField.text && heightTextField.text) { + [widthTextField.text, heightTextField.text] = [heightTextField.text, widthTextField.text]; + + checked = !checked + } + } + + function setHorizontal() { + checked = false + horizontalBar.color = DialogValues.textColorInteraction + verticalBar.color = "white" + } + + function setVertical() { + checked = true + horizontalBar.color = "white" + verticalBar.color = DialogValues.textColorInteraction + } + } // Orientation button + + } // GridLayout: orientation + width + height + + Rectangle { width: parent.width; height: 1; color: DialogValues.dividerlineColor } + + SC.Section { + width: parent.width + caption: qsTr("Advanced") + captionPixelSize: DialogValues.defaultPixelSize + captionColor: DialogValues.darkPaneColor + captionTextColor: DialogValues.textColor + leftPadding: 0 + expanded: true + visible: dialogBox.haveVirtualKeyboard || dialogBox.haveTargetQtVersion + + Column { + spacing: DialogValues.defaultPadding + width: parent.width + + /* We need a spacer of -10 in order to have actual 18px spacing between + * section bottom and the checkbox. Otherwise, with Column spacing set to + * 18, without a spacer, the default space to the first item would be 10, + * for some reason. */ + Item { width: parent.width; height: -10 } + + SC.CheckBox { + id: useQtVirtualKeyboard + actionIndicatorVisible: false + text: qsTr("Use Qt Virtual Keyboard") + font.pixelSize: DialogValues.defaultPixelSize + checked: dialogBox.useVirtualKeyboard + visible: dialogBox.haveVirtualKeyboard + } + + RowLayout { // Target Qt Version + width: parent.width + visible: dialogBox.haveTargetQtVersion + + Text { + text: "Target Qt Version:" + font.pixelSize: DialogValues.defaultPixelSize + lineHeight: DialogValues.defaultLineHeight + lineHeightMode: Text.FixedHeight + color: DialogValues.textColor + } + + SC.ComboBox { // Target Qt Version ComboBox + id: qtVersionComboBox + actionIndicatorVisible: false + implicitWidth: 70 + Layout.alignment: Qt.AlignRight + currentIndex: 1 + font.pixelSize: DialogValues.defaultPixelSize + + model: ListModel { + ListElement { + name: "Qt 5" + } + ListElement { + name: "Qt 6" + } + } + + width: parent.width + + onActivated: (index) => { + dialogBox.setTargetQtVersion(index) + } + } // Target Qt Version ComboBox + + } // RowLayout + } // Column + } // SC.Section + + Binding { + target: dialogBox + property: "useVirtualKeyboard" + value: useQtVirtualKeyboard.checked + } + + } // Column + } // Item + } +} diff --git a/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/DialogValues.qml b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/DialogValues.qml new file mode 100644 index 00000000000..5bcfadaa785 --- /dev/null +++ b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/DialogValues.qml @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +pragma Singleton +import QtQml + +import StudioTheme as StudioTheme + +QtObject { + readonly property int dialogWidth: 1522 + readonly property int dialogHeight: 994 + readonly property int projectViewMinimumWidth: 600 + readonly property int projectViewMinimumHeight: projectViewHeight + readonly property int dialogContentHeight: projectViewHeight + 300 // i.e. dialog without header and footer + readonly property int loadedPanesWidth: detailsPaneWidth + stylesPaneWidth + readonly property int detailsPaneWidth: 330 + detailsPanePadding * 2 + readonly property int stylesPaneWidth: styleImageWidth + stylesPanePadding * 2 + styleImageBorderWidth * 2 // i.e. 240px + readonly property int detailsPanePadding: 18 + readonly property int stylesPanePadding: 18 + readonly property int defaultPadding: 18 + + readonly property int styleImageWidth: 200 + readonly property int styleImageBorderWidth: 2 + readonly property int footerHeight: 73 + readonly property int projectItemWidth: 144 + readonly property int projectItemHeight: 144 + readonly property int projectViewHeight: projectItemHeight * 2 + projectViewHeaderHeight + readonly property int projectViewHeaderHeight: 38 + + readonly property int dialogButtonWidth: 100 + + readonly property int loadedPanesHeight: dialogContentHeight + readonly property int detailsPaneHeight: dialogContentHeight + + readonly property string darkPaneColor: StudioTheme.Values.themeBackgroundColorNormal + readonly property string lightPaneColor: StudioTheme.Values.themeBackgroundColorAlternate + + readonly property string textColor: StudioTheme.Values.themeTabInactiveText + readonly property string textColorInteraction: StudioTheme.Values.themeInteraction + readonly property string dividerlineColor: StudioTheme.Values.themeTextColorDisabled + readonly property string textError: StudioTheme.Values.themeError + readonly property string textWarning: StudioTheme.Values.themeWarning + + readonly property real defaultPixelSize: 14 + readonly property real defaultLineHeight: 21 + readonly property real viewHeaderPixelSize: 16 + readonly property real viewHeaderLineHeight: 24 + readonly property real paneTitlePixelSize: 18 + readonly property real paneTitleLineHeight: 27 + + // for a spacer item + function narrowSpacing(value, layoutSpacing = DialogValues.defaultPadding) { + /* e.g. if we want narrow spacing value = 11, then for the spacer item residing inside a + layout with spacing set to 18, we need to realize the fact that by adding the spacer + item, we already have 18 * 2 spacing added implicitly (i.e. spacing before the spacer + item and spacing after it). So we have to subtract 2 x layout spacing before setting + our own, narrower, spacing. + */ + return -layoutSpacing -layoutSpacing + value + } +} diff --git a/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/NewProjectView.qml b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/NewProjectView.qml new file mode 100644 index 00000000000..049b955420c --- /dev/null +++ b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/NewProjectView.qml @@ -0,0 +1,198 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +import QtQuick.Window +import QtQuick.Controls + +import QtQuick +import QtQuick.Layouts +import StudioTheme as StudioTheme + +GridView { + id: projectView + + required property Item loader + + header: TabBar { + id: tabBar + width: parent.width + height: DialogValues.projectViewHeaderHeight + + background: Rectangle { + color: DialogValues.lightPaneColor + } + + Repeater { + model: categoryModel + + TabButton { + padding: 0 + + width: headerText.contentWidth + 36 + + background: Item { // TabButton background + Rectangle { // bottom strip + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + width: headerText.contentWidth + height: 6 + radius: 10 + color: tabBar.currentIndex === index ? DialogValues.textColorInteraction + : "transparent" + } + } // TabButton background + + implicitHeight: headerText.height + DialogValues.defaultPadding - 7 + + contentItem: Item { + Column { + anchors.fill: parent + + Text { + id: headerText + color: tabBar.currentIndex == index ? DialogValues.textColorInteraction + : DialogValues.textColor + text: name + width: parent.width + font.weight: Font.DemiBold + font.pixelSize: DialogValues.viewHeaderPixelSize + lineHeight: DialogValues.viewHeaderLineHeight + lineHeightMode: Text.FixedHeight + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + + Item { width: parent.width; height: 11; } + } // Column + } // Item + + onClicked: { + projectModel.setPage(index) + projectView.currentIndex = 0 + projectView.currentIndexChanged() + } + } // TabButton + } // Repeater + } // Header - TabBar + + cellWidth: DialogValues.projectItemWidth + cellHeight: DialogValues.projectItemHeight + + boundsBehavior: Flickable.StopAtBounds + + children: [ + Rectangle { + color: DialogValues.darkPaneColor + anchors.fill: parent + z: -1 + } + ] + + model: projectModel + + // called by onModelReset and when user clicks on an item, or when the header item is changed. + onCurrentIndexChanged: { + dialogBox.selectedProject = projectView.currentIndex + var source = dialogBox.currentProjectQmlPath() + loader.source = source + } + + Connections { + target: projectModel + + // called when data is set (setWizardFactories) + function onModelReset() { + currentIndex = 0 + currentIndexChanged() + } + } + + delegate: ItemDelegate { + id: delegate + + width: DialogValues.projectItemWidth + height: DialogValues.projectItemHeight + + function fontIconCode(index) { + var code = projectModel.fontIconCode(index) + return code ? code : StudioTheme.Constants.wizardsUnknown + } + + Column { + width: parent.width + height: parent.height + + Label { + id: projectTypeIcon + text: fontIconCode(index) + color: DialogValues.textColor + width: parent.width + height: DialogValues.projectItemHeight / 2 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignBottom + renderType: Text.NativeRendering + font.pixelSize: 65 + font.family: StudioTheme.Constants.iconFont.family + } + + Text { + id: projectTypeLabel + color: DialogValues.textColor + + text: name + font.pixelSize: DialogValues.defaultPixelSize + lineHeight: DialogValues.defaultLineHeight + lineHeightMode: Text.FixedHeight + width: parent.width + height: DialogValues.projectItemHeight / 2 + wrapMode: Text.Wrap + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignTop + } + } // Column + + MouseArea { + anchors.fill: parent + onClicked: { + delegate.GridView.view.currentIndex = index + } + } + + states: [ + State { + when: delegate.GridView.isCurrentItem + PropertyChanges { + target: projectTypeLabel + color: DialogValues.textColorInteraction + } + + PropertyChanges { + target: projectTypeIcon + color: DialogValues.textColorInteraction + } + } // State + ] + } // ItemDelegate +} // GridView diff --git a/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Styles.qml b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Styles.qml new file mode 100644 index 00000000000..a1ef6696f3a --- /dev/null +++ b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Styles.qml @@ -0,0 +1,183 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +import QtQuick.Window +import QtQuick.Controls + +import QtQuick +import QtQuick.Layouts + +import StudioControls as SC + +Item { + width: DialogValues.stylesPaneWidth + + Component.onCompleted: { + dialogBox.stylesLoaded = true; + + /* + * TODO: roleNames is called before the backend model (in the proxy class StyleModel) is + * loaded, which may be buggy. But I found no way to force refresh the model, so as to + * reload the role names afterwards. setting styleModel.dynamicRoles doesn't appear to do + * anything. + */ + } + + Component.onDestruction: { + dialogBox.stylesLoaded = false; + } + + Rectangle { + color: DialogValues.lightPaneColor + anchors.fill: parent + + Item { + x: DialogValues.stylesPanePadding // left padding + width: parent.width - DialogValues.stylesPanePadding * 2 // right padding + height: parent.height + + ColumnLayout { + anchors.fill: parent + spacing: 5 + + Text { + id: styleTitleText + text: qsTr("Style") + width: parent.width; + font.weight: Font.DemiBold + font.pixelSize: DialogValues.paneTitlePixelSize + lineHeight: DialogValues.paneTitleLineHeight + lineHeightMode: Text.FixedHeight + color: DialogValues.textColor + + function refresh() { + text = qsTr("Style") + " (" + styleModel.rowCount() + ")" + } + } + + SC.ComboBox { // Style Filter ComboBox + actionIndicatorVisible: false + currentIndex: 0 + textRole: "text" + valueRole: "value" + font.pixelSize: DialogValues.defaultPixelSize + + model: ListModel { + ListElement { text: qsTr("All"); value: "all" } + ListElement { text: qsTr("Light"); value: "light" } + ListElement { text: qsTr("Dark"); value: "dark" } + } + + implicitWidth: parent.width + + onActivated: (index) => { + styleModel.filter(currentValue.toLowerCase()); + styleTitleText.refresh(); + } + } // Style Filter ComboBox + + ListView { + id: stylesList + Layout.fillWidth: true + Layout.fillHeight: true + clip: true + model: styleModel + + focus: true + boundsBehavior: Flickable.StopAtBounds + + highlightFollowsCurrentItem: false + + onCurrentIndexChanged: { + if (styleModel.rowCount() > 0) + dialogBox.styleIndex = stylesList.currentIndex; + } + + delegate: ItemDelegate { + id: delegateId + height: styleImage.height + DialogValues.styleImageBorderWidth + styleText.height + 1 + width: stylesList.width + + Rectangle { + anchors.fill: parent + color: DialogValues.lightPaneColor + + Column { + spacing: 0 + anchors.fill: parent + + Rectangle { + border.color: index == stylesList.currentIndex ? DialogValues.textColorInteraction : "transparent" + border.width: index == stylesList.currentIndex ? DialogValues.styleImageBorderWidth : 0 + color: "transparent" + width: parent.width + height: parent.height - styleText.height + + Image { + id: styleImage + asynchronous: false + source: "image://newprojectdialog_library/" + styleModel.iconId(model.index) + width: 200 + height: 262 + x: DialogValues.styleImageBorderWidth + y: DialogValues.styleImageBorderWidth + } + } // Rectangle + + Text { + id: styleText + text: model.display + font.pixelSize: DialogValues.defaultPixelSize + lineHeight: DialogValues.defaultLineHeight + height: 18 + lineHeightMode: Text.FixedHeight + horizontalAlignment: Text.AlignHCenter + width: parent.width + color: DialogValues.textColor + } + } // Column + } // Rectangle + + MouseArea { + anchors.fill: parent + onClicked: { + stylesList.currentIndex = index + } + } + } + + Connections { + target: styleModel + function onModelReset() { + stylesList.currentIndex = dialogBox.styleIndex; + stylesList.currentIndexChanged(); + styleTitleText.refresh(); + } + } + } // ListView + } // ColumnLayout + } // Parent Item + } // Rectangle +} diff --git a/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/qmldir b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/qmldir new file mode 100644 index 00000000000..d7c1562164f --- /dev/null +++ b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/qmldir @@ -0,0 +1,4 @@ +singleton DialogValues 1.0 DialogValues.qml +Details 1.0 Details.qml +Styles 1.0 Styles.qml +NewProjectView 1.0 NewProjectView.qml diff --git a/share/qtcreator/qmldesigner/newprojectdialog/imports/ProjectType/DefaultProject.qml b/share/qtcreator/qmldesigner/newprojectdialog/imports/ProjectType/DefaultProject.qml new file mode 100644 index 00000000000..05bc5fff042 --- /dev/null +++ b/share/qtcreator/qmldesigner/newprojectdialog/imports/ProjectType/DefaultProject.qml @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +import QtQuick.Window +import QtQuick.Controls + +import QtQuick +import QtQuick.Layouts + +import newprojectdialog + +Item { + anchors.fill: parent + + Row { + anchors.fill: parent + + Details { + height: parent.height + } + + Styles { + height: parent.height + } + } +} diff --git a/share/qtcreator/qmldesigner/newprojectdialog/imports/ProjectType/qmldir b/share/qtcreator/qmldesigner/newprojectdialog/imports/ProjectType/qmldir new file mode 100644 index 00000000000..6f3c69e9d42 --- /dev/null +++ b/share/qtcreator/qmldesigner/newprojectdialog/imports/ProjectType/qmldir @@ -0,0 +1 @@ +DefaultProject 1.0 DefaultProject.qml diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Section.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Section.qml index 23ee5615700..a6dbcfe11da 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Section.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Section.qml @@ -30,6 +30,9 @@ import StudioTheme 1.0 as StudioTheme Item { id: section property alias caption: label.text + property alias captionPixelSize: label.font.pixelSize + property alias captionColor: header.color + property alias captionTextColor: label.color property int leftPadding: 8 property int topPadding: 4 property int rightPadding: 0 diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt index e61b8ab4338..800cd3b775d 100644 --- a/src/plugins/CMakeLists.txt +++ b/src/plugins/CMakeLists.txt @@ -57,7 +57,6 @@ add_subdirectory(scxmleditor) add_subdirectory(subversion) add_subdirectory(compilationdatabaseprojectmanager) add_subdirectory(languageclient) -add_subdirectory(studiowelcome) # Level 6: add_subdirectory(cmakeprojectmanager) @@ -93,6 +92,7 @@ if (WIN32 AND CMAKE_CXX_COMPILER_ID MATCHES "Clang") set(qmldesigner_builddir ${PROJECT_BINARY_DIR}/qmldsgnr) endif() add_subdirectory(qmldesigner ${qmldesigner_builddir}) +add_subdirectory(studiowelcome) add_subdirectory(qnx) add_subdirectory(webassembly) add_subdirectory(mcusupport) diff --git a/src/plugins/coreplugin/icore.cpp b/src/plugins/coreplugin/icore.cpp index c118533426a..82a715f59e2 100644 --- a/src/plugins/coreplugin/icore.cpp +++ b/src/plugins/coreplugin/icore.cpp @@ -32,6 +32,7 @@ #include #include +#include #include #include @@ -165,9 +166,13 @@ namespace Core { // The Core Singleton static ICore *m_instance = nullptr; static MainWindow *m_mainwindow = nullptr; -std::function ICore::m_newDialogFactory = [](QWidget *parent) { + +static NewDialog *defaultDialogFactory(QWidget *parent) +{ return new NewDialogWidget(parent); -}; +} + +static std::function m_newDialogFactory = defaultDialogFactory; /*! Returns the pointer to the instance. Only use for connecting to signals. @@ -253,7 +258,23 @@ void ICore::showNewItemDialog(const QString &title, const QVariantMap &extraVariables) { QTC_ASSERT(!isNewItemDialogRunning(), return); - NewDialog *newDialog = ICore::m_newDialogFactory(dialogParent()); + + /* This is a workaround for QDS: In QDS, we currently have a "New Project" dialog box but we do + * not also have a "New file" dialog box (yet). Therefore, when requested to add a new file, we + * need to use QtCreator's dialog box. In QDS, if `factories` contains project wizard factories + * (even though it may contain file wizard factories as well), then we consider it to be a + * request for "New Project". Otherwise, if we only have file wizard factories, we defer to + * QtCreator's dialog and request "New File" + */ + auto dialogFactory = m_newDialogFactory; + bool haveProjectWizards = Utils::anyOf(factories, [](IWizardFactory *f) { + return f->kind() == IWizardFactory::ProjectWizard; + }); + + if (!haveProjectWizards) + dialogFactory = defaultDialogFactory; + + NewDialog *newDialog = dialogFactory(dialogParent()); connect(newDialog->widget(), &QObject::destroyed, m_instance, &ICore::updateNewItemDialogState); newDialog->setWizardFactories(factories, defaultLocation, extraVariables); newDialog->setWindowTitle(title); diff --git a/src/plugins/coreplugin/icore.h b/src/plugins/coreplugin/icore.h index 589cf49765e..93cf5c71f17 100644 --- a/src/plugins/coreplugin/icore.h +++ b/src/plugins/coreplugin/icore.h @@ -180,8 +180,6 @@ public: private: static void updateNewItemDialogState(); - - static std::function m_newDialogFactory; }; } // namespace Core diff --git a/src/plugins/coreplugin/mainwindow.cpp b/src/plugins/coreplugin/mainwindow.cpp index 59ba9b08abc..83d5a257a57 100644 --- a/src/plugins/coreplugin/mainwindow.cpp +++ b/src/plugins/coreplugin/mainwindow.cpp @@ -102,6 +102,14 @@ namespace Internal { enum { debugMainWindow = 0 }; +static bool isQtDesignStudio() +{ + QSettings *settings = Core::ICore::settings(); + const QString qdsStandaloneEntry = "QML/Designer/StandAloneMode"; //entry from qml settings + + return settings->value(qdsStandaloneEntry, false).toBool(); +} + MainWindow::MainWindow() : AppMainWindow() , m_coreImpl(new ICore(this)) @@ -519,7 +527,8 @@ void MainWindow::registerDefaultActions() // New File Action QIcon icon = QIcon::fromTheme(QLatin1String("document-new"), Utils::Icons::NEWFILE.icon()); - m_newAction = new QAction(icon, tr("&New File or Project..."), this); + QString newActionText = isQtDesignStudio() ? tr("&New Project...") : tr("&New File or Project..."); + m_newAction = new QAction(icon, newActionText, this); cmd = ActionManager::registerAction(m_newAction, Constants::NEW); cmd->setDefaultKeySequence(QKeySequence::New); mfile->addAction(cmd, Constants::G_FILE_NEW); diff --git a/src/plugins/projectexplorer/jsonwizard/jsonprojectpage.h b/src/plugins/projectexplorer/jsonwizard/jsonprojectpage.h index b362b988945..ced13950aac 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonprojectpage.h +++ b/src/plugins/projectexplorer/jsonwizard/jsonprojectpage.h @@ -25,12 +25,13 @@ #pragma once +#include "../projectexplorer_export.h" #include namespace ProjectExplorer { // Documentation inside. -class JsonProjectPage : public Utils::ProjectIntroPage +class PROJECTEXPLORER_EXPORT JsonProjectPage : public Utils::ProjectIntroPage { Q_OBJECT diff --git a/src/plugins/studiowelcome/CMakeLists.txt b/src/plugins/studiowelcome/CMakeLists.txt index 2ae3bdcc9a0..3d290d6486b 100644 --- a/src/plugins/studiowelcome/CMakeLists.txt +++ b/src/plugins/studiowelcome/CMakeLists.txt @@ -1,12 +1,20 @@ add_qtc_plugin(StudioWelcome CONDITION TARGET Qt5::QuickWidgets DEPENDS Qt5::QuickWidgets - PLUGIN_DEPENDS Core ProjectExplorer QtSupport + PLUGIN_DEPENDS Core ProjectExplorer QtSupport QmlDesigner DEFINES STUDIO_QML_PATH="${CMAKE_CURRENT_SOURCE_DIR}/qml/" SOURCES studiowelcomeplugin.cpp studiowelcomeplugin.h + newprojectdialogimageprovider.cpp newprojectdialogimageprovider.h + newprojectmodel.cpp newprojectmodel.h examplecheckout.cpp examplecheckout.h studiowelcome_global.h + qdsnewdialog.cpp qdsnewdialog.h + wizardfactories.cpp wizardfactories.h + createproject.cpp createproject.h + wizardhandler.cpp wizardhandler.h + screensizemodel.h + stylemodel.h stylemodel.cpp studiowelcome.qrc "${PROJECT_SOURCE_DIR}/src/share/3rdparty/studiofonts/studiofonts.qrc" EXTRA_TRANSLATIONS diff --git a/src/plugins/studiowelcome/createproject.cpp b/src/plugins/studiowelcome/createproject.cpp new file mode 100644 index 00000000000..1b6dd93e9d7 --- /dev/null +++ b/src/plugins/studiowelcome/createproject.cpp @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "createproject.h" + +#include + +#include +#include + +using namespace StudioWelcome; + +void CreateProject::execute() +{ + m_wizard.run([&](QWizardPage *page) { + if (auto *p = dynamic_cast(page)) + processProjectPage(p); + else if (auto *p = dynamic_cast(page)) + processFieldPage(p); + }); +} + +void CreateProject::processProjectPage(ProjectExplorer::JsonProjectPage *page) +{ + page->setProjectName(m_projectName); + page->setFilePath(m_projectLocation); + + page->setUseAsDefaultPath(m_saveAsDefaultLocation); + page->fieldsUpdated(); +} + +void CreateProject::processFieldPage(ProjectExplorer::JsonFieldPage *page) +{ + if (page->jsonField("ScreenFactor")) + m_wizard.setScreenSizeIndex(m_screenSizeIndex); + + if (page->jsonField("TargetQtVersion") && m_targetQtVersionIndex > -1) + m_wizard.setTargetQtVersionIndex(m_targetQtVersionIndex); + + if (page->jsonField("ControlsStyle")) + m_wizard.setStyleIndex(m_styleIndex); + + if (page->jsonField("UseVirtualKeyboard")) + m_wizard.setUseVirtualKeyboard(m_useVirtualKeyboard); + + auto widthField = dynamic_cast(page->jsonField("CustomScreenWidth")); + auto heightField = dynamic_cast(page->jsonField("CustomScreenHeight")); + + if (widthField && heightField) { + if (!m_customWidth.isEmpty() && !m_customHeight.isEmpty()) { + widthField->setText(m_customWidth); + heightField->setText(m_customHeight); + } + } +} diff --git a/src/plugins/studiowelcome/createproject.h b/src/plugins/studiowelcome/createproject.h new file mode 100644 index 00000000000..9709bbee30e --- /dev/null +++ b/src/plugins/studiowelcome/createproject.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "wizardhandler.h" + +namespace ProjectExplorer { +class JsonProjectPage; +} + +namespace StudioWelcome { + +class CreateProject +{ +public: + CreateProject(WizardHandler &wizard): m_wizard{wizard} {} + + CreateProject &withName(const QString &name) { m_projectName = name; return *this; } + CreateProject &atLocation(const Utils::FilePath &location) { m_projectLocation = location; return *this; } + CreateProject &withScreenSizes(int screenSizeIndex, const QString &customWidth, const QString &customHeight) + { + m_screenSizeIndex = screenSizeIndex; + m_customWidth = customWidth; + m_customHeight = customHeight; + return *this; + } + + CreateProject &withStyle(int styleIndex) { m_styleIndex = styleIndex; return *this; } + CreateProject &useQtVirtualKeyboard(bool value) { m_useVirtualKeyboard = value; return *this; } + CreateProject &saveAsDefaultLocation(bool value) { m_saveAsDefaultLocation = value; return *this; } + CreateProject &withTargetQtVersion(int targetQtVersionIndex) + { m_targetQtVersionIndex = targetQtVersionIndex; return *this; } + + void execute(); + +private: + void processProjectPage(ProjectExplorer::JsonProjectPage *page); + void processFieldPage(ProjectExplorer::JsonFieldPage *page); + +private: + WizardHandler &m_wizard; + + QString m_projectName; + Utils::FilePath m_projectLocation; + int m_screenSizeIndex = -1; + QString m_customWidth; + QString m_customHeight; + int m_styleIndex = -1; + bool m_useVirtualKeyboard = false; + bool m_saveAsDefaultLocation = false; + int m_targetQtVersionIndex = -1; +}; + +} // StudioWelcome diff --git a/src/plugins/studiowelcome/newprojectdialogimageprovider.cpp b/src/plugins/studiowelcome/newprojectdialogimageprovider.cpp new file mode 100644 index 00000000000..2c7e454f5b0 --- /dev/null +++ b/src/plugins/studiowelcome/newprojectdialogimageprovider.cpp @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "newprojectdialogimageprovider.h" + +#include +#include +#include + +namespace StudioWelcome { + +namespace Internal { + +NewProjectDialogImageProvider::NewProjectDialogImageProvider() + : QQuickImageProvider(QQuickImageProvider::Pixmap) +{} + +QPixmap NewProjectDialogImageProvider::invalidStyleIcon() +{ + QString iconPath = Core::ICore::resourcePath("qmldesigner/newprojectdialog/image/style-error.png").toString(); + QString file = Utils::StyleHelper::dpiSpecificImageFile(iconPath); + return QPixmap{file}; +} + +QPixmap NewProjectDialogImageProvider::requestStatusPixmap(const QString &id, QSize *size, const QSize &requestedSize) +{ + QPixmap pixmap; + + if (id == "status-warning") { + static const QPixmap warning = Utils::Icons::WARNING.pixmap(); + pixmap = warning; + } else if (id == "status-error") { + static const QPixmap error = Utils::Icons::CRITICAL.pixmap(); + pixmap = error; + } + + if (requestedSize.isValid()) + return pixmap.scaled(requestedSize); + + return pixmap; +} + +QPixmap NewProjectDialogImageProvider::requestStylePixmap(const QString &id, QSize *size, const QSize &requestedSize) +{ + QString realPath = Core::ICore::resourcePath("qmldesigner/newprojectdialog/image/" + id).toString(); + + QPixmap pixmap{realPath}; + + if (size) { + size->setWidth(pixmap.width()); + size->setHeight(pixmap.height()); + } + + if (pixmap.isNull()) + pixmap = invalidStyleIcon(); + + if (requestedSize.isValid()) + return pixmap.scaled(requestedSize); + + return pixmap; +} + +QPixmap NewProjectDialogImageProvider::requestPixmap(const QString &id, QSize *size, const QSize &requestedSize) +{ + if (id.startsWith("style-")) + return requestStylePixmap(id, size, requestedSize); + + if (id.startsWith("status-")) + return requestStatusPixmap(id, size, requestedSize); + + return QPixmap{}; +} + +} // namespace Internal + +} // namespace StudioWelcome + diff --git a/src/plugins/studiowelcome/newprojectdialogimageprovider.h b/src/plugins/studiowelcome/newprojectdialogimageprovider.h new file mode 100644 index 00000000000..f149d082c21 --- /dev/null +++ b/src/plugins/studiowelcome/newprojectdialogimageprovider.h @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include + +namespace StudioWelcome { + +namespace Internal { + +class NewProjectDialogImageProvider : public QQuickImageProvider +{ +public: + NewProjectDialogImageProvider(); + + QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize) override; + +private: + QPixmap requestStatusPixmap(const QString &id, QSize *size, const QSize &requestedSize); + QPixmap requestStylePixmap(const QString &id, QSize *size, const QSize &requestedSize); + + static QPixmap invalidStyleIcon(); +}; + +} // namespace Internal + +} // namespace StudioWelcome diff --git a/src/plugins/studiowelcome/newprojectmodel.cpp b/src/plugins/studiowelcome/newprojectmodel.cpp new file mode 100644 index 00000000000..07589a4c041 --- /dev/null +++ b/src/plugins/studiowelcome/newprojectmodel.cpp @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "newprojectmodel.h" + +using namespace StudioWelcome; + +/****************** BaseNewProjectModel ******************/ + +BaseNewProjectModel::BaseNewProjectModel(QObject *parent) + : QAbstractListModel(parent) +{} + +QHash BaseNewProjectModel::roleNames() const +{ + QHash roleNames; + roleNames[Qt::UserRole] = "name"; + return roleNames; +} + +void BaseNewProjectModel::setProjects(const ProjectsByCategory &projectsByCategory) +{ + beginResetModel(); + + for (auto &[id, category] : projectsByCategory) { + m_categories.push_back(category.name); + m_projects.push_back(category.items); + } + + endResetModel(); +} + +/****************** NewProjectCategoryModel ******************/ + +NewProjectCategoryModel::NewProjectCategoryModel(QObject *parent) + : BaseNewProjectModel(parent) +{} + +int NewProjectCategoryModel::rowCount(const QModelIndex &) const +{ + return static_cast(categories().size()); +} + +QVariant NewProjectCategoryModel::data(const QModelIndex &index, int role) const +{ + return categories().at(index.row()); +} + +/****************** NewProjectModel ******************/ + +NewProjectModel::NewProjectModel(QObject *parent) + : BaseNewProjectModel(parent) +{} + +int NewProjectModel::rowCount(const QModelIndex &) const +{ + if (projects().empty()) + return 0; + + return static_cast(projectsOfCurrentCategory().size()); +} + +QVariant NewProjectModel::data(const QModelIndex &index, int role) const +{ + return projectsOfCurrentCategory().at(index.row()).name; +} + +void NewProjectModel::setPage(int index) +{ + beginResetModel(); + + m_page = static_cast(index); + + endResetModel(); +} + +QString NewProjectModel::fontIconCode(int index) const +{ + Utils::optional projectItem = project(index); + if (!projectItem) + return ""; + + return projectItem->fontIconCode; +} diff --git a/src/plugins/studiowelcome/newprojectmodel.h b/src/plugins/studiowelcome/newprojectmodel.h new file mode 100644 index 00000000000..9e6cdd157b9 --- /dev/null +++ b/src/plugins/studiowelcome/newprojectmodel.h @@ -0,0 +1,145 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include +#include + +#include +#include + +namespace Utils { +class Wizard; +} + +namespace StudioWelcome { + +struct ProjectItem +{ + QString name; + QString categoryId; + QString description; + QUrl qmlPath; + QString fontIconCode; + std::function create; +}; + +inline QDebug &operator<<(QDebug &d, const ProjectItem &item) +{ + d << "name=" << item.name; + d << "; category = " << item.categoryId; + + return d; +} + +struct ProjectCategory +{ + QString id; + QString name; + std::vector items; +}; + +inline QDebug &operator<<(QDebug &d, const ProjectCategory &cat) +{ + d << "id=" << cat.id; + d << "; name=" << cat.name; + d << "; items=" << cat.items; + + return d; +} + +using ProjectsByCategory = std::map; + +/****************** BaseNewProjectModel ******************/ + +class BaseNewProjectModel : public QAbstractListModel +{ + using ProjectItems = std::vector>; + using Categories = std::vector; + +public: + explicit BaseNewProjectModel(QObject *parent = nullptr); + QHash roleNames() const override; + void setProjects(const ProjectsByCategory &projects); + +protected: + const ProjectItems &projects() const { return m_projects; } + const Categories &categories() const { return m_categories; } + +private: + ProjectItems m_projects; + Categories m_categories; +}; + +/****************** NewProjectCategoryModel ******************/ + +class NewProjectCategoryModel : public BaseNewProjectModel +{ +public: + explicit NewProjectCategoryModel(QObject *parent = nullptr); + int rowCount(const QModelIndex &parent) const override; + QVariant data(const QModelIndex &index, int role) const override; +}; + +/****************** NewProjectModel ******************/ + +class NewProjectModel : public BaseNewProjectModel +{ + Q_OBJECT +public: + explicit NewProjectModel(QObject *parent = nullptr); + int rowCount(const QModelIndex &parent) const override; + QVariant data(const QModelIndex &index, int role) const override; + + Q_INVOKABLE void setPage(int index); // called from QML when view's header item is clicked + Q_INVOKABLE QString fontIconCode(int index) const; + + int page() const { return static_cast(m_page); } + + Utils::optional project(size_t selection) const + { + if (projects().empty()) + return {}; + + if (m_page < projects().size()) { + const std::vector projectsOfCategory = projects().at(m_page); + if (selection < projectsOfCategory.size()) + return projects().at(m_page).at(selection); + } + return {}; + } + + bool empty() const { return projects().empty(); } + +private: + const std::vector projectsOfCurrentCategory() const + { return projects().at(m_page); } + +private: + size_t m_page = 0; +}; + +} // namespace StudioWelcome diff --git a/src/plugins/studiowelcome/qdsnewdialog.cpp b/src/plugins/studiowelcome/qdsnewdialog.cpp new file mode 100644 index 00000000000..b031a083bcf --- /dev/null +++ b/src/plugins/studiowelcome/qdsnewdialog.cpp @@ -0,0 +1,343 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include +#include + +#include "qdsnewdialog.h" + +#include +#include +#include +#include + +#include "createproject.h" +#include "wizardfactories.h" +#include "newprojectdialogimageprovider.h" + +using namespace StudioWelcome; + +namespace { + +/* + * NOTE: copied from projectexplorer/jsonwizard/jsonprojectpage.h +*/ +QString uniqueProjectName(const QString &path) +{ + const QDir pathDir(path); + //: File path suggestion for a new project. If you choose + //: to translate it, make sure it is a valid path name without blanks + //: and using only ascii chars. + const QString prefix = QObject::tr("UntitledProject"); + + QString name = prefix; + int i = 0; + while (pathDir.exists(name)) + name = prefix + QString::number(++i); + + return name; +} + +} + +/***********************/ + +QdsNewDialog::QdsNewDialog(QWidget *parent) + : m_dialog{new QQuickWidget(parent)} + , m_categoryModel{new NewProjectCategoryModel(this)} + , m_projectModel{new NewProjectModel(this)} + , m_screenSizeModel{new ScreenSizeModel(this)} + , m_styleModel{new StyleModel(this)} +{ + setParent(m_dialog); + + m_dialog->rootContext()->setContextProperties(QVector{ + {{"categoryModel"}, QVariant::fromValue(m_categoryModel.data())}, + {{"projectModel"}, QVariant::fromValue(m_projectModel.data())}, + {{"screenSizeModel"}, QVariant::fromValue(m_screenSizeModel.data())}, + {{"styleModel"}, QVariant::fromValue(m_styleModel.data())}, + {{"dialogBox"}, QVariant::fromValue(this)}, + }); + + m_dialog->setResizeMode(QQuickWidget::SizeRootObjectToView); // SizeViewToRootObject + m_dialog->engine()->addImageProvider(QStringLiteral("newprojectdialog_library"), + new Internal::NewProjectDialogImageProvider()); + QmlDesigner::Theme::setupTheme(m_dialog->engine()); + m_dialog->engine()->addImportPath(Core::ICore::resourcePath("qmldesigner/propertyEditorQmlSources/imports").toString()); + m_dialog->engine()->addImportPath(Core::ICore::resourcePath("qmldesigner/newprojectdialog/imports").toString()); + QString sourcesPath = qmlPath(); + m_dialog->setSource(QUrl::fromLocalFile(sourcesPath)); + + m_dialog->setWindowModality(Qt::ApplicationModal); + m_dialog->setWindowFlags(Qt::Dialog); + m_dialog->setAttribute(Qt::WA_DeleteOnClose); + m_dialog->setMinimumSize(1155, 804); + + QObject::connect(&m_wizard, &WizardHandler::deletingWizard, this, &QdsNewDialog::onDeletingWizard); + QObject::connect(&m_wizard, &WizardHandler::wizardCreated, this, &QdsNewDialog::onWizardCreated); + QObject::connect(&m_wizard, &WizardHandler::statusMessageChanged, this, &QdsNewDialog::onStatusMessageChanged); + QObject::connect(&m_wizard, &WizardHandler::projectCanBeCreated, this, &QdsNewDialog::onProjectCanBeCreatedChanged); + + QObject::connect(&m_wizard, &WizardHandler::wizardCreationFailed, this, [this]() { + QMessageBox::critical(m_dialog, "New project", "Failed to initialize data"); + reject(); + delete this; + }); + + QObject::connect(m_styleModel.data(), &StyleModel::modelAboutToBeReset, this, [this]() { + this->m_qmlStyleIndex = -1; + }); +} + +void QdsNewDialog::onDeletingWizard() +{ + m_screenSizeModel->setBackendModel(nullptr); + m_qmlScreenSizeIndex = -1; + m_screenSizeModel->reset(); + + m_styleModel->setBackendModel(nullptr); + m_qmlStyleIndex = -1; +} + +void QdsNewDialog::setProjectName(const QString &name) +{ + m_qmlProjectName = name; + m_wizard.setProjectName(name); +} + +void QdsNewDialog::setProjectLocation(const QString &location) +{ + m_qmlProjectLocation = Utils::FilePath::fromString(QDir::toNativeSeparators(location)); + m_wizard.setProjectLocation(m_qmlProjectLocation); +} + +void QdsNewDialog::onStatusMessageChanged(Utils::InfoLabel::InfoType type, const QString &message) +{ + switch (type) { + case Utils::InfoLabel::Warning: + m_qmlStatusType = "warning"; + break; + case Utils::InfoLabel::Error: + m_qmlStatusType = "error"; + break; + default: + m_qmlStatusType = "normal"; + break; + } + + emit statusTypeChanged(); + + m_qmlStatusMessage = message; + emit statusMessageChanged(); +} + +void QdsNewDialog::onProjectCanBeCreatedChanged(bool value) +{ + if (m_qmlFieldsValid == value) + return; + + m_qmlFieldsValid = value; + + emit fieldsValidChanged(); +} + +void QdsNewDialog::onWizardCreated(QStandardItemModel *screenSizeModel, QStandardItemModel *styleModel) +{ + m_screenSizeModel->setBackendModel(screenSizeModel); + m_styleModel->setBackendModel(styleModel); + + if (m_qmlDetailsLoaded) { + m_screenSizeModel->reset(); + emit haveVirtualKeyboardChanged(); + emit haveTargetQtVersionChanged(); + + setProjectName(m_qmlProjectName); + setProjectLocation(m_qmlProjectLocation.toString()); + } + + if (m_qmlStylesLoaded) + m_styleModel->reset(); +} + +QString QdsNewDialog::currentProjectQmlPath() const +{ + if (!m_currentProject || m_currentProject->qmlPath.isEmpty()) + return ""; + + return m_currentProject->qmlPath.toString(); +} + +void QdsNewDialog::setScreenSizeIndex(int index) +{ + m_wizard.setScreenSizeIndex(index); + m_qmlScreenSizeIndex = index; +} + +void QdsNewDialog::setTargetQtVersion(int index) +{ + m_wizard.setTargetQtVersionIndex(index); + m_qmlTargetQtVersionIndex = index; +} + +void QdsNewDialog::setStyleIndex(int index) +{ + if (!m_qmlStylesLoaded) + return; + + if (index == -1) { + m_qmlStyleIndex = index; + return; + } + + m_qmlStyleIndex = index; + int actualIndex = m_styleModel->actualIndex(m_qmlStyleIndex); + QTC_ASSERT(actualIndex >= 0, return); + + m_wizard.setStyleIndex(actualIndex); +} + +int QdsNewDialog::getStyleIndex() const +{ + /** + * m_wizard.styleIndex property is the wizard's (backend's) value of the style index. + * The initial value (saved in the wizard.json) is read from there. Any subsequent reads of + * the style index should use m_styleIndex, which is the QML's style index property. Setting + * the style index should update both the m_styleIndex and the backend. In this regard, the + * QdsNewDialog's m_styleIndex acts as some kind of cache. + */ + + if (!m_qmlStylesLoaded) + return -1; + + if (m_qmlStyleIndex == -1) { + int actualIndex = m_wizard.styleIndex(); + // Not nice, get sets the property... m_qmlStyleIndex acts like a cache. + m_qmlStyleIndex = m_styleModel->filteredIndex(actualIndex); + return m_qmlStyleIndex; + } + + return m_styleModel->actualIndex(m_qmlStyleIndex); +} + +void QdsNewDialog::setWizardFactories(QList factories_, + const Utils::FilePath &defaultLocation, + const QVariantMap &) +{ + Utils::Id platform = Utils::Id::fromSetting("Desktop"); + + WizardFactories factories{factories_, m_dialog, platform}; + + m_categoryModel->setProjects(factories.projectsGroupedByCategory()); // calls model reset + m_projectModel->setProjects(factories.projectsGroupedByCategory()); // calls model reset + + if (m_qmlSelectedProject > -1) + setSelectedProject(m_qmlSelectedProject); + + if (factories.empty()) + return; // TODO: some message box? + + const Core::IWizardFactory *first = factories.front(); + Utils::FilePath projectLocation = first->runPath(defaultLocation); + + m_qmlProjectName = uniqueProjectName(projectLocation.toString()); + emit projectNameChanged(); // So that QML knows to update the field + + m_qmlProjectLocation = Utils::FilePath::fromString(QDir::toNativeSeparators(projectLocation.toString())); + emit projectLocationChanged(); // So that QML knows to update the field + + if (m_qmlDetailsLoaded) + m_screenSizeModel->reset(); + + if (m_qmlStylesLoaded) + m_styleModel->reset(); +} + +QString QdsNewDialog::qmlPath() const +{ + return Core::ICore::resourcePath("qmldesigner/newprojectdialog/NewProjectDialog.qml").toString(); +} + +void QdsNewDialog::showDialog() +{ + m_dialog->show(); +} + +bool QdsNewDialog::getHaveVirtualKeyboard() const +{ + return m_wizard.haveVirtualKeyboard(); +} + +bool QdsNewDialog::getHaveTargetQtVersion() const +{ + return m_wizard.haveTargetQtVersion(); +} + +void QdsNewDialog::accept() +{ + CreateProject create{m_wizard}; + + create.withName(m_qmlProjectName) + .atLocation(m_qmlProjectLocation) + .withScreenSizes(m_qmlScreenSizeIndex, m_qmlCustomWidth, m_qmlCustomHeight) + .withStyle(m_qmlStyleIndex) + .useQtVirtualKeyboard(m_qmlUseVirtualKeyboard) + .saveAsDefaultLocation(m_qmlSaveAsDefaultLocation) + .withTargetQtVersion(m_qmlTargetQtVersionIndex) + .execute(); + + m_dialog->close(); +} + +void QdsNewDialog::reject() +{ + m_screenSizeModel->setBackendModel(nullptr); + m_styleModel->setBackendModel(nullptr); + m_wizard.destroyWizard(); + + m_dialog->close(); +} + +QString QdsNewDialog::chooseProjectLocation() +{ + Utils::FilePath newPath = Utils::FileUtils::getExistingDirectory(m_dialog, tr("Choose Directory"), + m_qmlProjectLocation); + + return QDir::toNativeSeparators(newPath.toString()); +} + +void QdsNewDialog::setSelectedProject(int selection) +{ + if (m_qmlSelectedProject != selection || m_projectPage != m_projectModel->page()) { + m_qmlSelectedProject = selection; + + m_currentProject = m_projectModel->project(m_qmlSelectedProject); + if (m_currentProject) { + setProjectDescription(m_currentProject->description); + + m_projectPage = m_projectModel->page(); + m_wizard.reset(m_currentProject.value(), m_qmlSelectedProject, m_qmlProjectLocation); + } + } +} diff --git a/src/plugins/studiowelcome/qdsnewdialog.h b/src/plugins/studiowelcome/qdsnewdialog.h new file mode 100644 index 00000000000..ede50bc97a7 --- /dev/null +++ b/src/plugins/studiowelcome/qdsnewdialog.h @@ -0,0 +1,170 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include + +#include +#include +#include + +#include "wizardhandler.h" +#include "newprojectmodel.h" +#include "screensizemodel.h" +#include "stylemodel.h" + +QT_BEGIN_NAMESPACE +class QStandardItemModel; +QT_END_NAMESPACE + +namespace StudioWelcome { +class QdsNewDialog : public QObject, public Core::NewDialog +{ + Q_OBJECT + +public: + Q_PROPERTY(int selectedProject MEMBER m_qmlSelectedProject WRITE setSelectedProject) + Q_PROPERTY(QString projectName MEMBER m_qmlProjectName WRITE setProjectName NOTIFY projectNameChanged) + Q_PROPERTY(QString projectLocation MEMBER m_qmlProjectLocation READ projectLocation WRITE setProjectLocation NOTIFY projectLocationChanged) + Q_PROPERTY(QString projectDescription MEMBER m_qmlProjectDescription READ projectDescription WRITE setProjectDescription NOTIFY projectDescriptionChanged) + Q_PROPERTY(QString customWidth MEMBER m_qmlCustomWidth) + Q_PROPERTY(QString customHeight MEMBER m_qmlCustomHeight) + Q_PROPERTY(int styleIndex MEMBER m_qmlStyleIndex READ getStyleIndex WRITE setStyleIndex) + Q_PROPERTY(bool useVirtualKeyboard MEMBER m_qmlUseVirtualKeyboard READ getUseVirtualKeyboard WRITE setUseVirtualKeyboard NOTIFY useVirtualKeyboardChanged) + Q_PROPERTY(bool haveVirtualKeyboard MEMBER m_qmlHaveVirtualKeyboard READ getHaveVirtualKeyboard NOTIFY haveVirtualKeyboardChanged) + Q_PROPERTY(bool haveTargetQtVersion MEMBER m_qmlHaveTargetQtVersion READ getHaveTargetQtVersion NOTIFY haveTargetQtVersionChanged) + Q_PROPERTY(bool saveAsDefaultLocation MEMBER m_qmlSaveAsDefaultLocation WRITE setSaveAsDefaultLocation) + Q_PROPERTY(QString statusMessage MEMBER m_qmlStatusMessage READ getStatusMessage NOTIFY statusMessageChanged) + Q_PROPERTY(QString statusType MEMBER m_qmlStatusType READ getStatusType NOTIFY statusTypeChanged) + Q_PROPERTY(bool fieldsValid MEMBER m_qmlFieldsValid READ getFieldsValid NOTIFY fieldsValidChanged) + + Q_PROPERTY(bool detailsLoaded MEMBER m_qmlDetailsLoaded) + Q_PROPERTY(bool stylesLoaded MEMBER m_qmlStylesLoaded) + + Q_INVOKABLE QString currentProjectQmlPath() const; + Q_INVOKABLE void setScreenSizeIndex(int index); // called when ComboBox item is "activated" + Q_INVOKABLE void setTargetQtVersion(int index); + + Q_INVOKABLE QString chooseProjectLocation(); + + explicit QdsNewDialog(QWidget *parent); + + QWidget *widget() override { return m_dialog; } + + void setWizardFactories(QList factories, const Utils::FilePath &defaultLocation, + const QVariantMap &extraVariables) override; + void setWindowTitle(const QString &title) override { m_dialog->setWindowTitle(title); } + void showDialog() override; + void setSelectedProject(int selection); + + void setStyleIndex(int index); + int getStyleIndex() const; + void setUseVirtualKeyboard(bool value) { m_qmlUseVirtualKeyboard = value; } + bool getUseVirtualKeyboard() const { return m_qmlUseVirtualKeyboard; } + + bool getFieldsValid() const { return m_qmlFieldsValid; } + bool getHaveVirtualKeyboard() const; + bool getHaveTargetQtVersion() const; + + void setSaveAsDefaultLocation(bool value) { m_qmlSaveAsDefaultLocation = value; } + + QString getStatusMessage() const { return m_qmlStatusMessage; } + QString getStatusType() const { return m_qmlStatusType; } + +public slots: + void accept(); + void reject(); + +signals: + void projectNameChanged(); + void projectLocationChanged(); + void projectDescriptionChanged(); + void useVirtualKeyboardChanged(); + void haveVirtualKeyboardChanged(); + void haveTargetQtVersionChanged(); + void statusMessageChanged(); + void statusTypeChanged(); + void fieldsValidChanged(); + +private slots: + void onStatusMessageChanged(Utils::InfoLabel::InfoType type, const QString &message); + void onProjectCanBeCreatedChanged(bool value); + +private: + QString qmlPath() const; + + void setProjectName(const QString &name); + void setProjectLocation(const QString &location); + QString projectLocation() const { return m_qmlProjectLocation.toString(); } + + void setProjectDescription(const QString &description) + { + m_qmlProjectDescription = description; + emit projectDescriptionChanged(); + } + + QString projectDescription() const { return m_qmlProjectDescription; } + +private slots: + void onDeletingWizard(); + void onWizardCreated(QStandardItemModel *screenSizeModel, QStandardItemModel *styleModel); + +private: + QQuickWidget *m_dialog = nullptr; + QPointer m_categoryModel; + QPointer m_projectModel; + QPointer m_screenSizeModel; + QPointer m_styleModel; + QString m_qmlProjectName; + Utils::FilePath m_qmlProjectLocation; + QString m_qmlProjectDescription; + int m_qmlSelectedProject = -1; + int m_qmlScreenSizeIndex = -1; + int m_qmlTargetQtVersionIndex = -1; + // m_qmlStyleIndex is like a cache, so it needs to be updated on get() + mutable int m_qmlStyleIndex = -1; + bool m_qmlUseVirtualKeyboard = false; + bool m_qmlHaveVirtualKeyboard = false; + bool m_qmlHaveTargetQtVersion = false; + bool m_qmlSaveAsDefaultLocation = false; + bool m_qmlFieldsValid = false; + QString m_qmlStatusMessage; + QString m_qmlStatusType; + + int m_projectPage = -1; // i.e. the page in the Presets View + + QString m_qmlCustomWidth; + QString m_qmlCustomHeight; + + bool m_qmlDetailsLoaded = false; + bool m_qmlStylesLoaded = false; + + Utils::optional m_currentProject; + + WizardHandler m_wizard; +}; + +} //namespace StudioWelcome diff --git a/src/plugins/studiowelcome/screensizemodel.h b/src/plugins/studiowelcome/screensizemodel.h new file mode 100644 index 00000000000..e01f17295c5 --- /dev/null +++ b/src/plugins/studiowelcome/screensizemodel.h @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include +#include +#include + +class ScreenSizeModel : public QAbstractListModel +{ + Q_OBJECT + +public: + explicit ScreenSizeModel(QObject *parent = nullptr) + : QAbstractListModel(parent) + {} + + Q_INVOKABLE QSize screenSizes(int index) const + { + constexpr auto invalid = QSize{0, 0}; + if (!m_backendModel) + return invalid; + + auto *item = m_backendModel->item(index, 0); + // Matches strings like "1024 x 768" or "1080 x 1920 (FullHD)" + QRegularExpression re{R"__(^(\d+)\s*x\s*(\d+).*)__"}; + + if (!item) + return invalid; + + auto m = re.match(item->text()); + if (!m.hasMatch()) + return invalid; + + bool ok = false; + int width = m.captured(1).toInt(&ok); + if (!ok) + return invalid; + + int height = m.captured(2).toInt(&ok); + if (!ok) + return invalid; + + return QSize{width, height}; + } + + int rowCount(const QModelIndex &parent = QModelIndex()) const override + { + if (m_backendModel) + return m_backendModel->rowCount(); + + return 0; + } + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override + { + if (m_backendModel) { + auto *item = m_backendModel->item(index.row(), index.column()); + return item->text(); + } + + return ""; + } + + QHash roleNames() const override + { + if (m_backendModel) + return m_backendModel->roleNames(); + + QHash roleNames; + roleNames[Qt::UserRole] = "name"; + return roleNames; + } + + void reset() { + beginResetModel(); + endResetModel(); + } + + void setBackendModel(QStandardItemModel *model) + { + m_backendModel = model; + } + +private: + QStandardItemModel *m_backendModel = nullptr; +}; + diff --git a/src/plugins/studiowelcome/studiowelcome.pro b/src/plugins/studiowelcome/studiowelcome.pro index e2ccee8576f..3cdee86f789 100644 --- a/src/plugins/studiowelcome/studiowelcome.pro +++ b/src/plugins/studiowelcome/studiowelcome.pro @@ -12,10 +12,20 @@ DEFINES += STUDIO_QML_PATH=\\\"$$PWD/qml/\\\" HEADERS += \ studiowelcome_global.h \ studiowelcomeplugin.h \ + newprojectdialogimageprovider.h \ + qdsnewdialog.h \ + wizardfactories.h \ + createproject.h \ + newprojectmodel.h \ examplecheckout.h SOURCES += \ studiowelcomeplugin.cpp \ + qdsnewdialog.cpp \ + wizardfactories.cpp \ + createproject.cpp \ + newprojectdialogimageprovider.cpp \ + newprojectmodel.cpp \ examplecheckout.cpp OTHER_FILES += \ diff --git a/src/plugins/studiowelcome/studiowelcome.qbs b/src/plugins/studiowelcome/studiowelcome.qbs index f2bec88af22..c630d83f01c 100644 --- a/src/plugins/studiowelcome/studiowelcome.qbs +++ b/src/plugins/studiowelcome/studiowelcome.qbs @@ -17,8 +17,18 @@ QtcPlugin { "studiowelcome_global.h", "studiowelcomeplugin.h", "studiowelcomeplugin.cpp", + "qdsnewdialog.cpp", + "qdsnewdialog.h", + "wizardfactories.cpp", + "wizardfactories.h", + "createproject.cpp", + "createproject.h", + "newprojectmodel.cpp", + "newprojectmodel.h", "examplecheckout.h", "examplecheckout.cpp", + "newprojectdialogimageprovider.h", + "newprojectdialogimageprovider.cpp", "studiowelcome.qrc", ] diff --git a/src/plugins/studiowelcome/studiowelcomeplugin.cpp b/src/plugins/studiowelcome/studiowelcomeplugin.cpp index d1195675624..56ef7302842 100644 --- a/src/plugins/studiowelcome/studiowelcomeplugin.cpp +++ b/src/plugins/studiowelcome/studiowelcomeplugin.cpp @@ -26,6 +26,8 @@ #include "studiowelcomeplugin.h" #include "examplecheckout.h" +#include "qdsnewdialog.h" + #include #include #include @@ -368,6 +370,9 @@ void StudioWelcomePlugin::extensionsInitialized() s_view->setSource(QUrl("qrc:/qml/splashscreen/main.qml")); #endif + // disabled by default + Core::ICore::setNewDialogFactory([](QWidget *parent) { return new QdsNewDialog(parent); }); + QTC_ASSERT(s_view->rootObject(), qWarning() << "The StudioWelcomePlugin has a runtime depdendency on " "qt/qtquicktimeline."; diff --git a/src/plugins/studiowelcome/stylemodel.cpp b/src/plugins/studiowelcome/stylemodel.cpp new file mode 100644 index 00000000000..9aee4ff7d32 --- /dev/null +++ b/src/plugins/studiowelcome/stylemodel.cpp @@ -0,0 +1,130 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "stylemodel.h" + +#include "utils/algorithm.h" +#include "utils/qtcassert.h" + +#include + +StyleModel::StyleModel(QObject *parent) + : QAbstractListModel(parent) + , m_backendModel(nullptr) +{} + +QString StyleModel::iconId(int index) const +{ + if (!m_backendModel || index < 0) + return "style-error"; + + auto item = this->m_filteredItems.at(index); + QString styleName = item->text(); + QString id{"style-"}; + id += styleName.toLower().replace(' ', '_') + ".png"; + + return id; +} + +void StyleModel::filter(const QString &what) +{ + if (what.toLower() == "all") + m_filteredItems = this->filterItems(m_items, ""); + else if (what.toLower() == "light") + m_filteredItems = this->filterItems(m_items, "light"); + else if (what.toLower() == "dark") + m_filteredItems = this->filterItems(m_items, "dark"); + else + m_filteredItems.clear(); + + reset(); +} + +StyleModel::Items StyleModel::filterItems(const Items &items, const QString &kind) +{ + if (kind.isEmpty()) + return items; + + return Utils::filtered(items, [&kind](auto *item) { + QString pattern{"\\S "}; + pattern += kind; + + QRegularExpression re{pattern, QRegularExpression::CaseInsensitiveOption}; + return re.match(item->text()).hasMatch(); + }); +} + +int StyleModel::filteredIndex(int actualIndex) +{ + if (actualIndex < 0) + return actualIndex; + + QStandardItem *item = m_items.at(actualIndex); + // TODO: perhaps should add this kind of find to utils/algorithm.h + auto it = std::find(std::cbegin(m_filteredItems), std::cend(m_filteredItems), item); + if (it == std::cend(m_filteredItems)) + return -1; + + return std::distance(std::cbegin(m_filteredItems), it); +} + +int StyleModel::actualIndex(int filteredIndex) +{ + if (filteredIndex < 0) + return filteredIndex; + + QTC_ASSERT(filteredIndex < static_cast(m_filteredItems.size()), return -1); + + QStandardItem *item = m_filteredItems.at(filteredIndex); + auto it = std::find(std::cbegin(m_items), std::cend(m_items), item); + if (it == std::cend(m_items)) + return -1; + + auto result = std::distance(std::cbegin(m_items), it); + QTC_ASSERT(result >= 0, return -1); + QTC_ASSERT(result <= static_cast(m_items.size()), return -1); + + return result; +} + +void StyleModel::setBackendModel(QStandardItemModel *model) +{ + m_backendModel = model; + + if (m_backendModel) { + m_count = model->rowCount(); + m_roles = model->roleNames(); + m_items.clear(); + + for (int i = 0; i < m_count; ++i) + m_items.push_back(model->item(i, 0)); + + m_filteredItems = filterItems(m_items, ""); + } else { + m_count = 0; + m_items.clear(); + m_filteredItems.clear(); + } +} diff --git a/src/plugins/studiowelcome/stylemodel.h b/src/plugins/studiowelcome/stylemodel.h new file mode 100644 index 00000000000..6d6d09620d1 --- /dev/null +++ b/src/plugins/studiowelcome/stylemodel.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include +#include + +class StyleModel : public QAbstractListModel +{ + Q_OBJECT + +private: + using Items = std::vector; + +public: + explicit StyleModel(QObject *parent = nullptr); + + Q_INVOKABLE QString iconId(int index) const; + Q_INVOKABLE void filter(const QString &what = "all"); + + int rowCount(const QModelIndex &parent = QModelIndex()) const override + { + if (m_backendModel) + return static_cast(m_filteredItems.size()); + + return 0; + } + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override + { + if (m_backendModel) { + auto *item = m_filteredItems.at(index.row()); + return item->text(); + } + + return ""; + } + + QHash roleNames() const override + { + if (m_backendModel) + return m_roles; + + /** + * TODO: roleNames is called before the backend model is loaded, which may be buggy. But I + * found no way to force refresh the model, so as to reload the role names afterwards. + */ + + QHash roleNames; + roleNames[Qt::UserRole] = "display"; + return roleNames; + } + + void reset() + { + beginResetModel(); + endResetModel(); + } + + int filteredIndex(int actualIndex); + int actualIndex(int filteredIndex); + void setBackendModel(QStandardItemModel *model); + +private: + static Items filterItems(const Items &items, const QString &kind); + +private: + QStandardItemModel *m_backendModel; + Items m_items, m_filteredItems; + int m_count = -1; + QHash m_roles; +}; + diff --git a/src/plugins/studiowelcome/wizardfactories.cpp b/src/plugins/studiowelcome/wizardfactories.cpp new file mode 100644 index 00000000000..a7cb20b0c62 --- /dev/null +++ b/src/plugins/studiowelcome/wizardfactories.cpp @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include +#include +#include + +#include "wizardfactories.h" + +namespace { +// TODO: should be extern, check coreplugin/dialogs/newdialogwidget.cpp +const char BLACKLISTED_CATEGORIES_KEY[] = "Core/NewDialog/BlacklistedCategories"; +} + +using namespace StudioWelcome; + +WizardFactories::WizardFactories(QList &factories, QWidget *wizardParent, const Utils::Id &platform) + : m_wizardParent{wizardParent} + , m_platform{platform} + , m_factories{factories} +{ + QVariant value = Core::ICore::settings()->value(BLACKLISTED_CATEGORIES_KEY); + m_blacklist = Utils::Id::fromStringList(value.toStringList()); + + sortByCategoryAndId(); + filter(); + m_projectItems = makeProjectItemsGroupedByCategory(); +} + +void WizardFactories::sortByCategoryAndId() +{ + Utils::sort(m_factories, [](Core::IWizardFactory *lhs, Core::IWizardFactory *rhs) { + if (lhs->category() == rhs->category()) + return lhs->id().toString() < rhs->id().toString(); + else + return lhs->category() < rhs->category(); + }); +} + +void WizardFactories::filter() +{ + QList acceptedFactories; + // TODO: perhaps I could use Utils::filtered here. + std::copy_if(std::begin(m_factories), std::end(m_factories), std::back_inserter(acceptedFactories), + [&](auto *wizard) { + return wizard->isAvailable(m_platform) + && wizard->kind() == Core::IWizardFactory::ProjectWizard + && !m_blacklist.contains(Utils::Id::fromString(wizard->category())); + }); + + m_factories = acceptedFactories; +} + +ProjectItem WizardFactories::makeProjectItem(Core::IWizardFactory *f, QWidget *parent, + const Utils::Id &platform) +{ + using namespace std::placeholders; + + return { + /*.name =*/f->displayName(), + /*.categoryId =*/f->category(), + /*. description =*/f->description(), + /*.qmlPath =*/f->detailsPageQmlPath(), + /*.fontIconCode =*/f->fontIcondCode(), + /*.create =*/ std::bind(&Core::IWizardFactory::runWizard, f, _1, parent, platform, + QVariantMap(), false), + }; +} + +std::map WizardFactories::makeProjectItemsGroupedByCategory() +{ + QMap categories; + + for (auto *f : std::as_const(m_factories)) { + if (!categories.contains(f->category())) { + categories[f->category()] = { + /*.id =*/ f->category(), + /*.name =*/ f->displayCategory(), + /*.items = */ + { + makeProjectItem(f, m_wizardParent, m_platform), + }, + }; + } else { + auto projectItem = makeProjectItem(f, m_wizardParent, m_platform); + categories[f->category()].items.push_back(projectItem); + } + } + + return categories.toStdMap(); +} diff --git a/src/plugins/studiowelcome/wizardfactories.h b/src/plugins/studiowelcome/wizardfactories.h new file mode 100644 index 00000000000..c41300ff091 --- /dev/null +++ b/src/plugins/studiowelcome/wizardfactories.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "newprojectmodel.h" + +#include + +namespace Core { +class IWizardFactory; +} + +namespace StudioWelcome { + +class WizardFactories +{ +public: + WizardFactories(QList &factories, QWidget *wizardParent, + const Utils::Id &platform); + + const Core::IWizardFactory *front() const { return m_factories.front(); } + const std::map &projectsGroupedByCategory() const + { return m_projectItems; } + + bool empty() const { return m_factories.empty(); } + +private: + void sortByCategoryAndId(); + void filter(); + + ProjectItem makeProjectItem(Core::IWizardFactory *f, QWidget *parent, const Utils::Id &platform); + std::map makeProjectItemsGroupedByCategory(); + +private: + QSet m_blacklist; + QWidget *m_wizardParent; + Utils::Id m_platform; + + QList m_factories; + std::map m_projectItems; +}; + +} // namespace StudioWelcome diff --git a/src/plugins/studiowelcome/wizardhandler.cpp b/src/plugins/studiowelcome/wizardhandler.cpp new file mode 100644 index 00000000000..fce7aa120f9 --- /dev/null +++ b/src/plugins/studiowelcome/wizardhandler.cpp @@ -0,0 +1,249 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include +#include + +#include "wizardhandler.h" + +#include +#include + +#include + +#include "utils/wizard.h" +#include + +using namespace StudioWelcome; + +void WizardHandler::reset(const ProjectItem &projectInfo, int projectSelection, const Utils::FilePath &location) +{ + m_projectItem = projectInfo; + m_projectLocation = location; + m_selectedProject = projectSelection; + + if (!m_wizard) { + setupWizard(); + } else { + QObject::connect(m_wizard, &QObject::destroyed, this, &WizardHandler::onWizardResetting); + + // DON'T SET `m_selectedProject = -1` --- we are switching now to a separate project. + emit deletingWizard(); + + m_wizard->deleteLater(); + } +} + +void WizardHandler::destroyWizard() +{ + emit deletingWizard(); + + m_selectedProject = -1; + m_wizard->deleteLater(); + m_wizard = nullptr; +} + +void WizardHandler::setupWizard() +{ + m_wizard = m_projectItem.create(m_projectLocation); + if (!m_wizard) { + emit wizardCreationFailed(); + return; + } + + initializeProjectPage(m_wizard->page(0)); + initializeFieldsPage(m_wizard->page(1)); + + auto *screenFactorModel = getScreenFactorModel(m_detailsPage); + auto *styleModel = getStyleModel(m_detailsPage); + + emit wizardCreated(screenFactorModel, styleModel); +} + +void WizardHandler::setProjectName(const QString &name) +{ + QTC_ASSERT(m_wizard, return); + + QWizardPage *projectPage = m_wizard->page(0); + auto *jpp = dynamic_cast(projectPage); + QTC_ASSERT(jpp, return); + + jpp->setProjectName(name); +} + +void WizardHandler::setProjectLocation(const Utils::FilePath &location) +{ + QTC_ASSERT(m_wizard, return); + + QWizardPage *projectPage = m_wizard->page(0); + auto *jpp = dynamic_cast(projectPage); + QTC_ASSERT(jpp, return); + + jpp->setFilePath(location); +} + +void WizardHandler::initializeProjectPage(QWizardPage *page) +{ + auto *jpp = dynamic_cast(page); + QTC_ASSERT(jpp, return); + + QObject::connect(jpp, &ProjectExplorer::JsonProjectPage::statusMessageChanged, this, &WizardHandler::statusMessageChanged); + QObject::connect(jpp, &ProjectExplorer::JsonProjectPage::completeChanged, this, &WizardHandler::onProjectIntroCompleteChanged); +} + +void WizardHandler::initializeFieldsPage(QWizardPage *page) +{ + auto fieldsPage = dynamic_cast(page); // required for page->jsonField + QTC_ASSERT(fieldsPage, return); + m_detailsPage = fieldsPage; + + fieldsPage->initializePage(); +} + +void WizardHandler::onProjectIntroCompleteChanged() +{ + auto *page = dynamic_cast(QObject::sender()); + QTC_ASSERT(page, return); + + emit projectCanBeCreated(page->isComplete()); +} + +QStandardItemModel *WizardHandler::getScreenFactorModel(ProjectExplorer::JsonFieldPage *page) +{ + auto *field = page->jsonField("ScreenFactor"); + if (!field) + return nullptr; + + auto *cbfield = dynamic_cast(field); + QTC_ASSERT(cbfield, return nullptr); + + return cbfield->model(); +} + +QStandardItemModel *WizardHandler::getStyleModel(ProjectExplorer::JsonFieldPage *page) +{ + auto *field = page->jsonField("ControlsStyle"); + if (!field) + return nullptr; + + auto *cbfield = dynamic_cast(field); + QTC_ASSERT(cbfield, return nullptr); + + return cbfield->model(); +} + +void WizardHandler::onWizardResetting() +{ + m_wizard = nullptr; + + // if have a wizard request pending => create new wizard + // note: we always have a wizard request pending here, unless the dialogbox was requested to be destroyed. + // if m_selectedProject != -1 => the wizard was destroyed as a result of reset to a different project type + if (m_selectedProject > -1) + setupWizard(); +} + +void WizardHandler::setScreenSizeIndex(int index) +{ + auto *field = m_detailsPage->jsonField("ScreenFactor"); + auto *cbfield = dynamic_cast(field); + QTC_ASSERT(cbfield, return); + + cbfield->selectRow(index); +} + +void WizardHandler::setTargetQtVersionIndex(int index) +{ + auto *field = m_detailsPage->jsonField("TargetQtVersion"); + auto *cbfield = dynamic_cast(field); + QTC_ASSERT(cbfield, return); + + cbfield->selectRow(index); +} + +bool WizardHandler::haveTargetQtVersion() const +{ + return m_wizard->hasField("TargetQtVersion"); +} + +void WizardHandler::setStyleIndex(int index) +{ + auto *field = m_detailsPage->jsonField("ControlsStyle"); + auto *cbfield = dynamic_cast(field); + QTC_ASSERT(cbfield, return); + + cbfield->selectRow(index); +} + +int WizardHandler::styleIndex() const +{ + auto *field = m_detailsPage->jsonField("ControlsStyle"); + auto *cbfield = dynamic_cast(field); + QTC_ASSERT(cbfield, return -1); + + return cbfield->selectedRow(); +} + +void WizardHandler::setUseVirtualKeyboard(bool value) +{ + auto *field = m_detailsPage->jsonField("UseVirtualKeyboard"); + auto *cbfield = dynamic_cast(field); + QTC_ASSERT(cbfield, return); + + cbfield->setChecked(value); +} + +bool WizardHandler::haveVirtualKeyboard() const +{ + return m_wizard->hasField("UseVirtualKeyboard"); +} + +void WizardHandler::run(const std::function &processPage) +{ + m_wizard->restart(); + + int nextId = 0; + do { + QWizardPage *page = m_wizard->currentPage(); + QTC_ASSERT(page, return); + + processPage(page); + + if (!page->validatePage() || !page->isComplete()) { + QMessageBox::warning(m_wizard, "New project", "Could not create the project because fields are invalid"); + return; + } + + nextId = m_wizard->nextId(); + m_wizard->next(); + } while (-1 != nextId); + + m_selectedProject = -1; + + // Note: don't call `emit deletingWizard()` here. + + // Note: QWizard::accept calls QObject::deleteLater on the wizard + m_wizard->accept(); +} diff --git a/src/plugins/studiowelcome/wizardhandler.h b/src/plugins/studiowelcome/wizardhandler.h new file mode 100644 index 00000000000..a828d595f66 --- /dev/null +++ b/src/plugins/studiowelcome/wizardhandler.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "newprojectmodel.h" + +#include +#include + +QT_BEGIN_NAMESPACE +class QWizard; +class QWizardPage; +class QStandardItemModel; +QT_END_NAMESPACE + +namespace ProjectExplorer { +class JsonFieldPage; +} + +namespace StudioWelcome { + +class WizardHandler: public QObject +{ + Q_OBJECT + +public: + //TODO: location should not be needed in reset() -- only when creating the project + void reset(const ProjectItem &projectInfo, int projectSelection, const Utils::FilePath &location); + void setScreenSizeIndex(int index); + void setTargetQtVersionIndex(int index); + bool haveTargetQtVersion() const; + void setStyleIndex(int index); + int styleIndex() const; + void destroyWizard(); + + void setUseVirtualKeyboard(bool value); + bool haveVirtualKeyboard() const; + + void setProjectName(const QString &name); + void setProjectLocation(const Utils::FilePath &location); + + void run(const std::function &processPage); + +signals: + void deletingWizard(); + void wizardCreated(QStandardItemModel *screenSizeModel, QStandardItemModel *styleModel); + void statusMessageChanged(Utils::InfoLabel::InfoType type, const QString &message); + void projectCanBeCreated(bool value); + void wizardCreationFailed(); + +private: + void setupWizard(); + void initializeProjectPage(QWizardPage *page); + void initializeFieldsPage(QWizardPage *page); + + QStandardItemModel *getScreenFactorModel(ProjectExplorer::JsonFieldPage *page); + QStandardItemModel *getStyleModel(ProjectExplorer::JsonFieldPage *page); + +private slots: + void onWizardResetting(); + void onProjectIntroCompleteChanged(); + +private: + Utils::Wizard *m_wizard = nullptr; + ProjectExplorer::JsonFieldPage *m_detailsPage = nullptr; + + int m_selectedProject = -1; + + ProjectItem m_projectItem; + Utils::FilePath m_projectLocation; +}; + +} // StudioWelcome