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 {
|
||||
id: section
|
||||
property alias caption: label.text
|
||||
property alias captionPixelSize: label.font.pixelSize
|
||||
property alias captionColor: header.color
|
||||
property alias captionTextColor: label.color
|
||||
property int leftPadding: 8
|
||||
property int topPadding: 4
|
||||
property int rightPadding: 0
|
||||
|
@@ -57,7 +57,6 @@ add_subdirectory(scxmleditor)
|
||||
add_subdirectory(subversion)
|
||||
add_subdirectory(compilationdatabaseprojectmanager)
|
||||
add_subdirectory(languageclient)
|
||||
add_subdirectory(studiowelcome)
|
||||
|
||||
# Level 6:
|
||||
add_subdirectory(cmakeprojectmanager)
|
||||
@@ -93,6 +92,7 @@ if (WIN32 AND CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(qmldesigner_builddir ${PROJECT_BINARY_DIR}/qmldsgnr)
|
||||
endif()
|
||||
add_subdirectory(qmldesigner ${qmldesigner_builddir})
|
||||
add_subdirectory(studiowelcome)
|
||||
add_subdirectory(qnx)
|
||||
add_subdirectory(webassembly)
|
||||
add_subdirectory(mcusupport)
|
||||
|
@@ -32,6 +32,7 @@
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/algorithm.h>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDebug>
|
||||
@@ -165,9 +166,13 @@ namespace Core {
|
||||
// The Core Singleton
|
||||
static ICore *m_instance = nullptr;
|
||||
static MainWindow *m_mainwindow = nullptr;
|
||||
std::function<NewDialog *(QWidget *)> ICore::m_newDialogFactory = [](QWidget *parent) {
|
||||
|
||||
static NewDialog *defaultDialogFactory(QWidget *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.
|
||||
@@ -253,7 +258,23 @@ void ICore::showNewItemDialog(const QString &title,
|
||||
const QVariantMap &extraVariables)
|
||||
{
|
||||
QTC_ASSERT(!isNewItemDialogRunning(), return);
|
||||
NewDialog *newDialog = ICore::m_newDialogFactory(dialogParent());
|
||||
|
||||
/* This is a workaround for QDS: In QDS, we currently have a "New Project" dialog box but we do
|
||||
* not also have a "New file" dialog box (yet). Therefore, when requested to add a new file, we
|
||||
* need to use QtCreator's dialog box. In QDS, if `factories` contains project wizard factories
|
||||
* (even though it may contain file wizard factories as well), then we consider it to be a
|
||||
* request for "New Project". Otherwise, if we only have file wizard factories, we defer to
|
||||
* QtCreator's dialog and request "New File"
|
||||
*/
|
||||
auto dialogFactory = m_newDialogFactory;
|
||||
bool haveProjectWizards = Utils::anyOf(factories, [](IWizardFactory *f) {
|
||||
return f->kind() == IWizardFactory::ProjectWizard;
|
||||
});
|
||||
|
||||
if (!haveProjectWizards)
|
||||
dialogFactory = defaultDialogFactory;
|
||||
|
||||
NewDialog *newDialog = dialogFactory(dialogParent());
|
||||
connect(newDialog->widget(), &QObject::destroyed, m_instance, &ICore::updateNewItemDialogState);
|
||||
newDialog->setWizardFactories(factories, defaultLocation, extraVariables);
|
||||
newDialog->setWindowTitle(title);
|
||||
|
@@ -180,8 +180,6 @@ public:
|
||||
|
||||
private:
|
||||
static void updateNewItemDialogState();
|
||||
|
||||
static std::function<NewDialog *(QWidget *)> m_newDialogFactory;
|
||||
};
|
||||
|
||||
} // namespace Core
|
||||
|
@@ -102,6 +102,14 @@ namespace Internal {
|
||||
|
||||
enum { debugMainWindow = 0 };
|
||||
|
||||
static bool isQtDesignStudio()
|
||||
{
|
||||
QSettings *settings = Core::ICore::settings();
|
||||
const QString qdsStandaloneEntry = "QML/Designer/StandAloneMode"; //entry from qml settings
|
||||
|
||||
return settings->value(qdsStandaloneEntry, false).toBool();
|
||||
}
|
||||
|
||||
MainWindow::MainWindow()
|
||||
: AppMainWindow()
|
||||
, m_coreImpl(new ICore(this))
|
||||
@@ -519,7 +527,8 @@ void MainWindow::registerDefaultActions()
|
||||
|
||||
// New File Action
|
||||
QIcon icon = QIcon::fromTheme(QLatin1String("document-new"), Utils::Icons::NEWFILE.icon());
|
||||
m_newAction = new QAction(icon, tr("&New File or Project..."), this);
|
||||
QString newActionText = isQtDesignStudio() ? tr("&New Project...") : tr("&New File or Project...");
|
||||
m_newAction = new QAction(icon, newActionText, this);
|
||||
cmd = ActionManager::registerAction(m_newAction, Constants::NEW);
|
||||
cmd->setDefaultKeySequence(QKeySequence::New);
|
||||
mfile->addAction(cmd, Constants::G_FILE_NEW);
|
||||
|
@@ -25,12 +25,13 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../projectexplorer_export.h"
|
||||
#include <utils/projectintropage.h>
|
||||
|
||||
namespace ProjectExplorer {
|
||||
|
||||
// Documentation inside.
|
||||
class JsonProjectPage : public Utils::ProjectIntroPage
|
||||
class PROJECTEXPLORER_EXPORT JsonProjectPage : public Utils::ProjectIntroPage
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
@@ -1,12 +1,20 @@
|
||||
add_qtc_plugin(StudioWelcome
|
||||
CONDITION TARGET Qt5::QuickWidgets
|
||||
DEPENDS Qt5::QuickWidgets
|
||||
PLUGIN_DEPENDS Core ProjectExplorer QtSupport
|
||||
PLUGIN_DEPENDS Core ProjectExplorer QtSupport QmlDesigner
|
||||
DEFINES STUDIO_QML_PATH="${CMAKE_CURRENT_SOURCE_DIR}/qml/"
|
||||
SOURCES
|
||||
studiowelcomeplugin.cpp studiowelcomeplugin.h
|
||||
newprojectdialogimageprovider.cpp newprojectdialogimageprovider.h
|
||||
newprojectmodel.cpp newprojectmodel.h
|
||||
examplecheckout.cpp examplecheckout.h
|
||||
studiowelcome_global.h
|
||||
qdsnewdialog.cpp qdsnewdialog.h
|
||||
wizardfactories.cpp wizardfactories.h
|
||||
createproject.cpp createproject.h
|
||||
wizardhandler.cpp wizardhandler.h
|
||||
screensizemodel.h
|
||||
stylemodel.h stylemodel.cpp
|
||||
studiowelcome.qrc
|
||||
"${PROJECT_SOURCE_DIR}/src/share/3rdparty/studiofonts/studiofonts.qrc"
|
||||
EXTRA_TRANSLATIONS
|
||||
|
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 += \
|
||||
studiowelcome_global.h \
|
||||
studiowelcomeplugin.h \
|
||||
newprojectdialogimageprovider.h \
|
||||
qdsnewdialog.h \
|
||||
wizardfactories.h \
|
||||
createproject.h \
|
||||
newprojectmodel.h \
|
||||
examplecheckout.h
|
||||
|
||||
SOURCES += \
|
||||
studiowelcomeplugin.cpp \
|
||||
qdsnewdialog.cpp \
|
||||
wizardfactories.cpp \
|
||||
createproject.cpp \
|
||||
newprojectdialogimageprovider.cpp \
|
||||
newprojectmodel.cpp \
|
||||
examplecheckout.cpp
|
||||
|
||||
OTHER_FILES += \
|
||||
|
@@ -17,8 +17,18 @@ QtcPlugin {
|
||||
"studiowelcome_global.h",
|
||||
"studiowelcomeplugin.h",
|
||||
"studiowelcomeplugin.cpp",
|
||||
"qdsnewdialog.cpp",
|
||||
"qdsnewdialog.h",
|
||||
"wizardfactories.cpp",
|
||||
"wizardfactories.h",
|
||||
"createproject.cpp",
|
||||
"createproject.h",
|
||||
"newprojectmodel.cpp",
|
||||
"newprojectmodel.h",
|
||||
"examplecheckout.h",
|
||||
"examplecheckout.cpp",
|
||||
"newprojectdialogimageprovider.h",
|
||||
"newprojectdialogimageprovider.cpp",
|
||||
"studiowelcome.qrc",
|
||||
]
|
||||
|
||||
|
@@ -26,6 +26,8 @@
|
||||
#include "studiowelcomeplugin.h"
|
||||
#include "examplecheckout.h"
|
||||
|
||||
#include "qdsnewdialog.h"
|
||||
|
||||
#include <coreplugin/coreconstants.h>
|
||||
#include <coreplugin/dialogs/restartdialog.h>
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
@@ -368,6 +370,9 @@ void StudioWelcomePlugin::extensionsInitialized()
|
||||
s_view->setSource(QUrl("qrc:/qml/splashscreen/main.qml"));
|
||||
#endif
|
||||
|
||||
// disabled by default
|
||||
Core::ICore::setNewDialogFactory([](QWidget *parent) { return new QdsNewDialog(parent); });
|
||||
|
||||
QTC_ASSERT(s_view->rootObject(),
|
||||
qWarning() << "The StudioWelcomePlugin has a runtime depdendency on "
|
||||
"qt/qtquicktimeline.";
|
||||
|
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
|