diff --git a/cmake/QtCreatorAPI.cmake b/cmake/QtCreatorAPI.cmake index c417d3ab9eb..df497f70e93 100644 --- a/cmake/QtCreatorAPI.cmake +++ b/cmake/QtCreatorAPI.cmake @@ -94,7 +94,7 @@ function(qtc_output_binary_dir varName) endfunction() function(add_qtc_library name) - cmake_parse_arguments(_arg "STATIC;OBJECT;SKIP_TRANSLATION;ALLOW_ASCII_CASTS;UNVERSIONED" + cmake_parse_arguments(_arg "STATIC;OBJECT;SKIP_TRANSLATION;ALLOW_ASCII_CASTS;UNVERSIONED;FEATURE_INFO" "DESTINATION;COMPONENT;SOURCES_PREFIX;BUILD_DEFAULT" "CONDITION;DEPENDS;PUBLIC_DEPENDS;DEFINES;PUBLIC_DEFINES;INCLUDES;PUBLIC_INCLUDES;SOURCES;EXPLICIT_MOC;SKIP_AUTOMOC;EXTRA_TRANSLATIONS;PROPERTIES" ${ARGN} ) @@ -110,6 +110,7 @@ function(add_qtc_library name) update_cached_list(__QTC_LIBRARIES "${name}") + condition_info(_extra_text _arg_CONDITION) if (NOT _arg_CONDITION) set(_arg_CONDITION ON) endif() @@ -131,6 +132,9 @@ function(add_qtc_library name) set(_library_enabled OFF) endif() + if(DEFINED _arg_FEATURE_INFO) + add_feature_info("Library ${name}" _library_enabled "${_extra_text}") + endif() if (NOT _library_enabled) return() endif() diff --git a/doc/qtcreator/images/qmldesigner-form-editor-move-cursor.png b/doc/qtcreator/images/qmldesigner-form-editor-move-cursor.png new file mode 100644 index 00000000000..5aa3a6c3fbb Binary files /dev/null and b/doc/qtcreator/images/qmldesigner-form-editor-move-cursor.png differ diff --git a/doc/qtcreator/images/qmldesigner-form-editor.png b/doc/qtcreator/images/qmldesigner-form-editor.png index 5aa3a6c3fbb..b042afe44e7 100644 Binary files a/doc/qtcreator/images/qmldesigner-form-editor.png and b/doc/qtcreator/images/qmldesigner-form-editor.png differ diff --git a/doc/qtcreator/images/qmldesigner-transition-editor-startup.png b/doc/qtcreator/images/qmldesigner-transition-editor-startup.png new file mode 100644 index 00000000000..d269470e0d0 Binary files /dev/null and b/doc/qtcreator/images/qmldesigner-transition-editor-startup.png differ diff --git a/doc/qtcreator/images/qtquick-transition-editor-settings.png b/doc/qtcreator/images/qtquick-transition-editor-settings.png index 6fb41716127..a0fef65a51a 100644 Binary files a/doc/qtcreator/images/qtquick-transition-editor-settings.png and b/doc/qtcreator/images/qtquick-transition-editor-settings.png differ diff --git a/doc/qtcreator/images/qtquick-transition-editor-view.png b/doc/qtcreator/images/qtquick-transition-editor-view.png index 406b540135f..3d747783af5 100644 Binary files a/doc/qtcreator/images/qtquick-transition-editor-view.png and b/doc/qtcreator/images/qtquick-transition-editor-view.png differ diff --git a/doc/qtcreator/src/qtcreator-toc.qdoc b/doc/qtcreator/src/qtcreator-toc.qdoc index 055a093b302..4ea17f3dd78 100644 --- a/doc/qtcreator/src/qtcreator-toc.qdoc +++ b/doc/qtcreator/src/qtcreator-toc.qdoc @@ -96,6 +96,7 @@ \li \l{Library} \li \l{Navigator} \li \l{Properties} + \li \l{Transition Editor} \endlist \li \l {Creating UIs} \list diff --git a/doc/qtcreator/src/qtquick/qtquick-designer.qdoc b/doc/qtcreator/src/qtquick/qtquick-designer.qdoc index 90287f9a7ca..43966d926c9 100644 --- a/doc/qtcreator/src/qtquick/qtquick-designer.qdoc +++ b/doc/qtcreator/src/qtquick/qtquick-designer.qdoc @@ -101,7 +101,7 @@ actions. \li \l{Adding States} \row - \li \l{Animating Transitions Between States}{Transition Editor} + \li \l{Transition Editor} \li Enables you to make movement between states smooth by animating the changes between states. \li \l{Animating Transitions Between States} diff --git a/doc/qtcreator/src/qtquick/qtquick-form-editor.qdoc b/doc/qtcreator/src/qtquick/qtquick-form-editor.qdoc index e93be2f583f..12aa6187b0a 100644 --- a/doc/qtcreator/src/qtquick/qtquick-form-editor.qdoc +++ b/doc/qtcreator/src/qtquick/qtquick-form-editor.qdoc @@ -33,47 +33,129 @@ You design applications in the \uicontrol {Form Editor} view by placing \l{Component Types}{2D components} and \l{Assets}{assets} into it. - When you select items in \uicontrol {Form Editor}, markers - appear around their edges and in their corners. Depending on the shape of - the cursor, you can move, resize, or rotate the item by dragging it. - The following image shows the move cursor. - \image qmldesigner-form-editor.png "Form Editor view" - \section1 Resizing 2D Items + When you select components in \uicontrol {Form Editor}, markers appear + around their edges and in their corners. Depending on the shape of the + cursor, you can apply the following actions on the components by dragging + them: - When the resize cursor is displayed, you can drag the selection handles - to resize items. + \list + \li \l{Moving Components}{Move components} + \li \l{Resizing 2D Components}{Resize components} + \li \l{Rotating 2D Components}{Rotate components} + \endlist + + \section1 Summary of Form Editor Buttons + + The \uicontrol {Form Editor} toolbar contains the following buttons and + fields. + + \table + \header + \li Button/Field + \li Tooltip + \li Read More + \row + \li \inlineimage no_snapping.png + \li Disables snapping. + \li \l{Snapping to Parent and Sibling Components} + \row + \li \inlineimage snapping_and_anchoring.png + \li Anchors the component to the components that it is snapped to. + \li \l{Snapping to Parent and Sibling Components} + \row + \li \inlineimage snapping.png + \li Snaps components to their parent or sibling components when you + align them. + \li \l{Snapping to Parent and Sibling Components} + \row + \li \inlineimage boundingrect.png + \li Hides and shows component boundaries. + \li \l{Hiding Component Boundaries} + \row + \li \uicontrol {Override Width} + \li Shows a preview of the component using the specified width. + \li \l{Previewing Component Size} + \row + \li \uicontrol {Override Height} + \li Shows a preview of the component using the specified height. + \li \l{Previewing Component Size} + \row + \li \inlineimage icons/canvas-color.png + \li Sets the color of the \uicontrol {Form Editor} working area. + \li \l{Setting Canvas Color} + \row + \li \inlineimage icons/zoomIn.png + \li Zooms in. + \li \l{Zooming} + \row + \li \inlineimage icons/zoomOut.png + \li Zooms out. + \li \l{Zooming} + \row + \li Zoom level + \li Sets the zoom level that you select from the list. + \li \l{Zooming} + \row + \li \inlineimage icons/zoomAll.png + \li Zooms to fit all content. + \li \l{Zooming} + \row + \li \inlineimage icons/zoomSelection.png + \li Zooms to fit the current selection. + \li \l{Zooming} + \row + \li \inlineimage reset.png + \li Refreshes the contents of \uicontrol {Form Editor}. + \li \l{Refreshing Form Editor Contents} + \endtable + + \section1 Moving Components + + When the move cursor is displayed, you can move the selected component to + any position in \uicontrol {Form Editor}. + + \image qmldesigner-form-editor-move-cursor.png "Move cursor in Form Editor view" + + For more information about alternative ways of positioning components in + UIs, see \l{Positioning Items}. + + \section1 Resizing 2D Components + + When the resize cursor is displayed, you can drag the markers to resize + components. \image qtquick-designer-scaling-items.png "Form Editor view" - \if defined(qtdesignstudio) - To have the resizing done from the center of the selected item instead from - its edges, press \key Alt. + To have the resizing done from the center of the selected component rather + than from its edges, press \key Alt (or the option key on \macos). To preserve the image aspect ratio while resizing when using the corner - handles, press \key Shift. This also works on items that are anchored + markers, press \key Shift. This also works on components that are anchored using left, right, top, or bottom anchors. - To both resize from the center of the item and preserve the aspect ratio, - press \key Alt+Shift. - \endif + To both resize from the center of the component and preserve the aspect + ratio, press \key Alt+Shift (or the option key + \key Shift on \macos). - \section1 Rotating 2D Items + For more information about alternative ways to specify the size of a + component in a UI, see \l{2D Geometry}. + + \section1 Rotating 2D Components When the rotation cursor \inlineimage icons/rotation-cursor.png - is displayed in one of the corners of an item, you can drag - clockwise or counter-clockwise to freely rotate the item around - its origin in \uicontrol {Form Editor}. + is displayed in one of the corners of a component, you can drag + clockwise or counter-clockwise to freely rotate the component around + its origin. \image qtquick-designer-rotating-items.png "2D rotation tool" - Additionally, press \key Shift or \key Alt to rotate items in steps of 5 or - 45 degrees, respectively. + Additionally, press \key Shift or \key Alt (or the option key on \macos) + to rotate components in steps of 5 or 45 degrees, respectively. You can set the \l{Managing 2D Transformations}{origin} in the \uicontrol Origin field in the \uicontrol Advanced tab in the - \uicontrol Properties view. There, you can also enter the value + \l Properties view. There, you can also enter the value of the \uicontrol Rotation property in degrees. \section1 Zooming @@ -85,43 +167,23 @@ \image qmldesigner-zooming.gif "Zooming in Form Editor" - The following table lists the zoom buttons: + \section1 Snapping to Parent and Sibling Components - \table - \header - \li Icon - \li Tooltip - \row - \li \inlineimage icons/zoomIn.png - \li Zoom in - \row - \li \inlineimage icons/zoomOut.png - \li Zoom out - \row - \li \inlineimage icons/zoomAll.png - \li Zoom to fit all content - \row - \li \inlineimage icons/zoomSelection.png - \li Zoom to fit the current selection - \endtable - - \section1 Snapping to Parent and Sibling Items - - When you are working on a design, you can use snapping to align - items in \uicontrol {Form Editor}. Click the \inlineimage snapping.png - button to have the items snap to their parent or sibling items. Snapping - lines automatically appear to help you position the items. + You can use snapping to align components in \uicontrol {Form Editor}. + Click the \inlineimage snapping.png + button to have the components snap to their parent or sibling components. + Snapping lines automatically appear to help you position the components. Click the \inlineimage snapping_and_anchoring.png - button to anchor the item to the items that you snap to. + button to anchor the component to the components that you snap to. Only one snapping button can be selected at the time. Selecting one snapping button automatically deselects the others. Choose \uicontrol Tools > \uicontrol Options > \uicontrol {Qt Quick} > \uicontrol {Qt Quick Designer} to specify settings for snapping. In the \uicontrol {Parent item padding} field, specify the - distance in pixels between the parent item and the snapping lines. In the - \uicontrol {Sibling item spacing} field, specify the distance in pixels between - sibling items and the snapping lines. + distance in pixels between the parent component and the snapping lines. In + the \uicontrol {Sibling item spacing} field, specify the distance in pixels + between sibling components and the snapping lines. \image qtquick-designer-options.png "Qt Quick Designer options" @@ -130,33 +192,36 @@ \image qmldesigner-snap-margins.png "Snapping lines on canvas" - \section1 Hiding Item Boundaries + For alternative ways of aligning and distributing components by using the + \l Properties view, see \l{Aligning and Distributing Items}. - \uicontrol {Form Editor} displays the boundaries of items. + \section1 Hiding Component Boundaries + + \uicontrol {Form Editor} displays the boundaries of components. To hide them, select the \inlineimage boundingrect.png button. \section1 Previewing Component Size - The width and height of the root item in a QML file determine the size of - the component. You can reuse components, such as buttons, in different - sizes in other QML files and design UIs for use with different device + The width and height of the root component in a UI file determine the size + of the component. You can reuse components, such as buttons, in different + sizes in other UI files and design UIs for use with different device profiles, screen resolution, or screen orientation. The component size - might also be zero (0,0) if its final size is determined by property - bindings. + might also be zero (0,0) if its final size is determined by + \l{Setting Bindings}{property bindings}. To experiment with different component sizes, enter values in the \uicontrol {Override Width} and \uicontrol {Override Height} fields (1) on - the canvas toolbar. The changes are displayed in the \uicontrol {Form Editor} + the toolbar. The changes are displayed in the \uicontrol {Form Editor} view (2) and in the \uicontrol States view (3), but the property - values are not changed permanently in the QML file. You can permanently + values are not changed permanently in the UI file. You can permanently change the property values in the \uicontrol Properties view (4). - \image qmldesigner-preview-size.png "Canvas width and height" + \image qmldesigner-preview-size.png "Component width and height" - To set the initial size of the root item, select \uicontrol Tools > + To set the initial size of the root component, select \uicontrol Tools > \uicontrol Options > \uicontrol {Qt Quick} > \uicontrol {Qt Quick Designer} and - specify the item width and height in the \uicontrol {Root Item Init Size} + specify the component width and height in the \uicontrol {Root Item Init Size} group. \section1 Specifying Canvas Size @@ -167,8 +232,8 @@ \section1 Setting Canvas Color - If you set the background of the root item of your component transparent, - the canvas color can make it difficult to see the component you are working + If you set the background of the root component transparent, the color of + the working area can make it difficult to see the component you are working on. To make components more visible, you can select the canvas color in the \inlineimage icons/canvas-color.png list. By default, the color is transparent. Setting the canvas color does @@ -176,13 +241,14 @@ \image qmldesigner-canvas-color.png "Transparent canvas color for a transparent component" - \section1 Refreshing the Form Editor Contents + \section1 Refreshing Form Editor Contents - When you open QML files in the Design mode, the items in the file are drawn - in \uicontrol {Form Editor}. When you edit the item properties, the QML - file and the contents of the editor might get out of sync. For example, when - you change the position of an item within a column or a row, the new - position might not be displayed correctly in \uicontrol {Form Editor}. + When you open a UI file, the components in the file are drawn in + \uicontrol {Form Editor}. When you edit component properties in + \l Properties, the code and its representation in \uicontrol {Form Editor} + might get out of sync. For example, when you change the position of a + component within a column or a row, the new position might not be displayed + correctly in \uicontrol {Form Editor}. To refresh the contents of \uicontrol {Form Editor}, press \key R or select the \inlineimage reset.png diff --git a/doc/qtcreator/src/qtquick/qtquick-properties.qdoc b/doc/qtcreator/src/qtquick/qtquick-properties.qdoc index 5bfd3d4a11f..56329f11f0c 100644 --- a/doc/qtcreator/src/qtquick/qtquick-properties.qdoc +++ b/doc/qtcreator/src/qtquick/qtquick-properties.qdoc @@ -71,7 +71,7 @@ The value of the \uicontrol {Custom ID} field specifies the name of an \l{Annotating Designs}{annotation}. - \section2 Geometry + \section2 2D Geometry In the \uicontrol Position group, you can set the position of a component on the x and y axis. The position of a component in the UI can be either @@ -83,7 +83,7 @@ it in the \uicontrol Z field in the \uicontrol Advanced tab. In the \uicontrol Size group, you can set the width and height of a - component. You can also use the resize cursor to \l{Resizing 2D Items} + component. You can also use the resize cursor to \l{Resizing 2D Components} {resize 2D components} in \uicontrol {Form Editor} or the scaling gizmo to \l{Scaling Items}{scale 3D components} in \uicontrol {3D Editor}. The values in the \uicontrol X and \uicontrol Y fields change accordingly. diff --git a/doc/qtcreator/src/qtquick/qtquick-states.qdoc b/doc/qtcreator/src/qtquick/qtquick-states.qdoc index 9dc2867e28b..f4ed8940e14 100644 --- a/doc/qtcreator/src/qtquick/qtquick-states.qdoc +++ b/doc/qtcreator/src/qtquick/qtquick-states.qdoc @@ -61,6 +61,8 @@ \li Show a different view. \endlist + You can animate transitions between states in \l{Transition Editor}. + \section1 Creating States To open the \uicontrol States view, select \uicontrol View > @@ -208,6 +210,4 @@ \if defined(qtcreator) \include qtquick-states-scxml.qdocinc scxml state machines \endif - - \include qtquick-transition-editor.qdocinc transition editor */ diff --git a/doc/qtcreator/src/qtquick/qtquick-transition-editor.qdoc b/doc/qtcreator/src/qtquick/qtquick-transition-editor.qdoc new file mode 100644 index 00000000000..12ade5c3c4b --- /dev/null +++ b/doc/qtcreator/src/qtquick/qtquick-transition-editor.qdoc @@ -0,0 +1,143 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Creator documentation. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** +****************************************************************************/ + +/*! + \page qtquick-transition-editor.html + \previouspage qtquick-states-view.html + \nextpage qtquick-timeline-view.html + + \title Transition Editor + + To make movement between states smooth, you can use + \uicontrol {Transition Editor} to animate the changes between + states. + + First, you need to \l{Adding States}{add states} in the \l States view + and \l{Specifying Component Properties}{edit some properties} that can be + animated, such as colors or numbers, in the \l Properties view. For example, + you can animate the changes in the position of a component. + + \image qtquick-transition-editor-view.png "Transition Editor view" + + In \uicontrol {Transition Editor}, you can set the start frame, end + frame, and duration for the transition of each property. You can also + set an \l{Editing Easing Curves}{easing curve} for each animation and + the maximum duration of the whole transition. + + \section1 Zooming in Transition Editor + + Use the slider on the toolbar to set the zooming level in + \uicontrol {Transition Editor}. Select the \inlineimage zoom_small.png + and \inlineimage zoom_big.png + buttons to zoom out of or into the view. + + \section1 Summary of Transition Editor Toolbar Actions + + \table + \header + \li Button/Field + \li Action + \li Read More + \row + \li \inlineimage animation.png + \li Opens \uicontrol {Transition Settings} dialog for editing + transition settings. + \li \l{Specifying Transition Settings} + \row + \li Transition ID + \li Displays a list of transitions that you can open in + \uicontrol {Transition Editor}. + \li \l{Animating Transitions Between States} + \row + \li \inlineimage curve_editor.png + \li Opens \uicontrol {Easing Curve Editor} for attaching an easing + curve to the selected transition. + \li \l{Editing Easing Curves} + \row + \li \inlineimage zoom_small.png + \li \uicontrol {Zoom Out} (\key Ctrl+-): zooms out of the view. + \li \l{Zooming in Transition Editor} + \row + \li Slider + \li Sets the zooming level. + \li \l{Zooming in Transition Editor} + \row + \li \inlineimage zoom_big.png + \li \uicontrol {Zoom In} (\key Ctrl++): zooms into the view. + \li \l{Zooming in Transition Editor} + \row + \li Maximum Duration + \li Specifies the maximum duration of the transition. + \li + \endtable + + \section1 Animating Transitions Between States + + To animate transitions: + + \list 1 + \li Select \uicontrol View > \uicontrol Views > + \uicontrol {Transition Editor}. + \image qmldesigner-transition-editor-startup.png "Empty Transition Editor" + \li Select the \inlineimage plus.png + (\uicontrol {Add Transition}) button to add a transition. This + works only if you have added at least one state and modified at + least one property in it. + \image qtquick-transition-editor-view.png "Transition Editor view" + \li Move the blue bar next to the component or property name to set + the start and end frame of the animation of the property. Pull its + left and right edges to set the duration of the animation. + \li To attach an \l{Editing Easing Curves}{easing curve} to the + selected transition, select the \inlineimage curve_editor.png + (\uicontrol {Easing Curve Editor (C)}) button. + \endlist + + \section1 Specifying Transition Settings + + To modify transition settings, select the \inlineimage animation.png + (\uicontrol {Transition Settings (S)}) button in + \uicontrol {Transition Editor}. + + \image qtquick-transition-editor-settings.png "Transition settings" + + To add transitions: + + \list 1 + \li Select the \inlineimage plus.png + (\uicontrol {Add Transition}) button. + \li In the \uicontrol {Transition ID} field, enter an ID for the + transition. + \li In the \uicontrol From field, select the state to transition from. + \li In the \uicontrol To field, select the state to transition to. + \endlist + + To remove the current transition, select the \inlineimage minus.png + (\uicontrol {Remove Transition}) button. + + \if defined(qtcreator) + For an example of animating transitions between states, see + \l {Creating a Qt Quick Application}. + \endif +*/ diff --git a/doc/qtcreator/src/qtquick/qtquick-transition-editor.qdocinc b/doc/qtcreator/src/qtquick/qtquick-transition-editor.qdocinc deleted file mode 100644 index ff20d84e22a..00000000000 --- a/doc/qtcreator/src/qtquick/qtquick-transition-editor.qdocinc +++ /dev/null @@ -1,73 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Creator documentation. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Free Documentation License Usage -** Alternatively, this file may be used under the terms of the GNU Free -** Documentation License version 1.3 as published by the Free Software -** Foundation and appearing in the file included in the packaging of -** this file. Please review the following information to ensure -** the GNU Free Documentation License version 1.3 requirements -** will be met: https://www.gnu.org/licenses/fdl-1.3.html. -** -****************************************************************************/ - -/*! -//! [transition editor] - - \section1 Animating Transitions Between States - - To make movement between states smooth, you can use - \uicontrol {Transition Editor} to animate the changes between - states. First, you need to \l{Creating States}{add states} in - the \uicontrol States view and \l{Specifying Component Properties} - {edit some properties} that can be animated, such as colors or - numbers, in the \uicontrol Properties view. For example, you - can animate the changes in the position of an object. - - In \uicontrol {Transition Editor}, you can set the start frame, end - frame, and duration for the transition of each property. You can also - set an easing curve for each transition. - - Use the slider on the menu bar to the zooming level in the view. - - To add transitions: - - \list 1 - \li Select \uicontrol View > \uicontrol Views > - \uicontrol {Transition Editor} to display the view. - \li Select the \inlineimage plus.png - (\uicontrol {Add Transition}) button to add a transition. This - works only if you have added at least one state and modified at - least one property in it. - \image qtquick-transition-editor-view.png "Transition Editor view" - \li Move the blue bar next to the component or property name to set - the start and end frame of the animation of the property. Pull its - left and right edges to set the duration of the animation. - \li To attach an easing curve to a transition, select - \inlineimage curve_editor.png - (\uicontrol {Easing Curve Editor (C)}) on the toolbar. For more - information, see \l{Editing Easing Curves}. - \li To modify transition settings, select the \inlineimage animation.png - (\uicontrol {Transition Settings (S)}) button on the toolbar. - \image qtquick-transition-editor-settings.png "Transition settings" - \endlist - - \if defined(qtcreator) - For an example of animating transitions between states, see - \l {Creating a Qt Quick Application}. - \endif - -//! [transition editor] -*/ diff --git a/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc index a0965261c6f..3fad0989341 100644 --- a/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc +++ b/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc @@ -62,6 +62,7 @@ \li \l{Library} \li \l{Navigator} \li \l{Properties} + \li \l{Transition Editor} \endlist \li \l{Managing Workspaces} \li \l{Managing Sessions} diff --git a/share/qtcreator/debugger/lldbbridge.py b/share/qtcreator/debugger/lldbbridge.py index d7311c4a6dd..e1e0222d02b 100644 --- a/share/qtcreator/debugger/lldbbridge.py +++ b/share/qtcreator/debugger/lldbbridge.py @@ -787,8 +787,6 @@ class Dumper(DumperBase): def removeTypePrefix(self, name): return re.sub('^(struct|class|union|enum|typedef) ', '', name) - __funcSignature_Regex__ = re.compile(r'^.+\(.*\)') - def lookupNativeType(self, name): #DumperBase.warn('LOOKUP TYPE NAME: %s' % name) typeobj = self.typeCache.get(name) @@ -809,7 +807,7 @@ class Dumper(DumperBase): # Note that specifying a prefix like enum or typedef or class will make the call fail to # find the type, thus the prefix is stripped. nonPrefixedName = self.canonicalTypeName(self.removeTypePrefix(name)) - if __funcSignature_Regex__.match(nonPrefixedName) is not None: + if re.match(r'^.+\(.*\)', nonPrefixedName) is not None: return lldb.SBType() typeobjlist = self.target.FindTypes(nonPrefixedName) @@ -851,7 +849,7 @@ class Dumper(DumperBase): def lookupNativeTypeInAllModules(self, name): needle = self.canonicalTypeName(name) #DumperBase.warn('NEEDLE: %s ' % needle) - self.warn('Searching for type %s across all target modules, this could be very slow' % name) + DumperBase.warn('Searching for type %s across all target modules, this could be very slow' % name) for i in range(self.target.GetNumModules()): module = self.target.GetModuleAtIndex(i) # SBModule.GetType is new somewhere after early 300.x diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/instances.pri b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/instances.pri index d0096f86609..81c00b796e0 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/instances.pri +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/instances.pri @@ -13,7 +13,6 @@ versionAtLeast(QT_VERSION, 5.15.0) { HEADERS += $$PWD/qt5nodeinstanceserver.h \ $$PWD/capturenodeinstanceserverdispatcher.h \ - $$PWD/capturescenecreatedcommand.h \ $$PWD/nodeinstanceserverdispatcher.h \ $$PWD/qt5captureimagenodeinstanceserver.h \ $$PWD/qt5capturepreviewnodeinstanceserver.h \ diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml index f7cf00d92c3..045398205db 100644 --- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml +++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml @@ -29,6 +29,9 @@ import QtQuickDesignerTheme 1.0 import HelperWidgets 2.0 Item { + id: delegateRoot + signal showContextMenu() + Rectangle { anchors.rightMargin: 1 anchors.topMargin: 1 @@ -71,11 +74,12 @@ Item { ImagePreviewTooltipArea { id: mouseRegion - anchors.fill: parent + onShowContextMenu: delegateRoot.showContextMenu() onPressed: { - rootView.startDragAndDrop(itemLibraryEntry) + if (mouse.button === Qt.LeftButton) + rootView.startDragAndDrop(itemLibraryEntry, mapToGlobal(mouse.x, mouse.y)) } } } diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml index 2f792372331..a93bc173a81 100644 --- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml +++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml @@ -77,11 +77,14 @@ ScrollView { id: itemsView property string importToRemove: "" + property string importToAdd: "" + property var currentItem: null // called from C++ to close context menu on focus out function closeContextMenu() { - contextMenu.close() + importContextMenu.close() + itemContextMenu.close() } Item { @@ -99,11 +102,11 @@ ScrollView { 2 * cellVerticalMargin + cellVerticalSpacing StudioControls.Menu { - id: contextMenu + id: importContextMenu StudioControls.MenuItem { text: qsTr("Remove Module") - enabled: importToRemove !== "" && importToRemove !== "QtQuick" + enabled: importToRemove !== "" onTriggered: rootView.removeImport(importToRemove) } @@ -119,6 +122,19 @@ ScrollView { onTriggered: itemLibraryModel.collapseAll() } } + + StudioControls.Menu { + id: itemContextMenu + // Workaround for menu item implicit width not properly propagating to menu + width: importMenuItem.implicitWidth + + StudioControls.MenuItem { + id: importMenuItem + text: qsTr("Import Module: ") + importToAdd + enabled: currentItem + onTriggered: rootView.addImportForItem(currentItem) + } + } } Column { @@ -144,8 +160,8 @@ ScrollView { importExpanded = !importExpanded } onShowContextMenu: { - importToRemove = importUsed ? "" : importUrl - contextMenu.popup() + importToRemove = importRemovable ? importUrl : "" + importContextMenu.popup() } Column { @@ -180,6 +196,15 @@ ScrollView { visible: itemVisible width: styleConstants.cellWidth + itemGrid.flexibleWidth height: styleConstants.cellHeight + onShowContextMenu: { + if (!itemUsable) { + importToAdd = itemRequiredImport + if (importToAdd !== "") { + currentItem = itemLibraryEntry + itemContextMenu.popup() + } + } + } } } } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ImagePreviewTooltipArea.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ImagePreviewTooltipArea.qml index 5921bf50520..0f2f5b69b9e 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ImagePreviewTooltipArea.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ImagePreviewTooltipArea.qml @@ -30,12 +30,19 @@ import QtQuick.Layouts 1.0 MouseArea { id: mouseArea + signal showContextMenu() + onExited: tooltipBackend.hideTooltip() onCanceled: tooltipBackend.hideTooltip() - onClicked: forceActiveFocus() onPositionChanged: tooltipBackend.reposition() + onClicked: { + forceActiveFocus() + if (mouse.button === Qt.RightButton) + showContextMenu() + } hoverEnabled: true + acceptedButtons: Qt.LeftButton | Qt.RightButton Timer { interval: 1000 diff --git a/src/libs/extensionsystem/CMakeLists.txt b/src/libs/extensionsystem/CMakeLists.txt index 71e5cbd3801..a8424c1df47 100644 --- a/src/libs/extensionsystem/CMakeLists.txt +++ b/src/libs/extensionsystem/CMakeLists.txt @@ -17,3 +17,11 @@ add_qtc_library(ExtensionSystem pluginmanager_p.h SKIP_AUTOMOC pluginmanager.cpp ) + +find_package(Qt5 COMPONENTS Test QUIET) + +extend_qtc_library(ExtensionSystem + CONDITION TARGET Qt5::Test + DEPENDS Qt5::Test + DEFINES WITH_TESTS +) diff --git a/src/libs/extensionsystem/pluginmanager.cpp b/src/libs/extensionsystem/pluginmanager.cpp index adfe161ba8e..ab83ed210b4 100644 --- a/src/libs/extensionsystem/pluginmanager.cpp +++ b/src/libs/extensionsystem/pluginmanager.cpp @@ -1474,7 +1474,7 @@ void PluginManagerPrivate::loadPlugin(PluginSpec *spec, PluginSpec::State destSt return; std::unique_ptr lockFile; - if (enableCrashCheck) + if (enableCrashCheck && destState < PluginSpec::Stopped) lockFile.reset(new LockFile(this, spec)); switch (destState) { diff --git a/src/libs/tracing/CMakeLists.txt b/src/libs/tracing/CMakeLists.txt index 9cc68ec149a..b7205527f38 100644 --- a/src/libs/tracing/CMakeLists.txt +++ b/src/libs/tracing/CMakeLists.txt @@ -5,6 +5,8 @@ if (WITH_TESTS) endif() add_qtc_library(Tracing + CONDITION Qt5_VERSION VERSION_LESS 6.0.0 + FEATURE_INFO DEPENDS Utils Qt5::Qml Qt5::Quick PUBLIC_DEPENDS Qt5::Widgets SOURCES ${TEST_SOURCES} diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index 155ee558add..73832c173a1 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -1131,7 +1131,9 @@ void StringAspect::update() } if (d->m_textEditDisplay) { - d->m_textEditDisplay->setText(displayedString); + const QString old = d->m_textEditDisplay->document()->toPlainText(); + if (displayedString != old) + d->m_textEditDisplay->setText(displayedString); d->updateWidgetFromCheckStatus(d->m_textEditDisplay.data()); } diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index d4d2f0d2675..7b2d8eb5690 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -519,15 +519,14 @@ void CMakeBuildSettingsWidget::updateButtonState() break; case CMakeProjectManager::ConfigModel::DataItem::UNKNOWN: default: - ni.type = CMakeConfigItem::INTERNAL; + ni.type = CMakeConfigItem::UNINITIALIZED; break; } return ni; }); m_resetButton->setEnabled(m_configModel->hasChanges() && !isParsing); - m_reconfigureButton->setEnabled((!configChanges.isEmpty() || m_configModel->hasCMakeChanges()) - && !isParsing); + m_reconfigureButton->setEnabled(!configChanges.isEmpty() && !isParsing); m_buildConfiguration->setConfigurationChanges(configChanges); } diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index abd515f1a0f..ec843295ebd 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -56,6 +56,7 @@ #include #include +#include #include #include @@ -283,9 +284,8 @@ void CMakeBuildSystem::triggerParsing() } if ((0 == (reparseParameters & REPARSE_FORCE_EXTRA_CONFIGURATION)) - && !m_parameters.extraCMakeArguments.isEmpty()) { - if (mustApplyExtraArguments()) - reparseParameters |= REPARSE_FORCE_CMAKE_RUN | REPARSE_FORCE_EXTRA_CONFIGURATION; + && mustApplyExtraArguments(m_parameters)) { + reparseParameters |= REPARSE_FORCE_CMAKE_RUN | REPARSE_FORCE_EXTRA_CONFIGURATION; } qCDebug(cmakeBuildSystemLog) << "Asking reader to parse"; @@ -372,6 +372,27 @@ QString CMakeBuildSystem::reparseParametersString(int reparseFlags) return result.trimmed(); } +void CMakeBuildSystem::writeConfigurationIntoBuildDirectory() +{ + const Utils::MacroExpander *expander = cmakeBuildConfiguration()->macroExpander(); + const FilePath buildDir = workDirectory(m_parameters); + QTC_ASSERT(buildDir.exists(), return ); + + const FilePath settingsFile = buildDir.pathAppended("qtcsettings.cmake"); + + QByteArray contents; + contents.append("# This file is managed by Qt Creator, do not edit!\n\n"); + contents.append( + transform(cmakeBuildConfiguration()->configurationChanges(), + [expander](const CMakeConfigItem &item) { return item.toCMakeSetLine(expander); }) + .join('\n') + .toUtf8()); + + QFile file(settingsFile.toString()); + QTC_ASSERT(file.open(QFile::WriteOnly | QFile::Truncate), return ); + file.write(contents); +} + void CMakeBuildSystem::setParametersAndRequestParse(const BuildDirParameters ¶meters, const int reparseParameters) { @@ -405,6 +426,8 @@ void CMakeBuildSystem::setParametersAndRequestParse(const BuildDirParameters &pa m_reader.setParameters(m_parameters); + writeConfigurationIntoBuildDirectory(); + if (reparseParameters & REPARSE_URGENT) { qCDebug(cmakeBuildSystemLog) << "calling requestReparse"; requestParse(); @@ -414,15 +437,15 @@ void CMakeBuildSystem::setParametersAndRequestParse(const BuildDirParameters &pa } } -bool CMakeBuildSystem::mustApplyExtraArguments() const +bool CMakeBuildSystem::mustApplyExtraArguments(const BuildDirParameters ¶meters) const { - if (m_parameters.extraCMakeArguments.isEmpty()) + if (parameters.extraCMakeArguments.isEmpty()) return false; auto answer = QMessageBox::question(Core::ICore::mainWindow(), tr("Apply configuration changes?"), tr("Run CMake with \"%1\"?") - .arg(m_parameters.extraCMakeArguments.join(" ")), + .arg(parameters.extraCMakeArguments.join(" ")), QMessageBox::Apply | QMessageBox::Discard, QMessageBox::Apply); return answer == QMessageBox::Apply; @@ -482,12 +505,10 @@ bool CMakeBuildSystem::persistCMakeState() qCDebug(cmakeBuildSystemLog) << "Checking whether build system needs to be persisted:" << "workdir:" << parameters.workDirectory << "buildDir:" << parameters.buildDirectory - << "Has extraargs:" << !parameters.extraCMakeArguments.isEmpty() - << "must apply extra Args:" - << mustApplyExtraArguments(); + << "Has extraargs:" << !parameters.extraCMakeArguments.isEmpty(); if (parameters.workDirectory == parameters.buildDirectory - && !parameters.extraCMakeArguments.isEmpty() && mustApplyExtraArguments()) { + && mustApplyExtraArguments(parameters)) { reparseFlags = REPARSE_FORCE_EXTRA_CONFIGURATION; qCDebug(cmakeBuildSystemLog) << " -> must run CMake with extra arguments."; } diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.h b/src/plugins/cmakeprojectmanager/cmakebuildsystem.h index 283990ed7be..7667b77a772 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.h +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.h @@ -29,7 +29,6 @@ #include "cmakebuildtarget.h" #include "cmakeprojectnodes.h" #include "fileapireader.h" -#include "utils/macroexpander.h" #include @@ -117,7 +116,7 @@ private: void setParametersAndRequestParse(const BuildDirParameters ¶meters, const int reparseParameters); - bool mustApplyExtraArguments() const; + bool mustApplyExtraArguments(const BuildDirParameters ¶meters) const; // State handling: // Parser states: @@ -155,6 +154,8 @@ private: void runCTest(); + void writeConfigurationIntoBuildDirectory(); + ProjectExplorer::TreeScanner m_treeScanner; QHash m_mimeBinaryCache; QList m_allFiles; diff --git a/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp b/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp index f979c283f35..4887bd130dd 100644 --- a/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp @@ -145,9 +145,11 @@ CMakeConfigItem::Type CMakeConfigItem::typeStringToType(const QByteArray &type) return CMakeConfigItem::PATH; if (type == "STATIC") return CMakeConfigItem::STATIC; + if (type == "INTERNAL") + return CMakeConfigItem::INTERNAL; - QTC_CHECK(type == "INTERNAL" || type == "UNINITIALIZED"); - return CMakeConfigItem::INTERNAL; + QTC_CHECK(type == "UNINITIALIZED"); + return CMakeConfigItem::UNINITIALIZED; } QString CMakeConfigItem::typeToTypeString(const CMakeConfigItem::Type t) @@ -163,8 +165,10 @@ QString CMakeConfigItem::typeToTypeString(const CMakeConfigItem::Type t) return {"INTERNAL"}; case CMakeProjectManager::CMakeConfigItem::STATIC: return {"STATIC"}; - case CMakeConfigItem::BOOL: + case CMakeProjectManager::CMakeConfigItem::BOOL: return {"BOOL"}; + case CMakeProjectManager::CMakeConfigItem::UNINITIALIZED: + return {"UNINITIALIZED"}; } QTC_CHECK(false); return {}; @@ -418,6 +422,9 @@ QString CMakeConfigItem::toString(const Utils::MacroExpander *expander) const case CMakeProjectManager::CMakeConfigItem::INTERNAL: typeStr = QLatin1String("INTERNAL"); break; + case CMakeProjectManager::CMakeConfigItem::UNINITIALIZED: + typeStr = QLatin1String("UNINITIALIZED"); + break; case CMakeProjectManager::CMakeConfigItem::STRING: default: typeStr = QLatin1String("STRING"); diff --git a/src/plugins/cmakeprojectmanager/cmakeconfigitem.h b/src/plugins/cmakeprojectmanager/cmakeconfigitem.h index 10c7651f6f7..7da405a48d8 100644 --- a/src/plugins/cmakeprojectmanager/cmakeconfigitem.h +++ b/src/plugins/cmakeprojectmanager/cmakeconfigitem.h @@ -45,7 +45,7 @@ namespace CMakeProjectManager { class CMAKE_EXPORT CMakeConfigItem { public: - enum Type { FILEPATH, PATH, BOOL, STRING, INTERNAL, STATIC }; + enum Type { FILEPATH, PATH, BOOL, STRING, INTERNAL, STATIC, UNINITIALIZED }; CMakeConfigItem(); CMakeConfigItem(const QByteArray &k, Type t, const QByteArray &d, const QByteArray &v, const QStringList &s = {}); CMakeConfigItem(const QByteArray &k, const QByteArray &v); diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp index 002a2b82623..211aca4065d 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp @@ -46,7 +46,9 @@ CMakeInputsNode::CMakeInputsNode(const Utils::FilePath &cmakeLists) : { setPriority(Node::DefaultPriority - 10); // Bottom most! setDisplayName(QCoreApplication::translate("CMakeFilesProjectNode", "CMake Modules")); - setIcon(QIcon(":/projectexplorer/images/session.png")); // TODO: Use a better icon! + static const QIcon modulesIcon = Core::FileIconProvider::directoryIcon( + ProjectExplorer::Constants::FILEOVERLAY_MODULES); + setIcon(modulesIcon); setListInProject(false); } diff --git a/src/plugins/cmakeprojectmanager/configmodel.cpp b/src/plugins/cmakeprojectmanager/configmodel.cpp index f30adb22394..b3bf8533c6d 100644 --- a/src/plugins/cmakeprojectmanager/configmodel.cpp +++ b/src/plugins/cmakeprojectmanager/configmodel.cpp @@ -123,11 +123,6 @@ bool ConfigModel::hasChanges() const }); } -bool ConfigModel::hasCMakeChanges() const -{ - return Utils::contains(m_configuration, [](const InternalDataItem &i) { return i.isCMakeChanged; }); -} - bool ConfigModel::canForceTo(const QModelIndex &idx, const ConfigModel::DataItem::Type type) const { if (idx.model() != const_cast(this) || idx.column() != 1) @@ -264,7 +259,6 @@ void ConfigModel::setConfiguration(const QList &c // merge old/new entry: InternalDataItem item(*newIt); item.newValue = (newIt->value != oldIt->newValue) ? oldIt->newValue : QString(); - item.isCMakeChanged = (oldIt->value != newIt->value); item.isUserChanged = !item.newValue.isEmpty() && (item.newValue != item.value); result << item; ++newIt; @@ -390,7 +384,6 @@ QVariant ConfigModelTreeItem::data(int column, int role) const return toolTip(); case Qt::FontRole: { QFont font; - font.setItalic(dataItem->isCMakeChanged); font.setBold(dataItem->isUserNew); font.setStrikeOut((!dataItem->inCMakeCache && !dataItem->isUserNew) || dataItem->isUnset); return font; @@ -414,7 +407,6 @@ QVariant ConfigModelTreeItem::data(int column, int role) const case Qt::FontRole: { QFont font; font.setBold((dataItem->isUserChanged || dataItem->isUserNew) && !dataItem->isUnset); - font.setItalic(dataItem->isCMakeChanged); font.setStrikeOut((!dataItem->inCMakeCache && !dataItem->isUserNew) || dataItem->isUnset); return font; } diff --git a/src/plugins/cmakeprojectmanager/configmodel.h b/src/plugins/cmakeprojectmanager/configmodel.h index 70f0fa3960a..a5cb94612e5 100644 --- a/src/plugins/cmakeprojectmanager/configmodel.h +++ b/src/plugins/cmakeprojectmanager/configmodel.h @@ -101,7 +101,7 @@ public: cmi.type = CMakeConfigItem::STRING; break; case DataItem::UNKNOWN: - cmi.type = CMakeConfigItem::INTERNAL; + cmi.type = CMakeConfigItem::UNINITIALIZED; break; } cmi.isUnset = isUnset; @@ -144,7 +144,6 @@ public: void resetAllChanges(); bool hasChanges() const; - bool hasCMakeChanges() const; bool canForceTo(const QModelIndex &idx, const DataItem::Type type) const; void forceTo(const QModelIndex &idx, const DataItem::Type type); @@ -168,7 +167,6 @@ private: bool isUserChanged = false; bool isUserNew = false; - bool isCMakeChanged = false; QString newValue; QString kitValue; }; diff --git a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp index 80ea50c6d0c..1474a8da4da 100644 --- a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp +++ b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp @@ -179,6 +179,14 @@ QVector extractBacktraceInformation(const BacktraceInf return info; } +static bool isChildOf(const FilePath &path, const QStringList &prefixes) +{ + for (const QString &prefix : prefixes) + if (path.isChildOf(FilePath::fromString(prefix))) + return true; + return false; +} + QList generateBuildTargets(const PreprocessedData &input, const FilePath &sourceDirectory, const FilePath &buildDirectory) @@ -269,16 +277,28 @@ QList generateBuildTargets(const PreprocessedData &input, if (f.role == "libraries") tmp = tmp.parentDir(); - if (!tmp.isEmpty() - && tmp.isDir()) { // f.role is libraryPath or frameworkPath - librarySeachPaths.append(tmp); - // Libraries often have their import libs in ../lib and the - // actual dll files in ../bin on windows. Qt is one example of that. - if (tmp.fileName() == "lib" && HostOsInfo::isWindowsHost()) { - const FilePath path = tmp.parentDir().pathAppended("bin"); + if (!tmp.isEmpty() && tmp.isDir()) { + // f.role is libraryPath or frameworkPath + // On Linux, exclude sub-paths from "/lib(64)", "/usr/lib(64)" and + // "/usr/local/lib" since these are usually in the standard search + // paths. There probably are more, but the naming schemes are arbitrary + // so we'd need to ask the linker ("ld --verbose | grep SEARCH_DIR"). + if (!HostOsInfo::isLinuxHost() + || !isChildOf(tmp, + {"/lib", + "/lib64", + "/usr/lib", + "/usr/lib64", + "/usr/local/lib"})) { + librarySeachPaths.append(tmp); + // Libraries often have their import libs in ../lib and the + // actual dll files in ../bin on windows. Qt is one example of that. + if (tmp.fileName() == "lib" && HostOsInfo::isWindowsHost()) { + const FilePath path = tmp.parentDir().pathAppended("bin"); - if (path.isDir()) - librarySeachPaths.append(path); + if (path.isDir()) + librarySeachPaths.append(path); + } } } } diff --git a/src/plugins/cmakeprojectmanager/fileapiparser.cpp b/src/plugins/cmakeprojectmanager/fileapiparser.cpp index 3e0cdc56d89..1e2ccfb0114 100644 --- a/src/plugins/cmakeprojectmanager/fileapiparser.cpp +++ b/src/plugins/cmakeprojectmanager/fileapiparser.cpp @@ -892,7 +892,9 @@ FileApiData FileApiParser::parseData(const QFileInfo &replyFileInfo, const QStri } auto it = std::find_if(codeModels.cbegin(), codeModels.cend(), - [cmakeBuildType](const Configuration& cfg) { return cfg.name == cmakeBuildType; }); + [cmakeBuildType](const Configuration& cfg) { + return QString::compare(cfg.name, cmakeBuildType, Qt::CaseInsensitive) == 0; + }); if (it == codeModels.cend()) { errorMessage = QString("No '%1' CMake configuration found!").arg(cmakeBuildType); qWarning() << errorMessage; diff --git a/src/plugins/cmakeprojectmanager/fileapireader.cpp b/src/plugins/cmakeprojectmanager/fileapireader.cpp index 152f22b468f..0657782c980 100644 --- a/src/plugins/cmakeprojectmanager/fileapireader.cpp +++ b/src/plugins/cmakeprojectmanager/fileapireader.cpp @@ -321,9 +321,10 @@ void FileApiReader::makeBackupConfiguration(bool store) if (!store) std::swap(cmakeCacheTxt, cmakeCacheTxtPrev); - if (!FileUtils::copyIfDifferent(cmakeCacheTxt, cmakeCacheTxtPrev)) - Core::MessageManager::writeFlashing(tr("Failed to copy %1 to %2.") - .arg(cmakeCacheTxt.toString(), cmakeCacheTxtPrev.toString())); + if (cmakeCacheTxt.exists()) + if (!FileUtils::copyIfDifferent(cmakeCacheTxt, cmakeCacheTxtPrev)) + Core::MessageManager::writeFlashing(tr("Failed to copy %1 to %2.") + .arg(cmakeCacheTxt.toString(), cmakeCacheTxtPrev.toString())); } diff --git a/src/plugins/coreplugin/iwelcomepage.cpp b/src/plugins/coreplugin/iwelcomepage.cpp index 20f1c2194d6..735444c967e 100644 --- a/src/plugins/coreplugin/iwelcomepage.cpp +++ b/src/plugins/coreplugin/iwelcomepage.cpp @@ -57,7 +57,7 @@ IWelcomePage::~IWelcomePage() g_welcomePages.removeOne(this); } -static QPalette buttonPalette(bool isActive, bool isCursorInside, bool forText) +QPalette WelcomePageFrame::buttonPalette(bool isActive, bool isCursorInside, bool forText) { QPalette pal; Theme *theme = Utils::creatorTheme(); @@ -174,8 +174,8 @@ bool WelcomePageButtonPrivate::isActive() const void WelcomePageButtonPrivate::doUpdate(bool cursorInside) { const bool active = isActive(); - q->setPalette(buttonPalette(active, cursorInside, false)); - const QPalette lpal = buttonPalette(active, cursorInside, true); + q->setPalette(WelcomePageFrame::buttonPalette(active, cursorInside, false)); + const QPalette lpal = WelcomePageFrame::buttonPalette(active, cursorInside, true); m_label->setPalette(lpal); if (m_icon) m_icon->setPalette(lpal); diff --git a/src/plugins/coreplugin/iwelcomepage.h b/src/plugins/coreplugin/iwelcomepage.h index bc4ea7878d0..1a89b5df8c4 100644 --- a/src/plugins/coreplugin/iwelcomepage.h +++ b/src/plugins/coreplugin/iwelcomepage.h @@ -68,6 +68,8 @@ public: WelcomePageFrame(QWidget *parent); void paintEvent(QPaintEvent *event) override; + + static QPalette buttonPalette(bool isActive, bool isCursorInside, bool forText); }; class CORE_EXPORT WelcomePageButton : public WelcomePageFrame diff --git a/src/plugins/coreplugin/themechooser.cpp b/src/plugins/coreplugin/themechooser.cpp index 2f4127b5a98..13af462167f 100644 --- a/src/plugins/coreplugin/themechooser.cpp +++ b/src/plugins/coreplugin/themechooser.cpp @@ -171,6 +171,12 @@ ThemeChooser::~ThemeChooser() delete d; } +static QString defaultThemeId() +{ + return Theme::systemUsesDarkMode() ? QString(Constants::DEFAULT_DARK_THEME) + : QString(Constants::DEFAULT_THEME); +} + void ThemeChooser::apply() { const int index = d->m_themeComboBox->currentIndex(); @@ -181,9 +187,7 @@ void ThemeChooser::apply() const QString currentThemeId = ThemeEntry::themeSetting().toString(); if (currentThemeId != themeId) { // save filename of selected theme in global config - settings->setValueWithDefault(Constants::SETTINGS_THEME, - themeId, - QString(Constants::DEFAULT_THEME)); + settings->setValueWithDefault(Constants::SETTINGS_THEME, themeId, defaultThemeId()); RestartDialog restartDialog(ICore::dialogParent(), tr("The theme change will take effect after restart.")); restartDialog.exec(); @@ -225,10 +229,8 @@ QList ThemeEntry::availableThemes() Id ThemeEntry::themeSetting() { - auto defaultId = Theme::systemUsesDarkMode() ? Constants::DEFAULT_DARK_THEME - : Constants::DEFAULT_THEME; const Id setting = Id::fromSetting( - ICore::settings()->value(Constants::SETTINGS_THEME, defaultId)); + ICore::settings()->value(Constants::SETTINGS_THEME, defaultThemeId())); const QList themes = availableThemes(); if (themes.empty()) diff --git a/src/plugins/coreplugin/welcomepagehelper.cpp b/src/plugins/coreplugin/welcomepagehelper.cpp index e7b183a964b..15b5591bf61 100644 --- a/src/plugins/coreplugin/welcomepagehelper.cpp +++ b/src/plugins/coreplugin/welcomepagehelper.cpp @@ -57,15 +57,17 @@ static QFont sizedFont(int size, const QWidget *widget) SearchBox::SearchBox(QWidget *parent) : WelcomePageFrame(parent) { - QPalette pal; + QPalette pal = buttonPalette(false, false, true); pal.setColor(QPalette::Base, themeColor(Theme::Welcome_BackgroundColor)); + // for macOS dark mode + pal.setColor(QPalette::Text, themeColor(Theme::Welcome_TextColor)); + setPalette(pal); m_lineEdit = new FancyLineEdit; m_lineEdit->setFiltering(true); m_lineEdit->setFrame(false); m_lineEdit->setFont(sizedFont(14, this)); m_lineEdit->setAttribute(Qt::WA_MacShowFocusRect, false); - m_lineEdit->setPalette(pal); auto box = new QHBoxLayout(this); box->setContentsMargins(10, 3, 3, 3); @@ -84,6 +86,7 @@ GridView::GridView(QWidget *parent) setSelectionMode(QAbstractItemView::NoSelection); setFrameShape(QFrame::NoFrame); setGridStyle(Qt::NoPen); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); QPalette pal; pal.setColor(QPalette::Base, themeColor(Theme::Welcome_BackgroundColor)); diff --git a/src/plugins/cppeditor/cppeditorwidget.cpp b/src/plugins/cppeditor/cppeditorwidget.cpp index 738c15f45d2..7643b1976b2 100644 --- a/src/plugins/cppeditor/cppeditorwidget.cpp +++ b/src/plugins/cppeditor/cppeditorwidget.cpp @@ -421,6 +421,7 @@ static void addSearchResults(CppTools::Usages usages, SearchResult &search, cons item.setFilePath(FilePath::fromString(usage.path)); item.setLineText(lineContent); item.setMainRange(range); + item.setUseTextEditorFont(true); search.addResult(item); } } diff --git a/src/plugins/cpptools/cppfindreferences.cpp b/src/plugins/cpptools/cppfindreferences.cpp index 72fe7b885de..d0fe1c75bdd 100644 --- a/src/plugins/cpptools/cppfindreferences.cpp +++ b/src/plugins/cpptools/cppfindreferences.cpp @@ -636,6 +636,7 @@ static void displayResults(SearchResult *search, QFutureWatcheraddResult(item); if (parameters.prettySymbolName.isEmpty()) @@ -831,6 +832,7 @@ void CppFindReferences::findMacroUses(const CPlusPlus::Macro ¯o, const QStri item.setFilePath(Utils::FilePath::fromString(macro.fileName())); item.setLineText(line); item.setMainRange(macro.line(), column, macro.nameToQString().length()); + item.setUseTextEditorFont(true); search->addResult(item); } diff --git a/src/plugins/cpptools/semantichighlighter.cpp b/src/plugins/cpptools/semantichighlighter.cpp index df40dce813d..d4d250166ca 100644 --- a/src/plugins/cpptools/semantichighlighter.cpp +++ b/src/plugins/cpptools/semantichighlighter.cpp @@ -31,6 +31,7 @@ #include #include +#include #include #include @@ -45,6 +46,8 @@ static Q_LOGGING_CATEGORY(log, "qtc.cpptools.semantichighlighter", QtWarningMsg) namespace CppTools { +static Utils::Id parenSource() { return "CppTools"; } + static const QList> splitRawStringLiteral(const HighlightingResult &result, const QTextBlock &startBlock) { @@ -147,6 +150,13 @@ void SemanticHighlighter::run() m_watcher->setFuture(m_highlightingRunner()); } +static Parentheses getClearedParentheses(const QTextBlock &block) +{ + return Utils::filtered(TextDocumentLayout::parentheses(block), [](const Parenthesis &p) { + return p.source != parenSource(); + }); +} + void SemanticHighlighter::onHighlighterResultAvailable(int from, int to) { if (documentRevision() != m_revision) @@ -169,6 +179,9 @@ void SemanticHighlighter::onHighlighterResultAvailable(int from, int to) const HighlightingResult &result = m_watcher->future().resultAt(i); if (result.kind != AngleBracketOpen && result.kind != AngleBracketClose && result.kind != TernaryIf && result.kind != TernaryElse) { + const QTextBlock block = + m_baseTextDocument->document()->findBlockByNumber(result.line - 1); + TextDocumentLayout::setParentheses(block, getClearedParentheses(block)); continue; } if (parentheses.first.isValid() && result.line - 1 > parentheses.first.blockNumber()) { @@ -177,16 +190,20 @@ void SemanticHighlighter::onHighlighterResultAvailable(int from, int to) } if (!parentheses.first.isValid()) { parentheses.first = m_baseTextDocument->document()->findBlockByNumber(result.line - 1); - parentheses.second = TextDocumentLayout::parentheses(parentheses.first); + parentheses.second = getClearedParentheses(parentheses.first); } + Parenthesis paren; if (result.kind == AngleBracketOpen) - parentheses.second << Parenthesis(Parenthesis::Opened, '<', result.column - 1); + paren = {Parenthesis::Opened, '<', result.column - 1}; else if (result.kind == AngleBracketClose) - parentheses.second << Parenthesis(Parenthesis::Closed, '>', result.column - 1); + paren = {Parenthesis::Closed, '>', result.column - 1}; else if (result.kind == TernaryIf) - parentheses.second << Parenthesis(Parenthesis::Opened, '?', result.column - 1); + paren = {Parenthesis::Opened, '?', result.column - 1}; else if (result.kind == TernaryElse) - parentheses.second << Parenthesis(Parenthesis::Closed, ':', result.column - 1); + paren = {Parenthesis::Closed, ':', result.column - 1}; + QTC_ASSERT(paren.pos != -1, continue); + paren.source = parenSource(); + parentheses.second << paren; } if (parentheses.first.isValid()) TextDocumentLayout::setParentheses(parentheses.first, parentheses.second); @@ -202,6 +219,27 @@ void SemanticHighlighter::onHighlighterFinished() clearExtraAdditionalFormatsUntilEnd(highlighter, m_watcher->future()); } } + + // Clear out previous "semantic parentheses". + QTextBlock firstResultBlock; + QTextBlock lastResultBlock; + if (m_watcher->future().resultCount() == 0) { + firstResultBlock = lastResultBlock = m_baseTextDocument->document()->lastBlock(); + } else { + firstResultBlock = m_baseTextDocument->document()->findBlockByNumber( + m_watcher->resultAt(0).line - 1); + lastResultBlock = m_baseTextDocument->document()->findBlockByNumber( + m_watcher->future().resultAt(m_watcher->future().resultCount() - 1).line - 1); + } + for (QTextBlock currentBlock = m_baseTextDocument->document()->firstBlock(); + currentBlock != firstResultBlock; currentBlock = currentBlock.next()) { + TextDocumentLayout::setParentheses(currentBlock, getClearedParentheses(currentBlock)); + } + for (QTextBlock currentBlock = lastResultBlock.next(); currentBlock.isValid(); + currentBlock = currentBlock.next()) { + TextDocumentLayout::setParentheses(currentBlock, getClearedParentheses(currentBlock)); + } + m_watcher.reset(); } diff --git a/src/plugins/ctfvisualizer/CMakeLists.txt b/src/plugins/ctfvisualizer/CMakeLists.txt index 32f1188e3ec..1b4df7f2fa2 100644 --- a/src/plugins/ctfvisualizer/CMakeLists.txt +++ b/src/plugins/ctfvisualizer/CMakeLists.txt @@ -1,4 +1,5 @@ add_qtc_plugin(CtfVisualizer + CONDITION TARGET Tracing DEPENDS Tracing Qt5::QuickWidgets INCLUDES ${PROJECT_SOURCE_DIR}/src PLUGIN_DEPENDS Core Debugger ProjectExplorer diff --git a/src/plugins/languageclient/languageclientsettings.cpp b/src/plugins/languageclient/languageclientsettings.cpp index fff4b3d9c0e..db793e3c110 100644 --- a/src/plugins/languageclient/languageclientsettings.cpp +++ b/src/plugins/languageclient/languageclientsettings.cpp @@ -79,6 +79,7 @@ constexpr char executableKey[] = "executable"; constexpr char argumentsKey[] = "arguments"; constexpr char settingsGroupKey[] = "LanguageClient"; constexpr char clientsKey[] = "clients"; +constexpr char typedClientsKey[] = "typedClients"; constexpr char mimeType[] = "application/language.client.setting"; namespace LanguageClient { @@ -615,16 +616,21 @@ QList LanguageClientSettings::fromSettings(QSettings *settingsIn { settingsIn->beginGroup(settingsGroupKey); QList result; - for (const QVariant& var : settingsIn->value(clientsKey).toList()) { - const QMap &map = var.toMap(); - Utils::Id typeId = Utils::Id::fromSetting(map.value(typeIdKey)); - if (!typeId.isValid()) - typeId = Constants::LANGUAGECLIENT_STDIO_SETTINGS_ID; - if (BaseSettings *settings = generateSettings(typeId)) { - settings->fromMap(var.toMap()); - result << settings; + + for (auto varList : + {settingsIn->value(clientsKey).toList(), settingsIn->value(typedClientsKey).toList()}) { + for (const QVariant &var : varList) { + const QMap &map = var.toMap(); + Utils::Id typeId = Utils::Id::fromSetting(map.value(typeIdKey)); + if (!typeId.isValid()) + typeId = Constants::LANGUAGECLIENT_STDIO_SETTINGS_ID; + if (BaseSettings *settings = generateSettings(typeId)) { + settings->fromMap(map); + result << settings; + } } } + settingsIn->endGroup(); return result; } @@ -659,10 +665,16 @@ void LanguageClientSettings::toSettings(QSettings *settings, const QList &languageClientSettings) { settings->beginGroup(settingsGroupKey); - settings->setValue(clientsKey, Utils::transform(languageClientSettings, - [](const BaseSettings *setting){ - return QVariant(setting->toMap()); - })); + auto transform = [](const QList &settings) { + return Utils::transform(settings, [](const BaseSettings *setting) { + return QVariant(setting->toMap()); + }); + }; + auto isStdioSetting = Utils::equal(&BaseSettings::m_settingsTypeId, + Utils::Id(Constants::LANGUAGECLIENT_STDIO_SETTINGS_ID)); + auto [stdioSettings, typedSettings] = Utils::partition(languageClientSettings, isStdioSetting); + settings->setValue(clientsKey, transform(stdioSettings)); + settings->setValue(typedClientsKey, transform(typedSettings)); settings->endGroup(); } diff --git a/src/plugins/perfprofiler/CMakeLists.txt b/src/plugins/perfprofiler/CMakeLists.txt index 20345cb0389..97f82871f02 100644 --- a/src/plugins/perfprofiler/CMakeLists.txt +++ b/src/plugins/perfprofiler/CMakeLists.txt @@ -1,4 +1,5 @@ add_qtc_plugin(PerfProfiler + CONDITION TARGET Tracing DEPENDS Tracing Qt5::QuickWidgets PLUGIN_DEPENDS Core Debugger ProjectExplorer QtSupport SOURCES diff --git a/src/plugins/projectexplorer/images/fileoverlay_modules.png b/src/plugins/projectexplorer/images/fileoverlay_modules.png new file mode 100644 index 00000000000..0ebdea29e5c Binary files /dev/null and b/src/plugins/projectexplorer/images/fileoverlay_modules.png differ diff --git a/src/plugins/projectexplorer/images/fileoverlay_modules@2x.png b/src/plugins/projectexplorer/images/fileoverlay_modules@2x.png new file mode 100644 index 00000000000..96c940d5c76 Binary files /dev/null and b/src/plugins/projectexplorer/images/fileoverlay_modules@2x.png differ diff --git a/src/plugins/projectexplorer/images/session.png b/src/plugins/projectexplorer/images/session.png deleted file mode 100644 index 6d526f6bee1..00000000000 Binary files a/src/plugins/projectexplorer/images/session.png and /dev/null differ diff --git a/src/plugins/projectexplorer/projectexplorer.qrc b/src/plugins/projectexplorer/projectexplorer.qrc index 76a913e8df1..b09c7e26da0 100644 --- a/src/plugins/projectexplorer/projectexplorer.qrc +++ b/src/plugins/projectexplorer/projectexplorer.qrc @@ -24,7 +24,6 @@ images/debugger_overlay_small@2x.png images/analyzer_overlay_small.png images/analyzer_overlay_small@2x.png - images/session.png images/BuildSettings.png images/CodeStyleSettings.png images/RunSettings.png @@ -67,6 +66,8 @@ images/fileoverlay_product@2x.png images/fileoverlay_group.png images/fileoverlay_group@2x.png + images/fileoverlay_modules.png + images/fileoverlay_modules@2x.png images/fileoverlay_ui.png images/fileoverlay_ui@2x.png images/fileoverlay_scxml.png diff --git a/src/plugins/projectexplorer/projectexplorerconstants.h b/src/plugins/projectexplorer/projectexplorerconstants.h index 5bc3a8da3f0..e0f7fa80459 100644 --- a/src/plugins/projectexplorer/projectexplorerconstants.h +++ b/src/plugins/projectexplorer/projectexplorerconstants.h @@ -215,6 +215,7 @@ const char PROJECTTREE_ID[] = "Projects"; const char FILEOVERLAY_QT[]=":/projectexplorer/images/fileoverlay_qt.png"; const char FILEOVERLAY_GROUP[] = ":/projectexplorer/images/fileoverlay_group.png"; const char FILEOVERLAY_PRODUCT[] = ":/projectexplorer/images/fileoverlay_product.png"; +const char FILEOVERLAY_MODULES[] = ":/projectexplorer/images/fileoverlay_modules.png"; const char FILEOVERLAY_QML[]=":/projectexplorer/images/fileoverlay_qml.png"; const char FILEOVERLAY_UI[]=":/projectexplorer/images/fileoverlay_ui.png"; const char FILEOVERLAY_QRC[]=":/projectexplorer/images/fileoverlay_qrc.png"; diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index 41e70cb1e95..5681c7f15d7 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -6,7 +6,7 @@ endif() add_qtc_plugin(QmlDesigner DEPENDS QmlJS LanguageUtils QmlEditorWidgets AdvancedDockingSystem - Qt5::QuickWidgets Qt5::CorePrivate Sqlite + Qt5::QuickWidgets Qt5::CorePrivate Sqlite Threads::Threads DEFINES DESIGNER_CORE_LIBRARY IDE_LIBRARY_BASENAME=\"${IDE_LIBRARY_BASE_PATH}\" diff --git a/src/plugins/qmldesigner/components/curveeditor/curveeditor.cpp b/src/plugins/qmldesigner/components/curveeditor/curveeditor.cpp index 800dc0c523b..23623ae3095 100644 --- a/src/plugins/qmldesigner/components/curveeditor/curveeditor.cpp +++ b/src/plugins/qmldesigner/components/curveeditor/curveeditor.cpp @@ -100,7 +100,9 @@ QToolBar *CurveEditor::createToolBar(CurveEditorModel *model) auto setLinearInterpolation = [this]() { m_view->setInterpolation(Keyframe::Interpolation::Linear); }; - auto setStepInterpolation = [this]() { m_view->setInterpolation(Keyframe::Interpolation::Step); }; + auto setStepInterpolation = [this]() { + m_view->setInterpolation(Keyframe::Interpolation::Step); + }; auto setSplineInterpolation = [this]() { m_view->setInterpolation(Keyframe::Interpolation::Bezier); }; diff --git a/src/plugins/qmldesigner/components/curveeditor/curveeditorview.cpp b/src/plugins/qmldesigner/components/curveeditor/curveeditorview.cpp index 51fc7c31a32..b885b3d91c5 100644 --- a/src/plugins/qmldesigner/components/curveeditor/curveeditorview.cpp +++ b/src/plugins/qmldesigner/components/curveeditor/curveeditorview.cpp @@ -338,7 +338,8 @@ void CurveEditorView::commitKeyframes(TreeItem *item) group.setValue(QVariant(pos.y()), pos.x()); if (previous.isValid()) { - if (frame.interpolation() == Keyframe::Interpolation::Bezier) { + if (frame.interpolation() == Keyframe::Interpolation::Bezier || + frame.interpolation() == Keyframe::Interpolation::Step ) { CurveSegment segment(previous, frame); if (segment.isValid()) attachEasingCurve(group, pos.x(), segment.easingCurve()); @@ -346,8 +347,6 @@ void CurveEditorView::commitKeyframes(TreeItem *item) QVariant data = frame.data(); if (data.type() == static_cast(QMetaType::QEasingCurve)) attachEasingCurve(group, pos.x(), data.value()); - } else if (frame.interpolation() == Keyframe::Interpolation::Step) { - // Warning: Keyframe::Interpolation::Step not yet implemented } } diff --git a/src/plugins/qmldesigner/components/curveeditor/curvesegment.cpp b/src/plugins/qmldesigner/components/curveeditor/curvesegment.cpp index 75d956c666c..cf2861991bd 100644 --- a/src/plugins/qmldesigner/components/curveeditor/curvesegment.cpp +++ b/src/plugins/qmldesigner/components/curveeditor/curvesegment.cpp @@ -294,6 +294,13 @@ void CurveSegment::extend(QPainterPath &path) const QEasingCurve CurveSegment::easingCurve() const { + if (interpolation() == Keyframe::Interpolation::Step) { + QEasingCurve curve; + curve.addCubicBezierSegment(QPointF(0.1, 0.0), QPointF(0.9, 0.0), QPointF(1.0, 0.0)); + curve.addCubicBezierSegment(QPointF(1.0, 0.1), QPointF(1.0, 0.9), QPointF(1.0, 1.0)); + return curve; + } + auto mapPosition = [this](const QPointF &position) { QPointF min = m_left.position(); QPointF max = m_right.position(); diff --git a/src/plugins/qmldesigner/components/integration/designdocument.cpp b/src/plugins/qmldesigner/components/integration/designdocument.cpp index ae4b09bdc41..c626f4baa59 100644 --- a/src/plugins/qmldesigner/components/integration/designdocument.cpp +++ b/src/plugins/qmldesigner/components/integration/designdocument.cpp @@ -370,7 +370,8 @@ void DesignDocument::close() void DesignDocument::updateSubcomponentManager() { Q_ASSERT(m_subComponentManager); - m_subComponentManager->update(QUrl::fromLocalFile(fileName().toString()), currentModel()->imports()); + m_subComponentManager->update(QUrl::fromLocalFile(fileName().toString()), + currentModel()->imports() + currentModel()->possibleImports()); } void DesignDocument::deleteSelected() diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryaddimportmodel.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryaddimportmodel.cpp index 377662b032b..4c89d339353 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryaddimportmodel.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryaddimportmodel.cpp @@ -40,6 +40,7 @@ ItemLibraryAddImportModel::ItemLibraryAddImportModel(QObject *parent) // add role names m_roleNames.insert(Qt::UserRole + 1, "importUrl"); m_roleNames.insert(Qt::UserRole + 2, "importVisible"); + m_roleNames.insert(Qt::UserRole + 3, "isSeparator"); } ItemLibraryAddImportModel::~ItemLibraryAddImportModel() @@ -63,7 +64,10 @@ QVariant ItemLibraryAddImportModel::data(const QModelIndex &index, int role) con return importUrl; if (m_roleNames[role] == "importVisible") - return m_searchText.isEmpty() || m_importFilterList.contains(importUrl); + return m_searchText.isEmpty() || importUrl.isEmpty() || m_importFilterList.contains(importUrl); + + if (m_roleNames[role] == "isSeparator") + return importUrl.isEmpty(); qWarning() << Q_FUNC_INFO << "invalid role requested"; @@ -83,9 +87,9 @@ void ItemLibraryAddImportModel::update(const QList &possibleImports) const DesignerMcuManager &mcuManager = DesignerMcuManager::instance(); const bool isQtForMCUs = mcuManager.isMCUProject(); QList filteredImports; - const QStringList mcuAllowedList = mcuManager.allowedImports(); - const QStringList mcuBannedList = mcuManager.bannedImports(); if (isQtForMCUs) { + const QStringList mcuAllowedList = mcuManager.allowedImports(); + const QStringList mcuBannedList = mcuManager.bannedImports(); filteredImports = Utils::filtered(possibleImports, [&](const Import &import) { return (mcuAllowedList.contains(import.url()) @@ -96,7 +100,7 @@ void ItemLibraryAddImportModel::update(const QList &possibleImports) filteredImports = possibleImports; } - Utils::sort(filteredImports, [](const Import &firstImport, const Import &secondImport) { + Utils::sort(filteredImports, [this](const Import &firstImport, const Import &secondImport) { if (firstImport.url() == secondImport.url()) return firstImport.toString() < secondImport.toString(); @@ -106,6 +110,10 @@ void ItemLibraryAddImportModel::update(const QList &possibleImports) if (secondImport.url() == "QtQuick") return false; + const bool firstPriority = m_priorityImports.contains(firstImport.url()); + if (firstPriority != m_priorityImports.contains(secondImport.url())) + return firstPriority; + if (firstImport.isLibraryImport() && secondImport.isFileImport()) return false; @@ -122,9 +130,15 @@ void ItemLibraryAddImportModel::update(const QList &possibleImports) }); // create import sections + bool previousIsPriority = false; for (const Import &import : std::as_const(filteredImports)) { - if (import.isLibraryImport()) + if (import.isLibraryImport()) { + bool currentIsPriority = m_priorityImports.contains(import.url()); + if (previousIsPriority && !currentIsPriority) + m_importList.append(Import::empty()); // empty import acts as a separator m_importList.append(import); + previousIsPriority = currentIsPriority; + } } endResetModel(); @@ -153,4 +167,9 @@ Import ItemLibraryAddImportModel::getImportAt(int index) const return m_importList.at(index); } +void ItemLibraryAddImportModel::setPriorityImports(const QSet &priorityImports) +{ + m_priorityImports = priorityImports; +} + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryaddimportmodel.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryaddimportmodel.h index bab5ecf73c5..3ed6b3f3b5e 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryaddimportmodel.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryaddimportmodel.h @@ -50,11 +50,14 @@ public: void setSearchText(const QString &searchText); Import getImportAt(int index) const; + void setPriorityImports(const QSet &priorityImports); + private: QString m_searchText; QList m_importList; QSet m_importFilterList; QHash m_roleNames; + QSet m_priorityImports; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp index b78dcb6eece..f434788dda7 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp @@ -664,7 +664,12 @@ void ItemLibraryAssetImporter::finalizeQuick3DImport() timer->callOnTimeout([this, timer, progressTitle, model, doc]() { if (!isCancelled()) { notifyProgress(++counter * 5, progressTitle); - if (counter == 10) { + if (counter < 10) { + // Do not proceed while application isn't active as the filesystem + // watcher qmljs uses won't trigger unless application is active + if (QApplication::applicationState() != Qt::ApplicationActive) + --counter; + } else if (counter == 10) { model->rewriterView()->textModifier()->replace(0, 0, {}); } else if (counter == 19) { try { diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.cpp index 1845c025400..1cc032090e2 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.cpp @@ -127,6 +127,9 @@ void ItemLibraryCategoriesModel::sortCategorySections() }; std::sort(m_categoryList.begin(), m_categoryList.end(), categorySort); + + for (const auto &category : qAsConst(m_categoryList)) + category->sortItems(); } void ItemLibraryCategoriesModel::resetModel() diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.cpp index 1662b0ce966..55ef88a97c6 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.cpp @@ -70,6 +70,8 @@ bool ItemLibraryCategory::updateItemVisibility(const QString &searchText, bool * bool itemVisible = item->itemName().toLower().contains(searchText) || item->typeName().toLower().contains(searchText); + if (searchText.isEmpty() && !item->isUsable()) + itemVisible = false; bool itemChanged = item->setVisible(itemVisible); *changed |= itemChanged; diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.cpp index f2f22b1b74f..649d879895d 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.cpp @@ -28,18 +28,22 @@ namespace QmlDesigner { -ItemLibraryImport::ItemLibraryImport(const Import &import, QObject *parent, bool isUserSection) +ItemLibraryImport::ItemLibraryImport(const Import &import, QObject *parent, SectionType sectionType) : QObject(parent), m_import(import), - m_isUserSection(isUserSection) + m_sectionType(sectionType) { + updateRemovable(); } QString ItemLibraryImport::importName() const { - if (m_isUserSection) + if (m_sectionType == SectionType::User) return userComponentsTitle(); + if (m_sectionType == SectionType::Unimported) + return unimportedComponentsTitle(); + if (importUrl() == "QtQuick") return tr("Default Components"); @@ -48,9 +52,12 @@ QString ItemLibraryImport::importName() const QString ItemLibraryImport::importUrl() const { - if (m_isUserSection) + if (m_sectionType == SectionType::User) return userComponentsTitle(); + if (m_sectionType == SectionType::Unimported) + return unimportedComponentsTitle(); + return m_import.url(); } @@ -61,11 +68,14 @@ bool ItemLibraryImport::importExpanded() const QString ItemLibraryImport::sortingName() const { - if (m_isUserSection) // user components always come first - return "_"; + if (m_sectionType == SectionType::User) + return "_"; // user components always come first + + if (m_sectionType == SectionType::Unimported) + return "zzzzzz"; // Unimported components always come last if (!hasCategories()) // imports with no categories are at the bottom of the list - return "zzzzz" + importName(); + return "zzzzz_" + importName(); return importName(); } @@ -113,6 +123,7 @@ bool ItemLibraryImport::setVisible(bool isVisible) { if (isVisible != m_isVisible) { m_isVisible = isVisible; + emit importVisibleChanged(); return true; } @@ -126,7 +137,11 @@ bool ItemLibraryImport::importVisible() const void ItemLibraryImport::setImportUsed(bool importUsed) { - m_importUsed = importUsed; + if (importUsed != m_importUsed) { + m_importUsed = importUsed; + updateRemovable(); + emit importUsedChanged(); + } } bool ItemLibraryImport::importUsed() const @@ -134,6 +149,11 @@ bool ItemLibraryImport::importUsed() const return m_importUsed; } +bool ItemLibraryImport::importRemovable() const +{ + return m_importRemovable; +} + bool ItemLibraryImport::hasCategories() const { return m_categoryModel.rowCount() > 0; @@ -146,7 +166,10 @@ void ItemLibraryImport::sortCategorySections() void ItemLibraryImport::setImportExpanded(bool expanded) { - m_importExpanded = expanded; + if (expanded != m_importExpanded) { + m_importExpanded = expanded; + emit importExpandChanged(); + } } ItemLibraryCategory *ItemLibraryImport::getCategorySection(const QString &categoryName) const @@ -159,15 +182,30 @@ ItemLibraryCategory *ItemLibraryImport::getCategorySection(const QString &catego return nullptr; } -bool ItemLibraryImport::isUserSection() const -{ - return m_isUserSection; -} - // static QString ItemLibraryImport::userComponentsTitle() { return tr("My Components"); } +QString ItemLibraryImport::unimportedComponentsTitle() +{ + return tr("All Other Components"); +} + +ItemLibraryImport::SectionType ItemLibraryImport::sectionType() const +{ + return m_sectionType; +} + +void ItemLibraryImport::updateRemovable() +{ + bool importRemovable = !m_importUsed && m_sectionType == SectionType::Default + && m_import.url() != "QtQuick"; + if (importRemovable != m_importRemovable) { + m_importRemovable = importRemovable; + emit importRemovableChanged(); + } +} + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.h index c922e984084..8993dfcb8b6 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.h @@ -41,10 +41,18 @@ class ItemLibraryImport : public QObject Q_PROPERTY(bool importVisible READ importVisible NOTIFY importVisibleChanged FINAL) Q_PROPERTY(bool importUsed READ importUsed NOTIFY importUsedChanged FINAL) Q_PROPERTY(bool importExpanded READ importExpanded WRITE setImportExpanded NOTIFY importExpandChanged FINAL) + Q_PROPERTY(bool importRemovable READ importRemovable NOTIFY importRemovableChanged FINAL) Q_PROPERTY(QObject *categoryModel READ categoryModel NOTIFY categoryModelChanged FINAL) public: - ItemLibraryImport(const Import &import, QObject *parent = nullptr, bool isUserSection = false); + enum class SectionType { + Default, + User, + Unimported + }; + + ItemLibraryImport(const Import &import, QObject *parent = nullptr, + SectionType sectionType = SectionType::Default); QString importName() const; QString importUrl() const; @@ -53,6 +61,7 @@ public: Import importEntry() const; bool importVisible() const; bool importUsed() const; + bool importRemovable() const; bool hasCategories() const; ItemLibraryCategory *getCategorySection(const QString &categoryName) const; @@ -66,21 +75,26 @@ public: void expandCategories(bool expand = true); static QString userComponentsTitle(); + static QString unimportedComponentsTitle(); - bool isUserSection() const; + SectionType sectionType() const; signals: void categoryModelChanged(); void importVisibleChanged(); void importUsedChanged(); void importExpandChanged(); + void importRemovableChanged(); private: + void updateRemovable(); + Import m_import; bool m_importExpanded = true; bool m_isVisible = true; bool m_importUsed = false; - bool m_isUserSection = false; // user components import section + bool m_importRemovable = false; + SectionType m_sectionType = SectionType::Default; ItemLibraryCategoriesModel m_categoryModel; }; diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitem.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitem.cpp index 31d5edb57cf..78e06f0b56b 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitem.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitem.cpp @@ -27,9 +27,10 @@ namespace QmlDesigner { -ItemLibraryItem::ItemLibraryItem(const ItemLibraryEntry &itemLibraryEntry, QObject *parent) - : QObject(parent), - m_itemLibraryEntry(itemLibraryEntry) +ItemLibraryItem::ItemLibraryItem(const ItemLibraryEntry &itemLibraryEntry, bool isUsable, QObject *parent) + : QObject(parent) + , m_itemLibraryEntry(itemLibraryEntry) + , m_isUsable(isUsable) { } @@ -61,6 +62,11 @@ QString ItemLibraryItem::componentPath() const return m_itemLibraryEntry.customComponentSource(); } +QString ItemLibraryItem::requiredImport() const +{ + return m_itemLibraryEntry.requiredImport(); +} + bool ItemLibraryItem::setVisible(bool isVisible) { if (isVisible != m_isVisible) { @@ -77,6 +83,11 @@ bool ItemLibraryItem::isVisible() const return m_isVisible; } +bool ItemLibraryItem::isUsable() const +{ + return m_isUsable; +} + QVariant ItemLibraryItem::itemLibraryEntry() const { return QVariant::fromValue(m_itemLibraryEntry); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitem.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitem.h index d7321b11794..564a2a9aa54 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitem.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitem.h @@ -43,18 +43,22 @@ class ItemLibraryItem: public QObject Q_PROPERTY(QString itemLibraryIconPath READ itemLibraryIconPath FINAL) Q_PROPERTY(bool itemVisible READ isVisible NOTIFY visibilityChanged FINAL) Q_PROPERTY(QString componentPath READ componentPath FINAL) + Q_PROPERTY(bool itemUsable READ isUsable FINAL) + Q_PROPERTY(QString itemRequiredImport READ requiredImport FINAL) public: - ItemLibraryItem(const ItemLibraryEntry &itemLibraryEntry, QObject *parent); + ItemLibraryItem(const ItemLibraryEntry &itemLibraryEntry, bool isImported, QObject *parent); ~ItemLibraryItem() override; QString itemName() const; QString typeName() const; QString itemLibraryIconPath() const; QString componentPath() const; + QString requiredImport() const; bool setVisible(bool isVisible); bool isVisible() const; + bool isUsable() const; QVariant itemLibraryEntry() const; @@ -64,6 +68,7 @@ signals: private: ItemLibraryEntry m_itemLibraryEntry; bool m_isVisible = true; + bool m_isUsable = false; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitemsmodel.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitemsmodel.cpp index b9530917241..f4f02d124d6 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitemsmodel.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitemsmodel.cpp @@ -70,7 +70,7 @@ void ItemLibraryItemsModel::addItem(ItemLibraryItem *element) { m_itemList.append(element); - element->setVisible(true); + element->setVisible(element->isUsable()); } const QList> &ItemLibraryItemsModel::items() const diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp index 25bef1edd4b..4def2f46dc3 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp @@ -167,7 +167,7 @@ void ItemLibraryModel::setSearchText(const QString &searchText) } } -Import entryToImport(const ItemLibraryEntry &entry) +Import ItemLibraryModel::entryToImport(const ItemLibraryEntry &entry) { if (entry.majorVersion() == -1 && entry.minorVersion() == -1) return Import::createFileImport(entry.requiredImport()); @@ -177,6 +177,28 @@ Import entryToImport(const ItemLibraryEntry &entry) } +// Returns true if first import version is higher or equal to second import version +static bool compareVersions(const QString &version1, const QString &version2) +{ + if (version2.isEmpty() || version1 == version2) + return true; + const QStringList version1List = version1.split(QLatin1Char('.')); + const QStringList version2List = version2.split(QLatin1Char('.')); + if (version1List.count() == 2 && version2List.count() == 2) { + int major1 = version1List.constFirst().toInt(); + int major2 = version2List.constFirst().toInt(); + if (major1 > major2) { + return true; + } else if (major1 == major2) { + int minor1 = version1List.constLast().toInt(); + int minor2 = version2List.constLast().toInt(); + if (minor1 >= minor2) + return true; + } + } + return false; +} + void ItemLibraryModel::update(ItemLibraryInfo *itemLibraryInfo, Model *model) { if (!model) @@ -190,60 +212,91 @@ void ItemLibraryModel::update(ItemLibraryInfo *itemLibraryInfo, Model *model) QString projectName = project ? project->displayName() : ""; // create import sections + QHash importHash; for (const Import &import : model->imports()) { if (import.isLibraryImport() && import.url() != projectName) { - ItemLibraryImport *itemLibImport = new ItemLibraryImport(import, this); - m_importList.append(itemLibImport); - itemLibImport->setImportExpanded(loadExpandedState(import.url())); + bool addNew = true; + ItemLibraryImport *oldImport = importHash.value(import.url()); + if (oldImport && oldImport->importEntry().url() == import.url()) { + // Retain the higher version if multiples exist + if (compareVersions(oldImport->importEntry().version(), import.version())) + addNew = false; + else + delete oldImport; + } + if (addNew) { + ItemLibraryImport *itemLibImport = new ItemLibraryImport(import, this); + importHash.insert(import.url(), itemLibImport); + } } } + for (const auto itemLibImport : qAsConst(importHash)) { + m_importList.append(itemLibImport); + itemLibImport->setImportExpanded(loadExpandedState(itemLibImport->importEntry().url())); + } + const QList itemLibEntries = itemLibraryInfo->entries(); for (const ItemLibraryEntry &entry : itemLibEntries) { NodeMetaInfo metaInfo = model->metaInfo(entry.typeName()); bool valid = metaInfo.isValid() && metaInfo.majorVersion() == entry.majorVersion(); bool isItem = valid && metaInfo.isSubclassOf("QtQuick.Item"); - bool forceVisiblity = valid && NodeHints::fromItemLibraryEntry(entry).visibleInLibrary(); + bool forceVisibility = valid && NodeHints::fromItemLibraryEntry(entry).visibleInLibrary(); if (m_flowMode && metaInfo.isValid()) { isItem = metaInfo.isSubclassOf("FlowView.FlowItem") || metaInfo.isSubclassOf("FlowView.FlowWildcard") || metaInfo.isSubclassOf("FlowView.FlowDecision"); - forceVisiblity = isItem; + forceVisibility = isItem; } + bool blocked = false; const DesignerMcuManager &mcuManager = DesignerMcuManager::instance(); if (mcuManager.isMCUProject()) { const QSet blockTypes = mcuManager.bannedItems(); if (blockTypes.contains(QString::fromUtf8(entry.typeName()))) - valid = false; + blocked = true; } - if (valid && (isItem || forceVisiblity) // We can change if the navigator does support pure QObjects - && (entry.requiredImport().isEmpty() - || model->hasImport(entryToImport(entry), true, true))) { - + Import import = entryToImport(entry); + bool hasImport = model->hasImport(import, true, true); + bool isImportPossible = false; + if (!hasImport) + isImportPossible = model->isImportPossible(import, true, true); + bool isUsable = (valid && (isItem || forceVisibility)) + && (entry.requiredImport().isEmpty() || hasImport); + if (!blocked && (isUsable || isImportPossible)) { ItemLibraryImport *importSection = nullptr; - QString catName = entry.category(); - if (catName == ItemLibraryImport::userComponentsTitle()) { - // create an import section for user components - importSection = importByUrl(ItemLibraryImport::userComponentsTitle()); + if (isUsable) { + if (catName == ItemLibraryImport::userComponentsTitle()) { + // create an import section for user components + importSection = importByUrl(ItemLibraryImport::userComponentsTitle()); + if (!importSection) { + importSection = new ItemLibraryImport( + {}, this, ItemLibraryImport::SectionType::User); + m_importList.append(importSection); + importSection->setImportExpanded(loadExpandedState(catName)); + } + } else { + if (catName.startsWith("Qt Quick - ")) + catName = catName.mid(11); // remove "Qt Quick - " + importSection = importByUrl(entry.requiredImport()); + } + } else { + catName = ItemLibraryImport::unimportedComponentsTitle(); + importSection = importByUrl(catName); if (!importSection) { - importSection = new ItemLibraryImport({}, this, true); + importSection = new ItemLibraryImport( + {}, this, ItemLibraryImport::SectionType::Unimported); m_importList.append(importSection); importSection->setImportExpanded(loadExpandedState(catName)); } - } else { - if (catName.startsWith("Qt Quick - ")) - catName = catName.mid(11); // remove "Qt Quick - " - - importSection = importByUrl(entry.requiredImport()); } - if (!importSection) { // should not happen, but just in case + if (!importSection) { qWarning() << __FUNCTION__ << "No import section found! skipping entry: " << entry.name(); continue; } @@ -253,12 +306,12 @@ void ItemLibraryModel::update(ItemLibraryInfo *itemLibraryInfo, Model *model) if (!categorySection) { categorySection = new ItemLibraryCategory(catName, importSection); importSection->addCategory(categorySection); - if (!importSection->isUserSection()) + if (importSection->sectionType() == ItemLibraryImport::SectionType::Default) categorySection->setExpanded(loadExpandedState(categorySection->categoryName())); } // create item - auto item = new ItemLibraryItem(entry, categorySection); + auto item = new ItemLibraryItem(entry, isUsable, categorySection); categorySection->addItem(item); } } @@ -300,7 +353,9 @@ ItemLibraryImport *ItemLibraryModel::importByUrl(const QString &importUrl) const if (itemLibraryImport->importUrl() == importUrl || (importUrl.isEmpty() && itemLibraryImport->importUrl() == "QtQuick") || (importUrl == ItemLibraryImport::userComponentsTitle() - && itemLibraryImport->isUserSection())) { + && itemLibraryImport->sectionType() == ItemLibraryImport::SectionType::User) + || (importUrl == ItemLibraryImport::unimportedComponentsTitle() + && itemLibraryImport->sectionType() == ItemLibraryImport::SectionType::Unimported)) { return itemLibraryImport; } } @@ -324,9 +379,11 @@ void ItemLibraryModel::updateVisibility(bool *changed) for (ItemLibraryImport *import : std::as_const(m_importList)) { bool categoryChanged = false; bool hasVisibleItems = import->updateCategoryVisibility(m_searchText, &categoryChanged); - *changed |= categoryChanged; + if (import->sectionType() == ItemLibraryImport::SectionType::Unimported) + *changed |= import->setVisible(!m_searchText.isEmpty()); + // expand import if it has an item matching search criteria if (hasVisibleItems && !import->importExpanded()) import->setImportExpanded(); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h index 535bfb014f9..2412550a3a0 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h @@ -69,6 +69,8 @@ public: Q_INVOKABLE void expandAll(); Q_INVOKABLE void collapseAll(); + Import entryToImport(const ItemLibraryEntry &entry); + private: void updateVisibility(bool *changed); void addRoleNames(); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp index 9fdef025483..7ce542de024 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp @@ -86,15 +86,35 @@ bool ItemLibraryWidget::eventFilter(QObject *obj, QEvent *event) QMetaObject::invokeMethod(m_itemViewQuickWidget->rootObject(), "closeContextMenu"); } else if (event->type() == QMouseEvent::MouseMove) { if (m_itemToDrag.isValid()) { - ItemLibraryEntry entry = m_itemToDrag.value(); - auto drag = new QDrag(this); - drag->setPixmap(Utils::StyleHelper::dpiSpecificImageFile(entry.libraryEntryIconPath())); - drag->setMimeData(m_itemLibraryModel->getMimeData(entry)); - drag->exec(); - drag->deleteLater(); + QMouseEvent *me = static_cast(event); + if ((me->globalPos() - m_dragStartPoint).manhattanLength() > 10) { + ItemLibraryEntry entry = m_itemToDrag.value(); + // For drag to be handled correctly, we must have the component properly imported + // beforehand, so we import the module immediately when the drag starts + if (!entry.requiredImport().isEmpty()) { + Import import = Import::createLibraryImport(entry.requiredImport()); + if (!m_model->hasImport(import, true, true)) { + const QList possImports = m_model->possibleImports(); + for (const auto &possImport : possImports) { + if (possImport.url() == import.url()) { + m_model->changeImports({possImport}, {}); + break; + } + } + } + } - m_itemToDrag = {}; + auto drag = new QDrag(this); + drag->setPixmap(Utils::StyleHelper::dpiSpecificImageFile(entry.libraryEntryIconPath())); + drag->setMimeData(m_itemLibraryModel->getMimeData(entry)); + drag->exec(); + drag->deleteLater(); + + m_itemToDrag = {}; + } } + } else if (event->type() == QMouseEvent::MouseButtonRelease) { + m_itemToDrag = {}; } return QObject::eventFilter(obj, event); @@ -229,11 +249,16 @@ void ItemLibraryWidget::setItemLibraryInfo(ItemLibraryInfo *itemLibraryInfo) if (m_itemLibraryInfo) { disconnect(m_itemLibraryInfo.data(), &ItemLibraryInfo::entriesChanged, this, &ItemLibraryWidget::delayedUpdateModel); + disconnect(m_itemLibraryInfo.data(), &ItemLibraryInfo::priorityImportsChanged, + this, &ItemLibraryWidget::handlePriorityImportsChanged); } m_itemLibraryInfo = itemLibraryInfo; if (itemLibraryInfo) { connect(m_itemLibraryInfo.data(), &ItemLibraryInfo::entriesChanged, this, &ItemLibraryWidget::delayedUpdateModel); + connect(m_itemLibraryInfo.data(), &ItemLibraryInfo::priorityImportsChanged, + this, &ItemLibraryWidget::handlePriorityImportsChanged); + m_itemLibraryAddImportModel->setPriorityImports(m_itemLibraryInfo->priorityImports()); } delayedUpdateModel(); } @@ -344,6 +369,7 @@ void ItemLibraryWidget::updateModel() void ItemLibraryWidget::updatePossibleImports(const QList &possibleImports) { m_itemLibraryAddImportModel->update(possibleImports); + delayedUpdateModel(); } void ItemLibraryWidget::updateUsedImports(const QList &usedImports) @@ -365,6 +391,14 @@ void ItemLibraryWidget::updateSearch() } } +void ItemLibraryWidget::handlePriorityImportsChanged() +{ + if (!m_itemLibraryInfo.isNull()) { + m_itemLibraryAddImportModel->setPriorityImports(m_itemLibraryInfo->priorityImports()); + m_itemLibraryAddImportModel->update(m_model->possibleImports()); + } +} + void ItemLibraryWidget::setResourcePath(const QString &resourcePath) { if (m_resourcesView->model() == m_resourcesFileSystemModel.data()) { @@ -374,12 +408,13 @@ void ItemLibraryWidget::setResourcePath(const QString &resourcePath) updateSearch(); } -void ItemLibraryWidget::startDragAndDrop(const QVariant &itemLibEntry) +void ItemLibraryWidget::startDragAndDrop(const QVariant &itemLibEntry, const QPointF &mousePos) { // Actual drag is created after mouse has moved to avoid a QDrag bug that causes drag to stay // active (and blocks mouse release) if mouse is released at the same spot of the drag start. // This doesn't completely eliminate the bug but makes it significantly harder to produce. m_itemToDrag = itemLibEntry; + m_dragStartPoint = mousePos.toPoint(); } void ItemLibraryWidget::setFlowMode(bool b) @@ -396,6 +431,15 @@ void ItemLibraryWidget::removeImport(const QString &importUrl) m_model->changeImports({}, {importSection->importEntry()}); } +void ItemLibraryWidget::addImportForItem(const QVariant &entry) +{ + QTC_ASSERT(m_itemLibraryModel, return); + QTC_ASSERT(m_model, return); + + Import import = m_itemLibraryModel->entryToImport(entry.value()); + m_model->changeImports({import}, {}); +} + void ItemLibraryWidget::addResources(const QStringList &files) { auto document = QmlDesignerPlugin::instance()->currentDesignDocument(); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h index 5bde054fc9b..0b78c485e58 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h @@ -39,6 +39,7 @@ #include #include #include +#include #include @@ -87,8 +88,9 @@ public: void setModel(Model *model); void setFlowMode(bool b); - Q_INVOKABLE void startDragAndDrop(const QVariant &itemLibEntry); + Q_INVOKABLE void startDragAndDrop(const QVariant &itemLibEntry, const QPointF &mousePos); Q_INVOKABLE void removeImport(const QString &importUrl); + Q_INVOKABLE void addImportForItem(const QVariant &entry); signals: void itemActivated(const QString& itemName); @@ -102,6 +104,7 @@ private: void addResources(const QStringList &files); void importDroppedFiles(const QList &files); void updateSearch(); + void handlePriorityImportsChanged(); QTimer m_compressionTimer; QSize m_itemIconSize; @@ -126,6 +129,7 @@ private: QVariant m_itemToDrag; bool m_updateRetry = false; QString m_filterText; + QPoint m_dragStartPoint; private slots: void handleTabChanged(int index); diff --git a/src/plugins/qmldesigner/components/itemlibrary/qml/addimport.qml b/src/plugins/qmldesigner/components/itemlibrary/qml/addimport.qml index 60712394abd..e73623bd7ee 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/qml/addimport.qml +++ b/src/plugins/qmldesigner/components/itemlibrary/qml/addimport.qml @@ -57,9 +57,11 @@ Column { delegate: Rectangle { width: listView.width - height: 25 - color: mouseArea.containsMouse ? Qt.lighter(Theme.qmlDesignerButtonColor(), 1.3) - : Theme.qmlDesignerButtonColor() + height: isSeparator ? 4 : 25 + color: isSeparator ? Theme.color(Theme.BackgroundColorNormal) + : mouseArea.containsMouse + ? Qt.lighter(Theme.qmlDesignerButtonColor(), 1.3) + : Theme.qmlDesignerButtonColor() visible: importVisible Text { @@ -77,6 +79,7 @@ Column { anchors.fill: parent hoverEnabled: true onClicked: addImport(index) + enabled: !isSeparator } } } diff --git a/src/plugins/qmldesigner/components/richtexteditor/richtexteditorproxy.cpp b/src/plugins/qmldesigner/components/richtexteditor/richtexteditorproxy.cpp index 12e0cee41bc..5d7d631ccf5 100644 --- a/src/plugins/qmldesigner/components/richtexteditor/richtexteditorproxy.cpp +++ b/src/plugins/qmldesigner/components/richtexteditor/richtexteditorproxy.cpp @@ -24,23 +24,25 @@ ****************************************************************************/ #include "richtexteditorproxy.h" +#include "richtexteditor.h" #include #include +#include + #include #include #include -#include "richtexteditor.h" - namespace QmlDesigner { RichTextEditorProxy::RichTextEditorProxy(QObject *parent) : QObject(parent) - , m_dialog(new QDialog{}) + , m_dialog(new QDialog(Core::ICore::dialogParent())) , m_widget(new RichTextEditor{}) { + m_dialog->setModal(true); QGridLayout *layout = new QGridLayout{}; layout->addWidget(m_widget); diff --git a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorview.cpp b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorview.cpp index 3b648f5435a..97dc457f39c 100644 --- a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorview.cpp +++ b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorview.cpp @@ -110,7 +110,7 @@ void TransitionEditorView::nodeReparented(const ModelNode &node, const ModelNode parent = newPropertyParent.parentModelNode(); - qDebug() << Q_FUNC_INFO << parent; + // qDebug() << Q_FUNC_INFO << parent; if (parent.isValid() && parent.metaInfo().isValid() && parent.metaInfo().isSubclassOf("QtQuick.Transition")) { asyncUpdate(parent); diff --git a/src/plugins/qmldesigner/designercore/include/itemlibraryinfo.h b/src/plugins/qmldesigner/designercore/include/itemlibraryinfo.h index e7d0c3e2927..b31b3d916c3 100644 --- a/src/plugins/qmldesigner/designercore/include/itemlibraryinfo.h +++ b/src/plugins/qmldesigner/designercore/include/itemlibraryinfo.h @@ -29,6 +29,7 @@ #include "propertycontainer.h" #include +#include #include namespace QmlDesigner { @@ -108,11 +109,14 @@ public: void clearEntries(); QStringList blacklistImports() const; + QSet priorityImports() const; void addBlacklistImports(const QStringList &list); + void addPriorityImports(const QSet &set); signals: void entriesChanged(); + void priorityImportsChanged(); private: // functions ItemLibraryInfo(QObject *parent = nullptr); @@ -123,6 +127,7 @@ private: // variables QPointer m_baseInfo; QStringList m_blacklistImports; + QSet m_priorityImports; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/metainfo/itemlibraryinfo.cpp b/src/plugins/qmldesigner/designercore/metainfo/itemlibraryinfo.cpp index 4fc5e7c0887..5bdb5530f60 100644 --- a/src/plugins/qmldesigner/designercore/metainfo/itemlibraryinfo.cpp +++ b/src/plugins/qmldesigner/designercore/metainfo/itemlibraryinfo.cpp @@ -344,11 +344,27 @@ QStringList ItemLibraryInfo::blacklistImports() const return list; } +QSet ItemLibraryInfo::priorityImports() const +{ + QSet set = m_priorityImports; + if (m_baseInfo) + set.unite(m_baseInfo->m_priorityImports); + return set; +} + void ItemLibraryInfo::addBlacklistImports(const QStringList &list) { m_blacklistImports.append(list); } +void ItemLibraryInfo::addPriorityImports(const QSet &set) +{ + if (!set.isEmpty()) { + m_priorityImports.unite(set); + emit priorityImportsChanged(); + } +} + void ItemLibraryInfo::setBaseInfo(ItemLibraryInfo *baseInfo) { m_baseInfo = baseInfo; diff --git a/src/plugins/qmldesigner/designercore/metainfo/metainforeader.cpp b/src/plugins/qmldesigner/designercore/metainfo/metainforeader.cpp index 83d826ad9ac..c9ae1ef0d0c 100644 --- a/src/plugins/qmldesigner/designercore/metainfo/metainforeader.cpp +++ b/src/plugins/qmldesigner/designercore/metainfo/metainforeader.cpp @@ -26,6 +26,8 @@ #include "metainforeader.h" #include "metainfo.h" +#include + #include #include #include @@ -230,8 +232,10 @@ void MetaInfoReader::readImportsProperty(const QString &name, const QVariant &va if (name == "blacklistImports" && !values.isEmpty()) { m_metaInfo.itemLibraryInfo()->addBlacklistImports(values); - } else if (name == "showTagsForImports" && !values.isEmpty()) { - // Flow tags removed, but keeping this for now to avoid errors parsing old metadata files + } else if ((name == "priorityImports" || name == "showTagsForImports") && !values.isEmpty()) { + // Flow tags are no longer shown, but the old property is still supported for prioritizing + // imports to keep compatibility with old metainfo files. + m_metaInfo.itemLibraryInfo()->addPriorityImports(Utils::toSet(values)); } else { addError(tr("Unknown property for Imports %1").arg(name), currentSourceLocation()); setParserState(Error); diff --git a/src/plugins/qmldesigner/qmldesignerplugin.cpp b/src/plugins/qmldesigner/qmldesignerplugin.cpp index d8c9f60f5ec..1d56ef0e8ce 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.cpp +++ b/src/plugins/qmldesigner/qmldesignerplugin.cpp @@ -45,8 +45,6 @@ #include #include -#include - #include #include #include @@ -62,6 +60,7 @@ #include #include #include +#include #include #include #include @@ -71,6 +70,7 @@ #include #include +#include #include #include @@ -232,12 +232,13 @@ bool QmlDesignerPlugin::initialize(const QStringList & /*arguments*/, QString *e bool QmlDesignerPlugin::delayedInitialize() { // adding default path to item library plugins - const QString pluginPath = Utils::HostOsInfo::isMacHost() - ? QString(QCoreApplication::applicationDirPath() + "/../PlugIns/QmlDesigner") - : QString(QCoreApplication::applicationDirPath() + "/../" - + QLatin1String(IDE_LIBRARY_BASENAME) + "/" + Core::Constants::IDE_ID - + "/plugins/qmldesigner"); - MetaInfo::setPluginPaths(QStringList(pluginPath)); + const QString postfix = Utils::HostOsInfo::isMacHost() ? QString("/QmlDesigner") + : QString("/qmldesigner"); + const QStringList pluginPaths = + Utils::transform(ExtensionSystem::PluginManager::pluginPaths(), [postfix](const QString &p) { + return QString(p + postfix); + }); + MetaInfo::setPluginPaths(pluginPaths); d->settings.fromSettings(Core::ICore::settings()); diff --git a/src/plugins/qmljseditor/qmljsfindreferences.cpp b/src/plugins/qmljseditor/qmljsfindreferences.cpp index 4d4fe5c7b94..a251e823062 100644 --- a/src/plugins/qmljseditor/qmljsfindreferences.cpp +++ b/src/plugins/qmljseditor/qmljsfindreferences.cpp @@ -1012,6 +1012,7 @@ void FindReferences::displayResults(int first, int last) item.setFilePath(Utils::FilePath::fromString(result.path)); item.setLineText(result.lineText); item.setMainRange(result.line, result.col, result.len); + item.setUseTextEditorFont(true); m_currentSearch->addResult(item); } } diff --git a/src/plugins/qmlprofiler/CMakeLists.txt b/src/plugins/qmlprofiler/CMakeLists.txt index 9b465f3e45d..016e874e039 100644 --- a/src/plugins/qmlprofiler/CMakeLists.txt +++ b/src/plugins/qmlprofiler/CMakeLists.txt @@ -1,4 +1,5 @@ add_qtc_plugin(QmlProfiler + CONDITION TARGET Tracing DEPENDS QmlDebug QmlJS Tracing Qt5::QuickWidgets PLUGIN_DEPENDS Core Debugger ProjectExplorer QtSupport TextEditor SOURCES diff --git a/src/plugins/qtsupport/gettingstartedwelcomepage.cpp b/src/plugins/qtsupport/gettingstartedwelcomepage.cpp index fa75520ef34..bd93f8407f1 100644 --- a/src/plugins/qtsupport/gettingstartedwelcomepage.cpp +++ b/src/plugins/qtsupport/gettingstartedwelcomepage.cpp @@ -287,6 +287,10 @@ public: m_searcher->setPlaceholderText(ExamplesWelcomePage::tr("Search in Examples...")); auto exampleSetSelector = new QComboBox(this); + QPalette pal = exampleSetSelector->palette(); + // for macOS dark mode + pal.setColor(QPalette::Text, Utils::creatorTheme()->color(Theme::Welcome_TextColor)); + exampleSetSelector->setPalette(pal); exampleSetSelector->setMinimumWidth(GridProxyModel::GridItemWidth); exampleSetSelector->setMaximumWidth(GridProxyModel::GridItemWidth); ExampleSetModel *exampleSetModel = m_examplesModel->exampleSetModel(); diff --git a/src/plugins/remotelinux/rsyncdeploystep.cpp b/src/plugins/remotelinux/rsyncdeploystep.cpp index 7aafa41b46f..65ffce4030b 100644 --- a/src/plugins/remotelinux/rsyncdeploystep.cpp +++ b/src/plugins/remotelinux/rsyncdeploystep.cpp @@ -159,8 +159,19 @@ void RsyncDeployService::deployNextFile() } const DeployableFile file = m_deployableFiles.takeFirst(); const RsyncCommandLine cmdLine = RsyncDeployStep::rsyncCommand(*connection(), m_flags); + QString localFilePath = file.localFilePath().toString(); + + // On Windows, rsync is either from msys or cygwin. Neither work with the other's ssh.exe. + if (HostOsInfo::isWindowsHost()) { + localFilePath = '/' + localFilePath.at(0) + localFilePath.mid(2); + if (anyOf(cmdLine.options, [](const QString &opt) { + return opt.contains("cygwin", Qt::CaseInsensitive); })) { + localFilePath.prepend("/cygdrive"); + } + } + const QStringList args = QStringList(cmdLine.options) - << (file.localFilePath().toString() + (file.localFilePath().isDir() ? "/" : QString())) + << (localFilePath + (file.localFilePath().isDir() ? "/" : QString())) << (cmdLine.remoteHostSpec + ':' + file.remoteFilePath()); m_rsync.start("rsync", args); // TODO: Get rsync location from settings? } @@ -228,7 +239,7 @@ RsyncCommandLine RsyncDeployStep::rsyncCommand(const SshConnection &sshConnectio { const QString sshCmdLine = QtcProcess::joinArgs( QStringList{SshSettings::sshFilePath().toUserOutput()} - << sshConnection.connectionOptions(SshSettings::sshFilePath())); + << sshConnection.connectionOptions(SshSettings::sshFilePath()), OsTypeLinux); const SshConnectionParameters sshParams = sshConnection.connectionParameters(); return RsyncCommandLine(QStringList{"-e", sshCmdLine, flags}, sshParams.userName() + '@' + sshParams.host()); diff --git a/src/plugins/studiowelcome/CMakeLists.txt b/src/plugins/studiowelcome/CMakeLists.txt index b04caf2a6d4..fe7f34ca7f4 100644 --- a/src/plugins/studiowelcome/CMakeLists.txt +++ b/src/plugins/studiowelcome/CMakeLists.txt @@ -4,6 +4,7 @@ add_qtc_plugin(StudioWelcome DEFINES STUDIO_QML_PATH="${CMAKE_CURRENT_SOURCE_DIR}/qml/" SOURCES studiowelcomeplugin.cpp studiowelcomeplugin.h + examplecheckout.cpp examplecheckout.h studiowelcome_global.h studiowelcome.qrc "${PROJECT_SOURCE_DIR}/src/share/3rdparty/studiofonts/studiofonts.qrc" diff --git a/src/plugins/studiowelcome/examplecheckout.cpp b/src/plugins/studiowelcome/examplecheckout.cpp new file mode 100644 index 00000000000..c7180155d85 --- /dev/null +++ b/src/plugins/studiowelcome/examplecheckout.cpp @@ -0,0 +1,347 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ +#include "examplecheckout.h" + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +ExampleCheckout::ExampleCheckout(QObject *) {} + +void ExampleCheckout::checkoutExample(const QUrl &url) +{ + FileDownloader::registerQmlType(); + static bool once = []() { + FileDownloader::registerQmlType(); + FileExtractor::registerQmlType(); + return true; + }(); + + QTC_ASSERT(once, ;); + + m_dialog.reset(new QDialog(Core::ICore::dialogParent())); + m_dialog->setModal(true); + m_dialog->setFixedSize(620, 300); + QHBoxLayout *layout = new QHBoxLayout(m_dialog.get()); + layout->setContentsMargins(2, 2, 2, 2); + + auto widget = new QQuickWidget(m_dialog.get()); + + layout->addWidget(widget); + widget->engine()->addImportPath("qrc:/studiofonts"); + + widget->engine()->addImportPath(Core::ICore::resourcePath() + + "/qmldesigner/propertyEditorQmlSources/imports"); + + widget->setSource(QUrl("qrc:/qml/downloaddialog/main.qml")); + + m_dialog->setWindowFlag(Qt::Tool, true); + widget->setResizeMode(QQuickWidget::SizeRootObjectToView); + + rootObject = widget->rootObject(); + + QTC_ASSERT(rootObject, qWarning() << "QML error"; return ); + + rootObject->setProperty("url", url); + + m_dialog->show(); + + rootObject = widget->rootObject(); + + connect(rootObject, SIGNAL(canceled()), this, SLOT(handleCancel())); + connect(rootObject, SIGNAL(accepted()), this, SLOT(handleAccepted())); +} + +QString ExampleCheckout::extractionFolder() const +{ + return m_extrationFolder; +} + +ExampleCheckout::~ExampleCheckout() {} + +void ExampleCheckout::handleCancel() +{ + m_dialog->close(); + m_dialog.release()->deleteLater(); + deleteLater(); +} + +void ExampleCheckout::handleAccepted() +{ + QQmlProperty property(rootObject, "path"); + m_extrationFolder = property.read().toString(); + m_dialog->close(); + emit finishedSucessfully(); + m_dialog.release()->deleteLater(); + deleteLater(); +} + +void FileDownloader::registerQmlType() +{ + qmlRegisterType("ExampleCheckout", 1, 0, "FileDownloader"); +} + +FileDownloader::FileDownloader(QObject *parent) + : QObject(parent) +{} + +FileDownloader::~FileDownloader() +{ + m_tempFile.remove(); +} + +void FileDownloader::start() +{ + m_tempFile.setFileName(QDir::tempPath() + "/" + name() + ".XXXXXX" + ".zip"); + + m_tempFile.open(QIODevice::WriteOnly); + + auto request = QNetworkRequest(m_url); + request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, true); + QNetworkReply *reply = Utils::NetworkAccessManager::instance()->get(request); + + QNetworkReply::connect(reply, &QNetworkReply::readyRead, [this, reply]() { + m_tempFile.write(reply->readAll()); + }); + + QNetworkReply::connect(reply, + &QNetworkReply::downloadProgress, + this, + [this](qint64 current, qint64 max) { + if (max == 0) + return; + + m_progress = current * 100 / max; + emit progressChanged(); + }); + + QNetworkReply::connect(reply, &QNetworkReply::finished, [this, reply]() { + if (reply->error()) { + m_tempFile.remove(); + if (m_url != reply->url()) { + m_url = reply->url(); + start(); + } else { + emit downloadFailed(); + } + } else { + m_tempFile.flush(); + m_tempFile.close(); + m_finished = true; + emit finishedChanged(); + } + }); +} + +void FileDownloader::setUrl(const QUrl &url) +{ + m_url = url; + + emit nameChanged(); +} + +QUrl FileDownloader::url() const +{ + return m_url; +} + +bool FileDownloader::finished() const +{ + return m_finished; +} + +bool FileDownloader::error() const +{ + return m_error; +} + +QString FileDownloader::name() const +{ + const QFileInfo fileInfo(m_url.path()); + return fileInfo.baseName(); +} + +QString FileDownloader::completeBaseName() const +{ + const QFileInfo fileInfo(m_url.path()); + return fileInfo.completeBaseName(); +} + +int FileDownloader::progress() const +{ + return m_progress; +} + +QString FileDownloader::tempFile() const +{ + return QFileInfo(m_tempFile).canonicalFilePath(); +} + +FileExtractor::FileExtractor(QObject *parent) + : QObject(parent) +{ + if (Core::DocumentManager::instance()) + m_targetPath = Core::DocumentManager::projectsDirectory(); + else + m_targetPath = Utils::FilePath::fromString("/temp/"); + + m_timer.setInterval(500); + m_timer.setSingleShot(false); +} + +FileExtractor::~FileExtractor() {} + +void FileExtractor::registerQmlType() +{ + qmlRegisterType("ExampleCheckout", 1, 0, "FileExtractor"); +} + +QString FileExtractor::targetPath() const +{ + return m_targetPath.toUserOutput(); +} + +void FileExtractor::browse() +{ + const QString path = QFileDialog::getExistingDirectory(Core::ICore::dialogParent(), + (tr("Choose Directory")), + m_targetPath.toString()); + + if (!path.isEmpty()) + m_targetPath = Utils::FilePath::fromString(path); + + emit targetPathChanged(); + emit targetFolderExistsChanged(); +} + +void FileExtractor::setSourceFile(QString &sourceFilePath) +{ + m_sourceFile = Utils::FilePath::fromString(sourceFilePath); + emit targetFolderExistsChanged(); +} + +void FileExtractor::setArchiveName(QString &filePath) +{ + m_archiveName = filePath; +} + +const QString FileExtractor::detailedText() +{ + return m_detailedText; +} + +bool FileExtractor::finished() const +{ + return m_finished; +} + +QString FileExtractor::currentFile() const +{ + return m_currentFile; +} + +QString FileExtractor::size() const +{ + return m_size; +} + +QString FileExtractor::count() const +{ + return m_count; +} + +bool FileExtractor::targetFolderExists() const +{ + const QString targetFolder = m_targetPath.toString() + "/" + m_archiveName; + return QFileInfo(targetFolder).exists(); +} + +QString FileExtractor::archiveName() const +{ + return m_archiveName; +} + +QString FileExtractor::sourceFile() const +{ + return m_sourceFile.toString(); +} + +void FileExtractor::extract() +{ + Utils::Archive *archive = Utils::Archive::unarchive(m_sourceFile, m_targetPath); + archive->setParent(this); + QTC_ASSERT(archive, return ); + + m_timer.start(); + const QString targetFolder = m_targetPath.toString() + "/" + m_archiveName; + qint64 bytesBefore = QStorageInfo(m_targetPath.toFileInfo().dir()).bytesAvailable(); + + QTimer::connect(&m_timer, &QTimer::timeout, [this, bytesBefore, targetFolder]() { + static QHash hash; + QDirIterator it(targetFolder, {"*.*"}, QDir::Files, QDirIterator::Subdirectories); + + int count = 0; + while (it.hasNext()) { + if (!hash.contains(it.fileName())) { + m_currentFile = it.fileName(); + hash.insert(m_currentFile, 0); + emit currentFileChanged(); + } + it.next(); + count++; + } + + m_size = QString::number(bytesBefore + - QStorageInfo(m_targetPath.toFileInfo().dir()).bytesAvailable()); + + m_count = QString::number(count); + emit sizeChanged(); + }); + + QObject::connect(archive, &Utils::Archive::outputReceived, this, [this](const QString &output) { + m_detailedText += output; + emit detailedTextChanged(); + }); + + QObject::connect(archive, &Utils::Archive::finished, [this](bool ret) { + m_finished = ret; + m_timer.stop(); + emit finishedChanged(); + QTC_ASSERT(ret, ;); + }); +} diff --git a/src/plugins/studiowelcome/examplecheckout.h b/src/plugins/studiowelcome/examplecheckout.h new file mode 100644 index 00000000000..0038d7f2c0f --- /dev/null +++ b/src/plugins/studiowelcome/examplecheckout.h @@ -0,0 +1,163 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include + +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE +class QDialog; +QT_END_NAMESPACE + +class ExampleCheckout : public QObject +{ + Q_OBJECT +public: + explicit ExampleCheckout(QObject *parent = nullptr); + + Q_INVOKABLE void checkoutExample(const QUrl &url); + + QString extractionFolder() const; + + ~ExampleCheckout(); + +public slots: + void handleCancel(); + void handleAccepted(); + +signals: + void finishedSucessfully(); + +private: + std::unique_ptr m_dialog; + QObject *rootObject = nullptr; + QString m_extrationFolder; +}; + +class FileExtractor : public QObject +{ + Q_OBJECT + + Q_PROPERTY(QString targetPath READ targetPath NOTIFY targetPathChanged) + Q_PROPERTY(QString archiveName READ archiveName WRITE setArchiveName) + Q_PROPERTY(QString detailedText READ detailedText NOTIFY detailedTextChanged) + Q_PROPERTY(QString currentFile READ currentFile NOTIFY currentFileChanged) + Q_PROPERTY(QString size READ size NOTIFY sizeChanged) + Q_PROPERTY(QString count READ count NOTIFY sizeChanged) + Q_PROPERTY(QString sourceFile READ sourceFile WRITE setSourceFile) + Q_PROPERTY(bool finished READ finished NOTIFY finishedChanged) + Q_PROPERTY(bool targetFolderExists READ targetFolderExists NOTIFY targetFolderExistsChanged) + +public: + explicit FileExtractor(QObject *parent = nullptr); + ~FileExtractor(); + + static void registerQmlType(); + + QString targetPath() const; + void setSourceFile(QString &sourceFilePath); + void setArchiveName(QString &filePath); + const QString detailedText(); + bool finished() const; + QString currentFile() const; + QString size() const; + QString count() const; + bool targetFolderExists() const; + + QString sourceFile() const; + QString archiveName() const; + + Q_INVOKABLE void browse(); + Q_INVOKABLE void extract(); + +signals: + void targetPathChanged(); + void detailedTextChanged(); + void finishedChanged(); + void currentFileChanged(); + void sizeChanged(); + void targetFolderExistsChanged(); + +private: + Utils::FilePath m_targetPath; + Utils::FilePath m_sourceFile; + QString m_detailedText; + bool m_finished = false; + QTimer m_timer; + QString m_currentFile; + QString m_size; + QString m_count; + QString m_archiveName; +}; + +class FileDownloader : public QObject +{ + Q_OBJECT + + Q_PROPERTY(QUrl url READ url WRITE setUrl) + Q_PROPERTY(bool finished READ finished NOTIFY finishedChanged) + Q_PROPERTY(bool error READ error NOTIFY errorChanged) + Q_PROPERTY(QString name READ name NOTIFY nameChanged) + Q_PROPERTY(QString completeBaseName READ completeBaseName NOTIFY nameChanged) + Q_PROPERTY(int progress READ progress NOTIFY progressChanged) + Q_PROPERTY(QString tempFile READ tempFile NOTIFY finishedChanged) + +public: + explicit FileDownloader(QObject *parent = nullptr); + + ~FileDownloader(); + + void setUrl(const QUrl &url); + QUrl url() const; + bool finished() const; + bool error() const; + static void registerQmlType(); + QString name() const; + QString completeBaseName() const; + int progress() const; + QString tempFile() const; + + Q_INVOKABLE void start(); + +signals: + void finishedChanged(); + void errorChanged(); + void nameChanged(); + void progressChanged(); + void downloadFailed(); + +private: + QUrl m_url; + bool m_finished = false; + bool m_error = false; + int m_progress = 0; + QFile m_tempFile; +}; diff --git a/src/plugins/studiowelcome/qml/downloaddialog/ArcItem.qml b/src/plugins/studiowelcome/qml/downloaddialog/ArcItem.qml new file mode 100644 index 00000000000..fa38d302dba --- /dev/null +++ b/src/plugins/studiowelcome/qml/downloaddialog/ArcItem.qml @@ -0,0 +1,249 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +import QtQuick 2.9 +import QtQuick.Shapes 1.0 + +Shape { + id: root + + implicitWidth: 100 + implicitHeight: 100 + + property alias gradient: path.fillGradient + property alias strokeStyle: path.strokeStyle + property alias strokeWidth: path.strokeWidth + property alias strokeColor: path.strokeColor + property alias dashPattern: path.dashPattern + property alias joinStyle: path.joinStyle + property alias fillColor: path.fillColor + property alias capStyle: path.capStyle + property alias dashOffset: path.dashOffset + + property real begin: 0 + property real end: 90 + + property real arcWidth: 10 + + property real arcWidthBegin: arcWidth + property real arcWidthEnd: arcWidth + + property real radiusInnerAdjust: 0 + property real radiusOuterAdjust: 0 + + property real alpha: clamp(sortedEnd() - sortedBegin(),0, 359.9) + + layer.enabled: antialiasing + layer.smooth: antialiasing + layer.textureSize: Qt.size(width * 2, height * 2) + property bool outlineArc: false + + property bool round: false + + property bool roundEnd: round + property bool roundBegin: round + + function clamp(num, min, max) { + return num <= min ? min : num >= max ? max : num; + } + + function myCos(angleInDegrees) { + var angleInRadians = angleInDegrees * Math.PI / 180.0; + return Math.cos(angleInRadians) + } + + function mySin(angleInDegrees) { + var angleInRadians = angleInDegrees * Math.PI / 180.0; + return Math.sin(angleInRadians) + } + + function polarToCartesianX(centerX, centerY, radius, angleInDegrees) { + var angleInRadians = angleInDegrees * Math.PI / 180.0; + var x = centerX + radius * Math.cos(angleInRadians) + return x + } + + function polarToCartesianY(centerX, centerY, radius, angleInDegrees) { + var angleInRadians = angleInDegrees * Math.PI / 180.0; + var y = centerY + radius * Math.sin(angleInRadians); + return y + } + + function calc() + { + path.__xRadius = root.width / 2 - root.strokeWidth / 2 + path.__yRadius = root.height / 2 - root.strokeWidth / 2 + + path.__Xcenter = root.width / 2 + path.__Ycenter = root.height / 2 + + path.startX = root.polarToCartesianX(path.__Xcenter, path.__Ycenter, path.__xRadius, root.sortedBegin() - 90) + root.__beginOff * myCos(root.sortedBegin() + 90) + path.startY = root.polarToCartesianY(path.__Xcenter, path.__Ycenter, path.__yRadius, root.sortedBegin() - 90) + root.__beginOff * mySin(root.sortedBegin() + 90) + + arc1.x = root.polarToCartesianX(path.__Xcenter, path.__Ycenter, path.__xRadius, root.sortedEnd() - 90) + root.__endOff * myCos(root.sortedEnd() + 90) + arc1.y = root.polarToCartesianY(path.__Xcenter, path.__Ycenter, path.__yRadius, root.sortedEnd() - 90) + root.__endOff * mySin(root.sortedEnd() + 90) + + arc1.radiusX = path.__xRadius - root.__endOff / 2 -root.__beginOff / 2 + root.radiusOuterAdjust + arc1.radiusY = path.__yRadius - root.__endOff / 2 -root.__beginOff / 2 + root.radiusOuterAdjust + + arc1.useLargeArc = root.alpha > 180 + } + + function sortedBegin() + { + return(Math.min(root.begin, root.end)) + } + + function sortedEnd() + { + return(Math.max(root.begin, root.end)) + } + + + onWidthChanged: calc() + onHeightChanged: calc() + onBeginChanged: calc() + onEndChanged: calc() + onAlphaChanged: calc() + + ShapePath { + id: path + + property real __xRadius + property real __yRadius + + property real __Xcenter + property real __Ycenter + + strokeColor: "red" + strokeWidth: 4 + capStyle: ShapePath.FlatCap + } + + property real __beginOff: { + + if (root.arcWidthEnd > root.arcWidthBegin) + return (root.arcWidthEnd - root.arcWidthBegin) / 2 + + return 0; + } + + property real __endOff: { + + if (root.arcWidthBegin > root.arcWidthEnd) + return (root.arcWidthBegin - root.arcWidthEnd) / 2 + + return 0; + } + + property real __startP: root.arcWidthBegin + __beginOff + property real __endP: root.arcWidthEnd + __endOff + + Item { + id: shapes + PathArc { + id: arc1 + property bool add: true + } + + PathLine { + relativeX: root.arcWidthEnd * myCos(root.sortedEnd()) + relativeY: root.arcWidthEnd * mySin(root.sortedEnd()) + property bool add: !root.roundEnd && (root.outlineArc && root.alpha < 359.8) + + } + + PathArc { + relativeX: root.arcWidthEnd * myCos(root.sortedEnd()) + relativeY: root.arcWidthEnd * mySin(root.sortedEnd()) + radiusX: root.arcWidthEnd /2 + radiusY: root.arcWidthEnd /2 + property bool add: root.roundEnd && (root.outlineArc && root.alpha < 359.8) + } + + PathMove { + relativeX: root.arcWidthEnd * myCos(root.sortedEnd()) + relativeY: root.arcWidthEnd * mySin(root.sortedEnd()) + property bool add: root.outlineArc && root.alpha > 359.7 + } + + PathArc { + id: arc2 + useLargeArc: arc1.useLargeArc + + radiusX: path.__xRadius - root.arcWidthBegin + root.__beginOff / 2 + root.__endOff / 2 + root.radiusInnerAdjust + radiusY:path.__yRadius - root.arcWidthBegin + root.__beginOff / 2 + root.__endOff / 2 + root.radiusInnerAdjust + + x: path.startX + root.arcWidthBegin * myCos(root.sortedBegin()) + y: path.startY + root.arcWidthBegin * mySin(root.sortedBegin()) + + direction: PathArc.Counterclockwise + + property bool add: root.outlineArc + } + + + PathLine { + x: path.startX + y: path.startY + property bool add: !root.roundBegin && root.outlineArc && root.alpha < 359.8 + + } + + PathArc { + x: path.startX + y: path.startY + radiusX: root.arcWidthEnd /2 + radiusY: root.arcWidthEnd /2 + property bool add: root.roundBegin && root.outlineArc && root.alpha < 359.8 + } + + PathMove { + x: path.startX + y: path.startY + property bool add: root.outlineArc && root.alpha == 360 + } + } + + function invalidatePaths() { + if (!root.__completed) + return + + for (var i = 0; i < shapes.resources.length; i++) { + var s = shapes.resources[i]; + if (s.add) + path.pathElements.push(s) + } + + } + + property bool __completed: false + + Component.onCompleted: { + root.__completed = true + invalidatePaths() + calc() + } +} diff --git a/src/plugins/studiowelcome/qml/downloaddialog/CircularIndicator.ui.qml b/src/plugins/studiowelcome/qml/downloaddialog/CircularIndicator.ui.qml new file mode 100644 index 00000000000..15b2e265527 --- /dev/null +++ b/src/plugins/studiowelcome/qml/downloaddialog/CircularIndicator.ui.qml @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + + +import QtQuick 2.12 +import QtQuick.Timeline 1.0 + +Rectangle { + id: rectangle + width: 60 + height: 60 + color: "#8c8c8c" + radius: 50 + property alias inputMax: rangeMapper.inputMax + property alias inputMin: rangeMapper.inputMin + property alias value: minMaxMapper.input + + ArcItem { + id: arc + x: -1 + y: -1 + width: 62 + height: 62 + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + end: rangeMapper.value + antialiasing: true + strokeWidth: 8 + strokeColor: "#ffffff" + capStyle: 32 + fillColor: "#00000000" + } + + RangeMapper { + id: rangeMapper + outputMax: 358 + input: minMaxMapper.value + } + + MinMaxMapper { + id: minMaxMapper + input: 95 + max: rangeMapper.inputMax + min: rangeMapper.inputMin + } + + Rectangle { + id: rectangle1 + width: 60 + height: 60 + color: "#ffffff" + radius: 40 + anchors.verticalCenter: parent.verticalCenter + scale: 1 + anchors.horizontalCenter: parent.horizontalCenter + } + + Timeline { + id: timeline + currentFrame: rangeMapper.value + enabled: true + endFrame: 360 + startFrame: 0 + + KeyframeGroup { + target: rectangle1 + property: "opacity" + Keyframe { + frame: 0 + value: 0 + } + + Keyframe { + frame: 360 + value: 1 + } + } + + KeyframeGroup { + target: rectangle1 + property: "scale" + Keyframe { + frame: 360 + value: 1 + } + + Keyframe { + frame: 0 + value: 0.1 + } + } + + KeyframeGroup { + target: arc + property: "opacity" + Keyframe { + value: 0 + frame: 0 + } + + Keyframe { + value: 1 + frame: 40 + } + } + } +} diff --git a/src/plugins/studiowelcome/qml/downloaddialog/CoolProgressBar.ui.qml b/src/plugins/studiowelcome/qml/downloaddialog/CoolProgressBar.ui.qml new file mode 100644 index 00000000000..b48880406c5 --- /dev/null +++ b/src/plugins/studiowelcome/qml/downloaddialog/CoolProgressBar.ui.qml @@ -0,0 +1,193 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + + +import QtQuick 2.12 +import QtQuick.Timeline 1.0 + +Item { + id: coolProgressBar + width: 605 + height: 16 + property alias value: timeline.currentFrame + clip: true + + Timeline { + id: timeline + enabled: true + endFrame: 100 + startFrame: 0 + + KeyframeGroup { + target: rectangle + property: "width" + Keyframe { + value: 0 + frame: 0 + } + + Keyframe { + value: 150 + frame: 25 + } + + Keyframe { + value: 300 + frame: 50 + } + + Keyframe { + value: 450 + frame: 75 + } + + Keyframe { + value: 600 + frame: 100 + } + } + + KeyframeGroup { + target: rectangle1 + property: "width" + Keyframe { + value: 0 + frame: 0 + } + + Keyframe { + value: 300 + frame: 25 + } + + Keyframe { + value: 450 + frame: 50 + } + + Keyframe { + value: 600 + frame: 75 + } + } + + KeyframeGroup { + target: rectangle2 + property: "width" + Keyframe { + value: 0 + frame: 0 + } + + Keyframe { + value: 450 + frame: 25 + } + + Keyframe { + value: 600 + frame: 50 + } + } + + KeyframeGroup { + target: rectangle3 + property: "width" + Keyframe { + value: 0 + frame: 0 + } + + Keyframe { + value: 600 + frame: 25 + } + } + + KeyframeGroup { + target: content + property: "opacity" + Keyframe { + value: 0 + frame: 0 + } + + Keyframe { + value: 1 + frame: 50 + } + } + } + + Item { + id: content + anchors.fill: parent + + Rectangle { + id: rectangle + y: 0 + width: 80 + height: 16 + color: "#ffffff" + radius: 12 + } + + Rectangle { + id: rectangle1 + y: 0 + width: 80 + height: 16 + opacity: 0.6 + color: "#ffffff" + radius: 12 + } + + Rectangle { + id: rectangle2 + y: 0 + width: 80 + height: 16 + opacity: 0.4 + color: "#ffffff" + radius: 12 + } + + Rectangle { + id: rectangle3 + y: 0 + width: 80 + height: 16 + opacity: 0.2 + color: "#ffffff" + radius: 12 + } + } +} + +/*##^## +Designer { + D{i:0;height:16;width:590}D{i:1} +} +##^##*/ diff --git a/src/plugins/studiowelcome/qml/downloaddialog/DialogButton.qml b/src/plugins/studiowelcome/qml/downloaddialog/DialogButton.qml new file mode 100644 index 00000000000..d21acdde359 --- /dev/null +++ b/src/plugins/studiowelcome/qml/downloaddialog/DialogButton.qml @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +import QtQuick 2.10 +import QtQuick.Templates 2.1 as T + +T.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" + + property color defaultColor: "#b9b9ba" + property color checkedColor: "#ffffff" + + background: buttonBackground + Rectangle { + id: buttonBackground + color: control.defaultColor + implicitWidth: 100 + implicitHeight: 40 + opacity: enabled ? 1 : 0.3 + radius: 0 + border.width: 1 + } + + contentItem: textItem + Text { + id: textItem + text: control.text + + opacity: enabled ? 1.0 : 0.3 + color: "#bababa" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + + states: [ + State { + name: "normal" + when: !control.down && !control.checked + PropertyChanges { + target: buttonBackground + color: "#2d2e30" + } + }, + State { + name: "down" + when: control.down || control.checked + PropertyChanges { + target: textItem + color: control.checkedColor + } + + PropertyChanges { + target: buttonBackground + color: "#545456" + border.color: "#70a2f5" + border.width: 2 + } + } + ] +} diff --git a/src/plugins/studiowelcome/qml/downloaddialog/DialogLabel.qml b/src/plugins/studiowelcome/qml/downloaddialog/DialogLabel.qml new file mode 100644 index 00000000000..c5dac79a504 --- /dev/null +++ b/src/plugins/studiowelcome/qml/downloaddialog/DialogLabel.qml @@ -0,0 +1,37 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick.Controls 2.15 + +import ExampleCheckout 1.0 +import QtQuick.Layouts 1.11 + +import StudioFonts 1.0 + +Text { + font.family: StudioFonts.titilliumWeb_light + color: root.textColor +} diff --git a/src/plugins/studiowelcome/qml/downloaddialog/MinMaxMapper.qml b/src/plugins/studiowelcome/qml/downloaddialog/MinMaxMapper.qml new file mode 100644 index 00000000000..451c098f9e3 --- /dev/null +++ b/src/plugins/studiowelcome/qml/downloaddialog/MinMaxMapper.qml @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Quick Designer Components. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.10 + +QtObject { + id: object + + + property real input + + property bool minClipped: object.input < object.min + property bool maxClipped: object.input > object.max + property bool outOfRage: object.maxClipped ||object.minClipped + + property real value: { + if (object.maxClipped) + return object.max + + if (object.minClipped) + return object.min + + return object.input + } + + property real min: 0 + property real max: 100 +} diff --git a/src/plugins/studiowelcome/qml/downloaddialog/RangeMapper.qml b/src/plugins/studiowelcome/qml/downloaddialog/RangeMapper.qml new file mode 100644 index 00000000000..dc75325b084 --- /dev/null +++ b/src/plugins/studiowelcome/qml/downloaddialog/RangeMapper.qml @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Quick Designer Components. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.10 + +QtObject { + id: object + + + property real input + + property real value: { + var slope = (object.outputMax - object.outputMin) / (object.inputMax - object.inputMin) + return object.outputMin + slope * (object.input - object.inputMin) + } + + property real inputMin: 0 + property real inputMax: 100 + property real outputMin: 0 + property real outputMax: 100 + +} diff --git a/src/plugins/studiowelcome/qml/downloaddialog/downloaddialog.qmlproject b/src/plugins/studiowelcome/qml/downloaddialog/downloaddialog.qmlproject new file mode 100644 index 00000000000..880c6022a96 --- /dev/null +++ b/src/plugins/studiowelcome/qml/downloaddialog/downloaddialog.qmlproject @@ -0,0 +1,47 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +import QmlProject 1.1 + +Project { + mainFile: "main.qml" + + /* Include .qml, .js, and image files from current directory and subdirectories */ + QmlFiles { + directory: "." + } + JavaScriptFiles { + directory: "." + } + ImageFiles { + directory: "." + } + /* List of plugin directories passed to QML runtime */ + importPaths: [ "mockData", "../../../../share/3rdparty/studiofonts", "../../../../../share/qtcreator/qmldesigner/propertyEditorQmlSources/imports" ] + + Environment { + QT_AUTO_SCREEN_SCALE_FACTOR: "1" + } +} diff --git a/src/plugins/studiowelcome/qml/downloaddialog/main.qml b/src/plugins/studiowelcome/qml/downloaddialog/main.qml new file mode 100644 index 00000000000..cb7f62a68c4 --- /dev/null +++ b/src/plugins/studiowelcome/qml/downloaddialog/main.qml @@ -0,0 +1,312 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick.Controls 2.15 + +import ExampleCheckout 1.0 +import QtQuick.Layouts 1.11 + +import StudioFonts 1.0 + +Rectangle { + id: root + property alias url: downloader.url + property string path: fileExtractor.targetPath + width: 620 + height: 300 + + color: "#2d2e30" + + property color textColor: "#b9b9ba" + + signal canceled + signal accepted + + StackLayout { + id: stackLayout + anchors.fill: parent + currentIndex: 0 + + FileExtractor { + id: fileExtractor + sourceFile: downloader.tempFile + archiveName: downloader.completeBaseName + } + + FileDownloader { + id: downloader + //onNameChanged: start() + onFinishedChanged: { + button.enabled = downloader.finished + if (!downloader.finished) + stackLayout.currentIndex = 3 + } + + onDownloadFailed: stackLayout.currentIndex = 3 + } + + Item { + id: download + Layout.fillHeight: true + Layout.fillWidth: true + + DialogButton { + id: button + x: 532 + y: 432 + text: qsTr("Continue") + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.bottomMargin: 20 + anchors.rightMargin: 20 + enabled: false + onClicked: stackLayout.currentIndex = 1 + } + + CoolProgressBar { + id: coolProgressBar + width: 605 + anchors.top: parent.top + value: downloader.progress + anchors.horizontalCenter: parent.horizontalCenter + anchors.topMargin: 69 + } + + DialogLabel { + x: 201 + text: "Downloading Example " + downloader.completeBaseName + anchors.top: parent.top + anchors.topMargin: 22 + anchors.horizontalCenter: parent.horizontalCenter + } + + DialogButton { + id: downloadbutton + y: 420 + enabled: !button.enabled + text: qsTr("Start Download") + anchors.left: parent.left + anchors.bottom: parent.bottom + anchors.leftMargin: 20 + anchors.bottomMargin: 20 + onClicked: { + downloadbutton.enabled = false + downloader.start() + } + } + + CircularIndicator { + id: circularIndicator + x: 304 + anchors.top: parent.top + anchors.horizontalCenterOffset: 0 + value: downloader.progress + anchors.topMargin: 120 + anchors.horizontalCenter: parent.horizontalCenter + } + + } + + Item { + id: destiationfolder + Layout.fillHeight: true + Layout.fillWidth: true + + DialogButton { + id: nextPageDestination + x: 532 + y: 432 + text: qsTr("Continue") + anchors.right: parent.right + anchors.bottom: parent.bottom + enabled: !fileExtractor.targetFolderExists + anchors.bottomMargin: 20 + anchors.rightMargin: 20 + onClicked: { + stackLayout.currentIndex = 2 + fileExtractor.extract() + } + } + + RowLayout { + y: 114 + anchors.left: parent.left + anchors.right: parent.right + anchors.rightMargin: 104 + anchors.leftMargin: 67 + + TextField { + id: textField + text: fileExtractor.targetPath + Layout.fillWidth: true + font.family: StudioFonts.titilliumWeb_light + wrapMode: Text.WordWrap + selectByMouse: true + readOnly: true + } + + DialogButton { + id: browse + text: qsTr("Browse") + onClicked: fileExtractor.browse() + } + } + + DialogLabel { + id: label + y: 436 + text: qsTr("Folder ") + downloader.completeBaseName + (" already exists") + anchors.left: parent.left + anchors.bottom: parent.bottom + anchors.leftMargin: 20 + anchors.bottomMargin: 20 + visible: !nextPageDestination.enabled + } + + DialogButton { + id: button5 + x: 400 + y: 420 + text: qsTr("Cancel") + anchors.right: nextPageDestination.left + anchors.bottom: parent.bottom + anchors.bottomMargin: 20 + anchors.rightMargin: 20 + onClicked: root.canceled() + } + + DialogLabel { + text: "Choose installation folder" + anchors.top: parent.top + anchors.topMargin: 22 + anchors.horizontalCenter: parent.horizontalCenter + x: 8 + } + } + + Item { + id: extraction + Layout.fillHeight: true + Layout.fillWidth: true + + + DialogButton { + id: done + x: 532 + y: 432 + text: qsTr("Open") + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.bottomMargin: 20 + anchors.rightMargin: 20 + enabled: fileExtractor.finished + onClicked: root.accepted() + } + + + DialogLabel { + id: text2 + text: fileExtractor.count + " files " + (fileExtractor.size / 1024 / 1024).toFixed(2) + " MB "+ fileExtractor.currentFile + anchors.left: parent.left + anchors.bottom: parent.bottom + font.pixelSize: 12 + wrapMode: Text.WrapAnywhere + anchors.leftMargin: 20 + anchors.bottomMargin: 20 + } + + + DialogButton { + id: details + x: 8 + text: qsTr("Details") + anchors.top: parent.top + anchors.topMargin: 66 + anchors.horizontalCenter: parent.horizontalCenter + checkable: true + } + + + DialogLabel { + x: 8 + text: "Extracting Example " + downloader.completeBaseName + anchors.top: parent.top + anchors.topMargin: 22 + anchors.horizontalCenter: parent.horizontalCenter + } + + Flickable { + visible: details.checked + clip: true + anchors.bottomMargin: 60 + anchors.rightMargin: 20 + anchors.leftMargin: 20 + anchors.topMargin: 120 + anchors.fill: parent + id: flickable + interactive: false + + DialogLabel { + onHeightChanged: flickable.contentY = text1.implicitHeight - flickable.height + id: text1 + + text: fileExtractor.detailedText + + font.pixelSize: 12 + wrapMode: Text.WrapAnywhere + + width: flickable.width + } + } + } + + Item { + id: failed + Layout.fillHeight: true + Layout.fillWidth: true + + DialogButton { + id: finish + x: 532 + y: 432 + text: qsTr("Finish") + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.bottomMargin: 20 + anchors.rightMargin: 20 + onClicked: root.canceled() + } + + DialogLabel { + x: 8 + text: qsTr("Download failed") + anchors.top: parent.top + anchors.topMargin: 22 + anchors.horizontalCenter: parent.horizontalCenter + } + } + } +} diff --git a/src/plugins/studiowelcome/qml/downloaddialog/mockData/ExampleCheckout/FileDownloader.qml b/src/plugins/studiowelcome/qml/downloaddialog/mockData/ExampleCheckout/FileDownloader.qml new file mode 100644 index 00000000000..bf873ec5631 --- /dev/null +++ b/src/plugins/studiowelcome/qml/downloaddialog/mockData/ExampleCheckout/FileDownloader.qml @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +import QtQuick 2.0 + +QtObject { + id: root + + signal downloadFailed + + property bool finished: false + + property bool url + + property int progress: 55 + Behavior on progress { PropertyAnimation { + duration: 2000 + } + } + + function start() { + timer.start() + root.progress = 100 + + } + + property Timer timer: Timer { + interval: 2000 + repeat: false + onTriggered: { + root.finished + root.progress = 1000 + finished = true + } + + } +} diff --git a/src/plugins/studiowelcome/qml/downloaddialog/mockData/ExampleCheckout/FileExtractor.qml b/src/plugins/studiowelcome/qml/downloaddialog/mockData/ExampleCheckout/FileExtractor.qml new file mode 100644 index 00000000000..d3ee8e20f6b --- /dev/null +++ b/src/plugins/studiowelcome/qml/downloaddialog/mockData/ExampleCheckout/FileExtractor.qml @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +import QtQuick 2.0 + +QtObject { + signal finished + + property string sourceFile: "SomeExample.zip" + property string archiveName: "SomeExample" + + property string targetPath: "/extract/here" + + property string detailedText: "Start" + + "\n1 Some detailed info about extraction\nSome detailed info about extraction\nSome detailed info about extractionSome detailed info about extractionSome detailed info about extraction" + + "\n2 Some detailed info about extraction\nSome detailed info about extraction\nSome detailed info about extractionSome detailed info about extractionSome detailed info about extraction" + + "\n3 Some detailed info about extraction\nSome detailed info about extraction\nSome detailed info about extractionSome detailed info about extractionSome detailed info about extraction" + + "\nend" +} diff --git a/src/plugins/studiowelcome/qml/downloaddialog/mockData/ExampleCheckout/qmldir b/src/plugins/studiowelcome/qml/downloaddialog/mockData/ExampleCheckout/qmldir new file mode 100644 index 00000000000..7c2bb0bcd49 --- /dev/null +++ b/src/plugins/studiowelcome/qml/downloaddialog/mockData/ExampleCheckout/qmldir @@ -0,0 +1,2 @@ +FileDownloader 1.0 FileDownloader.qml +FileExtractor 1.0 FileExtractor.qml diff --git a/src/plugins/studiowelcome/qml/welcomepage/ExamplesModel.qml b/src/plugins/studiowelcome/qml/welcomepage/ExamplesModel.qml index 5e9fe07985c..3f33f0205e8 100644 --- a/src/plugins/studiowelcome/qml/welcomepage/ExamplesModel.qml +++ b/src/plugins/studiowelcome/qml/welcomepage/ExamplesModel.qml @@ -74,4 +74,13 @@ ListModel { thumbnail: "images/washingmachinedemo_thumbnail.png" displayName: "Washing Machine" } + + ListElement { + projectName: "highendivisystem" + qmlFileName: "Screen01.ui.qml" + thumbnail: "images/highendivi_thumbnail.png" + displayName: "Highend IVI System" + url: "https://download.qt.io/learning/examples/qtdesignstudio/highendivisystem.zip" + showDownload: true + } } diff --git a/src/plugins/studiowelcome/qml/welcomepage/HoverOverDesaturate.qml b/src/plugins/studiowelcome/qml/welcomepage/HoverOverDesaturate.qml index e160a1f70e3..a7d7501a52c 100644 --- a/src/plugins/studiowelcome/qml/welcomepage/HoverOverDesaturate.qml +++ b/src/plugins/studiowelcome/qml/welcomepage/HoverOverDesaturate.qml @@ -35,6 +35,8 @@ Item { property alias imageSource: image.source property alias labelText: label.text + property alias downloadIcon: downloadCloud.visible + onVisibleChanged: { animateOpacity.start() animateScale.start() @@ -89,6 +91,19 @@ Item { rectangle.color = "#262728" label.color = "#686868" } + + Image { + id: downloadCloud + x: 210 + y: 118 + width: 60 + height: 60 + source: "images/downloadCloud.svg" + sourceSize.height: 60 + sourceSize.width: 60 + fillMode: Image.PreserveAspectFit + visible: false + } } } @@ -187,3 +202,9 @@ Item { font.family: StudioFonts.titilliumWeb_regular } } + +/*##^## +Designer { + D{i:0;formeditorZoom:1.3300000429153442}D{i:8} +} +##^##*/ diff --git a/src/plugins/studiowelcome/qml/welcomepage/ProjectsGrid.qml b/src/plugins/studiowelcome/qml/welcomepage/ProjectsGrid.qml index 6faf3a65547..6a18d10ded3 100644 --- a/src/plugins/studiowelcome/qml/welcomepage/ProjectsGrid.qml +++ b/src/plugins/studiowelcome/qml/welcomepage/ProjectsGrid.qml @@ -39,6 +39,7 @@ GridView { id: hoverOverDesaturate imageSource: typeof(thumbnail) === "undefined" ? "images/thumbnail_test.png" : thumbnail; labelText: displayName + downloadIcon: typeof(showDownload) === "undefined" ? false : showDownload; SequentialAnimation { id: animation diff --git a/src/plugins/studiowelcome/qml/welcomepage/images/downloadCloud.svg b/src/plugins/studiowelcome/qml/welcomepage/images/downloadCloud.svg new file mode 100644 index 00000000000..3a527c3e54f --- /dev/null +++ b/src/plugins/studiowelcome/qml/welcomepage/images/downloadCloud.svg @@ -0,0 +1,29 @@ + + + + + + + diff --git a/src/plugins/studiowelcome/qml/welcomepage/images/highendivi_thumbnail.png b/src/plugins/studiowelcome/qml/welcomepage/images/highendivi_thumbnail.png new file mode 100644 index 00000000000..5428c80776e Binary files /dev/null and b/src/plugins/studiowelcome/qml/welcomepage/images/highendivi_thumbnail.png differ diff --git a/src/plugins/studiowelcome/qml/welcomepage/main.qml b/src/plugins/studiowelcome/qml/welcomepage/main.qml index 759ac459235..771f4845858 100644 --- a/src/plugins/studiowelcome/qml/welcomepage/main.qml +++ b/src/plugins/studiowelcome/qml/welcomepage/main.qml @@ -60,7 +60,7 @@ Item { ScrollView { ProjectsGrid { model: ExamplesModel {} - onItemSelected: projectModel.openExample(item.projectName, item.qmlFileName) + onItemSelected: projectModel.openExample(item.projectName, item.qmlFileName, item.url) } } diff --git a/src/plugins/studiowelcome/studiowelcome.pro b/src/plugins/studiowelcome/studiowelcome.pro index 183f955a490..e2ccee8576f 100644 --- a/src/plugins/studiowelcome/studiowelcome.pro +++ b/src/plugins/studiowelcome/studiowelcome.pro @@ -12,9 +12,11 @@ DEFINES += STUDIO_QML_PATH=\\\"$$PWD/qml/\\\" HEADERS += \ studiowelcome_global.h \ studiowelcomeplugin.h \ + examplecheckout.h SOURCES += \ - studiowelcomeplugin.cpp + studiowelcomeplugin.cpp \ + examplecheckout.cpp OTHER_FILES += \ StudioWelcome.json.in diff --git a/src/plugins/studiowelcome/studiowelcome.qbs b/src/plugins/studiowelcome/studiowelcome.qbs index b875a35c777..f2bec88af22 100644 --- a/src/plugins/studiowelcome/studiowelcome.qbs +++ b/src/plugins/studiowelcome/studiowelcome.qbs @@ -17,6 +17,8 @@ QtcPlugin { "studiowelcome_global.h", "studiowelcomeplugin.h", "studiowelcomeplugin.cpp", + "examplecheckout.h", + "examplecheckout.cpp", "studiowelcome.qrc", ] diff --git a/src/plugins/studiowelcome/studiowelcomeplugin.cpp b/src/plugins/studiowelcome/studiowelcomeplugin.cpp index 5cb362b0998..a2ac354fa01 100644 --- a/src/plugins/studiowelcome/studiowelcomeplugin.cpp +++ b/src/plugins/studiowelcome/studiowelcomeplugin.cpp @@ -24,6 +24,7 @@ ****************************************************************************/ #include "studiowelcomeplugin.h" +#include "examplecheckout.h" #include #include @@ -175,9 +176,29 @@ public: QDesktopServices::openUrl(QUrl("qthelp://org.qt-project.qtcreator/doc/index.html")); } - Q_INVOKABLE void openExample(const QString &example, const QString &formFile) + Q_INVOKABLE void openExample(const QString &example, const QString &formFile, const QString &url) { - const QString projectFile = Core::ICore::resourcePath() + "/examples/" + example + "/" + example + ".qmlproject"; + if (!url.isEmpty()) { + ExampleCheckout *checkout = new ExampleCheckout; + checkout->checkoutExample(QUrl::fromUserInput(url)); + connect(checkout, + &ExampleCheckout::finishedSucessfully, + this, + [checkout, this, formFile, example]() { + const QString projectFile = checkout->extractionFolder() + "/" + example + + "/" + example + ".qmlproject"; + + ProjectExplorer::ProjectExplorerPlugin::openProjectWelcomePage(projectFile); + const QString qmlFile = checkout->extractionFolder() + "/" + example + "/" + + formFile; + + Core::EditorManager::openEditor(qmlFile); + }); + return; + } + + const QString projectFile = Core::ICore::resourcePath() + "/examples/" + example + "/" + + example + ".qmlproject"; ProjectExplorer::ProjectExplorerPlugin::openProjectWelcomePage(projectFile); const QString qmlFile = Core::ICore::resourcePath() + "/examples/" + example + "/" + formFile; Core::EditorManager::openEditor(qmlFile); diff --git a/src/plugins/texteditor/textdocumentlayout.h b/src/plugins/texteditor/textdocumentlayout.h index 7097d684c3b..776552a7efd 100644 --- a/src/plugins/texteditor/textdocumentlayout.h +++ b/src/plugins/texteditor/textdocumentlayout.h @@ -30,6 +30,8 @@ #include "textmark.h" #include "textdocument.h" +#include + #include #include @@ -48,6 +50,7 @@ struct TEXTEDITOR_EXPORT Parenthesis : pos(position), chr(c), type(t) {} int pos = -1; QChar chr; + Utils::Id source; Type type = Opened; }; diff --git a/src/shared/CMakeLists.txt b/src/shared/CMakeLists.txt index 6101e2a46c0..ec0069078d8 100644 --- a/src/shared/CMakeLists.txt +++ b/src/shared/CMakeLists.txt @@ -37,7 +37,7 @@ if (ENABLE_BUILD_QBS) set(INSTALL_PUBLIC_HEADERS OFF CACHE BOOL "") set(WITH_TESTS OFF) - set(WITH_PROJECT_FILE_UPDATES ON) + set(WITH_PROJECT_FILE_UPDATES ON CACHE BOOL "") set(QBS_INSTALL_QCH_DOCS ${WITH_DOCS} CACHE BOOL "") add_subdirectory(qbs) endif() diff --git a/src/shared/qbs b/src/shared/qbs index 7b50dca83a5..b9907900069 160000 --- a/src/shared/qbs +++ b/src/shared/qbs @@ -1 +1 @@ -Subproject commit 7b50dca83a5a75a5c24b5ef329f25990daf2ff50 +Subproject commit b99079000697268bdf29c8ae09aa9fc02235edfc diff --git a/src/tools/3rdparty/cplusplus-keywordgen/CMakeLists.txt b/src/tools/3rdparty/cplusplus-keywordgen/CMakeLists.txt index d1e10e73448..ec08ef50ec0 100644 --- a/src/tools/3rdparty/cplusplus-keywordgen/CMakeLists.txt +++ b/src/tools/3rdparty/cplusplus-keywordgen/CMakeLists.txt @@ -1,4 +1,5 @@ add_qtc_executable(cplusplus-keywordgen + SKIP_INSTALL DEPENDS CPlusPlus Utils SOURCES cplusplus-keywordgen.cpp PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} diff --git a/src/tools/iconlister/iconlister.cpp b/src/tools/iconlister/iconlister.cpp index e8b9d3eb18d..d3d084e8ca5 100644 --- a/src/tools/iconlister/iconlister.cpp +++ b/src/tools/iconlister/iconlister.cpp @@ -334,8 +334,6 @@ void IconLister::addProjectExplorerIcons() {QIcon(":/projectexplorer/images/category_buildrun.png"), "category_buildrun.png", prefix, ""}, - {QIcon(":/projectexplorer/images/session.png"), "session.png", prefix, - ""}, {QIcon(":/projectexplorer/images/BuildSettings.png"), "BuildSettings.png", prefix, ""}, {QIcon(":/projectexplorer/images/CodeStyleSettings.png"), "CodeStyleSettings.png", prefix, diff --git a/src/tools/icons/qtcreatoricons.svg b/src/tools/icons/qtcreatoricons.svg index e0bec68332c..bc5658d99cd 100644 --- a/src/tools/icons/qtcreatoricons.svg +++ b/src/tools/icons/qtcreatoricons.svg @@ -18,6 +18,18 @@ sodipodi:docname="qtcreatoricons.svg"> + + + + @@ -587,6 +599,15 @@ values="0.66 0 0 0.35 0.0182292 0.02 0.66 0.02 0.35 0.0182292 0.08 0.08 0.66 0.35 0.02 0 0 0 1 0 " id="feColorMatrix2747" /> + + + + + + + + + + +