Implement custom presets
Task-number: QDS-4989 Change-Id: I95844ae97204ad3bb94905c89f8e16b79eed8f64 Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
@@ -32,6 +32,7 @@ import StudioTheme as StudioTheme
|
|||||||
import StudioControls as SC
|
import StudioControls as SC
|
||||||
|
|
||||||
import NewProjectDialog
|
import NewProjectDialog
|
||||||
|
import BackendApi
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: rootDialog
|
id: rootDialog
|
||||||
@@ -161,17 +162,43 @@ Item {
|
|||||||
readonly property int animDur: 500
|
readonly property int animDur: 500
|
||||||
id: tabBar
|
id: tabBar
|
||||||
x: 10 // left padding
|
x: 10 // left padding
|
||||||
width: parent.width - 64 // right padding
|
width: parent.width - 20 // right padding
|
||||||
height: DialogValues.projectViewHeaderHeight
|
height: DialogValues.projectViewHeaderHeight
|
||||||
color: DialogValues.lightPaneColor
|
color: DialogValues.lightPaneColor
|
||||||
|
|
||||||
|
function selectTab(tabIndex, selectLast = false) {
|
||||||
|
var item = repeater.itemAt(tabIndex)
|
||||||
|
tabBarRow.currIndex = tabIndex
|
||||||
|
|
||||||
|
projectView.selectLast = selectLast
|
||||||
|
BackendApi.presetModel.setPage(tabIndex) // NOTE: it resets preset model
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: BackendApi
|
||||||
|
|
||||||
|
function onUserPresetSaved() {
|
||||||
|
var customTabIndex = repeater.count - 1
|
||||||
|
tabBar.selectTab(customTabIndex, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
function onLastUserPresetRemoved() {
|
||||||
|
tabBar.selectTab(0, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
id: tabBarRow
|
id: tabBarRow
|
||||||
spacing: 20
|
spacing: 20
|
||||||
property int currIndex: 0
|
property int currIndex: 0
|
||||||
|
readonly property string currentTabName:
|
||||||
|
repeater.count > 0 && repeater.itemAt(currIndex)
|
||||||
|
? repeater.itemAt(currIndex).text
|
||||||
|
: ''
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
model: categoryModel
|
id: repeater
|
||||||
|
model: BackendApi.categoryModel
|
||||||
Text {
|
Text {
|
||||||
text: name
|
text: name
|
||||||
font.weight: Font.DemiBold
|
font.weight: Font.DemiBold
|
||||||
@@ -184,13 +211,7 @@ Item {
|
|||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
onClicked: {
|
onClicked: {
|
||||||
tabBarRow.currIndex = index
|
tabBar.selectTab(index)
|
||||||
presetModel.setPage(index)
|
|
||||||
projectView.currentIndex = 0
|
|
||||||
projectView.currentIndexChanged()
|
|
||||||
|
|
||||||
strip.x = parent.x
|
|
||||||
strip.width = parent.width
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,8 +220,19 @@ Item {
|
|||||||
} // tabBarRow
|
} // tabBarRow
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
function computeX() {
|
||||||
|
var item = tabBarRow.children[tabBarRow.currIndex] ?? tabBarRow.children[0]
|
||||||
|
return item.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
function computeWidth() {
|
||||||
|
var item = tabBarRow.children[tabBarRow.currIndex] ?? tabBarRow.children[0]
|
||||||
|
return item.width;
|
||||||
|
}
|
||||||
|
|
||||||
id: strip
|
id: strip
|
||||||
width: tabBarRow.children[0].width
|
x: computeX()
|
||||||
|
width: computeWidth()
|
||||||
height: 5
|
height: 5
|
||||||
radius: 2
|
radius: 2
|
||||||
color: DialogValues.textColorInteraction
|
color: DialogValues.textColorInteraction
|
||||||
@@ -209,35 +241,40 @@ Item {
|
|||||||
Behavior on x { SmoothedAnimation { duration: tabBar.animDur } }
|
Behavior on x { SmoothedAnimation { duration: tabBar.animDur } }
|
||||||
Behavior on width { SmoothedAnimation { duration: strip.width === 0 ? 0 : tabBar.animDur } } // do not animate initial width
|
Behavior on width { SmoothedAnimation { duration: strip.width === 0 ? 0 : tabBar.animDur } } // do not animate initial width
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: rootDialog
|
|
||||||
function onWidthChanged() {
|
|
||||||
if (rootDialog.width < 1200) { // 1200 = the width threshold
|
|
||||||
tabBar.width = tabBar.parent.width - 20
|
|
||||||
projectView.width = projectView.parent.width - 20
|
|
||||||
} else {
|
|
||||||
tabBar.width = tabBar.parent.width - 64
|
|
||||||
projectView.width = projectView.parent.width - 64
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // Rectangle
|
} // Rectangle
|
||||||
|
|
||||||
NewProjectView {
|
Rectangle {
|
||||||
id: projectView
|
id: projectViewFrame
|
||||||
x: 10 // left padding
|
x: 10 // left padding
|
||||||
width: parent.width - 64 // right padding
|
width: parent.width - 20 // right padding
|
||||||
height: DialogValues.projectViewHeight
|
height: DialogValues.projectViewHeight
|
||||||
loader: projectDetailsLoader
|
color: DialogValues.darkPaneColor
|
||||||
|
|
||||||
Connections {
|
Item {
|
||||||
target: rootDialog
|
anchors.fill: parent
|
||||||
function onHeightChanged() {
|
anchors.margins: DialogValues.gridMargins
|
||||||
if (rootDialog.height < 700) { // 700 = minimum height big dialog
|
|
||||||
projectView.height = DialogValues.projectViewHeight / 2
|
NewProjectView {
|
||||||
} else {
|
id: projectView
|
||||||
projectView.height = DialogValues.projectViewHeight
|
anchors.fill: parent
|
||||||
|
|
||||||
|
loader: projectDetailsLoader
|
||||||
|
currentTabName: tabBarRow.currentTabName
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: rootDialog
|
||||||
|
function onHeightChanged() {
|
||||||
|
if (rootDialog.height < 720) { // 720 = minimum height big dialog
|
||||||
|
DialogValues.projectViewHeight =
|
||||||
|
DialogValues.projectItemHeight
|
||||||
|
+ 2 * DialogValues.gridMargins
|
||||||
|
} else {
|
||||||
|
DialogValues.projectViewHeight =
|
||||||
|
DialogValues.projectItemHeight * 2
|
||||||
|
+ DialogValues.gridSpacing
|
||||||
|
+ 2 * DialogValues.gridMargins
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -247,12 +284,12 @@ Item {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: descriptionText
|
id: descriptionText
|
||||||
text: dialogBox.projectDescription
|
text: BackendApi.projectDescription
|
||||||
font.pixelSize: DialogValues.defaultPixelSize
|
font.pixelSize: DialogValues.defaultPixelSize
|
||||||
lineHeight: DialogValues.defaultLineHeight
|
lineHeight: DialogValues.defaultLineHeight
|
||||||
lineHeightMode: Text.FixedHeight
|
lineHeightMode: Text.FixedHeight
|
||||||
leftPadding: 14
|
leftPadding: 14
|
||||||
width: projectView.width
|
width: projectViewFrame.width
|
||||||
color: DialogValues.textColor
|
color: DialogValues.textColor
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
maximumLineCount: 4
|
maximumLineCount: 4
|
||||||
@@ -298,7 +335,7 @@ Item {
|
|||||||
iconFont: StudioTheme.Constants.font
|
iconFont: StudioTheme.Constants.font
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
dialogBox.reject();
|
BackendApi.reject();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,11 +347,11 @@ Item {
|
|||||||
visible: true
|
visible: true
|
||||||
buttonIcon: qsTr("Create")
|
buttonIcon: qsTr("Create")
|
||||||
iconSize: DialogValues.defaultPixelSize
|
iconSize: DialogValues.defaultPixelSize
|
||||||
enabled: dialogBox.fieldsValid
|
enabled: BackendApi.fieldsValid
|
||||||
iconFont: StudioTheme.Constants.font
|
iconFont: StudioTheme.Constants.font
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
dialogBox.accept();
|
BackendApi.accept();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // RowLayout
|
} // RowLayout
|
||||||
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 5.0 KiB |
Before Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 8.3 KiB After Width: | Height: | Size: 5.1 KiB |
@@ -31,16 +31,13 @@ import QtQuick.Layouts
|
|||||||
import StudioControls as SC
|
import StudioControls as SC
|
||||||
import StudioTheme as StudioTheme
|
import StudioTheme as StudioTheme
|
||||||
|
|
||||||
|
import BackendApi
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
width: DialogValues.detailsPaneWidth
|
width: DialogValues.detailsPaneWidth
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: BackendApi.detailsLoaded = true
|
||||||
dialogBox.detailsLoaded = true;
|
Component.onDestruction: BackendApi.detailsLoaded = false
|
||||||
}
|
|
||||||
|
|
||||||
Component.onDestruction: {
|
|
||||||
dialogBox.detailsLoaded = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
color: DialogValues.darkPaneColor
|
color: DialogValues.darkPaneColor
|
||||||
@@ -53,13 +50,13 @@ Item {
|
|||||||
|
|
||||||
Column {
|
Column {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
spacing: DialogValues.defaultPadding
|
spacing: 5
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: detailsHeading
|
id: detailsHeading
|
||||||
text: qsTr("Details")
|
text: qsTr("Details")
|
||||||
height: DialogValues.paneTitleTextHeight
|
height: DialogValues.paneTitleTextHeight
|
||||||
width: parent.width;
|
width: parent.width
|
||||||
font.weight: Font.DemiBold
|
font.weight: Font.DemiBold
|
||||||
font.pixelSize: DialogValues.paneTitlePixelSize
|
font.pixelSize: DialogValues.paneTitlePixelSize
|
||||||
lineHeight: DialogValues.paneTitleLineHeight
|
lineHeight: DialogValues.paneTitleLineHeight
|
||||||
@@ -71,39 +68,36 @@ Item {
|
|||||||
Flickable {
|
Flickable {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: parent.height - detailsHeading.height - DialogValues.defaultPadding
|
height: parent.height - detailsHeading.height - DialogValues.defaultPadding
|
||||||
|
- savePresetButton.height
|
||||||
contentWidth: parent.width
|
contentWidth: parent.width
|
||||||
contentHeight: scrollContent.height
|
contentHeight: scrollContent.height
|
||||||
boundsBehavior: Flickable.StopAtBounds
|
boundsBehavior: Flickable.StopAtBounds
|
||||||
clip: true
|
clip: true
|
||||||
|
|
||||||
ScrollBar.vertical: SC.VerticalScrollBar {
|
ScrollBar.vertical: SC.VerticalScrollBar {}
|
||||||
}
|
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
id: scrollContent
|
id: scrollContent
|
||||||
width: parent.width - DialogValues.detailsPanePadding
|
width: parent.width - DialogValues.detailsPanePadding
|
||||||
height: DialogValues.detailsScrollableContentHeight
|
|
||||||
spacing: DialogValues.defaultPadding
|
spacing: DialogValues.defaultPadding
|
||||||
|
|
||||||
SC.TextField {
|
SC.TextField {
|
||||||
id: projectNameTextField
|
id: projectNameTextField
|
||||||
actionIndicatorVisible: false
|
actionIndicatorVisible: false
|
||||||
translationIndicatorVisible: false
|
translationIndicatorVisible: false
|
||||||
text: dialogBox.projectName
|
text: BackendApi.projectName
|
||||||
width: parent.width
|
width: parent.width
|
||||||
color: DialogValues.textColor
|
color: DialogValues.textColor
|
||||||
selectByMouse: true
|
selectByMouse: true
|
||||||
|
font.pixelSize: DialogValues.defaultPixelSize
|
||||||
|
|
||||||
onEditingFinished: {
|
onEditingFinished: {
|
||||||
text = text.charAt(0).toUpperCase() + text.slice(1)
|
text = text.charAt(0).toUpperCase() + text.slice(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
font.pixelSize: DialogValues.defaultPixelSize
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Binding {
|
Binding {
|
||||||
target: dialogBox
|
target: BackendApi
|
||||||
property: "projectName"
|
property: "projectName"
|
||||||
value: projectNameTextField.text
|
value: projectNameTextField.text
|
||||||
}
|
}
|
||||||
@@ -118,14 +112,14 @@ Item {
|
|||||||
id: projectLocationTextField
|
id: projectLocationTextField
|
||||||
actionIndicatorVisible: false
|
actionIndicatorVisible: false
|
||||||
translationIndicatorVisible: false
|
translationIndicatorVisible: false
|
||||||
text: dialogBox.projectLocation
|
text: BackendApi.projectLocation
|
||||||
color: DialogValues.textColor
|
color: DialogValues.textColor
|
||||||
selectByMouse: true
|
selectByMouse: true
|
||||||
font.pixelSize: DialogValues.defaultPixelSize
|
font.pixelSize: DialogValues.defaultPixelSize
|
||||||
}
|
}
|
||||||
|
|
||||||
Binding {
|
Binding {
|
||||||
target: dialogBox
|
target: BackendApi
|
||||||
property: "projectLocation"
|
property: "projectLocation"
|
||||||
value: projectLocationTextField.text
|
value: projectLocationTextField.text
|
||||||
}
|
}
|
||||||
@@ -138,7 +132,7 @@ Item {
|
|||||||
iconFont: StudioTheme.Constants.font
|
iconFont: StudioTheme.Constants.font
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
var newLocation = dialogBox.chooseProjectLocation()
|
var newLocation = BackendApi.chooseProjectLocation()
|
||||||
if (newLocation)
|
if (newLocation)
|
||||||
projectLocationTextField.text = newLocation
|
projectLocationTextField.text = newLocation
|
||||||
}
|
}
|
||||||
@@ -159,7 +153,7 @@ Item {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: statusMessage
|
id: statusMessage
|
||||||
text: dialogBox.statusMessage
|
text: BackendApi.statusMessage
|
||||||
font.pixelSize: DialogValues.defaultPixelSize
|
font.pixelSize: DialogValues.defaultPixelSize
|
||||||
lineHeight: DialogValues.defaultLineHeight
|
lineHeight: DialogValues.defaultLineHeight
|
||||||
lineHeightMode: Text.FixedHeight
|
lineHeightMode: Text.FixedHeight
|
||||||
@@ -172,7 +166,7 @@ Item {
|
|||||||
states: [
|
states: [
|
||||||
State {
|
State {
|
||||||
name: "warning"
|
name: "warning"
|
||||||
when: dialogBox.statusType === "warning"
|
when: BackendApi.statusType === "warning"
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: statusMessage
|
target: statusMessage
|
||||||
color: DialogValues.textWarning
|
color: DialogValues.textWarning
|
||||||
@@ -185,7 +179,7 @@ Item {
|
|||||||
|
|
||||||
State {
|
State {
|
||||||
name: "error"
|
name: "error"
|
||||||
when: dialogBox.statusType === "error"
|
when: BackendApi.statusType === "error"
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: statusMessage
|
target: statusMessage
|
||||||
color: DialogValues.textError
|
color: DialogValues.textError
|
||||||
@@ -208,7 +202,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Binding {
|
Binding {
|
||||||
target: dialogBox
|
target: BackendApi
|
||||||
property: "saveAsDefaultLocation"
|
property: "saveAsDefaultLocation"
|
||||||
value: defaultLocationCheckbox.checked
|
value: defaultLocationCheckbox.checked
|
||||||
}
|
}
|
||||||
@@ -219,25 +213,25 @@ Item {
|
|||||||
id: screenSizeComboBox
|
id: screenSizeComboBox
|
||||||
actionIndicatorVisible: false
|
actionIndicatorVisible: false
|
||||||
currentIndex: -1
|
currentIndex: -1
|
||||||
model: screenSizeModel
|
model: BackendApi.screenSizeModel
|
||||||
textRole: "display"
|
textRole: "display"
|
||||||
width: parent.width
|
width: parent.width
|
||||||
font.pixelSize: DialogValues.defaultPixelSize
|
font.pixelSize: DialogValues.defaultPixelSize
|
||||||
|
|
||||||
onActivated: (index) => {
|
onActivated: (index) => {
|
||||||
dialogBox.setScreenSizeIndex(index);
|
BackendApi.setScreenSizeIndex(index);
|
||||||
|
|
||||||
var size = screenSizeModel.screenSizes(index);
|
var size = BackendApi.screenSizeModel.screenSizes(index);
|
||||||
widthField.realValue = size.width;
|
widthField.realValue = size.width;
|
||||||
heightField.realValue = size.height;
|
heightField.realValue = size.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: screenSizeModel
|
target: BackendApi.screenSizeModel
|
||||||
function onModelReset() {
|
function onModelReset() {
|
||||||
var newIndex = screenSizeComboBox.currentIndex > -1
|
var newIndex = screenSizeComboBox.currentIndex > -1
|
||||||
? screenSizeComboBox.currentIndex
|
? screenSizeComboBox.currentIndex
|
||||||
: dialogBox.screenSizeIndex()
|
: BackendApi.screenSizeIndex()
|
||||||
|
|
||||||
screenSizeComboBox.currentIndex = newIndex
|
screenSizeComboBox.currentIndex = newIndex
|
||||||
screenSizeComboBox.activated(newIndex)
|
screenSizeComboBox.activated(newIndex)
|
||||||
@@ -248,10 +242,8 @@ Item {
|
|||||||
GridLayout { // orientation + width + height
|
GridLayout { // orientation + width + height
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: 85
|
height: 85
|
||||||
|
|
||||||
columns: 4
|
columns: 4
|
||||||
rows: 2
|
rows: 2
|
||||||
|
|
||||||
columnSpacing: 10
|
columnSpacing: 10
|
||||||
rowSpacing: 10
|
rowSpacing: 10
|
||||||
|
|
||||||
@@ -295,10 +287,7 @@ Item {
|
|||||||
font.pixelSize: DialogValues.defaultPixelSize
|
font.pixelSize: DialogValues.defaultPixelSize
|
||||||
|
|
||||||
onRealValueChanged: {
|
onRealValueChanged: {
|
||||||
var height = heightField.realValue
|
if (widthField.realValue >= heightField.realValue)
|
||||||
var width = realValue
|
|
||||||
|
|
||||||
if (width >= height)
|
|
||||||
orientationButton.setHorizontal()
|
orientationButton.setHorizontal()
|
||||||
else
|
else
|
||||||
orientationButton.setVertical()
|
orientationButton.setVertical()
|
||||||
@@ -306,7 +295,7 @@ Item {
|
|||||||
} // Width Text Field
|
} // Width Text Field
|
||||||
|
|
||||||
Binding {
|
Binding {
|
||||||
target: dialogBox
|
target: BackendApi
|
||||||
property: "customWidth"
|
property: "customWidth"
|
||||||
value: widthField.realValue
|
value: widthField.realValue
|
||||||
}
|
}
|
||||||
@@ -323,10 +312,7 @@ Item {
|
|||||||
font.pixelSize: DialogValues.defaultPixelSize
|
font.pixelSize: DialogValues.defaultPixelSize
|
||||||
|
|
||||||
onRealValueChanged: {
|
onRealValueChanged: {
|
||||||
var height = realValue
|
if (widthField.realValue >= heightField.realValue)
|
||||||
var width = widthField.realValue
|
|
||||||
|
|
||||||
if (width >= height)
|
|
||||||
orientationButton.setHorizontal()
|
orientationButton.setHorizontal()
|
||||||
else
|
else
|
||||||
orientationButton.setVertical()
|
orientationButton.setVertical()
|
||||||
@@ -334,7 +320,7 @@ Item {
|
|||||||
} // Height Text Field
|
} // Height Text Field
|
||||||
|
|
||||||
Binding {
|
Binding {
|
||||||
target: dialogBox
|
target: BackendApi
|
||||||
property: "customHeight"
|
property: "customHeight"
|
||||||
value: heightField.realValue
|
value: heightField.realValue
|
||||||
}
|
}
|
||||||
@@ -345,7 +331,6 @@ Item {
|
|||||||
id: orientationButton
|
id: orientationButton
|
||||||
implicitWidth: 100
|
implicitWidth: 100
|
||||||
implicitHeight: 50
|
implicitHeight: 50
|
||||||
|
|
||||||
checked: false
|
checked: false
|
||||||
hoverEnabled: false
|
hoverEnabled: false
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
@@ -384,19 +369,19 @@ Item {
|
|||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (widthField.realValue && heightField.realValue) {
|
if (widthField.realValue && heightField.realValue) {
|
||||||
[widthField.realValue, heightField.realValue] = [heightField.realValue, widthField.realValue];
|
[widthField.realValue, heightField.realValue] = [heightField.realValue, widthField.realValue]
|
||||||
checked = !checked
|
orientationButton.checked = !orientationButton.checked
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setHorizontal() {
|
function setHorizontal() {
|
||||||
checked = false
|
orientationButton.checked = false
|
||||||
horizontalBar.color = DialogValues.textColorInteraction
|
horizontalBar.color = DialogValues.textColorInteraction
|
||||||
verticalBar.color = "white"
|
verticalBar.color = "white"
|
||||||
}
|
}
|
||||||
|
|
||||||
function setVertical() {
|
function setVertical() {
|
||||||
checked = true
|
orientationButton.checked = true
|
||||||
horizontalBar.color = "white"
|
horizontalBar.color = "white"
|
||||||
verticalBar.color = DialogValues.textColorInteraction
|
verticalBar.color = DialogValues.textColorInteraction
|
||||||
}
|
}
|
||||||
@@ -404,23 +389,27 @@ Item {
|
|||||||
|
|
||||||
} // GridLayout: orientation + width + height
|
} // GridLayout: orientation + width + height
|
||||||
|
|
||||||
Rectangle { width: parent.width; height: 1; color: DialogValues.dividerlineColor }
|
Rectangle {
|
||||||
|
width: parent.width
|
||||||
|
height: 1
|
||||||
|
color: DialogValues.dividerlineColor
|
||||||
|
}
|
||||||
|
|
||||||
SC.CheckBox {
|
SC.CheckBox {
|
||||||
id: useQtVirtualKeyboard
|
id: useQtVirtualKeyboard
|
||||||
actionIndicatorVisible: false
|
actionIndicatorVisible: false
|
||||||
text: qsTr("Use Qt Virtual Keyboard")
|
text: qsTr("Use Qt Virtual Keyboard")
|
||||||
font.pixelSize: DialogValues.defaultPixelSize
|
font.pixelSize: DialogValues.defaultPixelSize
|
||||||
checked: dialogBox.useVirtualKeyboard
|
checked: BackendApi.useVirtualKeyboard
|
||||||
visible: dialogBox.haveVirtualKeyboard
|
visible: BackendApi.haveVirtualKeyboard
|
||||||
}
|
}
|
||||||
|
|
||||||
RowLayout { // Target Qt Version
|
RowLayout { // Target Qt Version
|
||||||
width: parent.width
|
width: parent.width
|
||||||
visible: dialogBox.haveTargetQtVersion
|
visible: BackendApi.haveTargetQtVersion
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
text: "Target Qt Version:"
|
text: qsTr("Target Qt Version:")
|
||||||
font.pixelSize: DialogValues.defaultPixelSize
|
font.pixelSize: DialogValues.defaultPixelSize
|
||||||
lineHeight: DialogValues.defaultLineHeight
|
lineHeight: DialogValues.defaultLineHeight
|
||||||
lineHeightMode: Text.FixedHeight
|
lineHeightMode: Text.FixedHeight
|
||||||
@@ -432,33 +421,98 @@ Item {
|
|||||||
actionIndicatorVisible: false
|
actionIndicatorVisible: false
|
||||||
implicitWidth: 70
|
implicitWidth: 70
|
||||||
Layout.alignment: Qt.AlignRight
|
Layout.alignment: Qt.AlignRight
|
||||||
currentIndex: 1
|
currentIndex: BackendApi.targetQtVersionIndex
|
||||||
font.pixelSize: DialogValues.defaultPixelSize
|
font.pixelSize: DialogValues.defaultPixelSize
|
||||||
|
|
||||||
model: ListModel {
|
model: ListModel {
|
||||||
ListElement {
|
ListElement { name: "Qt 5" }
|
||||||
name: "Qt 5"
|
ListElement { name: "Qt 6" }
|
||||||
}
|
|
||||||
ListElement {
|
|
||||||
name: "Qt 6"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onActivated: (index) => {
|
onActivated: (index) => {
|
||||||
dialogBox.setTargetQtVersion(index)
|
BackendApi.targetQtVersionIndex = index
|
||||||
}
|
}
|
||||||
} // Target Qt Version ComboBox
|
} // Target Qt Version ComboBox
|
||||||
|
|
||||||
|
Binding {
|
||||||
|
target: BackendApi
|
||||||
|
property: "targetQtVersionIndex"
|
||||||
|
value: qtVersionComboBox.currentIndex
|
||||||
|
}
|
||||||
|
|
||||||
} // RowLayout
|
} // RowLayout
|
||||||
|
|
||||||
Binding {
|
Binding {
|
||||||
target: dialogBox
|
target: BackendApi
|
||||||
property: "useVirtualKeyboard"
|
property: "useVirtualKeyboard"
|
||||||
value: useQtVirtualKeyboard.checked
|
value: useQtVirtualKeyboard.checked
|
||||||
}
|
}
|
||||||
} // ScrollContent Column
|
} // ScrollContent Column
|
||||||
} // ScrollView
|
} // ScrollView
|
||||||
|
|
||||||
} // Column
|
} // Column
|
||||||
|
|
||||||
|
SC.AbstractButton {
|
||||||
|
id: savePresetButton
|
||||||
|
width: StudioTheme.Values.singleControlColumnWidth
|
||||||
|
buttonIcon: qsTr("Save Custom Preset")
|
||||||
|
iconFont: StudioTheme.Constants.font
|
||||||
|
iconSize: DialogValues.defaultPixelSize
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
|
||||||
|
onClicked: savePresetDialog.open()
|
||||||
|
}
|
||||||
|
|
||||||
|
PopupDialog {
|
||||||
|
id: savePresetDialog
|
||||||
|
title: qsTr("Save Preset")
|
||||||
|
standardButtons: Dialog.Save | Dialog.Cancel
|
||||||
|
modal: true
|
||||||
|
closePolicy: Popup.CloseOnEscape
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: DialogValues.popupDialogWidth
|
||||||
|
|
||||||
|
onAccepted: BackendApi.savePresetDialogAccept()
|
||||||
|
|
||||||
|
onOpened: {
|
||||||
|
presetNameTextField.selectAll()
|
||||||
|
presetNameTextField.forceActiveFocus()
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
width: parent.width
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: qsTr("Preset name")
|
||||||
|
font.pixelSize: DialogValues.defaultPixelSize
|
||||||
|
color: DialogValues.textColor
|
||||||
|
}
|
||||||
|
|
||||||
|
SC.TextField {
|
||||||
|
id: presetNameTextField
|
||||||
|
actionIndicatorVisible: false
|
||||||
|
translationIndicatorVisible: false
|
||||||
|
text: qsTr("MyPreset")
|
||||||
|
color: DialogValues.textColor
|
||||||
|
font.pixelSize: DialogValues.defaultPixelSize
|
||||||
|
Layout.fillWidth: true
|
||||||
|
maximumLength: 30
|
||||||
|
validator: RegularExpressionValidator { regularExpression: /\w[\w ]*/ }
|
||||||
|
|
||||||
|
onEditingFinished: {
|
||||||
|
presetNameTextField.text = text.trim()
|
||||||
|
presetNameTextField.text = text.replace(/\s+/g, " ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Binding {
|
||||||
|
target: BackendApi
|
||||||
|
property: "presetName"
|
||||||
|
value: presetNameTextField.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} // Item
|
} // Item
|
||||||
}
|
} // Rectangle
|
||||||
}
|
} // root Item
|
||||||
|
@@ -29,39 +29,57 @@ import QtQml
|
|||||||
import StudioTheme as StudioTheme
|
import StudioTheme as StudioTheme
|
||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
|
id: root
|
||||||
|
|
||||||
readonly property int dialogWidth: 1522
|
readonly property int dialogWidth: 1522
|
||||||
readonly property int dialogHeight: 940
|
readonly property int dialogHeight: 940
|
||||||
readonly property int projectViewMinimumWidth: 600
|
readonly property int projectViewMinimumWidth: 600
|
||||||
readonly property int projectViewMinimumHeight: projectViewHeight
|
readonly property int projectViewMinimumHeight: root.gridCellHeight
|
||||||
readonly property int dialogContentHeight: projectViewHeight + 300 // i.e. dialog without header and footer
|
readonly property int dialogContentHeight: root.projectViewHeight + 300 // i.e. dialog without header and footer
|
||||||
readonly property int loadedPanesWidth: detailsPaneWidth + stylesPaneWidth
|
readonly property int loadedPanesWidth: root.detailsPaneWidth + root.stylesPaneWidth
|
||||||
readonly property int detailsPaneWidth: 330 + detailsPanePadding * 2
|
readonly property int detailsPaneWidth: 330 + root.detailsPanePadding * 2
|
||||||
readonly property int dialogTitleTextHeight: 85
|
readonly property int dialogTitleTextHeight: 85
|
||||||
readonly property int paneTitleTextHeight: 47
|
readonly property int paneTitleTextHeight: 47
|
||||||
readonly property int logoWidth: 85
|
readonly property int logoWidth: 85
|
||||||
readonly property int logoHeight: 85
|
readonly property int logoHeight: 85
|
||||||
|
|
||||||
/* detailsScrollableContentHeight - the full height that may need to be scrolled to be fully
|
readonly property int stylesPaneWidth: root.styleImageWidth + root.stylesPanePadding * 2
|
||||||
visible, if the dialog box is too small. */
|
+ root.styleImageBorderWidth * 2 // i.e. 240px
|
||||||
readonly property int detailsScrollableContentHeight: 428
|
|
||||||
readonly property int stylesPaneWidth: styleImageWidth + stylesPanePadding * 2 + styleImageBorderWidth * 2 // i.e. 240px
|
|
||||||
readonly property int detailsPanePadding: 18
|
readonly property int detailsPanePadding: 18
|
||||||
readonly property int stylesPanePadding: 18
|
readonly property int stylesPanePadding: 18
|
||||||
readonly property int defaultPadding: 18
|
readonly property int defaultPadding: 18
|
||||||
readonly property int dialogLeftPadding: 35
|
readonly property int dialogLeftPadding: 35
|
||||||
|
|
||||||
|
readonly property int styleListItemHeight: root.styleImageHeight + root.styleTextHeight
|
||||||
|
+ 2 * root.styleImageBorderWidth
|
||||||
|
+ root.styleListItemBottomMargin
|
||||||
|
+ root.styleListItemSpacing
|
||||||
|
readonly property int styleListItemBottomMargin: 10
|
||||||
|
readonly property int styleListItemSpacing: 4
|
||||||
readonly property int styleImageWidth: 200
|
readonly property int styleImageWidth: 200
|
||||||
|
readonly property int styleImageHeight: 262
|
||||||
readonly property int styleImageBorderWidth: 2
|
readonly property int styleImageBorderWidth: 2
|
||||||
|
readonly property int styleTextHeight: 18
|
||||||
|
|
||||||
readonly property int footerHeight: 73
|
readonly property int footerHeight: 73
|
||||||
readonly property int projectItemWidth: 90
|
readonly property int projectItemWidth: 136
|
||||||
readonly property int projectItemHeight: 144
|
readonly property int projectItemHeight: 110
|
||||||
readonly property int projectViewHeight: projectItemHeight * 2
|
property int projectViewHeight: root.projectItemHeight * 2 + root.gridSpacing + root.gridMargins * 2
|
||||||
readonly property int projectViewHeaderHeight: 38
|
readonly property int projectViewHeaderHeight: 38
|
||||||
|
|
||||||
|
readonly property int gridMargins: 20
|
||||||
|
readonly property int gridCellWidth: root.projectItemWidth + root.gridSpacing
|
||||||
|
readonly property int gridCellHeight: root.projectItemHeight + root.gridSpacing
|
||||||
|
readonly property int gridSpacing: 2
|
||||||
|
|
||||||
readonly property int dialogButtonWidth: 100
|
readonly property int dialogButtonWidth: 100
|
||||||
|
|
||||||
readonly property int loadedPanesHeight: dialogContentHeight
|
// This is for internal popup dialogs
|
||||||
readonly property int detailsPaneHeight: dialogContentHeight
|
readonly property int popupDialogWidth: 270
|
||||||
|
readonly property int popupDialogPadding: 12
|
||||||
|
|
||||||
|
readonly property int loadedPanesHeight: root.dialogContentHeight
|
||||||
|
readonly property int detailsPaneHeight: root.dialogContentHeight
|
||||||
|
|
||||||
readonly property string darkPaneColor: StudioTheme.Values.themeBackgroundColorNormal
|
readonly property string darkPaneColor: StudioTheme.Values.themeBackgroundColorNormal
|
||||||
readonly property string lightPaneColor: StudioTheme.Values.themeBackgroundColorAlternate
|
readonly property string lightPaneColor: StudioTheme.Values.themeBackgroundColorAlternate
|
||||||
@@ -71,6 +89,8 @@ QtObject {
|
|||||||
readonly property string dividerlineColor: StudioTheme.Values.themeTextColorDisabled
|
readonly property string dividerlineColor: StudioTheme.Values.themeTextColorDisabled
|
||||||
readonly property string textError: StudioTheme.Values.themeError
|
readonly property string textError: StudioTheme.Values.themeError
|
||||||
readonly property string textWarning: StudioTheme.Values.themeWarning
|
readonly property string textWarning: StudioTheme.Values.themeWarning
|
||||||
|
readonly property string presetItemBackgroundHover: StudioTheme.Values.themeControlBackgroundGlobalHover
|
||||||
|
readonly property string presetItemBackgroundHoverInteraction: StudioTheme.Values.themeControlBackgroundInteraction
|
||||||
|
|
||||||
readonly property real defaultPixelSize: 14
|
readonly property real defaultPixelSize: 14
|
||||||
readonly property real defaultLineHeight: 21
|
readonly property real defaultLineHeight: 21
|
||||||
@@ -91,6 +111,6 @@ QtObject {
|
|||||||
item and spacing after it). So we have to subtract 2 x layout spacing before setting
|
item and spacing after it). So we have to subtract 2 x layout spacing before setting
|
||||||
our own, narrower, spacing.
|
our own, narrower, spacing.
|
||||||
*/
|
*/
|
||||||
return -layoutSpacing -layoutSpacing + value
|
return -layoutSpacing - layoutSpacing + value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -28,111 +28,252 @@ import QtQuick.Controls
|
|||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
import StudioControls as SC
|
||||||
import StudioTheme as StudioTheme
|
import StudioTheme as StudioTheme
|
||||||
|
|
||||||
GridView {
|
import BackendApi
|
||||||
id: projectView
|
|
||||||
|
ScrollView {
|
||||||
|
id: scrollView
|
||||||
|
|
||||||
required property Item loader
|
required property Item loader
|
||||||
|
required property string currentTabName
|
||||||
|
|
||||||
cellWidth: DialogValues.projectItemWidth
|
property string backgroundHoverColor: DialogValues.presetItemBackgroundHover
|
||||||
cellHeight: DialogValues.projectItemHeight
|
|
||||||
clip: true
|
|
||||||
|
|
||||||
boundsBehavior: Flickable.StopAtBounds
|
// selectLast: if true, it will select last item in the model after a model reset.
|
||||||
|
property bool selectLast: false
|
||||||
|
|
||||||
children: [
|
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
|
||||||
Rectangle {
|
ScrollBar.vertical: SC.VerticalScrollBar {
|
||||||
color: DialogValues.darkPaneColor
|
parent: scrollView
|
||||||
anchors.fill: parent
|
x: scrollView.width + (DialogValues.gridMargins
|
||||||
z: -1
|
- StudioTheme.Values.scrollBarThickness) * 0.5
|
||||||
}
|
y: scrollView.topPadding
|
||||||
]
|
height: scrollView.availableHeight
|
||||||
|
|
||||||
model: presetModel
|
|
||||||
|
|
||||||
// called by onModelReset and when user clicks on an item, or when the header item is changed.
|
|
||||||
onCurrentIndexChanged: {
|
|
||||||
dialogBox.selectedPreset = projectView.currentIndex
|
|
||||||
var source = dialogBox.currentPresetQmlPath()
|
|
||||||
loader.source = source
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
contentWidth: gridView.contentItem.childrenRect.width
|
||||||
target: presetModel
|
contentHeight: gridView.contentItem.childrenRect.height
|
||||||
|
|
||||||
// called when data is set (setWizardFactories)
|
GridView {
|
||||||
function onModelReset() {
|
id: gridView
|
||||||
currentIndex = 0
|
|
||||||
currentIndexChanged()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
delegate: ItemDelegate {
|
clip: true
|
||||||
id: delegate
|
anchors.fill: parent
|
||||||
|
cellWidth: DialogValues.gridCellWidth
|
||||||
|
cellHeight: DialogValues.gridCellHeight
|
||||||
|
rightMargin: -DialogValues.gridSpacing
|
||||||
|
bottomMargin: -DialogValues.gridSpacing
|
||||||
|
boundsBehavior: Flickable.StopAtBounds
|
||||||
|
model: BackendApi.presetModel
|
||||||
|
|
||||||
width: DialogValues.projectItemWidth
|
// called by onModelReset and when user clicks on an item, or when the header item is changed.
|
||||||
height: DialogValues.projectItemHeight
|
onCurrentIndexChanged: {
|
||||||
background: null
|
BackendApi.selectedPreset = gridView.currentIndex
|
||||||
|
var source = BackendApi.currentPresetQmlPath()
|
||||||
function fontIconCode(index) {
|
scrollView.loader.source = source
|
||||||
var code = presetModel.fontIconCode(index)
|
|
||||||
return code ? code : StudioTheme.Constants.wizardsUnknown
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Column {
|
Connections {
|
||||||
width: parent.width
|
target: BackendApi.presetModel
|
||||||
height: parent.height
|
|
||||||
|
|
||||||
Label {
|
// called when data is set (setWizardFactories)
|
||||||
id: projectTypeIcon
|
function onModelReset() {
|
||||||
text: fontIconCode(index)
|
if (scrollView.selectLast) {
|
||||||
color: DialogValues.textColor
|
gridView.currentIndex = BackendApi.presetModel.rowCount() - 1
|
||||||
width: parent.width
|
scrollView.selectLast = false
|
||||||
height: DialogValues.projectItemHeight / 2
|
} else {
|
||||||
horizontalAlignment: Text.AlignHCenter
|
gridView.currentIndex = 0
|
||||||
verticalAlignment: Text.AlignBottom
|
}
|
||||||
renderType: Text.NativeRendering
|
|
||||||
font.pixelSize: 65
|
// This will load Details.qml and Styles.qml by setting "source" on the Loader.
|
||||||
font.family: StudioTheme.Constants.iconFont.family
|
gridView.currentIndexChanged()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delegate: ItemDelegate {
|
||||||
|
id: delegate
|
||||||
|
|
||||||
|
property bool hover: delegate.hovered || removeMouseArea.containsMouse
|
||||||
|
|
||||||
|
width: DialogValues.projectItemWidth
|
||||||
|
height: DialogValues.projectItemHeight
|
||||||
|
|
||||||
|
onClicked: delegate.GridView.view.currentIndex = index
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
id: delegateBackground
|
||||||
|
width: parent.width
|
||||||
|
height: parent.height
|
||||||
|
color: delegate.hover ? scrollView.backgroundHoverColor : "transparent"
|
||||||
|
border.color: delegate.hover ? projectTypeName.color : "transparent"
|
||||||
|
}
|
||||||
|
|
||||||
|
function fontIconCode(index) {
|
||||||
|
var code = BackendApi.presetModel.fontIconCode(index)
|
||||||
|
return code ? code : StudioTheme.Constants.wizardsUnknown
|
||||||
|
}
|
||||||
|
|
||||||
|
contentItem: Item {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
spacing: 0
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.topMargin: -1
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
|
||||||
|
Label {
|
||||||
|
id: projectTypeIcon
|
||||||
|
text: delegate.fontIconCode(index)
|
||||||
|
color: DialogValues.textColor
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
verticalAlignment: Text.AlignBottom
|
||||||
|
renderType: Text.NativeRendering
|
||||||
|
font.pixelSize: 65
|
||||||
|
font.family: StudioTheme.Constants.iconFont.family
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
} // Preset type icon Label
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: projectTypeName
|
||||||
|
color: DialogValues.textColor
|
||||||
|
text: name
|
||||||
|
font.pixelSize: DialogValues.defaultPixelSize
|
||||||
|
lineHeight: DialogValues.defaultLineHeight
|
||||||
|
lineHeightMode: Text.FixedHeight
|
||||||
|
width: DialogValues.projectItemWidth - 16
|
||||||
|
elide: Text.ElideRight
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
verticalAlignment: Text.AlignTop
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
Layout.preferredWidth: projectTypeName.width
|
||||||
|
Layout.minimumWidth: projectTypeName.width
|
||||||
|
Layout.maximumWidth: projectTypeName.width
|
||||||
|
|
||||||
|
ToolTip {
|
||||||
|
id: toolTip
|
||||||
|
y: -toolTip.height
|
||||||
|
visible: delegate.hovered && projectTypeName.truncated
|
||||||
|
text: name
|
||||||
|
delay: 1000
|
||||||
|
height: 20
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
color: StudioTheme.Values.themeToolTipBackground
|
||||||
|
border.color: StudioTheme.Values.themeToolTipOutline
|
||||||
|
border.width: StudioTheme.Values.border
|
||||||
|
}
|
||||||
|
|
||||||
|
contentItem: Text {
|
||||||
|
color: StudioTheme.Values.themeToolTipText
|
||||||
|
text: toolTip.text
|
||||||
|
font.pixelSize: DialogValues.defaultPixelSize
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: projectTypeResolution
|
||||||
|
color: DialogValues.textColor
|
||||||
|
text: resolution
|
||||||
|
font.pixelSize: DialogValues.defaultPixelSize
|
||||||
|
lineHeight: DialogValues.defaultLineHeight
|
||||||
|
lineHeightMode: Text.FixedHeight
|
||||||
|
wrapMode: Text.Wrap
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
verticalAlignment: Text.AlignTop
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
} // ColumnLayout
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: removePresetButton
|
||||||
|
width: 20
|
||||||
|
height: 20
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.margins: 4
|
||||||
|
visible: isUserPreset === true
|
||||||
|
&& delegate.hover
|
||||||
|
&& scrollView.currentTabName !== "Recents"
|
||||||
|
|
||||||
|
Text {
|
||||||
|
anchors.fill: parent
|
||||||
|
text: StudioTheme.Constants.closeCross
|
||||||
|
color: DialogValues.textColor
|
||||||
|
horizontalAlignment: Qt.AlignHCenter
|
||||||
|
verticalAlignment: Qt.AlignVCenter
|
||||||
|
font.family: StudioTheme.Constants.iconFont.family
|
||||||
|
font.pixelSize: StudioTheme.Values.myIconFontSize
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: removeMouseArea
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: removeMouseArea.containsMouse ? Qt.PointingHandCursor
|
||||||
|
: Qt.ArrowCursor
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
removePresetDialog.presetName = projectTypeName.text
|
||||||
|
removePresetDialog.open()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // Delete preset button Item
|
||||||
|
} // Item
|
||||||
|
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
name: "current"
|
||||||
|
when: delegate.GridView.isCurrentItem
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
target: projectTypeName
|
||||||
|
color: DialogValues.textColorInteraction
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: projectTypeResolution
|
||||||
|
color: DialogValues.textColorInteraction
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: projectTypeIcon
|
||||||
|
color: DialogValues.textColorInteraction
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: scrollView
|
||||||
|
backgroundHoverColor: DialogValues.presetItemBackgroundHoverInteraction
|
||||||
|
}
|
||||||
|
} // State
|
||||||
|
]
|
||||||
|
} // ItemDelegate
|
||||||
|
|
||||||
|
PopupDialog {
|
||||||
|
id: removePresetDialog
|
||||||
|
|
||||||
|
property string presetName
|
||||||
|
|
||||||
|
title: qsTr("Delete Custom Preset")
|
||||||
|
standardButtons: Dialog.Yes | Dialog.No
|
||||||
|
modal: true
|
||||||
|
closePolicy: Popup.CloseOnEscape
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: DialogValues.popupDialogWidth
|
||||||
|
|
||||||
|
onAccepted: BackendApi.removeCurrentPreset()
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: projectTypeLabel
|
text: qsTr("Are you sure you want to delete \"" + removePresetDialog.presetName + "\" ?")
|
||||||
color: DialogValues.textColor
|
color: DialogValues.textColor
|
||||||
|
|
||||||
text: name
|
|
||||||
font.pixelSize: DialogValues.defaultPixelSize
|
font.pixelSize: DialogValues.defaultPixelSize
|
||||||
lineHeight: DialogValues.defaultLineHeight
|
wrapMode: Text.WordWrap
|
||||||
lineHeightMode: Text.FixedHeight
|
|
||||||
width: parent.width
|
width: DialogValues.popupDialogWidth - 2 * DialogValues.popupDialogPadding
|
||||||
height: DialogValues.projectItemHeight / 2
|
|
||||||
wrapMode: Text.Wrap
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
verticalAlignment: Text.AlignTop
|
|
||||||
}
|
}
|
||||||
} // Column
|
|
||||||
|
|
||||||
MouseArea {
|
} // Dialog
|
||||||
anchors.fill: parent
|
} // GridView
|
||||||
onClicked: {
|
} // ScrollView
|
||||||
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,66 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2022 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
import StudioTheme as StudioTheme
|
||||||
|
|
||||||
|
import BackendApi
|
||||||
|
|
||||||
|
Dialog {
|
||||||
|
id: root
|
||||||
|
padding: DialogValues.popupDialogPadding
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
color: DialogValues.darkPaneColor
|
||||||
|
border.color: StudioTheme.Values.themeInteraction
|
||||||
|
border.width: StudioTheme.Values.border
|
||||||
|
}
|
||||||
|
|
||||||
|
header: Label {
|
||||||
|
text: root.title
|
||||||
|
visible: root.title
|
||||||
|
elide: Label.ElideRight
|
||||||
|
font.bold: true
|
||||||
|
font.pixelSize: DialogValues.defaultPixelSize
|
||||||
|
padding: DialogValues.popupDialogPadding
|
||||||
|
color: DialogValues.textColor
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
x: 1
|
||||||
|
y: 1
|
||||||
|
width: parent.width - 2
|
||||||
|
height: parent.height - 1
|
||||||
|
color: DialogValues.darkPaneColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
footer: PopupDialogButtonBox {
|
||||||
|
visible: count > 0
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,107 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2022 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import StudioTheme as StudioTheme
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
implicitWidth: Math.max(
|
||||||
|
background ? background.implicitWidth : 0,
|
||||||
|
textItem.implicitWidth + leftPadding + rightPadding)
|
||||||
|
implicitHeight: Math.max(
|
||||||
|
background ? background.implicitHeight : 0,
|
||||||
|
textItem.implicitHeight + topPadding + bottomPadding)
|
||||||
|
leftPadding: 4
|
||||||
|
rightPadding: 4
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
id: background
|
||||||
|
implicitWidth: 80
|
||||||
|
implicitHeight: StudioTheme.Values.height
|
||||||
|
color: StudioTheme.Values.themeControlBackground
|
||||||
|
border.color: StudioTheme.Values.themeControlOutline
|
||||||
|
anchors.fill: parent
|
||||||
|
}
|
||||||
|
|
||||||
|
contentItem: Text {
|
||||||
|
id: textItem
|
||||||
|
text: root.text
|
||||||
|
font.family: StudioTheme.Constants.font.family
|
||||||
|
font.pixelSize: DialogValues.defaultPixelSize
|
||||||
|
color: StudioTheme.Values.themeTextColor
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
renderType: Text.QtRendering
|
||||||
|
anchors.fill: parent
|
||||||
|
}
|
||||||
|
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
name: "default"
|
||||||
|
when: !root.hovered && !root.checked && !root.pressed
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
target: background
|
||||||
|
color: StudioTheme.Values.themeControlBackground
|
||||||
|
border.color: StudioTheme.Values.themeControlOutline
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: textItem
|
||||||
|
color: StudioTheme.Values.themeTextColor
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "hover"
|
||||||
|
when: root.hovered && !root.checked && !root.pressed
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
target: background
|
||||||
|
color: StudioTheme.Values.themeControlBackgroundHover
|
||||||
|
border.color: StudioTheme.Values.themeControlOutline
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: textItem
|
||||||
|
color: StudioTheme.Values.themeTextColor
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "press"
|
||||||
|
when: root.hovered && root.pressed
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
target: background
|
||||||
|
color: StudioTheme.Values.themeInteraction
|
||||||
|
border.color: StudioTheme.Values.themeInteraction
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: textItem
|
||||||
|
color: StudioTheme.Values.themeIconColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@@ -0,0 +1,46 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2022 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
|
||||||
|
DialogButtonBox {
|
||||||
|
id: root
|
||||||
|
padding: DialogValues.popupDialogPadding
|
||||||
|
alignment: Qt.AlignRight | Qt.AlignBottom
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
implicitHeight: 40
|
||||||
|
x: 1
|
||||||
|
y: 1
|
||||||
|
width: parent.width - 2
|
||||||
|
height: parent.height - 2
|
||||||
|
color: DialogValues.darkPaneColor
|
||||||
|
}
|
||||||
|
|
||||||
|
delegate: PopupDialogButton {
|
||||||
|
width: root.count === 1 ? root.availableWidth / 2 : undefined
|
||||||
|
}
|
||||||
|
}
|
@@ -23,20 +23,21 @@
|
|||||||
**
|
**
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
import QtQuick.Window
|
import QtQuick.Window
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
|
|
||||||
import QtQuick
|
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
|
||||||
import StudioControls as SC
|
import StudioControls as SC
|
||||||
import StudioTheme as StudioTheme
|
import StudioTheme as StudioTheme
|
||||||
|
|
||||||
|
import BackendApi
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
width: DialogValues.stylesPaneWidth
|
width: DialogValues.stylesPaneWidth
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
dialogBox.stylesLoaded = true;
|
BackendApi.stylesLoaded = true
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TODO: roleNames is called before the backend model (in the proxy class StyleModel) is
|
* TODO: roleNames is called before the backend model (in the proxy class StyleModel) is
|
||||||
@@ -47,7 +48,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Component.onDestruction: {
|
Component.onDestruction: {
|
||||||
dialogBox.stylesLoaded = false;
|
BackendApi.stylesLoaded = false
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
@@ -57,116 +58,120 @@ Item {
|
|||||||
|
|
||||||
Item {
|
Item {
|
||||||
x: DialogValues.stylesPanePadding
|
x: DialogValues.stylesPanePadding
|
||||||
width: parent.width - DialogValues.stylesPanePadding * 2 + styleScrollBar.width
|
width: parent.width - DialogValues.stylesPanePadding * 2
|
||||||
height: parent.height
|
height: parent.height
|
||||||
|
|
||||||
ColumnLayout {
|
Text {
|
||||||
anchors.fill: parent
|
id: styleTitleText
|
||||||
spacing: 5
|
text: qsTr("Style")
|
||||||
|
height: DialogValues.paneTitleTextHeight
|
||||||
|
width: parent.width
|
||||||
|
font.weight: Font.DemiBold
|
||||||
|
font.pixelSize: DialogValues.paneTitlePixelSize
|
||||||
|
lineHeight: DialogValues.paneTitleLineHeight
|
||||||
|
lineHeightMode: Text.FixedHeight
|
||||||
|
color: DialogValues.textColor
|
||||||
|
verticalAlignment: Qt.AlignVCenter
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
Text {
|
function refresh() {
|
||||||
id: styleTitleText
|
styleTitleText.text = qsTr("Style") + " (" + BackendApi.styleModel.rowCount() + ")"
|
||||||
text: qsTr("Style")
|
}
|
||||||
Layout.minimumHeight: DialogValues.paneTitleTextHeight
|
}
|
||||||
font.weight: Font.DemiBold
|
|
||||||
font.pixelSize: DialogValues.paneTitlePixelSize
|
|
||||||
lineHeight: DialogValues.paneTitleLineHeight
|
|
||||||
lineHeightMode: Text.FixedHeight
|
|
||||||
color: DialogValues.textColor
|
|
||||||
verticalAlignment: Qt.AlignVCenter
|
|
||||||
|
|
||||||
function refresh() {
|
SC.ComboBox { // Style Filter ComboBox
|
||||||
text = qsTr("Style") + " (" + styleModel.rowCount() + ")"
|
id: styleComboBox
|
||||||
}
|
actionIndicatorVisible: false
|
||||||
|
currentIndex: 0
|
||||||
|
textRole: "text"
|
||||||
|
valueRole: "value"
|
||||||
|
font.pixelSize: DialogValues.defaultPixelSize
|
||||||
|
width: parent.width
|
||||||
|
|
||||||
|
anchors.top: styleTitleText.bottom
|
||||||
|
anchors.topMargin: 5
|
||||||
|
|
||||||
|
model: ListModel {
|
||||||
|
ListElement { text: qsTr("All"); value: "all" }
|
||||||
|
ListElement { text: qsTr("Light"); value: "light" }
|
||||||
|
ListElement { text: qsTr("Dark"); value: "dark" }
|
||||||
}
|
}
|
||||||
|
|
||||||
SC.ComboBox { // Style Filter ComboBox
|
onActivated: (index) => {
|
||||||
actionIndicatorVisible: false
|
BackendApi.styleModel.filter(currentValue.toLowerCase())
|
||||||
currentIndex: 0
|
styleTitleText.refresh()
|
||||||
textRole: "text"
|
}
|
||||||
valueRole: "value"
|
} // Style Filter ComboBox
|
||||||
font.pixelSize: DialogValues.defaultPixelSize
|
|
||||||
|
|
||||||
model: ListModel {
|
ScrollView {
|
||||||
ListElement { text: qsTr("All"); value: "all" }
|
id: scrollView
|
||||||
ListElement { text: qsTr("Light"); value: "light" }
|
|
||||||
ListElement { text: qsTr("Dark"); value: "dark" }
|
|
||||||
}
|
|
||||||
|
|
||||||
implicitWidth: parent.width
|
anchors.top: styleComboBox.bottom
|
||||||
|
anchors.topMargin: 11
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.bottomMargin: DialogValues.stylesPanePadding
|
||||||
|
width: parent.width
|
||||||
|
|
||||||
onActivated: (index) => {
|
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
|
||||||
styleModel.filter(currentValue.toLowerCase());
|
ScrollBar.vertical: SC.VerticalScrollBar {
|
||||||
styleTitleText.refresh();
|
id: styleScrollBar
|
||||||
}
|
x: stylesList.width + (DialogValues.stylesPanePadding
|
||||||
} // Style Filter ComboBox
|
- StudioTheme.Values.scrollBarThickness) * 0.5
|
||||||
|
}
|
||||||
Item { implicitWidth: 1; implicitHeight: 9 }
|
|
||||||
|
|
||||||
ListView {
|
ListView {
|
||||||
id: stylesList
|
id: stylesList
|
||||||
Layout.fillWidth: true
|
anchors.fill: parent
|
||||||
Layout.fillHeight: true
|
|
||||||
clip: true
|
|
||||||
model: styleModel
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: listViewMouseArea
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
propagateComposedEvents: true
|
|
||||||
}
|
|
||||||
|
|
||||||
focus: true
|
focus: true
|
||||||
|
clip: true
|
||||||
|
model: BackendApi.styleModel
|
||||||
boundsBehavior: Flickable.StopAtBounds
|
boundsBehavior: Flickable.StopAtBounds
|
||||||
|
|
||||||
highlightFollowsCurrentItem: false
|
highlightFollowsCurrentItem: false
|
||||||
|
bottomMargin: -DialogValues.styleListItemBottomMargin
|
||||||
ScrollBar.vertical: SC.VerticalScrollBar {
|
|
||||||
id: styleScrollBar
|
|
||||||
property int extraPadding: 0
|
|
||||||
bottomInset: extraPadding
|
|
||||||
bottomPadding: bottomInset + 16
|
|
||||||
viewMouseArea: listViewMouseArea
|
|
||||||
} // ScrollBar
|
|
||||||
|
|
||||||
onCurrentIndexChanged: {
|
onCurrentIndexChanged: {
|
||||||
if (styleModel.rowCount() > 0)
|
if (BackendApi.styleModel.rowCount() > 0)
|
||||||
dialogBox.styleIndex = stylesList.currentIndex;
|
BackendApi.styleIndex = stylesList.currentIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate: ItemDelegate {
|
delegate: ItemDelegate {
|
||||||
id: delegateId
|
id: delegateId
|
||||||
height: styleImage.height + DialogValues.styleImageBorderWidth + styleText.height + extraPadding.height + 1
|
width: stylesList.width
|
||||||
width: stylesList.width - styleScrollBar.width
|
height: DialogValues.styleListItemHeight
|
||||||
|
|
||||||
Component.onCompleted: {
|
onClicked: stylesList.currentIndex = index
|
||||||
styleScrollBar.extraPadding = styleText.height + extraPadding.height
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
background: Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
color: DialogValues.lightPaneColor
|
color: DialogValues.lightPaneColor
|
||||||
|
}
|
||||||
|
|
||||||
|
contentItem: Item {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
spacing: 0
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
spacing: DialogValues.styleListItemSpacing
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
border.color: index == stylesList.currentIndex ? DialogValues.textColorInteraction : "transparent"
|
width: DialogValues.styleImageWidth
|
||||||
border.width: index == stylesList.currentIndex ? DialogValues.styleImageBorderWidth : 0
|
+ 2 * DialogValues.styleImageBorderWidth
|
||||||
|
height: DialogValues.styleImageHeight
|
||||||
|
+ 2 * DialogValues.styleImageBorderWidth
|
||||||
|
border.color: index === stylesList.currentIndex ? DialogValues.textColorInteraction : "transparent"
|
||||||
|
border.width: index === stylesList.currentIndex ? DialogValues.styleImageBorderWidth : 0
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
width: parent.width
|
|
||||||
height: parent.height - styleText.height - extraPadding.height
|
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
id: styleImage
|
id: styleImage
|
||||||
asynchronous: false
|
|
||||||
source: "image://newprojectdialog_library/" + styleModel.iconId(model.index)
|
|
||||||
width: 200
|
|
||||||
height: 262
|
|
||||||
x: DialogValues.styleImageBorderWidth
|
x: DialogValues.styleImageBorderWidth
|
||||||
y: DialogValues.styleImageBorderWidth
|
y: DialogValues.styleImageBorderWidth
|
||||||
|
width: DialogValues.styleImageWidth
|
||||||
|
height: DialogValues.styleImageHeight
|
||||||
|
asynchronous: false
|
||||||
|
source: "image://newprojectdialog_library/" + BackendApi.styleModel.iconId(model.index)
|
||||||
}
|
}
|
||||||
} // Rectangle
|
} // Rectangle
|
||||||
|
|
||||||
@@ -175,35 +180,26 @@ Item {
|
|||||||
text: model.display
|
text: model.display
|
||||||
font.pixelSize: DialogValues.defaultPixelSize
|
font.pixelSize: DialogValues.defaultPixelSize
|
||||||
lineHeight: DialogValues.defaultLineHeight
|
lineHeight: DialogValues.defaultLineHeight
|
||||||
height: 18
|
height: DialogValues.styleTextHeight
|
||||||
lineHeightMode: Text.FixedHeight
|
lineHeightMode: Text.FixedHeight
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
width: parent.width
|
width: parent.width
|
||||||
color: DialogValues.textColor
|
color: DialogValues.textColor
|
||||||
}
|
}
|
||||||
|
|
||||||
Item { id: extraPadding; width: 1; height: 10 }
|
|
||||||
} // Column
|
} // Column
|
||||||
} // Rectangle
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
onClicked: {
|
|
||||||
stylesList.currentIndex = index
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: styleModel
|
target: BackendApi.styleModel
|
||||||
function onModelReset() {
|
function onModelReset() {
|
||||||
stylesList.currentIndex = dialogBox.styleIndex;
|
stylesList.currentIndex = BackendApi.styleIndex
|
||||||
stylesList.currentIndexChanged();
|
stylesList.currentIndexChanged()
|
||||||
styleTitleText.refresh();
|
styleTitleText.refresh()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // ListView
|
} // ListView
|
||||||
} // ColumnLayout
|
} // ScrollView
|
||||||
} // Parent Item
|
} // Parent Item
|
||||||
} // Rectangle
|
} // Rectangle
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,7 @@
|
|||||||
singleton DialogValues 1.0 DialogValues.qml
|
PopupDialog 1.0 PopupDialog.qml
|
||||||
|
PopupDialogButton 1.0 PopupDialogButton.qml
|
||||||
|
PopupDialogButtonBox 1.0 PopupDialogButtonBox.qml
|
||||||
Details 1.0 Details.qml
|
Details 1.0 Details.qml
|
||||||
Styles 1.0 Styles.qml
|
singleton DialogValues 1.0 DialogValues.qml
|
||||||
NewProjectView 1.0 NewProjectView.qml
|
NewProjectView 1.0 NewProjectView.qml
|
||||||
|
Styles 1.0 Styles.qml
|
||||||
|
@@ -35,37 +35,26 @@ ScrollBar {
|
|||||||
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
|
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
|
||||||
implicitContentHeight + topPadding + bottomPadding)
|
implicitContentHeight + topPadding + bottomPadding)
|
||||||
|
|
||||||
property bool scrollBarVisible: parent.childrenRect.height > parent.height
|
property bool scrollBarVisible: parent.contentHeight > scrollBar.height
|
||||||
// viewMouseArea: if set, the scrollbar will be visible only on hover over the view containing
|
|
||||||
// the mouse area item.
|
|
||||||
property MouseArea viewMouseArea: null
|
|
||||||
|
|
||||||
minimumSize: orientation == Qt.Horizontal ? height / width : width / height
|
|
||||||
|
|
||||||
|
minimumSize: scrollBar.width / scrollBar.height
|
||||||
orientation: Qt.Vertical
|
orientation: Qt.Vertical
|
||||||
policy: computePolicy()
|
policy: scrollBar.scrollBarVisible ? ScrollBar.AlwaysOn : ScrollBar.AlwaysOff
|
||||||
x: parent.width - width
|
|
||||||
y: 0
|
|
||||||
height: parent.availableHeight
|
height: parent.availableHeight
|
||||||
- (parent.bothVisible ? parent.horizontalThickness : 0)
|
- (parent.bothVisible ? parent.horizontalThickness : 0)
|
||||||
padding: 0
|
padding: scrollBar.active ? StudioTheme.Values.scrollBarActivePadding
|
||||||
|
: StudioTheme.Values.scrollBarInactivePadding
|
||||||
|
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
|
implicitWidth: StudioTheme.Values.scrollBarThickness
|
||||||
|
implicitHeight: StudioTheme.Values.scrollBarThickness
|
||||||
color: StudioTheme.Values.themeScrollBarTrack
|
color: StudioTheme.Values.themeScrollBarTrack
|
||||||
}
|
}
|
||||||
|
|
||||||
contentItem: Rectangle {
|
contentItem: Rectangle {
|
||||||
implicitWidth: StudioTheme.Values.scrollBarThickness
|
implicitWidth: StudioTheme.Values.scrollBarThickness - 2 * scrollBar.padding
|
||||||
|
implicitHeight: StudioTheme.Values.scrollBarThickness - 2 * scrollBar.padding
|
||||||
color: StudioTheme.Values.themeScrollBarHandle
|
color: StudioTheme.Values.themeScrollBarHandle
|
||||||
}
|
}
|
||||||
|
|
||||||
function computePolicy() {
|
|
||||||
if (!scrollBar.scrollBarVisible)
|
|
||||||
return ScrollBar.AlwaysOff;
|
|
||||||
|
|
||||||
if (scrollBar.viewMouseArea)
|
|
||||||
return scrollBar.viewMouseArea.containsMouse ? ScrollBar.AlwaysOn : ScrollBar.AlwaysOff
|
|
||||||
else
|
|
||||||
return ScrollBar.AlwaysOn;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -89,6 +89,8 @@ QtObject {
|
|||||||
property real typeLabelVerticalShift: Math.round(6 * values.scaleFactor)
|
property real typeLabelVerticalShift: Math.round(6 * values.scaleFactor)
|
||||||
|
|
||||||
property real scrollBarThickness: 10
|
property real scrollBarThickness: 10
|
||||||
|
property real scrollBarActivePadding: 1
|
||||||
|
property real scrollBarInactivePadding: 2
|
||||||
|
|
||||||
property real toolTipHeight: 25
|
property real toolTipHeight: 25
|
||||||
property int toolTipDelay: 1000
|
property int toolTipDelay: 1000
|
||||||
|
@@ -14,6 +14,7 @@ add_qtc_plugin(StudioWelcome
|
|||||||
createproject.cpp createproject.h
|
createproject.cpp createproject.h
|
||||||
wizardhandler.cpp wizardhandler.h
|
wizardhandler.cpp wizardhandler.h
|
||||||
recentpresets.cpp recentpresets.h
|
recentpresets.cpp recentpresets.h
|
||||||
|
userpresets.cpp userpresets.h
|
||||||
screensizemodel.h
|
screensizemodel.h
|
||||||
algorithm.h
|
algorithm.h
|
||||||
stylemodel.h stylemodel.cpp
|
stylemodel.h stylemodel.cpp
|
||||||
|
@@ -25,22 +25,30 @@
|
|||||||
|
|
||||||
#include "presetmodel.h"
|
#include "presetmodel.h"
|
||||||
#include <utils/optional.h>
|
#include <utils/optional.h>
|
||||||
#include <utils/qtcassert.h>
|
|
||||||
|
|
||||||
#include "algorithm.h"
|
#include "algorithm.h"
|
||||||
|
|
||||||
using namespace StudioWelcome;
|
using namespace StudioWelcome;
|
||||||
|
|
||||||
|
constexpr int NameRole = Qt::UserRole;
|
||||||
|
constexpr int ScreenSizeRole = Qt::UserRole + 1;
|
||||||
|
constexpr int IsUserPresetRole = Qt::UserRole + 2;
|
||||||
|
|
||||||
|
static const QString RecentsTabName = QObject::tr("Recents");
|
||||||
|
static const QString CustomTabName = QObject::tr("Custom");
|
||||||
|
|
||||||
/****************** PresetData ******************/
|
/****************** PresetData ******************/
|
||||||
|
|
||||||
void PresetData::setData(const PresetsByCategory &presetsByCategory,
|
void PresetData::setData(const PresetsByCategory &presetsByCategory,
|
||||||
const std::vector<RecentPreset> &loadedRecents)
|
const std::vector<UserPresetData> &userPresetsData,
|
||||||
|
const std::vector<RecentPresetData> &loadedRecentsData)
|
||||||
{
|
{
|
||||||
QTC_ASSERT(!presetsByCategory.empty(), return);
|
QTC_ASSERT(!presetsByCategory.empty(), return );
|
||||||
m_recents = loadedRecents;
|
m_recents = loadedRecentsData;
|
||||||
|
m_userPresets = userPresetsData;
|
||||||
|
|
||||||
if (!m_recents.empty()) {
|
if (!m_recents.empty()) {
|
||||||
m_categories.push_back("Recents");
|
m_categories.push_back(RecentsTabName);
|
||||||
m_presets.push_back({});
|
m_presets.push_back({});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,28 +57,95 @@ void PresetData::setData(const PresetsByCategory &presetsByCategory,
|
|||||||
m_presets.push_back(category.items);
|
m_presets.push_back(category.items);
|
||||||
}
|
}
|
||||||
|
|
||||||
PresetItems presets = Utils::flatten(m_presets);
|
PresetItems wizardPresets = Utils::flatten(m_presets);
|
||||||
|
|
||||||
std::vector<PresetItem> recentPresets = makeRecentPresets(presets);
|
PresetItems recentPresets = makeRecentPresets(wizardPresets);
|
||||||
|
if (!m_recents.empty()) {
|
||||||
if (!m_recents.empty())
|
|
||||||
m_presets[0] = recentPresets;
|
m_presets[0] = recentPresets;
|
||||||
|
}
|
||||||
|
|
||||||
|
PresetItems userPresetItems = makeUserPresets(wizardPresets);
|
||||||
|
if (!userPresetItems.empty()) {
|
||||||
|
m_categories.push_back(CustomTabName);
|
||||||
|
m_presets.push_back(userPresetItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_presetsByCategory = presetsByCategory;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<PresetItem> PresetData::makeRecentPresets(const PresetItems &wizardPresets)
|
void PresetData::reload(const std::vector<UserPresetData> &userPresetsData,
|
||||||
|
const std::vector<RecentPresetData> &loadedRecentsData)
|
||||||
{
|
{
|
||||||
static const PresetItem empty;
|
m_categories.clear();
|
||||||
|
m_presets.clear();
|
||||||
|
m_recents.clear();
|
||||||
|
m_userPresets.clear();
|
||||||
|
setData(m_presetsByCategory, userPresetsData, loadedRecentsData);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<PresetItem> PresetData::findPresetItemForUserPreset(const UserPresetData &preset,
|
||||||
|
const PresetItems &wizardPresets)
|
||||||
|
{
|
||||||
|
return Utils::findOrDefault(wizardPresets, [&preset](const std::shared_ptr<PresetItem> &item) {
|
||||||
|
return item->wizardName == preset.wizardName && item->categoryId == preset.categoryId;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
PresetItems PresetData::makeUserPresets(const PresetItems &wizardPresets)
|
||||||
|
{
|
||||||
PresetItems result;
|
PresetItems result;
|
||||||
|
|
||||||
for (const RecentPreset &recent : m_recents) {
|
for (const UserPresetData &userPresetData : m_userPresets) {
|
||||||
auto item = Utils::findOptional(wizardPresets, [&recent](const PresetItem &item) {
|
std::shared_ptr<PresetItem> foundPreset = findPresetItemForUserPreset(userPresetData,
|
||||||
return item.categoryId == std::get<0>(recent) && item.name == std::get<1>(recent);
|
wizardPresets);
|
||||||
});
|
if (!foundPreset)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (item) {
|
auto presetItem = std::make_shared<UserPresetItem>();
|
||||||
item->screenSizeName = std::get<2>(recent);
|
|
||||||
result.push_back(item.value());
|
presetItem->categoryId = userPresetData.categoryId;
|
||||||
|
presetItem->wizardName = userPresetData.wizardName;
|
||||||
|
presetItem->screenSizeName = userPresetData.screenSize;
|
||||||
|
|
||||||
|
presetItem->userName = userPresetData.name;
|
||||||
|
presetItem->qtVersion = userPresetData.qtVersion;
|
||||||
|
presetItem->styleName = userPresetData.styleName;
|
||||||
|
presetItem->useQtVirtualKeyboard = userPresetData.useQtVirtualKeyboard;
|
||||||
|
|
||||||
|
presetItem->create = foundPreset->create;
|
||||||
|
presetItem->description = foundPreset->description;
|
||||||
|
presetItem->fontIconCode = foundPreset->fontIconCode;
|
||||||
|
presetItem->qmlPath = foundPreset->qmlPath;
|
||||||
|
|
||||||
|
result.push_back(presetItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<PresetItem> PresetData::findPresetItemForRecent(const RecentPresetData &recent, const PresetItems &wizardPresets)
|
||||||
|
{
|
||||||
|
return Utils::findOrDefault(wizardPresets, [&recent](const std::shared_ptr<PresetItem> &item) {
|
||||||
|
bool sameName = item->categoryId == recent.category
|
||||||
|
&& item->displayName() == recent.presetName;
|
||||||
|
|
||||||
|
bool sameType = (recent.isUserPreset ? item->isUserPreset() : !item->isUserPreset());
|
||||||
|
|
||||||
|
return sameName && sameType;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
PresetItems PresetData::makeRecentPresets(const PresetItems &wizardPresets)
|
||||||
|
{
|
||||||
|
PresetItems result;
|
||||||
|
|
||||||
|
for (const RecentPresetData &recent : m_recents) {
|
||||||
|
std::shared_ptr<PresetItem> preset = findPresetItemForRecent(recent, wizardPresets);
|
||||||
|
|
||||||
|
if (preset) {
|
||||||
|
auto clone = std::shared_ptr<PresetItem>{preset->clone()};
|
||||||
|
clone->screenSizeName = recent.sizeName;
|
||||||
|
result.push_back(clone);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,8 +161,8 @@ BasePresetModel::BasePresetModel(const PresetData *data, QObject *parent)
|
|||||||
|
|
||||||
QHash<int, QByteArray> BasePresetModel::roleNames() const
|
QHash<int, QByteArray> BasePresetModel::roleNames() const
|
||||||
{
|
{
|
||||||
QHash<int, QByteArray> roleNames;
|
static QHash<int, QByteArray> roleNames{{NameRole, "name"},
|
||||||
roleNames[Qt::UserRole] = "name";
|
{ScreenSizeRole, "resolution"}};
|
||||||
return roleNames;
|
return roleNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,8 +172,9 @@ PresetCategoryModel::PresetCategoryModel(const PresetData *data, QObject *parent
|
|||||||
: BasePresetModel(data, parent)
|
: BasePresetModel(data, parent)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
int PresetCategoryModel::rowCount(const QModelIndex &) const
|
int PresetCategoryModel::rowCount(const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
|
Q_UNUSED(parent)
|
||||||
return static_cast<int>(m_data->categories().size());
|
return static_cast<int>(m_data->categories().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,9 +192,9 @@ PresetModel::PresetModel(const PresetData *data, QObject *parent)
|
|||||||
|
|
||||||
QHash<int, QByteArray> PresetModel::roleNames() const
|
QHash<int, QByteArray> PresetModel::roleNames() const
|
||||||
{
|
{
|
||||||
QHash<int, QByteArray> roleNames;
|
static QHash<int, QByteArray> roleNames{{NameRole, "name"},
|
||||||
roleNames[Qt::UserRole] = "name";
|
{ScreenSizeRole, "resolution"},
|
||||||
roleNames[Qt::UserRole + 1] = "size";
|
{IsUserPresetRole, "isUserPreset"}};
|
||||||
return roleNames;
|
return roleNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,9 +208,16 @@ int PresetModel::rowCount(const QModelIndex &) const
|
|||||||
|
|
||||||
QVariant PresetModel::data(const QModelIndex &index, int role) const
|
QVariant PresetModel::data(const QModelIndex &index, int role) const
|
||||||
{
|
{
|
||||||
Q_UNUSED(role)
|
std::shared_ptr<PresetItem> preset = presetsOfCurrentCategory().at(index.row());
|
||||||
PresetItem preset = presetsOfCurrentCategory().at(index.row());
|
|
||||||
return QVariant::fromValue<QString>(preset.name + "\n" + preset.screenSizeName);
|
if (role == NameRole)
|
||||||
|
return preset->displayName();
|
||||||
|
else if (role == ScreenSizeRole)
|
||||||
|
return preset->screenSize();
|
||||||
|
else if (role == IsUserPresetRole)
|
||||||
|
return preset->isUserPreset();
|
||||||
|
else
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void PresetModel::setPage(int index)
|
void PresetModel::setPage(int index)
|
||||||
@@ -148,7 +231,7 @@ void PresetModel::setPage(int index)
|
|||||||
|
|
||||||
QString PresetModel::fontIconCode(int index) const
|
QString PresetModel::fontIconCode(int index) const
|
||||||
{
|
{
|
||||||
Utils::optional<PresetItem> presetItem = preset(index);
|
std::shared_ptr<PresetItem> presetItem = preset(index);
|
||||||
if (!presetItem)
|
if (!presetItem)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
|
@@ -31,8 +31,10 @@
|
|||||||
|
|
||||||
#include <utils/filepath.h>
|
#include <utils/filepath.h>
|
||||||
#include <utils/optional.h>
|
#include <utils/optional.h>
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
#include "recentpresets.h"
|
#include "recentpresets.h"
|
||||||
|
#include "userpresets.h"
|
||||||
|
|
||||||
namespace Utils {
|
namespace Utils {
|
||||||
class Wizard;
|
class Wizard;
|
||||||
@@ -40,38 +42,115 @@ class Wizard;
|
|||||||
|
|
||||||
namespace StudioWelcome {
|
namespace StudioWelcome {
|
||||||
|
|
||||||
|
struct UserPresetItem;
|
||||||
|
|
||||||
struct PresetItem
|
struct PresetItem
|
||||||
{
|
{
|
||||||
QString name;
|
PresetItem() = default;
|
||||||
|
PresetItem(const QString &wizardName, const QString &category, const QString &sizeName = "")
|
||||||
|
: wizardName{wizardName}
|
||||||
|
, categoryId{category}
|
||||||
|
, screenSizeName{sizeName}
|
||||||
|
{}
|
||||||
|
|
||||||
|
virtual ~PresetItem() {}
|
||||||
|
virtual QString displayName() const { return wizardName; }
|
||||||
|
virtual QString screenSize() const { return screenSizeName; }
|
||||||
|
virtual std::unique_ptr<PresetItem> clone() const
|
||||||
|
{
|
||||||
|
return std::unique_ptr<PresetItem>{new PresetItem{*this}};
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool isUserPreset() const { return false; }
|
||||||
|
virtual UserPresetItem *asUserPreset() { return nullptr; }
|
||||||
|
std::function<Utils::Wizard *(const Utils::FilePath &path)> create;
|
||||||
|
|
||||||
|
public:
|
||||||
|
QString wizardName;
|
||||||
QString categoryId;
|
QString categoryId;
|
||||||
QString screenSizeName;
|
QString screenSizeName;
|
||||||
QString description;
|
QString description;
|
||||||
QUrl qmlPath;
|
QUrl qmlPath;
|
||||||
QString fontIconCode;
|
QString fontIconCode;
|
||||||
std::function<Utils::Wizard *(const Utils::FilePath &path)> create;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct UserPresetItem : public PresetItem
|
||||||
|
{
|
||||||
|
UserPresetItem() = default;
|
||||||
|
UserPresetItem(const QString &userName,
|
||||||
|
const QString &wizardName,
|
||||||
|
const QString &category,
|
||||||
|
const QString &sizeName = "")
|
||||||
|
: PresetItem{wizardName, category, sizeName}
|
||||||
|
, userName{userName}
|
||||||
|
{}
|
||||||
|
|
||||||
|
QString displayName() const override { return userName; }
|
||||||
|
std::unique_ptr<PresetItem> clone() const override
|
||||||
|
{
|
||||||
|
return std::unique_ptr<PresetItem>{new UserPresetItem{*this}};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isUserPreset() const override { return true; }
|
||||||
|
UserPresetItem *asUserPreset() override { return this; }
|
||||||
|
|
||||||
|
bool isValid() const
|
||||||
|
{
|
||||||
|
return !categoryId.isEmpty() && !wizardName.isEmpty() && !userName.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
QString userName;
|
||||||
|
bool useQtVirtualKeyboard;
|
||||||
|
QString qtVersion;
|
||||||
|
QString styleName;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline QDebug &operator<<(QDebug &d, const UserPresetItem &item);
|
||||||
|
|
||||||
inline QDebug &operator<<(QDebug &d, const PresetItem &item)
|
inline QDebug &operator<<(QDebug &d, const PresetItem &item)
|
||||||
{
|
{
|
||||||
d << "name=" << item.name;
|
d << "wizardName=" << item.wizardName;
|
||||||
d << "; category = " << item.categoryId;
|
d << "; category = " << item.categoryId;
|
||||||
d << "; size = " << item.screenSizeName;
|
d << "; size = " << item.screenSizeName;
|
||||||
|
|
||||||
|
if (item.isUserPreset())
|
||||||
|
d << (UserPresetItem &) item;
|
||||||
|
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline QDebug &operator<<(QDebug &d, const UserPresetItem &item)
|
||||||
|
{
|
||||||
|
d << "userName=" << item.userName;
|
||||||
|
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool operator==(const PresetItem &lhs, const PresetItem &rhs)
|
inline bool operator==(const PresetItem &lhs, const PresetItem &rhs)
|
||||||
{
|
{
|
||||||
return lhs.categoryId == rhs.categoryId && lhs.name == rhs.name;
|
return lhs.categoryId == rhs.categoryId && lhs.wizardName == rhs.wizardName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using PresetItems = std::vector<std::shared_ptr<PresetItem>>;
|
||||||
|
|
||||||
struct WizardCategory
|
struct WizardCategory
|
||||||
{
|
{
|
||||||
QString id;
|
QString id;
|
||||||
QString name;
|
QString name;
|
||||||
std::vector<PresetItem> items;
|
PresetItems items;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline QDebug &operator<<(QDebug &d, const std::shared_ptr<PresetItem> &preset)
|
||||||
|
{
|
||||||
|
if (preset)
|
||||||
|
d << *preset;
|
||||||
|
else
|
||||||
|
d << "(null)";
|
||||||
|
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
inline QDebug &operator<<(QDebug &d, const WizardCategory &cat)
|
inline QDebug &operator<<(QDebug &d, const WizardCategory &cat)
|
||||||
{
|
{
|
||||||
d << "id=" << cat.id;
|
d << "id=" << cat.id;
|
||||||
@@ -82,7 +161,6 @@ inline QDebug &operator<<(QDebug &d, const WizardCategory &cat)
|
|||||||
}
|
}
|
||||||
|
|
||||||
using PresetsByCategory = std::map<QString, WizardCategory>;
|
using PresetsByCategory = std::map<QString, WizardCategory>;
|
||||||
using PresetItems = std::vector<PresetItem>;
|
|
||||||
using Categories = std::vector<QString>;
|
using Categories = std::vector<QString>;
|
||||||
|
|
||||||
/****************** PresetData ******************/
|
/****************** PresetData ******************/
|
||||||
@@ -90,18 +168,28 @@ using Categories = std::vector<QString>;
|
|||||||
class PresetData
|
class PresetData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void setData(const PresetsByCategory &presets, const std::vector<RecentPreset> &recents);
|
void reload(const std::vector<UserPresetData> &userPresets,
|
||||||
|
const std::vector<RecentPresetData> &loadedRecents);
|
||||||
|
void setData(const PresetsByCategory &presets,
|
||||||
|
const std::vector<UserPresetData> &userPresets,
|
||||||
|
const std::vector<RecentPresetData> &recents);
|
||||||
|
|
||||||
const std::vector<PresetItems> &presets() const { return m_presets; }
|
const std::vector<PresetItems> &presets() const { return m_presets; }
|
||||||
const Categories &categories() const { return m_categories; }
|
const Categories &categories() const { return m_categories; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<PresetItem> makeRecentPresets(const PresetItems &wizardPresets);
|
PresetItems makeRecentPresets(const PresetItems &wizardPresets);
|
||||||
|
PresetItems makeUserPresets(const PresetItems &wizardPresets);
|
||||||
|
|
||||||
|
std::shared_ptr<PresetItem> findPresetItemForUserPreset(const UserPresetData &preset, const PresetItems &wizardPresets);
|
||||||
|
std::shared_ptr<PresetItem> findPresetItemForRecent(const RecentPresetData &recent, const PresetItems &wizardPresets);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<PresetItems> m_presets;
|
std::vector<PresetItems> m_presets;
|
||||||
Categories m_categories;
|
Categories m_categories;
|
||||||
std::vector<RecentPreset> m_recents;
|
std::vector<RecentPresetData> m_recents;
|
||||||
|
std::vector<UserPresetData> m_userPresets;
|
||||||
|
PresetsByCategory m_presetsByCategory;
|
||||||
};
|
};
|
||||||
|
|
||||||
/****************** PresetCategoryModel ******************/
|
/****************** PresetCategoryModel ******************/
|
||||||
@@ -149,14 +237,14 @@ public:
|
|||||||
|
|
||||||
int page() const { return static_cast<int>(m_page); }
|
int page() const { return static_cast<int>(m_page); }
|
||||||
|
|
||||||
Utils::optional<PresetItem> preset(size_t selection) const
|
const std::shared_ptr<PresetItem> preset(size_t selection) const
|
||||||
{
|
{
|
||||||
auto presets = m_data->presets();
|
auto presets = m_data->presets();
|
||||||
if (presets.empty())
|
if (presets.empty())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
if (m_page < presets.size()) {
|
if (m_page < presets.size()) {
|
||||||
const std::vector<PresetItem> presetsOfCategory = presets.at(m_page);
|
const PresetItems presetsOfCategory = presets.at(m_page);
|
||||||
if (selection < presetsOfCategory.size())
|
if (selection < presetsOfCategory.size())
|
||||||
return presets.at(m_page).at(selection);
|
return presets.at(m_page).at(selection);
|
||||||
}
|
}
|
||||||
@@ -166,8 +254,10 @@ public:
|
|||||||
bool empty() const { return m_data->presets().empty(); }
|
bool empty() const { return m_data->presets().empty(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const std::vector<PresetItem> presetsOfCurrentCategory() const
|
const PresetItems presetsOfCurrentCategory() const
|
||||||
{
|
{
|
||||||
|
QTC_ASSERT(m_page < m_data->presets().size(), return {});
|
||||||
|
|
||||||
return m_data->presets().at(m_page);
|
return m_data->presets().at(m_page);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -76,22 +76,14 @@ QdsNewDialog::QdsNewDialog(QWidget *parent)
|
|||||||
{
|
{
|
||||||
setParent(m_dialog);
|
setParent(m_dialog);
|
||||||
|
|
||||||
m_dialog->rootContext()->setContextProperties(QVector<QQmlContext::PropertyPair>{
|
|
||||||
{{"categoryModel"}, QVariant::fromValue(m_categoryModel.data())},
|
|
||||||
{{"presetModel"}, QVariant::fromValue(m_presetModel.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->setResizeMode(QQuickWidget::SizeRootObjectToView); // SizeViewToRootObject
|
||||||
m_dialog->engine()->addImageProvider(QStringLiteral("newprojectdialog_library"),
|
m_dialog->engine()->addImageProvider(QStringLiteral("newprojectdialog_library"),
|
||||||
new Internal::NewProjectDialogImageProvider());
|
new Internal::NewProjectDialogImageProvider());
|
||||||
QmlDesigner::Theme::setupTheme(m_dialog->engine());
|
QmlDesigner::Theme::setupTheme(m_dialog->engine());
|
||||||
|
qmlRegisterSingletonInstance<QdsNewDialog>("BackendApi", 1, 0, "BackendApi", this);
|
||||||
m_dialog->engine()->addImportPath(Core::ICore::resourcePath("qmldesigner/propertyEditorQmlSources/imports").toString());
|
m_dialog->engine()->addImportPath(Core::ICore::resourcePath("qmldesigner/propertyEditorQmlSources/imports").toString());
|
||||||
m_dialog->engine()->addImportPath(Core::ICore::resourcePath("qmldesigner/newprojectdialog/imports").toString());
|
m_dialog->engine()->addImportPath(Core::ICore::resourcePath("qmldesigner/newprojectdialog/imports").toString());
|
||||||
QString sourcesPath = qmlPath();
|
m_dialog->setSource(QUrl::fromLocalFile(qmlPath()));
|
||||||
m_dialog->setSource(QUrl::fromLocalFile(sourcesPath));
|
|
||||||
|
|
||||||
m_dialog->setWindowModality(Qt::ApplicationModal);
|
m_dialog->setWindowModality(Qt::ApplicationModal);
|
||||||
m_dialog->setWindowFlags(Qt::Dialog);
|
m_dialog->setWindowFlags(Qt::Dialog);
|
||||||
@@ -114,7 +106,7 @@ QdsNewDialog::QdsNewDialog(QWidget *parent)
|
|||||||
});
|
});
|
||||||
|
|
||||||
QObject::connect(m_styleModel.data(), &StyleModel::modelAboutToBeReset, this, [this]() {
|
QObject::connect(m_styleModel.data(), &StyleModel::modelAboutToBeReset, this, [this]() {
|
||||||
this->m_qmlStyleIndex = -1;
|
m_qmlStyleIndex = -1;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,18 +180,47 @@ void QdsNewDialog::onWizardCreated(QStandardItemModel *screenSizeModel, QStandar
|
|||||||
m_screenSizeModel->setBackendModel(screenSizeModel);
|
m_screenSizeModel->setBackendModel(screenSizeModel);
|
||||||
m_styleModel->setBackendModel(styleModel);
|
m_styleModel->setBackendModel(styleModel);
|
||||||
|
|
||||||
|
auto userPreset = m_currentPreset->asUserPreset();
|
||||||
|
|
||||||
if (m_qmlDetailsLoaded) {
|
if (m_qmlDetailsLoaded) {
|
||||||
updateScreenSizes();
|
if (m_currentPreset->isUserPreset()) {
|
||||||
|
if (m_wizard.haveVirtualKeyboard())
|
||||||
|
setUseVirtualKeyboard(userPreset->useQtVirtualKeyboard);
|
||||||
|
|
||||||
|
if (m_wizard.haveTargetQtVersion()) {
|
||||||
|
int index = m_wizard.targetQtVersionIndex(userPreset->qtVersion);
|
||||||
|
if (index != -1)
|
||||||
|
setTargetQtVersionIndex(index);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (m_wizard.haveTargetQtVersion()) {
|
||||||
|
int index = m_wizard.targetQtVersionIndex();
|
||||||
|
if (index != -1)
|
||||||
|
setTargetQtVersionIndex(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
emit haveVirtualKeyboardChanged();
|
emit haveVirtualKeyboardChanged();
|
||||||
emit haveTargetQtVersionChanged();
|
emit haveTargetQtVersionChanged();
|
||||||
|
|
||||||
|
updateScreenSizes();
|
||||||
|
|
||||||
setProjectName(m_qmlProjectName);
|
setProjectName(m_qmlProjectName);
|
||||||
setProjectLocation(m_qmlProjectLocation.toString());
|
setProjectLocation(m_qmlProjectLocation.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_qmlStylesLoaded)
|
if (m_qmlStylesLoaded && m_wizard.haveStyleModel()) {
|
||||||
|
if (m_currentPreset->isUserPreset()) {
|
||||||
|
int index = m_wizard.styleIndex(userPreset->styleName);
|
||||||
|
if (index != -1)
|
||||||
|
setStyleIndex(index);
|
||||||
|
} else {
|
||||||
|
/* NOTE: For a builtin preset, we don't need to set style index. That's because defaults
|
||||||
|
* will be loaded from the backend Wizard.
|
||||||
|
*/
|
||||||
|
}
|
||||||
m_styleModel->reset();
|
m_styleModel->reset();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString QdsNewDialog::currentPresetQmlPath() const
|
QString QdsNewDialog::currentPresetQmlPath() const
|
||||||
@@ -221,10 +242,19 @@ int QdsNewDialog::screenSizeIndex() const
|
|||||||
return m_wizard.screenSizeIndex();
|
return m_wizard.screenSizeIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QdsNewDialog::setTargetQtVersion(int index)
|
void QdsNewDialog::setTargetQtVersionIndex(int index)
|
||||||
{
|
{
|
||||||
m_wizard.setTargetQtVersionIndex(index);
|
if (m_qmlTargetQtVersionIndex != index) {
|
||||||
m_qmlTargetQtVersionIndex = index;
|
m_wizard.setTargetQtVersionIndex(index);
|
||||||
|
m_qmlTargetQtVersionIndex = index;
|
||||||
|
|
||||||
|
emit targetQtVersionIndexChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int QdsNewDialog::getTargetQtVersionIndex() const
|
||||||
|
{
|
||||||
|
return m_qmlTargetQtVersionIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QdsNewDialog::setStyleIndex(int index)
|
void QdsNewDialog::setStyleIndex(int index)
|
||||||
@@ -267,6 +297,14 @@ int QdsNewDialog::getStyleIndex() const
|
|||||||
return m_styleModel->actualIndex(m_qmlStyleIndex);
|
return m_styleModel->actualIndex(m_qmlStyleIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QdsNewDialog::setUseVirtualKeyboard(bool value)
|
||||||
|
{
|
||||||
|
if (m_qmlUseVirtualKeyboard != value) {
|
||||||
|
m_qmlUseVirtualKeyboard = value;
|
||||||
|
emit useVirtualKeyboardChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void QdsNewDialog::setWizardFactories(QList<Core::IWizardFactory *> factories_,
|
void QdsNewDialog::setWizardFactories(QList<Core::IWizardFactory *> factories_,
|
||||||
const Utils::FilePath &defaultLocation,
|
const Utils::FilePath &defaultLocation,
|
||||||
const QVariantMap &)
|
const QVariantMap &)
|
||||||
@@ -275,8 +313,9 @@ void QdsNewDialog::setWizardFactories(QList<Core::IWizardFactory *> factories_,
|
|||||||
|
|
||||||
WizardFactories factories{factories_, m_dialog, platform};
|
WizardFactories factories{factories_, m_dialog, platform};
|
||||||
|
|
||||||
std::vector<RecentPreset> recents = m_recentsStore.fetchAll();
|
std::vector<RecentPresetData> recents = m_recentsStore.fetchAll();
|
||||||
m_presetData.setData(factories.presetsGroupedByCategory(), recents);
|
std::vector<UserPresetData> userPresets = m_userPresetsStore.fetchAll();
|
||||||
|
m_presetData.setData(factories.presetsGroupedByCategory(), userPresets, recents);
|
||||||
|
|
||||||
m_categoryModel->reset();
|
m_categoryModel->reset();
|
||||||
m_presetModel->reset();
|
m_presetModel->reset();
|
||||||
@@ -296,12 +335,45 @@ void QdsNewDialog::setWizardFactories(QList<Core::IWizardFactory *> factories_,
|
|||||||
m_qmlProjectLocation = Utils::FilePath::fromString(QDir::toNativeSeparators(projectLocation.toString()));
|
m_qmlProjectLocation = Utils::FilePath::fromString(QDir::toNativeSeparators(projectLocation.toString()));
|
||||||
emit projectLocationChanged(); // So that QML knows to update the field
|
emit projectLocationChanged(); // So that QML knows to update the field
|
||||||
|
|
||||||
|
/* NOTE:
|
||||||
|
* Here we expect that details are loaded && that styles are loaded. We use the
|
||||||
|
* functionality below to update the state of the first item that is selected right when
|
||||||
|
* the dialog pops up. Otherwise, relying solely on onWizardCreated is not useful, since
|
||||||
|
* for the dialog popup, that wizard is created before details & styles are loaded.
|
||||||
|
*
|
||||||
|
* It might be a better alternative to receive notifications from QML in the cpp file, that
|
||||||
|
* style is loaded, and that details is loaded, and do updates from there. But, if we handle
|
||||||
|
* those events, they may be called before the wizard is created - so we would need to make
|
||||||
|
* sure that all events have occurred before we go ahead and configure the wizard.
|
||||||
|
*/
|
||||||
|
|
||||||
|
auto userPreset = m_currentPreset->asUserPreset();
|
||||||
|
|
||||||
if (m_qmlDetailsLoaded) {
|
if (m_qmlDetailsLoaded) {
|
||||||
updateScreenSizes();
|
updateScreenSizes();
|
||||||
|
|
||||||
|
if (m_wizard.haveTargetQtVersion()) {
|
||||||
|
int index = (userPreset ? m_wizard.targetQtVersionIndex(userPreset->qtVersion)
|
||||||
|
: m_wizard.targetQtVersionIndex());
|
||||||
|
if (index != -1)
|
||||||
|
setTargetQtVersionIndex(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_wizard.haveVirtualKeyboard() && userPreset)
|
||||||
|
setUseVirtualKeyboard(userPreset->useQtVirtualKeyboard);
|
||||||
|
|
||||||
|
emit haveVirtualKeyboardChanged();
|
||||||
|
emit haveTargetQtVersionChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_qmlStylesLoaded)
|
if (m_qmlStylesLoaded && m_wizard.haveStyleModel()) {
|
||||||
|
if (userPreset) {
|
||||||
|
int index = m_wizard.styleIndex(userPreset->styleName);
|
||||||
|
if (index != -1)
|
||||||
|
setStyleIndex(index);
|
||||||
|
}
|
||||||
m_styleModel->reset();
|
m_styleModel->reset();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString QdsNewDialog::qmlPath() const
|
QString QdsNewDialog::qmlPath() const
|
||||||
@@ -338,10 +410,10 @@ void QdsNewDialog::accept()
|
|||||||
.withTargetQtVersion(m_qmlTargetQtVersionIndex)
|
.withTargetQtVersion(m_qmlTargetQtVersionIndex)
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
PresetItem item = m_wizard.preset();
|
std::shared_ptr<PresetItem> item = m_wizard.preset();
|
||||||
QString customSizeName = m_qmlCustomWidth + " x " + m_qmlCustomHeight;
|
QString customSizeName = m_qmlCustomWidth + " x " + m_qmlCustomHeight;
|
||||||
|
|
||||||
m_recentsStore.add(item.categoryId, item.name, customSizeName);
|
m_recentsStore.add(item->categoryId, item->displayName(), customSizeName, item->isUserPreset());
|
||||||
|
|
||||||
m_dialog->close();
|
m_dialog->close();
|
||||||
m_dialog->deleteLater();
|
m_dialog->deleteLater();
|
||||||
@@ -355,6 +427,7 @@ void QdsNewDialog::reject()
|
|||||||
m_wizard.destroyWizard();
|
m_wizard.destroyWizard();
|
||||||
|
|
||||||
m_dialog->close();
|
m_dialog->close();
|
||||||
|
m_dialog = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString QdsNewDialog::chooseProjectLocation()
|
QString QdsNewDialog::chooseProjectLocation()
|
||||||
@@ -375,7 +448,76 @@ void QdsNewDialog::setSelectedPreset(int selection)
|
|||||||
setProjectDescription(m_currentPreset->description);
|
setProjectDescription(m_currentPreset->description);
|
||||||
|
|
||||||
m_presetPage = m_presetModel->page();
|
m_presetPage = m_presetModel->page();
|
||||||
m_wizard.reset(m_currentPreset.value(), m_qmlSelectedPreset);
|
m_wizard.reset(m_currentPreset, m_qmlSelectedPreset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QdsNewDialog::savePresetDialogAccept()
|
||||||
|
{
|
||||||
|
QString screenSize = m_qmlCustomWidth + " x " + m_qmlCustomHeight;
|
||||||
|
QString targetQtVersion = "";
|
||||||
|
QString styleName = "";
|
||||||
|
bool useVirtualKeyboard = false;
|
||||||
|
|
||||||
|
if (m_wizard.haveTargetQtVersion())
|
||||||
|
targetQtVersion = m_wizard.targetQtVersionName(m_qmlTargetQtVersionIndex);
|
||||||
|
|
||||||
|
if (m_wizard.haveStyleModel())
|
||||||
|
styleName = m_wizard.styleName(m_qmlStyleIndex);
|
||||||
|
|
||||||
|
if (m_wizard.haveVirtualKeyboard())
|
||||||
|
useVirtualKeyboard = m_qmlUseVirtualKeyboard;
|
||||||
|
|
||||||
|
UserPresetData preset = {m_currentPreset->categoryId,
|
||||||
|
m_currentPreset->wizardName,
|
||||||
|
m_qmlPresetName,
|
||||||
|
screenSize,
|
||||||
|
useVirtualKeyboard,
|
||||||
|
targetQtVersion,
|
||||||
|
styleName};
|
||||||
|
|
||||||
|
if (!m_userPresetsStore.save(preset)) {
|
||||||
|
QMessageBox::warning(m_dialog,
|
||||||
|
tr("Save Preset"),
|
||||||
|
tr("A preset with this name already exists."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// reload model
|
||||||
|
std::vector<RecentPresetData> recents = m_recentsStore.fetchAll();
|
||||||
|
std::vector<UserPresetData> userPresets = m_userPresetsStore.fetchAll();
|
||||||
|
m_presetData.reload(userPresets, recents);
|
||||||
|
|
||||||
|
m_categoryModel->reset();
|
||||||
|
|
||||||
|
emit userPresetSaved();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QdsNewDialog::removeCurrentPreset()
|
||||||
|
{
|
||||||
|
if (!m_currentPreset->isUserPreset()) {
|
||||||
|
qWarning() << "Will not attempt to remove non-user preset";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove preset & reload model
|
||||||
|
std::vector<RecentPresetData> recents = m_recentsStore.remove(m_currentPreset->categoryId,
|
||||||
|
m_currentPreset->displayName());
|
||||||
|
|
||||||
|
auto userPreset = m_currentPreset->asUserPreset();
|
||||||
|
m_userPresetsStore.remove(userPreset->categoryId, userPreset->displayName());
|
||||||
|
std::vector<UserPresetData> userPresets = m_userPresetsStore.fetchAll();
|
||||||
|
m_presetData.reload(userPresets, recents);
|
||||||
|
|
||||||
|
m_qmlSelectedPreset = -1;
|
||||||
|
m_presetPage = -1;
|
||||||
|
|
||||||
|
if (userPresets.size() == 0) {
|
||||||
|
m_presetModel->setPage(0);
|
||||||
|
emit lastUserPresetRemoved();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_categoryModel->reset();
|
||||||
|
m_presetModel->reset();
|
||||||
|
}
|
||||||
|
@@ -29,13 +29,13 @@
|
|||||||
|
|
||||||
#include <coreplugin/dialogs/newdialog.h>
|
#include <coreplugin/dialogs/newdialog.h>
|
||||||
#include <utils/infolabel.h>
|
#include <utils/infolabel.h>
|
||||||
#include <utils/optional.h>
|
|
||||||
|
|
||||||
#include "wizardhandler.h"
|
#include "wizardhandler.h"
|
||||||
#include "presetmodel.h"
|
#include "presetmodel.h"
|
||||||
#include "screensizemodel.h"
|
#include "screensizemodel.h"
|
||||||
#include "stylemodel.h"
|
#include "stylemodel.h"
|
||||||
#include "recentpresets.h"
|
#include "recentpresets.h"
|
||||||
|
#include "userpresets.h"
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
class QStandardItemModel;
|
class QStandardItemModel;
|
||||||
@@ -57,22 +57,31 @@ public:
|
|||||||
Q_PROPERTY(bool useVirtualKeyboard MEMBER m_qmlUseVirtualKeyboard READ getUseVirtualKeyboard WRITE setUseVirtualKeyboard NOTIFY useVirtualKeyboardChanged)
|
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 haveVirtualKeyboard MEMBER m_qmlHaveVirtualKeyboard READ getHaveVirtualKeyboard NOTIFY haveVirtualKeyboardChanged)
|
||||||
Q_PROPERTY(bool haveTargetQtVersion MEMBER m_qmlHaveTargetQtVersion READ getHaveTargetQtVersion NOTIFY haveTargetQtVersionChanged)
|
Q_PROPERTY(bool haveTargetQtVersion MEMBER m_qmlHaveTargetQtVersion READ getHaveTargetQtVersion NOTIFY haveTargetQtVersionChanged)
|
||||||
|
Q_PROPERTY(int targetQtVersionIndex MEMBER m_qmlTargetQtVersionIndex READ getTargetQtVersionIndex WRITE setTargetQtVersionIndex NOTIFY targetQtVersionIndexChanged)
|
||||||
Q_PROPERTY(bool saveAsDefaultLocation MEMBER m_qmlSaveAsDefaultLocation WRITE setSaveAsDefaultLocation)
|
Q_PROPERTY(bool saveAsDefaultLocation MEMBER m_qmlSaveAsDefaultLocation WRITE setSaveAsDefaultLocation)
|
||||||
Q_PROPERTY(QString statusMessage MEMBER m_qmlStatusMessage READ getStatusMessage NOTIFY statusMessageChanged)
|
Q_PROPERTY(QString statusMessage MEMBER m_qmlStatusMessage READ getStatusMessage NOTIFY statusMessageChanged)
|
||||||
Q_PROPERTY(QString statusType MEMBER m_qmlStatusType READ getStatusType NOTIFY statusTypeChanged)
|
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 fieldsValid MEMBER m_qmlFieldsValid READ getFieldsValid NOTIFY fieldsValidChanged)
|
||||||
|
Q_PROPERTY(QString presetName MEMBER m_qmlPresetName)
|
||||||
|
|
||||||
Q_PROPERTY(bool detailsLoaded MEMBER m_qmlDetailsLoaded)
|
Q_PROPERTY(bool detailsLoaded MEMBER m_qmlDetailsLoaded)
|
||||||
Q_PROPERTY(bool stylesLoaded MEMBER m_qmlStylesLoaded)
|
Q_PROPERTY(bool stylesLoaded MEMBER m_qmlStylesLoaded)
|
||||||
|
|
||||||
|
Q_INVOKABLE void removeCurrentPreset();
|
||||||
Q_INVOKABLE QString currentPresetQmlPath() const;
|
Q_INVOKABLE QString currentPresetQmlPath() const;
|
||||||
// TODO: screen size index should better be a property
|
// TODO: screen size index should better be a property
|
||||||
Q_INVOKABLE void setScreenSizeIndex(int index); // called when ComboBox item is "activated"
|
Q_INVOKABLE void setScreenSizeIndex(int index); // called when ComboBox item is "activated"
|
||||||
Q_INVOKABLE int screenSizeIndex() const;
|
Q_INVOKABLE int screenSizeIndex() const;
|
||||||
Q_INVOKABLE void setTargetQtVersion(int index);
|
|
||||||
|
|
||||||
Q_INVOKABLE QString chooseProjectLocation();
|
Q_INVOKABLE QString chooseProjectLocation();
|
||||||
|
|
||||||
|
Q_PROPERTY(QAbstractListModel *categoryModel MEMBER m_categoryModel CONSTANT);
|
||||||
|
Q_PROPERTY(QAbstractListModel *presetModel MEMBER m_presetModel CONSTANT);
|
||||||
|
Q_PROPERTY(QAbstractListModel *screenSizeModel MEMBER m_screenSizeModel CONSTANT);
|
||||||
|
Q_PROPERTY(QAbstractListModel *styleModel MEMBER m_styleModel CONSTANT);
|
||||||
|
|
||||||
|
/*********************/
|
||||||
|
|
||||||
explicit QdsNewDialog(QWidget *parent);
|
explicit QdsNewDialog(QWidget *parent);
|
||||||
|
|
||||||
QWidget *widget() override { return m_dialog; }
|
QWidget *widget() override { return m_dialog; }
|
||||||
@@ -85,7 +94,11 @@ public:
|
|||||||
|
|
||||||
void setStyleIndex(int index);
|
void setStyleIndex(int index);
|
||||||
int getStyleIndex() const;
|
int getStyleIndex() const;
|
||||||
void setUseVirtualKeyboard(bool value) { m_qmlUseVirtualKeyboard = value; }
|
|
||||||
|
void setTargetQtVersionIndex(int index);
|
||||||
|
int getTargetQtVersionIndex() const;
|
||||||
|
|
||||||
|
void setUseVirtualKeyboard(bool value);
|
||||||
bool getUseVirtualKeyboard() const { return m_qmlUseVirtualKeyboard; }
|
bool getUseVirtualKeyboard() const { return m_qmlUseVirtualKeyboard; }
|
||||||
|
|
||||||
bool getFieldsValid() const { return m_qmlFieldsValid; }
|
bool getFieldsValid() const { return m_qmlFieldsValid; }
|
||||||
@@ -101,6 +114,8 @@ public slots:
|
|||||||
void accept();
|
void accept();
|
||||||
void reject();
|
void reject();
|
||||||
|
|
||||||
|
void savePresetDialogAccept();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void projectNameChanged();
|
void projectNameChanged();
|
||||||
void projectLocationChanged();
|
void projectLocationChanged();
|
||||||
@@ -111,6 +126,9 @@ signals:
|
|||||||
void statusMessageChanged();
|
void statusMessageChanged();
|
||||||
void statusTypeChanged();
|
void statusTypeChanged();
|
||||||
void fieldsValidChanged();
|
void fieldsValidChanged();
|
||||||
|
void targetQtVersionIndexChanged();
|
||||||
|
void userPresetSaved();
|
||||||
|
void lastUserPresetRemoved();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onStatusMessageChanged(Utils::InfoLabel::InfoType type, const QString &message);
|
void onStatusMessageChanged(Utils::InfoLabel::InfoType type, const QString &message);
|
||||||
@@ -160,6 +178,7 @@ private:
|
|||||||
bool m_qmlFieldsValid = false;
|
bool m_qmlFieldsValid = false;
|
||||||
QString m_qmlStatusMessage;
|
QString m_qmlStatusMessage;
|
||||||
QString m_qmlStatusType;
|
QString m_qmlStatusType;
|
||||||
|
QString m_qmlPresetName;
|
||||||
|
|
||||||
int m_presetPage = -1; // i.e. the page in the Presets View
|
int m_presetPage = -1; // i.e. the page in the Presets View
|
||||||
|
|
||||||
@@ -169,10 +188,11 @@ private:
|
|||||||
bool m_qmlDetailsLoaded = false;
|
bool m_qmlDetailsLoaded = false;
|
||||||
bool m_qmlStylesLoaded = false;
|
bool m_qmlStylesLoaded = false;
|
||||||
|
|
||||||
Utils::optional<PresetItem> m_currentPreset;
|
std::shared_ptr<PresetItem> m_currentPreset;
|
||||||
|
|
||||||
WizardHandler m_wizard;
|
WizardHandler m_wizard;
|
||||||
RecentPresetsStore m_recentsStore;
|
RecentPresetsStore m_recentsStore;
|
||||||
|
UserPresetsStore m_userPresetsStore;
|
||||||
};
|
};
|
||||||
|
|
||||||
} //namespace StudioWelcome
|
} //namespace StudioWelcome
|
||||||
|
@@ -32,19 +32,27 @@
|
|||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
#include <utils/qtcsettings.h>
|
#include <utils/qtcsettings.h>
|
||||||
|
|
||||||
using Core::ICore;
|
|
||||||
using Utils::QtcSettings;
|
|
||||||
|
|
||||||
using namespace StudioWelcome;
|
using namespace StudioWelcome;
|
||||||
|
|
||||||
constexpr char GROUP_NAME[] = "RecentPresets";
|
constexpr char GROUP_NAME[] = "RecentPresets";
|
||||||
constexpr char WIZARDS[] = "Wizards";
|
constexpr char WIZARDS[] = "Wizards";
|
||||||
|
|
||||||
void RecentPresetsStore::add(const QString &categoryId, const QString &name, const QString &sizeName)
|
void RecentPresetsStore::add(const QString &categoryId,
|
||||||
|
const QString &name,
|
||||||
|
const QString &sizeName,
|
||||||
|
bool isUserPreset)
|
||||||
{
|
{
|
||||||
std::vector<RecentPreset> existing = fetchAll();
|
std::vector<RecentPresetData> existing = fetchAll();
|
||||||
QStringList encodedRecents = addRecentToExisting(RecentPreset{categoryId, name, sizeName},
|
|
||||||
existing);
|
std::vector<RecentPresetData> recents
|
||||||
|
= addRecentToExisting(RecentPresetData{categoryId, name, sizeName, isUserPreset}, existing);
|
||||||
|
|
||||||
|
save(recents);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RecentPresetsStore::save(const std::vector<RecentPresetData> &recents)
|
||||||
|
{
|
||||||
|
QStringList encodedRecents = encodeRecentPresets(recents);
|
||||||
|
|
||||||
m_settings->beginGroup(GROUP_NAME);
|
m_settings->beginGroup(GROUP_NAME);
|
||||||
m_settings->setValue(WIZARDS, encodedRecents);
|
m_settings->setValue(WIZARDS, encodedRecents);
|
||||||
@@ -52,8 +60,26 @@ void RecentPresetsStore::add(const QString &categoryId, const QString &name, con
|
|||||||
m_settings->sync();
|
m_settings->sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList RecentPresetsStore::addRecentToExisting(const RecentPreset &preset,
|
std::vector<RecentPresetData> RecentPresetsStore::remove(const QString &categoryId, const QString &presetName)
|
||||||
std::vector<RecentPreset> &recents)
|
{
|
||||||
|
std::vector<RecentPresetData> recents = fetchAll();
|
||||||
|
size_t countBefore = recents.size();
|
||||||
|
|
||||||
|
/* NOTE: when removing one preset, it may happen that there are more than one recent for that
|
||||||
|
* preset. In that case, we need to remove all associated recents, for the preset.*/
|
||||||
|
|
||||||
|
Utils::erase(recents, [&](const RecentPresetData &p) {
|
||||||
|
return p.category == categoryId && p.presetName == presetName;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (recents.size() < countBefore)
|
||||||
|
save(recents);
|
||||||
|
|
||||||
|
return recents;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<RecentPresetData> RecentPresetsStore::addRecentToExisting(
|
||||||
|
const RecentPresetData &preset, std::vector<RecentPresetData> &recents)
|
||||||
{
|
{
|
||||||
Utils::erase_one(recents, preset);
|
Utils::erase_one(recents, preset);
|
||||||
Utils::prepend(recents, preset);
|
Utils::prepend(recents, preset);
|
||||||
@@ -61,48 +87,64 @@ QStringList RecentPresetsStore::addRecentToExisting(const RecentPreset &preset,
|
|||||||
if (int(recents.size()) > m_max)
|
if (int(recents.size()) > m_max)
|
||||||
recents.pop_back();
|
recents.pop_back();
|
||||||
|
|
||||||
return encodeRecentPresets(recents);
|
return recents;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<RecentPreset> RecentPresetsStore::fetchAll() const
|
std::vector<RecentPresetData> RecentPresetsStore::fetchAll() const
|
||||||
{
|
{
|
||||||
m_settings->beginGroup(GROUP_NAME);
|
m_settings->beginGroup(GROUP_NAME);
|
||||||
QVariant value = m_settings->value(WIZARDS);
|
QVariant value = m_settings->value(WIZARDS);
|
||||||
m_settings->endGroup();
|
m_settings->endGroup();
|
||||||
|
|
||||||
std::vector<RecentPreset> result;
|
std::vector<RecentPresetData> result;
|
||||||
|
|
||||||
if (value.type() == QVariant::String)
|
if (value.type() == QVariant::String)
|
||||||
result.push_back(decodeOneRecentPreset(value.toString()));
|
result.push_back(decodeOneRecentPreset(value.toString()));
|
||||||
else if (value.type() == QVariant::StringList)
|
else if (value.type() == QVariant::StringList)
|
||||||
Utils::concat(result, decodeRecentPresets(value.toList()));
|
Utils::concat(result, decodeRecentPresets(value.toList()));
|
||||||
|
|
||||||
const RecentPreset empty;
|
const RecentPresetData empty;
|
||||||
return Utils::filtered(result, [&empty](const RecentPreset &recent) { return recent != empty; });
|
return Utils::filtered(result, [&empty](const RecentPresetData &recent) { return recent != empty; });
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList RecentPresetsStore::encodeRecentPresets(const std::vector<RecentPreset> &recents)
|
QStringList RecentPresetsStore::encodeRecentPresets(const std::vector<RecentPresetData> &recents)
|
||||||
{
|
{
|
||||||
return Utils::transform<QList>(recents, [](const RecentPreset &p) -> QString {
|
return Utils::transform<QList>(recents, [](const RecentPresetData &p) -> QString {
|
||||||
return std::get<0>(p) + "/" + std::get<1>(p) + ":" + std::get<2>(p);
|
QString name = p.presetName;
|
||||||
|
if (p.isUserPreset)
|
||||||
|
name.prepend("[U]");
|
||||||
|
|
||||||
|
return p.category + "/" + name + ":" + p.sizeName;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
RecentPreset RecentPresetsStore::decodeOneRecentPreset(const QString &encoded)
|
RecentPresetData RecentPresetsStore::decodeOneRecentPreset(const QString &encoded)
|
||||||
{
|
{
|
||||||
QRegularExpression pattern{R"(^(\S+)/(.+):(\d+ x \d+))"};
|
QRegularExpression pattern{R"(^(\S+)/(.+):(\d+ x \d+)$)"};
|
||||||
auto m = pattern.match(encoded);
|
auto m = pattern.match(encoded);
|
||||||
if (!m.hasMatch())
|
if (!m.hasMatch())
|
||||||
return RecentPreset{};
|
return RecentPresetData{};
|
||||||
|
|
||||||
QString category = m.captured(1);
|
QString category = m.captured(1);
|
||||||
QString name = m.captured(2);
|
QString name = m.captured(2);
|
||||||
QString size = m.captured(3);
|
QString size = m.captured(3);
|
||||||
|
bool isUserPreset = name.startsWith("[U]");
|
||||||
|
if (isUserPreset)
|
||||||
|
name = name.split("[U]")[1];
|
||||||
|
|
||||||
return std::make_tuple(category, name, size);
|
if (!QRegularExpression{R"(^\w[\w ]*$)"}.match(name).hasMatch())
|
||||||
|
return RecentPresetData{};
|
||||||
|
|
||||||
|
RecentPresetData result;
|
||||||
|
result.category = category;
|
||||||
|
result.presetName = name;
|
||||||
|
result.sizeName = size;
|
||||||
|
result.isUserPreset = isUserPreset;
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<RecentPreset> RecentPresetsStore::decodeRecentPresets(const QVariantList &values)
|
std::vector<RecentPresetData> RecentPresetsStore::decodeRecentPresets(const QVariantList &values)
|
||||||
{
|
{
|
||||||
return Utils::transform<std::vector>(values, [](const QVariant &value) {
|
return Utils::transform<std::vector>(values, [](const QVariant &value) {
|
||||||
return decodeOneRecentPreset(value.toString());
|
return decodeOneRecentPreset(value.toString());
|
||||||
|
@@ -31,8 +31,43 @@
|
|||||||
|
|
||||||
namespace StudioWelcome {
|
namespace StudioWelcome {
|
||||||
|
|
||||||
// preset category, preset name, size name
|
struct RecentPresetData
|
||||||
using RecentPreset = std::tuple<QString, QString, QString>;
|
{
|
||||||
|
RecentPresetData() = default;
|
||||||
|
RecentPresetData(const QString &category,
|
||||||
|
const QString &name,
|
||||||
|
const QString &size,
|
||||||
|
bool isUserPreset = false)
|
||||||
|
: category{category}
|
||||||
|
, presetName{name}
|
||||||
|
, sizeName{size}
|
||||||
|
, isUserPreset{isUserPreset}
|
||||||
|
{}
|
||||||
|
|
||||||
|
QString category;
|
||||||
|
QString presetName;
|
||||||
|
QString sizeName;
|
||||||
|
bool isUserPreset = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline bool operator==(const RecentPresetData &lhs, const RecentPresetData &rhs)
|
||||||
|
{
|
||||||
|
return lhs.category == rhs.category && lhs.presetName == rhs.presetName
|
||||||
|
&& lhs.sizeName == rhs.sizeName && lhs.isUserPreset == rhs.isUserPreset;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator!=(const RecentPresetData &lhs, const RecentPresetData &rhs)
|
||||||
|
{
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline QDebug &operator<<(QDebug &d, const RecentPresetData &preset)
|
||||||
|
{
|
||||||
|
d << "RecentPreset{category=" << preset.category << "; name=" << preset.presetName
|
||||||
|
<< "; size=" << preset.sizeName << "; isUserPreset=" << preset.isUserPreset << "}";
|
||||||
|
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
class RecentPresetsStore
|
class RecentPresetsStore
|
||||||
{
|
{
|
||||||
@@ -42,14 +77,21 @@ public:
|
|||||||
{}
|
{}
|
||||||
|
|
||||||
void setMaximum(int n) { m_max = n; }
|
void setMaximum(int n) { m_max = n; }
|
||||||
void add(const QString &categoryId, const QString &name, const QString &sizeName);
|
void add(const QString &categoryId,
|
||||||
std::vector<RecentPreset> fetchAll() const;
|
const QString &name,
|
||||||
|
const QString &sizeName,
|
||||||
|
bool isUserPreset = false);
|
||||||
|
|
||||||
|
std::vector<RecentPresetData> remove(const QString &categoryId, const QString &presetName);
|
||||||
|
std::vector<RecentPresetData> fetchAll() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QStringList addRecentToExisting(const RecentPreset &preset, std::vector<RecentPreset> &recents);
|
std::vector<RecentPresetData> addRecentToExisting(const RecentPresetData &preset,
|
||||||
static QStringList encodeRecentPresets(const std::vector<RecentPreset> &recents);
|
std::vector<RecentPresetData> &recents);
|
||||||
static std::vector<RecentPreset> decodeRecentPresets(const QVariantList &values);
|
static QStringList encodeRecentPresets(const std::vector<RecentPresetData> &recents);
|
||||||
static RecentPreset decodeOneRecentPreset(const QString &encoded);
|
static std::vector<RecentPresetData> decodeRecentPresets(const QVariantList &values);
|
||||||
|
static RecentPresetData decodeOneRecentPreset(const QString &encoded);
|
||||||
|
void save(const std::vector<RecentPresetData> &recents);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QSettings *m_settings = nullptr;
|
QSettings *m_settings = nullptr;
|
||||||
|
@@ -38,7 +38,9 @@ QtcPlugin {
|
|||||||
"wizardhandler.cpp",
|
"wizardhandler.cpp",
|
||||||
"wizardhandler.h",
|
"wizardhandler.h",
|
||||||
"recentpresets.cpp",
|
"recentpresets.cpp",
|
||||||
"recentpresets.h"
|
"recentpresets.h",
|
||||||
|
"userpresets.cpp",
|
||||||
|
"userpresets.h"
|
||||||
]
|
]
|
||||||
|
|
||||||
Group {
|
Group {
|
||||||
|
125
src/plugins/studiowelcome/userpresets.cpp
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2022 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "userpresets.h"
|
||||||
|
|
||||||
|
#include <coreplugin/icore.h>
|
||||||
|
#include <utils/algorithm.h>
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
|
using namespace StudioWelcome;
|
||||||
|
|
||||||
|
constexpr char PREFIX[] = "UserPresets";
|
||||||
|
|
||||||
|
UserPresetsStore::UserPresetsStore()
|
||||||
|
{
|
||||||
|
m_settings = std::make_unique<QSettings>(fullFilePath(), QSettings::IniFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
UserPresetsStore::UserPresetsStore(std::unique_ptr<QSettings> &&settings)
|
||||||
|
: m_settings{std::move(settings)}
|
||||||
|
{}
|
||||||
|
|
||||||
|
void UserPresetsStore::savePresets(const std::vector<UserPresetData> &presets)
|
||||||
|
{
|
||||||
|
m_settings->beginWriteArray(PREFIX, static_cast<int>(presets.size()));
|
||||||
|
|
||||||
|
for (size_t i = 0; i < presets.size(); ++i) {
|
||||||
|
m_settings->setArrayIndex(static_cast<int>(i));
|
||||||
|
const auto &preset = presets[i];
|
||||||
|
|
||||||
|
m_settings->setValue("categoryId", preset.categoryId);
|
||||||
|
m_settings->setValue("wizardName", preset.wizardName);
|
||||||
|
m_settings->setValue("name", preset.name);
|
||||||
|
m_settings->setValue("screenSize", preset.screenSize);
|
||||||
|
m_settings->setValue("useQtVirtualKeyboard", preset.useQtVirtualKeyboard);
|
||||||
|
m_settings->setValue("qtVersion", preset.qtVersion);
|
||||||
|
m_settings->setValue("styleName", preset.styleName);
|
||||||
|
}
|
||||||
|
m_settings->endArray();
|
||||||
|
m_settings->sync();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UserPresetsStore::save(const UserPresetData &newPreset)
|
||||||
|
{
|
||||||
|
QTC_ASSERT(newPreset.isValid(), return false);
|
||||||
|
|
||||||
|
std::vector<UserPresetData> presetItems = fetchAll();
|
||||||
|
if (Utils::anyOf(presetItems,
|
||||||
|
[&newPreset](const UserPresetData &p) { return p.name == newPreset.name; })) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
presetItems.push_back(newPreset);
|
||||||
|
savePresets(presetItems);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UserPresetsStore::remove(const QString &category, const QString &name)
|
||||||
|
{
|
||||||
|
std::vector<UserPresetData> presetItems = fetchAll();
|
||||||
|
auto item = Utils::take(presetItems, [&](const UserPresetData &p) {
|
||||||
|
return p.categoryId == category && p.name == name;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!item)
|
||||||
|
return;
|
||||||
|
|
||||||
|
savePresets(presetItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<UserPresetData> UserPresetsStore::fetchAll() const
|
||||||
|
{
|
||||||
|
std::vector<UserPresetData> result;
|
||||||
|
int size = m_settings->beginReadArray(PREFIX);
|
||||||
|
if (size >= 0)
|
||||||
|
result.reserve(static_cast<size_t>(size) + 1);
|
||||||
|
|
||||||
|
for (int i = 0; i < size; ++i) {
|
||||||
|
m_settings->setArrayIndex(i);
|
||||||
|
|
||||||
|
UserPresetData preset;
|
||||||
|
preset.categoryId = m_settings->value("categoryId").toString();
|
||||||
|
preset.wizardName = m_settings->value("wizardName").toString();
|
||||||
|
preset.name = m_settings->value("name").toString();
|
||||||
|
preset.screenSize = m_settings->value("screenSize").toString();
|
||||||
|
preset.useQtVirtualKeyboard = m_settings->value("useQtVirtualKeyboard").toBool();
|
||||||
|
preset.qtVersion = m_settings->value("qtVersion").toString();
|
||||||
|
preset.styleName = m_settings->value("styleName").toString();
|
||||||
|
|
||||||
|
if (preset.isValid())
|
||||||
|
result.push_back(std::move(preset));
|
||||||
|
}
|
||||||
|
m_settings->endArray();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString UserPresetsStore::fullFilePath() const
|
||||||
|
{
|
||||||
|
return Core::ICore::userResourcePath("UserPresets.ini").toString();
|
||||||
|
}
|
91
src/plugins/studiowelcome/userpresets.h
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2022 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <QSettings>
|
||||||
|
|
||||||
|
namespace StudioWelcome {
|
||||||
|
|
||||||
|
struct UserPresetData
|
||||||
|
{
|
||||||
|
QString categoryId;
|
||||||
|
QString wizardName;
|
||||||
|
QString name;
|
||||||
|
QString screenSize;
|
||||||
|
|
||||||
|
bool useQtVirtualKeyboard;
|
||||||
|
QString qtVersion;
|
||||||
|
QString styleName;
|
||||||
|
|
||||||
|
bool isValid() const
|
||||||
|
{
|
||||||
|
return !categoryId.isEmpty()
|
||||||
|
&& !wizardName.isEmpty()
|
||||||
|
&& !name.isEmpty();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline QDebug &operator<<(QDebug &d, const UserPresetData &preset)
|
||||||
|
{
|
||||||
|
d << "UserPreset{category = " << preset.categoryId;
|
||||||
|
d << "; wizardName = " << preset.wizardName;
|
||||||
|
d << "; name = " << preset.name;
|
||||||
|
d << "; screenSize = " << preset.screenSize;
|
||||||
|
d << "; keyboard = " << preset.useQtVirtualKeyboard;
|
||||||
|
d << "; qt = " << preset.qtVersion;
|
||||||
|
d << "; style = " << preset.styleName;
|
||||||
|
d << "}";
|
||||||
|
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator==(const UserPresetData &lhs, const UserPresetData &rhs)
|
||||||
|
{
|
||||||
|
return lhs.categoryId == rhs.categoryId && lhs.wizardName == rhs.wizardName
|
||||||
|
&& lhs.name == rhs.name && lhs.screenSize == rhs.screenSize
|
||||||
|
&& lhs.useQtVirtualKeyboard == rhs.useQtVirtualKeyboard && lhs.qtVersion == rhs.qtVersion
|
||||||
|
&& lhs.styleName == rhs.styleName;
|
||||||
|
}
|
||||||
|
|
||||||
|
class UserPresetsStore
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
UserPresetsStore();
|
||||||
|
UserPresetsStore(std::unique_ptr<QSettings> &&settings);
|
||||||
|
|
||||||
|
bool save(const UserPresetData &preset);
|
||||||
|
void remove(const QString &category, const QString &name);
|
||||||
|
std::vector<UserPresetData> fetchAll() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString fullFilePath() const;
|
||||||
|
void savePresets(const std::vector<UserPresetData> &presets);
|
||||||
|
|
||||||
|
std::unique_ptr<QSettings> m_settings;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace StudioWelcome
|
@@ -76,7 +76,7 @@ void WizardFactories::filter()
|
|||||||
m_factories = acceptedFactories;
|
m_factories = acceptedFactories;
|
||||||
}
|
}
|
||||||
|
|
||||||
PresetItem WizardFactories::makePresetItem(JsonWizardFactory *f, QWidget *parent,
|
std::shared_ptr<PresetItem> WizardFactories::makePresetItem(JsonWizardFactory *f, QWidget *parent,
|
||||||
const Utils::Id &platform)
|
const Utils::Id &platform)
|
||||||
{
|
{
|
||||||
using namespace std::placeholders;
|
using namespace std::placeholders;
|
||||||
@@ -89,16 +89,17 @@ PresetItem WizardFactories::makePresetItem(JsonWizardFactory *f, QWidget *parent
|
|||||||
else
|
else
|
||||||
sizeName = screenSizes[index];
|
sizeName = screenSizes[index];
|
||||||
|
|
||||||
return {
|
auto result = std::make_shared<PresetItem>();
|
||||||
/*.name =*/f->displayName(),
|
result->wizardName = f->displayName();
|
||||||
/*.categoryId =*/f->category(),
|
result->categoryId = f->category();
|
||||||
/*.screenSizeName=*/sizeName,
|
result->screenSizeName=sizeName;
|
||||||
/*.description =*/f->description(),
|
result->description = f->description();
|
||||||
/*.qmlPath =*/f->detailsPageQmlPath(),
|
result->qmlPath = f->detailsPageQmlPath();
|
||||||
/*.fontIconCode =*/m_getIconUnicode(f->fontIconName()),
|
result->fontIconCode = m_getIconUnicode(f->fontIconName());
|
||||||
/*.create =*/ std::bind(&JsonWizardFactory::runWizard, f, _1, parent, platform,
|
result->create
|
||||||
QVariantMap(), false),
|
= std::bind(&JsonWizardFactory::runWizard, f, _1, parent, platform, QVariantMap(), false);
|
||||||
};
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<QString, WizardCategory> WizardFactories::makePresetItemsGroupedByCategory()
|
std::map<QString, WizardCategory> WizardFactories::makePresetItemsGroupedByCategory()
|
||||||
|
@@ -64,7 +64,7 @@ private:
|
|||||||
void sortByCategoryAndId();
|
void sortByCategoryAndId();
|
||||||
void filter();
|
void filter();
|
||||||
|
|
||||||
PresetItem makePresetItem(JsonWizardFactory *f, QWidget *parent, const Utils::Id &platform);
|
std::shared_ptr<PresetItem> makePresetItem(JsonWizardFactory *f, QWidget *parent, const Utils::Id &platform);
|
||||||
std::map<QString, WizardCategory> makePresetItemsGroupedByCategory();
|
std::map<QString, WizardCategory> makePresetItemsGroupedByCategory();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@@ -38,7 +38,7 @@
|
|||||||
|
|
||||||
using namespace StudioWelcome;
|
using namespace StudioWelcome;
|
||||||
|
|
||||||
void WizardHandler::reset(const PresetItem &presetInfo, int presetSelection)
|
void WizardHandler::reset(const std::shared_ptr<PresetItem> &presetInfo, int presetSelection)
|
||||||
{
|
{
|
||||||
m_preset = presetInfo;
|
m_preset = presetInfo;
|
||||||
m_selectedPreset = presetSelection;
|
m_selectedPreset = presetSelection;
|
||||||
@@ -67,7 +67,7 @@ void WizardHandler::destroyWizard()
|
|||||||
|
|
||||||
void WizardHandler::setupWizard()
|
void WizardHandler::setupWizard()
|
||||||
{
|
{
|
||||||
m_wizard = m_preset.create(m_projectLocation);
|
m_wizard = m_preset->create(m_projectLocation);
|
||||||
if (!m_wizard) {
|
if (!m_wizard) {
|
||||||
emit wizardCreationFailed();
|
emit wizardCreationFailed();
|
||||||
return;
|
return;
|
||||||
@@ -142,6 +142,11 @@ QStandardItemModel *WizardHandler::getScreenFactorModel(ProjectExplorer::JsonFie
|
|||||||
return cbfield->model();
|
return cbfield->model();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WizardHandler::haveStyleModel() const
|
||||||
|
{
|
||||||
|
return m_wizard->hasField("ControlsStyle");
|
||||||
|
}
|
||||||
|
|
||||||
QStandardItemModel *WizardHandler::getStyleModel(ProjectExplorer::JsonFieldPage *page)
|
QStandardItemModel *WizardHandler::getStyleModel(ProjectExplorer::JsonFieldPage *page)
|
||||||
{
|
{
|
||||||
auto *field = page->jsonField("ControlsStyle");
|
auto *field = page->jsonField("ControlsStyle");
|
||||||
@@ -229,6 +234,47 @@ bool WizardHandler::haveTargetQtVersion() const
|
|||||||
return m_wizard->hasField("TargetQtVersion");
|
return m_wizard->hasField("TargetQtVersion");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString WizardHandler::targetQtVersionName(int index) const
|
||||||
|
{
|
||||||
|
auto *field = m_detailsPage->jsonField("TargetQtVersion");
|
||||||
|
auto *cbfield = dynamic_cast<ProjectExplorer::ComboBoxField *>(field);
|
||||||
|
QTC_ASSERT(cbfield, return "");
|
||||||
|
|
||||||
|
QStandardItemModel *model = cbfield->model();
|
||||||
|
if (index < 0 || index >= model->rowCount())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
QString text = model->item(index)->text();
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
int WizardHandler::targetQtVersionIndex(const QString &qtVersionName) const
|
||||||
|
{
|
||||||
|
auto *field = m_detailsPage->jsonField("TargetQtVersion");
|
||||||
|
auto *cbfield = dynamic_cast<ProjectExplorer::ComboBoxField *>(field);
|
||||||
|
QTC_ASSERT(cbfield, return -1);
|
||||||
|
|
||||||
|
const QStandardItemModel *model = cbfield->model();
|
||||||
|
for (int i = 0; i < model->rowCount(); ++i) {
|
||||||
|
const QStandardItem *item = model->item(i, 0);
|
||||||
|
const QString text = item->text();
|
||||||
|
|
||||||
|
if (text == qtVersionName)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int WizardHandler::targetQtVersionIndex() const
|
||||||
|
{
|
||||||
|
auto *field = m_detailsPage->jsonField("TargetQtVersion");
|
||||||
|
auto *cbfield = dynamic_cast<ProjectExplorer::ComboBoxField *>(field);
|
||||||
|
QTC_ASSERT(cbfield, return -1);
|
||||||
|
|
||||||
|
return cbfield->selectedRow();
|
||||||
|
}
|
||||||
|
|
||||||
void WizardHandler::setStyleIndex(int index)
|
void WizardHandler::setStyleIndex(int index)
|
||||||
{
|
{
|
||||||
auto *field = m_detailsPage->jsonField("ControlsStyle");
|
auto *field = m_detailsPage->jsonField("ControlsStyle");
|
||||||
@@ -247,6 +293,38 @@ int WizardHandler::styleIndex() const
|
|||||||
return cbfield->selectedRow();
|
return cbfield->selectedRow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int WizardHandler::styleIndex(const QString &styleName) const
|
||||||
|
{
|
||||||
|
auto *field = m_detailsPage->jsonField("ControlsStyle");
|
||||||
|
auto *cbfield = dynamic_cast<ProjectExplorer::ComboBoxField *>(field);
|
||||||
|
QTC_ASSERT(cbfield, return -1);
|
||||||
|
|
||||||
|
const QStandardItemModel *model = cbfield->model();
|
||||||
|
for (int i = 0; i < model->rowCount(); ++i) {
|
||||||
|
const QStandardItem *item = model->item(i, 0);
|
||||||
|
const QString text = item->text();
|
||||||
|
|
||||||
|
if (text == styleName)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString WizardHandler::styleName(int index) const
|
||||||
|
{
|
||||||
|
auto *field = m_detailsPage->jsonField("ControlsStyle");
|
||||||
|
auto *cbfield = dynamic_cast<ProjectExplorer::ComboBoxField *>(field);
|
||||||
|
QTC_ASSERT(cbfield, return "");
|
||||||
|
|
||||||
|
QStandardItemModel *model = cbfield->model();
|
||||||
|
if (index < 0 || index >= model->rowCount())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
QString text = model->item(index)->text();
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
void WizardHandler::setUseVirtualKeyboard(bool value)
|
void WizardHandler::setUseVirtualKeyboard(bool value)
|
||||||
{
|
{
|
||||||
auto *field = m_detailsPage->jsonField("UseVirtualKeyboard");
|
auto *field = m_detailsPage->jsonField("UseVirtualKeyboard");
|
||||||
|
@@ -47,15 +47,23 @@ class WizardHandler: public QObject
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void reset(const PresetItem &presetInfo, int presetSelection);
|
void reset(const std::shared_ptr<PresetItem> &presetInfo, int presetSelection);
|
||||||
void setScreenSizeIndex(int index);
|
void setScreenSizeIndex(int index);
|
||||||
int screenSizeIndex(const QString &sizeName) const;
|
int screenSizeIndex(const QString &sizeName) const;
|
||||||
QString screenSizeName(int index) const;
|
QString screenSizeName(int index) const;
|
||||||
int screenSizeIndex() const;
|
int screenSizeIndex() const;
|
||||||
|
int targetQtVersionIndex() const;
|
||||||
|
int targetQtVersionIndex(const QString &qtVersionName) const;
|
||||||
void setTargetQtVersionIndex(int index);
|
void setTargetQtVersionIndex(int index);
|
||||||
bool haveTargetQtVersion() const;
|
bool haveTargetQtVersion() const;
|
||||||
|
QString targetQtVersionName(int index) const;
|
||||||
|
|
||||||
void setStyleIndex(int index);
|
void setStyleIndex(int index);
|
||||||
int styleIndex() const;
|
int styleIndex() const;
|
||||||
|
int styleIndex(const QString &styleName) const;
|
||||||
|
QString styleName(int index) const;
|
||||||
|
bool haveStyleModel() const;
|
||||||
|
|
||||||
void destroyWizard();
|
void destroyWizard();
|
||||||
|
|
||||||
void setUseVirtualKeyboard(bool value);
|
void setUseVirtualKeyboard(bool value);
|
||||||
@@ -66,7 +74,7 @@ public:
|
|||||||
|
|
||||||
void run(const std::function<void (QWizardPage *)> &processPage);
|
void run(const std::function<void (QWizardPage *)> &processPage);
|
||||||
|
|
||||||
PresetItem preset() const { return m_preset; }
|
std::shared_ptr<PresetItem> preset() const { return m_preset; }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void deletingWizard();
|
void deletingWizard();
|
||||||
@@ -93,7 +101,7 @@ private:
|
|||||||
|
|
||||||
int m_selectedPreset = -1;
|
int m_selectedPreset = -1;
|
||||||
|
|
||||||
PresetItem m_preset;
|
std::shared_ptr<PresetItem> m_preset;
|
||||||
Utils::FilePath m_projectLocation;
|
Utils::FilePath m_projectLocation;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -18,12 +18,14 @@ add_qtc_test(tst_qml_wizard
|
|||||||
wizardfactories-test.cpp
|
wizardfactories-test.cpp
|
||||||
stylemodel-test.cpp
|
stylemodel-test.cpp
|
||||||
recentpresets-test.cpp
|
recentpresets-test.cpp
|
||||||
|
userpresets-test.cpp
|
||||||
presetmodel-test.cpp
|
presetmodel-test.cpp
|
||||||
test-utilities.h
|
test-utilities.h
|
||||||
test-main.cpp
|
test-main.cpp
|
||||||
"${StudioWelcomeDir}/wizardfactories.cpp"
|
"${StudioWelcomeDir}/wizardfactories.cpp"
|
||||||
"${StudioWelcomeDir}/stylemodel.cpp"
|
"${StudioWelcomeDir}/stylemodel.cpp"
|
||||||
"${StudioWelcomeDir}/recentpresets.cpp"
|
"${StudioWelcomeDir}/recentpresets.cpp"
|
||||||
|
"${StudioWelcomeDir}/userpresets.cpp"
|
||||||
"${StudioWelcomeDir}/presetmodel.cpp"
|
"${StudioWelcomeDir}/presetmodel.cpp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@@ -33,10 +33,18 @@ using ::testing::ElementsAreArray;
|
|||||||
using ::testing::PrintToString;
|
using ::testing::PrintToString;
|
||||||
|
|
||||||
namespace StudioWelcome {
|
namespace StudioWelcome {
|
||||||
|
|
||||||
|
void PrintTo(const UserPresetItem &item, std::ostream *os);
|
||||||
|
|
||||||
void PrintTo(const PresetItem &item, std::ostream *os)
|
void PrintTo(const PresetItem &item, std::ostream *os)
|
||||||
{
|
{
|
||||||
|
if (typeid(item) == typeid(UserPresetItem)) {
|
||||||
|
PrintTo((UserPresetItem &) item, os);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
*os << "{categId: " << item.categoryId << ", "
|
*os << "{categId: " << item.categoryId << ", "
|
||||||
<< "name: " << item.name;
|
<< "name: " << item.wizardName;
|
||||||
|
|
||||||
if (!item.screenSizeName.isEmpty())
|
if (!item.screenSizeName.isEmpty())
|
||||||
*os << ", size: " << item.screenSizeName;
|
*os << ", size: " << item.screenSizeName;
|
||||||
@@ -44,6 +52,26 @@ void PrintTo(const PresetItem &item, std::ostream *os)
|
|||||||
*os << "}";
|
*os << "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PrintTo(const UserPresetItem &item, std::ostream *os)
|
||||||
|
{
|
||||||
|
*os << "{categId: " << item.categoryId << ", "
|
||||||
|
<< "name: " << item.wizardName << ", "
|
||||||
|
<< "user name: " << item.userName;
|
||||||
|
|
||||||
|
if (!item.screenSizeName.isEmpty())
|
||||||
|
*os << ", size: " << item.screenSizeName;
|
||||||
|
|
||||||
|
*os << "}";
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintTo(const std::shared_ptr<PresetItem> &p, std::ostream *os)
|
||||||
|
{
|
||||||
|
if (p)
|
||||||
|
PrintTo(*p, os);
|
||||||
|
else
|
||||||
|
*os << "{null}";
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace StudioWelcome
|
} // namespace StudioWelcome
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@@ -51,20 +79,47 @@ std::pair<QString, WizardCategory> aCategory(const QString &categId,
|
|||||||
const QString &categName,
|
const QString &categName,
|
||||||
const std::vector<QString> &names)
|
const std::vector<QString> &names)
|
||||||
{
|
{
|
||||||
std::vector<PresetItem> items = Utils::transform(names, [&categId](const QString &name) {
|
std::vector<std::shared_ptr<PresetItem>> items
|
||||||
return PresetItem{name, categId};
|
= Utils::transform(names, [&categId](const QString &name) {
|
||||||
});
|
std::shared_ptr<PresetItem> item{new PresetItem};
|
||||||
|
item->wizardName = name;
|
||||||
|
item->categoryId = categId;
|
||||||
|
|
||||||
|
return item;
|
||||||
|
});
|
||||||
return std::make_pair(categId, WizardCategory{categId, categName, items});
|
return std::make_pair(categId, WizardCategory{categId, categName, items});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UserPresetData aUserPreset(const QString &categId, const QString &wizardName, const QString &userName)
|
||||||
|
{
|
||||||
|
UserPresetData preset;
|
||||||
|
preset.categoryId = categId;
|
||||||
|
preset.wizardName = wizardName;
|
||||||
|
preset.name = userName;
|
||||||
|
|
||||||
|
return preset;
|
||||||
|
}
|
||||||
|
|
||||||
MATCHER_P2(PresetIs, category, name, PrintToString(PresetItem{name, category}))
|
MATCHER_P2(PresetIs, category, name, PrintToString(PresetItem{name, category}))
|
||||||
{
|
{
|
||||||
return arg.categoryId == category && arg.name == name;
|
return arg->categoryId == category && arg->wizardName == name;
|
||||||
|
}
|
||||||
|
|
||||||
|
MATCHER_P3(UserPresetIs,
|
||||||
|
category,
|
||||||
|
wizardName,
|
||||||
|
userName,
|
||||||
|
PrintToString(UserPresetItem{wizardName, userName, category}))
|
||||||
|
{
|
||||||
|
auto userPreset = dynamic_cast<UserPresetItem *>(arg.get());
|
||||||
|
|
||||||
|
return userPreset->categoryId == category && userPreset->wizardName == wizardName
|
||||||
|
&& userPreset->userName == userName;
|
||||||
}
|
}
|
||||||
|
|
||||||
MATCHER_P3(PresetIs, category, name, size, PrintToString(PresetItem{name, category, size}))
|
MATCHER_P3(PresetIs, category, name, size, PrintToString(PresetItem{name, category, size}))
|
||||||
{
|
{
|
||||||
return arg.categoryId == category && arg.name == name && size == arg.screenSizeName;
|
return arg->categoryId == category && arg->wizardName == name && size == arg->screenSizeName;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
@@ -88,6 +143,7 @@ TEST(QdsPresetModel, haveSameArraySizeForPresetsAndCategories)
|
|||||||
aCategory("A.categ", "A", {"item a", "item b"}),
|
aCategory("A.categ", "A", {"item a", "item b"}),
|
||||||
aCategory("B.categ", "B", {"item c", "item d"}),
|
aCategory("B.categ", "B", {"item c", "item d"}),
|
||||||
},
|
},
|
||||||
|
{/*user presets*/},
|
||||||
{/*recents*/});
|
{/*recents*/});
|
||||||
|
|
||||||
ASSERT_THAT(data.presets(), SizeIs(2));
|
ASSERT_THAT(data.presets(), SizeIs(2));
|
||||||
@@ -105,6 +161,7 @@ TEST(QdsPresetModel, haveWizardPresetsNoRecents)
|
|||||||
aCategory("A.categ", "A", {"item a", "item b"}),
|
aCategory("A.categ", "A", {"item a", "item b"}),
|
||||||
aCategory("B.categ", "B", {"item c", "item d"}),
|
aCategory("B.categ", "B", {"item c", "item d"}),
|
||||||
},
|
},
|
||||||
|
{/*user presets*/},
|
||||||
{/*recents*/});
|
{/*recents*/});
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
@@ -115,11 +172,30 @@ TEST(QdsPresetModel, haveWizardPresetsNoRecents)
|
|||||||
ElementsAre(PresetIs("B.categ", "item c"), PresetIs("B.categ", "item d")));
|
ElementsAre(PresetIs("B.categ", "item c"), PresetIs("B.categ", "item d")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(QdsPresetModel, whenHaveUserPresetsButNoWizardPresetsReturnEmpty)
|
||||||
|
{
|
||||||
|
// Given
|
||||||
|
PresetData data;
|
||||||
|
|
||||||
|
// When
|
||||||
|
data.setData({/*builtin presets*/},
|
||||||
|
{
|
||||||
|
aUserPreset("A.Mobile", "Scroll", "iPhone5"),
|
||||||
|
aUserPreset("B.Desktop", "Launcher", "MacBook"),
|
||||||
|
},
|
||||||
|
{/*recents*/});
|
||||||
|
|
||||||
|
// Then
|
||||||
|
ASSERT_THAT(data.categories(), IsEmpty());
|
||||||
|
ASSERT_THAT(data.presets(), IsEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
TEST(QdsPresetModel, haveRecentsNoWizardPresets)
|
TEST(QdsPresetModel, haveRecentsNoWizardPresets)
|
||||||
{
|
{
|
||||||
PresetData data;
|
PresetData data;
|
||||||
|
|
||||||
data.setData({/*wizardPresets*/},
|
data.setData({/*wizardPresets*/},
|
||||||
|
{/*user presets*/},
|
||||||
{
|
{
|
||||||
{"A.categ", "Desktop", "640 x 480"},
|
{"A.categ", "Desktop", "640 x 480"},
|
||||||
{"B.categ", "Mobile", "800 x 600"},
|
{"B.categ", "Mobile", "800 x 600"},
|
||||||
@@ -129,7 +205,7 @@ TEST(QdsPresetModel, haveRecentsNoWizardPresets)
|
|||||||
ASSERT_THAT(data.presets(), IsEmpty());
|
ASSERT_THAT(data.presets(), IsEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(QdsPresetModel, recentsAddedBeforeWizardPresets)
|
TEST(QdsPresetModel, recentsAddedWithWizardPresets)
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
PresetData data;
|
PresetData data;
|
||||||
@@ -141,6 +217,7 @@ TEST(QdsPresetModel, recentsAddedBeforeWizardPresets)
|
|||||||
aCategory("A.categ", "A", {"Desktop", "item b"}),
|
aCategory("A.categ", "A", {"Desktop", "item b"}),
|
||||||
aCategory("B.categ", "B", {"item c", "Mobile"}),
|
aCategory("B.categ", "B", {"item c", "Mobile"}),
|
||||||
},
|
},
|
||||||
|
{/*user presets*/},
|
||||||
/*recents*/
|
/*recents*/
|
||||||
{
|
{
|
||||||
{"A.categ", "Desktop", "800 x 600"},
|
{"A.categ", "Desktop", "800 x 600"},
|
||||||
@@ -158,7 +235,98 @@ TEST(QdsPresetModel, recentsAddedBeforeWizardPresets)
|
|||||||
ElementsAre(PresetIs("B.categ", "item c"), PresetIs("B.categ", "Mobile"))}));
|
ElementsAre(PresetIs("B.categ", "item c"), PresetIs("B.categ", "Mobile"))}));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(QdsPresetModel, recentsShouldNotSorted)
|
TEST(QdsPresetModel, userPresetsAddedWithWizardPresets)
|
||||||
|
{
|
||||||
|
// Given
|
||||||
|
PresetData data;
|
||||||
|
|
||||||
|
// When
|
||||||
|
data.setData(
|
||||||
|
/*wizard presets*/
|
||||||
|
{
|
||||||
|
aCategory("A.categ", "A", {"Desktop", "item b"}),
|
||||||
|
aCategory("B.categ", "B", {"Mobile"}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
aUserPreset("A.categ", "Desktop", "Windows10"),
|
||||||
|
},
|
||||||
|
{/*recents*/});
|
||||||
|
|
||||||
|
// Then
|
||||||
|
ASSERT_THAT(data.categories(), ElementsAre("A", "B", "Custom"));
|
||||||
|
ASSERT_THAT(data.presets(),
|
||||||
|
ElementsAre(ElementsAre(PresetIs("A.categ", "Desktop"),
|
||||||
|
PresetIs("A.categ", "item b")),
|
||||||
|
ElementsAre(PresetIs("B.categ", "Mobile")),
|
||||||
|
ElementsAre(UserPresetIs("A.categ", "Desktop", "Windows10"))));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(QdsPresetModel, doesNotAddUserPresetsOfNonExistingCategory)
|
||||||
|
{
|
||||||
|
// Given
|
||||||
|
PresetData data;
|
||||||
|
|
||||||
|
// When
|
||||||
|
data.setData(
|
||||||
|
/*wizard presets*/
|
||||||
|
{
|
||||||
|
aCategory("A.categ", "A", {"Desktop"}), // Only category "A.categ" exists
|
||||||
|
},
|
||||||
|
{
|
||||||
|
aUserPreset("Bad.Categ", "Desktop", "Windows8"), // Bad.Categ does not exist
|
||||||
|
},
|
||||||
|
{/*recents*/});
|
||||||
|
|
||||||
|
// Then
|
||||||
|
ASSERT_THAT(data.categories(), ElementsAre("A"));
|
||||||
|
ASSERT_THAT(data.presets(), ElementsAre(ElementsAre(PresetIs("A.categ", "Desktop"))));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(QdsPresetModel, doesNotAddUserPresetIfWizardPresetItRefersToDoesNotExist)
|
||||||
|
{
|
||||||
|
// Given
|
||||||
|
PresetData data;
|
||||||
|
|
||||||
|
// When
|
||||||
|
data.setData(
|
||||||
|
/*wizard presets*/
|
||||||
|
{
|
||||||
|
aCategory("A.categ", "A", {"Desktop"}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
aUserPreset("B.categ", "BadWizard", "Tablet"), // BadWizard referenced does not exist
|
||||||
|
},
|
||||||
|
{/*recents*/});
|
||||||
|
|
||||||
|
// Then
|
||||||
|
ASSERT_THAT(data.categories(), ElementsAre("A"));
|
||||||
|
ASSERT_THAT(data.presets(), ElementsAre(ElementsAre(PresetIs("A.categ", "Desktop"))));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(QdsPresetModel, userPresetWithSameNameAsWizardPreset)
|
||||||
|
{
|
||||||
|
// Given
|
||||||
|
PresetData data;
|
||||||
|
|
||||||
|
// When
|
||||||
|
data.setData(
|
||||||
|
/*wizard presets*/
|
||||||
|
{
|
||||||
|
aCategory("A.categ", "A", {"Desktop"}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
aUserPreset("A.categ", "Desktop", "Desktop"),
|
||||||
|
},
|
||||||
|
{/*recents*/});
|
||||||
|
|
||||||
|
// Then
|
||||||
|
ASSERT_THAT(data.categories(), ElementsAre("A", "Custom"));
|
||||||
|
ASSERT_THAT(data.presets(),
|
||||||
|
ElementsAre(ElementsAre(PresetIs("A.categ", "Desktop")),
|
||||||
|
ElementsAre(UserPresetIs("A.categ", "Desktop", "Desktop"))));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(QdsPresetModel, recentsShouldNotBeSorted)
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
PresetData data;
|
PresetData data;
|
||||||
@@ -171,6 +339,7 @@ TEST(QdsPresetModel, recentsShouldNotSorted)
|
|||||||
aCategory("B.categ", "B", {"item c", "Mobile"}),
|
aCategory("B.categ", "B", {"item c", "Mobile"}),
|
||||||
aCategory("Z.categ", "Z", {"Z.desktop"}),
|
aCategory("Z.categ", "Z", {"Z.desktop"}),
|
||||||
},
|
},
|
||||||
|
{/*user presets*/},
|
||||||
/*recents*/
|
/*recents*/
|
||||||
{
|
{
|
||||||
{"Z.categ", "Z.desktop", "200 x 300"},
|
{"Z.categ", "Z.desktop", "200 x 300"},
|
||||||
@@ -197,6 +366,7 @@ TEST(QdsPresetModel, recentsOfSameWizardProjectButDifferentSizesAreRecognizedAsD
|
|||||||
aCategory("A.categ", "A", {"Desktop"}),
|
aCategory("A.categ", "A", {"Desktop"}),
|
||||||
aCategory("B.categ", "B", {"Mobile"}),
|
aCategory("B.categ", "B", {"Mobile"}),
|
||||||
},
|
},
|
||||||
|
{/*user presets*/},
|
||||||
/*recents*/
|
/*recents*/
|
||||||
{
|
{
|
||||||
{"B.categ", "Mobile", "400 x 400"},
|
{"B.categ", "Mobile", "400 x 400"},
|
||||||
@@ -223,6 +393,7 @@ TEST(QdsPresetModel, outdatedRecentsAreNotShown)
|
|||||||
aCategory("A.categ", "A", {"Desktop"}),
|
aCategory("A.categ", "A", {"Desktop"}),
|
||||||
aCategory("B.categ", "B", {"Mobile"}),
|
aCategory("B.categ", "B", {"Mobile"}),
|
||||||
},
|
},
|
||||||
|
{/*user presets*/},
|
||||||
/*recents*/
|
/*recents*/
|
||||||
{
|
{
|
||||||
{"B.categ", "NoLongerExists", "400 x 400"},
|
{"B.categ", "NoLongerExists", "400 x 400"},
|
||||||
|
@@ -38,6 +38,16 @@ using namespace StudioWelcome;
|
|||||||
constexpr char GROUP_NAME[] = "RecentPresets";
|
constexpr char GROUP_NAME[] = "RecentPresets";
|
||||||
constexpr char ITEMS[] = "Wizards";
|
constexpr char ITEMS[] = "Wizards";
|
||||||
|
|
||||||
|
namespace StudioWelcome {
|
||||||
|
void PrintTo(const RecentPresetData &recent, std::ostream *os)
|
||||||
|
{
|
||||||
|
*os << "{categId: " << recent.category << ", name: " << recent.presetName
|
||||||
|
<< ", size: " << recent.sizeName << ", isUser: " << recent.isUserPreset;
|
||||||
|
|
||||||
|
*os << "}";
|
||||||
|
}
|
||||||
|
} // namespace StudioWelcome
|
||||||
|
|
||||||
class QdsRecentPresets : public ::testing::Test
|
class QdsRecentPresets : public ::testing::Test
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
@@ -73,7 +83,7 @@ TEST_F(QdsRecentPresets, readFromEmptyStore)
|
|||||||
{
|
{
|
||||||
RecentPresetsStore store{&settings};
|
RecentPresetsStore store{&settings};
|
||||||
|
|
||||||
std::vector<RecentPreset> recents = store.fetchAll();
|
std::vector<RecentPresetData> recents = store.fetchAll();
|
||||||
|
|
||||||
ASSERT_THAT(recents, IsEmpty());
|
ASSERT_THAT(recents, IsEmpty());
|
||||||
}
|
}
|
||||||
@@ -82,7 +92,7 @@ TEST_F(QdsRecentPresets, readEmptyRecentPresets)
|
|||||||
{
|
{
|
||||||
RecentPresetsStore store = aStoreWithOne("");
|
RecentPresetsStore store = aStoreWithOne("");
|
||||||
|
|
||||||
std::vector<RecentPreset> recents = store.fetchAll();
|
std::vector<RecentPresetData> recents = store.fetchAll();
|
||||||
|
|
||||||
ASSERT_THAT(recents, IsEmpty());
|
ASSERT_THAT(recents, IsEmpty());
|
||||||
}
|
}
|
||||||
@@ -91,25 +101,34 @@ TEST_F(QdsRecentPresets, readOneRecentPresetAsList)
|
|||||||
{
|
{
|
||||||
RecentPresetsStore store = aStoreWithRecents({"category/preset:640 x 480"});
|
RecentPresetsStore store = aStoreWithRecents({"category/preset:640 x 480"});
|
||||||
|
|
||||||
std::vector<RecentPreset> recents = store.fetchAll();
|
std::vector<RecentPresetData> recents = store.fetchAll();
|
||||||
|
|
||||||
ASSERT_THAT(recents, ElementsAre(RecentPreset("category", "preset", "640 x 480")));
|
ASSERT_THAT(recents, ElementsAre(RecentPresetData("category", "preset", "640 x 480")));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(QdsRecentPresets, readOneRecentPresetAsString)
|
TEST_F(QdsRecentPresets, readOneRecentPresetAsString)
|
||||||
{
|
{
|
||||||
RecentPresetsStore store = aStoreWithOne("category/preset:200 x 300");
|
RecentPresetsStore store = aStoreWithOne("category/preset:200 x 300");
|
||||||
|
|
||||||
std::vector<RecentPreset> recents = store.fetchAll();
|
std::vector<RecentPresetData> recents = store.fetchAll();
|
||||||
|
|
||||||
ASSERT_THAT(recents, ElementsAre(RecentPreset("category", "preset", "200 x 300")));
|
ASSERT_THAT(recents, ElementsAre(RecentPresetData("category", "preset", "200 x 300")));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(QdsRecentPresets, readOneRecentUserPresetAsString)
|
||||||
|
{
|
||||||
|
RecentPresetsStore store = aStoreWithOne("category/[U]preset:200 x 300");
|
||||||
|
|
||||||
|
std::vector<RecentPresetData> recents = store.fetchAll();
|
||||||
|
|
||||||
|
ASSERT_THAT(recents, ElementsAre(RecentPresetData("category", "preset", "200 x 300", true)));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(QdsRecentPresets, readBadRecentPresetAsString)
|
TEST_F(QdsRecentPresets, readBadRecentPresetAsString)
|
||||||
{
|
{
|
||||||
RecentPresetsStore store = aStoreWithOne("no_category_only_preset");
|
RecentPresetsStore store = aStoreWithOne("no_category_only_preset");
|
||||||
|
|
||||||
std::vector<RecentPreset> recents = store.fetchAll();
|
std::vector<RecentPresetData> recents = store.fetchAll();
|
||||||
|
|
||||||
ASSERT_THAT(recents, IsEmpty());
|
ASSERT_THAT(recents, IsEmpty());
|
||||||
}
|
}
|
||||||
@@ -118,24 +137,32 @@ TEST_F(QdsRecentPresets, readBadRecentPresetAsInt)
|
|||||||
{
|
{
|
||||||
RecentPresetsStore store = aStoreWithOne(32);
|
RecentPresetsStore store = aStoreWithOne(32);
|
||||||
|
|
||||||
std::vector<RecentPreset> recents = store.fetchAll();
|
std::vector<RecentPresetData> recents = store.fetchAll();
|
||||||
|
|
||||||
ASSERT_THAT(recents, IsEmpty());
|
ASSERT_THAT(recents, IsEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(QdsRecentPresets, readBadRecentPresetsInList)
|
TEST_F(QdsRecentPresets, readBadRecentPresetsInList)
|
||||||
{
|
{
|
||||||
RecentPresetsStore store = aStoreWithRecents({"bad1", // no category, no size
|
RecentPresetsStore store = aStoreWithRecents({
|
||||||
"categ/name:800 x 600", // good
|
"bad1", // no category, no size
|
||||||
"categ/bad2", //no size
|
"categ/name:800 x 600", // good
|
||||||
"categ/bad3:", //no size
|
"categ/bad2", //no size
|
||||||
"categ 1/bad4:200 x 300", // category has space
|
"categ/bad3:", //no size
|
||||||
"categ/bad5: 400 x 300", // size starts with space
|
"categ 1/bad4:200 x 300", // category has space
|
||||||
"categ/bad6:400"}); // bad size
|
"categ/bad5: 400 x 300", // size starts with space
|
||||||
|
"categ/bad6:400", // bad size
|
||||||
|
"categ/[U]user:300 x 200", // good
|
||||||
|
"categ/[u]user2:300 x 200", // small cap "U"
|
||||||
|
"categ/[x]user3:300 x 200", // must be letter "U"
|
||||||
|
"categ/[U] user4:300 x 200", // space
|
||||||
|
});
|
||||||
|
|
||||||
std::vector<RecentPreset> recents = store.fetchAll();
|
std::vector<RecentPresetData> recents = store.fetchAll();
|
||||||
|
|
||||||
ASSERT_THAT(recents, ElementsAre(RecentPreset("categ", "name", "800 x 600")));
|
ASSERT_THAT(recents,
|
||||||
|
ElementsAre(RecentPresetData("categ", "name", "800 x 600", false),
|
||||||
|
RecentPresetData("categ", "user", "300 x 200", true)));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(QdsRecentPresets, readTwoRecentPresets)
|
TEST_F(QdsRecentPresets, readTwoRecentPresets)
|
||||||
@@ -143,11 +170,23 @@ TEST_F(QdsRecentPresets, readTwoRecentPresets)
|
|||||||
RecentPresetsStore store = aStoreWithRecents(
|
RecentPresetsStore store = aStoreWithRecents(
|
||||||
{"category_1/preset 1:640 x 480", "category_2/preset 2:320 x 200"});
|
{"category_1/preset 1:640 x 480", "category_2/preset 2:320 x 200"});
|
||||||
|
|
||||||
std::vector<RecentPreset> recents = store.fetchAll();
|
std::vector<RecentPresetData> recents = store.fetchAll();
|
||||||
|
|
||||||
ASSERT_THAT(recents,
|
ASSERT_THAT(recents,
|
||||||
ElementsAre(RecentPreset("category_1", "preset 1", "640 x 480"),
|
ElementsAre(RecentPresetData("category_1", "preset 1", "640 x 480"),
|
||||||
RecentPreset("category_2", "preset 2", "320 x 200")));
|
RecentPresetData("category_2", "preset 2", "320 x 200")));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(QdsRecentPresets, readRecentsToDifferentKindsOfPresets)
|
||||||
|
{
|
||||||
|
RecentPresetsStore store = aStoreWithRecents(
|
||||||
|
{"category_1/preset 1:640 x 480", "category_2/[U]preset 2:320 x 200"});
|
||||||
|
|
||||||
|
std::vector<RecentPresetData> recents = store.fetchAll();
|
||||||
|
|
||||||
|
ASSERT_THAT(recents,
|
||||||
|
ElementsAre(RecentPresetData("category_1", "preset 1", "640 x 480", false),
|
||||||
|
RecentPresetData("category_2", "preset 2", "320 x 200", true)));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(QdsRecentPresets, addFirstRecentPreset)
|
TEST_F(QdsRecentPresets, addFirstRecentPreset)
|
||||||
@@ -155,19 +194,44 @@ TEST_F(QdsRecentPresets, addFirstRecentPreset)
|
|||||||
RecentPresetsStore store{&settings};
|
RecentPresetsStore store{&settings};
|
||||||
|
|
||||||
store.add("A.Category", "Normal Application", "400 x 600");
|
store.add("A.Category", "Normal Application", "400 x 600");
|
||||||
std::vector<RecentPreset> recents = store.fetchAll();
|
std::vector<RecentPresetData> recents = store.fetchAll();
|
||||||
|
|
||||||
ASSERT_THAT(recents, ElementsAre(RecentPreset("A.Category", "Normal Application", "400 x 600")));
|
ASSERT_THAT(recents, ElementsAre(RecentPresetData("A.Category", "Normal Application", "400 x 600")));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(QdsRecentPresets, addFirstRecentUserPreset)
|
||||||
|
{
|
||||||
|
RecentPresetsStore store{&settings};
|
||||||
|
|
||||||
|
store.add("A.Category", "Normal Application", "400 x 600", /*user preset*/ true);
|
||||||
|
std::vector<RecentPresetData> recents = store.fetchAll();
|
||||||
|
|
||||||
|
ASSERT_THAT(recents,
|
||||||
|
ElementsAre(RecentPresetData("A.Category", "Normal Application", "400 x 600", true)));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(QdsRecentPresets, addExistingFirstRecentPreset)
|
TEST_F(QdsRecentPresets, addExistingFirstRecentPreset)
|
||||||
{
|
{
|
||||||
RecentPresetsStore store = aStoreWithRecents({"category/preset"});
|
RecentPresetsStore store = aStoreWithRecents({"category/preset:200 x 300"});
|
||||||
|
ASSERT_THAT(store.fetchAll(), ElementsAre(RecentPresetData("category", "preset", "200 x 300")));
|
||||||
|
|
||||||
store.add("category", "preset", "200 x 300");
|
store.add("category", "preset", "200 x 300");
|
||||||
std::vector<RecentPreset> recents = store.fetchAll();
|
std::vector<RecentPresetData> recents = store.fetchAll();
|
||||||
|
|
||||||
ASSERT_THAT(recents, ElementsAre(RecentPreset("category", "preset", "200 x 300")));
|
ASSERT_THAT(recents, ElementsAre(RecentPresetData("category", "preset", "200 x 300")));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(QdsRecentPresets, addRecentUserPresetWithSameNameAsExistingRecentNormalPreset)
|
||||||
|
{
|
||||||
|
RecentPresetsStore store = aStoreWithRecents({"category/preset:200 x 300"});
|
||||||
|
ASSERT_THAT(store.fetchAll(), ElementsAre(RecentPresetData("category", "preset", "200 x 300")));
|
||||||
|
|
||||||
|
store.add("category", "preset", "200 x 300", /*user preset*/ true);
|
||||||
|
std::vector<RecentPresetData> recents = store.fetchAll();
|
||||||
|
|
||||||
|
ASSERT_THAT(recents,
|
||||||
|
ElementsAre(RecentPresetData("category", "preset", "200 x 300", true),
|
||||||
|
RecentPresetData("category", "preset", "200 x 300", false)));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(QdsRecentPresets, addSecondRecentPreset)
|
TEST_F(QdsRecentPresets, addSecondRecentPreset)
|
||||||
@@ -175,11 +239,11 @@ TEST_F(QdsRecentPresets, addSecondRecentPreset)
|
|||||||
RecentPresetsStore store = aStoreWithRecents({"A.Category/Preset 1:800 x 600"});
|
RecentPresetsStore store = aStoreWithRecents({"A.Category/Preset 1:800 x 600"});
|
||||||
|
|
||||||
store.add("A.Category", "Preset 2", "640 x 480");
|
store.add("A.Category", "Preset 2", "640 x 480");
|
||||||
std::vector<RecentPreset> recents = store.fetchAll();
|
std::vector<RecentPresetData> recents = store.fetchAll();
|
||||||
|
|
||||||
ASSERT_THAT(recents,
|
ASSERT_THAT(recents,
|
||||||
ElementsAre(RecentPreset("A.Category", "Preset 2", "640 x 480"),
|
ElementsAre(RecentPresetData("A.Category", "Preset 2", "640 x 480"),
|
||||||
RecentPreset("A.Category", "Preset 1", "800 x 600")));
|
RecentPresetData("A.Category", "Preset 1", "800 x 600")));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(QdsRecentPresets, addSecondRecentPresetSameKindButDifferentSize)
|
TEST_F(QdsRecentPresets, addSecondRecentPresetSameKindButDifferentSize)
|
||||||
@@ -187,11 +251,11 @@ TEST_F(QdsRecentPresets, addSecondRecentPresetSameKindButDifferentSize)
|
|||||||
RecentPresetsStore store = aStoreWithRecents({"A.Category/Preset:800 x 600"});
|
RecentPresetsStore store = aStoreWithRecents({"A.Category/Preset:800 x 600"});
|
||||||
|
|
||||||
store.add("A.Category", "Preset", "640 x 480");
|
store.add("A.Category", "Preset", "640 x 480");
|
||||||
std::vector<RecentPreset> recents = store.fetchAll();
|
std::vector<RecentPresetData> recents = store.fetchAll();
|
||||||
|
|
||||||
ASSERT_THAT(recents,
|
ASSERT_THAT(recents,
|
||||||
ElementsAre(RecentPreset("A.Category", "Preset", "640 x 480"),
|
ElementsAre(RecentPresetData("A.Category", "Preset", "640 x 480"),
|
||||||
RecentPreset("A.Category", "Preset", "800 x 600")));
|
RecentPresetData("A.Category", "Preset", "800 x 600")));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(QdsRecentPresets, fetchesRecentPresetsInTheReverseOrderTheyWereAdded)
|
TEST_F(QdsRecentPresets, fetchesRecentPresetsInTheReverseOrderTheyWereAdded)
|
||||||
@@ -201,12 +265,12 @@ TEST_F(QdsRecentPresets, fetchesRecentPresetsInTheReverseOrderTheyWereAdded)
|
|||||||
store.add("A.Category", "Preset 1", "640 x 480");
|
store.add("A.Category", "Preset 1", "640 x 480");
|
||||||
store.add("A.Category", "Preset 2", "640 x 480");
|
store.add("A.Category", "Preset 2", "640 x 480");
|
||||||
store.add("A.Category", "Preset 3", "800 x 600");
|
store.add("A.Category", "Preset 3", "800 x 600");
|
||||||
std::vector<RecentPreset> recents = store.fetchAll();
|
std::vector<RecentPresetData> recents = store.fetchAll();
|
||||||
|
|
||||||
ASSERT_THAT(recents,
|
ASSERT_THAT(recents,
|
||||||
ElementsAre(RecentPreset("A.Category", "Preset 3", "800 x 600"),
|
ElementsAre(RecentPresetData("A.Category", "Preset 3", "800 x 600"),
|
||||||
RecentPreset("A.Category", "Preset 2", "640 x 480"),
|
RecentPresetData("A.Category", "Preset 2", "640 x 480"),
|
||||||
RecentPreset("A.Category", "Preset 1", "640 x 480")));
|
RecentPresetData("A.Category", "Preset 1", "640 x 480")));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(QdsRecentPresets, addingAnExistingRecentPresetMakesItTheFirst)
|
TEST_F(QdsRecentPresets, addingAnExistingRecentPresetMakesItTheFirst)
|
||||||
@@ -216,12 +280,12 @@ TEST_F(QdsRecentPresets, addingAnExistingRecentPresetMakesItTheFirst)
|
|||||||
"A.Category/Preset 3:640 x 480"});
|
"A.Category/Preset 3:640 x 480"});
|
||||||
|
|
||||||
store.add("A.Category", "Preset 3", "640 x 480");
|
store.add("A.Category", "Preset 3", "640 x 480");
|
||||||
std::vector<RecentPreset> recents = store.fetchAll();
|
std::vector<RecentPresetData> recents = store.fetchAll();
|
||||||
|
|
||||||
ASSERT_THAT(recents,
|
ASSERT_THAT(recents,
|
||||||
ElementsAre(RecentPreset("A.Category", "Preset 3", "640 x 480"),
|
ElementsAre(RecentPresetData("A.Category", "Preset 3", "640 x 480"),
|
||||||
RecentPreset("A.Category", "Preset 1", "200 x 300"),
|
RecentPresetData("A.Category", "Preset 1", "200 x 300"),
|
||||||
RecentPreset("A.Category", "Preset 2", "200 x 300")));
|
RecentPresetData("A.Category", "Preset 2", "200 x 300")));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(QdsRecentPresets, addingTooManyRecentPresetsRemovesTheOldestOne)
|
TEST_F(QdsRecentPresets, addingTooManyRecentPresetsRemovesTheOldestOne)
|
||||||
@@ -231,9 +295,9 @@ TEST_F(QdsRecentPresets, addingTooManyRecentPresetsRemovesTheOldestOne)
|
|||||||
store.setMaximum(2);
|
store.setMaximum(2);
|
||||||
|
|
||||||
store.add("A.Category", "Preset 3", "200 x 300");
|
store.add("A.Category", "Preset 3", "200 x 300");
|
||||||
std::vector<RecentPreset> recents = store.fetchAll();
|
std::vector<RecentPresetData> recents = store.fetchAll();
|
||||||
|
|
||||||
ASSERT_THAT(recents,
|
ASSERT_THAT(recents,
|
||||||
ElementsAre(RecentPreset("A.Category", "Preset 3", "200 x 300"),
|
ElementsAre(RecentPresetData("A.Category", "Preset 3", "200 x 300"),
|
||||||
RecentPreset("A.Category", "Preset 2", "200 x 300")));
|
RecentPresetData("A.Category", "Preset 2", "200 x 300")));
|
||||||
}
|
}
|
||||||
|
308
tests/auto/qml/qmldesigner/wizard/userpresets-test.cpp
Normal file
@@ -0,0 +1,308 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2022 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "test-utilities.h"
|
||||||
|
#include "userpresets.h"
|
||||||
|
|
||||||
|
#include <utils/filepath.h>
|
||||||
|
#include <utils/temporarydirectory.h>
|
||||||
|
|
||||||
|
namespace StudioWelcome {
|
||||||
|
|
||||||
|
void PrintTo(const UserPresetData &preset, std::ostream *os)
|
||||||
|
{
|
||||||
|
*os << "UserPresetData{category = " << preset.categoryId;
|
||||||
|
*os << "; wizardName = " << preset.wizardName;
|
||||||
|
*os << "; name = " << preset.name;
|
||||||
|
*os << "; screenSize = " << preset.screenSize;
|
||||||
|
*os << "; keyboard = " << preset.useQtVirtualKeyboard;
|
||||||
|
*os << "; qt = " << preset.qtVersion;
|
||||||
|
*os << "; style = " << preset.styleName;
|
||||||
|
*os << "}";
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintTo(const std::vector<UserPresetData> &presets, std::ostream *os)
|
||||||
|
{
|
||||||
|
if (presets.size() == 0) {
|
||||||
|
*os << "{}" << std::endl;
|
||||||
|
} else {
|
||||||
|
*os << "{" << std::endl;
|
||||||
|
for (size_t i = 0; i < presets.size(); ++i) {
|
||||||
|
*os << "#" << i << ": ";
|
||||||
|
PrintTo(presets[i], os);
|
||||||
|
*os << std::endl;
|
||||||
|
}
|
||||||
|
*os << "}" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace StudioWelcome
|
||||||
|
|
||||||
|
using namespace StudioWelcome;
|
||||||
|
|
||||||
|
constexpr char ARRAY_NAME[] = "UserPresets";
|
||||||
|
|
||||||
|
class QdsUserPresets : public ::testing::Test
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
void SetUp()
|
||||||
|
{
|
||||||
|
settings = std::make_unique<QSettings>(tempDir.filePath("test").toString(),
|
||||||
|
QSettings::IniFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
UserPresetsStore anEmptyStore() { return UserPresetsStore{std::move(settings)}; }
|
||||||
|
|
||||||
|
UserPresetsStore aStoreWithZeroItems()
|
||||||
|
{
|
||||||
|
settings->beginWriteArray(ARRAY_NAME, 0);
|
||||||
|
settings->endArray();
|
||||||
|
|
||||||
|
return UserPresetsStore{std::move(settings)};
|
||||||
|
}
|
||||||
|
|
||||||
|
UserPresetsStore aStoreWithOne(const UserPresetData &preset)
|
||||||
|
{
|
||||||
|
settings->beginWriteArray(ARRAY_NAME, 1);
|
||||||
|
settings->setArrayIndex(0);
|
||||||
|
|
||||||
|
settings->setValue("categoryId", preset.categoryId);
|
||||||
|
settings->setValue("wizardName", preset.wizardName);
|
||||||
|
settings->setValue("name", preset.name);
|
||||||
|
settings->setValue("screenSize", preset.screenSize);
|
||||||
|
settings->setValue("useQtVirtualKeyboard", preset.useQtVirtualKeyboard);
|
||||||
|
settings->setValue("qtVersion", preset.qtVersion);
|
||||||
|
settings->setValue("styleName", preset.styleName);
|
||||||
|
|
||||||
|
settings->endArray();
|
||||||
|
|
||||||
|
return UserPresetsStore{std::move(settings)};
|
||||||
|
}
|
||||||
|
|
||||||
|
UserPresetsStore aStoreWithPresets(const std::vector<UserPresetData> &presets)
|
||||||
|
{
|
||||||
|
settings->beginWriteArray(ARRAY_NAME, presets.size());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < presets.size(); ++i) {
|
||||||
|
settings->setArrayIndex(i);
|
||||||
|
const auto &preset = presets[i];
|
||||||
|
|
||||||
|
settings->setValue("categoryId", preset.categoryId);
|
||||||
|
settings->setValue("wizardName", preset.wizardName);
|
||||||
|
settings->setValue("name", preset.name);
|
||||||
|
settings->setValue("screenSize", preset.screenSize);
|
||||||
|
settings->setValue("useQtVirtualKeyboard", preset.useQtVirtualKeyboard);
|
||||||
|
settings->setValue("qtVersion", preset.qtVersion);
|
||||||
|
settings->setValue("styleName", preset.styleName);
|
||||||
|
}
|
||||||
|
settings->endArray();
|
||||||
|
|
||||||
|
return UserPresetsStore{std::move(settings)};
|
||||||
|
}
|
||||||
|
|
||||||
|
Utils::TemporaryDirectory tempDir{"userpresets-XXXXXX"};
|
||||||
|
std::unique_ptr<QSettings> settings;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString settingsPath;
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************* TESTS *******************/
|
||||||
|
|
||||||
|
TEST_F(QdsUserPresets, readEmptyUserPresets)
|
||||||
|
{
|
||||||
|
auto store = anEmptyStore();
|
||||||
|
|
||||||
|
auto presets = store.fetchAll();
|
||||||
|
|
||||||
|
ASSERT_THAT(presets, IsEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(QdsUserPresets, readEmptyArrayOfUserPresets)
|
||||||
|
{
|
||||||
|
auto store = aStoreWithZeroItems();
|
||||||
|
|
||||||
|
auto presets = store.fetchAll();
|
||||||
|
|
||||||
|
ASSERT_THAT(presets, IsEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(QdsUserPresets, readOneUserPreset)
|
||||||
|
{
|
||||||
|
UserPresetData preset{"A.categ", "3D App", "iPhone7", "400 x 20", true, "Qt 5", "Material Dark"};
|
||||||
|
auto store = aStoreWithOne(preset);
|
||||||
|
|
||||||
|
auto presets = store.fetchAll();
|
||||||
|
|
||||||
|
ASSERT_THAT(presets, ElementsAreArray({preset}));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(QdsUserPresets, readOneIncompleteUserPreset)
|
||||||
|
{
|
||||||
|
// A preset entry that has the required entries, but not the others.
|
||||||
|
UserPresetData preset{"A.categ", "3D App", "iPhone7", "", false, "", ""};
|
||||||
|
auto store = aStoreWithOne(preset);
|
||||||
|
|
||||||
|
auto presets = store.fetchAll();
|
||||||
|
|
||||||
|
ASSERT_THAT(presets, ElementsAreArray({preset}));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(QdsUserPresets, doesNotReadPresetsThatLackRequiredEntries)
|
||||||
|
{
|
||||||
|
// Required entries are: Category id, wizard name, preset name.
|
||||||
|
auto presetsInStore = std::vector<UserPresetData>{
|
||||||
|
UserPresetData{"", "3D App", "iPhone7", "400 x 20", true, "Qt 5", "Material Dark"},
|
||||||
|
UserPresetData{"A.categ", "", "iPhone7", "400 x 20", true, "Qt 5", "Material Dark"},
|
||||||
|
UserPresetData{"A.categ", "3D App", "", "400 x 20", true, "Qt 5", "Material Dark"},
|
||||||
|
};
|
||||||
|
auto store = aStoreWithPresets(presetsInStore);
|
||||||
|
|
||||||
|
auto presets = store.fetchAll();
|
||||||
|
|
||||||
|
ASSERT_THAT(presets, IsEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(QdsUserPresets, readSeveralUserPresets)
|
||||||
|
{
|
||||||
|
auto presetsInStore = std::vector<UserPresetData>{
|
||||||
|
UserPresetData{"A.categ", "3D App", "iPhone7", "400 x 20", true, "Qt 5", "Material Dark"},
|
||||||
|
UserPresetData{"B.categ", "2D App", "iPhone6", "200 x 50", false, "Qt 6", "Fusion"},
|
||||||
|
UserPresetData{"C.categ", "Empty", "Some Other", "60 x 30", true, "Qt 7", "Material Light"},
|
||||||
|
};
|
||||||
|
auto store = aStoreWithPresets(presetsInStore);
|
||||||
|
|
||||||
|
auto presets = store.fetchAll();
|
||||||
|
|
||||||
|
ASSERT_THAT(presets, ElementsAreArray(presetsInStore));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(QdsUserPresets, cannotSaveInvalidPreset)
|
||||||
|
{
|
||||||
|
// an invalid preset is a preset that lacks required fields.
|
||||||
|
UserPresetData invalidPreset{"", "3D App", "iPhone7", "400 x 20", true, "Qt 5", "Material Dark"};
|
||||||
|
auto store = anEmptyStore();
|
||||||
|
|
||||||
|
bool saved = store.save(invalidPreset);
|
||||||
|
|
||||||
|
auto presets = store.fetchAll();
|
||||||
|
ASSERT_THAT(presets, IsEmpty());
|
||||||
|
ASSERT_FALSE(saved);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(QdsUserPresets, savePresetInEmptyStore)
|
||||||
|
{
|
||||||
|
UserPresetData preset{"B.categ", "3D App", "iPhone7", "400 x 20", true, "Qt 5", "Material Dark"};
|
||||||
|
auto store = anEmptyStore();
|
||||||
|
|
||||||
|
store.save(preset);
|
||||||
|
|
||||||
|
auto presets = store.fetchAll();
|
||||||
|
ASSERT_THAT(presets, ElementsAre(preset));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(QdsUserPresets, saveIncompletePreset)
|
||||||
|
{
|
||||||
|
UserPresetData preset{"C.categ", "2D App", "Android", "", false, "", ""};
|
||||||
|
auto store = anEmptyStore();
|
||||||
|
|
||||||
|
store.save(preset);
|
||||||
|
|
||||||
|
auto presets = store.fetchAll();
|
||||||
|
ASSERT_THAT(presets, ElementsAre(preset));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(QdsUserPresets, cannotSavePresetWithSameName)
|
||||||
|
{
|
||||||
|
UserPresetData existing{"B.categ", "3D App", "Same Name", "400 x 20", true, "Qt 5", "Material Dark"};
|
||||||
|
auto store = aStoreWithOne(existing);
|
||||||
|
|
||||||
|
UserPresetData newPreset{"C.categ", "Empty", "Same Name", "100 x 30", false, "Qt 6", "Fusion"};
|
||||||
|
bool saved = store.save(newPreset);
|
||||||
|
|
||||||
|
ASSERT_FALSE(saved);
|
||||||
|
ASSERT_THAT(store.fetchAll(), ElementsAreArray({existing}));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(QdsUserPresets, saveNewPreset)
|
||||||
|
{
|
||||||
|
UserPresetData existing{"A.categ", "3D App", "iPhone7", "400 x 20", true, "Qt 5", "Material Dark"};
|
||||||
|
auto store = aStoreWithOne(existing);
|
||||||
|
|
||||||
|
UserPresetData newPreset{"A.categ", "Empty", "Huawei", "100 x 30", true, "Qt 6", "Fusion"};
|
||||||
|
store.save(newPreset);
|
||||||
|
|
||||||
|
auto presets = store.fetchAll();
|
||||||
|
ASSERT_THAT(presets, ElementsAre(existing, newPreset));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(QdsUserPresets, removeUserPresetFromEmptyStore)
|
||||||
|
{
|
||||||
|
UserPresetData preset{"C.categ", "2D App", "Android", "", false, "", ""};
|
||||||
|
auto store = anEmptyStore();
|
||||||
|
|
||||||
|
store.remove("A.categ", "User preset name");
|
||||||
|
|
||||||
|
auto presets = store.fetchAll();
|
||||||
|
ASSERT_THAT(presets, IsEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(QdsUserPresets, removeExistingUserPreset)
|
||||||
|
{
|
||||||
|
UserPresetData existing{"A.categ", "3D App", "iPhone7", "400 x 20", true, "Qt 5", "Material Dark"};
|
||||||
|
auto store = aStoreWithOne(existing);
|
||||||
|
|
||||||
|
store.remove("A.categ", "iPhone7");
|
||||||
|
|
||||||
|
auto presets = store.fetchAll();
|
||||||
|
ASSERT_THAT(presets, IsEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(QdsUserPresets, removeNonExistingUserPreset)
|
||||||
|
{
|
||||||
|
UserPresetData existing{"A.categ", "3D App", "iPhone7", "400 x 20", true, "Qt 5", "Material Dark"};
|
||||||
|
auto store = aStoreWithOne(existing);
|
||||||
|
|
||||||
|
store.remove("A.categ", "Android");
|
||||||
|
|
||||||
|
auto presets = store.fetchAll();
|
||||||
|
ASSERT_THAT(presets, ElementsAre(existing));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(QdsUserPresets, removeExistingUserPresetInStoreWithManyPresets)
|
||||||
|
{
|
||||||
|
auto presetsInStore = std::vector<UserPresetData>{
|
||||||
|
UserPresetData{"A.categ", "3D App", "iPhone7", "400 x 20", true, "Qt 5", "Material Dark"},
|
||||||
|
UserPresetData{"B.categ", "2D App", "iPhone6", "200 x 50", false, "Qt 6", "Fusion"},
|
||||||
|
UserPresetData{"C.categ", "Empty", "Some Other", "60 x 30", true, "Qt 7", "Material Light"},
|
||||||
|
};
|
||||||
|
auto store = aStoreWithPresets(presetsInStore);
|
||||||
|
|
||||||
|
store.remove("B.categ", "iPhone6");
|
||||||
|
|
||||||
|
auto presets = store.fetchAll();
|
||||||
|
ASSERT_THAT(presets, ElementsAre(presetsInStore[0], presetsInStore[2]));
|
||||||
|
}
|
||||||
|
|
@@ -151,7 +151,7 @@ private:
|
|||||||
|
|
||||||
QStringList presetNames(const WizardCategory &cat)
|
QStringList presetNames(const WizardCategory &cat)
|
||||||
{
|
{
|
||||||
QStringList result = Utils::transform<QStringList>(cat.items, &PresetItem::name);
|
QStringList result = Utils::transform<QStringList>(cat.items, &PresetItem::wizardName);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -319,9 +319,9 @@ TEST_F(QdsWizardFactories, createsPresetItemAndCategoryCorrectlyFromWizardFactor
|
|||||||
ASSERT_EQ("myDisplayCategory", category.name);
|
ASSERT_EQ("myDisplayCategory", category.name);
|
||||||
|
|
||||||
auto presetItem = presets["myCategoryId"].items[0];
|
auto presetItem = presets["myCategoryId"].items[0];
|
||||||
ASSERT_EQ("myName", presetItem.name);
|
ASSERT_EQ("myName", presetItem->wizardName);
|
||||||
ASSERT_EQ("myDescription", presetItem.description);
|
ASSERT_EQ("myDescription", presetItem->description);
|
||||||
ASSERT_EQ("qrc:/my/qml/path", presetItem.qmlPath.toString());
|
ASSERT_EQ("qrc:/my/qml/path", presetItem->qmlPath.toString());
|
||||||
ASSERT_EQ("\uABCD", presetItem.fontIconCode);
|
ASSERT_EQ("\uABCD", presetItem->fontIconCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|