Implement the New Project creation wizard for QDS
Task-number: QDS-4490 Change-Id: Ie8073e8838ec14a7f11ad972acc6fca4456adf58 Reviewed-by: Alessandro Portale <alessandro.portale@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
@@ -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
|
||||||
|
}
|
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 4.5 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 8.9 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 4.5 KiB |
After Width: | Height: | Size: 9.5 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 9.6 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 9.6 KiB |
@@ -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
|
||||||
|
}
|
||||||
|
}
|
@@ -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
|
||||||
|
}
|
||||||
|
}
|
@@ -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
|
@@ -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
|
||||||
|
}
|
@@ -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
|
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1 @@
|
|||||||
|
DefaultProject 1.0 DefaultProject.qml
|
@@ -30,6 +30,9 @@ import StudioTheme 1.0 as StudioTheme
|
|||||||
Item {
|
Item {
|
||||||
id: section
|
id: section
|
||||||
property alias caption: label.text
|
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 leftPadding: 8
|
||||||
property int topPadding: 4
|
property int topPadding: 4
|
||||||
property int rightPadding: 0
|
property int rightPadding: 0
|
||||||
|
@@ -57,7 +57,6 @@ add_subdirectory(scxmleditor)
|
|||||||
add_subdirectory(subversion)
|
add_subdirectory(subversion)
|
||||||
add_subdirectory(compilationdatabaseprojectmanager)
|
add_subdirectory(compilationdatabaseprojectmanager)
|
||||||
add_subdirectory(languageclient)
|
add_subdirectory(languageclient)
|
||||||
add_subdirectory(studiowelcome)
|
|
||||||
|
|
||||||
# Level 6:
|
# Level 6:
|
||||||
add_subdirectory(cmakeprojectmanager)
|
add_subdirectory(cmakeprojectmanager)
|
||||||
@@ -93,6 +92,7 @@ if (WIN32 AND CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
|||||||
set(qmldesigner_builddir ${PROJECT_BINARY_DIR}/qmldsgnr)
|
set(qmldesigner_builddir ${PROJECT_BINARY_DIR}/qmldsgnr)
|
||||||
endif()
|
endif()
|
||||||
add_subdirectory(qmldesigner ${qmldesigner_builddir})
|
add_subdirectory(qmldesigner ${qmldesigner_builddir})
|
||||||
|
add_subdirectory(studiowelcome)
|
||||||
add_subdirectory(qnx)
|
add_subdirectory(qnx)
|
||||||
add_subdirectory(webassembly)
|
add_subdirectory(webassembly)
|
||||||
add_subdirectory(mcusupport)
|
add_subdirectory(mcusupport)
|
||||||
|
@@ -32,6 +32,7 @@
|
|||||||
#include <extensionsystem/pluginmanager.h>
|
#include <extensionsystem/pluginmanager.h>
|
||||||
|
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
#include <utils/algorithm.h>
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
@@ -165,9 +166,13 @@ namespace Core {
|
|||||||
// The Core Singleton
|
// The Core Singleton
|
||||||
static ICore *m_instance = nullptr;
|
static ICore *m_instance = nullptr;
|
||||||
static MainWindow *m_mainwindow = nullptr;
|
static MainWindow *m_mainwindow = nullptr;
|
||||||
std::function<NewDialog *(QWidget *)> ICore::m_newDialogFactory = [](QWidget *parent) {
|
|
||||||
|
static NewDialog *defaultDialogFactory(QWidget *parent)
|
||||||
|
{
|
||||||
return new NewDialogWidget(parent);
|
return new NewDialogWidget(parent);
|
||||||
};
|
}
|
||||||
|
|
||||||
|
static std::function<NewDialog *(QWidget *)> m_newDialogFactory = defaultDialogFactory;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns the pointer to the instance. Only use for connecting to signals.
|
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)
|
const QVariantMap &extraVariables)
|
||||||
{
|
{
|
||||||
QTC_ASSERT(!isNewItemDialogRunning(), return);
|
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);
|
connect(newDialog->widget(), &QObject::destroyed, m_instance, &ICore::updateNewItemDialogState);
|
||||||
newDialog->setWizardFactories(factories, defaultLocation, extraVariables);
|
newDialog->setWizardFactories(factories, defaultLocation, extraVariables);
|
||||||
newDialog->setWindowTitle(title);
|
newDialog->setWindowTitle(title);
|
||||||
|
@@ -180,8 +180,6 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
static void updateNewItemDialogState();
|
static void updateNewItemDialogState();
|
||||||
|
|
||||||
static std::function<NewDialog *(QWidget *)> m_newDialogFactory;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Core
|
} // namespace Core
|
||||||
|
@@ -102,6 +102,14 @@ namespace Internal {
|
|||||||
|
|
||||||
enum { debugMainWindow = 0 };
|
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()
|
MainWindow::MainWindow()
|
||||||
: AppMainWindow()
|
: AppMainWindow()
|
||||||
, m_coreImpl(new ICore(this))
|
, m_coreImpl(new ICore(this))
|
||||||
@@ -519,7 +527,8 @@ void MainWindow::registerDefaultActions()
|
|||||||
|
|
||||||
// New File Action
|
// New File Action
|
||||||
QIcon icon = QIcon::fromTheme(QLatin1String("document-new"), Utils::Icons::NEWFILE.icon());
|
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 = ActionManager::registerAction(m_newAction, Constants::NEW);
|
||||||
cmd->setDefaultKeySequence(QKeySequence::New);
|
cmd->setDefaultKeySequence(QKeySequence::New);
|
||||||
mfile->addAction(cmd, Constants::G_FILE_NEW);
|
mfile->addAction(cmd, Constants::G_FILE_NEW);
|
||||||
|
@@ -25,12 +25,13 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "../projectexplorer_export.h"
|
||||||
#include <utils/projectintropage.h>
|
#include <utils/projectintropage.h>
|
||||||
|
|
||||||
namespace ProjectExplorer {
|
namespace ProjectExplorer {
|
||||||
|
|
||||||
// Documentation inside.
|
// Documentation inside.
|
||||||
class JsonProjectPage : public Utils::ProjectIntroPage
|
class PROJECTEXPLORER_EXPORT JsonProjectPage : public Utils::ProjectIntroPage
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
@@ -1,12 +1,20 @@
|
|||||||
add_qtc_plugin(StudioWelcome
|
add_qtc_plugin(StudioWelcome
|
||||||
CONDITION TARGET Qt5::QuickWidgets
|
CONDITION TARGET Qt5::QuickWidgets
|
||||||
DEPENDS 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/"
|
DEFINES STUDIO_QML_PATH="${CMAKE_CURRENT_SOURCE_DIR}/qml/"
|
||||||
SOURCES
|
SOURCES
|
||||||
studiowelcomeplugin.cpp studiowelcomeplugin.h
|
studiowelcomeplugin.cpp studiowelcomeplugin.h
|
||||||
|
newprojectdialogimageprovider.cpp newprojectdialogimageprovider.h
|
||||||
|
newprojectmodel.cpp newprojectmodel.h
|
||||||
examplecheckout.cpp examplecheckout.h
|
examplecheckout.cpp examplecheckout.h
|
||||||
studiowelcome_global.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
|
studiowelcome.qrc
|
||||||
"${PROJECT_SOURCE_DIR}/src/share/3rdparty/studiofonts/studiofonts.qrc"
|
"${PROJECT_SOURCE_DIR}/src/share/3rdparty/studiofonts/studiofonts.qrc"
|
||||||
EXTRA_TRANSLATIONS
|
EXTRA_TRANSLATIONS
|
||||||
|
77
src/plugins/studiowelcome/createproject.cpp
Normal file
@@ -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 <projectexplorer/jsonwizard/jsonprojectpage.h>
|
||||||
|
|
||||||
|
#include <projectexplorer/jsonwizard/jsonfieldpage.h>
|
||||||
|
#include <projectexplorer/jsonwizard/jsonfieldpage_p.h>
|
||||||
|
|
||||||
|
using namespace StudioWelcome;
|
||||||
|
|
||||||
|
void CreateProject::execute()
|
||||||
|
{
|
||||||
|
m_wizard.run([&](QWizardPage *page) {
|
||||||
|
if (auto *p = dynamic_cast<ProjectExplorer::JsonProjectPage *>(page))
|
||||||
|
processProjectPage(p);
|
||||||
|
else if (auto *p = dynamic_cast<ProjectExplorer::JsonFieldPage *>(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<ProjectExplorer::LineEditField *>(page->jsonField("CustomScreenWidth"));
|
||||||
|
auto heightField = dynamic_cast<ProjectExplorer::LineEditField *>(page->jsonField("CustomScreenHeight"));
|
||||||
|
|
||||||
|
if (widthField && heightField) {
|
||||||
|
if (!m_customWidth.isEmpty() && !m_customHeight.isEmpty()) {
|
||||||
|
widthField->setText(m_customWidth);
|
||||||
|
heightField->setText(m_customHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
77
src/plugins/studiowelcome/createproject.h
Normal file
@@ -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
|
99
src/plugins/studiowelcome/newprojectdialogimageprovider.cpp
Normal file
@@ -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 <coreplugin/icore.h>
|
||||||
|
#include <utils/utilsicons.h>
|
||||||
|
#include <utils/stylehelper.h>
|
||||||
|
|
||||||
|
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
|
||||||
|
|
50
src/plugins/studiowelcome/newprojectdialogimageprovider.h
Normal file
@@ -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 <QQuickImageProvider>
|
||||||
|
|
||||||
|
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
|
106
src/plugins/studiowelcome/newprojectmodel.cpp
Normal file
@@ -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<int, QByteArray> BaseNewProjectModel::roleNames() const
|
||||||
|
{
|
||||||
|
QHash<int, QByteArray> 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<int>(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<int>(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<size_t>(index);
|
||||||
|
|
||||||
|
endResetModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString NewProjectModel::fontIconCode(int index) const
|
||||||
|
{
|
||||||
|
Utils::optional<ProjectItem> projectItem = project(index);
|
||||||
|
if (!projectItem)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
return projectItem->fontIconCode;
|
||||||
|
}
|
145
src/plugins/studiowelcome/newprojectmodel.h
Normal file
@@ -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 <QAbstractListModel>
|
||||||
|
#include <QUrl>
|
||||||
|
|
||||||
|
#include <utils/filepath.h>
|
||||||
|
#include <utils/optional.h>
|
||||||
|
|
||||||
|
namespace Utils {
|
||||||
|
class Wizard;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace StudioWelcome {
|
||||||
|
|
||||||
|
struct ProjectItem
|
||||||
|
{
|
||||||
|
QString name;
|
||||||
|
QString categoryId;
|
||||||
|
QString description;
|
||||||
|
QUrl qmlPath;
|
||||||
|
QString fontIconCode;
|
||||||
|
std::function<Utils::Wizard *(const Utils::FilePath &path)> 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<ProjectItem> 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<QString, ProjectCategory>;
|
||||||
|
|
||||||
|
/****************** BaseNewProjectModel ******************/
|
||||||
|
|
||||||
|
class BaseNewProjectModel : public QAbstractListModel
|
||||||
|
{
|
||||||
|
using ProjectItems = std::vector<std::vector<ProjectItem>>;
|
||||||
|
using Categories = std::vector<QString>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit BaseNewProjectModel(QObject *parent = nullptr);
|
||||||
|
QHash<int, QByteArray> 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<int>(m_page); }
|
||||||
|
|
||||||
|
Utils::optional<ProjectItem> project(size_t selection) const
|
||||||
|
{
|
||||||
|
if (projects().empty())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (m_page < projects().size()) {
|
||||||
|
const std::vector<ProjectItem> 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<ProjectItem> projectsOfCurrentCategory() const
|
||||||
|
{ return projects().at(m_page); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t m_page = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace StudioWelcome
|
343
src/plugins/studiowelcome/qdsnewdialog.cpp
Normal file
@@ -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 <QQmlContext>
|
||||||
|
#include <QMessageBox>
|
||||||
|
|
||||||
|
#include "qdsnewdialog.h"
|
||||||
|
|
||||||
|
#include <coreplugin/icore.h>
|
||||||
|
#include <coreplugin/iwizardfactory.h>
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
|
#include <qmldesigner/components/componentcore/theme.h>
|
||||||
|
|
||||||
|
#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<QQmlContext::PropertyPair>{
|
||||||
|
{{"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<Core::IWizardFactory *> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
170
src/plugins/studiowelcome/qdsnewdialog.h
Normal file
@@ -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 <QQuickWidget>
|
||||||
|
|
||||||
|
#include <coreplugin/dialogs/newdialog.h>
|
||||||
|
#include <utils/infolabel.h>
|
||||||
|
#include <utils/optional.h>
|
||||||
|
|
||||||
|
#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<Core::IWizardFactory *> 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<NewProjectCategoryModel> m_categoryModel;
|
||||||
|
QPointer<NewProjectModel> m_projectModel;
|
||||||
|
QPointer<ScreenSizeModel> m_screenSizeModel;
|
||||||
|
QPointer<StyleModel> 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<ProjectItem> m_currentProject;
|
||||||
|
|
||||||
|
WizardHandler m_wizard;
|
||||||
|
};
|
||||||
|
|
||||||
|
} //namespace StudioWelcome
|
111
src/plugins/studiowelcome/screensizemodel.h
Normal file
@@ -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 <QAbstractListModel>
|
||||||
|
#include <QStandardItemModel>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
|
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<int, QByteArray> roleNames() const override
|
||||||
|
{
|
||||||
|
if (m_backendModel)
|
||||||
|
return m_backendModel->roleNames();
|
||||||
|
|
||||||
|
QHash<int, QByteArray> roleNames;
|
||||||
|
roleNames[Qt::UserRole] = "name";
|
||||||
|
return roleNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset() {
|
||||||
|
beginResetModel();
|
||||||
|
endResetModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBackendModel(QStandardItemModel *model)
|
||||||
|
{
|
||||||
|
m_backendModel = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QStandardItemModel *m_backendModel = nullptr;
|
||||||
|
};
|
||||||
|
|
@@ -12,10 +12,20 @@ DEFINES += STUDIO_QML_PATH=\\\"$$PWD/qml/\\\"
|
|||||||
HEADERS += \
|
HEADERS += \
|
||||||
studiowelcome_global.h \
|
studiowelcome_global.h \
|
||||||
studiowelcomeplugin.h \
|
studiowelcomeplugin.h \
|
||||||
|
newprojectdialogimageprovider.h \
|
||||||
|
qdsnewdialog.h \
|
||||||
|
wizardfactories.h \
|
||||||
|
createproject.h \
|
||||||
|
newprojectmodel.h \
|
||||||
examplecheckout.h
|
examplecheckout.h
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
studiowelcomeplugin.cpp \
|
studiowelcomeplugin.cpp \
|
||||||
|
qdsnewdialog.cpp \
|
||||||
|
wizardfactories.cpp \
|
||||||
|
createproject.cpp \
|
||||||
|
newprojectdialogimageprovider.cpp \
|
||||||
|
newprojectmodel.cpp \
|
||||||
examplecheckout.cpp
|
examplecheckout.cpp
|
||||||
|
|
||||||
OTHER_FILES += \
|
OTHER_FILES += \
|
||||||
|
@@ -17,8 +17,18 @@ QtcPlugin {
|
|||||||
"studiowelcome_global.h",
|
"studiowelcome_global.h",
|
||||||
"studiowelcomeplugin.h",
|
"studiowelcomeplugin.h",
|
||||||
"studiowelcomeplugin.cpp",
|
"studiowelcomeplugin.cpp",
|
||||||
|
"qdsnewdialog.cpp",
|
||||||
|
"qdsnewdialog.h",
|
||||||
|
"wizardfactories.cpp",
|
||||||
|
"wizardfactories.h",
|
||||||
|
"createproject.cpp",
|
||||||
|
"createproject.h",
|
||||||
|
"newprojectmodel.cpp",
|
||||||
|
"newprojectmodel.h",
|
||||||
"examplecheckout.h",
|
"examplecheckout.h",
|
||||||
"examplecheckout.cpp",
|
"examplecheckout.cpp",
|
||||||
|
"newprojectdialogimageprovider.h",
|
||||||
|
"newprojectdialogimageprovider.cpp",
|
||||||
"studiowelcome.qrc",
|
"studiowelcome.qrc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@@ -26,6 +26,8 @@
|
|||||||
#include "studiowelcomeplugin.h"
|
#include "studiowelcomeplugin.h"
|
||||||
#include "examplecheckout.h"
|
#include "examplecheckout.h"
|
||||||
|
|
||||||
|
#include "qdsnewdialog.h"
|
||||||
|
|
||||||
#include <coreplugin/coreconstants.h>
|
#include <coreplugin/coreconstants.h>
|
||||||
#include <coreplugin/dialogs/restartdialog.h>
|
#include <coreplugin/dialogs/restartdialog.h>
|
||||||
#include <coreplugin/editormanager/editormanager.h>
|
#include <coreplugin/editormanager/editormanager.h>
|
||||||
@@ -368,6 +370,9 @@ void StudioWelcomePlugin::extensionsInitialized()
|
|||||||
s_view->setSource(QUrl("qrc:/qml/splashscreen/main.qml"));
|
s_view->setSource(QUrl("qrc:/qml/splashscreen/main.qml"));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// disabled by default
|
||||||
|
Core::ICore::setNewDialogFactory([](QWidget *parent) { return new QdsNewDialog(parent); });
|
||||||
|
|
||||||
QTC_ASSERT(s_view->rootObject(),
|
QTC_ASSERT(s_view->rootObject(),
|
||||||
qWarning() << "The StudioWelcomePlugin has a runtime depdendency on "
|
qWarning() << "The StudioWelcomePlugin has a runtime depdendency on "
|
||||||
"qt/qtquicktimeline.";
|
"qt/qtquicktimeline.";
|
||||||
|
130
src/plugins/studiowelcome/stylemodel.cpp
Normal file
@@ -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 <QRegularExpression>
|
||||||
|
|
||||||
|
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<int>(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<int>(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();
|
||||||
|
}
|
||||||
|
}
|
96
src/plugins/studiowelcome/stylemodel.h
Normal file
@@ -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 <QAbstractListModel>
|
||||||
|
#include <QStandardItemModel>
|
||||||
|
|
||||||
|
class StyleModel : public QAbstractListModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private:
|
||||||
|
using Items = std::vector<QStandardItem *>;
|
||||||
|
|
||||||
|
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<int>(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<int, QByteArray> 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<int, QByteArray> 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<int, QByteArray> m_roles;
|
||||||
|
};
|
||||||
|
|
113
src/plugins/studiowelcome/wizardfactories.cpp
Normal file
@@ -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 <coreplugin/icore.h>
|
||||||
|
#include <coreplugin/iwizardfactory.h>
|
||||||
|
#include <utils/algorithm.h>
|
||||||
|
|
||||||
|
#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<Core::IWizardFactory *> &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<Core::IWizardFactory *> 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<QString, ProjectCategory> WizardFactories::makeProjectItemsGroupedByCategory()
|
||||||
|
{
|
||||||
|
QMap<QString, ProjectCategory> 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();
|
||||||
|
}
|
66
src/plugins/studiowelcome/wizardfactories.h
Normal file
@@ -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 <utils/id.h>
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class IWizardFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace StudioWelcome {
|
||||||
|
|
||||||
|
class WizardFactories
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
WizardFactories(QList<Core::IWizardFactory *> &factories, QWidget *wizardParent,
|
||||||
|
const Utils::Id &platform);
|
||||||
|
|
||||||
|
const Core::IWizardFactory *front() const { return m_factories.front(); }
|
||||||
|
const std::map<QString, ProjectCategory> &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<QString, ProjectCategory> makeProjectItemsGroupedByCategory();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QSet<Utils::Id> m_blacklist;
|
||||||
|
QWidget *m_wizardParent;
|
||||||
|
Utils::Id m_platform;
|
||||||
|
|
||||||
|
QList<Core::IWizardFactory *> m_factories;
|
||||||
|
std::map<QString, ProjectCategory> m_projectItems;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace StudioWelcome
|
249
src/plugins/studiowelcome/wizardhandler.cpp
Normal file
@@ -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 <QWizardPage>
|
||||||
|
#include <QMessageBox>
|
||||||
|
|
||||||
|
#include "wizardhandler.h"
|
||||||
|
|
||||||
|
#include <projectexplorer/jsonwizard/jsonfieldpage.h>
|
||||||
|
#include <projectexplorer/jsonwizard/jsonfieldpage_p.h>
|
||||||
|
|
||||||
|
#include <projectexplorer/jsonwizard/jsonprojectpage.h>
|
||||||
|
|
||||||
|
#include "utils/wizard.h"
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
|
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<ProjectExplorer::JsonProjectPage *>(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<ProjectExplorer::JsonProjectPage *>(projectPage);
|
||||||
|
QTC_ASSERT(jpp, return);
|
||||||
|
|
||||||
|
jpp->setFilePath(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WizardHandler::initializeProjectPage(QWizardPage *page)
|
||||||
|
{
|
||||||
|
auto *jpp = dynamic_cast<ProjectExplorer::JsonProjectPage *>(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<ProjectExplorer::JsonFieldPage *>(page); // required for page->jsonField
|
||||||
|
QTC_ASSERT(fieldsPage, return);
|
||||||
|
m_detailsPage = fieldsPage;
|
||||||
|
|
||||||
|
fieldsPage->initializePage();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WizardHandler::onProjectIntroCompleteChanged()
|
||||||
|
{
|
||||||
|
auto *page = dynamic_cast<ProjectExplorer::JsonProjectPage *>(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<ProjectExplorer::ComboBoxField *>(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<ProjectExplorer::ComboBoxField*>(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<ProjectExplorer::ComboBoxField *>(field);
|
||||||
|
QTC_ASSERT(cbfield, return);
|
||||||
|
|
||||||
|
cbfield->selectRow(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WizardHandler::setTargetQtVersionIndex(int index)
|
||||||
|
{
|
||||||
|
auto *field = m_detailsPage->jsonField("TargetQtVersion");
|
||||||
|
auto *cbfield = dynamic_cast<ProjectExplorer::ComboBoxField *>(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<ProjectExplorer::ComboBoxField *>(field);
|
||||||
|
QTC_ASSERT(cbfield, return);
|
||||||
|
|
||||||
|
cbfield->selectRow(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
int WizardHandler::styleIndex() const
|
||||||
|
{
|
||||||
|
auto *field = m_detailsPage->jsonField("ControlsStyle");
|
||||||
|
auto *cbfield = dynamic_cast<ProjectExplorer::ComboBoxField *>(field);
|
||||||
|
QTC_ASSERT(cbfield, return -1);
|
||||||
|
|
||||||
|
return cbfield->selectedRow();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WizardHandler::setUseVirtualKeyboard(bool value)
|
||||||
|
{
|
||||||
|
auto *field = m_detailsPage->jsonField("UseVirtualKeyboard");
|
||||||
|
auto *cbfield = dynamic_cast<ProjectExplorer::CheckBoxField *>(field);
|
||||||
|
QTC_ASSERT(cbfield, return);
|
||||||
|
|
||||||
|
cbfield->setChecked(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WizardHandler::haveVirtualKeyboard() const
|
||||||
|
{
|
||||||
|
return m_wizard->hasField("UseVirtualKeyboard");
|
||||||
|
}
|
||||||
|
|
||||||
|
void WizardHandler::run(const std::function<void(QWizardPage *)> &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();
|
||||||
|
}
|
96
src/plugins/studiowelcome/wizardhandler.h
Normal file
@@ -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 <utils/filepath.h>
|
||||||
|
#include <utils/infolabel.h>
|
||||||
|
|
||||||
|
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<void (QWizardPage *)> &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
|