diff options
author | The Qt Project <gerrit-noreply@qt-project.org> | 2024-01-18 12:32:01 +0000 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2024-01-18 12:32:01 +0000 |
commit | 5772a85751b905fa070f9c11fc930cb256c231c5 (patch) | |
tree | e93dd6cb9e9a0d340f0ebbc8e833f0b601492c70 | |
parent | d51e116ac4219f90ce8ca35e032f4387fe581a6f (diff) | |
parent | 399f7a1968c7d64580bdd209c4747a6979e07c93 (diff) |
Merge "Merge remote-tracking branch 'origin/qds/dev'"
242 files changed, 6205 insertions, 849 deletions
diff --git a/doc/qtdesignstudio/images/apply-effect-maker-effect.webp b/doc/qtdesignstudio/images/apply-effect-maker-effect.webp Binary files differindex 64c89bf92b..732a54eb8a 100644 --- a/doc/qtdesignstudio/images/apply-effect-maker-effect.webp +++ b/doc/qtdesignstudio/images/apply-effect-maker-effect.webp diff --git a/doc/qtdesignstudio/images/figma-binding-reset.png b/doc/qtdesignstudio/images/figma-binding-reset.png Binary files differnew file mode 100644 index 0000000000..55fed02207 --- /dev/null +++ b/doc/qtdesignstudio/images/figma-binding-reset.png diff --git a/doc/qtdesignstudio/images/qt-figma-bridge-settings.png b/doc/qtdesignstudio/images/qt-figma-bridge-settings.png Binary files differindex 0e91ceb5c8..e19eb3cd3a 100644 --- a/doc/qtdesignstudio/images/qt-figma-bridge-settings.png +++ b/doc/qtdesignstudio/images/qt-figma-bridge-settings.png diff --git a/doc/qtdesignstudio/images/qt-figma-bridge.png b/doc/qtdesignstudio/images/qt-figma-bridge.png Binary files differindex 9e2f9d16a9..1233ed03d5 100644 --- a/doc/qtdesignstudio/images/qt-figma-bridge.png +++ b/doc/qtdesignstudio/images/qt-figma-bridge.png diff --git a/doc/qtdesignstudio/images/qt-sketch-bridge-settings.png b/doc/qtdesignstudio/images/qt-sketch-bridge-settings.png Binary files differindex 9ce32618b9..60ab727607 100644 --- a/doc/qtdesignstudio/images/qt-sketch-bridge-settings.png +++ b/doc/qtdesignstudio/images/qt-sketch-bridge-settings.png diff --git a/doc/qtdesignstudio/images/qtcreator-workspace-attaching-views.webp b/doc/qtdesignstudio/images/qtcreator-workspace-attaching-views.webp Binary files differindex ee6d6f54aa..130ee78bb7 100644 --- a/doc/qtdesignstudio/images/qtcreator-workspace-attaching-views.webp +++ b/doc/qtdesignstudio/images/qtcreator-workspace-attaching-views.webp diff --git a/doc/qtdesignstudio/images/qtds-running-emulator.png b/doc/qtdesignstudio/images/qtds-running-emulator.png Binary files differdeleted file mode 100644 index b8d7470166..0000000000 --- a/doc/qtdesignstudio/images/qtds-running-emulator.png +++ /dev/null diff --git a/doc/qtdesignstudio/images/qtds-running-emulator.webp b/doc/qtdesignstudio/images/qtds-running-emulator.webp Binary files differnew file mode 100644 index 0000000000..38fb172747 --- /dev/null +++ b/doc/qtdesignstudio/images/qtds-running-emulator.webp diff --git a/doc/qtdesignstudio/images/studio-qtquick-3d-default-material.webp b/doc/qtdesignstudio/images/studio-qtquick-3d-default-material.webp Binary files differindex 0306408df1..4b7bc1a20c 100644 --- a/doc/qtdesignstudio/images/studio-qtquick-3d-default-material.webp +++ b/doc/qtdesignstudio/images/studio-qtquick-3d-default-material.webp diff --git a/doc/qtdesignstudio/images/studio-qtquick-3d-material.webp b/doc/qtdesignstudio/images/studio-qtquick-3d-material.webp Binary files differindex 1c5b1cecf2..43c4303cf8 100644 --- a/doc/qtdesignstudio/images/studio-qtquick-3d-material.webp +++ b/doc/qtdesignstudio/images/studio-qtquick-3d-material.webp diff --git a/doc/qtdesignstudio/src/prototyping/qtquick-live-preview-android.qdoc b/doc/qtdesignstudio/src/prototyping/qtquick-live-preview-android.qdoc index 69840eb0b2..2012baf1bd 100644 --- a/doc/qtdesignstudio/src/prototyping/qtquick-live-preview-android.qdoc +++ b/doc/qtdesignstudio/src/prototyping/qtquick-live-preview-android.qdoc @@ -162,7 +162,7 @@ Now the emulator runs, the qtdesignviewer APK delivered with the \QDS installation is uploaded, and the project is uploaded and shown in the emulator. - \image qtds-running-emulator.png + \image qtds-running-emulator.webp Note the following: \list diff --git a/doc/qtdesignstudio/src/qtbridge/qtbridge-figma-using.qdoc b/doc/qtdesignstudio/src/qtbridge/qtbridge-figma-using.qdoc index 5dd5f6d8bd..8b93a1e268 100644 --- a/doc/qtdesignstudio/src/qtbridge/qtbridge-figma-using.qdoc +++ b/doc/qtdesignstudio/src/qtbridge/qtbridge-figma-using.qdoc @@ -124,10 +124,14 @@ \li Purpose \row \li \uicontrol ID - \li \QBF automatically proposes identifiers for all groups and layers. + \li \QBF automatically derives identifiers for all groups and layers + from layer name. You can change them in this field. Use unique and descriptive IDs to avoid duplicate IDs when the layer and the respective artwork are imported into \QDS. + \note Once the ID is edited, the automatic assignment of ID from + layer name stops for this layer. Use \inlineimage figma-binding-reset.png + button next to \uicontrol ID to reset the ID back to automatic assignment. \row \li \uicontrol {Export as} \li Determines how to export the group or layer: @@ -146,6 +150,8 @@ into one component. \li \uicontrol Skipped completely skips the selected layer. \endlist + \note Use \inlineimage figma-binding-reset.png button next to + \uicontrol {Export as} to reset to default value. \row \li \uicontrol {Custom Component Type} \li Determines the \l{Component Types}{component type} to morph this @@ -205,13 +211,8 @@ \li Exports the component generated from this layer as an alias in the parent component. \row - \li \uicontrol Visible - \li Determines the visibility of the layer. - \row - \li \uicontrol Clip - \li Enables clipping in the component generated from the layer. The - generated component will clip its own painting, as well as the - painting of its children, to its bounding rectangle. + \li \uicontrol {Start Screen} + \li Sets the component to be the starting component in \QDS project. \endtable \section2 Settings @@ -240,6 +241,10 @@ \li Exports vectors as components of the type \l{SVG Path Item} from the Qt Quick Studio Components module. \row + \li \uicontrol {Create page hierarchy} + \li Organize the generated UI in \QDS under the directory named after the + parent page of the respective component. + \row \li \uicontrol {Reset plugin data} \li Resets all settings for all layers and groups (also in the \uicontrol Home tab) to default values. This means that you diff --git a/doc/qtdesignstudio/src/qtbridge/qtbridge-sketch-using.qdoc b/doc/qtdesignstudio/src/qtbridge/qtbridge-sketch-using.qdoc index 27b1e0e8b9..06f23a2996 100644 --- a/doc/qtdesignstudio/src/qtbridge/qtbridge-sketch-using.qdoc +++ b/doc/qtdesignstudio/src/qtbridge/qtbridge-sketch-using.qdoc @@ -278,6 +278,14 @@ \note The factor is independent of the asset scale settings, that is, 2x assets shall have a size of 5x when a scale factor of 2.5 is selected. + \section1 Organizing + + Select the \uicontrol {Organize output in pages} to organize the generated UI inside + the directory named after the parent page of the respective component. The default behavior + is to generate UI inside the directory selected during import in \QDS. + \note Using invalid characters or reservered file names for the page name will result into + imports errors as page name is used for the directory name to organize the UI files in \QDS . + \section1 Exporting Library Symbols \QBSK can handle symbols used from a local library. Before you use \QBSK to export a document diff --git a/doc/qtdesignstudio/src/views/qtquick-designer.qdoc b/doc/qtdesignstudio/src/views/qtquick-designer.qdoc index dbf07849f0..9f706ed014 100644 --- a/doc/qtdesignstudio/src/views/qtquick-designer.qdoc +++ b/doc/qtdesignstudio/src/views/qtquick-designer.qdoc @@ -225,6 +225,12 @@ \li \li \l{Managing Workspaces} \row + \li \inlineimage icons/lockoff.png + / \inlineimage icons/lockon.png + \li Toggles the views to locked or movable in \QDS. + \li + \li \l{Managing Workspaces} + \row \li \uicontrol Share \li Shares the application online using Qt Design Viewer. \li diff --git a/doc/qtdesignstudio/src/views/studio-workspaces.qdoc b/doc/qtdesignstudio/src/views/studio-workspaces.qdoc index 35fcf8418f..2b6d2e2e27 100644 --- a/doc/qtdesignstudio/src/views/studio-workspaces.qdoc +++ b/doc/qtdesignstudio/src/views/studio-workspaces.qdoc @@ -14,10 +14,11 @@ To detach views: \list + \li Toggle \inlineimage icons/lockon.png + to \inlineimage icons/lockoff.png + at the top toolbar. \li Double-click the title bar of the view. \li Start dragging the view to another position. - \li Select the \inlineimage icons/detach-group-icon.png - (\uicontrol {Detach Group}) button. \endlist You can move detached views or groups of views anywhere on the screen. @@ -32,6 +33,11 @@ To open closed views, select \uicontrol View > \uicontrol Views. + \note To lock all views, toggle + \inlineimage icons/lockoff.png + to \inlineimage icons/lockon.png + at the top toolbar. + \section1 Saving Workspaces The changes you make to a workspace are saved when you exit \QDS. diff --git a/scripts/build.py b/scripts/build.py index 6cd795a744..66d5d25d43 100755 --- a/scripts/build.py +++ b/scripts/build.py @@ -60,7 +60,8 @@ def get_arguments(): parser.add_argument('--no-cdb', help='Skip cdbextension and the python dependency packaging step (Windows)', action='store_true', default=(not common.is_windows_platform())) - parser.add_argument('--no-qbs', help='Skip building Qbs as part of Qt Creator', action='store_true', default=False); + parser.add_argument('--no-qbs', help='Skip building Qbs as part of Qt Creator', + action='store_true', default=False); parser.add_argument('--no-docs', help='Skip documentation generation', action='store_true', default=False) parser.add_argument('--no-build-date', help='Does not show build date in about dialog, for reproducible builds', @@ -75,6 +76,8 @@ def get_arguments(): action='store_true', default=False) parser.add_argument('--with-cpack', help='Create packages with cpack', action='store_true', default=False) + parser.add_argument('--with-sdk-tool', help='Builds a internal sdk-tool (not standalone) which is used in Qt Design Studio builds', + action='store_true', default=False) parser.add_argument('--add-path', help='Prepends a CMAKE_PREFIX_PATH to the build', action='append', dest='prefix_paths', default=[]) parser.add_argument('--add-module-path', help='Prepends a CMAKE_MODULE_PATH to the build', @@ -171,7 +174,7 @@ def build_qtcreator(args, paths): '-DWITH_DOCS=' + cmake_option(not args.no_docs), '-DBUILD_QBS=' + cmake_option(build_qbs), '-DBUILD_DEVELOPER_DOCS=' + cmake_option(not args.no_docs), - '-DBUILD_EXECUTABLE_SDKTOOL=OFF', + '-DBUILD_EXECUTABLE_SDKTOOL=' + cmake_option(args.with_sdk_tool), '-DQTC_FORCE_XCB=ON', '-DWITH_TESTS=' + cmake_option(args.with_tests)] cmake_args += common_cmake_arguments(args) diff --git a/scripts/build_plugin.py b/scripts/build_plugin.py index 4f4ddfdcb0..9469fc5dfe 100755 --- a/scripts/build_plugin.py +++ b/scripts/build_plugin.py @@ -147,15 +147,15 @@ def package(args, paths): if common.is_windows_platform() and args.sign_command: command = shlex.split(args.sign_command) common.check_print_call(command + [paths.install]) - common.check_print_call(['7z', 'a', '-mmt2', os.path.join(paths.result, args.name + '.7z'), '*'], + common.check_print_call(['7z', 'a', '-mmt' + args.zip_threads, os.path.join(paths.result, args.name + '.7z'), '*'], paths.install) if os.path.exists(paths.dev_install): # some plugins might not provide anything in Devel - common.check_print_call(['7z', 'a', '-mmt2', + common.check_print_call(['7z', 'a', '-mmt' + args.zip_threads, os.path.join(paths.result, args.name + '_dev.7z'), '*'], paths.dev_install) # check for existence - the DebugInfo install target doesn't work for telemetry plugin if args.with_debug_info and os.path.exists(paths.debug_install): - common.check_print_call(['7z', 'a', '-mmt2', + common.check_print_call(['7z', 'a', '-mmt' + args.zip_threads, os.path.join(paths.result, args.name + '-debug.7z'), '*'], paths.debug_install) if common.is_mac_platform() and common.codesign_call(): diff --git a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsEditDelegate.qml b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsEditDelegate.qml index 44058419be..e368bb0933 100644 --- a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsEditDelegate.qml +++ b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsEditDelegate.qml @@ -3,7 +3,6 @@ import QtQuick import CollectionDetails 1.0 as CollectionDetails -import HelperWidgets 2.0 as HelperWidgets import StudioControls 1.0 as StudioControls import StudioHelpers as StudioHelpers import StudioTheme 1.0 as StudioTheme @@ -11,119 +10,106 @@ import QtQuick.Templates as T Item { id: root - required property var columnType - property var __modifier : textEditor - property bool __changesAccepted: true + required property var columnType TableView.onCommit: { - if (root.__changesAccepted) - edit = __modifier.editor.editValue - } - - Component.onCompleted: { - __changesAccepted = true - if (edit && edit !== "") - root.__modifier.editor.editValue = edit + if (editorLoader.changesAccepted && edit !== editorLoader.acceptedValue) + edit = editorLoader.acceptedValue } onActiveFocusChanged: { - if (root.activeFocus) - root.__modifier.editor.forceActiveFocus() - } - - Connections { - id: modifierFocusConnection - - target: root.__modifier.editor - - function onActiveFocusChanged() { - if (!modifierFocusConnection.target.activeFocus) - root.TableView.commit() + if (root.activeFocus && !editorLoader.triggered && editorLoader.item) { + editorLoader.triggered = true + editorLoader.item.open() } + + // active focus should be checked again, because it might be affected by editorLoader.item + if (root.activeFocus && editorLoader.editor) + editorLoader.editor.forceActiveFocus() } - EditorPopup { - id: textEditor + Loader { + id: editorLoader - editor: textField + active: true - StudioControls.TextField { - id: textField + property var editor: editorLoader.item ? editorLoader.item.editor : null + property var editValue: editorLoader.editor ? editorLoader.editor.editValue : null + property var acceptedValue: null + property bool changesAccepted: true + property bool triggered: false - property alias editValue: textField.text + Connections { + id: modifierFocusConnection - actionIndicator.visible: false - translationIndicatorVisible: false + target: editorLoader.editor + enabled: editorLoader.item !== undefined - onRejected: root.__changesAccepted = false + function onActiveFocusChanged() { + if (!modifierFocusConnection.target.activeFocus) { + editorLoader.acceptedValue = editorLoader.editValue + root.TableView.commit() + } + } } - } - EditorPopup { - id: numberEditor + Component { + id: textEditor - editor: numberField + EditorPopup { + editor: textField - StudioControls.RealSpinBox { - id: numberField + StudioControls.TextField { + id: textField - property alias editValue: numberField.realValue + property alias editValue: textField.text - actionIndicator.visible: false - realFrom: -9e9 - realTo: 9e9 - realStepSize: 1.0 - decimals: 6 - } - } + actionIndicator.visible: false + translationIndicatorVisible: false - EditorPopup { - id: boolEditor + onRejected: editorLoader.changesAccepted = false + } + } + } - editor: boolField + Component { + id: numberEditor - StudioControls.CheckBox { - id: boolField + EditorPopup { - property alias editValue: boolField.checked + editor: numberField - actionIndicatorVisible: false - } - } + StudioControls.RealSpinBox { + id: numberField - EditorPopup { - id: colorEditor + property alias editValue: numberField.realValue - editor: colorPicker - - implicitHeight: colorPicker.height + topPadding + bottomPadding - implicitWidth: colorPicker.width + leftPadding + rightPadding - padding: 8 - - StudioHelpers.ColorBackend { - id: colorBackend + actionIndicator.visible: false + realFrom: -9e9 + realTo: 9e9 + realStepSize: 1.0 + decimals: 6 + trailingZeroes: false + } + } } - StudioControls.ColorEditorPopup { - id: colorPicker + Component { + id: boolEditor - property alias editValue: colorBackend.color - color: colorBackend.color + EditorPopup { - width: 200 + editor: boolField - Keys.onEnterPressed: colorPicker.focus = false + StudioControls.CheckBox { + id: boolField - onActivateColor: function(color) { - colorBackend.activateColor(color) - } - } + property alias editValue: boolField.checked - background: Rectangle { - color: StudioTheme.Values.themeControlBackgroundInteraction - border.color: StudioTheme.Values.themeInteraction - border.width: StudioTheme.Values.border + actionIndicatorVisible: false + } + } } } @@ -135,7 +121,7 @@ Item { implicitHeight: contentHeight implicitWidth: contentWidth - enabled: visible + focus: true visible: false Connections { @@ -144,6 +130,8 @@ Item { function onActiveFocusChanged() { if (!editorPopup.editor.activeFocus) editorPopup.close() + else if (edit) + editorPopup.editor.editValue = edit } } @@ -151,7 +139,7 @@ Item { target: editorPopup.editor.Keys function onEscapePressed() { - root.__changesAccepted = false + editorLoader.changesAccepted = false editorPopup.close() } } @@ -165,14 +153,8 @@ Item { && columnType !== CollectionDetails.DataType.Number PropertyChanges { - target: root - __modifier: textEditor - } - - PropertyChanges { - target: textEditor - visible: true - focus: true + target: editorLoader + sourceComponent: textEditor } }, State { @@ -180,14 +162,8 @@ Item { when: columnType === CollectionDetails.DataType.Number PropertyChanges { - target: root - __modifier: numberEditor - } - - PropertyChanges { - target: numberEditor - visible: true - focus: true + target: editorLoader + sourceComponent: numberEditor } }, State { @@ -195,14 +171,8 @@ Item { when: columnType === CollectionDetails.DataType.Boolean PropertyChanges { - target: root - __modifier: boolEditor - } - - PropertyChanges { - target: boolEditor - visible: true - focus: true + target: editorLoader + sourceComponent: boolEditor } }, State { @@ -210,14 +180,8 @@ Item { when: columnType === CollectionDetails.DataType.Color PropertyChanges { - target: root - __modifier: colorEditor - } - - PropertyChanges { - target: colorEditor - visible: true - focus: true + target: editorLoader + sourceComponent: null } } ] diff --git a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsToolbar.qml b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsToolbar.qml index 3e268d10f4..da13f62db0 100644 --- a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsToolbar.qml +++ b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsToolbar.qml @@ -102,7 +102,7 @@ Item { icon: StudioTheme.Constants.save_medium tooltip: qsTr("Save changes") enabled: root.model.collectionName !== "" - onClicked: root.model.saveCurrentCollection() + onClicked: root.model.saveDataStoreCollections() } IconButton { @@ -114,7 +114,6 @@ Item { } } - PlatformWidgets.FileDialog { id: fileDialog diff --git a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsView.qml b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsView.qml index e208553a4c..598ed56229 100644 --- a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsView.qml +++ b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsView.qml @@ -6,8 +6,8 @@ import QtQuick.Controls import QtQuick.Layouts import CollectionDetails 1.0 as CollectionDetails import HelperWidgets 2.0 as HelperWidgets -import StudioTheme 1.0 as StudioTheme import StudioControls 1.0 as StudioControls +import StudioTheme 1.0 as StudioTheme Rectangle { id: root @@ -18,7 +18,6 @@ Rectangle { implicitWidth: 300 implicitHeight: 400 - color: StudioTheme.Values.themeControlBackground ColumnLayout { @@ -114,14 +113,17 @@ Rectangle { color: StudioTheme.Values.themeControlBackgroundInteraction MouseArea { + id: topHeaderMouseArea + anchors.fill: parent anchors.margins: 5 acceptedButtons: Qt.LeftButton | Qt.RightButton + hoverEnabled: true onClicked: (mouse) => { tableView.model.selectColumn(index) if (mouse.button === Qt.RightButton) { - let posX = index === root.model.columnCount() - 1 ? parent.width - editProperyDialog.width : 0 + let posX = index === root.model.columnCount() - 1 ? parent.width - editPropertyDialog.width : 0 headerMenu.clickedHeaderIndex = index headerMenu.dialogPos = parent.mapToGlobal(posX, parent.height) @@ -130,9 +132,17 @@ Rectangle { } } - HelperWidgets.ToolTipArea { - anchors.fill: parent - text: root.model.propertyType(index) + ToolTip { + id: topHeaderToolTip + + property bool expectedToBeShown: topHeaderMouseArea.containsMouse + visible: expectedToBeShown && text !== "" + delay: 1000 + + onExpectedToBeShownChanged: { + if (expectedToBeShown) + text = root.model.propertyType(index) + } } } @@ -148,8 +158,8 @@ Rectangle { StudioControls.MenuItem { text: qsTr("Edit") - onTriggered: editProperyDialog.openDialog(headerMenu.clickedHeaderIndex, - headerMenu.dialogPos) + onTriggered: editPropertyDialog.openDialog(headerMenu.clickedHeaderIndex, + headerMenu.dialogPos) } StudioControls.MenuItem { @@ -206,11 +216,22 @@ Rectangle { delegate: Rectangle { id: itemCell + + clip: true implicitWidth: 100 - implicitHeight: itemText.height - border.color: dataTypeWarning !== CollectionDetails.Warning.None ? - StudioTheme.Values.themeWarning : StudioTheme.Values.themeControlBackgroundInteraction + implicitHeight: StudioTheme.Values.baseHeight + color: itemSelected ? StudioTheme.Values.themeControlBackgroundInteraction + : StudioTheme.Values.themeControlBackground border.width: 1 + border.color: { + if (dataTypeWarning !== CollectionDetails.Warning.None) + return StudioTheme.Values.themeWarning + + if (itemSelected) + return StudioTheme.Values.themeControlOutlineInteraction + + return StudioTheme.Values.themeControlBackgroundInteraction + } HelperWidgets.ToolTipArea { anchors.fill: parent @@ -220,59 +241,125 @@ Rectangle { acceptedButtons: Qt.NoButton } - Text { - id: itemText - - text: display - color: StudioTheme.Values.themePlaceholderTextColorInteraction - width: parent.width - leftPadding: 5 - topPadding: 3 - bottomPadding: 3 - font.pixelSize: StudioTheme.Values.baseFontSize - horizontalAlignment: Text.AlignLeft - verticalAlignment: Text.AlignVCenter - elide: Text.ElideRight + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.RightButton + onClicked: (mouse) => { + let row = index % tableView.model.rowCount() + + tableView.model.selectRow(row) + cellContextMenu.popup() + } + } + + Loader { + id: cellContentLoader + + property int cellColumnType: columnType ? columnType : 0 + + Component { + id: cellText + + Text { + text: display + color: itemSelected ? StudioTheme.Values.themeInteraction + : StudioTheme.Values.themePlaceholderTextColorInteraction + leftPadding: 5 + topPadding: 3 + bottomPadding: 3 + font.pixelSize: StudioTheme.Values.baseFontSize + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + elide: Text.ElideRight + } + } + + Component { + id: colorEditorComponent + + ColorViewDelegate {} + } + + function resetSource() { + if (columnType === CollectionDetails.DataType.Color) + cellContentLoader.sourceComponent = colorEditorComponent + else + cellContentLoader.sourceComponent = cellText + } + + Component.onCompleted: resetSource() + onCellColumnTypeChanged: resetSource() } TableView.editDelegate: CollectionDetailsEditDelegate { anchors { - top: itemText.top - left: itemText.left + top: itemCell.top + left: itemCell.left } } - states: [ - State { - name: "default" - when: !itemSelected + StudioControls.Menu { + id: cellContextMenu - PropertyChanges { - target: itemCell - color: StudioTheme.Values.themeControlBackground - } + width: 140 + + StudioControls.MenuItem { + HelperWidgets.IconLabel { + icon: StudioTheme.Constants.addrowabove_medium + + anchors.left: parent.left + anchors.leftMargin: 10 + anchors.verticalCenter: parent.verticalCenter - PropertyChanges { - target: itemText - color: StudioTheme.Values.themePlaceholderTextColorInteraction + Text { + text: qsTr("Add row above") + color: StudioTheme.Values.themeTextColor + anchors.left: parent.right + anchors.leftMargin: 10 + } } - }, - State { - name: "selected" - when: itemSelected - - PropertyChanges { - target: itemCell - color: StudioTheme.Values.themeControlBackgroundInteraction - border.color: StudioTheme.Values.themeControlBackground + + onTriggered: root.model.insertRow(root.model.selectedRow) + } + + StudioControls.MenuItem { + HelperWidgets.IconLabel { + icon: StudioTheme.Constants.addrowabove_medium + + anchors.left: parent.left + anchors.leftMargin: 10 + anchors.verticalCenter: parent.verticalCenter + + Text { + text: qsTr("Add row below") + color: StudioTheme.Values.themeTextColor + anchors.left: parent.right + anchors.leftMargin: 10 + } } - PropertyChanges { - target: itemText - color: StudioTheme.Values.themeInteraction + onTriggered: root.model.insertRow(root.model.selectedRow + 1) + } + + StudioControls.MenuItem { + HelperWidgets.IconLabel { + icon: StudioTheme.Constants.addrowabove_medium + + anchors.left: parent.left + anchors.leftMargin: 10 + anchors.verticalCenter: parent.verticalCenter + + Text { + text: qsTr("Delete this row") + color: StudioTheme.Values.themeTextColor + anchors.left: parent.right + anchors.leftMargin: 10 + } } + + onTriggered: root.model.removeRows(root.model.selectedRow, 1) } - ] + } } } @@ -388,10 +475,15 @@ Rectangle { } EditPropertyDialog { - id: editProperyDialog + id: editPropertyDialog model: root.model } + Connections { + target: root.parent + onIsHorizontalChanged: editPropertyDialog.close() + } + StudioControls.Dialog { id: deleteColumnDialog diff --git a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionView.qml b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionView.qml index 32f71cc231..a53453ac49 100644 --- a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionView.qml +++ b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionView.qml @@ -4,9 +4,8 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import QtQuickDesignerTheme 1.0 -import HelperWidgets 2.0 as HelperWidgets -import StudioTheme 1.0 as StudioTheme +import HelperWidgets as HelperWidgets +import StudioTheme as StudioTheme import CollectionEditorBackend Item { diff --git a/share/qtcreator/qmldesigner/collectionEditorQmlSource/ColorViewDelegate.qml b/share/qtcreator/qmldesigner/collectionEditorQmlSource/ColorViewDelegate.qml new file mode 100644 index 0000000000..1414a2dd3a --- /dev/null +++ b/share/qtcreator/qmldesigner/collectionEditorQmlSource/ColorViewDelegate.qml @@ -0,0 +1,282 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick.Layouts +import QtQuick.Shapes +import QtQuick.Templates as T +import HelperWidgets 2.0 as HelperWidgets +import StudioTheme as StudioTheme +import StudioControls as StudioControls +import QtQuickDesignerTheme +import QtQuickDesignerColorPalette + +Row { + id: colorEditor + + property color color + property bool supportGradient: false + readonly property color __editColor: edit + + property variant value: { + if (!edit) + return "white" // default color for Rectangle + + if (colorEditor.isVector3D) { + return Qt.rgba(__editColor.x, + __editColor.y, + __editColor.z, 1) + } + + return __editColor + } + + property alias gradientPropertyName: popupDialog.gradientPropertyName + + property alias gradientThumbnail: gradientThumbnail + property alias shapeGradientThumbnail: shapeGradientThumbnail + + property bool shapeGradients: false + property bool isVector3D: false + property color originalColor + + property bool __block: false + + function resetShapeColor() { + if (edit) + edit = "" + } + + function writeColor() { + if (colorEditor.isVector3D) { + edit = Qt.vector3d(colorEditor.color.r, + colorEditor.color.g, + colorEditor.color.b) + } else { + edit = colorEditor.color + } + } + + function initEditor() { + colorEditor.syncColor() + } + + // Syncing color from backend to frontend and block reflection + function syncColor() { + colorEditor.__block = true + colorEditor.color = colorEditor.value + hexTextField.syncColor() + colorEditor.__block = false + } + + Connections { + id: backendConnection + + target: colorEditor + + function onValueChanged() { + if (popupDialog.isSolid()) + colorEditor.syncColor() + } + + function on__EditColorChanged() { + if (popupDialog.isSolid()) + colorEditor.syncColor() + } + } + + Timer { + id: colorEditorTimer + + repeat: false + interval: 100 + running: false + onTriggered: { + backendConnection.enabled = false + colorEditor.writeColor() + hexTextField.syncColor() + backendConnection.enabled = true + } + } + + onColorChanged: { + if (colorEditor.__block) + return + + if (!popupDialog.isInValidState) + return + + popupDialog.commitToGradient() + + // Delay setting the color to keep ui responsive + if (popupDialog.isSolid()) + colorEditorTimer.restart() + } + + Rectangle { + id: preview + + implicitWidth: StudioTheme.Values.twoControlColumnWidth + implicitHeight: StudioTheme.Values.height + color: colorEditor.color + border.color: StudioTheme.Values.themeControlOutline + border.width: StudioTheme.Values.border + + Rectangle { + id: gradientThumbnail + + anchors.fill: parent + anchors.margins: StudioTheme.Values.border + visible: !popupDialog.isSolid() + && !colorEditor.shapeGradients + && popupDialog.isLinearGradient() + } + + Shape { + id: shape + + anchors.fill: parent + anchors.margins: StudioTheme.Values.border + visible: !popupDialog.isSolid() && colorEditor.shapeGradients + + ShapePath { + id: shapeGradientThumbnail + + startX: shape.x - 1 + startY: shape.y - 1 + strokeWidth: -1 + strokeColor: "green" + + PathLine { + x: shape.x - 1 + y: shape.height + } + PathLine { + x: shape.width + y: shape.height + } + PathLine { + x: shape.width + y: shape.y - 1 + } + } + } + + Image { + anchors.fill: parent + source: "qrc:/navigator/icon/checkers.png" + fillMode: Image.Tile + z: -1 + } + + MouseArea { + anchors.fill: parent + onClicked: { + popupDialog.visibility ? popupDialog.close() : popupDialog.open() + forceActiveFocus() + } + } + + StudioControls.PopupDialog { + id: popupDialog + + property bool isInValidState: loader.active ? popupDialog.loaderItem.isInValidState : true + property QtObject loaderItem: loader.item + property string gradientPropertyName + + keepOpen: loader.item?.eyeDropperActive ?? false + + width: 260 + + function commitToGradient() { + if (!loader.active) + return + + if (colorEditor.supportGradient && popupDialog.loaderItem.gradientModel.hasGradient) { + var hexColor = convertColorToString(colorEditor.color) + hexTextField.text = hexColor + edit = hexColor + popupDialog.loaderItem.commitGradientColor() + } + } + + function isSolid() { + if (!loader.active) + return true + + return popupDialog.loaderItem.isSolid() + } + + function isLinearGradient(){ + if (!loader.active) + return false + + return popupDialog.loaderItem.isLinearGradient() + } + + function ensureLoader() { + if (!loader.active) + loader.active = true + } + + function open() { + popupDialog.ensureLoader() + popupDialog.show(preview) + } + + function determineActiveColorMode() { + if (loader.active && popupDialog.loaderItem) + popupDialog.loaderItem.determineActiveColorMode() + else + colorEditor.syncColor() + } + + Loader { + id: loader + + active: colorEditor.supportGradient + + sourceComponent: HelperWidgets.ColorEditorPopup { + shapeGradients: colorEditor.shapeGradients + supportGradient: colorEditor.supportGradient + width: popupDialog.contentWidth + } + + onLoaded: { + popupDialog.loaderItem.initEditor() + popupDialog.titleBar = loader.item.titleBarContent + } + } + } + } + + HelperWidgets.LineEdit { + id: hexTextField + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + width: hexTextField.implicitWidth + enabled: popupDialog.isSolid() + writeValueManually: true + validator: RegularExpressionValidator { + regularExpression: /#[0-9A-Fa-f]{6}([0-9A-Fa-f]{2})?/g + } + showTranslateCheckBox: false + showExtendedFunctionButton: false + indicatorVisible: false + + onAccepted: colorEditor.color = hexTextField.text + onCommitData: { + colorEditor.color = hexTextField.text + if (popupDialog.isSolid()) + colorEditor.writeColor() + } + + function syncColor() { + hexTextField.text = colorEditor.color + } + } + + Component.onCompleted: popupDialog.determineActiveColorMode() + + on__EditColorChanged: popupDialog.determineActiveColorMode() +} diff --git a/share/qtcreator/qmldesigner/collectionEditorQmlSource/EditPropertyDialog.qml b/share/qtcreator/qmldesigner/collectionEditorQmlSource/EditPropertyDialog.qml index 37fd92cdd6..27e3527e01 100644 --- a/share/qtcreator/qmldesigner/collectionEditorQmlSource/EditPropertyDialog.qml +++ b/share/qtcreator/qmldesigner/collectionEditorQmlSource/EditPropertyDialog.qml @@ -36,6 +36,11 @@ StudioControls.Dialog { root.open() } + onWidthChanged: { + if (visible && x > parent.width) + root.close() + } + onAccepted: { if (nameTextField.text !== "" && nameTextField.text !== root.__currentName) root.model.renameColumn(root.__propertyIndex, nameTextField.text) @@ -50,13 +55,13 @@ StudioControls.Dialog { Grid { columns: 2 rows: 2 - spacing: 2 + rowSpacing: 2 + columnSpacing: 25 verticalItemAlignment: Grid.AlignVCenter Text { text: qsTr("Name") color: StudioTheme.Values.themeTextColor - width: 50 verticalAlignment: Text.AlignVCenter } @@ -129,14 +134,12 @@ StudioControls.Dialog { Row { height: 40 spacing: 5 - anchors.right: parent.right HelperWidgets.Button { id: editButton text: qsTr("Apply") enabled: nameTextField.text !== "" - width: 70 anchors.bottom: parent.bottom onClicked: root.accept() @@ -145,7 +148,6 @@ StudioControls.Dialog { HelperWidgets.Button { text: qsTr("Cancel") anchors.bottom: parent.bottom - width: 70 onClicked: root.reject() } diff --git a/share/qtcreator/qmldesigner/collectionEditorQmlSource/ImportDialog.qml b/share/qtcreator/qmldesigner/collectionEditorQmlSource/ImportDialog.qml index e7bcefff77..3f8108005c 100644 --- a/share/qtcreator/qmldesigner/collectionEditorQmlSource/ImportDialog.qml +++ b/share/qtcreator/qmldesigner/collectionEditorQmlSource/ImportDialog.qml @@ -4,10 +4,9 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import QtQuickDesignerTheme 1.0 import Qt.labs.platform as PlatformWidgets -import HelperWidgets 2.0 as HelperWidgets -import StudioControls 1.0 as StudioControls +import HelperWidgets as HelperWidgets +import StudioControls as StudioControls import StudioTheme as StudioTheme StudioControls.Dialog { diff --git a/share/qtcreator/qmldesigner/collectionEditorQmlSource/NewCollectionDialog.qml b/share/qtcreator/qmldesigner/collectionEditorQmlSource/NewCollectionDialog.qml index 5cac7fd3fc..ec87bbb872 100644 --- a/share/qtcreator/qmldesigner/collectionEditorQmlSource/NewCollectionDialog.qml +++ b/share/qtcreator/qmldesigner/collectionEditorQmlSource/NewCollectionDialog.qml @@ -4,12 +4,11 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import QtQuickDesignerTheme 1.0 import Qt.labs.platform as PlatformWidgets -import HelperWidgets 2.0 as HelperWidgets -import StudioControls 1.0 as StudioControls +import HelperWidgets as HelperWidgets +import StudioControls as StudioControls import StudioTheme as StudioTheme -import CollectionEditor 1.0 +import CollectionEditor StudioControls.Dialog { id: root diff --git a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibrary.qml b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibrary.qml index 63ac2517ae..c6db8425ff 100644 --- a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibrary.qml +++ b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibrary.qml @@ -4,10 +4,9 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import QtQuickDesignerTheme -import HelperWidgets 2.0 as HelperWidgets -import StudioControls 1.0 as StudioControls -import StudioTheme 1.0 as StudioTheme +import HelperWidgets as HelperWidgets +import StudioControls as StudioControls +import StudioTheme as StudioTheme import ContentLibraryBackend Item { diff --git a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryEffect.qml b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryEffect.qml index d418cab0db..b20cc71e15 100644 --- a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryEffect.qml +++ b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryEffect.qml @@ -3,10 +3,8 @@ import QtQuick import QtQuick.Layouts -import QtQuickDesignerTheme import HelperWidgets import QtQuick.Controls - import StudioTheme as StudioTheme import ContentLibraryBackend diff --git a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterial.qml b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterial.qml index 9160c91606..93b226d6ca 100644 --- a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterial.qml +++ b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterial.qml @@ -4,10 +4,8 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import QtQuickDesignerTheme import HelperWidgets import StudioTheme as StudioTheme - import ContentLibraryBackend import WebFetcher diff --git a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTexture.qml b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTexture.qml index 74ece1c015..f74f190040 100644 --- a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTexture.qml +++ b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTexture.qml @@ -4,10 +4,8 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import QtQuickDesignerTheme import HelperWidgets import StudioTheme as StudioTheme - import ContentLibraryBackend import WebFetcher diff --git a/share/qtcreator/qmldesigner/contentLibraryQmlSource/UnimportBundleMaterialDialog.qml b/share/qtcreator/qmldesigner/contentLibraryQmlSource/UnimportBundleMaterialDialog.qml index edb6ce3670..48be045d8b 100644 --- a/share/qtcreator/qmldesigner/contentLibraryQmlSource/UnimportBundleMaterialDialog.qml +++ b/share/qtcreator/qmldesigner/contentLibraryQmlSource/UnimportBundleMaterialDialog.qml @@ -4,7 +4,6 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import QtQuickDesignerTheme import HelperWidgets import StudioControls as StudioControls import StudioTheme as StudioTheme diff --git a/share/qtcreator/qmldesigner/edit3dQmlSource/BakeLightsProgressDialog.qml b/share/qtcreator/qmldesigner/edit3dQmlSource/BakeLightsProgressDialog.qml index 259a0a1ab5..7da6aeffb1 100644 --- a/share/qtcreator/qmldesigner/edit3dQmlSource/BakeLightsProgressDialog.qml +++ b/share/qtcreator/qmldesigner/edit3dQmlSource/BakeLightsProgressDialog.qml @@ -4,7 +4,6 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import QtQuickDesignerTheme import HelperWidgets import StudioControls as StudioControls import StudioTheme as StudioTheme diff --git a/share/qtcreator/qmldesigner/edit3dQmlSource/BakeLightsSetupDialog.qml b/share/qtcreator/qmldesigner/edit3dQmlSource/BakeLightsSetupDialog.qml index 5c202a4a60..7366bef8c1 100644 --- a/share/qtcreator/qmldesigner/edit3dQmlSource/BakeLightsSetupDialog.qml +++ b/share/qtcreator/qmldesigner/edit3dQmlSource/BakeLightsSetupDialog.qml @@ -4,7 +4,6 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import QtQuickDesignerTheme import HelperWidgets import StudioControls as StudioControls import StudioTheme as StudioTheme diff --git a/share/qtcreator/qmldesigner/edit3dQmlSource/SnapConfigurationDialog.qml b/share/qtcreator/qmldesigner/edit3dQmlSource/SnapConfigurationDialog.qml index 43460b7f71..61551216c1 100644 --- a/share/qtcreator/qmldesigner/edit3dQmlSource/SnapConfigurationDialog.qml +++ b/share/qtcreator/qmldesigner/edit3dQmlSource/SnapConfigurationDialog.qml @@ -4,7 +4,6 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import QtQuickDesignerTheme import HelperWidgets as HelperWidgets import StudioControls as StudioControls import StudioTheme as StudioTheme diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/BlurHelper.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/BlurHelper.qml index 0227d0f54a..da68339603 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/BlurHelper.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/BlurHelper.qml @@ -12,6 +12,7 @@ Item { property alias blurSrc3: blurredItemSource3 property alias blurSrc4: blurredItemSource4 property alias blurSrc5: blurredItemSource5 + property Item source: null component BlurItem: ShaderEffect { property vector2d offset: Qt.vector2d((1.0 + rootItem.blurMultiplier) / width, @@ -37,8 +38,8 @@ Item { // Size of the first blurred item is by default half of the source. // Increase for quality and decrease for performance & more blur. readonly property int blurItemSize: 8 - width: Math.ceil(rootItem.width / 16) * blurItemSize - height: Math.ceil(rootItem.height / 16) * blurItemSize + width: Math.ceil((rootItem.source ? rootItem.source.width : 16) / 16) * blurItemSize + height: Math.ceil((rootItem.source ? rootItem.source.height : 16) / 16) * blurItemSize } BlurItem { id: blurredItemSource2 diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectCompositionNode.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectCompositionNode.qml index 2ccaeaf36c..c1cd4632d2 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectCompositionNode.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectCompositionNode.qml @@ -3,10 +3,9 @@ import QtQuick import QtQuick.Controls -import QtQuickDesignerTheme import HelperWidgets as HelperWidgets import StudioControls as StudioControls -import StudioTheme 1.0 as StudioTheme +import StudioTheme as StudioTheme import EffectMakerBackend HelperWidgets.Section { diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectCompositionNodeUniform.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectCompositionNodeUniform.qml index d696fccc1e..9cd42633d4 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectCompositionNodeUniform.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectCompositionNodeUniform.qml @@ -4,10 +4,9 @@ import QtQuick import QtQuick.Dialogs import QtQuick.Layouts -import QtQuickDesignerTheme import HelperWidgets as HelperWidgets import StudioControls as StudioControls -import StudioTheme 1.0 as StudioTheme +import StudioTheme as StudioTheme import EffectMakerBackend Item { diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml index d3ccb36a74..d86aaad27d 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml @@ -65,12 +65,12 @@ Item { EffectMakerTopBar { onAddClicked: { - root.onSaveChangesCallback = () => { EffectMakerBackend.effectMakerModel.clear() } + root.onSaveChangesCallback = () => { EffectMakerBackend.effectMakerModel.clear(true) } if (EffectMakerBackend.effectMakerModel.hasUnsavedChanges) saveChangesDialog.open() else - EffectMakerBackend.effectMakerModel.clear() + EffectMakerBackend.effectMakerModel.clear(true) } onSaveClicked: { diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMakerPreview.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMakerPreview.qml index ea0b2d1295..16dc2bf3a1 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMakerPreview.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMakerPreview.qml @@ -2,10 +2,9 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 import QtQuick -import QtQuickDesignerTheme import HelperWidgets as HelperWidgets import StudioControls as StudioControls -import StudioTheme 1.0 as StudioTheme +import StudioTheme as StudioTheme import EffectMakerBackend Column { @@ -196,7 +195,7 @@ Column { BlurHelper { id: blurHelper - anchors.fill: parent + source: source property int blurMax: g_propertyData.blur_helper_max_level ? g_propertyData.blur_helper_max_level : 64 property real blurMultiplier: g_propertyData.blurMultiplier ? g_propertyData.blurMultiplier : 0 } diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMakerTopBar.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMakerTopBar.qml index 9c962655e3..2dfa856237 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMakerTopBar.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMakerTopBar.qml @@ -2,10 +2,9 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 import QtQuick -import QtQuickDesignerTheme import HelperWidgets as HelperWidgets import StudioControls as StudioControls -import StudioTheme 1.0 as StudioTheme +import StudioTheme as StudioTheme import EffectMakerBackend Rectangle { diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectNode.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectNode.qml index f3fca1ccec..865b60cf82 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectNode.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectNode.qml @@ -3,10 +3,9 @@ import QtQuick import QtQuick.Controls -import QtQuickDesignerTheme import HelperWidgets import StudioControls as StudioControls -import StudioTheme 1.0 as StudioTheme +import StudioTheme as StudioTheme import EffectMakerBackend Rectangle { diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectNodesComboBox.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectNodesComboBox.qml index a2187d4aba..dc6f54a5aa 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectNodesComboBox.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectNodesComboBox.qml @@ -2,10 +2,9 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 import QtQuick -import QtQuickDesignerTheme import HelperWidgets as HelperWidgets import StudioControls as StudioControls -import StudioTheme 1.0 as StudioTheme +import StudioTheme as StudioTheme import EffectMakerBackend StudioControls.ComboBox { diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/PreviewImagesComboBox.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/PreviewImagesComboBox.qml index feadaa1d94..988b28a072 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/PreviewImagesComboBox.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/PreviewImagesComboBox.qml @@ -2,10 +2,9 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 import QtQuick -import QtQuickDesignerTheme import HelperWidgets as HelperWidgets import StudioControls as StudioControls -import StudioTheme 1.0 as StudioTheme +import StudioTheme as StudioTheme import EffectMakerBackend StudioControls.ComboBox { diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/SaveAsDialog.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/SaveAsDialog.qml index 8e762cebbd..eef2411669 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/SaveAsDialog.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/SaveAsDialog.qml @@ -84,6 +84,9 @@ StudioControls.Dialog { text: qsTr("Save") enabled: nameText.text !== "" onClicked: { + if (!enabled) // needed since this event handler can be triggered from keyboard events + return + EffectMakerBackend.effectMakerModel.saveComposition(nameText.text) if (root.clearOnClose) { diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/ValueBool.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/ValueBool.qml index 201f997698..f59a3a4408 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/ValueBool.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/ValueBool.qml @@ -2,9 +2,8 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 import QtQuick -import QtQuickDesignerTheme import StudioControls as StudioControls -import StudioTheme 1.0 as StudioTheme +import StudioTheme as StudioTheme import EffectMakerBackend StudioControls.CheckBox { diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/ValueColor.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/ValueColor.qml index 1f601f9063..5d86d3513f 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/ValueColor.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/ValueColor.qml @@ -2,9 +2,8 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 import QtQuick -import QtQuickDesignerTheme import StudioControls as StudioControls -import StudioTheme 1.0 as StudioTheme +import StudioTheme as StudioTheme import EffectMakerBackend Row { diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/ValueDefine.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/ValueDefine.qml index d5a6cf139a..7aa4a8a568 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/ValueDefine.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/ValueDefine.qml @@ -2,9 +2,8 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 import QtQuick -import QtQuickDesignerTheme import StudioControls as StudioControls -import StudioTheme 1.0 as StudioTheme +import StudioTheme as StudioTheme import EffectMakerBackend Row { diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/ValueFloat.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/ValueFloat.qml index 9c2d2c80a2..ea557b1877 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/ValueFloat.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/ValueFloat.qml @@ -2,9 +2,8 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 import QtQuick -import QtQuickDesignerTheme import StudioControls as StudioControls -import StudioTheme 1.0 as StudioTheme +import StudioTheme as StudioTheme import EffectMakerBackend Row { diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/ValueImage.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/ValueImage.qml index 832350ef17..a4f3ccd5ae 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/ValueImage.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/ValueImage.qml @@ -2,9 +2,8 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 import QtQuick -import QtQuickDesignerTheme import HelperWidgets as HelperWidgets -import StudioTheme 1.0 as StudioTheme +import StudioTheme as StudioTheme import EffectMakerBackend Row { diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/ValueInt.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/ValueInt.qml index b5db8db05e..38a95f4970 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/ValueInt.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/ValueInt.qml @@ -2,9 +2,8 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 import QtQuick -import QtQuickDesignerTheme import StudioControls as StudioControls -import StudioTheme 1.0 as StudioTheme +import StudioTheme as StudioTheme import EffectMakerBackend Row { diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/ValueVec2.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/ValueVec2.qml index 9207e98a62..a5c0c9db74 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/ValueVec2.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/ValueVec2.qml @@ -3,9 +3,8 @@ import QtQuick import QtQuick.Layouts -import QtQuickDesignerTheme import StudioControls as StudioControls -import StudioTheme 1.0 as StudioTheme +import StudioTheme as StudioTheme import EffectMakerBackend RowLayout { diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/ValueVec3.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/ValueVec3.qml index 52df4c999a..5369795a68 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/ValueVec3.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/ValueVec3.qml @@ -3,9 +3,8 @@ import QtQuick import QtQuick.Layouts -import QtQuickDesignerTheme import StudioControls as StudioControls -import StudioTheme 1.0 as StudioTheme +import StudioTheme as StudioTheme import EffectMakerBackend RowLayout { diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/ValueVec4.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/ValueVec4.qml index 05954e5b65..bb93cd0008 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/ValueVec4.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/ValueVec4.qml @@ -3,9 +3,8 @@ import QtQuick import QtQuick.Layouts -import QtQuickDesignerTheme import StudioControls as StudioControls -import StudioTheme 1.0 as StudioTheme +import StudioTheme as StudioTheme import EffectMakerBackend RowLayout { diff --git a/share/qtcreator/qmldesigner/insight/Main.qml b/share/qtcreator/qmldesigner/insight/Main.qml index 14a69ce80f..a6be9cb1be 100644 --- a/share/qtcreator/qmldesigner/insight/Main.qml +++ b/share/qtcreator/qmldesigner/insight/Main.qml @@ -3,9 +3,8 @@ import QtQuick import QtQuick.Controls -import QtQuickDesignerTheme 1.0 -import HelperWidgets 2.0 as HelperWidgets -import StudioControls 1.0 as StudioControls +import HelperWidgets as HelperWidgets +import StudioControls as StudioControls import StudioTheme as StudioTheme Rectangle { diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/AddModuleView.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/AddModuleView.qml index 6ed7052b8e..e036139315 100644 --- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/AddModuleView.qml +++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/AddModuleView.qml @@ -1,11 +1,10 @@ // Copyright (C) 2021 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuickDesignerTheme 1.0 -import HelperWidgets 2.0 -import StudioTheme 1.0 as StudioTheme +import QtQuick +import QtQuick.Controls +import HelperWidgets +import StudioTheme as StudioTheme import ItemLibraryBackend Column { diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml index 1178de4a87..266dba995d 100644 --- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml +++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml @@ -1,12 +1,12 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuickDesignerTheme 1.0 -import HelperWidgets 2.0 -import StudioTheme 1.0 as StudioTheme +import QtQuick +import QtQuick.Controls +import HelperWidgets +import StudioTheme as StudioTheme import ItemLibraryBackend +import QtQuickDesignerTheme Item { id: delegateRoot diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml index cf5049d647..62c907e76f 100644 --- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml +++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml @@ -2,11 +2,11 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 import QtQuick import QtQuick.Layouts -import QtQuickDesignerTheme 1.0 -import HelperWidgets 2.0 as HelperWidgets -import StudioControls 1.0 as StudioControls -import StudioTheme 1.0 as StudioTheme +import HelperWidgets as HelperWidgets +import StudioControls as StudioControls +import StudioTheme as StudioTheme import ItemLibraryBackend +import QtQuickDesignerTheme /* The view displaying the item grid. The following Qml context properties have to be set: - ItemLibraryModel itemLibraryModel diff --git a/share/qtcreator/qmldesigner/materialBrowserQmlSource/ChooseMaterialProperty.qml b/share/qtcreator/qmldesigner/materialBrowserQmlSource/ChooseMaterialProperty.qml index ddbdbfa7c8..770cde48c9 100644 --- a/share/qtcreator/qmldesigner/materialBrowserQmlSource/ChooseMaterialProperty.qml +++ b/share/qtcreator/qmldesigner/materialBrowserQmlSource/ChooseMaterialProperty.qml @@ -4,7 +4,6 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import QtQuickDesignerTheme import HelperWidgets import StudioControls as StudioControls import StudioTheme as StudioTheme diff --git a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml index e0dacef36b..d84570b434 100644 --- a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml +++ b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml @@ -2,10 +2,9 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 import QtQuick -import QtQuickDesignerTheme 1.0 -import HelperWidgets 2.0 as HelperWidgets -import StudioControls 1.0 as StudioControls -import StudioTheme 1.0 as StudioTheme +import HelperWidgets as HelperWidgets +import StudioControls as StudioControls +import StudioTheme as StudioTheme import MaterialBrowserBackend Item { diff --git a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowserItemName.qml b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowserItemName.qml index 800217bac5..18dbd3b194 100644 --- a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowserItemName.qml +++ b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowserItemName.qml @@ -1,11 +1,10 @@ // Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import QtQuickDesignerTheme 1.0 -import HelperWidgets 2.0 -import StudioTheme 1.0 as StudioTheme +import QtQuick +import QtQuick.Layouts +import HelperWidgets +import StudioTheme as StudioTheme import MaterialBrowserBackend TextInput { diff --git a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialItem.qml b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialItem.qml index ce1b12aeae..47eed8a7d6 100644 --- a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialItem.qml +++ b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialItem.qml @@ -1,11 +1,10 @@ // Copyright (C) 2022 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import QtQuickDesignerTheme 1.0 -import HelperWidgets 2.0 -import StudioTheme 1.0 as StudioTheme +import QtQuick +import QtQuick.Layouts +import HelperWidgets +import StudioTheme as StudioTheme import MaterialBrowserBackend Item { diff --git a/share/qtcreator/qmldesigner/materialBrowserQmlSource/TextureItem.qml b/share/qtcreator/qmldesigner/materialBrowserQmlSource/TextureItem.qml index 4eaa449c62..5ed132461b 100644 --- a/share/qtcreator/qmldesigner/materialBrowserQmlSource/TextureItem.qml +++ b/share/qtcreator/qmldesigner/materialBrowserQmlSource/TextureItem.qml @@ -4,7 +4,6 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import QtQuickDesignerTheme import HelperWidgets import StudioTheme as StudioTheme import MaterialBrowserBackend diff --git a/share/qtcreator/qmldesigner/materialEditorQmlSources/EmptyMaterialEditorPane.qml b/share/qtcreator/qmldesigner/materialEditorQmlSources/EmptyMaterialEditorPane.qml index 39b0929a44..0c6d7e39b2 100644 --- a/share/qtcreator/qmldesigner/materialEditorQmlSources/EmptyMaterialEditorPane.qml +++ b/share/qtcreator/qmldesigner/materialEditorQmlSources/EmptyMaterialEditorPane.qml @@ -2,9 +2,8 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 import QtQuick -import QtQuickDesignerTheme 1.0 -import HelperWidgets 2.0 -import StudioTheme 1.0 as StudioTheme +import HelperWidgets +import StudioTheme as StudioTheme PropertyEditorPane { id: root diff --git a/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorPane.qml b/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorPane.qml index 0187cde695..dde7ecd0dc 100644 --- a/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorPane.qml +++ b/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorPane.qml @@ -2,8 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 import QtQuick -import QtQuickDesignerTheme 1.0 -import HelperWidgets 2.0 +import HelperWidgets PropertyEditorPane { id: itemPane diff --git a/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorToolBar.qml b/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorToolBar.qml index d5a9acf974..290c84317d 100644 --- a/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorToolBar.qml +++ b/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorToolBar.qml @@ -2,11 +2,10 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 import QtQuick -import QtQuickDesignerTheme 1.0 -import HelperWidgets 2.0 as HelperWidgets -import StudioControls 1.0 as StudioControls -import StudioTheme 1.0 as StudioTheme -import MaterialToolBarAction 1.0 +import HelperWidgets as HelperWidgets +import StudioControls as StudioControls +import StudioTheme as StudioTheme +import MaterialToolBarAction Rectangle { id: root diff --git a/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorTopSection.qml b/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorTopSection.qml index dbc023d83b..23311636bc 100644 --- a/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorTopSection.qml +++ b/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorTopSection.qml @@ -4,10 +4,9 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import QtQuickDesignerTheme 1.0 -import HelperWidgets 2.0 as HelperWidgets -import StudioControls 1.0 as StudioControls -import StudioTheme 1.0 as StudioTheme +import HelperWidgets as HelperWidgets +import StudioControls as StudioControls +import StudioTheme as StudioTheme Column { id: root diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/AnchorRow.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/AnchorRow.qml index a6c57a73ed..34fa2f3be3 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/AnchorRow.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/AnchorRow.qml @@ -1,13 +1,11 @@ // Copyright (C) 2021 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import HelperWidgets 2.0 -import QtQuickDesignerTheme 1.0 - -import StudioControls 1.0 as StudioControls -import StudioTheme 1.0 as StudioTheme +import QtQuick +import QtQuick.Layouts +import HelperWidgets +import StudioControls as StudioControls +import StudioTheme as StudioTheme SectionLayout { id: anchorRow diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/AbstractButtonSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/AbstractButtonSection.qml index e625e5c842..b4b3362aa7 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/AbstractButtonSection.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/AbstractButtonSection.qml @@ -1,11 +1,10 @@ // Copyright (C) 2022 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import HelperWidgets 2.0 -import QtQuickDesignerTheme 1.0 -import StudioTheme 1.0 as StudioTheme +import QtQuick +import QtQuick.Layouts +import HelperWidgets +import StudioTheme as StudioTheme Section { caption: qsTr("Button Content") diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ButtonSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ButtonSection.qml index dbfbfd1fd4..977ac431bc 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ButtonSection.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ButtonSection.qml @@ -1,11 +1,10 @@ // Copyright (C) 2022 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import HelperWidgets 2.0 -import QtQuickDesignerTheme 1.0 -import StudioTheme 1.0 as StudioTheme +import QtQuick +import QtQuick.Layouts +import HelperWidgets +import StudioTheme as StudioTheme Section { id: section diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ButtonSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ButtonSpecifics.qml index ab22345980..2c10d89ad8 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ButtonSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ButtonSpecifics.qml @@ -1,11 +1,10 @@ // Copyright (C) 2022 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import HelperWidgets 2.0 -import QtQuickDesignerTheme 1.0 -import StudioTheme 1.0 as StudioTheme +import QtQuick +import QtQuick.Layouts +import HelperWidgets +import StudioTheme as StudioTheme Column { anchors.left: parent.left diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ControlSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ControlSpecifics.qml index 687053b324..dd28d662cd 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ControlSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ControlSpecifics.qml @@ -1,11 +1,10 @@ // Copyright (C) 2022 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import HelperWidgets 2.0 -import QtQuickDesignerTheme 1.0 -import StudioTheme 1.0 as StudioTheme +import QtQuick +import QtQuick.Layouts +import HelperWidgets +import StudioTheme as StudioTheme Column { anchors.left: parent.left diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/QtObjectPane.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/QtObjectPane.qml index 92e157dfdc..12be7b8f34 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/QtObjectPane.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/QtObjectPane.qml @@ -3,9 +3,8 @@ import QtQuick import QtQuick.Layouts -import QtQuickDesignerTheme 1.0 -import HelperWidgets 2.0 -import StudioTheme 1.0 as StudioTheme +import HelperWidgets +import StudioTheme as StudioTheme PropertyEditorPane { id: itemPane diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/emptyPane.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/emptyPane.qml index a5dc28f6f8..3ec325d8f1 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/emptyPane.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/emptyPane.qml @@ -1,18 +1,17 @@ // Copyright (C) 2021 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -import QtQuick 2.15 -import QtQuick.Controls 2.15 as Controls -import QtQuick.Layouts 1.15 -import HelperWidgets 2.0 -import QtQuickDesignerTheme 1.0 -import StudioTheme 1.0 as StudioTheme +import QtQuick +import QtQuick.Controls as Controls +import QtQuick.Layouts +import HelperWidgets +import StudioTheme as StudioTheme Rectangle { id: itemPane width: 320 height: 400 - color: Theme.qmlDesignerBackgroundColorDarkAlternate() + color: StudioTheme.Values.themePanelBackground ColumnLayout { id: mainColumn diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Object3DPane.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Object3DPane.qml index c532281d6f..e4f7554442 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Object3DPane.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Object3DPane.qml @@ -3,9 +3,8 @@ import QtQuick import QtQuick.Layouts -import QtQuickDesignerTheme 1.0 -import HelperWidgets 2.0 -import StudioTheme 1.0 as StudioTheme +import HelperWidgets +import StudioTheme as StudioTheme PropertyEditorPane { id: itemPane diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ButtonRowButton.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ButtonRowButton.qml index 3d4373cdf0..9b376a82d8 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ButtonRowButton.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ButtonRowButton.qml @@ -1,10 +1,9 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import QtQuickDesignerTheme 1.0 -import StudioTheme 1.0 as StudioTheme +import QtQuick +import QtQuick.Layouts +import StudioTheme as StudioTheme Item { id: buttonRowButton diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorEditor.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorEditor.qml index 3262b03065..f9e72ad67d 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorEditor.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorEditor.qml @@ -7,7 +7,6 @@ import QtQuick.Shapes import QtQuick.Templates as T import StudioTheme as StudioTheme import StudioControls as StudioControls -import QtQuickDesignerTheme import QtQuickDesignerColorPalette SecondColumnLayout { @@ -36,6 +35,7 @@ SecondColumnLayout { property alias shapeGradientThumbnail: shapeGradientThumbnail property alias showExtendedFunctionButton: hexTextField.showExtendedFunctionButton + property alias showHexTextField: hexTextField.visible property bool shapeGradients: false property color originalColor diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorEditorPopup.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorEditorPopup.qml index fcf2d341b8..0591d1cb5a 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorEditorPopup.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorEditorPopup.qml @@ -5,7 +5,6 @@ import QtQuick import QtQuick.Layouts import QtQuick.Shapes import QtQuick.Templates as T -import QtQuickDesignerTheme import StudioTheme as StudioTheme import StudioControls as StudioControls import QtQuickDesignerColorPalette @@ -393,10 +392,7 @@ Column { } } } - } - Connections { - target: modelNodeBackend function onSelectionChanged() { root.initEditor() } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComponentSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComponentSection.qml index 49809cb9d9..a29bda0ba5 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComponentSection.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComponentSection.qml @@ -1,13 +1,12 @@ // Copyright (C) 2021 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import QtQuickDesignerTheme 1.0 -import QtQuick.Templates 2.15 as T -import HelperWidgets 2.0 -import StudioTheme 1.0 as StudioTheme +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Templates as T +import HelperWidgets +import StudioTheme as StudioTheme Section { id: root diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ExpressionTextField.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ExpressionTextField.qml index b968768043..7b67735188 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ExpressionTextField.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ExpressionTextField.qml @@ -1,12 +1,11 @@ // Copyright (C) 2021 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -import QtQuick 2.15 -import QtQuick.Window 2.15 -import QtQuick.Controls 2.15 -import QtQuickDesignerTheme 1.0 -import StudioControls 1.0 as StudioControls -import StudioTheme 1.0 as StudioTheme +import QtQuick +import QtQuick.Window +import QtQuick.Controls +import StudioControls as StudioControls +import StudioTheme as StudioTheme StudioControls.TextField { id: textField diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ExtendedFunctionLogic.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ExtendedFunctionLogic.qml index c82aa2cea5..76e6bd8f09 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ExtendedFunctionLogic.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ExtendedFunctionLogic.qml @@ -1,11 +1,10 @@ // Copyright (C) 2021 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -import QtQuick 2.15 -import StudioControls 1.0 as StudioControls -import StudioTheme 1.0 as StudioTheme -import QtQuickDesignerTheme 1.0 -import HelperWidgets 2.0 +import QtQuick +import StudioControls as StudioControls +import StudioTheme as StudioTheme +import HelperWidgets Item { id: extendedFunctionButton diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/GradientPresetList.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/GradientPresetList.qml index 6af54c11b9..2503d35103 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/GradientPresetList.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/GradientPresetList.qml @@ -4,7 +4,6 @@ import QtQuick import QtQuick.Layouts import Qt.labs.platform -import QtQuickDesignerTheme import HelperWidgets import StudioControls as StudioControls import StudioTheme as StudioTheme diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/GradientPresetTabContent.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/GradientPresetTabContent.qml index 050fb64f48..d53c512c3b 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/GradientPresetTabContent.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/GradientPresetTabContent.qml @@ -1,13 +1,12 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import QtQuickDesignerTheme 1.0 -import HelperWidgets 2.0 -import StudioControls 1.0 as StudioControls -import StudioTheme 1.0 as StudioTheme +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import HelperWidgets +import StudioControls as StudioControls +import StudioTheme as StudioTheme Rectangle { id: tabBackground diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/IconButton.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/IconButton.qml index 4852b05a98..008320cb92 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/IconButton.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/IconButton.qml @@ -1,10 +1,9 @@ // Copyright (C) 2022 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuickDesignerTheme 1.0 -import StudioTheme 1.0 as StudioTheme +import QtQuick +import QtQuick.Controls +import StudioTheme as StudioTheme Rectangle { id: root diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/LineEdit.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/LineEdit.qml index dffe3d779e..96378cb6d7 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/LineEdit.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/LineEdit.qml @@ -1,10 +1,9 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -import QtQuick 2.15 -import StudioControls 1.0 as StudioControls -import StudioTheme 1.0 as StudioTheme -import QtQuickDesignerTheme 1.0 +import QtQuick +import StudioControls as StudioControls +import StudioTheme as StudioTheme StudioControls.TextField { id: lineEdit diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/PropertyEditorPane.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/PropertyEditorPane.qml index 26151ec916..f35a21f453 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/PropertyEditorPane.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/PropertyEditorPane.qml @@ -4,16 +4,15 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import QtQuickDesignerTheme 1.0 -import HelperWidgets 2.0 as HelperWidgets -import StudioTheme 1.0 as StudioTheme +import HelperWidgets as HelperWidgets +import StudioTheme as StudioTheme Rectangle { id: itemPane width: 320 height: 400 - color: Theme.qmlDesignerBackgroundColorDarkAlternate() + color: StudioTheme.Values.themePanelBackground Component.onCompleted: Controller.mainScrollView = mainScrollView diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/RoundedPanel.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/RoundedPanel.qml index 5cfd1076bf..aec3a2e3f2 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/RoundedPanel.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/RoundedPanel.qml @@ -1,10 +1,9 @@ // Copyright (C) 2021 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import QtQuickDesignerTheme 1.0 -import StudioTheme 1.0 as StudioTheme +import QtQuick +import QtQuick.Layouts +import StudioTheme as StudioTheme Rectangle { id: panel diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ScrollView.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ScrollView.qml index abe62052e8..707f3e5669 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ScrollView.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ScrollView.qml @@ -28,6 +28,8 @@ Flickable { // and set the ads focus on it. objectName: "__mainSrollView" + flickDeceleration: 10000 + HoverHandler { id: hoverHandler } ScrollBar.horizontal: StudioControls.TransientScrollBar { diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml index 5eb40e42cc..f078f3dd48 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml @@ -1,12 +1,11 @@ // Copyright (C) 2021 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -import QtQuick 2.15 -import QtQuick.Controls 2.15 as Controls -import QtQuick.Layouts 1.15 -import QtQuickDesignerTheme 1.0 -import StudioControls 1.0 as StudioControls -import StudioTheme 1.0 as StudioTheme +import QtQuick +import QtQuick.Controls as Controls +import QtQuick.Layouts +import StudioControls as StudioControls +import StudioTheme as StudioTheme Item { id: section diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml index 3b00a30a1f..16d74c66f0 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml @@ -7,7 +7,6 @@ import QtQuick.Controls import HelperWidgets import StudioControls as StudioControls import StudioTheme as StudioTheme -import QtQuickDesignerTheme Row { id: root diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/qmldir b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/qmldir index 6fc885ac57..94c3da2718 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/qmldir +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/qmldir @@ -10,6 +10,7 @@ ButtonRowButton 2.0 ButtonRowButton.qml CharacterSection 2.0 CharacterSection.qml CheckBox 2.0 CheckBox.qml ColorEditor 2.0 ColorEditor.qml +ColorEditorPopup 2.0 ColorEditorPopup.qml ColorLogic 2.0 ColorLogic.qml ComboBox 2.0 ComboBox.qml ComponentButton 2.0 ComponentButton.qml diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ColorEditor.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ColorEditor.qml index 458cceb31e..9069370e9c 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ColorEditor.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ColorEditor.qml @@ -3,7 +3,6 @@ import QtQuick import StudioTheme as StudioTheme -import QtQuickDesignerTheme import QtQuickDesignerColorPalette import StudioHelpers diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/PopupDialog.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/PopupDialog.qml index 594e115639..4da26cf494 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/PopupDialog.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/PopupDialog.qml @@ -104,7 +104,7 @@ QtObject { return root.maximumHeight + (2 * window.margin) } visible: false - flags: Qt.FramelessWindowHint | Qt.Dialog + flags: Qt.FramelessWindowHint | Qt.Dialog | Qt.WindowStaysOnTopHint color: "transparent" onClosing: function (close) { diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBox.qml index 19496da346..37612af13f 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBox.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBox.qml @@ -37,6 +37,8 @@ T.SpinBox { property bool drag: false property bool sliderDrag: sliderPopup.drag + property bool trailingZeroes: true + property bool dirty: false // user modification flag // TODO Not used anymore. Will be removed when all dependencies were removed. @@ -204,11 +206,14 @@ T.SpinBox { textFromValue: function (value, locale) { locale.numberOptions = Locale.OmitGroupSeparator - return Number(control.realValue).toLocaleString(locale, 'f', control.decimals) + var decimals = trailingZeroes ? control.decimals : decimalCounter(value) + + return Number(control.realValue).toLocaleString(locale, 'f', decimals) } valueFromText: function (text, locale) { control.setRealValue(Number.fromLocaleString(locale, spinBoxInput.text)) + return 0 } @@ -400,4 +405,14 @@ T.SpinBox { if (control.realValue !== currValue) control.realValueModified() } + + function decimalCounter(number) { + var strNumber = Math.abs(number).toString() + var decimalIndex = strNumber.indexOf('.') + + // Set 'index' to a minimum of 1 if there are no fractions + var index = decimalIndex == -1 ? 1 : strNumber.length - decimalIndex - 1 + + return Math.min(index, control.decimals); + } } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SearchBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SearchBox.qml index d885271ecb..efdfa49af7 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SearchBox.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SearchBox.qml @@ -3,8 +3,7 @@ import QtQuick import QtQuick.Templates as T -import QtQuickDesignerTheme 1.0 -import StudioTheme 1.0 as StudioTheme +import StudioTheme as StudioTheme T.TextField { id: control diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TopLevelComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TopLevelComboBox.qml index 3aa5d70940..27f8333d24 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TopLevelComboBox.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TopLevelComboBox.qml @@ -4,7 +4,6 @@ import QtQuick import QtQuick.Templates as T import StudioTheme as StudioTheme -import QtQuickDesignerTheme import StudioWindowManager T.ComboBox { diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/impl/ColorEditorPopup.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/impl/ColorEditorPopup.qml index ba37645239..4f46b356f3 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/impl/ColorEditorPopup.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/impl/ColorEditorPopup.qml @@ -5,7 +5,6 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts import QtQuick.Templates as T -import QtQuickDesignerTheme import StudioControls as StudioControls import StudioTheme as StudioTheme import QtQuickDesignerColorPalette diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Values.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Values.qml index 6b179e4229..6b2e6b75cb 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Values.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Values.qml @@ -3,7 +3,7 @@ pragma Singleton import QtQuick -import QtQuickDesignerTheme 1.0 +import QtQuickDesignerTheme QtObject { id: values diff --git a/share/qtcreator/qmldesigner/textureEditorQmlSource/EmptyTextureEditorPane.qml b/share/qtcreator/qmldesigner/textureEditorQmlSource/EmptyTextureEditorPane.qml index 244f3beb83..adaf5dba56 100644 --- a/share/qtcreator/qmldesigner/textureEditorQmlSource/EmptyTextureEditorPane.qml +++ b/share/qtcreator/qmldesigner/textureEditorQmlSource/EmptyTextureEditorPane.qml @@ -2,9 +2,8 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 import QtQuick -import QtQuickDesignerTheme 1.0 -import HelperWidgets 2.0 -import StudioTheme 1.0 as StudioTheme +import HelperWidgets +import StudioTheme as StudioTheme PropertyEditorPane { id: root diff --git a/share/qtcreator/qmldesigner/textureEditorQmlSource/TextureEditorPane.qml b/share/qtcreator/qmldesigner/textureEditorQmlSource/TextureEditorPane.qml index ddf452d6f0..06fbfd5593 100644 --- a/share/qtcreator/qmldesigner/textureEditorQmlSource/TextureEditorPane.qml +++ b/share/qtcreator/qmldesigner/textureEditorQmlSource/TextureEditorPane.qml @@ -2,8 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 import QtQuick -import QtQuickDesignerTheme 1.0 -import HelperWidgets 2.0 +import HelperWidgets PropertyEditorPane { id: itemPane diff --git a/share/qtcreator/qmldesigner/textureEditorQmlSource/TextureEditorToolBar.qml b/share/qtcreator/qmldesigner/textureEditorQmlSource/TextureEditorToolBar.qml index 6a61a76ef6..f7d2e502ff 100644 --- a/share/qtcreator/qmldesigner/textureEditorQmlSource/TextureEditorToolBar.qml +++ b/share/qtcreator/qmldesigner/textureEditorQmlSource/TextureEditorToolBar.qml @@ -2,10 +2,9 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 import QtQuick -import QtQuickDesignerTheme 1.0 -import HelperWidgets 2.0 as HelperWidgets -import StudioTheme 1.0 as StudioTheme -import TextureToolBarAction 1.0 +import HelperWidgets as HelperWidgets +import StudioTheme as StudioTheme +import TextureToolBarAction Rectangle { id: root diff --git a/share/qtcreator/qmldesigner/toolbar/Main.qml b/share/qtcreator/qmldesigner/toolbar/Main.qml index 63b3aef565..af83887832 100644 --- a/share/qtcreator/qmldesigner/toolbar/Main.qml +++ b/share/qtcreator/qmldesigner/toolbar/Main.qml @@ -3,11 +3,9 @@ import QtQuick import QtQuick.Controls -import StudioControls 1.0 as StudioControls -import StudioTheme 1.0 as StudioTheme -import QtQuickDesignerTheme 1.0 - -import ToolBar 1.0 +import StudioControls as StudioControls +import StudioTheme as StudioTheme +import ToolBar Rectangle { id: root diff --git a/share/qtcreator/qmldesigner/welcomepage/BrandBar.qml b/share/qtcreator/qmldesigner/welcomepage/BrandBar.qml new file mode 100644 index 0000000000..721e2b06dd --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/BrandBar.qml @@ -0,0 +1,64 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick.Controls +import WelcomeScreen 1.0 + +Item { + id: brandBar + width: 850 + height: 150 + + Image { + id: brandIcon + width: 100 + height: 100 + anchors.verticalCenter: parent.verticalCenter + source: "images/ds.png" + fillMode: Image.PreserveAspectFit + } + + Text { + id: welcomeTo + color: Constants.currentGlobalText + text: qsTr("Welcome to") + anchors.verticalCenter: parent.verticalCenter + anchors.left: brandIcon.right + anchors.leftMargin: 5 + verticalAlignment: Text.AlignVCenter + font.pixelSize: 36 + font.family: "titillium web" + } + + Text { + id: brandLabel + color: Constants.currentBrand + text: qsTr("Qt Design Studio") + anchors.verticalCenter: parent.verticalCenter + anchors.left: welcomeTo.right + anchors.leftMargin: 8 + verticalAlignment: Text.AlignVCenter + font.pixelSize: 36 + font.family: "titillium web" + } + + Text { + width: 291 + height: 55 + color: Constants.currentGlobalText + text: { + if (Constants.communityEdition) + return qsTr("Community Edition") + if (Constants.enterpriseEdition) + return qsTr("Enterprise Edition") + return qsTr("Professional Edition") + } + anchors.verticalCenter: parent.verticalCenter + anchors.left: brandLabel.right + anchors.leftMargin: 8 + verticalAlignment: Text.AlignVCenter + font.pixelSize: 36 + font.family: "titillium web" + } +} diff --git a/share/qtcreator/qmldesigner/welcomepage/CheckButton.ui.qml b/share/qtcreator/qmldesigner/welcomepage/CheckButton.ui.qml new file mode 100644 index 0000000000..1e1f4557a1 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/CheckButton.ui.qml @@ -0,0 +1,108 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick.Templates +import WelcomeScreen 1.0 + +Button { + id: control + + implicitWidth: Math.max( + buttonBackground ? buttonBackground.implicitWidth : 0, + textItem.implicitWidth + leftPadding + rightPadding) + implicitHeight: Math.max( + buttonBackground ? buttonBackground.implicitHeight : 0, + textItem.implicitHeight + topPadding + bottomPadding) + leftPadding: 4 + rightPadding: 4 + + text: "My Button" + checkable: true + state: "normal" + + property bool decorated: false + + background: Rectangle { + id: buttonBackground + color: "#00000000" + implicitWidth: 100 + implicitHeight: 40 + opacity: buttonBackground.enabled ? 1 : 0.3 + radius: 2 + border.color: "#047eff" + anchors.fill: parent + } + + contentItem: Text { + id: textItem + text: control.text + font.pixelSize: 18 + opacity: textItem.enabled ? 1.0 : 0.3 + color: "#047eff" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + + Rectangle { + id: decoration + width: 10 + visible: control.decorated + color: Constants.currentBrand + border.color: Constants.currentBrand + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.rightMargin: 1 + anchors.bottomMargin: 1 + anchors.topMargin: 1 + } + + states: [ + State { + name: "normal" + when: !control.down && !control.hovered && !control.checked + + PropertyChanges { + target: buttonBackground + color: Constants.currentPushButtonNormalBackground + border.color: Constants.currentPushButtonNormalOutline + } + + PropertyChanges { + target: textItem + color: Constants.currentGlobalText + } + }, + State { + name: "hover" + when: control.hovered && !control.checked && !control.down + + PropertyChanges { + target: textItem + color: Constants.currentGlobalText + } + + PropertyChanges { + target: buttonBackground + color: Constants.currentPushButtonHoverBackground + border.color: Constants.currentPushButtonHoverOutline + } + }, + State { + name: "active" + when: control.checked || control.down + + PropertyChanges { + target: textItem + color: Constants.darkActiveGlobalText + } + + PropertyChanges { + target: buttonBackground + color: Constants.currentBrand + border.color: "#00000000" + } + } + ] +} diff --git a/share/qtcreator/qmldesigner/welcomepage/CustomDialog.qml b/share/qtcreator/qmldesigner/welcomepage/CustomDialog.qml new file mode 100644 index 0000000000..76b3c4c8e7 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/CustomDialog.qml @@ -0,0 +1,42 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick.Controls +import WelcomeScreen 1.0 + +Dialog { + id: root + padding: 12 + + background: Rectangle { + color: Constants.currentDialogBackground + border.color: Constants.currentDialogBorder + border.width: 1 + } + + header: Label { + text: root.title + visible: root.title + elide: Label.ElideRight + font.bold: true + padding: 12 + color: Constants.currentGlobalText + + background: Rectangle { + x: 1 + y: 1 + width: parent.width - 2 + height: parent.height - 1 + color: Constants.currentDialogBackground + } + } + + footer: CustomDialogButtonBox { + visible: count > 0 + } + + Overlay.modal: Rectangle { + color: Color.transparent(Constants.currentDialogBackground, 0.5) + } +} diff --git a/share/qtcreator/qmldesigner/welcomepage/CustomDialogButtonBox.qml b/share/qtcreator/qmldesigner/welcomepage/CustomDialogButtonBox.qml new file mode 100644 index 0000000000..8437e5dbe3 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/CustomDialogButtonBox.qml @@ -0,0 +1,25 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick.Controls +import WelcomeScreen 1.0 + +DialogButtonBox { + id: root + padding: 12 + alignment: Qt.AlignRight | Qt.AlignBottom + + background: Rectangle { + implicitHeight: 40 + x: 1 + y: 1 + width: parent.width - 2 + height: parent.height - 2 + color: Constants.currentDialogBackground + } + + delegate: DialogButton { + width: root.count === 1 ? root.availableWidth / 2 : undefined + } +} diff --git a/share/qtcreator/qmldesigner/welcomepage/CustomGrid.qml b/share/qtcreator/qmldesigner/welcomepage/CustomGrid.qml new file mode 100644 index 0000000000..bc7c4faf4a --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/CustomGrid.qml @@ -0,0 +1,41 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick.Layouts +import WelcomeScreen 1.0 +import DataModels 1.0 + +Item { + id: gridContainer + width: 1460 + height: 760 + + property alias hover: scrollView.outsideHover + property alias model: gridView.model + property alias delegate: gridView.delegate + + Connections { + target: gridContainer + onWidthChanged: Constants.responsiveResize(gridContainer.width) + } + + CustomScrollView { + id: scrollView + anchors.fill: parent + + GridView { + id: gridView + clip: true + anchors.fill: parent + rightMargin: -Constants.gridSpacing + bottomMargin: -Constants.gridSpacing + boundsBehavior: Flickable.StopAtBounds + cellWidth: Constants.gridCellSize + cellHeight: Constants.gridCellSize + + model: ExamplesModel {} + delegate: ThumbnailDelegate {} + } + } +} diff --git a/share/qtcreator/qmldesigner/welcomepage/CustomScrollBar.qml b/share/qtcreator/qmldesigner/welcomepage/CustomScrollBar.qml new file mode 100644 index 0000000000..1cc020774f --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/CustomScrollBar.qml @@ -0,0 +1,98 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick.Templates as T +import WelcomeScreen 1.0 +import StudioTheme 1.0 as StudioTheme + +T.ScrollBar { + id: control + + property bool show: false + property bool otherInUse: false + property bool isNeeded: control.size < 1.0 + property bool inUse: control.hovered || control.pressed + property int thickness: control.inUse || control.otherInUse ? 10 : 8 + + property bool scrollBarVisible: parent.childrenRect.height > parent.height + + implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, + implicitContentWidth + leftPadding + rightPadding) + implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, + implicitContentHeight + topPadding + bottomPadding) + + hoverEnabled: true + padding: 0 + minimumSize: orientation === Qt.Horizontal ? height / width : width / height + + opacity: 0.0 + + contentItem: Rectangle { + implicitWidth: control.thickness + implicitHeight: control.thickness + radius: width / 2 + color: control.inUse ? Constants.currentScrollBarHandle + : Constants.currentScrollBarHandle_idle + } + + background: Rectangle { + id: controlTrack + color: Constants.currentScrollBarTrack + opacity: control.inUse || control.otherInUse ? 0.3 : 0.0 + radius: width / 2 + + Behavior on opacity { + PropertyAnimation { + duration: 100 + easing.type: Easing.InOutQuad + } + } + } + + states: [ + State { + name: "show" + when: control.show + PropertyChanges { + target: control + opacity: 1.0 + } + }, + State { + name: "hide" + when: !control.show + PropertyChanges { + target: control + opacity: 0.0 + } + } + ] + + transitions: Transition { + from: "show" + SequentialAnimation { + PauseAnimation { duration: 450 } + NumberAnimation { + target: control + duration: 200 + property: "opacity" + to: 0.0 + } + } + } + + Behavior on thickness { + PropertyAnimation { + duration: 100 + easing.type: Easing.InOutQuad + } + } + + Behavior on x { + PropertyAnimation { + duration: 100 + easing.type: Easing.InOutQuad + } + } +} diff --git a/share/qtcreator/qmldesigner/welcomepage/CustomScrollView.qml b/share/qtcreator/qmldesigner/welcomepage/CustomScrollView.qml new file mode 100644 index 0000000000..5526cb3e1d --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/CustomScrollView.qml @@ -0,0 +1,25 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick.Templates as T + +T.ScrollView { + id: control + + property bool outsideHover: false + + hoverEnabled: true + + T.ScrollBar.vertical: CustomScrollBar { + id: verticalScrollBar + parent: control + x: control.width + (verticalScrollBar.inUse ? 4 : 5) + y: control.topPadding + height: control.availableHeight + orientation: Qt.Vertical + + show: (control.hovered || control.focus || control.outsideHover) + && verticalScrollBar.isNeeded + } +} diff --git a/share/qtcreator/qmldesigner/welcomepage/DialogButton.qml b/share/qtcreator/qmldesigner/welcomepage/DialogButton.qml new file mode 100644 index 0000000000..e7fb13e042 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/DialogButton.qml @@ -0,0 +1,89 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick.Templates +import WelcomeScreen 1.0 + +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: 20 + opacity: enabled ? 1 : 0.3 + radius: 2 + color: Constants.currentPushButtonNormalBackground + border.color: Constants.currentPushButtonNormalOutline + anchors.fill: parent + } + + contentItem: Text { + id: textItem + text: root.text + font.pixelSize: 12 + opacity: enabled ? 1.0 : 0.3 + color: Constants.currentGlobalText + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + + states: [ + State { + name: "default" + when: !root.down && !root.hovered && !root.checked + + PropertyChanges { + target: background + color: Constants.currentPushButtonNormalBackground + border.color: Constants.currentPushButtonNormalOutline + } + + PropertyChanges { + target: textItem + color: Constants.currentGlobalText + } + }, + State { + name: "hover" + when: root.hovered && !root.checked && !root.down + + PropertyChanges { + target: textItem + color: Constants.currentGlobalText + } + + PropertyChanges { + target: background + color: Constants.currentPushButtonHoverBackground + border.color: Constants.currentPushButtonHoverOutline + } + }, + State { + name: "active" + when: root.checked || root.down + + PropertyChanges { + target: textItem + color: Constants.currentActiveGlobalText + } + + PropertyChanges { + target: background + color: Constants.currentBrand + border.color: "#00000000" + } + } + ] +} diff --git a/share/qtcreator/qmldesigner/welcomepage/DownloadButton.qml b/share/qtcreator/qmldesigner/welcomepage/DownloadButton.qml new file mode 100644 index 0000000000..07f107eb33 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/DownloadButton.qml @@ -0,0 +1,134 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick.Controls +import WelcomeScreen 1.0 +import StudioTheme 1.0 as StudioTheme + +Item { + id: root + width: 30 + height: 30 + state: "default" + + property bool dowloadPressed: false + property bool isHovered: mouseArea.containsMouse + + property bool globalHover: false + + property bool alreadyDownloaded: false + property bool updateAvailable: false + property bool downloadUnavailable: false + + signal downloadClicked() + + property color currentColor: { + if (root.updateAvailable) + return Constants.amberLight + if (root.alreadyDownloaded) + return Constants.greenLight + if (root.downloadUnavailable) + return Constants.redLight + + return Constants.currentGlobalText + } + + property string currentIcon: { + if (root.updateAvailable) + return StudioTheme.Constants.downloadUpdate + if (root.alreadyDownloaded) + return StudioTheme.Constants.downloaded + if (root.downloadUnavailable) + return StudioTheme.Constants.downloadUnavailable + + return StudioTheme.Constants.download + } + + property string currentToolTipText: { + if (root.updateAvailable) + return qsTr("Update available.") + if (root.alreadyDownloaded) + return qsTr("Example was already downloaded.") + if (root.downloadUnavailable) + return qsTr("Network or example is not available or the link is broken.") + + return qsTr("Download the example.") + } + + Text { + id: downloadIcon + color: root.currentColor + font.family: StudioTheme.Constants.iconFont.family + text: root.currentIcon + anchors.fill: parent + font.pixelSize: 22 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + anchors.bottomMargin: 0 + } + + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + propagateComposedEvents: true + + Connections { + target: mouseArea + onClicked: root.downloadClicked() + } + } + + ToolTip { + id: toolTip + y: -toolTip.height + visible: mouseArea.containsMouse + text: root.currentToolTipText + delay: 1000 + height: 20 + background: Rectangle { + color: Constants.currentToolTipBackground + border.color: Constants.currentToolTipOutline + border.width: 1 + } + contentItem: Text { + color: Constants.currentToolTipText + text: toolTip.text + verticalAlignment: Text.AlignVCenter + } + } + + states: [ + State { + name: "default" + when: !mouseArea.pressed && !mouseArea.containsMouse && !root.globalHover + PropertyChanges { + target: downloadIcon + color: root.currentColor + } + }, + State { + name: "pressed" + when: mouseArea.pressed && mouseArea.containsMouse + PropertyChanges { + target: downloadIcon + color: Constants.currentBrand + scale: 1.2 + } + }, + State { + name: "hover" + when: mouseArea.containsMouse && !mouseArea.pressed && !root.globalHover + PropertyChanges { + target: downloadIcon + scale: 1.2 + } + }, + State { + name: "globalHover" + extend: "hover" + when: root.globalHover && !mouseArea.pressed && !mouseArea.containsMouse + } + ] +} diff --git a/share/qtcreator/qmldesigner/welcomepage/DownloadPanel.qml b/share/qtcreator/qmldesigner/welcomepage/DownloadPanel.qml new file mode 100644 index 0000000000..8cd7099787 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/DownloadPanel.qml @@ -0,0 +1,79 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick.Controls +import WelcomeScreen 1.0 + +Rectangle { + id: root + color: Constants.currentNormalThumbnailBackground + + property alias value: progressBar.value + property alias text: progressLabel.text + property alias allowCancel: progressBar.closeButtonVisible + + readonly property int pixelSize: 12 + readonly property int textMargin: 5 + + signal cancelRequested + + DownloadProgressBar { + id: progressBar + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: pushButton.top + anchors.bottomMargin: 40 + anchors.rightMargin: 10 + anchors.leftMargin: 10 + + onCancelRequested: root.cancelRequested() + + Text { + id: progressLabel + color: Constants.currentGlobalText + text: qsTr("Progress:") + anchors.top: parent.bottom + anchors.topMargin: root.textMargin + anchors.left: parent.left + font.pixelSize: root.pixelSize + } + + Text { + id: progressAmount + color: Constants.currentGlobalText + text: stringMapper.text + anchors.top: parent.bottom + anchors.topMargin: root.textMargin + anchors.right: percentSign.left + anchors.rightMargin: root.textMargin + font.pixelSize: root.pixelSize + } + + Text { + id: percentSign + color: Constants.currentGlobalText + text: qsTr("%") + anchors.right: parent.right + anchors.top: parent.bottom + anchors.topMargin: root.textMargin + font.pixelSize: root.pixelSize + } + } + + PushButton { + id: pushButton + y: 177 + visible: progressBar.downloadFinished + text: qsTr("Open") + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottomMargin: 40 + } + + StringMapper { + id: stringMapper + decimals: 1 + input: root.value + } +} diff --git a/share/qtcreator/qmldesigner/welcomepage/DownloadProgressBar.qml b/share/qtcreator/qmldesigner/welcomepage/DownloadProgressBar.qml new file mode 100644 index 0000000000..5fb0f637ca --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/DownloadProgressBar.qml @@ -0,0 +1,80 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick.Controls +import WelcomeScreen 1.0 +import StudioTheme as StudioTheme + +Item { + id: progressBar + width: 272 + height: 25 + property bool downloadFinished: false + property int value: 0 + property bool closeButtonVisible + //property alias numberAnimationRunning: numberAnimation.running + + readonly property int margin: 4 + + signal cancelRequested + + Rectangle { + id: progressBarGroove + color: Constants.currentNormalThumbnailLabelBackground + anchors.fill: parent + } + + Rectangle { + id: progressBarTrack + width: progressBar.value * ((progressBar.width - closeButton.width) - 2 * progressBar.margin) / 100 + color: Constants.currentBrand + border.color: "#002e769e" + anchors.left: parent.left + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.margins: progressBar.margin + } + + Text { + id: closeButton + visible: progressBar.closeButtonVisible + width: 20 + text: StudioTheme.Constants.closeCross + color: Constants.currentBrand + horizontalAlignment: Qt.AlignHCenter + verticalAlignment: Qt.AlignVCenter + font.family: StudioTheme.Constants.iconFont.family + font.pixelSize: StudioTheme.Values.myIconFontSize + + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.margins: progressBar.margin + + MouseArea { + anchors.fill: parent + onClicked: { + progressBar.cancelRequested() + } + } + } + +/* + NumberAnimation { + id: numberAnimation + target: progressBarTrack + property: "width" + duration: 2500 + easing.bezierCurve: [0.197,0.543,0.348,0.279,0.417,0.562,0.437,0.757,0.548,0.731,0.616,0.748,0.728,0.789,0.735,0.982,1,1] + alwaysRunToEnd: true + to: progressBar.width + from: 0 + } + + Connections { + target: numberAnimation + onFinished: progressBar.downloadFinished = true + } +*/ +} diff --git a/share/qtcreator/qmldesigner/welcomepage/MainGridStack.qml b/share/qtcreator/qmldesigner/welcomepage/MainGridStack.qml new file mode 100644 index 0000000000..73b023bddc --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/MainGridStack.qml @@ -0,0 +1,166 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import WelcomeScreen 1.0 +import projectmodel 1.0 +import DataModels 1.0 +import UiTour +import StudioControls as StudioControls + +Item { + id: thumbnails + width: 1500 + height: 800 + clip: true + + property alias stackLayoutCurrentIndex: gridStackLayout.currentIndex + property var projectModel: Constants.projectModel + + Rectangle { + id: thumbnailGridBack + color: Constants.currentThumbnailGridBackground + anchors.fill: parent + + HoverHandler { id: hoverHandler } + + StackLayout { + id: gridStackLayout + visible: !Constants.isListView + anchors.fill: parent + anchors.margins: Constants.gridMargins + currentIndex: 0 + + CustomGrid { + id: recentGrid + Layout.fillWidth: true + Layout.fillHeight: true + hover: hoverHandler.hovered + model: thumbnails.projectModel + delegate: ThumbnailDelegate { + id: delegate + type: ThumbnailDelegate.Type.RecentProject + hasPath: true + thumbnailPlaceholderSource: previewUrl + onClicked: projectModel.openProjectAt(index) + onRightClicked: { + removeMenuItem.index = index + contextMenu.popup(delegate) + } + } + + Text { + text: qsTr("Create a new project using the \"<b>Create Project</b>\" or open an existing project using the \"<b>Open Project</b>\" option. ") + font.pixelSize: 18 + color: Constants.currentGlobalText + anchors.centerIn: parent + width: recentGrid.width + horizontalAlignment: Text.AlignHCenter + leftPadding: 20 + rightPadding: 20 + wrapMode: Text.WordWrap + visible: projectModel.count === 0 + } + + StudioControls.Menu { + id: contextMenu + + StudioControls.MenuItem { + id: removeMenuItem + + property int index: -1 + + text: qsTr("Remove Project from Recent Projects") + onTriggered: projectModel.removeFromRecentProjects(removeMenuItem.index) + } + + StudioControls.MenuItem { + text: qsTr("Clear Recent Project List") + onTriggered: projectModel.clearRecentProjects() + } + } + } + + CustomGrid { + id: examplesGrid + Layout.fillWidth: true + Layout.fillHeight: true + hover: hoverHandler.hovered + model: ExamplesModel { id: examplesModel} + delegate: ThumbnailDelegate { + type: ThumbnailDelegate.Type.Example + downloadable: showDownload + hasUpdate: showUpdate + downloadUrl: url + thumbnailPlaceholderSource: examplesModel.resolveUrl(thumbnail) + onClicked: projectModel.openExample(targetPath, + projectName, + qmlFileName, + explicitQmlproject) + } + } + + CustomGrid { + id: tutorialsGrid + Layout.fillWidth: true + Layout.fillHeight: true + hover: hoverHandler.hovered + model: TutorialsModel { id: tutorialsModel} + delegate: ThumbnailDelegate { + type: ThumbnailDelegate.Type.Tutorial + thumbnailPlaceholderSource: tutorialsModel.resolveUrl(thumbnail) + onClicked: Qt.openUrlExternally(url) + } + } + + CustomGrid { + id: tourGrid + Layout.fillWidth: true + Layout.fillHeight: true + hover: hoverHandler.hovered + model: TourModel {} + delegate: TourThumbnailDelegate { + id: thumbnailDelegate + visible: !slidePlayer.visible + enabled: !slidePlayer.visible + + Connections { + target: thumbnailDelegate + onClicked: tourGrid.startTour(qmlFileName) + } + } + + function startTour(url) { + slidePlayer.visible = true + slidePlayer.slideSource = Qt.resolvedUrl(url) + } + + SlidePlayer { + id: slidePlayer + anchors.fill: parent + visible: false + } + + TourDialogButton { + id: closeButton + anchors.right: parent.right + anchors.top: parent.top + anchors.rightMargin: 16 + anchors.topMargin: 16 + visible: slidePlayer.visible + + Connections { + target: closeButton + onButtonClicked: { + slidePlayer.visible = false + slidePlayer.loaderActive = false + slidePlayer.loaderActive = true + } + } + } + } + } + } +} diff --git a/share/qtcreator/qmldesigner/welcomepage/MainScreen.qml b/share/qtcreator/qmldesigner/welcomepage/MainScreen.qml new file mode 100644 index 0000000000..b2e09d4308 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/MainScreen.qml @@ -0,0 +1,318 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import WelcomeScreen 1.0 +import projectmodel 1.0 +import DataModels 1.0 + +Rectangle { + id: appBackground + height: Constants.height + color: Constants.currentThemeBackground + width: 1842 + //anchors.fill: parent //this is required to make it responsive but commented out to force minimum size to work + property int pageIndex: 0 + property bool designMode: !(typeof (Constants.projectModel.designMode) === "undefined") + + signal openUiTour + signal closeUiTour + + function uiTourClosed() { + recentProjects.checked = true + } + + TestControlPanel { + id: controlPanel + x: 1644 + width: 220 + height: 127 + visible: appBackground.designMode + anchors.right: parent.right + anchors.top: parent.top + anchors.topMargin: 15 + anchors.rightMargin: 56 + } + + ColumnLayout { + id: openCreatelayout + y: 150 + anchors.left: parent.left + anchors.right: thumbnails.left + anchors.rightMargin: 20 + spacing: 15 + anchors.leftMargin: 20 + + PushButton { + id: createProject + height: 50 + text: qsTr("Create Project ...") + + Layout.maximumHeight: 75 + Layout.minimumHeight: 25 + Layout.fillWidth: true + Layout.preferredHeight: 50 + decorated: true + onClicked: Constants.projectModel.createProject() + } + + PushButton { + id: openProject + height: 50 + text: qsTr("Open Project ...") + + Layout.maximumHeight: 75 + Layout.minimumHeight: 25 + Layout.fillWidth: true + Layout.preferredHeight: 50 + decorated: true + onClicked: Constants.projectModel.openProject() + } + + Text { + id: newQtLabel + width: 266 + height: 40 + color: Constants.currentGlobalText + text: qsTr("New to Qt?") + font.pixelSize: 24 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + Layout.fillWidth: true + } + + PushButton { + id: getStarted + height: 50 + text: qsTr("Get Started") + Layout.maximumHeight: 75 + Layout.minimumHeight: 25 + Layout.preferredHeight: 50 + Layout.fillWidth: true + onClicked: Constants.projectModel.showHelp() + } + } + + ColumnLayout { + id: currentPageMenuLayout + y: 422 + anchors.left: parent.left + anchors.right: thumbnails.left + anchors.rightMargin: 20 + anchors.leftMargin: 20 + spacing: 15 + + CheckButton { + id: recentProjects + text: qsTr("Recent Projects") + autoExclusive: true + checked: true + Layout.fillWidth: true + + Connections { + target: recentProjects + function onClicked(mouse) { appBackground.pageIndex = 0 } + } + } + + CheckButton { + id: examples + text: qsTr("Examples") + autoExclusive: true + Layout.fillWidth: true + + Connections { + target: examples + function onClicked(mouse) { appBackground.pageIndex = 1 } + } + } + + CheckButton { + id: tutorials + text: qsTr("Tutorials") + autoExclusive: true + Layout.fillWidth: true + + Connections { + target: tutorials + function onClicked(mouse) { appBackground.pageIndex = 2 } + } + } + + CheckButton { + id: tours + text: qsTr("UI Tour") + autoExclusive: true + Layout.fillWidth: true + + Connections { + target: tours + function onClicked(mouse) { appBackground.pageIndex = 3 } + } + } + } + + BrandBar { + id: brandBar + y: 0 + anchors.left: parent.left + anchors.leftMargin: 20 + + Rectangle { + id: loadProgress + x: 4 + y: 120 + width: Constants.loadingProgress * 10 + height: 4 + color: Constants.currentGlobalText + opacity: Constants.loadingProgress > 90 ? (100 - Constants.loadingProgress) / 10 : 1 + } + } + + MainGridStack { + id: thumbnails + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.topMargin: 150 + anchors.rightMargin: 56 + anchors.bottomMargin: 54 + anchors.leftMargin: 290 + stackLayoutCurrentIndex: appBackground.pageIndex + } + + RowLayout { + id: linkRow + y: 1041 + height: 25 + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.leftMargin: 290 + anchors.rightMargin: 55 + anchors.bottomMargin: 14 + spacing: 0 + + PushButton { + id: userGuide + text: qsTr("User Guide") + fontpixelSize: 12 + Layout.minimumWidth: 100 + Layout.fillWidth: true + Layout.preferredHeight: 25 + Layout.preferredWidth: 200 + decorated: true + onClicked: Qt.openUrlExternally("https://doc.qt.io/qtdesignstudio/") + } + + Item { + width: 200 + height: 200 + Layout.fillWidth: true + Layout.preferredWidth: 50 + Layout.preferredHeight: 25 + } + + PushButton { + id: blog + text: qsTr("Blog") + fontpixelSize: 12 + Layout.minimumWidth: 100 + Layout.fillWidth: true + Layout.preferredHeight: 25 + Layout.preferredWidth: 200 + decorated: true + onClicked: Qt.openUrlExternally("https://blog.qt.io/") + } + + Item { + width: 200 + height: 200 + Layout.fillWidth: true + Layout.preferredWidth: 50 + Layout.preferredHeight: 25 + } + + PushButton { + id: forums + text: qsTr("Forums") + fontpixelSize: 12 + Layout.minimumWidth: 100 + Layout.fillWidth: true + Layout.preferredHeight: 25 + Layout.preferredWidth: 200 + decorated: true + onClicked: Qt.openUrlExternally("https://forum.qt.io/") + } + + Item { + width: 200 + height: 200 + Layout.fillWidth: true + Layout.preferredWidth: 50 + Layout.preferredHeight: 25 + } + + PushButton { + id: account + text: qsTr("Account") + fontpixelSize: 12 + Layout.minimumWidth: 100 + Layout.fillWidth: true + Layout.preferredHeight: 25 + Layout.preferredWidth: 200 + decorated: true + onClicked: Qt.openUrlExternally("https://login.qt.io/login") + } + + Item { + width: 200 + height: 200 + Layout.fillWidth: true + Layout.preferredWidth: 50 + Layout.preferredHeight: 25 + } + + PushButton { + id: getQt + text: qsTr("Get Qt") + fontpixelSize: 12 + Layout.minimumWidth: 100 + Layout.fillWidth: true + Layout.preferredHeight: 25 + Layout.preferredWidth: 200 + decorated: true + onClicked: Qt.openUrlExternally("https://www.qt.io/pricing") + } + + Item { + width: 200 + height: 200 + Layout.fillWidth: true + Layout.preferredWidth: 50 + Layout.preferredHeight: 25 + } + + SocialButton { + id: social + text: "" + Layout.minimumWidth: 100 + Layout.fillWidth: true + Layout.preferredHeight: 25 + Layout.preferredWidth: 200 + decorated: true + } + } + + BlogBanner { + id: blogBanner + anchors.left: parent.left + anchors.leftMargin: 20 + anchors.right: thumbnails.left + anchors.rightMargin: 20 + y: 657 + } +} diff --git a/share/qtcreator/qmldesigner/welcomepage/PushButton.ui.qml b/share/qtcreator/qmldesigner/welcomepage/PushButton.ui.qml new file mode 100644 index 0000000000..a87c0241c6 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/PushButton.ui.qml @@ -0,0 +1,108 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick.Templates +import WelcomeScreen 1.0 + +Button { + id: control + + implicitWidth: Math.max( + buttonBackground ? buttonBackground.implicitWidth : 0, + textItem.implicitWidth + leftPadding + rightPadding) + implicitHeight: Math.max( + buttonBackground ? buttonBackground.implicitHeight : 0, + textItem.implicitHeight + topPadding + bottomPadding) + leftPadding: 4 + rightPadding: 4 + + text: "My Button" + state: "normal" + + property alias fontpixelSize: textItem.font.pixelSize + property bool decorated: false + + background: Rectangle { + id: buttonBackground + color: "#00000000" + implicitWidth: 100 + implicitHeight: 40 + opacity: buttonBackground.enabled ? 1 : 0.3 + radius: 2 + border.color: "#047eff" + anchors.fill: parent + } + + contentItem: Text { + id: textItem + text: control.text + font.pixelSize: 18 + opacity: textItem.enabled ? 1.0 : 0.3 + color: Constants.currentGlobalText + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + + Rectangle { + id: decoration + width: 10 + visible: control.decorated + color: Constants.currentBrand + border.color: Constants.currentBrand + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.rightMargin: 1 + anchors.bottomMargin: 1 + anchors.topMargin: 1 + } + + states: [ + State { + name: "normal" + when: !control.down && !control.hovered + + PropertyChanges { + target: buttonBackground + color: Constants.currentPushButtonNormalBackground + border.color: Constants.currentPushButtonNormalOutline + } + + PropertyChanges { + target: textItem + color: Constants.currentGlobalText + } + }, + State { + name: "hover" + when: control.hovered && !control.down + + PropertyChanges { + target: textItem + color: Constants.currentGlobalText + } + + PropertyChanges { + target: buttonBackground + color: Constants.currentPushButtonHoverBackground + border.color: Constants.currentPushButtonHoverOutline + } + }, + State { + name: "press" + when: control.down + + PropertyChanges { + target: textItem + color: Constants.darkActiveGlobalText + } + + PropertyChanges { + target: buttonBackground + color: Constants.currentBrand + border.color: "#00000000" + } + } + ] +} diff --git a/share/qtcreator/qmldesigner/welcomepage/RangeMapper.qml b/share/qtcreator/qmldesigner/welcomepage/RangeMapper.qml new file mode 100644 index 0000000000..76c67f719f --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/RangeMapper.qml @@ -0,0 +1,42 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick + +QtObject { + id: object + +/*! + The input value. +*/ + property real input: 0 + +/*! + The output value. +*/ + property real output: { + var slope = (object.outputMaximum - object.outputMinimum) / (object.inputMaximum - object.inputMinimum) + return object.outputMinimum + slope * (object.input - object.inputMinimum) + } + +/*! + The minimum input value. +*/ + property real inputMinimum: 0 + +/*! + The maximum input value. +*/ + property real inputMaximum: 100 + +/*! + The minimum output value. +*/ + property real outputMinimum: 0 + +/*! + The maximum output value. +*/ + property real outputMaximum: 100 + +} diff --git a/share/qtcreator/qmldesigner/welcomepage/SocialButton.qml b/share/qtcreator/qmldesigner/welcomepage/SocialButton.qml new file mode 100644 index 0000000000..864486966d --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/SocialButton.qml @@ -0,0 +1,129 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick.Templates +import QtQuick.Layouts +import WelcomeScreen 1.0 + +Button { + id: control + + implicitWidth: Math.max( + buttonBackground ? buttonBackground.implicitWidth : 0, + textItem.implicitWidth + leftPadding + rightPadding) + implicitHeight: Math.max( + buttonBackground ? buttonBackground.implicitHeight : 0, + textItem.implicitHeight + topPadding + bottomPadding) + leftPadding: 4 + rightPadding: 4 + + text: "" + visible: true + state: "normal" + + property alias fontpixelSize: textItem.font.pixelSize + property bool decorated: false + + background: Rectangle { + id: buttonBackground + color: "#fca4a4" + implicitWidth: 100 + implicitHeight: 40 + opacity: buttonBackground.enabled ? 1 : 0.3 + radius: 2 + border.color: "#047eff" + anchors.fill: parent + } + + contentItem: Text { + id: textItem + visible: false + text: qsTr("Text") + font.pixelSize: 12 + } + + Rectangle { + id: decoration + width: 10 + visible: control.decorated + color: Constants.currentBrand + border.color: Constants.currentBrand + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.rightMargin: 1 + anchors.bottomMargin: 1 + anchors.topMargin: 1 + } + + RowLayout { + anchors.fill: parent + + Item { + width: 200 + height: 200 + Layout.fillWidth: true + Layout.fillHeight: true + } + + YoutubeButton { + id: youtubeButton + Layout.fillHeight: true + Layout.preferredWidth: 60 + } + + Item { + width: 200 + height: 200 + Layout.fillHeight: true + Layout.fillWidth: true + } + + TwitterButton { + id: twitterButton + Layout.maximumHeight: 15 + Layout.minimumHeight: 15 + Layout.preferredHeight: 15 + Layout.fillHeight: false + Layout.preferredWidth: 25 + } + + Item { + width: 200 + height: 200 + Layout.fillHeight: true + Layout.fillWidth: true + } + } + + states: [ + State { + name: "normal" + when: !youtubeButton.isHovered && !twitterButton.isHovered && !control.hovered + + PropertyChanges { + target: buttonBackground + color: Constants.currentPushButtonNormalBackground + border.color: Constants.currentPushButtonNormalOutline + } + }, + State { + name: "hover" + when: control.hovered || youtubeButton.isHovered || twitterButton.isHovered + + PropertyChanges { + target: buttonBackground + color: Constants.currentPushButtonHoverBackground + border.color: Constants.currentPushButtonHoverOutline + } + } + ] +} + +/*##^## +Designer { + D{i:0;formeditorZoom:4;height:25;width:207}D{i:3;locked:true}D{i:7}D{i:9} +} +##^##*/ + diff --git a/share/qtcreator/qmldesigner/welcomepage/StringMapper.qml b/share/qtcreator/qmldesigner/welcomepage/StringMapper.qml new file mode 100644 index 0000000000..71d17117fb --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/StringMapper.qml @@ -0,0 +1,68 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick 2.10 + +/*! + \qmltype StringMapper + \inqmlmodule QtQuick.Studio.LogicHelper + \since QtQuick.Studio.LogicHelper 1.0 + \inherits QtObject + + \brief Converts numbers to strings with the defined precision. + + The StringMapper type maps numbers to strings. The string mapper + \l input property is bound to the \c value property of a control that + provides the number and the \l text property of the string mapper is + mapped to the \c text property of type that displays the string. + + Designers can use the String Mapper type in \QDS instead of writing + JavaScript expressions. + + \section1 Example Usage + + In the following example, we use \l Text type to display the numerical + value of a \l Slider type as a string: + + \code + Rectangle { + Slider { + id: slider + value: 0.5 + } + Text { + id: text1 + text: stringMapper.text + } + StringMapper { + id: stringMapper + input: slider.value + } + } + \endcode +*/ + +QtObject { + id: object + +/*! + The value to convert to a string. +*/ + property real input: 0 + +/*! + The number of digits after the decimal separator. +*/ + property int decimals: 2 + +/*! + The \l input value as a string. +*/ + property string text: object.input.toFixed(object.decimals) +} + +/*##^## +Designer { + D{i:0;autoSize:true;height:480;width:640} +} +##^##*/ diff --git a/share/qtcreator/qmldesigner/welcomepage/Tag.qml b/share/qtcreator/qmldesigner/welcomepage/Tag.qml new file mode 100644 index 0000000000..109cf43516 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/Tag.qml @@ -0,0 +1,28 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick.Controls +import WelcomeScreen 1.0 +import QtQuick.Layouts 1.0 + +Rectangle { + id: tagBackground + width: 84 + height: 15 + color: Constants.currentBrand + visible: tagLabel.text.length + + property alias text: tagLabel.text + + Text { + id: tagLabel + color: Constants.darkActiveGlobalText + text: qsTr("tag name") + anchors.fill: parent + font.pixelSize: 10 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + //font.weight: Font.ExtraLight + } +} diff --git a/share/qtcreator/qmldesigner/welcomepage/TagArea.qml b/share/qtcreator/qmldesigner/welcomepage/TagArea.qml new file mode 100644 index 0000000000..04722d7ba8 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/TagArea.qml @@ -0,0 +1,43 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick.Controls +import WelcomeScreen 1.0 +import QtQuick.Layouts + +Item { + id: root + height: (repeater.count > root.columnCount) ? root.tagHeight * 2 + root.tagSpacing + : root.tagHeight + + property alias tags: repeater.model + // private + property int tagWidth: 75 + property int tagHeight: 25 + property int tagSpacing: 4 + + readonly property int columnCount: 3 + + Connections { + target: root + onWidthChanged: root.tagWidth = Math.floor((root.width - root.tagSpacing + * (root.columnCount - 1)) / root.columnCount) + } + + Flow { + anchors.fill: parent + spacing: root.tagSpacing + + Repeater { + id: repeater + model: ["Qt 6", "Qt for MCU", "3D"] + + Tag { + text: modelData + width: root.tagWidth + height: root.tagHeight + } + } + } +} diff --git a/share/qtcreator/qmldesigner/welcomepage/TestControlPanel.qml b/share/qtcreator/qmldesigner/welcomepage/TestControlPanel.qml new file mode 100644 index 0000000000..50ed31cab7 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/TestControlPanel.qml @@ -0,0 +1,153 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import WelcomeScreen 1.0 +import StudioTheme 1.0 as Theme + +Rectangle { + id: controlPanel + width: 220 + height: 80 + color: "#9b787878" + radius: 10 + + property bool closeOpen: true + + Text { + id: closeOpen + x: 203 + color: "#ffffff" + text: qsTr("X") + anchors.right: parent.right + anchors.top: parent.top + font.pixelSize: 12 + horizontalAlignment: Text.AlignRight + anchors.rightMargin: 9 + anchors.topMargin: 6 + + MouseArea { + id: mouseArea + anchors.fill: parent + + Connections { + target: mouseArea + function onClicked(mouse) { controlPanel.closeOpen = !controlPanel.closeOpen } + } + } + } + + Text { + id: themeSwitchLabel + x: 8 + y: 50 + color: "#ffffff" + text: qsTr("Theme") + font.pixelSize: 12 + horizontalAlignment: Text.AlignRight + anchors.rightMargin: 6 + } + + Text { + id: lightLabel + x: 172 + y: 26 + color: "#ffffff" + text: qsTr("light") + font.pixelSize: 12 + horizontalAlignment: Text.AlignRight + } + + Text { + id: darkLabel + x: 65 + y: 26 + color: "#ffffff" + text: qsTr("dark") + font.pixelSize: 12 + horizontalAlignment: Text.AlignRight + } + + Slider { + id: themeSlider + x: 58 + y: 44 + width: 145 + height: 28 + snapMode: RangeSlider.SnapAlways + value: 0 + from: 0 + to: 1 + stepSize: 1 + + Connections { + target: themeSlider + function onValueChanged(value) { Theme.Values.style = themeSlider.value } + } + } + + CheckBox { + id: basicCheckBox + x: 60 + y: 79 + text: qsTr("") + checked: true + onToggled: { Constants.basic = !Constants.basic } + } + + CheckBox { + id: communityCheckBox + x: 174 + y: 79 + text: qsTr("") + checked: false + onToggled: { Constants.communityEdition = !Constants.communityEdition } + } + + Text { + id: basicEditionLabel + x: 8 + y: 92 + color: "#ffffff" + text: qsTr("Basic") + font.pixelSize: 12 + horizontalAlignment: Text.AlignRight + anchors.rightMargin: 6 + } + + Text { + id: communityEditionLabel + x: 116 + y: 92 + color: "#ffffff" + text: qsTr("Community") + font.pixelSize: 12 + horizontalAlignment: Text.AlignRight + anchors.rightMargin: 6 + } + + states: [ + State { + name: "open" + when: controlPanel.closeOpen + }, + State { + name: "close" + when: !controlPanel.closeOpen + + PropertyChanges { + target: closeOpen + text: qsTr("<") + } + + PropertyChanges { + target: controlPanel + width: 28 + height: 26 + clip: true + } + } + ] +} diff --git a/share/qtcreator/qmldesigner/welcomepage/ThumbnailDelegate.qml b/share/qtcreator/qmldesigner/welcomepage/ThumbnailDelegate.qml new file mode 100644 index 0000000000..d50627d05e --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/ThumbnailDelegate.qml @@ -0,0 +1,630 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import WelcomeScreen 1.0 +import ExampleCheckout 1.0 + +Item { + id: root + width: Constants.thumbnailSize + height: Constants.thumbnailSize + clip: true + state: "normal" + + property bool textWrapped: false + property bool hasDescription: false + property bool hasPath: false + property bool hasUpdate: false + property bool downloadable: false + property int numberOfPanels: 3 + + enum Type { + RecentProject, + Example, + Tutorial + } + + property int type: ThumbnailDelegate.Type.RecentProject + + property alias projectNameLabelText: projectNameLabel.text + property alias projectPathLabelText: projectPathLabel.text + property alias thumbnailPlaceholderSource: thumbnailPlaceholder.source + + property alias downloadUrl: downloader.url + property alias tempFile: downloader.outputFile + property alias completeBaseName: downloader.completeBaseName + property alias targetPath: extractor.targetPath + + property alias bannerLabelText: updateText.text + + enum Panel { + InBetween, + Download, + Main, + Details + } + + property int currentPanel: ThumbnailDelegate.Panel.Main + + signal clicked() + signal rightClicked() + + function startDownload() { + twirlToDownloadAnimation.start() + downloadPanel.text = downloadPanel.downloadText + downloadPanel.allowCancel = true + downloadPanel.value = Qt.binding(function() { return downloader.progress }) + downloader.start() + mouseArea.enabled = false + } + + function thumbnailClicked() { + if (root.type === ThumbnailDelegate.Type.RecentProject + || root.type === ThumbnailDelegate.Type.Tutorial) + root.clicked() // open recent project/tutorial + + if (Constants.loadingProgress < 95) + return + if (root.type === ThumbnailDelegate.Type.Example) { + if (root.downloadable + && !downloadButton.alreadyDownloaded + && !downloadButton.downloadUnavailable) { + root.startDownload() + } else if (downloadButton.alreadyDownloaded) { + root.clicked() // open example + } + } + } + + MouseArea { + id: mouseArea + anchors.fill: parent + propagateComposedEvents: true + hoverEnabled: true + acceptedButtons: Qt.LeftButton | Qt.RightButton + + Connections { + target: mouseArea + function onClicked(mouse) { + if (mouse.button === Qt.RightButton) + root.rightClicked() + else + root.thumbnailClicked(mouse) + } + } + } + + CustomDialog { + id: overwriteDialog + title: qsTr("Overwrite Example?") + standardButtons: Dialog.Yes | Dialog.No + modal: true + anchors.centerIn: parent + + onAccepted: root.startDownload() + + Text { + width: parent.width + horizontalAlignment: Text.AlignHCenter + font.pixelSize: 12 + color: Constants.currentGlobalText + text: qsTr("Example already exists.<br>Do you want to replace it?") + } + } + + Item { + id: canvas + width: Constants.thumbnailSize + height: Constants.thumbnailSize * root.numberOfPanels + + DownloadPanel { + id: downloadPanel + + height: Constants.thumbnailSize + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: mainPanel.top + radius: 10 + value: downloader.progress + + readonly property string downloadText: qsTr("Downloading...") + readonly property string extractText: qsTr("Extracting...") + + onCancelRequested: downloader.cancel() + } + + Rectangle { + id: mainPanel + height: Constants.thumbnailSize + anchors.left: parent.left + anchors.right: parent.right + color: "#ea8c8c" + radius: 10 + + property bool multiline: (projectNameLabelMetric.width >= projectNameLabel.width) + + TextMetrics { + id: projectNameLabelMetric + text: projectNameLabel.text + font: projectNameLabel.font + } + + Image { + id: thumbnailPlaceholder + anchors.fill: parent + anchors.bottomMargin: Constants.imageBottomMargin + anchors.rightMargin: Constants.thumbnailMargin + anchors.leftMargin: Constants.thumbnailMargin + anchors.topMargin: Constants.thumbnailMargin + fillMode: Image.PreserveAspectFit + verticalAlignment: Image.AlignTop + mipmap: true + } + + Rectangle { + id: projectNameBackground + height: mainPanel.multiline && !root.hasPath ? Constants.titleHeightMultiline + : Constants.titleHeight + color: "#e5b0e4" + radius: 3 + anchors.left: parent.left + anchors.right: parent.right + anchors.top: thumbnailPlaceholder.bottom + anchors.topMargin: Constants.titleBackgroundTopMargin + anchors.leftMargin: Constants.thumbnailMargin + anchors.rightMargin: Constants.thumbnailMargin + + Text { + id: projectNameLabel + color: Constants.currentGlobalText + text: typeof(displayName) === "undefined" ? projectName : displayName + elide: root.hasPath ? Text.ElideMiddle : Text.ElideRight + font.pixelSize: 16 + wrapMode: Text.WordWrap + maximumLineCount: 2 + clip: false + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.right: parent.right + anchors.leftMargin: Constants.titleMargin + anchors.rightMargin: Constants.titleMargin + + MouseArea { + id: projectNameMouseArea + anchors.fill: parent + hoverEnabled: true + // Only enable the MouseArea if label actually contains text + enabled: projectNameLabel.text !== "" ? true : false + + Connections { + target: projectNameMouseArea + onClicked: root.thumbnailClicked() + } + } + + ToolTip { + id: projectNameToolTip + y: -projectNameToolTip.height + visible: projectNameMouseArea.containsMouse && projectNameLabel.truncated + text: projectNameLabel.text + delay: 1000 + height: 20 + background: Rectangle { + color: Constants.currentToolTipBackground + border.color: Constants.currentToolTipOutline + border.width: 1 + } + contentItem: Text { + color: Constants.currentToolTipText + text: projectNameToolTip.text + verticalAlignment: Text.AlignVCenter + } + } + } + + DownloadButton { + id: downloadButton + + anchors.right: parent.right + anchors.top: parent.top + visible: root.downloadable + enabled: !downloadButton.downloadUnavailable + + globalHover: (mouseArea.containsMouse || projectNameMouseArea.containsMouse) + && !downloadButton.alreadyDownloaded + && !downloadButton.downloadUnavailable + && !downloadButton.updateAvailable + + alreadyDownloaded: extractor.targetFolderExists + downloadUnavailable: !downloader.available + updateAvailable: downloader.lastModified > extractor.birthTime + + FileDownloader { + id: downloader + downloadEnabled: $dataModel.downloadEnabled() + probeUrl: true + + onFinishedChanged: { + downloadPanel.text = downloadPanel.extractText + downloadPanel.allowCancel = false + downloadPanel.value = Qt.binding(function() { return extractor.progress }) + extractor.extract() + } + + onDownloadStarting: { + $dataModel.usageStatisticsDownloadExample(downloader.name) + } + + onDownloadCanceled: { + downloadPanel.text = "" + downloadPanel.value = 0 + twirlToMainAnimation.start() + mouseArea.enabled = true + } + } + + FileExtractor { + id: extractor + archiveName: downloader.completeBaseName + sourceFile: downloader.outputFile + targetPath: $dataModel.targetPath() + alwaysCreateDir: true + clearTargetPathContents: true + onFinishedChanged: { + twirlToMainAnimation.start() + root.bannerLabelText = qsTr("Recently Downloaded") + mouseArea.enabled = true + } + } + + Connections { + target: downloadButton + onDownloadClicked: { + if (downloadButton.alreadyDownloaded) { + overwriteDialog.open() + } else { + if (downloadButton.enabled) + root.startDownload() + } + } + } + + Connections { + target: $dataModel + onTargetPathMustChange: (path) => { + extractor.changeTargetPath(path) + } + } + } + } + + Text { + id: projectPathLabel + visible: root.hasPath + color: Constants.currentBrand + text: typeof(prettyFilePath) === "undefined" ? "" : prettyFilePath + elide: Text.ElideLeft + renderType: Text.NativeRendering + font.pixelSize: 16 + anchors.left: parent.left + anchors.right: parent.right + anchors.top: projectNameBackground.bottom + anchors.topMargin: 5 + anchors.rightMargin: Constants.thumbnailMargin + anchors.leftMargin: Constants.thumbnailMargin + leftPadding: 5 + + MouseArea { + id: projectPathMouseArea + anchors.fill: parent + hoverEnabled: true + // Only enable the MouseArea if label actually contains text + enabled: projectPathLabel.text !== "" + } + + ToolTip { + id: projectPathToolTip + y: -projectPathToolTip.height + visible: projectPathMouseArea.containsMouse && projectPathLabel.truncated + text: projectPathLabel.text + delay: 1000 + height: 20 + background: Rectangle { + color: Constants.currentToolTipBackground + border.color: Constants.currentToolTipOutline + border.width: 1 + } + contentItem: Text { + color: Constants.currentToolTipText + text: projectPathToolTip.text + verticalAlignment: Text.AlignVCenter + } + } + } + + Rectangle { + id: updateBackground + width: 200 + height: 25 + visible: root.bannerLabelText !== "" + color: Constants.currentBrand + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + anchors.topMargin: 0 + anchors.rightMargin: Constants.thumbnailMargin + anchors.leftMargin: Constants.thumbnailMargin + + Text { + id: updateText + color: Constants.darkActiveGlobalText + text: typeof(displayName) === "bannerText" ? "" : bannerText + anchors.fill: parent + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + } + } + + Rectangle { + id: detailsPanel + height: Constants.thumbnailSize + anchors.left: parent.left + anchors.right: parent.right + anchors.top: mainPanel.bottom + color: Constants.currentNormalThumbnailBackground + radius: 10 + + Text { + id: recentProjectInfo + color: Constants.currentGlobalText + text: typeof(description) === "undefined" ? "" : description + anchors.fill: parent + font.pixelSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignTop + wrapMode: Text.WordWrap + anchors.margins: Constants.thumbnailMargin + anchors.topMargin: 25 + } + + TagArea { + id: tagArea + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.bottomMargin: Constants.thumbnailMargin + anchors.rightMargin: Constants.thumbnailMargin + anchors.leftMargin: Constants.thumbnailMargin + tags: typeof(tagData) === "undefined" ? "" : tagData.split(",") + } + } + } + + states: [ + State { + name: "normal" + when: !mouseArea.containsMouse && !(mouseArea.pressedButtons & Qt.LeftButton) + && !projectPathMouseArea.containsMouse && !projectNameMouseArea.containsMouse + && !downloadButton.isHovered && !twirlButtonDown.isHovered + && !twirlButtonUp.isHovered + + PropertyChanges { + target: mainPanel + color: Constants.currentNormalThumbnailBackground + border.width: 0 + } + PropertyChanges { + target: detailsPanel + color: Constants.currentNormalThumbnailBackground + border.width: 0 + } + PropertyChanges { + target: projectNameBackground + color: Constants.currentNormalThumbnailLabelBackground + } + PropertyChanges { + target: twirlButtonDown + parentHovered: false + } + PropertyChanges { + target: twirlButtonUp + parentHovered: false + } + }, + State { + name: "hover" + when: (mouseArea.containsMouse || projectPathMouseArea.containsMouse + || projectNameMouseArea.containsMouse || downloadButton.isHovered + || twirlButtonDown.isHovered || twirlButtonUp.isHovered) + && !(mouseArea.pressedButtons & Qt.LeftButton) && !root.hasDescription + + PropertyChanges { + target: mainPanel + color: Constants.currentHoverThumbnailBackground + border.width: 0 + } + PropertyChanges { + target: detailsPanel + color: Constants.currentHoverThumbnailBackground + border.width: 0 + } + PropertyChanges { + target: projectNameBackground + color: Constants.currentHoverThumbnailLabelBackground + } + PropertyChanges { + target: thumbnailPlaceholder + visible: true + } + PropertyChanges { + target: twirlButtonDown + parentHovered: true + } + PropertyChanges { + target: twirlButtonUp + parentHovered: true + } + }, + State { + name: "press" + when: (mouseArea.pressedButtons & Qt.LeftButton) && !root.hasDescription + + PropertyChanges { + target: mainPanel + color: Constants.currentHoverThumbnailBackground + border.color: Constants.currentBrand + border.width: 2 + } + PropertyChanges { + target: detailsPanel + color: Constants.currentHoverThumbnailBackground + border.color: Constants.currentBrand + border.width: 2 + } + PropertyChanges { + target: projectNameBackground + color: Constants.currentBrand + } + PropertyChanges { + target: thumbnailPlaceholder + visible: true + } + PropertyChanges { + target: projectNameLabel + color: Constants.darkActiveGlobalText + } + }, + State { + name: "hoverDescription" + when: mouseArea.containsMouse && !(mouseArea.pressedButtons & Qt.LeftButton) + && root.hasDescription + + PropertyChanges { + target: mainPanel + color: Constants.currentHoverThumbnailBackground + border.width: 0 + } + PropertyChanges { + target: projectNameBackground + color: Constants.currentHoverThumbnailLabelBackground + } + PropertyChanges { + target: thumbnailPlaceholder + visible: true + } + }, + State { + name: "pressDescription" + when: (mouseArea.pressedButtons & Qt.LeftButton) && root.hasDescription + + PropertyChanges { + target: mainPanel + color: Constants.currentHoverThumbnailBackground + border.color: Constants.currentBrand + border.width: 2 + } + PropertyChanges { + target: projectNameBackground + color: Constants.currentBrand + } + PropertyChanges { + target: thumbnailPlaceholder + visible: true + } + } + ] + + TwirlButton { + id: twirlButtonDown + height: 20 + visible: root.currentPanel === ThumbnailDelegate.Panel.Main + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + + Connections { + target: twirlButtonDown + onTriggerRelease: twirlToDetailsAnimation.start() + } + } + + TwirlButton { + id: twirlButtonUp + height: 20 + visible: root.currentPanel === ThumbnailDelegate.Panel.Details + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + rotation: 180 + + Connections { + target: twirlButtonUp + onTriggerRelease: twirlToMainAnimation.start() + } + } + + NumberAnimation { + id: twirlToDetailsAnimation + target: canvas + property: "y" + easing.bezierCurve: [0.972,-0.176,0.0271,1.16,1,1] + duration: 250 + alwaysRunToEnd: true + to: -Constants.thumbnailSize // dynamic size because of rescale - needs to be inverted because animation goes into negative range + from: canvas.y + } + + NumberAnimation { + id: twirlToMainAnimation + target: canvas + property: "y" + easing.bezierCurve: [0.972,-0.176,0.0271,1.16,1,1] + alwaysRunToEnd: true + duration: 250 + to: 0 + from: canvas.y + } + + NumberAnimation { + id: twirlToDownloadAnimation + target: canvas + property: "y" + easing.bezierCurve: [0.972,-0.176,0.0271,1.16,1,1] + alwaysRunToEnd: true + duration: 250 + to: Constants.thumbnailSize + from: canvas.y + } + + Connections { + target: twirlToDetailsAnimation + onStarted: root.currentPanel = ThumbnailDelegate.Panel.InBetween + onFinished: { + root.currentPanel = ThumbnailDelegate.Panel.Details + canvas.y = Qt.binding(function() {return -Constants.thumbnailSize }) + } + } + + Connections { + target: twirlToMainAnimation + onStarted: root.currentPanel = ThumbnailDelegate.Panel.InBetween + onFinished: { + root.currentPanel = ThumbnailDelegate.Panel.Main + canvas.y = Qt.binding(function() {return 0 }) + } + } + + Connections { + target: twirlToDownloadAnimation + onStarted: root.currentPanel = ThumbnailDelegate.Panel.InBetween + onFinished: { + root.currentPanel = ThumbnailDelegate.Panel.Download + canvas.y = Qt.binding(function() {return Constants.thumbnailSize }) + } + } +} diff --git a/share/qtcreator/qmldesigner/welcomepage/TourDialogButton.qml b/share/qtcreator/qmldesigner/welcomepage/TourDialogButton.qml new file mode 100644 index 0000000000..35ace283ed --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/TourDialogButton.qml @@ -0,0 +1,69 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick.Controls +import WelcomeScreen 1.0 +import StudioTheme 1.0 as StudioTheme +import UiTour + +Item { + id: tourButton + width: 40 + height: 40 + property alias dialogButtonText: dialogButton.text + + signal buttonClicked + + Text { + id: dialogButton + color: "#ffffff" + font.family: StudioTheme.Constants.iconFont.family + text: StudioTheme.Constants.closeFile_large + font.pixelSize: 32 + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + } + + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + + Connections { + target: mouseArea + onClicked: tourButton.buttonClicked() + } + } + + states: [ + State { + name: "normal" + when: !mouseArea.containsMouse && !mouseArea.pressed + + PropertyChanges { + target: dialogButton + color: "#ecebeb" + font.pixelSize: 28 + } + }, + State { + name: "hover" + when: mouseArea.containsMouse && !mouseArea.pressed + + PropertyChanges { + target: dialogButton + font.pixelSize: 29 + } + }, + State { + name: "press" + when: mouseArea.pressed + + PropertyChanges { + target: dialogButton + font.pixelSize: 29 + } + } + ] +} diff --git a/share/qtcreator/qmldesigner/welcomepage/TourModel.qml b/share/qtcreator/qmldesigner/welcomepage/TourModel.qml new file mode 100644 index 0000000000..db6224f7d6 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/TourModel.qml @@ -0,0 +1,73 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick + +ListModel { + ListElement { + qmlFileName: "tours/welcomepage-tour/WelcomeSlideShow.ui.qml" + thumbnail: "images/welcome-page.png" + title: QT_TR_NOOP("Welcome Page") + subtitle: QT_TR_NOOP("The welcome page of Qt Design Studio.") + } + ListElement { + qmlFileName: "tours/workspace-tour/WorkspaceSlideShow.ui.qml" + thumbnail: "images/workspaces.png" + title: QT_TR_NOOP("Workspaces") + subtitle: QT_TR_NOOP("Introduction to the most important workspaces.") + } + ListElement { + qmlFileName: "tours/toolbar-tour/ToolbarSlideShow.ui.qml" + thumbnail: "images/top-toolbar.png" + title: QT_TR_NOOP("Top Toolbar") + subtitle: QT_TR_NOOP("Short explanation of the top toolbar.") + } + ListElement { + qmlFileName: "tours/states-tour/StatesSlideShow.ui.qml" + thumbnail: "images/states.png" + title: QT_TR_NOOP("States") + subtitle: QT_TR_NOOP("An introduction to states.") + } + ListElement { + qmlFileName: "tours/sortcomponents-tour/SortComponentsSlideShow.ui.qml" + thumbnail: "images/sorting-components.png" + title: QT_TR_NOOP("Sorting Components") + subtitle: QT_TR_NOOP("A way to organize multiple components.") + } + ListElement { + qmlFileName: "tours/connectcomponents-tour/ConnectComponentsSlideShow.ui.qml" + thumbnail: "images/connecting-components.png" + title: QT_TR_NOOP("Connecting Components") + subtitle: QT_TR_NOOP("A way to connect components with actions.") + } + ListElement { + qmlFileName: "tours/addassets-tour/AddAssetsSlideShow.ui.qml" + thumbnail: "images/adding-assets.png" + title: QT_TR_NOOP("Adding Assets") + subtitle: QT_TR_NOOP("A way to add new assets to the project.") + } + ListElement { + qmlFileName: "tours/animation-tour/AnimationSlideShow.ui.qml" + thumbnail: "images/animation-2d.png" + title: QT_TR_NOOP("Creating 2D Animation") + subtitle: QT_TR_NOOP("A way to create a 2D Animation.") + } + ListElement { + qmlFileName: "tours/studiocomponents-border-arc-tour/StudioComponentBorderArcSlideShow.ui.qml" + thumbnail: "images/border-arc.png" + title: QT_TR_NOOP("Border and Arc") + subtitle: QT_TR_NOOP("Work with Border and Arc Studio Components.") + } + ListElement { + qmlFileName: "tours/studiocomponents-ellipse-pie-tour/StudioComponentEllipsePieSlideShow.ui.qml" + thumbnail: "images/ellipse-pie.png" + title: QT_TR_NOOP("Ellipse and Pie") + subtitle: QT_TR_NOOP("Work with Ellipse and Pie Studio Components.") + } + ListElement { + qmlFileName: "tours/studiocomponents-polygon-triangle-rectangle-tour/StudioComponentPolygonTriangleRectangleSlideShow.ui.qml" + thumbnail: "images/complex-shapes.png" + title: QT_TR_NOOP("Complex Shapes") + subtitle: QT_TR_NOOP("Work with Polygon, Triangle and Rectangle Studio Components.") + } +} diff --git a/share/qtcreator/qmldesigner/welcomepage/TourProgressBar.qml b/share/qtcreator/qmldesigner/welcomepage/TourProgressBar.qml new file mode 100644 index 0000000000..bae49c0fe4 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/TourProgressBar.qml @@ -0,0 +1,41 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick.Controls +import WelcomeScreen 1.0 + +Item { + id: progressBar + + property int endSlide: 10 + property int currentSlide: 1 + + Rectangle { + id: progressBarGroove + color: "#272727" + radius: 5 + border.color: "#00000000" + anchors.fill: parent + } + + Rectangle { + id: progressBarTrack + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.bottomMargin: 1 + anchors.topMargin: 1 + width: (progressBarGroove.width / 100) * rangeMapper.output + color: "#57b9fc" + radius: 4.5 + } + + RangeMapper { + id: rangeMapper + inputMaximum: progressBar.endSlide + outputMaximum: 100 + outputMinimum: 0 + inputMinimum: 0 + input: progressBar.currentSlide + } +} diff --git a/share/qtcreator/qmldesigner/welcomepage/TourRestartButton.qml b/share/qtcreator/qmldesigner/welcomepage/TourRestartButton.qml new file mode 100644 index 0000000000..55f367ffb9 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/TourRestartButton.qml @@ -0,0 +1,84 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import WelcomeScreen 1.0 + +Rectangle { + id: restart + height: 36 + color: "#00ffffff" + radius: 18 + border.color: "#f9f9f9" + border.width: 3 + state: "normal" + + signal restart() + + Text { + id: text2 + color: "#ffffff" + text: qsTrId("Restart") + anchors.verticalCenter: parent.verticalCenter + font.pixelSize: 12 + anchors.horizontalCenter: parent.horizontalCenter + } + + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + + Connections { + target: mouseArea + onClicked: restart.restart() + } + } + + states: [ + State { + name: "normal" + when: !mouseArea.containsMouse && !mouseArea.pressed + + PropertyChanges { + target: text2 + color: "#dedede" + } + + PropertyChanges { + target: restart + border.color: "#dedede" + } + }, + State { + name: "hover" + when: mouseArea.containsMouse && !mouseArea.pressed + + PropertyChanges { + target: restart + color: "#00ffffff" + border.color: "#ffffff" + } + + PropertyChanges { + target: text2 + color: "#ffffff" + } + }, + State { + name: "press" + when: mouseArea.pressed + + PropertyChanges { + target: restart + color: "#ffffff" + border.color: "#ffffff" + } + + PropertyChanges { + target: text2 + color: "#000000" + } + } + ] +} diff --git a/share/qtcreator/qmldesigner/welcomepage/TourThumbnailDelegate.qml b/share/qtcreator/qmldesigner/welcomepage/TourThumbnailDelegate.qml new file mode 100644 index 0000000000..0f61a2a3c4 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/TourThumbnailDelegate.qml @@ -0,0 +1,164 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick.Controls +import WelcomeScreen 1.0 + +Item { + id: root + width: Constants.thumbnailSize + height: Constants.thumbnailSize + state: "normal" + clip: true + + property bool complete: root.currentSlide === root.endSlide + + // Needs to be set from the current slide show and user progress + property int currentSlide: 0 + property int endSlide: 10 + + signal clicked() + + Rectangle { + id: background + radius: 10 + color: Constants.currentNormalThumbnailBackground + anchors.fill: parent + + property bool multiline: (tourNameLabelMetric.width >= tourNameLabel.width) + + TextMetrics { + id: tourNameLabelMetric + text: tourNameLabel.text + font: tourNameLabel.font + } + + Image { + id: thumbnailPlaceholder + source: thumbnail + anchors.fill: parent + anchors.bottomMargin: Constants.imageBottomMargin + anchors.rightMargin: Constants.thumbnailMargin + anchors.leftMargin: Constants.thumbnailMargin + anchors.topMargin: Constants.thumbnailMargin + fillMode: Image.PreserveAspectFit + verticalAlignment: Image.AlignTop + mipmap: true + } + + Rectangle { + id: tourNameBackground + height: background.multiline ? Constants.titleHeightMultiline : Constants.titleHeight + color: "#e5b0e4" + radius: 3 + anchors.left: parent.left + anchors.right: parent.right + anchors.top: thumbnailPlaceholder.bottom + anchors.topMargin: Constants.titleBackgroundTopMargin + anchors.leftMargin: Constants.thumbnailMargin + anchors.rightMargin: Constants.thumbnailMargin + + Text { + id: tourNameLabel + color: Constants.currentGlobalText + font.pixelSize: 16 + text: title + wrapMode: Text.WordWrap + maximumLineCount: 2 + clip: false + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.right: parent.right + anchors.leftMargin: Constants.titleMargin + anchors.rightMargin: Constants.titleMargin + } + } + + Text { + id: subtitleCaption + color: Constants.currentGlobalText + text: subtitle + renderType: Text.NativeRendering + font.pixelSize: 14 + wrapMode: Text.WordWrap + anchors.left: parent.left + anchors.right: parent.right + anchors.top: tourNameBackground.bottom + anchors.topMargin: 5 + anchors.rightMargin: Constants.thumbnailMargin + anchors.leftMargin: Constants.thumbnailMargin + leftPadding: 5 + rightPadding: 5 + } + + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + + Connections { + target: mouseArea + onClicked: root.clicked() + } + } + } + + states: [ + State { + name: "normal" + when: root.enabled && !mouseArea.containsMouse && !mouseArea.pressed && !root.complete + + PropertyChanges { + target: background + color: Constants.currentNormalThumbnailBackground + border.width: 0 + } + PropertyChanges { + target: tourNameBackground + color: Constants.currentNormalThumbnailLabelBackground + } + PropertyChanges { + target: mouseArea + enabled: true + } + }, + State { + name: "hover" + when: root.enabled && mouseArea.containsMouse && !mouseArea.pressed && !root.complete + + PropertyChanges { + target: background + color: Constants.currentHoverThumbnailBackground + border.width: 0 + } + PropertyChanges { + target: tourNameBackground + color: Constants.currentHoverThumbnailLabelBackground + } + PropertyChanges { + target: mouseArea + enabled: true + } + }, + State { + name: "press" + when: root.enabled && mouseArea.pressed && !root.complete + + PropertyChanges { + target: background + color: Constants.currentHoverThumbnailBackground + border.color: Constants.currentBrand + border.width: 2 + } + PropertyChanges { + target: tourNameBackground + color: Constants.currentBrand + } + PropertyChanges { + target: mouseArea + enabled: true + } + } + ] +} diff --git a/share/qtcreator/qmldesigner/welcomepage/TwirlButton.qml b/share/qtcreator/qmldesigner/welcomepage/TwirlButton.qml new file mode 100644 index 0000000000..e9813ad997 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/TwirlButton.qml @@ -0,0 +1,118 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick.Controls +import WelcomeScreen 1.0 +import QtQuick.Layouts +import StudioTheme 1.0 as StudioTheme + +Item { + id: twirlButton + width: 25 + height: 25 + state: "normal" + + property bool parentHovered: false + property bool isHovered: mouseArea.containsMouse + signal triggerRelease() + + Rectangle { + id: background + color: "#eab336" + border.width: 0 + anchors.fill: parent + } + + Text { + id: twirlIcon + width: 23 + height: 23 + color: Constants.currentGlobalText + font.family: StudioTheme.Constants.iconFont.family + text: StudioTheme.Constants.adsDropDown + anchors.verticalCenter: parent.verticalCenter + anchors.bottom: parent.bottom + font.pixelSize: 14 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + anchors.horizontalCenter: parent.horizontalCenter + } + + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + + Connections { + target: mouseArea + onReleased: twirlButton.triggerRelease() + } + } + + states: [ + State { + name: "hidden" + when: !mouseArea.containsMouse && !mouseArea.pressed && !twirlButton.parentHovered + + PropertyChanges { + target: background + visible: false + } + PropertyChanges { + target: twirlIcon + visible: false + } + }, + State { + name: "normal" + when: !mouseArea.containsMouse && !mouseArea.pressed && twirlButton.parentHovered + + PropertyChanges { + target: background + visible: false + } + PropertyChanges { + target: twirlIcon + visible: true + } + }, + State { + name: "hover" + when: mouseArea.containsMouse && !mouseArea.pressed + + PropertyChanges { + target: twirlIcon + scale: 1.4 + } + PropertyChanges { + target: background + visible: true + color: Constants.currentHoverThumbnailLabelBackground + } + PropertyChanges { + target: twirlIcon + visible: true + } + }, + State { + name: "press" + when: mouseArea.pressed + + PropertyChanges { + target: twirlIcon + color: Constants.currentGlobalText + scale: 1.8 + } + PropertyChanges { + target: background + visible: true + color: Constants.currentBrand + } + PropertyChanges { + target: twirlIcon + visible: true + } + } + ] +} diff --git a/share/qtcreator/qmldesigner/welcomepage/TwitterButton.qml b/share/qtcreator/qmldesigner/welcomepage/TwitterButton.qml new file mode 100644 index 0000000000..9349fcd32c --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/TwitterButton.qml @@ -0,0 +1,125 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import WelcomeScreen 1.0 +import StudioTheme 1.0 as StudioTheme + +Item { + id: twitterButton + state: "darkNormal" + + property bool isHovered: mouseArea.containsMouse + + Image { + id: twitterDarkNormal + anchors.fill: parent + source: "images/twitterDarkNormal.png" + fillMode: Image.PreserveAspectFit + } + + Image { + id: twitterLightNormal + anchors.fill: parent + source: "images/twitterLightNormal.png" + fillMode: Image.PreserveAspectFit + } + + Image { + id: twitterHover + anchors.fill: parent + source: "images/twitterHover.png" + fillMode: Image.PreserveAspectFit + } + + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + + Connections { + target: mouseArea + function onClicked(mouse) { Qt.openUrlExternally("https://twitter.com/qtproject/") } + } + } + + states: [ + State { + name: "darkNormal" + when: !StudioTheme.Values.isLightTheme && !mouseArea.containsMouse && !mouseArea.pressed + + PropertyChanges { + target: twitterDarkNormal + visible: true + } + + PropertyChanges { + target: twitterLightNormal + visible: false + } + + PropertyChanges { + target: twitterHover + visible: false + } + }, + State { + name: "lightNormal" + when: StudioTheme.Values.isLightTheme && !mouseArea.containsMouse && !mouseArea.pressed + + PropertyChanges { + target: twitterHover + visible: false + } + + PropertyChanges { + target: twitterLightNormal + visible: true + } + + PropertyChanges { + target: twitterDarkNormal + visible: false + } + }, + State { + name: "hover" + when: mouseArea.containsMouse && !mouseArea.pressed + + PropertyChanges { + target: twitterHover + visible: true + } + + PropertyChanges { + target: twitterLightNormal + visible: false + } + + PropertyChanges { + target: twitterDarkNormal + visible: false + } + }, + State { + name: "press" + when: (mouseArea.containsMouse || !mouseArea.containsMouse) && mouseArea.pressed + + PropertyChanges { + target: twitterHover + visible: true + scale: 1.1 + } + + PropertyChanges { + target: twitterLightNormal + visible: false + } + + PropertyChanges { + target: twitterDarkNormal + visible: false + } + } + ] +} diff --git a/share/qtcreator/qmldesigner/welcomepage/WelcomePage.qml b/share/qtcreator/qmldesigner/welcomepage/WelcomePage.qml new file mode 100644 index 0000000000..2f8778f2f8 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/WelcomePage.qml @@ -0,0 +1,52 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import WelcomeScreen 1.0 +import projectmodel 1.0 + +Item { + id: appFrame + clip: true + width: Constants.width + height: Constants.height + + property int loadingProgress: 50 + + onLoadingProgressChanged: Constants.loadingProgress = appFrame.loadingProgress + + NumberAnimation { + target: appFrame + property: "loadingProgress" + from: 0 + to: 100 + loops: Animation.Infinite + running: false + duration: 1000 + } + + MainScreen { + id: screen + anchors.fill: parent + anchors.leftMargin: screen.designMode ? 0 : -45 // hide sidebar + } + + property int pageIndex: 0 + property int minimumWidth: 1200 + property int minimumHeight: 720 + + onHeightChanged: { + if (appFrame.height > appFrame.minimumHeight) + appFrame.anchors.fill = parent + else if (appFrame.height < appFrame.minimumHeight) + appFrame.height = appFrame.minimumHeight + } + onWidthChanged: { + if (appFrame.width > appFrame.minimumWidth) + appFrame.anchors.fill = parent + else if (appFrame.width < appFrame.minimumWidth) + appFrame.width = appFrame.minimumWidth + } +} diff --git a/share/qtcreator/qmldesigner/welcomepage/WelcomeScreen.qmlproject b/share/qtcreator/qmldesigner/welcomepage/WelcomeScreen.qmlproject new file mode 100644 index 0000000000..539db2133a --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/WelcomeScreen.qmlproject @@ -0,0 +1,49 @@ +/* File generated by Qt Creator */ + +import QmlProject 1.1 + +Project { + mainFile: "WelcomePage.qml" + + /* Include .qml, .js, and image files from current directory and subdirectories */ + QmlFiles { + directory: "." + } + + JavaScriptFiles { + directory: "." + } + + ImageFiles { + directory: "." + } + + Files { + filter: "*.conf" + files: ["qtquickcontrols2.conf"] + } + + Files { + filter: "qmldir" + directory: "." + } + + Files { + filter: "*.ttf;*.otf" + } + + Environment { + QT_QUICK_CONTROLS_CONF: "qtquickcontrols2.conf" + //QT_AUTO_SCREEN_SCALE_FACTOR: "1" + QT_SCALE_FACTOR: "0.8" + QT_LOGGING_RULES: "qt.qml.connections=false" + } + + qt6Project: true + + /* List of plugin directories passed to QML runtime */ + importPaths: [ "imports", "studioImports", "asset_imports", "mockData", "dataImports" ] + + /* Required for deployment */ + targetDirectory: "/opt/WelcomeScreen" +} diff --git a/share/qtcreator/qmldesigner/welcomepage/YoutubeButton.qml b/share/qtcreator/qmldesigner/welcomepage/YoutubeButton.qml new file mode 100644 index 0000000000..ec7eb54ace --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/YoutubeButton.qml @@ -0,0 +1,201 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick.Templates +import WelcomeScreen 1.0 +import StudioTheme 1.0 as StudioTheme + +Item { + id: youtubeButton + state: "darkNormal" + + property bool isHovered: mouseArea.containsMouse + + Image { + id: youtubeDarkNormal + anchors.fill: parent + source: "images/youtubeDarkNormal.png" + fillMode: Image.PreserveAspectFit + } + + Image { + id: youtubeLightNormal + anchors.fill: parent + source: "images/youtubeLightNormal.png" + fillMode: Image.PreserveAspectFit + } + + Image { + id: youtubeLightHover + anchors.fill: parent + source: "images/youtubeLightHover.png" + fillMode: Image.PreserveAspectFit + } + + Image { + id: youtubeDarkHover + anchors.fill: parent + source: "images/youtubeDarkHover.png" + fillMode: Image.PreserveAspectFit + } + + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + + Connections { + target: mouseArea + function onClicked(mouse) { Qt.openUrlExternally("https://www.youtube.com/user/QtStudios/") } + } + } + states: [ + State { + name: "darkNormal" + when: !StudioTheme.Values.isLightTheme && !mouseArea.containsMouse && !mouseArea.pressed + + PropertyChanges { + target: youtubeDarkNormal + visible: true + } + + PropertyChanges { + target: youtubeLightNormal + visible: false + } + + PropertyChanges { + target: youtubeLightHover + visible: false + } + + PropertyChanges { + target: youtubeDarkHover + visible: false + } + }, + State { + name: "lightNormal" + when: StudioTheme.Values.isLightTheme && !mouseArea.containsMouse && !mouseArea.pressed + + PropertyChanges { + target: youtubeDarkHover + visible: false + } + + PropertyChanges { + target: youtubeLightHover + visible: false + } + + PropertyChanges { + target: youtubeLightNormal + visible: true + } + + PropertyChanges { + target: youtubeDarkNormal + visible: false + } + }, + State { + name: "darkHover" + when: !StudioTheme.Values.isLightTheme && mouseArea.containsMouse && !mouseArea.pressed + + PropertyChanges { + target: youtubeDarkNormal + visible: false + } + + PropertyChanges { + target: youtubeLightNormal + visible: false + } + + PropertyChanges { + target: youtubeLightHover + visible: false + } + + PropertyChanges { + target: youtubeDarkHover + visible: true + } + }, + State { + name: "lightHover" + when: StudioTheme.Values.isLightTheme && mouseArea.containsMouse && !mouseArea.pressed + + PropertyChanges { + target: youtubeDarkHover + visible: false + } + + PropertyChanges { + target: youtubeLightHover + visible: true + } + + PropertyChanges { + target: youtubeLightNormal + visible: false + } + + PropertyChanges { + target: youtubeDarkNormal + visible: false + } + }, + State { + name: "darkPress" + when: !StudioTheme.Values.isLightTheme && mouseArea.pressed + + PropertyChanges { + target: youtubeDarkHover + visible: true + scale: 1.1 + } + + PropertyChanges { + target: youtubeLightHover + visible: false + } + + PropertyChanges { + target: youtubeLightNormal + visible: false + } + + PropertyChanges { + target: youtubeDarkNormal + visible: false + } + }, + State { + name: "lightPress" + when: StudioTheme.Values.isLightTheme && mouseArea.pressed + + PropertyChanges { + target: youtubeDarkHover + visible: false + } + + PropertyChanges { + target: youtubeLightHover + visible: true + scale: 1.1 + } + + PropertyChanges { + target: youtubeLightNormal + visible: false + } + + PropertyChanges { + target: youtubeDarkNormal + visible: false + } + } + ] +} diff --git a/share/qtcreator/qmldesigner/welcomepage/fonts/fonts.txt b/share/qtcreator/qmldesigner/welcomepage/fonts/fonts.txt new file mode 100644 index 0000000000..ab96122067 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/fonts/fonts.txt @@ -0,0 +1 @@ +Fonts in this folder are loaded automatically. diff --git a/share/qtcreator/qmldesigner/welcomepage/images/adding-assets.png b/share/qtcreator/qmldesigner/welcomepage/images/adding-assets.png Binary files differnew file mode 100644 index 0000000000..099b8d3ec3 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/images/adding-assets.png diff --git a/share/qtcreator/qmldesigner/welcomepage/images/animation-2d.png b/share/qtcreator/qmldesigner/welcomepage/images/animation-2d.png Binary files differnew file mode 100644 index 0000000000..1a607e1fd9 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/images/animation-2d.png diff --git a/share/qtcreator/qmldesigner/welcomepage/images/border-arc.png b/share/qtcreator/qmldesigner/welcomepage/images/border-arc.png Binary files differnew file mode 100644 index 0000000000..d1575c49f5 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/images/border-arc.png diff --git a/share/qtcreator/qmldesigner/welcomepage/images/complex-shapes.png b/share/qtcreator/qmldesigner/welcomepage/images/complex-shapes.png Binary files differnew file mode 100644 index 0000000000..371295b831 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/images/complex-shapes.png diff --git a/share/qtcreator/qmldesigner/welcomepage/images/congratulations.png b/share/qtcreator/qmldesigner/welcomepage/images/congratulations.png Binary files differnew file mode 100644 index 0000000000..816feb76b4 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/images/congratulations.png diff --git a/share/qtcreator/qmldesigner/welcomepage/images/connecting-components.png b/share/qtcreator/qmldesigner/welcomepage/images/connecting-components.png Binary files differnew file mode 100644 index 0000000000..9f8e45cd4e --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/images/connecting-components.png diff --git a/share/qtcreator/qmldesigner/welcomepage/images/ds.png b/share/qtcreator/qmldesigner/welcomepage/images/ds.png Binary files differnew file mode 100644 index 0000000000..e523ba4082 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/images/ds.png diff --git a/share/qtcreator/qmldesigner/welcomepage/images/ellipse-pie.png b/share/qtcreator/qmldesigner/welcomepage/images/ellipse-pie.png Binary files differnew file mode 100644 index 0000000000..a081ea81bf --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/images/ellipse-pie.png diff --git a/share/qtcreator/qmldesigner/welcomepage/images/newThumbnail.png b/share/qtcreator/qmldesigner/welcomepage/images/newThumbnail.png Binary files differnew file mode 100644 index 0000000000..046c053570 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/images/newThumbnail.png diff --git a/share/qtcreator/qmldesigner/welcomepage/images/noPreview.png b/share/qtcreator/qmldesigner/welcomepage/images/noPreview.png Binary files differnew file mode 100644 index 0000000000..33641e6fb0 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/images/noPreview.png diff --git a/share/qtcreator/qmldesigner/welcomepage/images/place_holder.png b/share/qtcreator/qmldesigner/welcomepage/images/place_holder.png Binary files differnew file mode 100644 index 0000000000..96e7e63796 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/images/place_holder.png diff --git a/share/qtcreator/qmldesigner/welcomepage/images/sorting-components.png b/share/qtcreator/qmldesigner/welcomepage/images/sorting-components.png Binary files differnew file mode 100644 index 0000000000..19b2182d3f --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/images/sorting-components.png diff --git a/share/qtcreator/qmldesigner/welcomepage/images/states.png b/share/qtcreator/qmldesigner/welcomepage/images/states.png Binary files differnew file mode 100644 index 0000000000..41f1bbaddd --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/images/states.png diff --git a/share/qtcreator/qmldesigner/welcomepage/images/thumbnailImage.png b/share/qtcreator/qmldesigner/welcomepage/images/thumbnailImage.png Binary files differnew file mode 100644 index 0000000000..f54508029a --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/images/thumbnailImage.png diff --git a/share/qtcreator/qmldesigner/welcomepage/images/thumbnail_test.png b/share/qtcreator/qmldesigner/welcomepage/images/thumbnail_test.png Binary files differnew file mode 100644 index 0000000000..3c4834e644 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/images/thumbnail_test.png diff --git a/share/qtcreator/qmldesigner/welcomepage/images/top-toolbar.png b/share/qtcreator/qmldesigner/welcomepage/images/top-toolbar.png Binary files differnew file mode 100644 index 0000000000..33601d658b --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/images/top-toolbar.png diff --git a/share/qtcreator/qmldesigner/welcomepage/images/twitterDarkNormal.png b/share/qtcreator/qmldesigner/welcomepage/images/twitterDarkNormal.png Binary files differnew file mode 100644 index 0000000000..bd2349329c --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/images/twitterDarkNormal.png diff --git a/share/qtcreator/qmldesigner/welcomepage/images/twitterHover.png b/share/qtcreator/qmldesigner/welcomepage/images/twitterHover.png Binary files differnew file mode 100644 index 0000000000..a10316113d --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/images/twitterHover.png diff --git a/share/qtcreator/qmldesigner/welcomepage/images/twitterLightNormal.png b/share/qtcreator/qmldesigner/welcomepage/images/twitterLightNormal.png Binary files differnew file mode 100644 index 0000000000..b6ad88c5b6 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/images/twitterLightNormal.png diff --git a/share/qtcreator/qmldesigner/welcomepage/images/welcome-page.png b/share/qtcreator/qmldesigner/welcomepage/images/welcome-page.png Binary files differnew file mode 100644 index 0000000000..4c072eb2a1 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/images/welcome-page.png diff --git a/share/qtcreator/qmldesigner/welcomepage/images/workspaces.png b/share/qtcreator/qmldesigner/welcomepage/images/workspaces.png Binary files differnew file mode 100644 index 0000000000..ce4b5f6158 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/images/workspaces.png diff --git a/share/qtcreator/qmldesigner/welcomepage/images/youtubeDarkHover.png b/share/qtcreator/qmldesigner/welcomepage/images/youtubeDarkHover.png Binary files differnew file mode 100644 index 0000000000..a58f1cd0cf --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/images/youtubeDarkHover.png diff --git a/share/qtcreator/qmldesigner/welcomepage/images/youtubeDarkNormal.png b/share/qtcreator/qmldesigner/welcomepage/images/youtubeDarkNormal.png Binary files differnew file mode 100644 index 0000000000..7c5a5cd918 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/images/youtubeDarkNormal.png diff --git a/share/qtcreator/qmldesigner/welcomepage/images/youtubeLightHover.png b/share/qtcreator/qmldesigner/welcomepage/images/youtubeLightHover.png Binary files differnew file mode 100644 index 0000000000..15a16b3bb1 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/images/youtubeLightHover.png diff --git a/share/qtcreator/qmldesigner/welcomepage/images/youtubeLightNormal.png b/share/qtcreator/qmldesigner/welcomepage/images/youtubeLightNormal.png Binary files differnew file mode 100644 index 0000000000..9ec959fc92 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/images/youtubeLightNormal.png diff --git a/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/Highlight.ui.qml b/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/Highlight.ui.qml new file mode 100644 index 0000000000..a3bd85184a --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/Highlight.ui.qml @@ -0,0 +1,61 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick.Controls +import QtQuick.Timeline + +Rectangle { + id: root + width: 872 + height: 860 + radius: 4 + color: "transparent" + border.color: "#1381e3" + border.width: 8 + state: "off" + + property bool active: true + + states: [ + State { + name: "on" + when: root.active + + PropertyChanges { + target: root + } + }, + State { + name: "off" + when: !root.active + + PropertyChanges { + target: root + opacity: 0 + } + } + ] + + transitions: [ + Transition { + id: transition + to: "*" + from: "*" + ParallelAnimation { + SequentialAnimation { + PauseAnimation { duration: 0 } + + PropertyAnimation { + target: root + property: "opacity" + duration: 150 + } + } + } + } + ] +} + + + diff --git a/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/Slide.qml b/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/Slide.qml new file mode 100644 index 0000000000..cb94d05ad2 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/Slide.qml @@ -0,0 +1,118 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick.Controls +import QtQuick.Timeline + +Item { + id: root + width: 1920 + height: 1080 + + property string caption: "This is a string" + property string title: "this is a string" + property bool active: false + + function prev() { + var states = root.stateNames() + + if (states.length === 0) + return false + + if (root.state === "") + return false + + var index = states.indexOf(root.state) + + // base state is not in the list + if (index > 0) { + root.state = states[index - 1] + return true + } + + return false + } + + function next() { + var states = root.stateNames() + + if (states.length === 0) + return false + + if (root.state === "") { + root.state = states[0] + return true + } + + var index = states.indexOf(root.state) + + if (index < (states.length - 1)) { + root.state = states[index + 1] + return true + } + + return false + } + + function stateNames() { + var states = [] + + for (var i = 0; i < root.states.length; i++) { + var state = root.states[i] + states.push(state.name) + } + + return states + } + + signal activated + + function activate() { + root.active = true + stateGroup.state = "active" + root.activated() + } + + function done() { + stateGroup.state = "done" + } + + function init() { + root.active = false + stateGroup.state = "inactive" + } + + StateGroup { + id: stateGroup + states: [ + State { + name: "active" + + PropertyChanges { + target: root + opacity: 1 + visible: true + } + }, + State { + name: "inactive" + + PropertyChanges { + target: root + opacity: 0 + visible: true + } + }, + State { + name: "done" + + PropertyChanges { + target: root + opacity: 1 + visible: true + } + } + ] + } +} diff --git a/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/SlideNavButton.qml b/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/SlideNavButton.qml new file mode 100644 index 0000000000..07f744e300 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/SlideNavButton.qml @@ -0,0 +1,71 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick.Controls +import WelcomeScreen 1.0 +import StudioTheme 1.0 as StudioTheme +import UiTour + +Item { + id: tourButton + width: 120 + height: 120 + property alias dialogButtonRotation: dialogButton.rotation + property alias dialogButtonFontpixelSize: dialogButton.font.pixelSize + property alias dialogButtonText: dialogButton.text + + signal buttonClicked + + Text { + id: dialogButton + color: "#ffffff" + text: StudioTheme.Constants.nextFile_large + font.family: StudioTheme.Constants.iconFont.family + font.pixelSize: 32 + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + } + + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + + Connections { + target: mouseArea + onClicked: tourButton.buttonClicked() + } + } + + states: [ + State { + name: "normal" + when: !mouseArea.containsMouse && !mouseArea.pressed + + PropertyChanges { + target: dialogButton + color: "#ecebeb" + font.pixelSize: 92 + } + }, + State { + name: "hover" + when: mouseArea.containsMouse && !mouseArea.pressed + + PropertyChanges { + target: dialogButton + font.pixelSize: 96 + } + }, + State { + name: "press" + when: mouseArea.pressed + + PropertyChanges { + target: dialogButton + font.pixelSize: 98 + } + } + ] +} diff --git a/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/SlidePlayer.qml b/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/SlidePlayer.qml new file mode 100644 index 0000000000..5664223990 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/SlidePlayer.qml @@ -0,0 +1,132 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick.Layouts +import QtQuick.Shapes +import UiTour + +Item { + id: root + width: 1920 + height: 1080 + visible: true + + property alias slideSource: loader.source + property alias loaderActive: loader.active + property var mainScreen: loader.item + + Image { + id: gradientRect + anchors.fill: parent + source: "gradientRect.webp" + mipmap: true + fillMode: Image.Stretch + } + + RowLayout { + anchors.fill: parent + + Item { + Layout.preferredWidth: 160 + Layout.maximumWidth: 160 + Layout.fillHeight: true + + SlideNavButton { + id: prevSlideButton + dialogButtonRotation: 180 + visible: ((mainScreen.currentSlide + 1) !== 1) + anchors.fill: parent + + Connections { + target: prevSlideButton + onButtonClicked: mainScreen.prev() + } + } + } + + Column { + id: content + Layout.fillWidth: true + Layout.preferredWidth: 120 + + Item { + id: titleFrame + width: content.width + height: 100 + + Text { + color: "#ffffff" + text: mainScreen.title + font.pixelSize: 40 + font.bold: true + wrapMode: Text.WordWrap + anchors.centerIn: parent + } + } + + Item { + id: slideFrame + width: content.width + height: Math.min(1080 * content.width / 1920, + root.height - (titleFrame.height + captionFrame.height + indicatorFrame.height)) + + Loader { + id: loader + source: "MySlideShow.ui.qml" + transformOrigin: Item.Center + scale: Math.min(slideFrame.width / 1920, slideFrame.height / 1080) + anchors.centerIn: parent + } + } + + Item { + id: captionFrame + width: content.width + height: 140 + + Text { + id: captionText + color: "#ffffff" + text: mainScreen.caption + font.pixelSize: 20 + font.bold: true + wrapMode: Text.WordWrap + anchors.fill: parent + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + } + + Item { + id: indicatorFrame + width: content.width + height: 100 + + Text { + color: "#ffffff" + text: (mainScreen.currentSlide + 1) + "/" + mainScreen.progress + font.pixelSize: 20 + anchors.centerIn: parent + } + } + } + + Item { + Layout.preferredWidth: 160 + Layout.maximumWidth: 160 + Layout.fillHeight: true + + SlideNavButton { + id: nextSlideButton + visible: (mainScreen.progress !== (mainScreen.currentSlide + 1)) + anchors.fill: parent + + Connections { + target: nextSlideButton + onButtonClicked: mainScreen.next() + } + } + } + } +} diff --git a/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/SlideShow.qml b/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/SlideShow.qml new file mode 100644 index 0000000000..8e7195fcb1 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/SlideShow.qml @@ -0,0 +1,85 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick.Controls + +Rectangle { + id: root + width: 1920 + height: 1080 + color: "#00000000" + + property string caption + property string title + + property int progress: 0 + property int currentSlide: 0 + + function next() { + if (root.currentSlide === (root.progress - 1)) + return + + var index = root.findActive() + var current = root.children[index] + + root.currentSlide++ + + if (current.next()) { + root.caption = current.caption + root.title = current.title + return + } + + root.children[index].init() + root.children[index + 1].activate() + + root.caption = root.children[index + 1].caption + root.title = root.children[index + 1].title + } + + function prev() { + if (root.currentSlide === 0) + return + + var index = root.findActive() + var current = root.children[index] + + root.currentSlide-- + + if (current.prev()) { + root.caption = current.caption + root.title = current.title + return + } + + root.children[index].init() + root.children[index - 1].activate() + root.caption = root.children[index - 1].caption + root.title = root.children[index - 1].title + } + + function findActive() { + for (var i = 0; i < root.children.length; i++) { + var child = root.children[i] + if (child.active) + return i + } + return -1 + } + + Component.onCompleted: { + for (var i = 0; i < root.children.length; i++) { + var child = root.children[i] + child.init() + root.progress += child.states.length + if (i === 0) { + child.visible = true + child.activate() + } + } + + root.caption = root.children[0].caption + root.title = root.children[0].title + } +} diff --git a/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/StrongHighlight.ui.qml b/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/StrongHighlight.ui.qml new file mode 100644 index 0000000000..7b9f315b68 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/StrongHighlight.ui.qml @@ -0,0 +1,107 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick.Controls +import QtQuick.Timeline + +Rectangle { + id: root + width: 600 + height: 600 + radius: 2 + color: "transparent" + border.color: "#1381e3" + border.width: 8 + state: "off" + + property bool active: true + + property color shadowColor: "#aa1b1b1b" + + property int globalX: root.x //200 + property int globalY: root.y //200 + property int parentWidth: root.parent.width //1200 + property int parentHeight: root.parent.height //1200 + + Rectangle { + z: -1 + color: "transparent" + anchors.fill: parent + border.color: root.shadowColor + border.width: 3 + } + + Rectangle { + x: -width + z: -1 + width: root.globalX + height: root.height + color: root.shadowColor + } + + Rectangle { + x: root.width + z: -1 + width: root.parentWidth - root.globalX - root.width + height: root.height + color: root.shadowColor + } + + Rectangle { + x: -root.globalX + y: -root.globalY + z: -1 + width: root.parentWidth + height: root.globalY + color: root.shadowColor + } + + Rectangle { + x: -root.globalX + y: root.height + z: -1 + width: root.parentWidth + height: root.parentHeight - root.globalY - root.height + color: root.shadowColor + } + + states: [ + State { + name: "on" + when: root.active + + PropertyChanges { + target: root + } + }, + State { + name: "off" + when: !root.active + + PropertyChanges { + target: root + opacity: 0 + } + } + ] + + transitions: [ + Transition { + id: transition + to: "*" + from: "*" + ParallelAnimation { + SequentialAnimation { + PauseAnimation { duration: 0 } + + PropertyAnimation { + target: root + property: "opacity" + duration: 150 + } + } + } + } + ] +} diff --git a/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/gradientRect.webp b/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/gradientRect.webp Binary files differnew file mode 100644 index 0000000000..78c2be6dbe --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/gradientRect.webp diff --git a/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/qmldir b/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/qmldir new file mode 100644 index 0000000000..cf5ba7db2f --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/qmldir @@ -0,0 +1,6 @@ +Highlight 1.0 Highlight.ui.qml +StrongHighlight 1.0 StrongHighlight.ui.qml +Slide 1.0 Slide.qml +SlideShow 1.0 SlideShow.qml +SlidePlayer 1.0 SlidePlayer.qml +SlideNavButton 1.0 SlideNavButton.qml diff --git a/share/qtcreator/qmldesigner/welcomepage/imports/WelcomeScreen/Constants.qml b/share/qtcreator/qmldesigner/welcomepage/imports/WelcomeScreen/Constants.qml new file mode 100644 index 0000000000..2e4806cff5 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/imports/WelcomeScreen/Constants.qml @@ -0,0 +1,189 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +pragma Singleton + +import QtQuick +import StudioTheme 1.0 +import projectmodel 1.0 + +QtObject { + id: root + + property int loadingProgress: 100 + readonly property int width: 1842 + readonly property int height: 1080 + property bool communityEdition: projectModel.communityVersion + property bool enterpriseEdition: projectModel.enterpriseVersion + + /* Edit this comment to add your custom font */ + readonly property font font: Qt.font({ + "family": Qt.application.font.family, + "pixelSize": Qt.application.font.pixelSize + }) + readonly property font largeFont: Qt.font({ + "family": Qt.application.font.family, + "pixelSize": Qt.application.font.pixelSize * 1.6 + }) + + readonly property color backgroundColor: "#c2c2c2" + + property var projectModel: ProjectModel {} + + // Responsive grid stuff + readonly property int minColumnCount: 2 + readonly property int minThumbnailSize: 244 + readonly property int gridSpacing: 8 + readonly property int scrollBarWidth: 10 + readonly property int gridMargins: 20 + readonly property int scrollBarTrackSize: 10 + + property int thumbnailSize: root.adaptiveThumbnailSize + property int gridCellSize: root.adaptiveThumbnailSize + root.gridSpacing + property int adaptiveThumbnailSize: root.minThumbnailSize // default to minimum size + + function responsiveResize(width) { + var columnCount = Math.max(Math.floor(width / (root.minThumbnailSize + root.gridSpacing)), + root.minColumnCount) + root.adaptiveThumbnailSize = Math.floor((width + root.gridSpacing) / columnCount - root.gridSpacing) + } + + // Thumbnail margins and sizes + property int thumbnailMargin: 10 + property int imageBottomMargin: 90 + property int titleBackgroundTopMargin: 5 + property int titleHeight: 30 + property int titleHeightMultiline: 52 + property int titleMargin: 5 + + /// THEME + + /// theme selector + property int currentTheme: 0 + property bool defaultBrand: true + property bool basic: true + + /// list view + property bool isListView: false + + /// Current theme - USE THESE IN YOUR PROPERTY BINDINGS! + + /// TRAFFIC LIGHT SYSTEM + property color greenLight: Values.themeGreenLight + property color amberLight: Values.themeAmberLight + property color redLight: Values.themeRedLight + + /// BRAND + property string currentBrand: root.defaultBrand ? root.qdsBrand : root.creatorBrand + + /// TEXT + property color currentGlobalText: Values.themeTextColor + property color currentActiveGlobalText: "#ffffff" + property string brandGlobalText: root.defaultBrand ? root.qdsGlobalText : root.creatorGlobalText + + /// BACKGROUND + property color currentThemeBackground: Values.welcomeScreenBackground + + /// DIALOG + property color currentDialogBackground: Values.themeThumbnailBackground + property color currentDialogBorder: root.currentBrand + + /// BUTTONS + property color currentPushButtonNormalBackground: Values.themeControlBackground + property color currentPushButtonHoverBackground: Values.themeControlBackgroundHover + + property color currentPushButtonNormalOutline: Values.themeControlOutline + property color currentPushButtonHoverOutline: Values.themeControlOutline + + /// THUMBNAILS + property color currentThumbnailGridBackground: Values.themeSubPanelBackground + + property color currentNormalThumbnailBackground: Values.themeThumbnailBackground + property color currentHoverThumbnailBackground: Values.themeControlBackgroundGlobalHover + + property color currentNormalThumbnailLabelBackground: Values.themeThumbnailLabelBackground + property color currentHoverThumbnailLabelBackground: Values.themeControlBackgroundInteraction + + /// TOOLTIP + property color currentToolTipBackground: Values.themeToolTipBackground + property color currentToolTipOutline: Values.themeToolTipOutline + property color currentToolTipText: Values.themeToolTipText + + property color currentScrollBarTrack: Values.themeScrollBarTrack + property color currentScrollBarHandle: Values.themeScrollBarHandle + property color currentScrollBarHandle_idle: Values.themeScrollBarHandle_idle + + /// GLOBAL COLORS + + /// brand + property string creatorBrand: "#54D263" + property string qdsBrand: "#57B9FC" + + + /// DARK THEME COLORS + property string darkBackground: "#242424" + property string modeBarDark: "#414141" + + /// globalText + property string darkGlobalText: "#ffffff" + property string darkActiveGlobalText: "#111111" + property string qdsGlobalText: "#ffffff" + property string creatorGlobalText: "#111111" + + /// button + property string darkPushButtonNormalBackground: "#323232" + property string darkPushButtonNormalOutline: "#000000" + property string darkPushButtonHoverBackground: "#474747" + property string darkPushButtonHoverOutline: "#000000" + + /// thumbnails + property string darkThumbnailGridBackground: "#040404" + property string darkNormalThumbnailBackground: "#292929" + property string darkNormalThumbnailLabelBackground: "#3D3D3D" + property string darkHoverThumbnailBackground: "#323232" + property string darkHoverThumbnailLabelBackground: "#474747" + + + /// MID THEME COLORS + property string midBackground: "#514e48" + property string modeBarMid: "#737068" + + /// globalText + property string midGlobalText: "#ffffff" + property string midActiveGlobalText: "#111111" + + /// button + property string midPushButtonNormalBackground: "#43413c" + property string midPushButtonNormalOutline: "#636058" + property string midPushButtonHoverBackground: "#504D47" + property string midPushButtonHoverOutline: "#737068" + + /// thumbnails + property string midThumbnailGridBackground: "#383732" + property string midNormalThumbnailBackground: "#514e48" + property string midNormalThumbnailLabelBackground: "#43413c" + property string midHoverThumbnailBackground: "#5B5851" + property string midHoverThumbnailLabelBackground: "#43413c" + + + /// LIGHT THEME COLORS + property string lightBackground: "#EAEAEA" + property string modeBarLight: "#D1CFCF" + + /// globalText + property string lightGlobalText: "#111111" + property string lightActiveGlobalText: "#ffffff" + + /// button + property string lightPushButtonNormalBackground: "#eaeaea" + property string lightPushButtonNormalOutline: "#CACECE" + property string lightPushButtonHoverBackground: "#E5E5E5" + property string lightPushButtonHoverOutline: "#CACECE" + + /// thumbnails + property string lightThumbnailGridBackground: "#EFEFEF" + property string lightNormalThumbnailBackground: "#F2F2F2" + property string lightNormalThumbnailLabelBackground: "#EBEBEB" + property string lightHoverThumbnailBackground: "#EAEAEA" + property string lightHoverThumbnailLabelBackground: "#E1E1E1" +} diff --git a/share/qtcreator/qmldesigner/welcomepage/imports/WelcomeScreen/designer/plugin.metainfo b/share/qtcreator/qmldesigner/welcomepage/imports/WelcomeScreen/designer/plugin.metainfo new file mode 100644 index 0000000000..680b425c54 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/imports/WelcomeScreen/designer/plugin.metainfo @@ -0,0 +1,13 @@ +MetaInfo { + Type { + name: "WelcomeScreen.EventListSimulator" + icon: ":/qtquickplugin/images/item-icon16.png" + + Hints { + visibleInNavigator: true + canBeDroppedInNavigator: true + canBeDroppedInFormEditor: false + canBeDroppedInView3D: false + } + } +} diff --git a/share/qtcreator/qmldesigner/welcomepage/imports/WelcomeScreen/qmldir b/share/qtcreator/qmldesigner/welcomepage/imports/WelcomeScreen/qmldir new file mode 100644 index 0000000000..6984623730 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/imports/WelcomeScreen/qmldir @@ -0,0 +1,2 @@ +singleton Constants 1.0 Constants.qml +EventListSimulator 1.0 EventListSimulator.qml diff --git a/share/qtcreator/qmldesigner/welcomepage/main.qml b/share/qtcreator/qmldesigner/welcomepage/main.qml new file mode 100644 index 0000000000..d76567b035 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/main.qml @@ -0,0 +1,22 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import WelcomeScreen 1.0 + +Loader { + id: loader + asynchronous: false + source: "MainScreen.qml" + + property int loadingProgress: 50 + + onLoadingProgressChanged: { + Constants.loadingProgress = loader.loadingProgress + } + + Rectangle { + anchors.fill: parent + color: Constants.currentThemeBackground + } +} diff --git a/share/qtcreator/qmldesigner/welcomepage/main.qml.qml b/share/qtcreator/qmldesigner/welcomepage/main.qml.qml new file mode 100644 index 0000000000..fdd65d5fb0 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/main.qml.qml @@ -0,0 +1,10 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick + +MainScreen { + color: "#ffffff" + border.color: "#ffffff" + +} diff --git a/share/qtcreator/qmldesigner/welcomepage/mockData/ExampleCheckout/FileDownloader.qml b/share/qtcreator/qmldesigner/welcomepage/mockData/ExampleCheckout/FileDownloader.qml new file mode 100644 index 0000000000..28801f7597 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/mockData/ExampleCheckout/FileDownloader.qml @@ -0,0 +1,16 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick 2.0 + +QtObject { + property url url + property bool finished + property bool error + property string name + property string completeBaseName + property int progress + property string outputFile + property date lastModified + property bool available +} diff --git a/share/qtcreator/qmldesigner/welcomepage/mockData/ExampleCheckout/FileExtractor.qml b/share/qtcreator/qmldesigner/welcomepage/mockData/ExampleCheckout/FileExtractor.qml new file mode 100644 index 0000000000..ab6ea047fe --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/mockData/ExampleCheckout/FileExtractor.qml @@ -0,0 +1,21 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick 2.0 + +QtObject { + + property string targetPath + property string archiveName + property string detailedText + property string currentFile + property string size + property string count + property string sourceFile + + property bool finished + property bool targetFolderExists + + property int progress + property date birthTime +} diff --git a/share/qtcreator/qmldesigner/welcomepage/mockData/ExampleCheckout/qmldir b/share/qtcreator/qmldesigner/welcomepage/mockData/ExampleCheckout/qmldir new file mode 100644 index 0000000000..d4bbe25310 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/mockData/ExampleCheckout/qmldir @@ -0,0 +1,2 @@ +FileExtractor 1.0 FileExtractor.qml +FileDownloader 1.0 FileDownloader.qml diff --git a/share/qtcreator/qmldesigner/welcomepage/mockData/projectmodel/ProjectModel.qml b/share/qtcreator/qmldesigner/welcomepage/mockData/projectmodel/ProjectModel.qml new file mode 100644 index 0000000000..dc083056dc --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/mockData/projectmodel/ProjectModel.qml @@ -0,0 +1,117 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick + +ListModel { + property bool communityVersion: true + property bool designMode: true + + ListElement { + displayName: "Project 01" + prettyFilePath: "my_file_1" + thumbnail: "images/thumbnail_test.png" + } + + ListElement { + displayName: "Project 02" + prettyFilePath: "my_file_2" + thumbnail: "images/thumbnail_test.png" + } + + ListElement { + displayName: "Project 03" + prettyFilePath: "my_file_3" + thumbnail: "images/thumbnail_test.png" + } + + ListElement { + displayName: "Project 04" + prettyFilePath: "my_file_4" + thumbnail: "images/thumbnail_test.png" + } + + ListElement { + displayName: "Project 05" + prettyFilePath: "my_file_5" + thumbnail: "images/thumbnail_test.png" + } + + ListElement { + displayName: "Project 06" + prettyFilePath: "my_file_6" + thumbnail: "images/thumbnail_test.png" + } + + ListElement { + displayName: "Project 07" + prettyFilePath: "my_file_7" + thumbnail: "images/thumbnail_test.png" + } + + ListElement { + displayName: "Project 08" + filename: "my_file_8" + thumbnail: "images/thumbnail_test.png" + } + + ListElement { + displayName: "Project 09" + filename: "my_file_9" + thumbnail: "images/thumbnail_test.png" + } + + ListElement { + displayName: "Project 10" + prettyFilePath: "my_file_10" + thumbnail: "images/thumbnail_test.png" + } + + ListElement { + displayName: "Project 11" + filename: "my_file_11" + thumbnail: "images/thumbnail_test.png" + } + + ListElement { + displayName: "Project 12" + prettyFilePath: "my_file_12" + thumbnail: "images/thumbnail_test.png" + } + + ListElement { + displayName: "Project 13" + filename: "my_file_13" + thumbnail: "images/thumbnail_test.png" + } + + ListElement { + displayName: "Project 14" + prettyFilePath: "my_file_14" + thumbnail: "images/thumbnail_test.png" + } + + ListElement { + displayName: "Project 15" + filename: "my_file_15" + thumbnail: "images/thumbnail_test.png" + } + + ListElement { + displayName: "Project 16" + filename: "my_file_16" + thumbnail: "images/thumbnail_test.png" + } + + ListElement { + displayName: "Project 17" + filename: "my_file_17" + thumbnail: "images/thumbnail_test.png" + } + + ListElement { + displayName: "Project 18" + prettyFilePath: "my_file_18" + thumbnail: "images/thumbnail_test.png" + } +} diff --git a/share/qtcreator/qmldesigner/welcomepage/mockData/projectmodel/qmldir b/share/qtcreator/qmldesigner/welcomepage/mockData/projectmodel/qmldir new file mode 100644 index 0000000000..0d7bc345c2 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/mockData/projectmodel/qmldir @@ -0,0 +1 @@ +ProjectModel 1.0 ProjectModel.qml diff --git a/share/qtcreator/qmldesigner/welcomepage/mockData/usagestatistics/UsageStatisticModel.qml b/share/qtcreator/qmldesigner/welcomepage/mockData/usagestatistics/UsageStatisticModel.qml new file mode 100644 index 0000000000..583f80b690 --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/mockData/usagestatistics/UsageStatisticModel.qml @@ -0,0 +1,8 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick + +QtObject { + property bool usageStatisticEnabled: false +} diff --git a/share/qtcreator/qmldesigner/welcomepage/mockData/usagestatistics/qmldir b/share/qtcreator/qmldesigner/welcomepage/mockData/usagestatistics/qmldir new file mode 100644 index 0000000000..c83a43a8ae --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/mockData/usagestatistics/qmldir @@ -0,0 +1 @@ +UsageStatisticModel 1.0 UsageStatisticModel.qml diff --git a/share/qtcreator/qmldesigner/welcomepage/qtquickcontrols2.conf b/share/qtcreator/qmldesigner/welcomepage/qtquickcontrols2.conf new file mode 100644 index 0000000000..db9486764e --- /dev/null +++ b/share/qtcreator/qmldesigner/welcomepage/qtquickcontrols2.conf @@ -0,0 +1,2 @@ +[Controls] +Style=Basic diff --git a/share/qtcreator/qmldesigner/workspacePresets/Advanced-3D.wrk b/share/qtcreator/qmldesigner/workspacePresets/Advanced-3D.wrk index 24eace89b8..f7f232dc60 100644 --- a/share/qtcreator/qmldesigner/workspacePresets/Advanced-3D.wrk +++ b/share/qtcreator/qmldesigner/workspacePresets/Advanced-3D.wrk @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<QtAdvancedDockingSystem version="1" userVersion="0" containers="1" displayName="3D Advanced"> +<QtAdvancedDockingSystem version="1" userVersion="0" containers="1" displayName="3D Advanced" mcusEnabled="false"> <container floating="false"> <splitter orientation="Vertical" count="2"> <splitter orientation="Horizontal" count="3"> diff --git a/share/qtcreator/qmldesigner/workspacePresets/Animation-2D.wrk b/share/qtcreator/qmldesigner/workspacePresets/Animation-2D.wrk index 346856dd50..c7045549fc 100644 --- a/share/qtcreator/qmldesigner/workspacePresets/Animation-2D.wrk +++ b/share/qtcreator/qmldesigner/workspacePresets/Animation-2D.wrk @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<QtAdvancedDockingSystem version="1" userVersion="0" containers="1" displayName="2D Animation"> +<QtAdvancedDockingSystem version="1" userVersion="0" containers="1" displayName="2D Animation" mcusEnabled="true"> <container floating="false"> <splitter orientation="Vertical" count="2"> <splitter orientation="Horizontal" count="3"> diff --git a/share/qtcreator/qmldesigner/workspacePresets/Animation-3D.wrk b/share/qtcreator/qmldesigner/workspacePresets/Animation-3D.wrk index 8f1d59119c..2481c365b9 100644 --- a/share/qtcreator/qmldesigner/workspacePresets/Animation-3D.wrk +++ b/share/qtcreator/qmldesigner/workspacePresets/Animation-3D.wrk @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<QtAdvancedDockingSystem version="1" userVersion="0" containers="1" displayName="3D Animation"> +<QtAdvancedDockingSystem version="1" userVersion="0" containers="1" displayName="3D Animation" mcusEnabled="false"> <container floating="false"> <splitter orientation="Horizontal" count="2"> <splitter orientation="Vertical" count="2"> diff --git a/share/qtcreator/qmldesigner/workspacePresets/Basic.wrk b/share/qtcreator/qmldesigner/workspacePresets/Basic.wrk index b1edb18677..ca1ef34110 100644 --- a/share/qtcreator/qmldesigner/workspacePresets/Basic.wrk +++ b/share/qtcreator/qmldesigner/workspacePresets/Basic.wrk @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<QtAdvancedDockingSystem version="1" userVersion="0" containers="1" displayName="Default"> +<QtAdvancedDockingSystem version="1" userVersion="0" containers="1" displayName="Default" mcusEnabled="true"> <container floating="false"> <splitter orientation="Horizontal" count="3"> <splitter orientation="Vertical" count="3"> diff --git a/share/qtcreator/qmldesigner/workspacePresets/Code.wrk b/share/qtcreator/qmldesigner/workspacePresets/Code.wrk index 82f734432f..828b930c5f 100644 --- a/share/qtcreator/qmldesigner/workspacePresets/Code.wrk +++ b/share/qtcreator/qmldesigner/workspacePresets/Code.wrk @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<QtAdvancedDockingSystem version="1" userVersion="0" containers="1" displayName="Code"> +<QtAdvancedDockingSystem version="1" userVersion="0" containers="1" displayName="Code" mcusEnabled="true"> <container floating="false"> <splitter orientation="Horizontal" count="3"> <splitter orientation="Vertical" count="3"> diff --git a/share/qtcreator/qmldesigner/workspacePresets/Essentials-3D.wrk b/share/qtcreator/qmldesigner/workspacePresets/Essentials-3D.wrk index 74215ffd45..2117c61db0 100644 --- a/share/qtcreator/qmldesigner/workspacePresets/Essentials-3D.wrk +++ b/share/qtcreator/qmldesigner/workspacePresets/Essentials-3D.wrk @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<QtAdvancedDockingSystem version="1" userVersion="0" containers="1" displayName="3D Essentials"> +<QtAdvancedDockingSystem version="1" userVersion="0" containers="1" displayName="3D Essentials" mcusEnabled="false"> <container floating="false"> <splitter orientation="Horizontal" count="3"> <splitter orientation="Vertical" count="3"> diff --git a/share/qtcreator/qmldesigner/workspacePresets/Essentials.wrk b/share/qtcreator/qmldesigner/workspacePresets/Essentials.wrk index e11f39ec94..c71b377d8c 100644 --- a/share/qtcreator/qmldesigner/workspacePresets/Essentials.wrk +++ b/share/qtcreator/qmldesigner/workspacePresets/Essentials.wrk @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<QtAdvancedDockingSystem version="1" containers="1" displayName="Essentials"> +<QtAdvancedDockingSystem version="1" containers="1" displayName="Essentials" mcusEnabled="true"> <container floating="false"> <splitter orientation="Horizontal" count="3"> <splitter orientation="Vertical" count="3"> diff --git a/share/qtcreator/qmldesigner/workspacePresets/UX-Design.wrk b/share/qtcreator/qmldesigner/workspacePresets/UX-Design.wrk index 5e97336662..f6c1329a7d 100644 --- a/share/qtcreator/qmldesigner/workspacePresets/UX-Design.wrk +++ b/share/qtcreator/qmldesigner/workspacePresets/UX-Design.wrk @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<QtAdvancedDockingSystem version="1" userVersion="0" containers="1" displayName="Design"> +<QtAdvancedDockingSystem version="1" userVersion="0" containers="1" displayName="Design" mcusEnabled="true"> <container floating="false"> <splitter orientation="Vertical" count="2"> <splitter orientation="Horizontal" count="3"> diff --git a/share/qtcreator/qmldesigner/workspacePresets/Views-All.wrk b/share/qtcreator/qmldesigner/workspacePresets/Views-All.wrk index 6dc9548347..011ead83a6 100644 --- a/share/qtcreator/qmldesigner/workspacePresets/Views-All.wrk +++ b/share/qtcreator/qmldesigner/workspacePresets/Views-All.wrk @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<QtAdvancedDockingSystem version="1" userVersion="0" containers="2" displayName="All Views"> +<QtAdvancedDockingSystem version="1" userVersion="0" containers="2" displayName="All Views" mcusEnabled="false"> <container floating="false"> <splitter orientation="Horizontal" count="3"> <splitter orientation="Vertical" count="3"> diff --git a/src/libs/advanceddockingsystem/dockmanager.cpp b/src/libs/advanceddockingsystem/dockmanager.cpp index 5cae131fac..b718302f4c 100644 --- a/src/libs/advanceddockingsystem/dockmanager.cpp +++ b/src/libs/advanceddockingsystem/dockmanager.cpp @@ -1578,6 +1578,55 @@ bool DockManager::writeDisplayName(const FilePath &filePath, const QString &disp return true; } +QString DockManager::readMcusEnabled(const FilePath &filePath) +{ + auto data = loadFile(filePath); + + if (data.isEmpty()) + return {}; + + auto tmp = data.startsWith("<?xml") ? data : qUncompress(data); + + DockingStateReader reader(tmp); + if (!reader.readNextStartElement()) + return {}; + + if (reader.name() != QLatin1String("QtAdvancedDockingSystem")) + return {}; + + return reader.attributes().value(workspaceMcusEnabledAttribute.toString()).toString(); +} + +bool DockManager::writeMcusEnabled(const FilePath &filePath, const QString &mcusEnabled) +{ + const expected_str<QByteArray> content = filePath.fileContents(); + + QTC_ASSERT_EXPECTED(content, return false); + + QDomDocument doc; + QString error_msg; + int error_line, error_col; + if (!doc.setContent(*content, &error_msg, &error_line, &error_col)) { + qWarning() << QString("XML error on line %1, col %2: %3") + .arg(error_line) + .arg(error_col) + .arg(error_msg); + return false; + } + + QDomElement docElem = doc.documentElement(); + docElem.setAttribute(workspaceMcusEnabledAttribute.toString(), mcusEnabled); + + const expected_str<void> result = write(filePath, doc.toByteArray(workspaceXmlFormattingIndent)); + if (!result) { + qWarning() << "Could not write mcusEnabled" << mcusEnabled << "to" << filePath << ":" + << result.error(); + return false; + } + + return true; +} + expected_str<void> DockManager::write(const FilePath &filePath, const QByteArray &data) { qCInfo(adsLog) << "Write" << filePath; @@ -1638,6 +1687,11 @@ void DockManager::syncWorkspacePresets() const QString name = readDisplayName(userFile); if (name.isEmpty()) writeDisplayName(userFile, name); + + const QString presetMcusEnabled = readMcusEnabled(filePath); + const QString mcusEnabled = readMcusEnabled(userFile); + if (mcusEnabled.isEmpty() || mcusEnabled != presetMcusEnabled) + writeMcusEnabled(userFile, presetMcusEnabled); } continue; @@ -1694,4 +1748,12 @@ void DockManager::saveLockWorkspace() d->m_settings->setValue(Constants::LOCK_WORKSPACE_SETTINGS_KEY, d->m_workspaceLocked); } +void DockManager::setMcusProject(bool value) { + m_mcusProject = value; +} + +bool DockManager::mcusProject() const { + return m_mcusProject; +} + } // namespace ADS diff --git a/src/libs/advanceddockingsystem/dockmanager.h b/src/libs/advanceddockingsystem/dockmanager.h index 53117b93e6..23aa21a578 100644 --- a/src/libs/advanceddockingsystem/dockmanager.h +++ b/src/libs/advanceddockingsystem/dockmanager.h @@ -57,6 +57,7 @@ inline constexpr QStringView workspaceFolderName{u"workspaces"}; inline constexpr QStringView workspaceFileExtension{u"wrk"}; inline constexpr QStringView workspaceOrderFileName{u"order.json"}; inline constexpr QStringView workspaceDisplayNameAttribute{u"displayName"}; +inline constexpr QStringView workspaceMcusEnabledAttribute{u"mcusEnabled"}; inline const int workspaceXmlFormattingIndent = 2; /** @@ -760,6 +761,8 @@ public: static QByteArray loadFile(const Utils::FilePath &filePath); static QString readDisplayName(const Utils::FilePath &filePath); static bool writeDisplayName(const Utils::FilePath &filePath, const QString &displayName); + static QString readMcusEnabled(const Utils::FilePath &filePath); + static bool writeMcusEnabled(const Utils::FilePath &filePath, const QString &mcusEnabled); /** * This is used to limit saving of workspaces to only when they were actually presented ones, @@ -768,6 +771,9 @@ public: */ void aboutToShow(); + void setMcusProject(bool value); + bool mcusProject() const; + signals: void aboutToUnloadWorkspace(QString fileName); void aboutToLoadWorkspace(QString fileName); @@ -789,6 +795,8 @@ private: void saveStartupWorkspace(); void saveLockWorkspace(); + + bool m_mcusProject = false; }; // class DockManager } // namespace ADS diff --git a/src/libs/advanceddockingsystem/workspace.cpp b/src/libs/advanceddockingsystem/workspace.cpp index d3b0785d90..8022b36f17 100644 --- a/src/libs/advanceddockingsystem/workspace.cpp +++ b/src/libs/advanceddockingsystem/workspace.cpp @@ -28,6 +28,12 @@ Workspace::Workspace(const Utils::FilePath &filePath, bool isPreset) } else { m_name = name; } + + QString mcusEnabled = DockManager::readMcusEnabled(m_filePath); + if (mcusEnabled.isEmpty()) + setMcusEnabled(true); + else + m_mcusEnabled = QVariant::fromValue(mcusEnabled).toBool(); } void Workspace::setName(const QString &name) @@ -84,6 +90,18 @@ bool Workspace::isPreset() const return m_preset; } +void Workspace::setMcusEnabled(bool enabled) +{ + QString mcusEnabled = QVariant::fromValue(enabled).toString(); + if (DockManager::writeMcusEnabled(filePath(), mcusEnabled)) + m_mcusEnabled = enabled; +} + +bool Workspace::isMcusEnabled() const +{ + return m_mcusEnabled; +} + Workspace::operator QString() const { return QString("Workspace %1 Preset[%2] %3") diff --git a/src/libs/advanceddockingsystem/workspace.h b/src/libs/advanceddockingsystem/workspace.h index c23db55d6b..e89edb5539 100644 --- a/src/libs/advanceddockingsystem/workspace.h +++ b/src/libs/advanceddockingsystem/workspace.h @@ -30,6 +30,9 @@ public: void setPreset(bool value); bool isPreset() const; + void setMcusEnabled(bool value); + bool isMcusEnabled() const; + friend bool operator==(const Workspace &a, const Workspace &b) { return a.fileName() == b.fileName(); @@ -50,6 +53,7 @@ private: QString m_name; Utils::FilePath m_filePath; bool m_preset = false; + bool m_mcusEnabled = true; }; } // namespace ADS diff --git a/src/libs/advanceddockingsystem/workspacemodel.cpp b/src/libs/advanceddockingsystem/workspacemodel.cpp index 99d3bd1473..2748d85fc6 100644 --- a/src/libs/advanceddockingsystem/workspacemodel.cpp +++ b/src/libs/advanceddockingsystem/workspacemodel.cpp @@ -22,7 +22,7 @@ WorkspaceModel::WorkspaceModel(DockManager *manager, QObject *parent) connect(m_manager, &DockManager::workspaceLoaded, this, &WorkspaceModel::resetWorkspaces); } -int WorkspaceModel::indexOfWorkspace(const QString &fileName) +int WorkspaceModel::indexOfWorkspace(const QString &fileName) const { return m_manager->workspaceIndex(fileName); } @@ -134,6 +134,10 @@ Qt::ItemFlags WorkspaceModel::flags(const QModelIndex &index) const { Qt::ItemFlags defaultFlags = QAbstractTableModel::flags(index); + Workspace *workspace = m_manager->workspace(workspaceAt(index.row())); + if (m_manager->mcusProject() && !workspace->isMcusEnabled()) + defaultFlags &= ~Qt::ItemIsEnabled; + if (index.isValid()) return Qt::ItemIsDragEnabled | defaultFlags; diff --git a/src/libs/advanceddockingsystem/workspacemodel.h b/src/libs/advanceddockingsystem/workspacemodel.h index fe868f71f5..2d6e0ef16b 100644 --- a/src/libs/advanceddockingsystem/workspacemodel.h +++ b/src/libs/advanceddockingsystem/workspacemodel.h @@ -21,7 +21,7 @@ public: explicit WorkspaceModel(DockManager *manager, QObject *parent = nullptr); - int indexOfWorkspace(const QString &fileName); + int indexOfWorkspace(const QString &fileName) const; QString workspaceAt(int row) const; int rowCount(const QModelIndex &parent = QModelIndex()) const override; diff --git a/src/libs/qmljs/qmljsinterpreter.h b/src/libs/qmljs/qmljsinterpreter.h index 3fcce78d11..8651196aef 100644 --- a/src/libs/qmljs/qmljsinterpreter.h +++ b/src/libs/qmljs/qmljsinterpreter.h @@ -1127,6 +1127,11 @@ public: [[maybe_unused]] const Document *context, [[maybe_unused]] ValueOwner *valueOwner, [[maybe_unused]] Snapshot *snapshot) {} + virtual Utils::FilePaths prioritizeImportPaths([[maybe_unused]] const Document *context, + const Utils::FilePaths &importPaths) + { + return importPaths; + } }; } // namespace QmlJS diff --git a/src/libs/qmljs/qmljslink.cpp b/src/libs/qmljs/qmljslink.cpp index b837037b7c..97c00e1c8d 100644 --- a/src/libs/qmljs/qmljslink.cpp +++ b/src/libs/qmljs/qmljslink.cpp @@ -219,6 +219,7 @@ Context::ImportsPerDocument LinkPrivate::linkImports() document.data(), m_valueOwner, &m_snapshot); + m_importPaths = provider->prioritizeImportPaths(document.data(), m_importPaths); } populateImportedTypes(imports, document); diff --git a/src/plugins/clangformat/clangformatbaseindenter.cpp b/src/plugins/clangformat/clangformatbaseindenter.cpp index ac788c8a4b..dbbacd48a9 100644 --- a/src/plugins/clangformat/clangformatbaseindenter.cpp +++ b/src/plugins/clangformat/clangformatbaseindenter.cpp @@ -389,6 +389,7 @@ Utils::ChangeSet convertReplacements(const QTextDocument *doc, .size(); QString replacementText = QString::fromStdString(replacement.getReplacementText().str()); + replacementText.replace("\r", ""); auto sameCharAt = [&](int replacementOffset) { if (replacementText.size() <= replacementOffset || replacementOffset < 0) return false; diff --git a/src/plugins/cppeditor/cpptoolsreuse.cpp b/src/plugins/cppeditor/cpptoolsreuse.cpp index c8ce0effea..d7e403a1cc 100644 --- a/src/plugins/cppeditor/cpptoolsreuse.cpp +++ b/src/plugins/cppeditor/cpptoolsreuse.cpp @@ -786,6 +786,7 @@ SearchResultItems symbolOccurrencesInDeclarationComments( QList<Text::Range> symbolOccurrencesInText(const QTextDocument &doc, QStringView text, int offset, const QString &symbolName) { + QTC_ASSERT(!symbolName.isEmpty(), return QList<Text::Range>()); QList<Text::Range> ranges; int index = 0; while (true) { diff --git a/src/plugins/effectmakernew/compositionnode.cpp b/src/plugins/effectmakernew/compositionnode.cpp index 9412153dde..811cdbcb8f 100644 --- a/src/plugins/effectmakernew/compositionnode.cpp +++ b/src/plugins/effectmakernew/compositionnode.cpp @@ -113,6 +113,9 @@ void CompositionNode::parse(const QString &effectName, const QString &qenPath, c m_fragmentCode = EffectUtils::codeFromJsonArray(json.value("fragmentCode").toArray()); m_vertexCode = EffectUtils::codeFromJsonArray(json.value("vertexCode").toArray()); + if (json.contains("enabled")) + m_isEnabled = json["enabled"].toBool(); + m_id = json.value("id").toString(); if (m_id.isEmpty() && !qenPath.isEmpty()) { QString fileName = qenPath.split('/').last(); diff --git a/src/plugins/effectmakernew/effectmakermodel.cpp b/src/plugins/effectmakernew/effectmakermodel.cpp index 4fcb6686a7..dc71418f1d 100644 --- a/src/plugins/effectmakernew/effectmakermodel.cpp +++ b/src/plugins/effectmakernew/effectmakermodel.cpp @@ -87,6 +87,7 @@ bool EffectMakerModel::setData(const QModelIndex &index, const QVariant &value, if (role == EnabledRole) { m_nodes.at(index.row())->setIsEnabled(value.toBool()); bakeShaders(); + setHasUnsavedChanges(true); emit dataChanged(index, index, {role}); } @@ -192,14 +193,17 @@ void EffectMakerModel::removeNode(int idx) emit nodesChanged(); } -void EffectMakerModel::clear() +void EffectMakerModel::clear(bool clearName) { beginResetModel(); qDeleteAll(m_nodes); m_nodes.clear(); endResetModel(); + + if (clearName) + setCurrentComposition(""); + setHasUnsavedChanges(!m_currentComposition.isEmpty()); - setCurrentComposition(""); setIsEmpty(true); emit nodesChanged(); @@ -413,6 +417,7 @@ void EffectMakerModel::setEffectError(const QString &errorMessage, int type, int QString additionalErrorInfo = detectErrorMessage(errorMessage); error.m_message = additionalErrorInfo + errorMessage; m_effectErrors.insert(type, error); + qWarning() << QString("Effect error (line: %2): %1").arg(error.m_message, error.m_line); Q_EMIT effectErrorChanged(); } @@ -556,13 +561,23 @@ QString EffectMakerModel::getQmlEffectString() { QString s; - s += QString("// Created with Qt Design Studio (version %1), %2\n\n") - .arg(qApp->applicationVersion(), QDateTime::currentDateTime().toString()); - s += "import QtQuick\n"; - s += '\n'; - s += "Item {\n"; - s += " id: rootItem\n"; - s += '\n'; + // _isEffectItem is type var to hide it from property view + QString header{ +R"( +// Created with Qt Design Studio (version %1), %2 + +import QtQuick + +Item { + id: rootItem + + property var _isEffectItem + property Item _oldParent: null +)" + }; + + s += header.arg(qApp->applicationVersion(), QDateTime::currentDateTime().toString()); + if (m_shaderFeatures.enabled(ShaderFeatures::Source)) { s += " // This is the main source for the effect\n"; s += " property Item source: null\n"; @@ -570,7 +585,7 @@ QString EffectMakerModel::getQmlEffectString() if (m_shaderFeatures.enabled(ShaderFeatures::Time) || m_shaderFeatures.enabled(ShaderFeatures::Frame)) { s += " // Enable this to animate iTime property\n"; - s += " property bool timeRunning: false\n"; + s += " property bool timeRunning: true\n"; } if (m_shaderFeatures.enabled(ShaderFeatures::Time)) { s += " // When timeRunning is false, this can be used to control iTime manually\n"; @@ -580,7 +595,33 @@ QString EffectMakerModel::getQmlEffectString() s += " // When timeRunning is false, this can be used to control iFrame manually\n"; s += " property int animatedFrame: frameAnimation.currentFrame\n"; } - s += '\n'; + + QString parentChanged{ +R"( + onParentChanged: { + if (_oldParent && _oldParent !== parent) { + _oldParent.layer.enabled = false + _oldParent.layer.effect = null + %2 + _oldParent.update() + _oldParent = null + } + if (parent) { + _oldParent = parent + parent.layer.enabled = true + parent.layer.effect = effectComponent + %1 + } + } +)" + }; + + parentChanged = parentChanged.arg(m_shaderFeatures.enabled(ShaderFeatures::Source) + ? QString("source = parent") : QString(), + m_shaderFeatures.enabled(ShaderFeatures::Source) + ? QString("source = null") : QString()); + s += parentChanged; + // Custom properties if (!m_exportedRootPropertiesString.isEmpty()) { s += m_exportedRootPropertiesString; @@ -595,19 +636,14 @@ QString EffectMakerModel::getQmlEffectString() s += '\n'; } - if (m_shaderFeatures.enabled(ShaderFeatures::BlurSources)) { - s += " BlurHelper {\n"; - s += " id: blurHelper\n"; - s += " anchors.fill: parent\n"; - int blurMax = 32; - if (g_propertyData.contains("BLUR_HELPER_MAX_LEVEL")) - blurMax = g_propertyData["BLUR_HELPER_MAX_LEVEL"].toInt(); - s += QString(" property int blurMax: %1\n").arg(blurMax); - s += " property real blurMultiplier: rootItem.blurMultiplier\n"; - s += " }\n"; - } + QString customImagesString = getQmlImagesString(true); + if (!customImagesString.isEmpty()) + s += customImagesString; + s += " Component {\n"; + s += " id: effectComponent\n"; s += getQmlComponentString(true); + s += " }\n"; s += "}\n"; return s; } @@ -651,7 +687,7 @@ void EffectMakerModel::saveComposition(const QString &name) void EffectMakerModel::openComposition(const QString &path) { - clear(); + clear(true); const QString effectName = QFileInfo(path).baseName(); setCurrentComposition(effectName); @@ -785,10 +821,10 @@ void EffectMakerModel::saveResources(const QString &name) for (int i = 1; i < qmlStringList.size(); i++) { QString line = qmlStringList.at(i).trimmed(); if (line.startsWith("vertexShader")) { - QString vsLine = " vertexShader: '" + vsFilename + "'"; + QString vsLine = " vertexShader: '" + vsFilename + "'"; qmlStringList[i] = vsLine; } else if (line.startsWith("fragmentShader")) { - QString fsLine = " fragmentShader: '" + fsFilename + "'"; + QString fsLine = " fragmentShader: '" + fsFilename + "'"; qmlStringList[i] = fsLine; } } @@ -1287,17 +1323,17 @@ void EffectMakerModel::updateCustomUniforms() if (!uniform->description().isEmpty()) { const QStringList descriptionLines = uniform->description().split('\n'); for (const QString &line : descriptionLines) - exportedEffectPropertiesString += QStringLiteral(" // ") + line + '\n'; + exportedEffectPropertiesString += QStringLiteral(" // ") + line + '\n'; } - exportedEffectPropertiesString += QStringLiteral(" ") + readOnly + exportedEffectPropertiesString += QStringLiteral(" ") + readOnly + "property " + propertyType + " " + propertyName + boundValueString + '\n'; } else { // Custom values are not added into root exportedRootPropertiesString += " property " + propertyType + " " + propertyName + valueString + '\n'; - exportedEffectPropertiesString += QStringLiteral(" ") - + readOnly + "property alias " + propertyName + exportedEffectPropertiesString += QStringLiteral(" ") + + readOnly + "property " + propertyType + " " + propertyName + ": rootItem." + uniform->name() + '\n'; } } @@ -1488,22 +1524,26 @@ QString EffectMakerModel::getQmlComponentString(bool localFiles) { if (localFiles) { const QString parent = blurHelper ? QString("blurHelper.") : QString("rootItem."); - return QString("readonly property alias %1: %2%3\n").arg(name, parent, var); + return QString("readonly property %1 %2: %3%4\n").arg(type, name, parent, var); } else { const QString parent = blurHelper ? "blurHelper." : QString(); return QString("readonly property %1 %2: %3%4\n").arg(type, name, parent, var); } }; - QString customImagesString = getQmlImagesString(localFiles); QString s; - QString l1 = localFiles ? QStringLiteral(" ") : QStringLiteral(""); - QString l2 = localFiles ? QStringLiteral(" ") : QStringLiteral(" "); - QString l3 = localFiles ? QStringLiteral(" ") : QStringLiteral(" "); + QString l1 = localFiles ? QStringLiteral(" ") : QStringLiteral(""); + QString l2 = localFiles ? QStringLiteral(" ") : QStringLiteral(" "); + QString l3 = localFiles ? QStringLiteral(" ") : QStringLiteral(" "); if (!localFiles) s += "import QtQuick\n"; s += l1 + "ShaderEffect {\n"; + + if (localFiles) { + // Explicit "source" property is required for render puppet to detect effect correctly + s += l2 + "property Item source: null\n"; + } if (m_shaderFeatures.enabled(ShaderFeatures::Source)) s += l2 + addProperty("iSource", "source", "Item"); if (m_shaderFeatures.enabled(ShaderFeatures::Time)) @@ -1529,15 +1569,18 @@ QString EffectMakerModel::getQmlComponentString(bool localFiles) // and when in exported component, property with binding to root value. s += localFiles ? m_exportedEffectPropertiesString : m_previewEffectPropertiesString; - if (!customImagesString.isEmpty()) - s += '\n' + customImagesString; + if (!localFiles) { + QString customImagesString = getQmlImagesString(false); + if (!customImagesString.isEmpty()) + s += '\n' + customImagesString; + } s += '\n'; const QString vertFile = localFiles ? m_vertexShaderFilename : m_vertexShaderPreviewFilename; const QString fragFile = localFiles ? m_fragmentShaderFilename : m_fragmentShaderPreviewFilename; s += l2 + "vertexShader: 'file:///" + vertFile + "'\n"; s += l2 + "fragmentShader: 'file:///" + fragFile + "'\n"; - s += l2 + "anchors.fill: parent\n"; + s += l2 + "anchors.fill: " + (localFiles ? "rootItem.source" : "parent") + "\n"; if (m_shaderFeatures.enabled(ShaderFeatures::GridMesh)) { QString gridSize = QString("%1, %2").arg(m_shaderFeatures.gridMeshWidth()) .arg(m_shaderFeatures.gridMeshHeight()); @@ -1545,6 +1588,18 @@ QString EffectMakerModel::getQmlComponentString(bool localFiles) s += l3 + QString("resolution: Qt.size(%1)\n").arg(gridSize); s += l2 + "}\n"; } + if (localFiles && m_shaderFeatures.enabled(ShaderFeatures::BlurSources)) { + s += l2 + "BlurHelper {\n"; + s += l3 + "id: blurHelper\n"; + s += l3 + "source: rootItem.source\n"; + int blurMax = 32; + if (g_propertyData.contains("BLUR_HELPER_MAX_LEVEL")) + blurMax = g_propertyData["BLUR_HELPER_MAX_LEVEL"].toInt(); + s += l3 + QString("property int blurMax: %1\n").arg(blurMax); + s += l3 + "property real blurMultiplier: rootItem.blurMultiplier\n"; + s += l2 + "}\n"; + } + s += l1 + "}\n"; return s; } diff --git a/src/plugins/effectmakernew/effectmakermodel.h b/src/plugins/effectmakernew/effectmakermodel.h index a25a4e4091..1bbac9cd55 100644 --- a/src/plugins/effectmakernew/effectmakermodel.h +++ b/src/plugins/effectmakernew/effectmakermodel.h @@ -66,7 +66,7 @@ public: Q_INVOKABLE void moveNode(int fromIdx, int toIdx); Q_INVOKABLE void removeNode(int idx); - Q_INVOKABLE void clear(); + Q_INVOKABLE void clear(bool clearName = false); Q_INVOKABLE void assignToSelected(); Q_INVOKABLE QString getUniqueEffectName() const; diff --git a/src/plugins/mcusupport/mcusupportimportprovider.cpp b/src/plugins/mcusupport/mcusupportimportprovider.cpp index b78baf8bd9..f83dec6cb7 100644 --- a/src/plugins/mcusupport/mcusupportimportprovider.cpp +++ b/src/plugins/mcusupport/mcusupportimportprovider.cpp @@ -119,6 +119,30 @@ void McuSupportImportProvider::loadBuiltins(ImportsPerDocument *importsPerDocume import.info = ImportInfo::moduleImport("qul", {1, 0}, QString()); getInterfacesImport(context->fileName(), importsPerDocument, import, valueOwner, snapshot); imports->append(import); +} + +FilePaths McuSupportImportProvider::prioritizeImportPaths(const Document *context, + const FilePaths &importPaths) +{ + if (!context) + return importPaths; + const std::optional<FilePath> cmakeFilesPathOpt = getTargetBuildFolder(context->fileName()); + if (!cmakeFilesPathOpt) + return importPaths; + FilePaths ret; + // qmltocpp uses an incomplete QtQuick folder present in the build folder + // to avoid taking precedence over the correct qul_install/include/*/StyleDefault + // move the import path to be last + std::copy_if(importPaths.cbegin(), + importPaths.cend(), + std::back_inserter(ret), + [cmakeFilesPathOpt](const FilePath &path) { return path != *cmakeFilesPathOpt; }); + + // nothing was removed + if (ret.size() == importPaths.size()) + return importPaths; + ret.push_back(*cmakeFilesPathOpt); + return ret; }; void McuSupportImportProvider::getInterfacesImport(const FilePath &path, @@ -156,6 +180,7 @@ std::optional<FilePath> McuSupportImportProvider::getFileModule(const FilePath & const FilePath &inputFile) const { const auto doc = QJsonDocument::fromJson(inputFile.fileContents().value_or("")); + if (!doc.isObject()) return {}; diff --git a/src/plugins/mcusupport/mcusupportimportprovider.h b/src/plugins/mcusupport/mcusupportimportprovider.h index c1a130ed3d..f7457751b0 100644 --- a/src/plugins/mcusupport/mcusupportimportprovider.h +++ b/src/plugins/mcusupport/mcusupportimportprovider.h @@ -29,6 +29,9 @@ public: ValueOwner *valueOwner, Snapshot *snapshot) override; + virtual Utils::FilePaths prioritizeImportPaths(const Document *context, + const Utils::FilePaths &importPaths) override; + // Add to the interfaces needed for a document // path: opened qml document // importsPerDocument: imports available in the document (considered imported) diff --git a/src/plugins/projectexplorer/abi.cpp b/src/plugins/projectexplorer/abi.cpp index 07365fc5dd..d1bd01b89b 100644 --- a/src/plugins/projectexplorer/abi.cpp +++ b/src/plugins/projectexplorer/abi.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "abi.h" +#include "projectexplorerconstants.h" #include <utils/algorithm.h> #include <utils/environment.h> @@ -437,6 +438,18 @@ static Abis abiOf(const QByteArray &data) return result; } +static QString androidAbiFromAbi(const Abi &abi) +{ + QString androidAbi; + if (abi.architecture() == Abi::Architecture::ArmArchitecture) + androidAbi = QLatin1String(abi.wordWidth() == 64 ? Constants::ANDROID_ABI_ARM64_V8A + : Constants::ANDROID_ABI_ARMEABI_V7A); + else + androidAbi = QLatin1String(abi.wordWidth() == 64 ? Constants::ANDROID_ABI_X86_64 + : Constants::ANDROID_ABI_X86); + return androidAbi; +} + // -------------------------------------------------------------------------- // Abi // -------------------------------------------------------------------------- @@ -908,7 +921,11 @@ Abi Abi::fromString(const QString &abiString) return Abi(architecture, os, flavor, format, 0); } - return Abi(architecture, os, flavor, format, wordWidth); + Abi abi(architecture, os, flavor, format, wordWidth); + if (abi.os() == LinuxOS && abi.osFlavor() == AndroidLinuxFlavor) + abi.m_param = androidAbiFromAbi(abi); + + return abi; } Abi::Architecture Abi::architectureFromString(const QString &a) diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index e167a83db3..b13841019c 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -839,7 +839,6 @@ extend_qtc_plugin(QmlDesigner collectiondetailssortfiltermodel.cpp collectiondetailssortfiltermodel.h collectioneditorconstants.h collectioneditorutils.cpp collectioneditorutils.h - collectionimporttools.cpp collectionimporttools.h collectionlistmodel.cpp collectionlistmodel.h collectionsourcemodel.cpp collectionsourcemodel.h collectionview.cpp collectionview.h diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.cpp index 4cc6717d91..90f0061c87 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.cpp @@ -28,7 +28,7 @@ const QMap<DataTypeWarning::Warning, QString> DataTypeWarning::dataTypeWarnings class CollectionDetails::Private { - using SourceFormat = CollectionEditor::SourceFormat; + using SourceFormat = CollectionEditorConstants::SourceFormat; public: QList<CollectionProperty> properties; @@ -85,6 +85,24 @@ static QVariant valueToVariant(const QJsonValue &value, CollectionDetails::DataT } } +static QJsonValue variantToJsonValue(const QVariant &variant) +{ + using VariantType = QVariant::Type; + + switch (variant.type()) { + case VariantType::Bool: + return variant.toBool(); + case VariantType::Double: + case VariantType::Int: + return variant.toDouble(); + case VariantType::String: + case VariantType::Color: + case VariantType::Url: + default: + return variant.toString(); + } +} + CollectionDetails::CollectionDetails() : d(new Private()) {} @@ -101,7 +119,7 @@ CollectionDetails::~CollectionDetails() = default; void CollectionDetails::resetDetails(const QStringList &propertyNames, const QList<QJsonObject> &elements, - CollectionEditor::SourceFormat format) + CollectionEditorConstants::SourceFormat format) { if (!isValid()) return; @@ -238,6 +256,7 @@ bool CollectionDetails::setPropertyValue(int row, int column, const QVariant &va return false; element.insert(d->properties.at(column).name, QJsonValue::fromVariant(value)); + markChanged(); return true; } @@ -277,8 +296,10 @@ bool CollectionDetails::setPropertyType(int column, DataType type) for (QJsonObject &element : d->elements) { if (element.contains(property.name)) { - QJsonValue value = element.value(property.name); - element.insert(property.name, valueToVariant(value, type).toJsonValue()); + const QJsonValue value = element.value(property.name); + const QVariant properTypedValue = valueToVariant(value, type); + const QJsonValue properTypedJsonValue = variantToJsonValue(properTypedValue); + element.insert(property.name, properTypedJsonValue); changed = true; } } @@ -294,7 +315,7 @@ CollectionReference CollectionDetails::reference() const return d->reference; } -CollectionEditor::SourceFormat CollectionDetails::sourceFormat() const +CollectionEditorConstants::SourceFormat CollectionDetails::sourceFormat() const { return d->sourceFormat; } @@ -354,8 +375,10 @@ DataTypeWarning::Warning CollectionDetails::cellWarningCheck(int row, int column const QString &propertyName = d->properties.at(column).name; const QJsonObject &element = d->elements.at(row); - if (element.isEmpty()) + if (typeAt(column) == DataType::Unknown || element.isEmpty() + || data(row, column) == QVariant::fromValue(nullptr)) { return DataTypeWarning::Warning::None; + } if (element.contains(propertyName) && typeAt(column) != typeAt(row, column)) return DataTypeWarning::Warning::CellDataTypeMismatch; @@ -458,16 +481,19 @@ void CollectionDetails::resetPropertyTypes() resetPropertyType(property); } -QString CollectionDetails::getCollectionAsJsonString() const +QJsonArray CollectionDetails::getCollectionAsJsonArray() const { QJsonArray collectionArray; for (const QJsonObject &element : std::as_const(d->elements)) collectionArray.push_back(element); - QString collectionString = QString::fromUtf8(QJsonDocument(collectionArray).toJson()); + return collectionArray; +} - return collectionString; +QString CollectionDetails::getCollectionAsJsonString() const +{ + return QString::fromUtf8(QJsonDocument(getCollectionAsJsonArray()).toJson()); } QString CollectionDetails::getCollectionAsCsvString() const diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.h b/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.h index c35068ce6f..9d8eb7eca0 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.h @@ -70,7 +70,7 @@ public: void resetDetails(const QStringList &propertyNames, const QList<QJsonObject> &elements, - CollectionEditor::SourceFormat format); + CollectionEditorConstants::SourceFormat format); void insertColumn(const QString &propertyName, int colIdx = -1, const QVariant &defaultValue = {}, @@ -86,7 +86,7 @@ public: bool setPropertyType(int column, DataType type); CollectionReference reference() const; - CollectionEditor::SourceFormat sourceFormat() const; + CollectionEditorConstants::SourceFormat sourceFormat() const; QVariant data(int row, int column) const; QString propertyAt(int column) const; DataType typeAt(int column) const; @@ -106,6 +106,8 @@ public: QString getCollectionAsJsonString() const; QString getCollectionAsCsvString() const; + QJsonArray getCollectionAsJsonArray() const; + static void registerDeclarativeType(); CollectionDetails &operator=(const CollectionDetails &other); diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp index 2279b60d13..52d5a6e2ba 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp @@ -7,11 +7,16 @@ #include "collectioneditorutils.h" #include "modelnode.h" +#include <coreplugin/editormanager/editormanager.h> + +#include <utils/fileutils.h> #include <utils/qtcassert.h> +#include <utils/textfileformat.h> #include <QFile> #include <QFileInfo> #include <QJsonArray> +#include <QJsonDocument> #include <QJsonObject> #include <QJsonParseError> @@ -19,17 +24,27 @@ namespace { QStringList getJsonHeaders(const QJsonArray &collectionArray) { - QSet<QString> result; + QSet<QString> resultSet; + QList<QString> result; + for (const QJsonValue &value : collectionArray) { if (value.isObject()) { const QJsonObject object = value.toObject(); - const QStringList headers = object.toVariantMap().keys(); - for (const QString &header : headers) - result.insert(header); + QJsonObject::ConstIterator element = object.constBegin(); + const QJsonObject::ConstIterator stopItem = object.constEnd(); + + while (element != stopItem) { + const QString property = element.key(); + if (!resultSet.contains(property)) { + result.append(property); + resultSet.insert(property); + } + ++element; + } } } - return result.values(); + return result; } class CollectionDataTypeHelper @@ -339,8 +354,10 @@ bool CollectionDetailsModel::setPropertyType(int column, const QString &newValue newValue)); if (changed) { emit headerDataChanged(Qt::Horizontal, column, column); - emit dataChanged(index(0, column), index(rowCount() - 1, column), - {Qt::DisplayRole, DataTypeRole, DataTypeWarningRole}); + emit dataChanged( + index(0, column), + index(rowCount() - 1, column), + {Qt::DisplayRole, Qt::EditRole, DataTypeRole, DataTypeWarningRole, ColumnDataTypeRole}); } return changed; @@ -353,8 +370,8 @@ bool CollectionDetailsModel::selectRow(int row) const int rows = rowCount(); - if (m_selectedRow >= rows) - return false; + if (row >= rows) + row = rows - 1; selectColumn(-1); @@ -388,7 +405,7 @@ QStringList CollectionDetailsModel::typesList() void CollectionDetailsModel::loadCollection(const ModelNode &sourceNode, const QString &collection) { - QString fileName = CollectionEditor::getSourceCollectionPath(sourceNode); + QString fileName = CollectionEditorUtils::getSourceCollectionPath(sourceNode); CollectionReference newReference{sourceNode, collection}; bool alreadyOpen = m_openedCollections.contains(newReference); @@ -403,21 +420,83 @@ void CollectionDetailsModel::loadCollection(const ModelNode &sourceNode, const Q } else { deselectAll(); switchToCollection(newReference); - if (sourceNode.type() == CollectionEditor::JSONCOLLECTIONMODEL_TYPENAME) + if (sourceNode.type() == CollectionEditorConstants::JSONCOLLECTIONMODEL_TYPENAME) loadJsonCollection(fileName, collection); - else if (sourceNode.type() == CollectionEditor::CSVCOLLECTIONMODEL_TYPENAME) + else if (sourceNode.type() == CollectionEditorConstants::CSVCOLLECTIONMODEL_TYPENAME) loadCsvCollection(fileName, collection); } } -bool CollectionDetailsModel::saveCurrentCollection() +bool CollectionDetailsModel::saveDataStoreCollections() { - return saveCollection({}, &m_currentCollection); + const ModelNode node = m_currentCollection.reference().node; + const Utils::FilePath path = CollectionEditorUtils::dataStoreJsonFilePath(); + Utils::FileReader fileData; + Utils::FileSaver sourceFile(path); + + if (!fileData.fetch(path)) { + qWarning() << Q_FUNC_INFO << "Cannot read the json file:" << fileData.errorString(); + return false; + } + + QJsonParseError jpe; + QJsonDocument document = QJsonDocument::fromJson(fileData.data(), &jpe); + + if (jpe.error == QJsonParseError::NoError) { + QJsonObject obj = document.object(); + + QList<CollectionDetails> collectionsToBeSaved; + for (CollectionDetails &openedCollection : m_openedCollections) { + const CollectionReference reference = openedCollection.reference(); + if (reference.node == node) { + obj.insert(reference.name, openedCollection.getCollectionAsJsonArray()); + collectionsToBeSaved << openedCollection; + } + } + + document.setObject(obj); + bool saved = sourceFile.write(document.toJson()); + saved &= sourceFile.finalize(); + + if (saved) { + const CollectionReference currentReference = m_currentCollection.reference(); + for (CollectionDetails &collection : collectionsToBeSaved) { + collection.markSaved(); + const CollectionReference reference = collection.reference(); + if (reference != currentReference) + closeCollectionIfSaved(reference); + } + return true; + } + } + return false; } -bool CollectionDetailsModel::exportCollection(const QString &filePath) +bool CollectionDetailsModel::exportCollection(const QUrl &url) { - return saveCollection(filePath, &m_currentCollection); + using Core::EditorManager; + using Utils::FilePath; + using Utils::TextFileFormat; + + QTC_ASSERT(m_currentCollection.isValid(), return false); + + bool saved = false; + const FilePath filePath = FilePath::fromUserInput(url.isLocalFile() ? url.toLocalFile() + : url.toString()); + const QString saveFormat = filePath.toFileInfo().suffix().toLower(); + const QString content = saveFormat == "csv" ? m_currentCollection.getCollectionAsCsvString() + : m_currentCollection.getCollectionAsJsonString(); + + TextFileFormat textFileFormat; + textFileFormat.codec = EditorManager::defaultTextCodec(); + textFileFormat.lineTerminationMode = EditorManager::defaultLineEnding(); + QString errorMessage; + saved = textFileFormat.writeFile(filePath, content, &errorMessage); + + if (!saved) + qWarning() << Q_FUNC_INFO << "Unable to write file" << errorMessage; + + return saved; } void CollectionDetailsModel::updateEmpty() @@ -453,19 +532,19 @@ void CollectionDetailsModel::closeCollectionIfSaved(const CollectionReference &c if (!collectionDetails.isChanged()) m_openedCollections.remove(collection); - - m_currentCollection = CollectionDetails{}; } void CollectionDetailsModel::closeCurrentCollectionIfSaved() { - if (m_currentCollection.isValid()) + if (m_currentCollection.isValid()) { closeCollectionIfSaved(m_currentCollection.reference()); + m_currentCollection = CollectionDetails{}; + } } void CollectionDetailsModel::loadJsonCollection(const QString &source, const QString &collection) { - using CollectionEditor::SourceFormat; + using CollectionEditorConstants::SourceFormat; QFile sourceFile(source); QJsonArray collectionNodes; @@ -510,7 +589,7 @@ void CollectionDetailsModel::loadJsonCollection(const QString &source, const QSt void CollectionDetailsModel::loadCsvCollection(const QString &source, [[maybe_unused]] const QString &collectionName) { - using CollectionEditor::SourceFormat; + using CollectionEditorConstants::SourceFormat; QFile sourceFile(source); QStringList headers; @@ -594,49 +673,6 @@ void CollectionDetailsModel::setCollectionName(const QString &newCollectionName) } } -bool CollectionDetailsModel::saveCollection(const QString &filePath, CollectionDetails *collection) -{ - bool saved = false; - - auto saveSingleCollection = [&](CollectionDetails &singleCollection) { - - const ModelNode node = singleCollection.reference().node; - QString path = CollectionEditor::getSourceCollectionPath(node); - QString saveFormat = CollectionEditor::getSourceCollectionType(node); - - if (!filePath.isEmpty()) { - QUrl url(filePath); - path = url.isLocalFile() ? QFileInfo(url.toLocalFile()).absoluteFilePath() : url.toString(); - saveFormat = url.isLocalFile() ? QFileInfo(url.toLocalFile()).suffix().toLower() : saveFormat; - } - - saved = saveCollectionFromString(path, (saveFormat == "json") ? singleCollection.getCollectionAsJsonString() : - (saveFormat == "csv") ? singleCollection.getCollectionAsCsvString() : QString()); - - if (saved && filePath.isEmpty()) - singleCollection.markSaved(); - }; - - if (!collection) { - for (CollectionDetails &openedCollection : m_openedCollections) - saveSingleCollection(openedCollection); - } else { - saveSingleCollection(*collection); - } - - return saved; -} - -bool CollectionDetailsModel::saveCollectionFromString(const QString &path, const QString &content) -{ - QFile file(path); - - if (file.open(QFile::WriteOnly) && file.write(content.toUtf8())) - return true; - - return false; -} - QString CollectionDetailsModel::warningToString(DataTypeWarning::Warning warning) const { return DataTypeWarning::getDataTypeWarningString(warning); diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.h b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.h index bf87d3838f..4fef84a3df 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.h @@ -62,8 +62,8 @@ public: void loadCollection(const ModelNode &sourceNode, const QString &collection); - Q_INVOKABLE bool saveCurrentCollection(); - Q_INVOKABLE bool exportCollection(const QString &filePath); + Q_INVOKABLE bool saveDataStoreCollections(); + Q_INVOKABLE bool exportCollection(const QUrl &url); signals: void collectionNameChanged(const QString &collectionName); @@ -81,8 +81,6 @@ private: void setCollectionName(const QString &newCollectionName); void loadJsonCollection(const QString &source, const QString &collection); void loadCsvCollection(const QString &source, const QString &collectionName); - bool saveCollection(const QString &filePath = {}, CollectionDetails *collection = nullptr); - bool saveCollectionFromString(const QString &path, const QString &content); QVariant variantFromString(const QString &value); QHash<CollectionReference, CollectionDetails> m_openedCollections; diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailssortfiltermodel.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailssortfiltermodel.cpp index 50fcadd494..f56bb36e88 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailssortfiltermodel.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailssortfiltermodel.cpp @@ -80,7 +80,9 @@ bool CollectionDetailsSortFilterModel::lessThan(const QModelIndex &sourceleft, if (sourceleft.column() == sourceRight.column()) { int column = sourceleft.column(); CollectionDetails::DataType columnType = m_source->propertyDataType(column); - return CollectionEditor::variantIslessThan(sourceleft.data(), sourceRight.data(), columnType); + return CollectionEditorUtils::variantIslessThan(sourceleft.data(), + sourceRight.data(), + columnType); } return false; diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorconstants.h b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorconstants.h index e914891de3..a591719d87 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorconstants.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorconstants.h @@ -3,7 +3,7 @@ #pragma once -namespace QmlDesigner::CollectionEditor { +namespace QmlDesigner::CollectionEditorConstants { enum class SourceFormat { Unknown, Json, Csv }; @@ -17,4 +17,4 @@ inline constexpr char CSVCOLLECTIONMODEL_TYPENAME[] = "QtQuick.Studio.Ut inline constexpr char JSONCOLLECTIONCHILDMODEL_TYPENAME[] = "QtQuick.Studio.Utils.ChildListModel"; inline constexpr char JSONBACKEND_TYPENAME[] = "JsonData"; -} // namespace QmlDesigner::CollectionEditor +} // namespace QmlDesigner::CollectionEditorConstants diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp index f48b6547ae..33867228d5 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp @@ -18,7 +18,10 @@ #include <QColor> #include <QJsonArray> +#include <QJsonDocument> #include <QJsonObject> +#include <QJsonParseError> +#include <QJsonValue> #include <QUrl> namespace { @@ -104,32 +107,32 @@ inline Utils::FilePath qmlDirFilePath() } // namespace -namespace QmlDesigner::CollectionEditor { +namespace QmlDesigner::CollectionEditorUtils { bool variantIslessThan(const QVariant &a, const QVariant &b, CollectionDetails::DataType type) { return std::visit(LessThanVisitor{}, valueToVariant(a, type), valueToVariant(b, type)); } -SourceFormat getSourceCollectionFormat(const ModelNode &node) +CollectionEditorConstants::SourceFormat getSourceCollectionFormat(const ModelNode &node) { using namespace QmlDesigner; - if (node.type() == CollectionEditor::JSONCOLLECTIONMODEL_TYPENAME) - return CollectionEditor::SourceFormat::Json; + if (node.type() == CollectionEditorConstants::JSONCOLLECTIONMODEL_TYPENAME) + return CollectionEditorConstants::SourceFormat::Json; - if (node.type() == CollectionEditor::CSVCOLLECTIONMODEL_TYPENAME) - return CollectionEditor::SourceFormat::Csv; + if (node.type() == CollectionEditorConstants::CSVCOLLECTIONMODEL_TYPENAME) + return CollectionEditorConstants::SourceFormat::Csv; - return CollectionEditor::SourceFormat::Unknown; + return CollectionEditorConstants::SourceFormat::Unknown; } QString getSourceCollectionType(const ModelNode &node) { using namespace QmlDesigner; - if (node.type() == CollectionEditor::JSONCOLLECTIONMODEL_TYPENAME) + if (node.type() == CollectionEditorConstants::JSONCOLLECTIONMODEL_TYPENAME) return "json"; - if (node.type() == CollectionEditor::CSVCOLLECTIONMODEL_TYPENAME) + if (node.type() == CollectionEditorConstants::CSVCOLLECTIONMODEL_TYPENAME) return "csv"; return {}; @@ -159,6 +162,20 @@ bool canAcceptCollectionAsModel(const ModelNode &node) && modelProperty.propertyType().isVariant(); } +bool hasTextRoleProperty(const ModelNode &node) +{ + const NodeMetaInfo nodeMetaInfo = node.metaInfo(); + if (!nodeMetaInfo.isValid()) + return false; + + const PropertyMetaInfo textRoleProperty = nodeMetaInfo.property("textRole"); + if (!textRoleProperty.isValid()) + return false; + + return textRoleProperty.isWritable() && !textRoleProperty.isPrivate() + && textRoleProperty.propertyType().isString(); +} + QString getSourceCollectionPath(const ModelNode &dataStoreNode) { using Utils::FilePath; @@ -280,4 +297,178 @@ bool ensureDataStoreExists(bool &justCreated) return false; } -} // namespace QmlDesigner::CollectionEditor +QJsonArray loadAsSingleJsonCollection(const QUrl &url) +{ + QFile file(url.isLocalFile() ? url.toLocalFile() : url.toString()); + QJsonArray collection; + QByteArray jsonData; + if (file.open(QFile::ReadOnly)) + jsonData = file.readAll(); + + file.close(); + if (jsonData.isEmpty()) + return {}; + + QJsonParseError parseError; + QJsonDocument document = QJsonDocument::fromJson(jsonData, &parseError); + if (parseError.error != QJsonParseError::NoError) + return {}; + + auto refineJsonArray = [](const QJsonArray &array) -> QJsonArray { + QJsonArray resultArray; + for (const QJsonValue &collectionData : array) { + if (collectionData.isObject()) { + QJsonObject rowObject = collectionData.toObject(); + const QStringList rowKeys = rowObject.keys(); + for (const QString &key : rowKeys) { + QJsonValue cellValue = rowObject.value(key); + if (cellValue.isArray()) + rowObject.remove(key); + } + resultArray.push_back(rowObject); + } + } + return resultArray; + }; + + if (document.isArray()) { + collection = refineJsonArray(document.array()); + } else if (document.isObject()) { + QJsonObject documentObject = document.object(); + const QStringList mainKeys = documentObject.keys(); + + bool arrayFound = false; + for (const QString &key : mainKeys) { + const QJsonValue &value = documentObject.value(key); + if (value.isArray()) { + arrayFound = true; + collection = refineJsonArray(value.toArray()); + break; + } + } + + if (!arrayFound) { + QJsonObject singleObject; + for (const QString &key : mainKeys) { + const QJsonValue value = documentObject.value(key); + + if (!value.isObject()) + singleObject.insert(key, value); + } + collection.push_back(singleObject); + } + } + return collection; +} + +QJsonArray loadAsCsvCollection(const QUrl &url) +{ + QFile sourceFile(url.isLocalFile() ? url.toLocalFile() : url.toString()); + QStringList headers; + QJsonArray elements; + + if (sourceFile.open(QFile::ReadOnly)) { + QTextStream stream(&sourceFile); + + if (!stream.atEnd()) + headers = stream.readLine().split(','); + + for (QString &header : headers) + header = header.trimmed(); + + if (!headers.isEmpty()) { + while (!stream.atEnd()) { + const QStringList recordDataList = stream.readLine().split(','); + int column = -1; + QJsonObject recordData; + for (const QString &cellData : recordDataList) { + if (++column == headers.size()) + break; + recordData.insert(headers.at(column), cellData); + } + elements.append(recordData); + } + } + } + + return elements; +} + +QString getFirstColumnName(const QString &collectionName) +{ + Utils::FilePath dataStorePath = CollectionEditorUtils::dataStoreJsonFilePath(); + + if (!dataStorePath.exists()) + return {}; + + Utils::FileReader dataStoreFile; + if (!dataStoreFile.fetch(dataStorePath)) + return {}; + + QJsonParseError jsonError; + QJsonDocument dataStoreDocument = QJsonDocument::fromJson(dataStoreFile.data(), &jsonError); + if (jsonError.error == QJsonParseError::NoError) { + QJsonObject rootObject = dataStoreDocument.object(); + if (rootObject.contains(collectionName)) { + QJsonArray collectionArray = rootObject.value(collectionName).toArray(); + for (const QJsonValue &elementValue : std::as_const(collectionArray)) { + const QJsonObject elementObject = elementValue.toObject(); + QJsonObject::ConstIterator element = elementObject.constBegin(); + if (element != elementObject.constEnd()) + return element.key(); + } + } else { + qWarning() << Q_FUNC_INFO << __LINE__ + << QString("Collection \"%1\" not found.").arg(collectionName); + } + } else { + qWarning() << Q_FUNC_INFO << __LINE__ << "Problem in reading json file." + << jsonError.errorString(); + } + + return {}; +} + +bool collectionHasColumn(const QString &collectionName, const QString &columnName) +{ + Utils::FilePath dataStorePath = CollectionEditorUtils::dataStoreJsonFilePath(); + + if (!dataStorePath.exists()) + return false; + + Utils::FileReader dataStoreFile; + if (!dataStoreFile.fetch(dataStorePath)) + return false; + + QJsonParseError jsonError; + QJsonDocument dataStoreDocument = QJsonDocument::fromJson(dataStoreFile.data(), &jsonError); + if (jsonError.error == QJsonParseError::NoError) { + QJsonObject rootObject = dataStoreDocument.object(); + if (rootObject.contains(collectionName)) { + QJsonArray collectionArray = rootObject.value(collectionName).toArray(); + for (const QJsonValue &elementValue : std::as_const(collectionArray)) { + const QJsonObject elementObject = elementValue.toObject(); + QJsonObject::ConstIterator element = elementObject.constBegin(); + const QJsonObject::ConstIterator stopItem = elementObject.constEnd(); + + while (element != stopItem) { + const QString keyName = element.key(); + ++element; + + if (columnName == keyName) + return true; + } + } + } else { + qWarning() << Q_FUNC_INFO << __LINE__ + << QString("Collection \"%1\" not found.").arg(collectionName); + } + } else { + qWarning() << Q_FUNC_INFO << __LINE__ << "Problem in reading json file." + << jsonError.errorString(); + } + + return false; +} + +} // namespace QmlDesigner::CollectionEditorUtils diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h index 036304a381..46429f04b6 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h @@ -14,11 +14,11 @@ namespace Utils { class FilePath; } -namespace QmlDesigner::CollectionEditor { +namespace QmlDesigner::CollectionEditorUtils { bool variantIslessThan(const QVariant &a, const QVariant &b, CollectionDetails::DataType type); -SourceFormat getSourceCollectionFormat(const QmlDesigner::ModelNode &node); +CollectionEditorConstants::SourceFormat getSourceCollectionFormat(const QmlDesigner::ModelNode &node); QString getSourceCollectionType(const QmlDesigner::ModelNode &node); @@ -34,6 +34,16 @@ bool ensureDataStoreExists(bool &justCreated); bool canAcceptCollectionAsModel(const ModelNode &node); +bool hasTextRoleProperty(const ModelNode &node); + QJsonArray defaultCollectionArray(); -} // namespace QmlDesigner::CollectionEditor +QJsonArray loadAsSingleJsonCollection(const QUrl &url); + +QJsonArray loadAsCsvCollection(const QUrl &url); + +QString getFirstColumnName(const QString &collectionName); + +bool collectionHasColumn(const QString &collectionName, const QString &columnName); + +} // namespace QmlDesigner::CollectionEditorUtils diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionimporttools.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionimporttools.cpp deleted file mode 100644 index 183730873d..0000000000 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionimporttools.cpp +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright (C) 2023 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "collectionimporttools.h" - -#include <QFile> -#include <QJsonArray> -#include <QJsonDocument> -#include <QJsonObject> -#include <QJsonParseError> -#include <QJsonValue> -#include <QUrl> - -namespace QmlDesigner::CollectionEditor::ImportTools { - -QJsonArray loadAsSingleJsonCollection(const QUrl &url) -{ - QFile file(url.isLocalFile() ? url.toLocalFile() : url.toString()); - QJsonArray collection; - QByteArray jsonData; - if (file.open(QFile::ReadOnly)) - jsonData = file.readAll(); - - file.close(); - if (jsonData.isEmpty()) - return {}; - - QJsonParseError parseError; - QJsonDocument document = QJsonDocument::fromJson(jsonData, &parseError); - if (parseError.error != QJsonParseError::NoError) - return {}; - - auto refineJsonArray = [](const QJsonArray &array) -> QJsonArray { - QJsonArray resultArray; - for (const QJsonValue &collectionData : array) { - if (collectionData.isObject()) { - QJsonObject rowObject = collectionData.toObject(); - const QStringList rowKeys = rowObject.keys(); - for (const QString &key : rowKeys) { - QJsonValue cellValue = rowObject.value(key); - if (cellValue.isArray()) - rowObject.remove(key); - } - resultArray.push_back(rowObject); - } - } - return resultArray; - }; - - if (document.isArray()) { - collection = refineJsonArray(document.array()); - } else if (document.isObject()) { - QJsonObject documentObject = document.object(); - const QStringList mainKeys = documentObject.keys(); - - bool arrayFound = false; - for (const QString &key : mainKeys) { - const QJsonValue &value = documentObject.value(key); - if (value.isArray()) { - arrayFound = true; - collection = refineJsonArray(value.toArray()); - break; - } - } - - if (!arrayFound) { - QJsonObject singleObject; - for (const QString &key : mainKeys) { - const QJsonValue value = documentObject.value(key); - - if (!value.isObject()) - singleObject.insert(key, value); - } - collection.push_back(singleObject); - } - } - return collection; -} - -QJsonArray loadAsCsvCollection(const QUrl &url) -{ - QFile sourceFile(url.isLocalFile() ? url.toLocalFile() : url.toString()); - QStringList headers; - QJsonArray elements; - - if (sourceFile.open(QFile::ReadOnly)) { - QTextStream stream(&sourceFile); - - if (!stream.atEnd()) - headers = stream.readLine().split(','); - - for (QString &header : headers) - header = header.trimmed(); - - if (!headers.isEmpty()) { - while (!stream.atEnd()) { - const QStringList recordDataList = stream.readLine().split(','); - int column = -1; - QJsonObject recordData; - for (const QString &cellData : recordDataList) { - if (++column == headers.size()) - break; - recordData.insert(headers.at(column), cellData); - } - elements.append(recordData); - } - } - } - - return elements; -} - -} // namespace QmlDesigner::CollectionEditor::ImportTools diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionimporttools.h b/src/plugins/qmldesigner/components/collectioneditor/collectionimporttools.h deleted file mode 100644 index 6ee4f590f7..0000000000 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionimporttools.h +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (C) 2023 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include <QtCore/qtconfigmacros.h> - -QT_BEGIN_NAMESPACE -class QJsonArray; -class QUrl; -QT_END_NAMESPACE - -namespace QmlDesigner::CollectionEditor::ImportTools { - -QJsonArray loadAsSingleJsonCollection(const QUrl &url); -QJsonArray loadAsCsvCollection(const QUrl &url); - -} // namespace QmlDesigner::CollectionEditor::ImportTools diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionlistmodel.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionlistmodel.cpp index d910569f0d..214ece078a 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionlistmodel.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionlistmodel.cpp @@ -29,7 +29,7 @@ namespace QmlDesigner { CollectionListModel::CollectionListModel(const ModelNode &sourceModel) : QStringListModel() , m_sourceNode(sourceModel) - , m_sourceType(CollectionEditor::getSourceCollectionType(sourceModel)) + , m_sourceType(CollectionEditorUtils::getSourceCollectionType(sourceModel)) { connect(this, &CollectionListModel::modelReset, this, &CollectionListModel::updateEmpty); connect(this, &CollectionListModel::rowsRemoved, this, &CollectionListModel::updateEmpty); @@ -87,8 +87,11 @@ bool CollectionListModel::removeRows(int row, int count, const QModelIndex &pare QStringList removedCollections = stringList().mid(row, count); bool itemsRemoved = Super::removeRows(row, count, parent); - if (itemsRemoved) + if (itemsRemoved) { emit collectionsRemoved(removedCollections); + if (m_selectedIndex >= row) + selectCollectionIndex(m_selectedIndex - count, true); + } return itemsRemoved; } @@ -121,7 +124,7 @@ ModelNode CollectionListModel::sourceNode() const QString CollectionListModel::sourceAddress() const { - return CollectionEditor::getSourceCollectionPath(m_sourceNode); + return CollectionEditorUtils::getSourceCollectionPath(m_sourceNode); } bool CollectionListModel::contains(const QString &collectionName) const diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.cpp index 0c57f18778..1f9c7aa5d7 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.cpp @@ -25,7 +25,8 @@ QSharedPointer<QmlDesigner::CollectionListModel> loadCollection( const QmlDesigner::ModelNode &sourceNode, QSharedPointer<QmlDesigner::CollectionListModel> initialCollection = {}) { - using namespace QmlDesigner::CollectionEditor; + using namespace QmlDesigner::CollectionEditorConstants; + using namespace QmlDesigner::CollectionEditorUtils; QString sourceFileAddress = getSourceCollectionPath(sourceNode); QSharedPointer<QmlDesigner::CollectionListModel> collectionsList; @@ -88,9 +89,9 @@ QVariant CollectionSourceModel::data(const QModelIndex &index, int role) const case NodeRole: return QVariant::fromValue(*collectionSource); case CollectionTypeRole: - return CollectionEditor::getSourceCollectionType(*collectionSource); + return CollectionEditorUtils::getSourceCollectionType(*collectionSource); case SourceRole: - return collectionSource->variantProperty(CollectionEditor::SOURCEFILE_PROPERTY).value(); + return collectionSource->variantProperty(CollectionEditorConstants::SOURCEFILE_PROPERTY).value(); case SelectedRole: return index.row() == m_selectedIndex; case CollectionsRole: @@ -116,7 +117,8 @@ bool CollectionSourceModel::setData(const QModelIndex &index, const QVariant &va collectionName.setValue(value.toString()); } break; case SourceRole: { - auto sourceAddress = collectionSource.variantProperty(CollectionEditor::SOURCEFILE_PROPERTY); + auto sourceAddress = collectionSource.variantProperty( + CollectionEditorConstants::SOURCEFILE_PROPERTY); if (sourceAddress.value() == value) return false; @@ -281,13 +283,13 @@ bool CollectionSourceModel::addCollectionToSource(const ModelNode &node, if (idx < 0) return returnError(tr("Node is not indexed in the models.")); - if (node.type() != CollectionEditor::JSONCOLLECTIONMODEL_TYPENAME) + if (node.type() != CollectionEditorConstants::JSONCOLLECTIONMODEL_TYPENAME) return returnError(tr("Node should be a JSON model.")); if (collectionExists(node, collectionName)) return returnError(tr("A model with the identical name already exists.")); - QString sourceFileAddress = CollectionEditor::getSourceCollectionPath(node); + QString sourceFileAddress = CollectionEditorUtils::getSourceCollectionPath(node); QFileInfo sourceFileInfo(sourceFileAddress); if (!sourceFileInfo.isFile()) @@ -325,6 +327,7 @@ bool CollectionSourceModel::addCollectionToSource(const ModelNode &node, return returnError(tr("No model is available for the JSON model group.")); collections->selectCollectionName(collectionName); + setSelectedCollectionName(collectionName); return true; } else { return returnError(tr("JSON document type should be an object containing models.")); @@ -403,9 +406,11 @@ void CollectionSourceModel::onSelectedCollectionChanged(CollectionListModel *col m_previousSelectedList = collectionList; - emit collectionSelected(collectionList->collectionNameAt(collectionIndex)); + setSelectedCollectionName(collectionList->collectionNameAt(collectionIndex)); selectSourceIndex(sourceIndex(collectionList->sourceNode())); + } else { + setSelectedCollectionName({}); } } @@ -413,7 +418,7 @@ void CollectionSourceModel::onCollectionNameChanged(CollectionListModel *collect const QString &oldName, const QString &newName) { auto emitRenameWarning = [this](const QString &msg) -> void { - emit this->warning(tr("Rename Model"), msg); + emit warning(tr("Rename Model"), msg); }; const ModelNode node = collectionList->sourceNode(); @@ -424,16 +429,16 @@ void CollectionSourceModel::onCollectionNameChanged(CollectionListModel *collect return; } - if (node.type() == CollectionEditor::CSVCOLLECTIONMODEL_TYPENAME) { + if (node.type() == CollectionEditorConstants::CSVCOLLECTIONMODEL_TYPENAME) { if (!setData(nodeIndex, newName, NameRole)) emitRenameWarning(tr("Can't rename the node")); return; - } else if (node.type() != CollectionEditor::JSONCOLLECTIONMODEL_TYPENAME) { + } else if (node.type() != CollectionEditorConstants::JSONCOLLECTIONMODEL_TYPENAME) { emitRenameWarning(tr("Invalid node type")); return; } - QString sourceFileAddress = CollectionEditor::getSourceCollectionPath(node); + QString sourceFileAddress = CollectionEditorUtils::getSourceCollectionPath(node); QFileInfo sourceFileInfo(sourceFileAddress); if (!sourceFileInfo.isFile()) { @@ -513,15 +518,15 @@ void CollectionSourceModel::onCollectionsRemoved(CollectionListModel *collection return; } - if (node.type() == CollectionEditor::CSVCOLLECTIONMODEL_TYPENAME) { + if (node.type() == CollectionEditorConstants::CSVCOLLECTIONMODEL_TYPENAME) { removeSource(node); return; - } else if (node.type() != CollectionEditor::JSONCOLLECTIONMODEL_TYPENAME) { + } else if (node.type() != CollectionEditorConstants::JSONCOLLECTIONMODEL_TYPENAME) { emitDeleteWarning(tr("Invalid node type")); return; } - QString sourceFileAddress = CollectionEditor::getSourceCollectionPath(node); + QString sourceFileAddress = CollectionEditorUtils::getSourceCollectionPath(node); QFileInfo sourceFileInfo(sourceFileAddress); if (!sourceFileInfo.isFile()) { @@ -575,9 +580,11 @@ void CollectionSourceModel::onCollectionsRemoved(CollectionListModel *collection } for (const QString &collectionName : std::as_const(collectionsRemovedFromDocument)) - emit this->collectionRemoved(collectionName); + emit collectionRemoved(collectionName); updateCollectionList(nodeIndex); + if (m_previousSelectedList == collectionList) + onSelectedCollectionChanged(collectionList, collectionList->selectedIndex()); } } @@ -607,12 +614,20 @@ void CollectionSourceModel::setSelectedIndex(int idx) } else if (m_previousSelectedList) { m_previousSelectedList->selectCollectionIndex(-1); m_previousSelectedList = {}; - emit this->collectionSelected({}); + setSelectedCollectionName({}); } } } } +void CollectionSourceModel::setSelectedCollectionName(const QString &collectionName) +{ + if (m_selectedCollectionName != collectionName) { + m_selectedCollectionName = collectionName; + emit collectionSelected(m_selectedCollectionName); + } +} + void CollectionSourceModel::updateEmpty() { bool isEmptyNow = m_collectionSources.isEmpty(); diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.h b/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.h index 487b616b97..5ab77f2a98 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.h @@ -87,6 +87,7 @@ private slots: private: void setSelectedIndex(int idx); + void setSelectedCollectionName(const QString &collectionName); void updateEmpty(); void updateCollectionList(QModelIndex index); void registerCollection(const QSharedPointer<CollectionListModel> &collection); @@ -98,6 +99,7 @@ private: QHash<qint32, int> m_sourceIndexHash; // internalId -> index QList<QSharedPointer<CollectionListModel>> m_collectionList; QPointer<CollectionListModel> m_previousSelectedList; + QString m_selectedCollectionName; int m_selectedIndex = -1; bool m_isEmpty = true; }; diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp index f17abf5d9f..7f3ee7192a 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp @@ -31,7 +31,7 @@ namespace { inline bool isStudioCollectionModel(const QmlDesigner::ModelNode &node) { - using namespace QmlDesigner::CollectionEditor; + using namespace QmlDesigner::CollectionEditorConstants; return node.metaInfo().typeName() == JSONCOLLECTIONMODEL_TYPENAME || node.metaInfo().typeName() == CSVCOLLECTIONMODEL_TYPENAME; } @@ -151,7 +151,7 @@ void CollectionView::variantPropertiesChanged(const QList<VariantProperty> &prop if (isStudioCollectionModel(node)) { if (property.name() == "objectName") m_widget->sourceModel()->updateNodeName(node); - else if (property.name() == CollectionEditor::SOURCEFILE_PROPERTY) + else if (property.name() == CollectionEditorConstants::SOURCEFILE_PROPERTY) m_widget->sourceModel()->updateNodeSource(node); } } @@ -169,7 +169,8 @@ void CollectionView::selectedNodesChanged(const QList<ModelNode> &selectedNodeLi bool singleSelectedHasModelProperty = false; if (singleNonCollectionNodeSelected) { const ModelNode selectedNode = selectedNodeList.first(); - singleSelectedHasModelProperty = CollectionEditor::canAcceptCollectionAsModel(selectedNode); + singleSelectedHasModelProperty = CollectionEditorUtils::canAcceptCollectionAsModel( + selectedNode); } m_widget->setTargetNodeSelected(singleSelectedHasModelProperty); @@ -204,7 +205,7 @@ void CollectionView::addResource(const QUrl &url, const QString &name, const QSt resourceMetaInfo.majorVersion(), resourceMetaInfo.minorVersion()); VariantProperty sourceProperty = resourceNode.variantProperty( - CollectionEditor::SOURCEFILE_PROPERTY); + CollectionEditorConstants::SOURCEFILE_PROPERTY); VariantProperty nameProperty = resourceNode.variantProperty("objectName"); sourceProperty.setValue(sourceAddress); nameProperty.setValue(name); @@ -252,18 +253,18 @@ void CollectionView::refreshModel() NodeMetaInfo CollectionView::jsonCollectionMetaInfo() const { - return model()->metaInfo(CollectionEditor::JSONCOLLECTIONMODEL_TYPENAME); + return model()->metaInfo(CollectionEditorConstants::JSONCOLLECTIONMODEL_TYPENAME); } NodeMetaInfo CollectionView::csvCollectionMetaInfo() const { - return model()->metaInfo(CollectionEditor::CSVCOLLECTIONMODEL_TYPENAME); + return model()->metaInfo(CollectionEditorConstants::CSVCOLLECTIONMODEL_TYPENAME); } void CollectionView::ensureStudioModelImport() { executeInTransaction(__FUNCTION__, [&] { - Import import = Import::createLibraryImport(CollectionEditor::COLLECTIONMODEL_IMPORT); + Import import = Import::createLibraryImport(CollectionEditorConstants::COLLECTIONMODEL_IMPORT); try { if (!model()->hasImport(import, true, true)) model()->changeImports({import}, {}); diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp index 9b14c2cd03..39097cbeb3 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp @@ -6,7 +6,6 @@ #include "collectiondetailsmodel.h" #include "collectiondetailssortfiltermodel.h" #include "collectioneditorutils.h" -#include "collectionimporttools.h" #include "collectionsourcemodel.h" #include "collectionview.h" #include "qmldesignerconstants.h" @@ -216,7 +215,7 @@ bool CollectionWidget::addCollection(const QString &collectionName, if (collectionType == "json") { QJsonObject jsonObject; - jsonObject.insert(collectionName, CollectionEditor::defaultCollectionArray()); + jsonObject.insert(collectionName, CollectionEditorUtils::defaultCollectionArray()); QFile sourceFile(sourcePath); if (!sourceFile.open(QFile::WriteOnly)) { @@ -258,10 +257,8 @@ bool CollectionWidget::addCollection(const QString &collectionName, } } else if (collectionType == "json") { QString errorMsg; - bool added = m_sourceModel->addCollectionToSource(node, - collectionName, - CollectionEditor::defaultCollectionArray(), - &errorMsg); + bool added = m_sourceModel->addCollectionToSource( + node, collectionName, CollectionEditorUtils::defaultCollectionArray(), &errorMsg); if (!added) warn(tr("Can not add a model to the JSON file"), errorMsg); return added; @@ -274,10 +271,10 @@ bool CollectionWidget::importToJson(const QVariant &sourceNode, const QString &collectionName, const QUrl &url) { - using CollectionEditor::SourceFormat; + using CollectionEditorConstants::SourceFormat; using Utils::FilePath; const ModelNode node = sourceNode.value<ModelNode>(); - const SourceFormat nodeFormat = CollectionEditor::getSourceCollectionFormat(node); + const SourceFormat nodeFormat = CollectionEditorUtils::getSourceCollectionFormat(node); QTC_ASSERT(node.isValid() && nodeFormat == SourceFormat::Json, return false); FilePath fileInfo = FilePath::fromUserInput(url.isLocalFile() ? url.toLocalFile() @@ -287,9 +284,9 @@ bool CollectionWidget::importToJson(const QVariant &sourceNode, QJsonArray loadedCollection; if (fileInfo.suffix() == "json") - loadedCollection = CollectionEditor::ImportTools::loadAsSingleJsonCollection(url); + loadedCollection = CollectionEditorUtils::loadAsSingleJsonCollection(url); else if (fileInfo.suffix() == "csv") - loadedCollection = CollectionEditor::ImportTools::loadAsCsvCollection(url); + loadedCollection = CollectionEditorUtils::loadAsCsvCollection(url); if (!loadedCollection.isEmpty()) { const QString newCollectionName = generateUniqueCollectionName(node, collectionName); @@ -327,7 +324,7 @@ bool CollectionWidget::addCollectionToDataStore(const QString &collectionName) bool added = m_sourceModel->addCollectionToSource(node, generateUniqueCollectionName(node, collectionName), - CollectionEditor::defaultCollectionArray(), + CollectionEditorUtils::defaultCollectionArray(), &errorMsg); if (!added) warn(tr("Failed to add a model to the default model group"), errorMsg); @@ -343,7 +340,7 @@ void CollectionWidget::assignCollectionToSelectedNode(const QString collectionNa void CollectionWidget::ensureDataStoreExists() { bool filesJustCreated = false; - bool filesExist = CollectionEditor::ensureDataStoreExists(filesJustCreated); + bool filesExist = CollectionEditorUtils::ensureDataStoreExists(filesJustCreated); if (filesExist && filesJustCreated) m_view->resetDataStoreNode(); } diff --git a/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.cpp b/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.cpp index bebc60f1de..a1f82bbc65 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.cpp @@ -7,6 +7,10 @@ #include "collectioneditorconstants.h" #include "collectioneditorutils.h" #include "model/qmltextgenerator.h" +#include "plaintexteditmodifier.h" +#include "qmldesignerbase/qmldesignerbaseplugin.h" +#include "qmldesignerexternaldependencies.h" +#include "rewriterview.h" #include <model.h> #include <nodemetainfo.h> @@ -23,20 +27,25 @@ #include <utils/fileutils.h> #include <utils/qtcassert.h> +#include <QPlainTextEdit> #include <QRegularExpression> #include <QRegularExpressionMatch> +#include <QScopedPointer> namespace { +inline constexpr char CHILDLISTMODEL_TYPENAME[] = "ChildListModel"; + QmlDesigner::PropertyNameList createNameList(const QmlDesigner::ModelNode &node) { using QmlDesigner::AbstractProperty; using QmlDesigner::PropertyName; using QmlDesigner::PropertyNameList; - static PropertyNameList defaultsNodeProps = {"id", - QmlDesigner::CollectionEditor::SOURCEFILE_PROPERTY, - QmlDesigner::CollectionEditor::JSONCHILDMODELNAME_PROPERTY, - "backend"}; + static PropertyNameList defaultsNodeProps = { + "id", + QmlDesigner::CollectionEditorConstants::SOURCEFILE_PROPERTY, + QmlDesigner::CollectionEditorConstants::JSONCHILDMODELNAME_PROPERTY, + "backend"}; PropertyNameList dynamicPropertyNames = Utils::transform( node.dynamicProperties(), [](const AbstractProperty &property) -> PropertyName { return property.name(); }); @@ -49,8 +58,8 @@ QmlDesigner::PropertyNameList createNameList(const QmlDesigner::ModelNode &node) bool isValidCollectionPropertyName(const QString &collectionId) { static const QmlDesigner::PropertyNameList reservedKeywords = { - QmlDesigner::CollectionEditor::SOURCEFILE_PROPERTY, - QmlDesigner::CollectionEditor::JSONBACKEND_TYPENAME, + QmlDesigner::CollectionEditorConstants::SOURCEFILE_PROPERTY, + QmlDesigner::CollectionEditorConstants::JSONBACKEND_TYPENAME, "backend", "models", }; @@ -59,6 +68,58 @@ bool isValidCollectionPropertyName(const QString &collectionId) && !reservedKeywords.contains(collectionId.toLatin1()); } +QMap<QString, QmlDesigner::PropertyName> getModelIdMap(const QmlDesigner::ModelNode &rootNode) +{ + using namespace QmlDesigner; + QMap<QString, PropertyName> modelNameForId; + + const QList<AbstractProperty> propertyNames = rootNode.dynamicProperties(); + + for (const AbstractProperty &property : std::as_const(propertyNames)) { + if (!property.isNodeProperty()) + continue; + + NodeProperty nodeProperty = property.toNodeProperty(); + if (!nodeProperty.hasDynamicTypeName(CHILDLISTMODEL_TYPENAME)) + continue; + + ModelNode childNode = nodeProperty.modelNode(); + if (childNode.hasProperty(CollectionEditorConstants::JSONCHILDMODELNAME_PROPERTY)) { + QString modelName = childNode + .property(CollectionEditorConstants::JSONCHILDMODELNAME_PROPERTY) + .toVariantProperty() + .value() + .toString(); + + if (!modelName.isEmpty()) + modelNameForId.insert(modelName, property.name()); + } + } + return modelNameForId; +} + +void setQmlContextToModel(QmlDesigner::Model *model, const QString &qmlContext) +{ + using namespace QmlDesigner; + Q_ASSERT(model); + + QScopedPointer<QPlainTextEdit> textEdit(new QPlainTextEdit); + QScopedPointer<NotIndentingTextEditModifier> modifier( + new NotIndentingTextEditModifier(textEdit.data())); + textEdit->hide(); + textEdit->setPlainText(qmlContext); + QmlDesigner::ExternalDependencies externalDependencies{QmlDesignerBasePlugin::settings()}; + QScopedPointer<RewriterView> rewriter( + new RewriterView(externalDependencies, QmlDesigner::RewriterView::Validate)); + + rewriter->setParent(model); + rewriter->setTextModifier(modifier.get()); + rewriter->setCheckSemanticErrors(false); + + model->attachView(rewriter.get()); + model->detachView(rewriter.get()); +} + } // namespace namespace QmlDesigner { @@ -77,15 +138,16 @@ void DataStoreModelNode::reloadModel() } bool forceUpdate = false; - const FilePath dataStoreQmlPath = CollectionEditor::dataStoreQmlFilePath(); - const FilePath dataStoreJsonPath = CollectionEditor::dataStoreJsonFilePath(); + const FilePath dataStoreQmlPath = CollectionEditorUtils::dataStoreQmlFilePath(); + const FilePath dataStoreJsonPath = CollectionEditorUtils::dataStoreJsonFilePath(); QUrl dataStoreQmlUrl = dataStoreQmlPath.toUrl(); if (dataStoreQmlPath.exists() && dataStoreJsonPath.exists()) { if (!m_model.get() || m_model->fileUrl() != dataStoreQmlUrl) { - m_model = Model::create(CollectionEditor::JSONCOLLECTIONMODEL_TYPENAME, 1, 1); + m_model = Model::create(CollectionEditorConstants::JSONCOLLECTIONMODEL_TYPENAME, 1, 1); forceUpdate = true; - Import import = Import::createLibraryImport(CollectionEditor::COLLECTIONMODEL_IMPORT); + Import import = Import::createLibraryImport( + CollectionEditorConstants::COLLECTIONMODEL_IMPORT); try { if (!m_model->hasImport(import, true, true)) m_model->changeImports({import}, {}); @@ -102,8 +164,10 @@ void DataStoreModelNode::reloadModel() m_dataRelativePath = dataStoreJsonPath.relativePathFrom(dataStoreQmlPath).toFSPathString(); - if (forceUpdate) + if (forceUpdate) { + preloadFile(); update(); + } } QStringList DataStoreModelNode::collectionNames() const @@ -143,6 +207,25 @@ void DataStoreModelNode::reset() setCollectionNames({}); } +void DataStoreModelNode::preloadFile() +{ + using Utils::FilePath; + using Utils::FileReader; + + if (!m_model) + return; + + const FilePath dataStoreQmlPath = dataStoreQmlFilePath(); + FileReader dataStoreQmlFile; + QString sourceQmlContext; + + if (dataStoreQmlFile.fetch(dataStoreQmlPath)) + sourceQmlContext = QString::fromLatin1(dataStoreQmlFile.data()); + + setQmlContextToModel(m_model.get(), sourceQmlContext); + m_collectionPropertyNames = getModelIdMap(m_model->rootModelNode()); +} + void DataStoreModelNode::updateDataStoreProperties() { QTC_ASSERT(model(), return); @@ -150,8 +233,6 @@ void DataStoreModelNode::updateDataStoreProperties() ModelNode rootNode = modelNode(); QTC_ASSERT(rootNode.isValid(), return); - static TypeName childNodeTypename = "ChildListModel"; - QSet<QString> collectionNamesToBeAdded; const QStringList allCollectionNames = m_collectionPropertyNames.keys(); for (const QString &collectionName : allCollectionNames) @@ -165,12 +246,13 @@ void DataStoreModelNode::updateDataStoreProperties() continue; NodeProperty nodeProprty = property.toNodeProperty(); - if (!nodeProprty.hasDynamicTypeName(childNodeTypename)) + if (!nodeProprty.hasDynamicTypeName(CHILDLISTMODEL_TYPENAME)) continue; ModelNode childNode = nodeProprty.modelNode(); - if (childNode.hasProperty(CollectionEditor::JSONCHILDMODELNAME_PROPERTY)) { - QString modelName = childNode.property(CollectionEditor::JSONCHILDMODELNAME_PROPERTY) + if (childNode.hasProperty(CollectionEditorConstants::JSONCHILDMODELNAME_PROPERTY)) { + QString modelName = childNode + .property(CollectionEditorConstants::JSONCHILDMODELNAME_PROPERTY) .toVariantProperty() .value() .toString(); @@ -189,32 +271,17 @@ void DataStoreModelNode::updateDataStoreProperties() QStringList collectionNamesLeft = collectionNamesToBeAdded.values(); Utils::sort(collectionNamesLeft); - for (const QString &collectionName : std::as_const(collectionNamesLeft)) { - PropertyName newPropertyName = getUniquePropertyName(collectionName); - if (newPropertyName.isEmpty()) { - qWarning() << __FUNCTION__ << __LINE__ - << QString("The property name cannot be generated from \"%1\"").arg(collectionName); - continue; - } - - ModelNode collectionNode = model()->createModelNode(childNodeTypename); - VariantProperty modelNameProperty = collectionNode.variantProperty( - CollectionEditor::JSONCHILDMODELNAME_PROPERTY); - modelNameProperty.setValue(collectionName); - - NodeProperty nodeProp = rootNode.nodeProperty(newPropertyName); - nodeProp.setDynamicTypeNameAndsetModelNode(childNodeTypename, collectionNode); - - m_collectionPropertyNames.insert(collectionName, newPropertyName); - } + for (const QString &collectionName : std::as_const(collectionNamesLeft)) + addCollectionNameToTheModel(collectionName, getUniquePropertyName(collectionName)); // Backend Property - ModelNode backendNode = model()->createModelNode(CollectionEditor::JSONBACKEND_TYPENAME); + ModelNode backendNode = model()->createModelNode(CollectionEditorConstants::JSONBACKEND_TYPENAME); NodeProperty backendProperty = rootNode.nodeProperty("backend"); - backendProperty.setDynamicTypeNameAndsetModelNode(CollectionEditor::JSONBACKEND_TYPENAME, + backendProperty.setDynamicTypeNameAndsetModelNode(CollectionEditorConstants::JSONBACKEND_TYPENAME, backendNode); // Source Property - VariantProperty sourceProp = rootNode.variantProperty(CollectionEditor::SOURCEFILE_PROPERTY); + VariantProperty sourceProp = rootNode.variantProperty( + CollectionEditorConstants::SOURCEFILE_PROPERTY); sourceProp.setValue(m_dataRelativePath); } @@ -231,19 +298,50 @@ void DataStoreModelNode::updateSingletonFile() imports += QStringLiteral("import %1\n").arg(import.toString(true)); QString content = pragmaSingleTone + imports + getModelQmlText(); - QUrl modelUrl = m_model->fileUrl(); - FileSaver file(FilePath::fromUserInput(modelUrl.isLocalFile() ? modelUrl.toLocalFile() - : modelUrl.toString())); + FileSaver file(dataStoreQmlFilePath()); file.write(content.toLatin1()); file.finalize(); } void DataStoreModelNode::update() { + if (!m_model.get()) + return; + updateDataStoreProperties(); updateSingletonFile(); } +void DataStoreModelNode::addCollectionNameToTheModel(const QString &collectionName, + const PropertyName &dataStorePropertyName) +{ + ModelNode rootNode = modelNode(); + QTC_ASSERT(rootNode.isValid(), return); + + if (dataStorePropertyName.isEmpty()) { + qWarning() << __FUNCTION__ << __LINE__ + << QString("The property name cannot be generated from \"%1\"").arg(collectionName); + return; + } + + ModelNode collectionNode = model()->createModelNode(CHILDLISTMODEL_TYPENAME); + VariantProperty modelNameProperty = collectionNode.variantProperty( + CollectionEditorConstants::JSONCHILDMODELNAME_PROPERTY); + modelNameProperty.setValue(collectionName); + + NodeProperty nodeProp = rootNode.nodeProperty(dataStorePropertyName); + nodeProp.setDynamicTypeNameAndsetModelNode(CHILDLISTMODEL_TYPENAME, collectionNode); + + m_collectionPropertyNames.insert(collectionName, dataStorePropertyName); +} + +Utils::FilePath DataStoreModelNode::dataStoreQmlFilePath() const +{ + QUrl modelUrl = m_model->fileUrl(); + return Utils::FilePath::fromUserInput(modelUrl.isLocalFile() ? modelUrl.toLocalFile() + : modelUrl.toString()); +} + PropertyName DataStoreModelNode::getUniquePropertyName(const QString &collectionName) { ModelNode dataStoreNode = modelNode(); @@ -300,7 +398,7 @@ void DataStoreModelNode::renameCollection(const QString &oldName, const QString NodeProperty collectionNode = dataStoreNode.property(oldPropertyName).toNodeProperty(); if (collectionNode.isValid()) { VariantProperty modelNameProperty = collectionNode.modelNode().variantProperty( - CollectionEditor::JSONCHILDMODELNAME_PROPERTY); + CollectionEditorConstants::JSONCHILDMODELNAME_PROPERTY); modelNameProperty.setValue(newName); m_collectionPropertyNames.remove(oldName); m_collectionPropertyNames.insert(newName, collectionNode.name()); @@ -333,7 +431,7 @@ void DataStoreModelNode::assignCollectionToNode(AbstractView *view, { QTC_ASSERT(targetNode.isValid(), return); - if (!CollectionEditor::canAcceptCollectionAsModel(targetNode)) + if (!CollectionEditorUtils::canAcceptCollectionAsModel(targetNode)) return; if (!m_collectionPropertyNames.contains(collectionName)) { @@ -352,12 +450,27 @@ void DataStoreModelNode::assignCollectionToNode(AbstractView *view, return; } - BindingProperty modelProperty = targetNode.bindingProperty("model"); - - QString identifier = QString("DataStore.%1").arg(QString::fromLatin1(sourceProperty.name())); - - view->executeInTransaction("assignCollectionToNode", [&modelProperty, &identifier]() { + view->executeInTransaction("assignCollectionToNode", [&]() { + QString identifier = QString("DataStore.%1").arg(QString::fromLatin1(sourceProperty.name())); + BindingProperty modelProperty = targetNode.bindingProperty("model"); modelProperty.setExpression(identifier); + if (CollectionEditorUtils::hasTextRoleProperty(targetNode)) { + VariantProperty textRoleProperty = targetNode.variantProperty("textRole"); + const QVariant currentTextRoleValue = textRoleProperty.value(); + + if (currentTextRoleValue.isValid() && !currentTextRoleValue.isNull()) { + if (currentTextRoleValue.type() == QVariant::String) { + const QString currentTextRole = currentTextRoleValue.toString(); + if (CollectionEditorUtils::collectionHasColumn(collectionName, currentTextRole)) + return; + } else { + return; + } + } + + QString textRoleValue = CollectionEditorUtils::getFirstColumnName(collectionName); + textRoleProperty.setValue(textRoleValue); + } }); } diff --git a/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.h b/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.h index 3048fc4fc9..1c855bca7a 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.h +++ b/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.h @@ -7,6 +7,10 @@ #include <QMap> +namespace Utils { +class FilePath; +} + namespace QmlDesigner { class Model; @@ -34,9 +38,14 @@ private: QString getModelQmlText(); void reset(); + void preloadFile(); void updateDataStoreProperties(); void updateSingletonFile(); void update(); + void addCollectionNameToTheModel(const QString &collectionName, + const PropertyName &dataStorePropertyName); + Utils::FilePath dataStoreQmlFilePath() const; + PropertyName getUniquePropertyName(const QString &collectionName); ModelPointer m_model; diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp index 6ad7ed994b..6e4b1a1efd 100644 --- a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp +++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp @@ -11,6 +11,7 @@ #include "formatoperation.h" #include "groupitemaction.h" #include "modelnodecontextmenu_helper.h" +#include "propertytreemodel.h" #include "qmldesignerconstants.h" #include "qmleditormenu.h" #include "rewritingexception.h" @@ -475,35 +476,20 @@ QStringList getSignalsList(const ModelNode &node) if (!node.hasMetaInfo()) return {}; - QStringList signalsList; - NodeMetaInfo nodeMetaInfo = node.metaInfo(); - - for (const auto &signalName : nodeMetaInfo.signalNames()) { - signalsList << QString::fromUtf8(signalName); - } - - //on...Changed are the most regular signals, we assign them the lowest priority, - //we don't need them right now -// QStringList signalsWithChanged = signalsList.filter("Changed"); - - //these are item specific, like MouseArea.clicked, they have higher priority - QStringList signalsWithoutChanged = signalsList; - signalsWithoutChanged.removeIf([](QString str) { - if (str.endsWith("Changed")) - return true; - return false; - }); - - QStringList finalResult; - finalResult.append(signalsWithoutChanged); + QStringList signalList; + std::vector<PropertyName> signalVector = PropertyTreeModel::sortedAndFilteredSignalNames( + node.metaInfo()); - if (finalResult.isEmpty()) - finalResult = signalsList; + std::vector<QString> signalVectorString = Utils::transform(signalVector, + [](const PropertyName &name) { + return QString::fromUtf8(name); + }); - finalResult.removeDuplicates(); + signalList.reserve(Utils::ssize(signalVectorString)); + std::copy(signalVectorString.begin(), signalVectorString.end(), std::back_inserter(signalList)); - return finalResult; + return signalList; } struct SlotEntry diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp index 79ff364c40..dd00cd48d4 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp +++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp @@ -1731,7 +1731,7 @@ bool useLayerEffect() QtcSettings *settings = Core::ICore::settings(); const Key layerEffectEntry = "QML/Designer/UseLayerEffect"; - return settings->value(layerEffectEntry, true).toBool(); + return settings->value(layerEffectEntry, false).toBool(); } bool validateEffect(const QString &effectPath) diff --git a/src/plugins/qmldesigner/components/connectioneditor/connectionmodel.cpp b/src/plugins/qmldesigner/components/connectioneditor/connectionmodel.cpp index e25f14411e..97919fa4fe 100644 --- a/src/plugins/qmldesigner/components/connectioneditor/connectionmodel.cpp +++ b/src/plugins/qmldesigner/components/connectioneditor/connectionmodel.cpp @@ -309,6 +309,13 @@ ModelNode ConnectionModel::getTargetNodeForConnection(const ModelNode &connectio static QString addOnToSignalName(const QString &signal) { + if (signal.isEmpty()) + return {}; + + static const QRegularExpression rx("^on[A-Z]"); + if (rx.match(signal).hasMatch()) + return signal; + QString ret = signal; ret[0] = ret.at(0).toUpper(); ret.prepend("on"); @@ -361,11 +368,10 @@ void ConnectionModel::addConnection(const PropertyName &signalName) ModelNode selectedNode = connectionView()->selectedModelNodes().constFirst(); PropertyName signalHandlerName = signalName; - if (signalHandlerName.isEmpty()) { - signalHandlerName = addOnToSignalName(QString::fromUtf8(getFirstSignalForTarget( - selectedNode.metaInfo()))) - .toUtf8(); - } + if (signalHandlerName.isEmpty()) + signalHandlerName = getFirstSignalForTarget(selectedNode.metaInfo()); + + signalHandlerName = addOnToSignalName(QString::fromUtf8(signalHandlerName)).toUtf8(); connectionView() ->executeInTransaction("ConnectionModel::addConnection", [=, &rootModelNode]() { @@ -855,7 +861,7 @@ int ConnectionModelBackendDelegate::currentRow() const return m_currentRow; } -QString removeOnFromSignalName(const QString &signal) +static QString removeOnFromSignalName(const QString &signal) { if (signal.isEmpty()) return {}; diff --git a/src/plugins/qmldesigner/components/connectioneditor/propertytreemodel.cpp b/src/plugins/qmldesigner/components/connectioneditor/propertytreemodel.cpp index 2b1f53243a..4189496316 100644 --- a/src/plugins/qmldesigner/components/connectioneditor/propertytreemodel.cpp +++ b/src/plugins/qmldesigner/components/connectioneditor/propertytreemodel.cpp @@ -72,9 +72,7 @@ const std::vector<PropertyName> blockListSlots = {"childAt", "inputMethodQuery", "positionAt", "positionToRectangle", - "isRightToLeft" - -}; + "isRightToLeft"}; const std::vector<PropertyName> priorityListSignals = {"clicked", "doubleClicked", @@ -99,7 +97,8 @@ const std::vector<PropertyName> priorityListSignals = {"clicked", "enabledChanged", "visibleChanged", "opacityChanged", - "rotationChanged"}; + "rotationChanged", + "positionChanged"}; const std::vector<PropertyName> priorityListProperties = {"opacity", "checked", @@ -572,8 +571,7 @@ const std::vector<PropertyName> PropertyTreeModel::sortedAndFilteredPropertyName const PropertyName name = metaInfo.name(); - if (!m_includeDotPropertiesOnFirstLevel - && name.contains(".")) + if (!m_includeDotPropertiesOnFirstLevel && name.contains(".")) return false; return filterProperty(name, metaInfo, recursive); @@ -606,8 +604,8 @@ const std::vector<PropertyName> PropertyTreeModel::sortedAndFilteredPropertyName return checkedPriorityList; } -const std::vector<PropertyName> PropertyTreeModel::sortedAndFilteredSignalNames( - const NodeMetaInfo &metaInfo, bool recursive) const +std::vector<PropertyName> PropertyTreeModel::sortedAndFilteredSignalNames(const NodeMetaInfo &metaInfo, + bool recursive) { Q_UNUSED(recursive); @@ -627,15 +625,14 @@ const std::vector<PropertyName> PropertyTreeModel::sortedAndFilteredSignalNames( std::set<PropertyName> set(std::make_move_iterator(sorted.begin()), std::make_move_iterator(sorted.end())); - auto checkedPriorityList = Utils::filtered(priorityListSignals, - [&set](const PropertyName &name) { - auto it = set.find(name); - const bool b = it != set.end(); - if (b) - set.erase(it); + auto checkedPriorityList = Utils::filtered(priorityListSignals, [&set](const PropertyName &name) { + auto it = set.find(name); + const bool b = it != set.end(); + if (b) + set.erase(it); - return b; - }); + return b; + }); //const int priorityLength = checkedPriorityList.size(); We eventually require this to get the prioproperties @@ -648,8 +645,8 @@ const std::vector<PropertyName> PropertyTreeModel::sortedAndFilteredSignalNames( return checkedPriorityList; } -const std::vector<PropertyName> PropertyTreeModel::sortedAndFilteredSlotNames( - const NodeMetaInfo &metaInfo, bool recursive) const +std::vector<PropertyName> PropertyTreeModel::sortedAndFilteredSlotNames(const NodeMetaInfo &metaInfo, + bool recursive) { Q_UNUSED(recursive); diff --git a/src/plugins/qmldesigner/components/connectioneditor/propertytreemodel.h b/src/plugins/qmldesigner/components/connectioneditor/propertytreemodel.h index df17c112da..07e1401c4a 100644 --- a/src/plugins/qmldesigner/components/connectioneditor/propertytreemodel.h +++ b/src/plugins/qmldesigner/components/connectioneditor/propertytreemodel.h @@ -84,6 +84,12 @@ public: QHash<int, QByteArray> roleNames() const override; + static std::vector<PropertyName> sortedAndFilteredSignalNames(const NodeMetaInfo &metaInfo, + bool recursive = false); + + static std::vector<PropertyName> sortedAndFilteredSlotNames(const NodeMetaInfo &metaInfo, + bool recursive = false); + private: QModelIndex ensureModelIndex(const ModelNode &node, int row) const; QModelIndex ensureModelIndex(const ModelNode &node, const PropertyName &name, int row) const; @@ -94,15 +100,10 @@ private: const std::vector<PropertyName> getDynamicProperties(const ModelNode &modelNode) const; const std::vector<PropertyName> getDynamicSignals(const ModelNode &modelNode) const; + const std::vector<PropertyName> sortedAndFilteredPropertyNames(const NodeMetaInfo &metaInfo, bool recursive = false) const; - const std::vector<PropertyName> sortedAndFilteredSignalNames(const NodeMetaInfo &metaInfo, - bool recursive = false) const; - - const std::vector<PropertyName> sortedAndFilteredSlotNames(const NodeMetaInfo &metaInfo, - bool recursive = false) const; - const std::vector<PropertyName> sortedDotPropertyNames(const NodeMetaInfo &metaInfo, const PropertyName &propertyName) const; diff --git a/src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp b/src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp index 404a5f5730..496f0e4b2c 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp +++ b/src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp @@ -262,6 +262,27 @@ void FormEditorItem::setFrameColor(const QColor &color) update(); } +void FormEditorItem::setHasEffect(bool hasEffect) +{ + m_hasEffect = hasEffect; +} + +bool FormEditorItem::hasEffect() const +{ + return m_hasEffect; +} + +bool FormEditorItem::parentHasEffect() const +{ + FormEditorItem *pi = parentItem(); + while (pi) { + if (pi->hasEffect()) + return true; + pi = pi->parentItem(); + } + return false; +} + FormEditorItem::~FormEditorItem() { scene()->removeItemFromHash(this); @@ -421,7 +442,7 @@ void FormEditorItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, painter->setClipRegion(boundingRect().toRect()); painter->setClipping(true); - if (!hideCompletely) { + if (!hideCompletely && !parentHasEffect()) { if (showPlaceHolder) { if (scene()->showBoundingRects() && m_boundingRect.width() > 15 && m_boundingRect.height() > 15) paintPlaceHolderForInvisbleItem(painter); diff --git a/src/plugins/qmldesigner/components/formeditor/formeditoritem.h b/src/plugins/qmldesigner/components/formeditor/formeditoritem.h index 69b67d0006..b035699772 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditoritem.h +++ b/src/plugins/qmldesigner/components/formeditor/formeditoritem.h @@ -98,6 +98,10 @@ public: void setFrameColor(const QColor &color); + void setHasEffect(bool hasEffect); + bool hasEffect() const; + bool parentHasEffect() const; + protected: AbstractFormEditorTool* tool() const; void paintBoundingRect(QPainter *painter) const; @@ -129,6 +133,7 @@ private: // variables bool m_highlightBoundingRect; bool m_blurContent; bool m_isContentVisible; + bool m_hasEffect; }; class FormEditorFlowItem : public FormEditorItem diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp index 4b63d9ced8..fcc04ed026 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp +++ b/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp @@ -140,7 +140,7 @@ void FormEditorView::setupFormEditorItemTree(const QmlItemNode &qmlItemNode) setupFormEditorItemTree(childNode.toQmlItemNode()); } } - } else { + } else if (!qmlItemNode.isEffectItem()) { m_scene->addFormEditorItem(qmlItemNode, FormEditorScene::Default); for (const QmlObjectNode &nextNode : qmlItemNode.allDirectSubNodes()) //TODO instance children //If the node has source for components/custom parsers we ignore it. @@ -280,6 +280,13 @@ void FormEditorView::nodeAboutToBeRemoved(const ModelNode &removedNode) removeNodeFromScene(qmlItemNode); } +void FormEditorView::nodeRemoved(const ModelNode &/*removedNode*/, + const NodeAbstractProperty &/*parentProperty*/, + PropertyChangeFlags /*propertyChange*/) +{ + updateHasEffects(); +} + void FormEditorView::rootNodeTypeChanged(const QString &/*type*/, int /*majorVersion*/, int /*minorVersion*/) { const QList<FormEditorItem *> items = m_scene->allFormEditorItems(); @@ -343,6 +350,8 @@ static inline bool hasNodeSourceOrNonItemParent(const ModelNode &node) void FormEditorView::nodeReparented(const ModelNode &node, const NodeAbstractProperty &/*newPropertyParent*/, const NodeAbstractProperty &/*oldPropertyParent*/, AbstractView::PropertyChangeFlags /*propertyChange*/) { addOrRemoveFormEditorItem(node); + + updateHasEffects(); } void FormEditorView::nodeSourceChanged(const ModelNode &node, @@ -830,6 +839,8 @@ void FormEditorView::setupFormEditorWidget() m_formEditorWidget->showWarningMessageBox(rewriterView()->warnings()); checkRootModelNode(); + + updateHasEffects(); } QmlItemNode findRecursiveQmlItemNode(const QmlObjectNode &firstQmlObjectNode) @@ -991,6 +1002,23 @@ void FormEditorView::setupRootItemSize() } } +void FormEditorView::updateHasEffects() +{ + if (model()) { + const QList<ModelNode> nodes = allModelNodes(); + for (const auto &node : nodes) { + QmlItemNode qmlNode(node); + FormEditorItem *item = m_scene->itemForQmlItemNode(qmlNode); + if (item) + item->setHasEffect(false); + if (qmlNode.isEffectItem()) { + FormEditorItem *parentItem = m_scene->itemForQmlItemNode(qmlNode.modelParentItem()); + parentItem->setHasEffect(true); + } + } + } +} + void FormEditorView::reset() { QTimer::singleShot(200, this, &FormEditorView::delayedReset); diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorview.h b/src/plugins/qmldesigner/components/formeditor/formeditorview.h index 1a9f15d016..d3c6cb21db 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorview.h +++ b/src/plugins/qmldesigner/components/formeditor/formeditorview.h @@ -52,6 +52,8 @@ public: void nodeCreated(const ModelNode &createdNode) override; void nodeAboutToBeRemoved(const ModelNode &removedNode) override; + void nodeRemoved(const ModelNode &removedNode, const NodeAbstractProperty &parentProperty, + PropertyChangeFlags propertyChange) override; void nodeReparented(const ModelNode &node, const NodeAbstractProperty &newPropertyParent, const NodeAbstractProperty &oldPropertyParent, AbstractView::PropertyChangeFlags propertyChange) override; void nodeSourceChanged(const ModelNode &node, const QString &newNodeSource) override; void nodeIdChanged(const ModelNode& node, const QString& newId, const QString& oldId) override; @@ -138,6 +140,7 @@ private: void checkRootModelNode(); void setupFormEditor3DView(); void setupRootItemSize(); + void updateHasEffects(); QPointer<FormEditorWidget> m_formEditorWidget; QPointer<FormEditorScene> m_scene; diff --git a/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp index ff0fa2ab9f..67043f02d1 100644 --- a/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp +++ b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp @@ -149,6 +149,14 @@ WorkspaceModel::WorkspaceModel(QObject *) }; if (!connectDockManager()) connect(designModeWidget(), &Internal::DesignModeWidget::initialized, this, connectDockManager); + + connect(ProjectExplorer::ProjectManager::instance(), + &ProjectExplorer::ProjectManager::projectFinishedParsing, + this, + [this]() { + beginResetModel(); + endResetModel(); + }); } int WorkspaceModel::rowCount(const QModelIndex &) const @@ -162,7 +170,8 @@ int WorkspaceModel::rowCount(const QModelIndex &) const QHash<int, QByteArray> WorkspaceModel::roleNames() const { static QHash<int, QByteArray> roleNames{{DisplayNameRole, "displayName"}, - {FileNameRole, "fileName"}}; + {FileNameRole, "fileName"}, + {Enabled, "enabled"}}; return roleNames; } @@ -176,6 +185,9 @@ QVariant WorkspaceModel::data(const QModelIndex &index, int role) const return workspace.name(); } else if (role == FileNameRole) { return workspace.fileName(); + } else if (role == Enabled) { + if (QmlProjectManager::QmlProject::isMCUs()) + return workspace.isMcusEnabled(); } else { qWarning() << Q_FUNC_INFO << "invalid role"; } diff --git a/src/plugins/qmldesigner/components/toolbar/toolbarbackend.h b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.h index 307704d63a..eb258f9ab7 100644 --- a/src/plugins/qmldesigner/components/toolbar/toolbarbackend.h +++ b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.h @@ -29,7 +29,8 @@ public: class WorkspaceModel : public QAbstractListModel { Q_OBJECT - enum { DisplayNameRole = Qt::DisplayRole, FileNameRole = Qt::UserRole }; + + enum { DisplayNameRole = Qt::DisplayRole, FileNameRole = Qt::UserRole, Enabled }; public: explicit WorkspaceModel(QObject *parent = nullptr); diff --git a/src/plugins/qmldesigner/designercore/include/qmlitemnode.h b/src/plugins/qmldesigner/designercore/include/qmlitemnode.h index 5816d60ce1..5948ec7ab1 100644 --- a/src/plugins/qmldesigner/designercore/include/qmlitemnode.h +++ b/src/plugins/qmldesigner/designercore/include/qmlitemnode.h @@ -139,6 +139,8 @@ public: bool isFlowActionArea() const; ModelNode rootModelNode() const; + bool isEffectItem() const; + friend auto qHash(const QmlItemNode &node) { return qHash(node.modelNode()); } }; diff --git a/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp b/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp index 0ce155ca6b..e01bdaaec3 100644 --- a/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp +++ b/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp @@ -182,14 +182,19 @@ QmlItemNode QmlItemNode::createQmlItemNodeForEffect(AbstractView *view, const QString effectName = QFileInfo(effectPath).baseName(); Import import = Import::createLibraryImport("Effects." + effectName, "1.0"); try { - if (!view->model()->hasImport(import, true, true)) + if (!view->model()->hasImport(import, true, true)) { view->model()->changeImports({import}, {}); + // Trigger async reset puppet to ensure full transaction is done before reset + view->resetPuppet(); + } } catch (const Exception &) { QTC_ASSERT(false, return); } TypeName type(effectName.toUtf8()); - newQmlItemNode = QmlItemNode(view->createModelNode(type, -1, -1)); + ModelNode newModelNode = view->createModelNode(type, -1, -1); + newModelNode.setIdWithoutRefactoring(view->model()->generateNewId(effectName)); + newQmlItemNode = QmlItemNode(newModelNode); placeEffectNode(parentProperty, newQmlItemNode, isLayerEffect); }; @@ -206,12 +211,8 @@ void QmlItemNode::placeEffectNode(NodeAbstractProperty &parentProperty, const Qm parentProperty.reparentHere(effectNode); - if (!isLayerEffect) { - effectNode.modelNode().bindingProperty("source").setExpression("parent"); - effectNode.modelNode().bindingProperty("anchors.fill").setExpression("parent"); - } else { + if (isLayerEffect) parentProperty.parentModelNode().variantProperty("layer.enabled").setValue(true); - } if (effectNode.modelNode().metaInfo().hasProperty("timeRunning")) effectNode.modelNode().variantProperty("timeRunning").setValue(true); @@ -617,6 +618,11 @@ ModelNode QmlItemNode::rootModelNode() const return {}; } +bool QmlItemNode::isEffectItem() const +{ + return modelNode().metaInfo().hasProperty("_isEffectItem"); +} + void QmlItemNode::setSize(const QSizeF &size) { if (!hasBindingProperty("width") && !(anchors().instanceHasAnchor(AnchorLineRight) diff --git a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp index 889f847197..037259e87e 100644 --- a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp +++ b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp @@ -388,6 +388,7 @@ bool smartVeryFuzzyCompare(const QVariant &value1, const QVariant &value2) void removeModelNode(const QmlDesigner::ModelNode &modelNode) { + QTC_ASSERT(modelNode.isValid(), return ); modelNode.model()->removeModelNodes({modelNode}, QmlDesigner::BypassModelResourceManagement::Yes); } @@ -400,6 +401,7 @@ bool smartColorCompare(const QVariant &value1, const QVariant &value2) void removeProperty(const QmlDesigner::AbstractProperty &modelProperty) { + QTC_ASSERT(modelProperty.isValid(), return ); modelProperty.model()->removeProperties({modelProperty}, QmlDesigner::BypassModelResourceManagement::Yes); } diff --git a/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.cpp b/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.cpp index b7f6d2ae55..f9eb8080f7 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.cpp +++ b/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.cpp @@ -294,10 +294,16 @@ Storage::Synchronization::Type QmlDocumentParser::parse(const QString &sourceCon QString filePath{m_pathCache.sourcePath(sourceId)}; environment.loadFile( +#if QT_VERSION < QT_VERSION_CHECK(6, 6, 0) filePath, filePath, sourceContent, QDateTime{}, +#else + QQmlJS::Dom::FileToLoad::fromMemory(environment.ownerAs<QQmlJS::Dom::DomEnvironment>(), + filePath, + sourceContent), +#endif [&](QmlDom::Path, const QmlDom::DomItem &, const QmlDom::DomItem &newItems) { items = newItems; }, diff --git a/src/plugins/qmldesigner/designmodewidget.cpp b/src/plugins/qmldesigner/designmodewidget.cpp index a8567dec38..a26eada911 100644 --- a/src/plugins/qmldesigner/designmodewidget.cpp +++ b/src/plugins/qmldesigner/designmodewidget.cpp @@ -34,6 +34,7 @@ #include <coreplugin/idocument.h> #include <coreplugin/inavigationwidgetfactory.h> +#include <projectexplorer/projectmanager.h> #include <qmlprojectmanager/qmlproject.h> #include <utils/algorithm.h> @@ -219,6 +220,13 @@ void DesignModeWidget::setup() QString sheet = QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/dockwidgets.css")); m_dockManager->setStyleSheet(Theme::replaceCssColors(sheet)); + connect(ProjectExplorer::ProjectManager::instance(), + &ProjectExplorer::ProjectManager::projectFinishedParsing, + m_dockManager, + [this]() { + this->m_dockManager->setMcusProject(QmlProjectManager::QmlProject::isMCUs()); + }); + // Setup icons const QString closeUnicode = Theme::getIconUnicode(Theme::Icon::close_small); const QString maximizeUnicode = Theme::getIconUnicode(Theme::Icon::maxBar_small); @@ -273,6 +281,7 @@ void DesignModeWidget::setup() Core::ActionContainer *mview = Core::ActionManager::actionContainer(Core::Constants::M_VIEW); // View > Views Core::ActionContainer *mviews = Core::ActionManager::createMenu(Core::Constants::M_VIEW_VIEWS); + connect(mviews->menu(), &QMenu::aboutToShow, this, &DesignModeWidget::aboutToShowViews); mviews->menu()->addSeparator(); // View > Workspaces Core::ActionContainer *mworkspaces = Core::ActionManager::createMenu(QmlDesigner::Constants::M_VIEW_WORKSPACES); @@ -482,6 +491,29 @@ void DesignModeWidget::setup() show(); } +static bool isMcuDisabledView(const QString viewId) +{ + static const QStringList mcuDisabledViews = {"Editor3D", "MaterialEditor", "MaterialBrowser", "TextureEditor"}; + return mcuDisabledViews.contains(viewId); +} + +void DesignModeWidget::aboutToShowViews() +{ + for (const WidgetInfo &widgetInfo : viewManager().widgetInfos()) { + QString id = widgetInfo.uniqueId; + ADS::DockWidget *dockWidget = m_dockManager->findDockWidget(id); + QAction *action = dockWidget->toggleViewAction(); + + bool isMcuProject = currentDesignDocument() && currentDesignDocument()->isQtForMCUsProject(); + if (isMcuProject && isMcuDisabledView(id) && action->isEnabled()) { + action->setChecked(false); + action->setEnabled(false); + } else if (!isMcuProject && !action->isEnabled()) { + action->setEnabled(true); + } + } +} + void DesignModeWidget::aboutToShowWorkspaces() { Core::ActionContainer *aci = Core::ActionManager::actionContainer( @@ -520,6 +552,9 @@ void DesignModeWidget::aboutToShowWorkspaces() action->setCheckable(true); if (workspace == *m_dockManager->activeWorkspace()) action->setChecked(true); + + if (currentDesignDocument() && currentDesignDocument()->isQtForMCUsProject()) + action->setEnabled(workspace.isMcusEnabled()); } menu->addActions(ag->actions()); } diff --git a/src/plugins/qmldesigner/designmodewidget.h b/src/plugins/qmldesigner/designmodewidget.h index 432549e694..464994b7e3 100644 --- a/src/plugins/qmldesigner/designmodewidget.h +++ b/src/plugins/qmldesigner/designmodewidget.h @@ -93,6 +93,7 @@ private: QWidget *createCenterWidget(); QWidget *createCrumbleBarFrame(); + void aboutToShowViews(); void aboutToShowWorkspaces(); QPointer<QWidget> m_bottomSideBar; diff --git a/src/plugins/qmlprojectmanager/qmlproject.cpp b/src/plugins/qmlprojectmanager/qmlproject.cpp index 0acba25ded..62a2d7bdfc 100644 --- a/src/plugins/qmlprojectmanager/qmlproject.cpp +++ b/src/plugins/qmlprojectmanager/qmlproject.cpp @@ -238,4 +238,17 @@ bool QmlProject::allowOnlySingleProject() return !settings->value(key, false).toBool(); } +bool QmlProject::isMCUs() +{ + if (!ProjectExplorer::ProjectManager::startupTarget()) + return false; + + const QmlProjectManager::QmlBuildSystem *buildSystem + = qobject_cast<QmlProjectManager::QmlBuildSystem *>( + ProjectExplorer::ProjectManager::startupTarget()->buildSystem()); + QTC_ASSERT(buildSystem, return false); + + return buildSystem && buildSystem->qtForMCUs(); +} + } // namespace QmlProjectManager diff --git a/src/plugins/qmlprojectmanager/qmlproject.h b/src/plugins/qmlprojectmanager/qmlproject.h index a41b05e57b..0091d77d6c 100644 --- a/src/plugins/qmlprojectmanager/qmlproject.h +++ b/src/plugins/qmlprojectmanager/qmlproject.h @@ -24,6 +24,8 @@ public: ProjectExplorer::Tasks projectIssues(const ProjectExplorer::Kit *k) const final; + static bool isMCUs(); + protected: RestoreResult fromMap(const Utils::Store &map, QString *errorMessage) override; diff --git a/src/plugins/qtsupport/baseqtversion.cpp b/src/plugins/qtsupport/baseqtversion.cpp index fb28d16aa3..da669423e3 100644 --- a/src/plugins/qtsupport/baseqtversion.cpp +++ b/src/plugins/qtsupport/baseqtversion.cpp @@ -77,7 +77,7 @@ class QtVersionData { public: // Update version if you add data members! - static const int version = 2; + static const int version = 3; bool installed = true; bool hasExamples = false; @@ -203,8 +203,11 @@ public: hostDataPath = FilePath::fromSettings(map.value("HostDataPath")); hostPrefixPath = FilePath::fromSettings(map.value("HostPrefixPath")); auto it = map.find("QtAbis"); - if (it != map.end()) - qtAbis = Utils::transform(it.value().toStringList(), &Abi::fromString); + if (it != map.end()) { + const auto qtAbisList = it.value().toStringList(); + if (!qtAbisList.isEmpty()) + qtAbis = Utils::transform(qtAbisList, &Abi::fromString); + } versionInfo = fromStore(map.value("VersionInfo").value<Store>()); } }; diff --git a/src/plugins/studiowelcome/studiowelcomeplugin.cpp b/src/plugins/studiowelcome/studiowelcomeplugin.cpp index b48d87121f..c80b64601b 100644 --- a/src/plugins/studiowelcome/studiowelcomeplugin.cpp +++ b/src/plugins/studiowelcome/studiowelcomeplugin.cpp @@ -759,7 +759,8 @@ WelcomeMode::WelcomeMode() m_dataModelDownloader->setForceDownload(true); connect(m_dataModelDownloader, &DataModelDownloader::progressChanged, this, [this](){ - m_quickWidget->rootObject()->setProperty("loadingProgress", m_dataModelDownloader->progress()); + if (m_quickWidget->rootObject()) + m_quickWidget->rootObject()->setProperty("loadingProgress", m_dataModelDownloader->progress()); }); connect(m_dataModelDownloader, &DataModelDownloader::finished, this, [this, welcomePagePath]() { |