forked from qt-creator/qt-creator
Merge "Merge remote-tracking branch 'origin/qds/dev'"
This commit is contained in:
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
The editor shows found issues as inline annotations if the project matches
|
The editor shows found issues as inline annotations if the project matches
|
||||||
the currently open one and the respective file is part of the project.
|
the currently open one and the respective file is part of the project.
|
||||||
Hover the mouse over an annotation to bring up a tooltip with a short
|
hover over an annotation to bring up a tooltip with a short
|
||||||
description of the issue.
|
description of the issue.
|
||||||
|
|
||||||
\image qtcreator-axivion-annotation.webp {Annotation popup}
|
\image qtcreator-axivion-annotation.webp {Annotation popup}
|
||||||
|
@@ -140,7 +140,7 @@
|
|||||||
\li Select \uicontrol Projects > \uicontrol {Project Settings} >
|
\li Select \uicontrol Projects > \uicontrol {Project Settings} >
|
||||||
\uicontrol {Clang Tools}.
|
\uicontrol {Clang Tools}.
|
||||||
\image qtcreator-clang-tools-settings.webp {Clang Tools customized settings}
|
\image qtcreator-clang-tools-settings.webp {Clang Tools customized settings}
|
||||||
\li Deselect \uicontrol {Use global settings}.
|
\li Clear \uicontrol {Use global settings}.
|
||||||
\li Specify \uicontrol preferences for the project.
|
\li Specify \uicontrol preferences for the project.
|
||||||
\li In \uicontrol {Suppressed diagnostics}, you can view the suppression
|
\li In \uicontrol {Suppressed diagnostics}, you can view the suppression
|
||||||
list for a project and to remove diagnostics from it.
|
list for a project and to remove diagnostics from it.
|
||||||
@@ -196,7 +196,7 @@
|
|||||||
generated during the build. For big projects, not building the
|
generated during the build. For big projects, not building the
|
||||||
project might save some time.
|
project might save some time.
|
||||||
|
|
||||||
\li To disable automatic analysis of open documents, deselect the
|
\li To disable automatic analysis of open documents, clear the
|
||||||
\uicontrol {Analyze open files} check box.
|
\uicontrol {Analyze open files} check box.
|
||||||
|
|
||||||
\li In the \uicontrol {Parallel jobs} field, select the number of jobs
|
\li In the \uicontrol {Parallel jobs} field, select the number of jobs
|
||||||
|
@@ -122,7 +122,7 @@
|
|||||||
Memcheck also reports uses of uninitialised values, most commonly with the
|
Memcheck also reports uses of uninitialised values, most commonly with the
|
||||||
message \uicontrol {Conditional jump or move depends on uninitialised value(s).}
|
message \uicontrol {Conditional jump or move depends on uninitialised value(s).}
|
||||||
To determine the root cause of these errors, the \uicontrol {Track origins of
|
To determine the root cause of these errors, the \uicontrol {Track origins of
|
||||||
uninitialized memory} check box is selected by default. You can deselect it
|
uninitialized memory} check box is selected by default. You can clear it
|
||||||
to make Memcheck run faster.
|
to make Memcheck run faster.
|
||||||
|
|
||||||
\section1 Viewing a Summary
|
\section1 Viewing a Summary
|
||||||
|
@@ -94,7 +94,7 @@
|
|||||||
source files are located. To hide the subfolder names and arrange the files
|
source files are located. To hide the subfolder names and arrange the files
|
||||||
only according to their source group, select \preferences >
|
only according to their source group, select \preferences >
|
||||||
\uicontrol CMake > \uicontrol General, and then
|
\uicontrol CMake > \uicontrol General, and then
|
||||||
deselect the \uicontrol {Show subfolders inside source group folders} check
|
clear the \uicontrol {Show subfolders inside source group folders} check
|
||||||
box. The change takes effect after you select \uicontrol Build >
|
box. The change takes effect after you select \uicontrol Build >
|
||||||
\uicontrol {Run CMake}.
|
\uicontrol {Run CMake}.
|
||||||
|
|
||||||
|
@@ -1109,7 +1109,7 @@
|
|||||||
If you cannot debug Qt objects because their data is corrupted, you can
|
If you cannot debug Qt objects because their data is corrupted, you can
|
||||||
switch off the debugging helpers to make low-level structures visible.
|
switch off the debugging helpers to make low-level structures visible.
|
||||||
|
|
||||||
To switch off the debugging helpers, deselect
|
To switch off the debugging helpers, clear
|
||||||
\uicontrol {Use Debugging Helpers} in \preferences >
|
\uicontrol {Use Debugging Helpers} in \preferences >
|
||||||
\uicontrol Debugger > \uicontrol {Locals & Expressions}.
|
\uicontrol Debugger > \uicontrol {Locals & Expressions}.
|
||||||
|
|
||||||
@@ -2166,7 +2166,7 @@
|
|||||||
\section1 Structure Members Are Not Sorted According to Structure Layout
|
\section1 Structure Members Are Not Sorted According to Structure Layout
|
||||||
|
|
||||||
By default, structure members are displayed in alphabetic order. To inspect
|
By default, structure members are displayed in alphabetic order. To inspect
|
||||||
the real layout in memory, deselect
|
the real layout in memory, clear
|
||||||
\uicontrol {Sort Members of Classes and Structs Alphabetically} in the
|
\uicontrol {Sort Members of Classes and Structs Alphabetically} in the
|
||||||
context menu in the \uicontrol Locals and \uicontrol Expressions views.
|
context menu in the \uicontrol Locals and \uicontrol Expressions views.
|
||||||
|
|
||||||
|
@@ -166,7 +166,7 @@
|
|||||||
|
|
||||||
When completion is invoked manually, \QC completes the common prefix of the
|
When completion is invoked manually, \QC completes the common prefix of the
|
||||||
list of suggestions. This is especially useful for classes with several
|
list of suggestions. This is especially useful for classes with several
|
||||||
similarly named members. To disable this functionality, deselect the
|
similarly named members. To disable this functionality, clear the
|
||||||
\uicontrol {Autocomplete common prefix} check box.
|
\uicontrol {Autocomplete common prefix} check box.
|
||||||
|
|
||||||
Select the \uicontrol {Automatically split strings} check box to split
|
Select the \uicontrol {Automatically split strings} check box to split
|
||||||
|
@@ -68,7 +68,7 @@
|
|||||||
To help you keep line length at a particular number of characters, set the
|
To help you keep line length at a particular number of characters, set the
|
||||||
number of characters in the \uicontrol {Display right margin at column}
|
number of characters in the \uicontrol {Display right margin at column}
|
||||||
field. To use a different color for the margin area, select the
|
field. To use a different color for the margin area, select the
|
||||||
\uicontrol {Tint whole margin area} check box. Deselect the check box to show
|
\uicontrol {Tint whole margin area} check box. Clear the check box to show
|
||||||
the margin as a vertical line.
|
the margin as a vertical line.
|
||||||
|
|
||||||
To use a context-specific margin when available, select the
|
To use a context-specific margin when available, select the
|
||||||
|
@@ -34,14 +34,14 @@
|
|||||||
percentage for viewing the text. You can also zoom in or out by pressing
|
percentage for viewing the text. You can also zoom in or out by pressing
|
||||||
\key {Ctrl++} or \key {Ctrl+-}, or by pressing \key Ctrl and rolling
|
\key {Ctrl++} or \key {Ctrl+-}, or by pressing \key Ctrl and rolling
|
||||||
the mouse button up or down. To disable the mouse wheel function, select
|
the mouse button up or down. To disable the mouse wheel function, select
|
||||||
\preferences > \uicontrol {Text Editor} > \uicontrol Behavior and deselect
|
\preferences > \uicontrol {Text Editor} > \uicontrol Behavior and clear
|
||||||
the \uicontrol {Enable scroll wheel zooming} check box.
|
the \uicontrol {Enable scroll wheel zooming} check box.
|
||||||
|
|
||||||
To improve the readability of text in the editor, adjust the line spacing in
|
To improve the readability of text in the editor, adjust the line spacing in
|
||||||
the \uicontrol {Line spacing} field.
|
the \uicontrol {Line spacing} field.
|
||||||
|
|
||||||
Antialiasing is used by default to make text look smoother and more readable
|
Antialiasing is used by default to make text look smoother and more readable
|
||||||
on the screen. Deselect the \uicontrol Antialias check box to turn off
|
on the screen. Clear the \uicontrol Antialias check box to turn off
|
||||||
antialiasing.
|
antialiasing.
|
||||||
|
|
||||||
\sa {Behavior}, {Change editor colors}
|
\sa {Behavior}, {Change editor colors}
|
||||||
|
@@ -88,7 +88,7 @@
|
|||||||
\endlist
|
\endlist
|
||||||
|
|
||||||
To use the built-in code model instead, select \preferences >
|
To use the built-in code model instead, select \preferences >
|
||||||
\uicontrol C++ > \uicontrol clangd, and deselect the \uicontrol {Use clangd} check box.
|
\uicontrol C++ > \uicontrol clangd, and clear the \uicontrol {Use clangd} check box.
|
||||||
This setting also exists on the project level, so that you can have the Clang-based
|
This setting also exists on the project level, so that you can have the Clang-based
|
||||||
services generally enabled, but switch them off for certain projects, or vice versa.
|
services generally enabled, but switch them off for certain projects, or vice versa.
|
||||||
|
|
||||||
@@ -337,7 +337,7 @@
|
|||||||
\li Select \uicontrol Projects > \uicontrol {Project Settings} >
|
\li Select \uicontrol Projects > \uicontrol {Project Settings} >
|
||||||
\uicontrol {Clangd}.
|
\uicontrol {Clangd}.
|
||||||
\image qtcreator-projects-settings-clangd.webp {Clangd preferences for a project}
|
\image qtcreator-projects-settings-clangd.webp {Clangd preferences for a project}
|
||||||
\li Deselect \uicontrol {Use global settings}.
|
\li Clear \uicontrol {Use global settings}.
|
||||||
\li Select \uicontrol {Use clangd}.
|
\li Select \uicontrol {Use clangd}.
|
||||||
\li Specify \uicontrol Clangd preferences for the project.
|
\li Specify \uicontrol Clangd preferences for the project.
|
||||||
\endlist
|
\endlist
|
||||||
|
@@ -230,7 +230,7 @@
|
|||||||
filter to locate the files.
|
filter to locate the files.
|
||||||
|
|
||||||
To use the sorting from the selected tool instead of from \QC,
|
To use the sorting from the selected tool instead of from \QC,
|
||||||
deselect the \uicontrol {Sort results} check box in the \c md
|
clear the \uicontrol {Sort results} check box in the \c md
|
||||||
locator filter configuration.
|
locator filter configuration.
|
||||||
|
|
||||||
\image qtcreator-locator-filter-edit-md.webp {Filter Configuration dialog}
|
\image qtcreator-locator-filter-edit-md.webp {Filter Configuration dialog}
|
||||||
|
@@ -81,8 +81,7 @@
|
|||||||
\uicontrol {Request Copilot Suggestion} in the \l{Navigate with locator}
|
\uicontrol {Request Copilot Suggestion} in the \l{Navigate with locator}
|
||||||
{locator}.
|
{locator}.
|
||||||
|
|
||||||
Hover the mouse over a suggestion to show a toolbar with
|
Hover over a suggestion to show a toolbar with \inlineimage icons/prev.png
|
||||||
\inlineimage icons/prev.png
|
|
||||||
and \inlineimage icons/next.png
|
and \inlineimage icons/next.png
|
||||||
buttons for cycling between Copilot suggestions.
|
buttons for cycling between Copilot suggestions.
|
||||||
|
|
||||||
|
@@ -47,8 +47,8 @@
|
|||||||
To use a locator filter:
|
To use a locator filter:
|
||||||
|
|
||||||
\list
|
\list
|
||||||
\li Type the locator filter prefix followed by \key Space. The prefix
|
\li Enter the locator filter prefix followed by \key Space. The prefix
|
||||||
is usually short, from one to three characters. Then type the search
|
is usually short, from one to three characters. Then enter the search
|
||||||
string (for example, a filename or class name) or the command to
|
string (for example, a filename or class name) or the command to
|
||||||
execute.
|
execute.
|
||||||
|
|
||||||
@@ -58,7 +58,7 @@
|
|||||||
selected filter.
|
selected filter.
|
||||||
\endlist
|
\endlist
|
||||||
|
|
||||||
As you type a search string,
|
As you enter a search string,
|
||||||
the locator shows the occurrences of that string regardless of where in the
|
the locator shows the occurrences of that string regardless of where in the
|
||||||
name of an object it appears. Some locator filters, such as colon, \c m,
|
name of an object it appears. Some locator filters, such as colon, \c m,
|
||||||
and \c t, support \e fuzzy matching, which means that you can enter the
|
and \c t, support \e fuzzy matching, which means that you can enter the
|
||||||
|
@@ -68,7 +68,7 @@
|
|||||||
select \preferences > \uicontrol {Text Editor} >
|
select \preferences > \uicontrol {Text Editor} >
|
||||||
\uicontrol Behavior > \uicontrol Typing.
|
\uicontrol Behavior > \uicontrol Typing.
|
||||||
|
|
||||||
To disable automatic indentation, deselect the
|
To disable automatic indentation, clear the
|
||||||
\uicontrol {Enable automatic indentation} check box.
|
\uicontrol {Enable automatic indentation} check box.
|
||||||
|
|
||||||
You can specify how the indentation is decreased when you press
|
You can specify how the indentation is decreased when you press
|
||||||
|
@@ -368,7 +368,7 @@
|
|||||||
|
|
||||||
If a Qt Quick test case does not have a name, it is marked
|
If a Qt Quick test case does not have a name, it is marked
|
||||||
\uicontrol Unnamed in the list. \uicontrol {Run All Tests} executes
|
\uicontrol Unnamed in the list. \uicontrol {Run All Tests} executes
|
||||||
unnamed test cases. You cannot select or deselect them.
|
unnamed test cases. You cannot select or clear them.
|
||||||
|
|
||||||
\QC scans the project for tests when you open the project and updates the
|
\QC scans the project for tests when you open the project and updates the
|
||||||
test list for the currently active test frameworks when you edit tests.
|
test list for the currently active test frameworks when you edit tests.
|
||||||
@@ -848,7 +848,7 @@
|
|||||||
|
|
||||||
To show all messages, select \uicontrol {Check All Filters}.
|
To show all messages, select \uicontrol {Check All Filters}.
|
||||||
|
|
||||||
To deselect all message types, select \uicontrol {Uncheck All Filters}.
|
To clear all message types, select \uicontrol {Uncheck All Filters}.
|
||||||
|
|
||||||
\section1 Blacklisting Tests
|
\section1 Blacklisting Tests
|
||||||
|
|
||||||
|
@@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
To set preferences for documentation comments for a particular project,
|
To set preferences for documentation comments for a particular project,
|
||||||
select \uicontrol Projects > \uicontrol {Project Settings} >
|
select \uicontrol Projects > \uicontrol {Project Settings} >
|
||||||
\uicontrol {Documentation Comments}, and deselect the
|
\uicontrol {Documentation Comments}, and clear the
|
||||||
\uicontrol {Use global settings} check box.
|
\uicontrol {Use global settings} check box.
|
||||||
|
|
||||||
\image qtcreator-preferences-documentation-comments.webp {Documentation Comments settings}
|
\image qtcreator-preferences-documentation-comments.webp {Documentation Comments settings}
|
||||||
|
@@ -137,7 +137,7 @@
|
|||||||
Increase the limit if frames are dropped during the recording.
|
Increase the limit if frames are dropped during the recording.
|
||||||
\row
|
\row
|
||||||
\li \uicontrol {Export animated images as infinite loop}
|
\li \uicontrol {Export animated images as infinite loop}
|
||||||
\li Whether to export animated images as inifite loops. Deselect
|
\li Whether to export animated images as inifite loops. Clear
|
||||||
this check box to only play the animation once.
|
this check box to only play the animation once.
|
||||||
\row
|
\row
|
||||||
\li \uicontrol {Write command line of FFmpeg calls to General Messages}
|
\li \uicontrol {Write command line of FFmpeg calls to General Messages}
|
||||||
|
@@ -149,7 +149,7 @@
|
|||||||
|
|
||||||
To trigger the GDB command that generates a core file while debugging,
|
To trigger the GDB command that generates a core file while debugging,
|
||||||
go to \uicontrol View > \uicontrol Views > \l {Debugger Log}.
|
go to \uicontrol View > \uicontrol Views > \l {Debugger Log}.
|
||||||
In the \uicontrol Command field, type \c gcore and select \key Enter. The
|
In the \uicontrol Command field, enter \c gcore and select \key Enter. The
|
||||||
core file is created in the current working directory. You can specify
|
core file is created in the current working directory. You can specify
|
||||||
another location for the file, including a relative or absolute path, as an
|
another location for the file, including a relative or absolute path, as an
|
||||||
argument of the command.
|
argument of the command.
|
||||||
@@ -232,7 +232,7 @@
|
|||||||
When you run a console application, you can view the output in the console
|
When you run a console application, you can view the output in the console
|
||||||
window of the calling application. If the
|
window of the calling application. If the
|
||||||
calling application is a GUI application (for example, a release-built
|
calling application is a GUI application (for example, a release-built
|
||||||
version of \QC), a new console window is opened. For this
|
version of \QC), a new console window is opened. For this
|
||||||
type of application, \c qDebug() and related functions use standard output
|
type of application, \c qDebug() and related functions use standard output
|
||||||
and error output.
|
and error output.
|
||||||
|
|
||||||
@@ -317,8 +317,8 @@
|
|||||||
in the tab bar, find our that the function is inline, fix the problem, and
|
in the tab bar, find our that the function is inline, fix the problem, and
|
||||||
forget where they came from.
|
forget where they came from.
|
||||||
|
|
||||||
With \QC, developers can type \c {Ctrl+K m AFun} to find the function.
|
With \QC, developers can enter \c {Ctrl+K m AFun} to find the function.
|
||||||
Typically, they only need to type 3 to 4 characters of the function name.
|
Typically, they only need to enter 3 to 4 characters of the function name.
|
||||||
They can then fix the problem and select \key Alt+Back to go back to where
|
They can then fix the problem and select \key Alt+Back to go back to where
|
||||||
they were.
|
they were.
|
||||||
|
|
||||||
|
@@ -100,7 +100,7 @@
|
|||||||
deployment time and only copies files that have changed since the last
|
deployment time and only copies files that have changed since the last
|
||||||
deployment. However, when you make major changes on the device, such as
|
deployment. However, when you make major changes on the device, such as
|
||||||
removing files from the device manually or flashing a new disk image, or
|
removing files from the device manually or flashing a new disk image, or
|
||||||
when you use another device with the same IP address, deselect the check box
|
when you use another device with the same IP address, clear the check box
|
||||||
once, to have \QC deploy all files again.
|
once, to have \QC deploy all files again.
|
||||||
|
|
||||||
\section2 Creating a Tarball
|
\section2 Creating a Tarball
|
||||||
|
@@ -22,7 +22,7 @@
|
|||||||
By default, \QC builds qmake projects (that have .pro files) in a separate
|
By default, \QC builds qmake projects (that have .pro files) in a separate
|
||||||
directory from the source directory, as \l{glossary-shadow-build}
|
directory from the source directory, as \l{glossary-shadow-build}
|
||||||
{shadow builds}. This keeps the files generated for each kit separate. If
|
{shadow builds}. This keeps the files generated for each kit separate. If
|
||||||
you only build and run with a single kit, you can deselect the
|
you only build and run with a single kit, you can clear the
|
||||||
\uicontrol {Shadow build} checkbox.
|
\uicontrol {Shadow build} checkbox.
|
||||||
|
|
||||||
Select the build directory in the \uicontrol {Build Directory} field. You
|
Select the build directory in the \uicontrol {Build Directory} field. You
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
\section1 Tooltips in Kit Selector
|
\section1 Tooltips in Kit Selector
|
||||||
|
|
||||||
In the \uicontrol {Tooltip in target selector} field, you can enter text
|
In the \uicontrol {Tooltip in target selector} field, you can enter text
|
||||||
that is displayed as a tooltip when you hover the mouse over the build
|
that is displayed as a tooltip when you hover over the build
|
||||||
configuration in the \l{Build for many platforms}{kit selector}.
|
configuration in the \l{Build for many platforms}{kit selector}.
|
||||||
|
|
||||||
You can create separate versions of project files to keep platform-dependent
|
You can create separate versions of project files to keep platform-dependent
|
||||||
|
@@ -60,7 +60,7 @@
|
|||||||
\li Enter code to see the resulting assembly code.
|
\li Enter code to see the resulting assembly code.
|
||||||
\endlist
|
\endlist
|
||||||
|
|
||||||
Hover the mouse over the assembly code, to have the matching source lines
|
hover over the assembly code, to have the matching source lines
|
||||||
highlighted.
|
highlighted.
|
||||||
|
|
||||||
You can also see the application status and output.
|
You can also see the application status and output.
|
||||||
|
@@ -85,7 +85,7 @@
|
|||||||
debug version. For example, if the release version is called example.lib,
|
debug version. For example, if the release version is called example.lib,
|
||||||
the debug version is called exampled.lib. You can specify that the letter
|
the debug version is called exampled.lib. You can specify that the letter
|
||||||
is added for the debug version and removed for the release version.
|
is added for the debug version and removed for the release version.
|
||||||
If the library name ends in \e d, deselect the \uicontrol {Remove "d" suffix
|
If the library name ends in \e d, clear the \uicontrol {Remove "d" suffix
|
||||||
for release version} option.
|
for release version} option.
|
||||||
|
|
||||||
For more information about the project file settings, see
|
For more information about the project file settings, see
|
||||||
|
@@ -66,7 +66,7 @@
|
|||||||
\list 1
|
\list 1
|
||||||
\li Select \preferences > \uicontrol Qbs.
|
\li Select \preferences > \uicontrol Qbs.
|
||||||
\image qtcreator-options-qbs.png "Qbs preferences"
|
\image qtcreator-options-qbs.png "Qbs preferences"
|
||||||
\li Deselect the \uicontrol {Use \QC settings directory for Qbs} check
|
\li Clear the \uicontrol {Use \QC settings directory for Qbs} check
|
||||||
box to store Qbs profiles in the Qbs settings directory.
|
box to store Qbs profiles in the Qbs settings directory.
|
||||||
\li In the \uicontrol {Path to qbs executable} field, you can view
|
\li In the \uicontrol {Path to qbs executable} field, you can view
|
||||||
and change the path to the Qbs executable.
|
and change the path to the Qbs executable.
|
||||||
|
@@ -21,7 +21,7 @@
|
|||||||
\uicontrol {Build Directory} field.
|
\uicontrol {Build Directory} field.
|
||||||
|
|
||||||
In the \uicontrol {Tooltip in target selector} field, you can enter text
|
In the \uicontrol {Tooltip in target selector} field, you can enter text
|
||||||
that is displayed as a tooltip when you hover the mouse over the build
|
that is displayed as a tooltip when you hover over the build
|
||||||
configuration in the \l{Build for many platforms}{kit selector}.
|
configuration in the \l{Build for many platforms}{kit selector}.
|
||||||
|
|
||||||
You can enter a name for the build configuration in the
|
You can enter a name for the build configuration in the
|
||||||
@@ -98,7 +98,7 @@
|
|||||||
|
|
||||||
\note On Windows, the build will fail if the application
|
\note On Windows, the build will fail if the application
|
||||||
is running because the executable file cannot be
|
is running because the executable file cannot be
|
||||||
overwritten. To avoid this issue, you can deselect this
|
overwritten. To avoid this issue, you can clear this
|
||||||
check box and add a \uicontrol {Qbs Install} deployment step
|
check box and add a \uicontrol {Qbs Install} deployment step
|
||||||
in the run settings that will be performed just before
|
in the run settings that will be performed just before
|
||||||
running the application.
|
running the application.
|
||||||
@@ -108,7 +108,7 @@
|
|||||||
starts.
|
starts.
|
||||||
|
|
||||||
\li Select \uicontrol {Use default location} to install the
|
\li Select \uicontrol {Use default location} to install the
|
||||||
artifacts to the default location. Deselect the check box to
|
artifacts to the default location. Clear the check box to
|
||||||
specify another location in the
|
specify another location in the
|
||||||
\uicontrol {Installation directory} field.
|
\uicontrol {Installation directory} field.
|
||||||
|
|
||||||
|
@@ -26,7 +26,7 @@
|
|||||||
\li Select \uicontrol Projects > \uicontrol {Project Settings} >
|
\li Select \uicontrol Projects > \uicontrol {Project Settings} >
|
||||||
\uicontrol Editor.
|
\uicontrol Editor.
|
||||||
|
|
||||||
\li Deselect \uicontrol {Use global settings}.
|
\li Clear \uicontrol {Use global settings}.
|
||||||
|
|
||||||
\li Specify text editor settings for the project.
|
\li Specify text editor settings for the project.
|
||||||
|
|
||||||
|
@@ -72,7 +72,7 @@
|
|||||||
\image qtcreator-settings-run-desktop.webp {Run Settings}
|
\image qtcreator-settings-run-desktop.webp {Run Settings}
|
||||||
|
|
||||||
To prevent \QC from automatically creating run configurations, select
|
To prevent \QC from automatically creating run configurations, select
|
||||||
\preferences > \uicontrol {Build & Run}, and then deselect the
|
\preferences > \uicontrol {Build & Run}, and then clear the
|
||||||
\uicontrol {Create suitable run configurations automatically} check box.
|
\uicontrol {Create suitable run configurations automatically} check box.
|
||||||
|
|
||||||
\section1 Overriding Global Preferences
|
\section1 Overriding Global Preferences
|
||||||
|
@@ -41,7 +41,7 @@
|
|||||||
\li Select \uicontrol{Next} (on Windows and Linux) or \uicontrol Continue
|
\li Select \uicontrol{Next} (on Windows and Linux) or \uicontrol Continue
|
||||||
(on \macos) to open the \uicontrol {Define Class} dialog.
|
(on \macos) to open the \uicontrol {Define Class} dialog.
|
||||||
\image qtcreator-new-qt-for-python-app-widgets-define-class.webp {Define Class dialog}
|
\image qtcreator-new-qt-for-python-app-widgets-define-class.webp {Define Class dialog}
|
||||||
\li In \uicontrol {Class name}, type \b {MyWidget} as the class
|
\li In \uicontrol {Class name}, enter \b {MyWidget} as the class
|
||||||
name.
|
name.
|
||||||
\li In \uicontrol {Base class}, select \b {QWidget} as the base class.
|
\li In \uicontrol {Base class}, select \b {QWidget} as the base class.
|
||||||
\note The \uicontrol {Source file} field is automatically updated to
|
\note The \uicontrol {Source file} field is automatically updated to
|
||||||
|
@@ -24,7 +24,7 @@
|
|||||||
\endlist
|
\endlist
|
||||||
|
|
||||||
To show the title bars of views, select \uicontrol View > \uicontrol Views,
|
To show the title bars of views, select \uicontrol View > \uicontrol Views,
|
||||||
and deselect the \uicontrol {Automatically Hide Title Bars} check box.
|
and clear the \uicontrol {Automatically Hide Title Bars} check box.
|
||||||
|
|
||||||
\section1 Attach views
|
\section1 Attach views
|
||||||
|
|
||||||
|
@@ -10,7 +10,7 @@
|
|||||||
\title Show and hide the main menu
|
\title Show and hide the main menu
|
||||||
|
|
||||||
On Linux and Windows, you can hide the main menu bar to save space on the
|
On Linux and Windows, you can hide the main menu bar to save space on the
|
||||||
screen. Select \uicontrol View, and deselect the \uicontrol {Show Menu Bar}
|
screen. Select \uicontrol View, and clear the \uicontrol {Show Menu Bar}
|
||||||
check box.
|
check box.
|
||||||
|
|
||||||
\image qtcreator-without-menubar.webp {Qt Creator without the main menu}
|
\image qtcreator-without-menubar.webp {Qt Creator without the main menu}
|
||||||
|
@@ -24,7 +24,7 @@
|
|||||||
\inlineimage icons/sort_alphabetically.png
|
\inlineimage icons/sort_alphabetically.png
|
||||||
(\uicontrol {Sort Alphabetically}).
|
(\uicontrol {Sort Alphabetically}).
|
||||||
\li To stop the synchronization with the type or symbol selected in the
|
\li To stop the synchronization with the type or symbol selected in the
|
||||||
editor, deselect \inlineimage icons/linkicon.png
|
editor, clear \inlineimage icons/linkicon.png
|
||||||
(\uicontrol {Synchronize with Editor}).
|
(\uicontrol {Synchronize with Editor}).
|
||||||
\endlist
|
\endlist
|
||||||
*/
|
*/
|
||||||
|
@@ -42,7 +42,7 @@
|
|||||||
in the context menu or select \key {Ctrl+A}.
|
in the context menu or select \key {Ctrl+A}.
|
||||||
|
|
||||||
\li To open links in a browser, files in the editor, or folders in the
|
\li To open links in a browser, files in the editor, or folders in the
|
||||||
\l Projects view, hover the mouse over them, and select \key Ctrl.
|
\l Projects view, hover over them, and select \key Ctrl.
|
||||||
|
|
||||||
\li To \l{Search in current file}{search} through the output, press
|
\li To \l{Search in current file}{search} through the output, press
|
||||||
\key {Ctrl+F}.
|
\key {Ctrl+F}.
|
||||||
|
@@ -108,7 +108,7 @@
|
|||||||
\li Close all files in a project.
|
\li Close all files in a project.
|
||||||
\li Close the selected project or all projects except the selected
|
\li Close the selected project or all projects except the selected
|
||||||
one. By default, this closes all files in the projects. To keep
|
one. By default, this closes all files in the projects. To keep
|
||||||
them open, deselect the \preferences > \uicontrol {Build & Run} >
|
them open, clear the \preferences > \uicontrol {Build & Run} >
|
||||||
\uicontrol General > \uicontrol {Close source files along with project}
|
\uicontrol General > \uicontrol {Close source files along with project}
|
||||||
check box.
|
check box.
|
||||||
\endlist
|
\endlist
|
||||||
@@ -139,7 +139,7 @@
|
|||||||
\endlist
|
\endlist
|
||||||
|
|
||||||
To stop synchronizing the position in the project tree with the file
|
To stop synchronizing the position in the project tree with the file
|
||||||
currently opened in the editor, deselect \inlineimage icons/linkicon.png
|
currently opened in the editor, clear \inlineimage icons/linkicon.png
|
||||||
(\uicontrol {Synchronize with Editor}).
|
(\uicontrol {Synchronize with Editor}).
|
||||||
|
|
||||||
Some build systems support adding and removing files to a project in \QC
|
Some build systems support adding and removing files to a project in \QC
|
||||||
|
@@ -57,7 +57,7 @@
|
|||||||
or select \key F6 and \key Shift+F6.
|
or select \key F6 and \key Shift+F6.
|
||||||
|
|
||||||
By default, a new build clears the \uicontrol Issues view. To keep
|
By default, a new build clears the \uicontrol Issues view. To keep
|
||||||
the issues from the previous build rounds, deselect \preferences >
|
the issues from the previous build rounds, clear \preferences >
|
||||||
\uicontrol {Build & Run} > \uicontrol General >
|
\uicontrol {Build & Run} > \uicontrol General >
|
||||||
\uicontrol {Clear issues list on new build}.
|
\uicontrol {Clear issues list on new build}.
|
||||||
|
|
||||||
|
@@ -54,7 +54,7 @@
|
|||||||
Unified Change Management (UCM) view, they are added to the change set of
|
Unified Change Management (UCM) view, they are added to the change set of
|
||||||
a UCM activity. By default, the activities are automatically assigned names.
|
a UCM activity. By default, the activities are automatically assigned names.
|
||||||
To disable this functionality, select \preferences >
|
To disable this functionality, select \preferences >
|
||||||
\uicontrol {Version Control} > \uicontrol ClearCase, and then deselect the
|
\uicontrol {Version Control} > \uicontrol ClearCase, and then clear the
|
||||||
\uicontrol {Auto assign activity names} check box.
|
\uicontrol {Auto assign activity names} check box.
|
||||||
|
|
||||||
To automatically check out files when you edit them, select the
|
To automatically check out files when you edit them, select the
|
||||||
|
@@ -64,7 +64,7 @@
|
|||||||
within the client workspace. By default, files are automatically opened for
|
within the client workspace. By default, files are automatically opened for
|
||||||
editing. To disable this feature, select \preferences >
|
editing. To disable this feature, select \preferences >
|
||||||
\uicontrol {Version Control} > \uicontrol Perforce,
|
\uicontrol {Version Control} > \uicontrol Perforce,
|
||||||
and then deselect the \uicontrol {Automatically open files when editing}
|
and then clear the \uicontrol {Automatically open files when editing}
|
||||||
check box.
|
check box.
|
||||||
|
|
||||||
To list files that are open for editing, select \uicontrol Tools >
|
To list files that are open for editing, select \uicontrol Tools >
|
||||||
|
@@ -145,7 +145,7 @@
|
|||||||
\row
|
\row
|
||||||
\li Check box - \uicontrol {Clean whitespace}
|
\li Check box - \uicontrol {Clean whitespace}
|
||||||
\li Removes trailing whitespace upon saving.
|
\li Removes trailing whitespace upon saving.
|
||||||
\li Enable this check box to remove trailing whitespace upon saving.
|
\li Select this check box to remove trailing whitespace upon saving.
|
||||||
\row
|
\row
|
||||||
\li Combo box - \uicontrol Size
|
\li Combo box - \uicontrol Size
|
||||||
\li The font size used in the terminal (in points).
|
\li The font size used in the terminal (in points).
|
||||||
|
@@ -202,7 +202,7 @@
|
|||||||
select \imageplus
|
select \imageplus
|
||||||
.
|
.
|
||||||
\li In the \uicontrol {Property Type} field, enter \e {Item}.
|
\li In the \uicontrol {Property Type} field, enter \e {Item}.
|
||||||
This field is a drop-down list, but you can also type text.
|
This field is a drop-down list, but you can also enter text.
|
||||||
\li In the \uicontrol {Property Value} field, enter \e {null}.
|
\li In the \uicontrol {Property Value} field, enter \e {null}.
|
||||||
\endlist
|
\endlist
|
||||||
\image animation-tutorial-property.png
|
\image animation-tutorial-property.png
|
||||||
|
@@ -116,7 +116,7 @@
|
|||||||
|
|
||||||
\image coffee-machine-properties.png
|
\image coffee-machine-properties.png
|
||||||
|
|
||||||
When we deselect the record button to stop recording the timeline, the
|
When we clear the record button to stop recording the timeline, the
|
||||||
new timeline appears in the view.
|
new timeline appears in the view.
|
||||||
|
|
||||||
For more information about using the timeline, see
|
For more information about using the timeline, see
|
||||||
|
@@ -54,7 +54,7 @@
|
|||||||
to return to the Standard screen. Finally, at frame 4000, we set the X
|
to return to the Standard screen. Finally, at frame 4000, we set the X
|
||||||
coordinate to -19 to return to the Trip screen.
|
coordinate to -19 to return to the Trip screen.
|
||||||
|
|
||||||
When we deselect the record button to stop recording the timeline, the
|
When we clear the record button to stop recording the timeline, the
|
||||||
new timeline appears in the view.
|
new timeline appears in the view.
|
||||||
|
|
||||||
When we select \e tripScreen in the \uicontrol Navigator, we can see the
|
When we select \e tripScreen in the \uicontrol Navigator, we can see the
|
||||||
|
@@ -158,7 +158,7 @@
|
|||||||
(\uicontrol {Per Property Recording}) button for the
|
(\uicontrol {Per Property Recording}) button for the
|
||||||
\uicontrol opacity property of \e repeatPassword to start
|
\uicontrol opacity property of \e repeatPassword to start
|
||||||
recording property changes.
|
recording property changes.
|
||||||
\li In \uicontrol Visibility > \uicontrol Opacity, type \e 0 to hide the button, and press
|
\li In \uicontrol Visibility > \uicontrol Opacity, enter \e 0 to hide the button, and press
|
||||||
\key Enter to save the value.
|
\key Enter to save the value.
|
||||||
\li Move the playhead to frame \e 1000 and change the opacity value to \e 1
|
\li Move the playhead to frame \e 1000 and change the opacity value to \e 1
|
||||||
to show the button.
|
to show the button.
|
||||||
|
@@ -23,7 +23,7 @@
|
|||||||
\l {progress-bar-control}{Progress Bar} component available in
|
\l {progress-bar-control}{Progress Bar} component available in
|
||||||
\uicontrol Components > \uicontrol {Qt Quick Controls}.
|
\uicontrol Components > \uicontrol {Qt Quick Controls}.
|
||||||
|
|
||||||
In the \uicontrol Design mode, we drag-and-drop a \uicontrol Rectangle from
|
In the \uicontrol Design mode, we drag a \uicontrol Rectangle from
|
||||||
\uicontrol Components > \uicontrol {Default Components} >
|
\uicontrol Components > \uicontrol {Default Components} >
|
||||||
\uicontrol Basic to the \l {2D} view and modify its size to create the
|
\uicontrol Basic to the \l {2D} view and modify its size to create the
|
||||||
background for the progress bar. We change its ID to \e pb_back in
|
background for the progress bar. We change its ID to \e pb_back in
|
||||||
@@ -31,12 +31,12 @@
|
|||||||
|
|
||||||
We want to be able to control the background rectangle and the text label
|
We want to be able to control the background rectangle and the text label
|
||||||
that was added by the project wizard, so we will use an \uicontrol Item
|
that was added by the project wizard, so we will use an \uicontrol Item
|
||||||
component for that. We drag-and-drop the Item from \uicontrol Components >
|
component for that. We drag the Item from \uicontrol Components >
|
||||||
\uicontrol {Default Components} > \uicontrol Basic
|
\uicontrol {Default Components} > \uicontrol Basic
|
||||||
to the \uicontrol {2D} view and change its ID to \e root in
|
to the \uicontrol {2D} view and change its ID to \e root in
|
||||||
\uicontrol Properties.
|
\uicontrol Properties.
|
||||||
|
|
||||||
To make the background and text children of the Item, we drag-and-drop them
|
To make the background and text children of the Item, we drag them
|
||||||
to the Item in \l Navigator. This enables us to use the anchor
|
to the Item in \l Navigator. This enables us to use the anchor
|
||||||
buttons in \uicontrol Properties > \uicontrol Layout to anchor them to their
|
buttons in \uicontrol Properties > \uicontrol Layout to anchor them to their
|
||||||
parent. We anchor the background to its parent on all edges, with a 30-pixel
|
parent. We anchor the background to its parent on all edges, with a 30-pixel
|
||||||
@@ -45,7 +45,7 @@
|
|||||||
|
|
||||||
\image progressbar-rectangle.png "Progress bar background in the 2D view"
|
\image progressbar-rectangle.png "Progress bar background in the 2D view"
|
||||||
|
|
||||||
We now drag-and-drop another rectangle on top of the background rectangle in
|
We now drag another rectangle on top of the background rectangle in
|
||||||
\uicontrol Navigator and change its ID to \e pb_front in
|
\uicontrol Navigator and change its ID to \e pb_front in
|
||||||
\uicontrol Properties.
|
\uicontrol Properties.
|
||||||
We then anchor the left, top, and bottom of the indicator to its parent with
|
We then anchor the left, top, and bottom of the indicator to its parent with
|
||||||
@@ -125,7 +125,7 @@
|
|||||||
We want the progress bar to be reusable, so we'll move it to a separate
|
We want the progress bar to be reusable, so we'll move it to a separate
|
||||||
component file. To make sure that the component will contain the timeline,
|
component file. To make sure that the component will contain the timeline,
|
||||||
we select \uicontrol {Filter Tree} in \uicontrol Navigator and then
|
we select \uicontrol {Filter Tree} in \uicontrol Navigator and then
|
||||||
deselect the \uicontrol {Show Only Visible Items} check box to show the
|
clear the \uicontrol {Show Only Visible Items} check box to show the
|
||||||
timeline component in \uicontrol Navigator. We then move the timeline
|
timeline component in \uicontrol Navigator. We then move the timeline
|
||||||
component to \e root to have it moved as a part of the root component.
|
component to \e root to have it moved as a part of the root component.
|
||||||
|
|
||||||
|
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
\e {Side Menu} displays a menu bar and a side menu that slides open when
|
\e {Side Menu} displays a menu bar and a side menu that slides open when
|
||||||
users click the menu icon. The appearance of the menu bar buttons changes
|
users click the menu icon. The appearance of the menu bar buttons changes
|
||||||
when users hover the cursor over them or select them.
|
when users hover over them or select them.
|
||||||
|
|
||||||
Each button opens an image file. The side menu can be used to apply
|
Each button opens an image file. The side menu can be used to apply
|
||||||
\l {2D effects}{graphical effects}, such as hue, saturation,
|
\l {2D effects}{graphical effects}, such as hue, saturation,
|
||||||
@@ -82,7 +82,7 @@
|
|||||||
We construct the menu bar in the \e {MainFile.ui.qml} file using the
|
We construct the menu bar in the \e {MainFile.ui.qml} file using the
|
||||||
\l {2D} view. The CustomButton component is listed in
|
\l {2D} view. The CustomButton component is listed in
|
||||||
\uicontrol Components > \uicontrol {My Components}.
|
\uicontrol Components > \uicontrol {My Components}.
|
||||||
We drag-and-drop several instances of the component to \uicontrol Navigator
|
We drag several instances of the component to \uicontrol Navigator
|
||||||
or the \uicontrol {2D} view and enclose them in a \uicontrol {Row Layout}
|
or the \uicontrol {2D} view and enclose them in a \uicontrol {Row Layout}
|
||||||
component instance to lay them out as a menu bar.
|
component instance to lay them out as a menu bar.
|
||||||
|
|
||||||
@@ -90,8 +90,8 @@
|
|||||||
|
|
||||||
We can change the properties of each CustomButton instance separately in
|
We can change the properties of each CustomButton instance separately in
|
||||||
the \uicontrol Properties view. We want only one of the menu bar buttons
|
the \uicontrol Properties view. We want only one of the menu bar buttons
|
||||||
to be checked at any time, so that checking another button automatically
|
to be selected at any time, so that selecting another button automatically
|
||||||
unchecks the previously checked one. Therefore, we set the
|
clears the previously selected one. Therefore, we set the
|
||||||
\l {AbstractButton::}{autoExclusive} property to \c true for all
|
\l {AbstractButton::}{autoExclusive} property to \c true for all
|
||||||
button instances.
|
button instances.
|
||||||
|
|
||||||
@@ -104,7 +104,7 @@
|
|||||||
\section1 Creating a side menu
|
\section1 Creating a side menu
|
||||||
|
|
||||||
We can now continue to create a side menu that slides open when users
|
We can now continue to create a side menu that slides open when users
|
||||||
click the burger menu. We drag-and-drop a \l Text component from
|
click the burger menu. We drag a \l Text component from
|
||||||
\uicontrol Components > \uicontrol {Default Components}
|
\uicontrol Components > \uicontrol {Default Components}
|
||||||
> \uicontrol Basic and a \l {slider-control}{Slider} component from
|
> \uicontrol Basic and a \l {slider-control}{Slider} component from
|
||||||
\uicontrol {Qt Quick Controls} to \uicontrol Navigator to create separate
|
\uicontrol {Qt Quick Controls} to \uicontrol Navigator to create separate
|
||||||
@@ -209,7 +209,7 @@
|
|||||||
in the \uicontrol Settings menu of the \uicontrol Value property in
|
in the \uicontrol Settings menu of the \uicontrol Value property in
|
||||||
\uicontrol Properties > \uicontrol Slider.
|
\uicontrol Properties > \uicontrol Slider.
|
||||||
|
|
||||||
We open the \e {EffectStack.qml} file, and drag-and-drop components from
|
We open the \e {EffectStack.qml} file, and drag components from
|
||||||
\uicontrol Components > \uicontrol {Qt Quick Studio Effects} to
|
\uicontrol Components > \uicontrol {Qt Quick Studio Effects} to
|
||||||
\uicontrol Navigator to create the effect stack.
|
\uicontrol Navigator to create the effect stack.
|
||||||
|
|
||||||
|
@@ -167,7 +167,7 @@
|
|||||||
|
|
||||||
In our UI, we use connections and states to move between screens. First,
|
In our UI, we use connections and states to move between screens. First,
|
||||||
we specify the application workflow in \e ApplicationFlow.qml. When the
|
we specify the application workflow in \e ApplicationFlow.qml. When the
|
||||||
file is open in the \uicontrol {2D} view, we drag-and-drop the components
|
file is open in the \uicontrol {2D} view, we drag the components
|
||||||
that define the screens in the application from \uicontrol Components to
|
that define the screens in the application from \uicontrol Components to
|
||||||
\uicontrol Navigator or the \uicontrol {2D} view: \e StartScreen,
|
\uicontrol Navigator or the \uicontrol {2D} view: \e StartScreen,
|
||||||
\e SettingsScreen, \e PresetsScreen, and \e RunningScreen.
|
\e SettingsScreen, \e PresetsScreen, and \e RunningScreen.
|
||||||
|
@@ -149,7 +149,7 @@
|
|||||||
the UI we will create. We use the imported components to create the
|
the UI we will create. We use the imported components to create the
|
||||||
UI in the \e {MainApp.ui.qml} file. The imported components are
|
UI in the \e {MainApp.ui.qml} file. The imported components are
|
||||||
listed in \uicontrol Components > \uicontrol {My Components},
|
listed in \uicontrol Components > \uicontrol {My Components},
|
||||||
and we can drag-and-drop them to the \l {2D} view.
|
and we can drag them to the \l {2D} view.
|
||||||
|
|
||||||
\image webinardemo-mainappui.png "Main app UI in Design mode"
|
\image webinardemo-mainappui.png "Main app UI in Design mode"
|
||||||
|
|
||||||
|
@@ -13,7 +13,7 @@
|
|||||||
that is to be animated, and apply the animation depending on the type of
|
that is to be animated, and apply the animation depending on the type of
|
||||||
behavior that is required.
|
behavior that is required.
|
||||||
|
|
||||||
You can drag-and-drop animation components from
|
You can drag animation components from
|
||||||
\uicontrol Components > \uicontrol {Default Components} >
|
\uicontrol Components > \uicontrol {Default Components} >
|
||||||
\uicontrol Animation to the \l Navigator or \l {2D} view to
|
\uicontrol Animation to the \l Navigator or \l {2D} view to
|
||||||
create instances of them.
|
create instances of them.
|
||||||
@@ -132,7 +132,7 @@
|
|||||||
|
|
||||||
You can create several animations that can run in parallel or in sequence.
|
You can create several animations that can run in parallel or in sequence.
|
||||||
To manage a group of animations that will play at the same time, create an
|
To manage a group of animations that will play at the same time, create an
|
||||||
instance of a \uicontrol {Parallel Animation} component and drag-and-drop
|
instance of a \uicontrol {Parallel Animation} component and drag
|
||||||
the other animations to it. To play the animations in the specified order,
|
the other animations to it. To play the animations in the specified order,
|
||||||
one after the other, create an instance of a
|
one after the other, create an instance of a
|
||||||
\uicontrol {Sequential Animation} instead.
|
\uicontrol {Sequential Animation} instead.
|
||||||
|
@@ -33,7 +33,7 @@
|
|||||||
(\uicontrol W) and height (\uicontrol H) of the button in
|
(\uicontrol W) and height (\uicontrol H) of the button in
|
||||||
\l Properties.
|
\l Properties.
|
||||||
|
|
||||||
\li Drag-and-drop a \uicontrol Rectangle from \uicontrol Components >
|
\li Drag a \uicontrol Rectangle from \uicontrol Components >
|
||||||
\uicontrol {Default Components} > \uicontrol Basic to the component
|
\uicontrol {Default Components} > \uicontrol Basic to the component
|
||||||
in \uicontrol Navigator. This creates a nested component where the
|
in \uicontrol Navigator. This creates a nested component where the
|
||||||
Item is the parent of the Rectangle. Components are positioned
|
Item is the parent of the Rectangle. Components are positioned
|
||||||
@@ -57,7 +57,7 @@
|
|||||||
|
|
||||||
\endlist
|
\endlist
|
||||||
|
|
||||||
\li Drag-and-drop a \uicontrol {Text} component to the Item in
|
\li Drag a \uicontrol {Text} component to the Item in
|
||||||
\uicontrol Navigator.
|
\uicontrol Navigator.
|
||||||
|
|
||||||
\li In the \uicontrol Properties view, edit the properties of the
|
\li In the \uicontrol Properties view, edit the properties of the
|
||||||
@@ -150,11 +150,11 @@
|
|||||||
\l Properties view to match the size of the images
|
\l Properties view to match the size of the images
|
||||||
you plan to use. This specifies the initial size of the button
|
you plan to use. This specifies the initial size of the button
|
||||||
component.
|
component.
|
||||||
\li Drag-and-drop two \uicontrol {Border Image} components from
|
\li Drag two \uicontrol {Border Image} components from
|
||||||
\uicontrol Components > \uicontrol {Default Components} >
|
\uicontrol Components > \uicontrol {Default Components} >
|
||||||
\uicontrol Basic to the root component in \uicontrol Navigator.
|
\uicontrol Basic to the root component in \uicontrol Navigator.
|
||||||
\li Drag-and-drop a \uicontrol Text component to the root component.
|
\li Drag a \uicontrol Text component to the root component.
|
||||||
\li Drag-and-drop a \uicontrol {Mouse Area} to the root component.
|
\li Drag a \uicontrol {Mouse Area} to the root component.
|
||||||
\li Select a border image to edit the values of its properties:
|
\li Select a border image to edit the values of its properties:
|
||||||
\list 1
|
\list 1
|
||||||
\li In the \uicontrol Id field, enter an ID for the border
|
\li In the \uicontrol Id field, enter an ID for the border
|
||||||
@@ -238,7 +238,7 @@
|
|||||||
When you work on other files in the project to create screens
|
When you work on other files in the project to create screens
|
||||||
or other components for the UI, the button component appears in
|
or other components for the UI, the button component appears in
|
||||||
\uicontrol Components > \uicontrol {My Components}.
|
\uicontrol Components > \uicontrol {My Components}.
|
||||||
You can drag-and-drop it to the \uicontrol {2D} or
|
You can drag it to the \uicontrol {2D} or
|
||||||
\uicontrol Navigator view to create button instances and modify the values
|
\uicontrol Navigator view to create button instances and modify the values
|
||||||
of their properties to assign them useful IDs, change their appearance,
|
of their properties to assign them useful IDs, change their appearance,
|
||||||
and set the button text for each button instance, for example.
|
and set the button text for each button instance, for example.
|
||||||
|
@@ -16,7 +16,7 @@
|
|||||||
To create component instances and edit their properties:
|
To create component instances and edit their properties:
|
||||||
|
|
||||||
\list 1
|
\list 1
|
||||||
\li Drag-and-drop components from \uicontrol Components (1) to the
|
\li Drag components from \uicontrol Components (1) to the
|
||||||
\l Navigator (2), \l {2D} (3), or \l {3D} view (4).
|
\l Navigator (2), \l {2D} (3), or \l {3D} view (4).
|
||||||
This creates instances of the components in the current
|
This creates instances of the components in the current
|
||||||
component file.
|
component file.
|
||||||
|
@@ -33,7 +33,7 @@
|
|||||||
capital letter.
|
capital letter.
|
||||||
\li Click \uicontrol Design to open the file in the
|
\li Click \uicontrol Design to open the file in the
|
||||||
\uicontrol {2D} view.
|
\uicontrol {2D} view.
|
||||||
\li Drag-and-drop a component from \uicontrol Components to
|
\li Drag a component from \uicontrol Components to
|
||||||
\uicontrol Navigator or the \uicontrol {2D} view.
|
\uicontrol Navigator or the \uicontrol {2D} view.
|
||||||
\li Edit component properties in the \uicontrol Properties view.
|
\li Edit component properties in the \uicontrol Properties view.
|
||||||
The available properties depend on the component type. You can
|
The available properties depend on the component type. You can
|
||||||
|
@@ -124,7 +124,7 @@
|
|||||||
\section3 Flat buttons
|
\section3 Flat buttons
|
||||||
|
|
||||||
A flat button typically does not draw a background unless it is pressed or
|
A flat button typically does not draw a background unless it is pressed or
|
||||||
checked. To create a flat button, select the \uicontrol Flat check box in
|
selected. To create a flat button, select the \uicontrol Flat check box in
|
||||||
the \uicontrol Button section.
|
the \uicontrol Button section.
|
||||||
|
|
||||||
The following image shows an example of a flat button:
|
The following image shows an example of a flat button:
|
||||||
@@ -134,7 +134,7 @@
|
|||||||
\section3 Icon buttons
|
\section3 Icon buttons
|
||||||
|
|
||||||
To create a button that contains an icon, use the wizard template to
|
To create a button that contains an icon, use the wizard template to
|
||||||
\l{Creating Custom Controls}{create a custom button} and drag-and-drop
|
\l{Creating Custom Controls}{create a custom button} and drag
|
||||||
the icon to the button background component. For an example of using the
|
the icon to the button background component. For an example of using the
|
||||||
wizard template, see \l{Creating a Push Button}.
|
wizard template, see \l{Creating a Push Button}.
|
||||||
|
|
||||||
|
@@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
\image qtquick-designer-image-type.png "Image component in different views"
|
\image qtquick-designer-image-type.png "Image component in different views"
|
||||||
|
|
||||||
When you drag-and-drop an image file from \uicontrol Assets to \l Navigator
|
When you drag an image file from \uicontrol Assets to \l Navigator
|
||||||
or the \l {2D} view, \QDS automatically
|
or the \l {2D} view, \QDS automatically
|
||||||
creates an instance of the Image component for you with the path to the
|
creates an instance of the Image component for you with the path to the
|
||||||
image file set as the value of the \uicontrol Source field in
|
image file set as the value of the \uicontrol Source field in
|
||||||
@@ -181,7 +181,7 @@
|
|||||||
(\uicontrol Paused) check box.
|
(\uicontrol Paused) check box.
|
||||||
|
|
||||||
When the \uicontrol Cache check box is selected, every frame of the
|
When the \uicontrol Cache check box is selected, every frame of the
|
||||||
animation is cached. Deselect the check box if you are playing a long
|
animation is cached. Clear the check box if you are playing a long
|
||||||
or large animation and you want to conserve memory.
|
or large animation and you want to conserve memory.
|
||||||
|
|
||||||
If the image data comes from a sequential device (such as a socket),
|
If the image data comes from a sequential device (such as a socket),
|
||||||
|
@@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
By default, the path is closed, which means that its start and end points
|
By default, the path is closed, which means that its start and end points
|
||||||
are identical. To create separate start and end points for it, right-click
|
are identical. To create separate start and end points for it, right-click
|
||||||
an edit point to open a context menu, and deselect \uicontrol {Closed Path}.
|
an edit point to open a context menu, and clear \uicontrol {Closed Path}.
|
||||||
|
|
||||||
To add intermediary points to a curve segment, select \uicontrol {Split Segment}
|
To add intermediary points to a curve segment, select \uicontrol {Split Segment}
|
||||||
in the context menu.
|
in the context menu.
|
||||||
|
@@ -79,7 +79,7 @@
|
|||||||
pressed.
|
pressed.
|
||||||
|
|
||||||
Even though \uicontrol {Mouse Area} is an invisible component, it has a
|
Even though \uicontrol {Mouse Area} is an invisible component, it has a
|
||||||
\uicontrol Visible property. Deselect the \uicontrol Visible check box in
|
\uicontrol Visible property. Clear the \uicontrol Visible check box in
|
||||||
the \uicontrol Visibility section to make the mouse area transparent to
|
the \uicontrol Visibility section to make the mouse area transparent to
|
||||||
mouse events.
|
mouse events.
|
||||||
|
|
||||||
|
@@ -45,7 +45,7 @@
|
|||||||
\list 1
|
\list 1
|
||||||
\li In the \uicontrol {Export path} field, specify the path where
|
\li In the \uicontrol {Export path} field, specify the path where
|
||||||
the metadata file and assets are exported.
|
the metadata file and assets are exported.
|
||||||
\li Deselect the \uicontrol {Export assets} check box to disable
|
\li Clear the \uicontrol {Export assets} check box to disable
|
||||||
exporting assets and only generate the metadata file.
|
exporting assets and only generate the metadata file.
|
||||||
\li Select the \uicontrol {Export components separately} check box to
|
\li Select the \uicontrol {Export components separately} check box to
|
||||||
generate separate metadata files for each component.
|
generate separate metadata files for each component.
|
||||||
|
@@ -30,7 +30,7 @@
|
|||||||
set of predefined properties, some of which control things that are
|
set of predefined properties, some of which control things that are
|
||||||
visible to users, while others are used behind the scene.
|
visible to users, while others are used behind the scene.
|
||||||
|
|
||||||
You drag-and-drop the preset components from the \uicontrol Components view
|
You drag the preset components from the \uicontrol Components view
|
||||||
to the \l {2D}, \l {3D}, or \l Navigator view to create
|
to the \l {2D}, \l {3D}, or \l Navigator view to create
|
||||||
instances of them. You then change the instances to your liking by modifying
|
instances of them. You then change the instances to your liking by modifying
|
||||||
their properties in the \l Properties view. The application code is
|
their properties in the \l Properties view. The application code is
|
||||||
|
@@ -11,12 +11,12 @@
|
|||||||
You can import 2D assets, such as images, fonts, and sound files, to \QDS to
|
You can import 2D assets, such as images, fonts, and sound files, to \QDS to
|
||||||
use them in your projects.
|
use them in your projects.
|
||||||
|
|
||||||
To import an asset, drag-and-drop the external file containing the asset from,
|
To import an asset, drag the external file containing the asset from,
|
||||||
for example, File Explorer on Windows, to the \uicontrol {2D},
|
for example, File Explorer on Windows, to the \uicontrol {2D},
|
||||||
\uicontrol Navigator, or \uicontrol {Code} view. Alternatively, select
|
\uicontrol Navigator, or \uicontrol {Code} view. Alternatively, select
|
||||||
\uicontrol Assets > \imageplus
|
\uicontrol Assets > \imageplus
|
||||||
and follow the instructions in the \uicontrol {Asset Import} dialog. You can
|
and follow the instructions in the \uicontrol {Asset Import} dialog. You can
|
||||||
also multiselect several external asset files to drag-and-drop them to
|
also multiselect several external asset files to drag them to
|
||||||
\QDS simultaneously.
|
\QDS simultaneously.
|
||||||
|
|
||||||
The imported images will appear in \uicontrol Assets.
|
The imported images will appear in \uicontrol Assets.
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
external font file to the \uicontrol {2D} view, it will be added to your
|
external font file to the \uicontrol {2D} view, it will be added to your
|
||||||
project as a text component. Other imported assets, such as sound files,
|
project as a text component. Other imported assets, such as sound files,
|
||||||
will only appear in \uicontrol Assets, and you can then
|
will only appear in \uicontrol Assets, and you can then
|
||||||
drag-and-drop them to a suitable view.
|
drag them to a suitable view.
|
||||||
|
|
||||||
\section1 Importing designs from other design tools
|
\section1 Importing designs from other design tools
|
||||||
|
|
||||||
@@ -74,9 +74,9 @@
|
|||||||
the image files to.
|
the image files to.
|
||||||
\li Select the \uicontrol {Create sub directory} check box to import the
|
\li Select the \uicontrol {Create sub directory} check box to import the
|
||||||
assets in a sub directory inside \uicontrol {Export Paths}.
|
assets in a sub directory inside \uicontrol {Export Paths}.
|
||||||
\li Deselect the \uicontrol {Import assets} check box if you only want
|
\li Clear the \uicontrol {Import assets} check box if you only want
|
||||||
to create QML files.
|
to create QML files.
|
||||||
\li Deselect the \uicontrol {Generate QML} check box if you only
|
\li Clear the \uicontrol {Generate QML} check box if you only
|
||||||
want to import assets.
|
want to import assets.
|
||||||
\li Select the \uicontrol {Merge QML} check box if you have imported the
|
\li Select the \uicontrol {Merge QML} check box if you have imported the
|
||||||
assets before and want to merge the changes into existing QML files
|
assets before and want to merge the changes into existing QML files
|
||||||
@@ -93,7 +93,7 @@
|
|||||||
The components that you specified in the design tool are displayed in
|
The components that you specified in the design tool are displayed in
|
||||||
\uicontrol Components > \uicontrol {My Components} as well as in the
|
\uicontrol Components > \uicontrol {My Components} as well as in the
|
||||||
\uicontrol Projects view as separate QML files. To use them,
|
\uicontrol Projects view as separate QML files. To use them,
|
||||||
drag-and-drop them from \uicontrol Components to the \uicontrol {2D} or
|
drag them from \uicontrol Components to the \uicontrol {2D} or
|
||||||
\l Navigator view.
|
\l Navigator view.
|
||||||
|
|
||||||
If asset importer conflicts, warnings, and errors are displayed in the
|
If asset importer conflicts, warnings, and errors are displayed in the
|
||||||
|
@@ -111,7 +111,7 @@
|
|||||||
|
|
||||||
Double-click the \uicontrol {Qt/SML Send} or \uicontrol {Qt/QML Receive}
|
Double-click the \uicontrol {Qt/SML Send} or \uicontrol {Qt/QML Receive}
|
||||||
block in Simulink to specify a property name. A pop-up for \uicontrol
|
block in Simulink to specify a property name. A pop-up for \uicontrol
|
||||||
{Block Parameters} appears. Type the name of the property in the \uicontrol
|
{Block Parameters} appears. Enter the name of the property in the \uicontrol
|
||||||
{Qt Signal/Property Name} field and click \uicontrol OK. The name, for
|
{Qt Signal/Property Name} field and click \uicontrol OK. The name, for
|
||||||
example speedProp, needs to match a \uicontrol signal or a \uicontrol
|
example speedProp, needs to match a \uicontrol signal or a \uicontrol
|
||||||
property in \QDS.
|
property in \QDS.
|
||||||
@@ -165,7 +165,7 @@
|
|||||||
bind the root item property. Select the \imageactionicon
|
bind the root item property. Select the \imageactionicon
|
||||||
(\uicontrol Actions) menu next to a property, and then select
|
(\uicontrol Actions) menu next to a property, and then select
|
||||||
\uicontrol {Set Binding}. In the \uicontrol {Binding Editor}, select the
|
\uicontrol {Set Binding}. In the \uicontrol {Binding Editor}, select the
|
||||||
text field and type in \c {<id>.<property name>}, for example
|
text field and enter \c {<id>.<property name>}, for example
|
||||||
\c rectangle.speedProp. For more information, see \l {Setting bindings}.
|
\c rectangle.speedProp. For more information, see \l {Setting bindings}.
|
||||||
|
|
||||||
\image studio-binding-editor.png "The Binding Editor window"
|
\image studio-binding-editor.png "The Binding Editor window"
|
||||||
|
@@ -268,7 +268,7 @@
|
|||||||
component now appears in \uicontrol {My 3D Components}.
|
component now appears in \uicontrol {My 3D Components}.
|
||||||
\image exporting-from-qt3ds/33-see-qml-stream-component-in-myqmlcomponents.png "QML stream in My QML Components"
|
\image exporting-from-qt3ds/33-see-qml-stream-component-in-myqmlcomponents.png "QML stream in My QML Components"
|
||||||
|
|
||||||
\li Drag-and-drop the QML stream component to MyOwnCluster in \uicontrol
|
\li Drag the QML stream component to MyOwnCluster in \uicontrol
|
||||||
Navigator.
|
Navigator.
|
||||||
\image exporting-from-qt3ds/34-drag-to-myowncluster-in-navigator.png "Drag the QML stream component to MyOwnCluster"
|
\image exporting-from-qt3ds/34-drag-to-myowncluster-in-navigator.png "Drag the QML stream component to MyOwnCluster"
|
||||||
|
|
||||||
|
@@ -9,7 +9,7 @@
|
|||||||
\title 3D effects
|
\title 3D effects
|
||||||
|
|
||||||
\QDS provides a set of 3D effects, which are visible in the \l {2D} view.
|
\QDS provides a set of 3D effects, which are visible in the \l {2D} view.
|
||||||
To apply a visual effect to a scene, drag-and-drop an effect from
|
To apply a visual effect to a scene, drag an effect from
|
||||||
\uicontrol Components > \uicontrol {Qt Quick 3D} >
|
\uicontrol Components > \uicontrol {Qt Quick 3D} >
|
||||||
\uicontrol {Qt Quick 3D Effects} to a \uicontrol SceneEnvironment component
|
\uicontrol {Qt Quick 3D Effects} to a \uicontrol SceneEnvironment component
|
||||||
in \l Navigator.
|
in \l Navigator.
|
||||||
|
@@ -14,7 +14,7 @@
|
|||||||
the \l Properties view simultaneously.
|
the \l Properties view simultaneously.
|
||||||
|
|
||||||
To add a \uicontrol Group component
|
To add a \uicontrol Group component
|
||||||
to your scene, drag-and-drop it from \uicontrol Components >
|
to your scene, drag it from \uicontrol Components >
|
||||||
\uicontrol {Qt Quick 3D} > \uicontrol {Qt Quick 3D} to the \l {3D}
|
\uicontrol {Qt Quick 3D} > \uicontrol {Qt Quick 3D} to the \l {3D}
|
||||||
view or to \l Navigator > \uicontrol View3D > \uicontrol {Scene Environment}
|
view or to \l Navigator > \uicontrol View3D > \uicontrol {Scene Environment}
|
||||||
> \uicontrol Scene.
|
> \uicontrol Scene.
|
||||||
|
@@ -47,7 +47,7 @@
|
|||||||
\l{https://doc.qt.io/qt/qml-qtquick3d-fileinstancing.html}{FileInstancing}
|
\l{https://doc.qt.io/qt/qml-qtquick3d-fileinstancing.html}{FileInstancing}
|
||||||
QML type.
|
QML type.
|
||||||
|
|
||||||
To use the \uicontrol Instancing component, drag-and-drop it from
|
To use the \uicontrol Instancing component, drag it from
|
||||||
\uicontrol Components to \uicontrol Scene in \uicontrol Navigator.
|
\uicontrol Components to \uicontrol Scene in \uicontrol Navigator.
|
||||||
|
|
||||||
\section2 Instancing properties
|
\section2 Instancing properties
|
||||||
@@ -84,11 +84,11 @@
|
|||||||
|
|
||||||
To build an instance table:
|
To build an instance table:
|
||||||
\list 1
|
\list 1
|
||||||
\li Drag-and-drop an \uicontrol {Instance List} component from
|
\li Drag an \uicontrol {Instance List} component from
|
||||||
\uicontrol Components > \uicontrol {Qt Quick 3D}
|
\uicontrol Components > \uicontrol {Qt Quick 3D}
|
||||||
> \uicontrol {Qt Quick 3D} to \uicontrol Scene in
|
> \uicontrol {Qt Quick 3D} to \uicontrol Scene in
|
||||||
\uicontrol Navigator.
|
\uicontrol Navigator.
|
||||||
\li Drag-and-drop \uicontrol {Instance List Entry} components to the
|
\li Drag \uicontrol {Instance List Entry} components to the
|
||||||
\uicontrol {Instance List} component to create list items.
|
\uicontrol {Instance List} component to create list items.
|
||||||
\image studio-3d-instancing-instance-list.png "Instance List and Instance Entries in Navigator"
|
\image studio-3d-instancing-instance-list.png "Instance List and Instance Entries in Navigator"
|
||||||
|
|
||||||
|
@@ -23,7 +23,7 @@
|
|||||||
\uicontrol {Target Qt Version} when \l {Creating projects}{creating your project}.
|
\uicontrol {Target Qt Version} when \l {Creating projects}{creating your project}.
|
||||||
|
|
||||||
To apply a 3D material to a component, you should first delete the default
|
To apply a 3D material to a component, you should first delete the default
|
||||||
material and then drag-and-drop a new material from
|
material and then drag a new material from
|
||||||
\uicontrol Components > \uicontrol {Qt Quick 3D Materials} >
|
\uicontrol Components > \uicontrol {Qt Quick 3D Materials} >
|
||||||
\uicontrol {Qt Quick 3D Materials} to a model component in \l Navigator.
|
\uicontrol {Qt Quick 3D Materials} to a model component in \l Navigator.
|
||||||
The materials you add to the model are listed in the model component's
|
The materials you add to the model are listed in the model component's
|
||||||
|
@@ -18,7 +18,7 @@
|
|||||||
The normal workflow is to use an external content creation tool to create
|
The normal workflow is to use an external content creation tool to create
|
||||||
a mesh, which also contains morph targets, and import it to \QDS.
|
a mesh, which also contains morph targets, and import it to \QDS.
|
||||||
|
|
||||||
To add a morph target for a model in \QDS, drag-and-drop a
|
To add a morph target for a model in \QDS, drag a
|
||||||
\uicontrol {Morph Target} component from \uicontrol Components
|
\uicontrol {Morph Target} component from \uicontrol Components
|
||||||
> \uicontrol {Qt Quick 3D} > \uicontrol {Qt Quick 3D} to \uicontrol Scene in
|
> \uicontrol {Qt Quick 3D} > \uicontrol {Qt Quick 3D} to \uicontrol Scene in
|
||||||
\l Navigator. Then select the model in \uicontrol Navigator, and in
|
\l Navigator. Then select the model in \uicontrol Navigator, and in
|
||||||
|
@@ -386,7 +386,7 @@
|
|||||||
when you select it again.
|
when you select it again.
|
||||||
|
|
||||||
To temporarily stop the simulation, select \uicontrol Paused. Particles
|
To temporarily stop the simulation, select \uicontrol Paused. Particles
|
||||||
are not destroyed, and when you deselect the check box, the simulation
|
are not destroyed, and when you clear the check box, the simulation
|
||||||
resumes from the point where you paused it.
|
resumes from the point where you paused it.
|
||||||
|
|
||||||
Select \uicontrol Logging to collect particle system statistics, such as
|
Select \uicontrol Logging to collect particle system statistics, such as
|
||||||
@@ -1131,7 +1131,7 @@
|
|||||||
them in \uicontrol Particles. Select \imageplus
|
them in \uicontrol Particles. Select \imageplus
|
||||||
to add logical particles to the list.
|
to add logical particles to the list.
|
||||||
|
|
||||||
Deselect \uicontrol Enabled to turn the affector off. Usually, this
|
Clear \uicontrol Enabled to turn the affector off. Usually, this
|
||||||
property is used in code to conditionally turn affectors off and on.
|
property is used in code to conditionally turn affectors off and on.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
Logic helpers are invisible components that you can use in connection with
|
Logic helpers are invisible components that you can use in connection with
|
||||||
controls, such as a \l {slider-control}{Slider} or \l {Check Box}.
|
controls, such as a \l {slider-control}{Slider} or \l {Check Box}.
|
||||||
To use a logic helper, drag-and-drop it from \uicontrol Components >
|
To use a logic helper, drag it from \uicontrol Components >
|
||||||
\uicontrol {Qt Quick Studio Logic Helper} to \l Navigator. If you cannot
|
\uicontrol {Qt Quick Studio Logic Helper} to \l Navigator. If you cannot
|
||||||
find the logic helpers in \uicontrol {Components}, you need to add the
|
find the logic helpers in \uicontrol {Components}, you need to add the
|
||||||
\uicontrol {Qt Quick Studio Logic Helper} module to your project,
|
\uicontrol {Qt Quick Studio Logic Helper} module to your project,
|
||||||
@@ -42,7 +42,7 @@
|
|||||||
The output is evaluated as \c true if both inputs are \c true.
|
The output is evaluated as \c true if both inputs are \c true.
|
||||||
|
|
||||||
For example, we could use the checked state of two check boxes to determine
|
For example, we could use the checked state of two check boxes to determine
|
||||||
the checked state of a third one. First, we drag-and-drop three instances of
|
the checked state of a third one. First, we drag three instances of
|
||||||
the \uicontrol {Check Box} components and one instance of the
|
the \uicontrol {Check Box} components and one instance of the
|
||||||
\uicontrol {And Operator} component to \uicontrol Navigator (1). Then, we
|
\uicontrol {And Operator} component to \uicontrol Navigator (1). Then, we
|
||||||
select the \uicontrol {And Operator} component instance (2) and set its
|
select the \uicontrol {And Operator} component instance (2) and set its
|
||||||
@@ -81,7 +81,7 @@
|
|||||||
condition is not met.
|
condition is not met.
|
||||||
|
|
||||||
For example, we could specify that if one check box is checked, another
|
For example, we could specify that if one check box is checked, another
|
||||||
one cannot be checked. First, we drag-and-drop two instances of the
|
one cannot be checked. First, we drag two instances of the
|
||||||
\uicontrol {Check Box} component and one instance of the
|
\uicontrol {Check Box} component and one instance of the
|
||||||
\uicontrol {Not Operator} component to \uicontrol Navigator. Then, we select
|
\uicontrol {Not Operator} component to \uicontrol Navigator. Then, we select
|
||||||
the \uicontrol {Not Operator} component instance and set its properties in
|
the \uicontrol {Not Operator} component instance and set its properties in
|
||||||
@@ -97,7 +97,7 @@
|
|||||||
|
|
||||||
\image studio-logic-helper-not-check-box.png "Check box checked property bound to NOT operator output"
|
\image studio-logic-helper-not-check-box.png "Check box checked property bound to NOT operator output"
|
||||||
|
|
||||||
When we preview our UI, the second check box is initially checked. However,
|
When we preview our UI, the second check box is initially selected. However,
|
||||||
when we select the first check box, the second one is automatically cleared.
|
when we select the first check box, the second one is automatically cleared.
|
||||||
|
|
||||||
\image studio-logic-helper-not-operator.gif "Previewing two check boxes bound with a NOT operator"
|
\image studio-logic-helper-not-operator.gif "Previewing two check boxes bound with a NOT operator"
|
||||||
@@ -110,7 +110,7 @@
|
|||||||
a slider and checkbox. Typically, it is used to bind a backend value
|
a slider and checkbox. Typically, it is used to bind a backend value
|
||||||
to a control, such as a slider.
|
to a control, such as a slider.
|
||||||
|
|
||||||
For example, to synchronize the values of two sliders, we drag-and-drop two
|
For example, to synchronize the values of two sliders, we drag two
|
||||||
instances of the \uicontrol Slider component and one instance of the
|
instances of the \uicontrol Slider component and one instance of the
|
||||||
\uicontrol {Bi Direct. Binding} component to the same parent component in
|
\uicontrol {Bi Direct. Binding} component to the same parent component in
|
||||||
\uicontrol Navigator. Then, we select the bi-directional binding instance
|
\uicontrol Navigator. Then, we select the bi-directional binding instance
|
||||||
@@ -140,7 +140,7 @@
|
|||||||
the string.
|
the string.
|
||||||
|
|
||||||
For example, to use a \l Text component to display the value of a
|
For example, to use a \l Text component to display the value of a
|
||||||
slider, we drag-and-drop \uicontrol Text, \uicontrol Slider, and
|
slider, we drag \uicontrol Text, \uicontrol Slider, and
|
||||||
\uicontrol {String Mapper} components to the same parent component. Then,
|
\uicontrol {String Mapper} components to the same parent component. Then,
|
||||||
we select the \uicontrol {String Mapper} instance in \uicontrol Navigator
|
we select the \uicontrol {String Mapper} instance in \uicontrol Navigator
|
||||||
to display its properties in \uicontrol Properties. There we bind the value
|
to display its properties in \uicontrol Properties. There we bind the value
|
||||||
@@ -175,7 +175,7 @@
|
|||||||
|
|
||||||
For example, to restrict the maximum value of a slider to 0.60,
|
For example, to restrict the maximum value of a slider to 0.60,
|
||||||
regardless of the maximum value set in the slider properties,
|
regardless of the maximum value set in the slider properties,
|
||||||
we drag-and-drop a \uicontrol {Min Max Mapper} to our example
|
we drag a \uicontrol {Min Max Mapper} to our example
|
||||||
above. We select it to display its properties in \uicontrol Properties.
|
above. We select it to display its properties in \uicontrol Properties.
|
||||||
Then, we bind the value of the \uicontrol Input property of the mapper to
|
Then, we bind the value of the \uicontrol Input property of the mapper to
|
||||||
the value of the \c value property of the slider and set the value
|
the value of the \c value property of the slider and set the value
|
||||||
|
@@ -47,11 +47,11 @@
|
|||||||
in \l Navigator, you can select \imagelockon
|
in \l Navigator, you can select \imagelockon
|
||||||
to unlock it. You can also lock individual easing curves for editing.
|
to unlock it. You can also lock individual easing curves for editing.
|
||||||
|
|
||||||
To lock an animation curve, hover the mouse over the property in the list,
|
To lock an animation curve, hover over the property in the list,
|
||||||
and then select \imagelockoff
|
and then select \imagelockoff
|
||||||
.
|
.
|
||||||
|
|
||||||
To pin an animation curve, hover the mouse over the property in the list,
|
To pin an animation curve, hover over the property in the list,
|
||||||
and then select \imagepin
|
and then select \imagepin
|
||||||
.
|
.
|
||||||
|
|
||||||
|
@@ -125,7 +125,7 @@
|
|||||||
|
|
||||||
\image qtquick-properties-visibility.png "Visibility properties"
|
\image qtquick-properties-visibility.png "Visibility properties"
|
||||||
|
|
||||||
Deselect the \uicontrol Visible check box to hide a component and all
|
Clear the \uicontrol Visible check box to hide a component and all
|
||||||
its child components, unless they have explicitly been set to be visible.
|
its child components, unless they have explicitly been set to be visible.
|
||||||
This might have surprise effects when using property bindings. In such
|
This might have surprise effects when using property bindings. In such
|
||||||
cases, it may be better to use the \uicontrol Opacity property instead.
|
cases, it may be better to use the \uicontrol Opacity property instead.
|
||||||
|
@@ -147,7 +147,7 @@
|
|||||||
not part of a view.
|
not part of a view.
|
||||||
\li In \uicontrol States, select the \uicontrol + symbol to create
|
\li In \uicontrol States, select the \uicontrol + symbol to create
|
||||||
a new state and give it a name. For example, \c Normal.
|
a new state and give it a name. For example, \c Normal.
|
||||||
\li In \l Properties (2), deselect the \uicontrol Visibility
|
\li In \l Properties (2), clear the \uicontrol Visibility
|
||||||
check box or set \uicontrol Opacity to 0 for each component that
|
check box or set \uicontrol Opacity to 0 for each component that
|
||||||
is not needed in this view. If you specify the setting for the
|
is not needed in this view. If you specify the setting for the
|
||||||
parent component, all child components inherit it and are also
|
parent component, all child components inherit it and are also
|
||||||
|
@@ -121,13 +121,14 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
component Cell: Rectangle {
|
component Cell: Rectangle {
|
||||||
required property string display
|
required property var display
|
||||||
required property int row
|
required property int row
|
||||||
required property int column
|
required property int column
|
||||||
|
|
||||||
required property bool editing
|
required property bool editing
|
||||||
|
|
||||||
required property bool isBinding
|
required property bool isBinding
|
||||||
|
required property var propertyValue
|
||||||
|
|
||||||
color: root.backgroundColor
|
color: root.backgroundColor
|
||||||
implicitWidth: root.cellWidth
|
implicitWidth: root.cellWidth
|
||||||
@@ -227,7 +228,7 @@ Rectangle {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
leftPadding: root.leftPadding
|
leftPadding: root.leftPadding
|
||||||
|
|
||||||
value: parseInt(numberDelegate.display)
|
value: numberDelegate.display
|
||||||
from: -1000 // TODO define min/max
|
from: -1000 // TODO define min/max
|
||||||
to: 1000
|
to: 1000
|
||||||
editable: true
|
editable: true
|
||||||
@@ -261,7 +262,7 @@ Rectangle {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
anchors.leftMargin: root.leftPadding
|
anchors.leftMargin: root.leftPadding
|
||||||
|
|
||||||
checked: flagDelegate.display === "true"
|
checked: flagDelegate.display
|
||||||
text: flagDelegate.display
|
text: flagDelegate.display
|
||||||
|
|
||||||
onToggled: {
|
onToggled: {
|
||||||
@@ -328,7 +329,7 @@ Rectangle {
|
|||||||
height: parent.height
|
height: parent.height
|
||||||
verticalAlignment: Qt.AlignVCenter
|
verticalAlignment: Qt.AlignVCenter
|
||||||
color: StudioTheme.Values.themeTextColor
|
color: StudioTheme.Values.themeTextColor
|
||||||
text: colorDelegate.display
|
text: colorDelegate.propertyValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -748,6 +748,10 @@ Item {
|
|||||||
enabled: !root.propNameError && !root.uniNameError
|
enabled: !root.propNameError && !root.uniNameError
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
|
// Remove the focus from the editing control. It fixes a mac bug where a
|
||||||
|
// control's value doesn't get applied when the Apply button is clicked
|
||||||
|
acceptButton.forceActiveFocus()
|
||||||
|
|
||||||
root.accepted()
|
root.accepted()
|
||||||
root.visible = false
|
root.visible = false
|
||||||
}
|
}
|
||||||
|
@@ -15,6 +15,7 @@ Section {
|
|||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
readonly property string disabledTooltip: qsTr("This property is defined by an anchor or a layout.")
|
readonly property string disabledTooltip: qsTr("This property is defined by an anchor or a layout.")
|
||||||
|
readonly property string disabledAnchoredTooltip: qsTr("Adjust this property manually from the 2D view or by changing margins from Layout.")
|
||||||
|
|
||||||
function positionDisabled() {
|
function positionDisabled() {
|
||||||
return anchorBackend.isFilled || anchorBackend.isInLayout
|
return anchorBackend.isFilled || anchorBackend.isInLayout
|
||||||
@@ -67,7 +68,7 @@ Section {
|
|||||||
|
|
||||||
ControlLabel {
|
ControlLabel {
|
||||||
text: "X"
|
text: "X"
|
||||||
tooltip: xSpinBox.enabled ? qsTr("X-coordinate") : root.disabledTooltip
|
tooltip: xSpinBox.enabled ? qsTr("X-coordinate") : root.disabledAnchoredTooltip
|
||||||
enabled: xSpinBox.enabled
|
enabled: xSpinBox.enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,7 +89,7 @@ Section {
|
|||||||
|
|
||||||
ControlLabel {
|
ControlLabel {
|
||||||
text: "Y"
|
text: "Y"
|
||||||
tooltip: xSpinBox.enabled ? qsTr("Y-coordinate") : root.disabledTooltip
|
tooltip: ySpinBox.enabled ? qsTr("Y-coordinate") : root.disabledAnchoredTooltip
|
||||||
enabled: ySpinBox.enabled
|
enabled: ySpinBox.enabled
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@@ -123,7 +124,7 @@ Section {
|
|||||||
ControlLabel {
|
ControlLabel {
|
||||||
//: The width of the object
|
//: The width of the object
|
||||||
text: qsTr("W", "width")
|
text: qsTr("W", "width")
|
||||||
tooltip: widthSpinBox.enabled ? qsTr("Width") : root.disabledTooltip
|
tooltip: widthSpinBox.enabled ? qsTr("Width") : root.disabledAnchoredTooltip
|
||||||
enabled: widthSpinBox.enabled
|
enabled: widthSpinBox.enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,7 +146,7 @@ Section {
|
|||||||
ControlLabel {
|
ControlLabel {
|
||||||
//: The height of the object
|
//: The height of the object
|
||||||
text: qsTr("H", "height")
|
text: qsTr("H", "height")
|
||||||
tooltip: heightSpinBox.enabled ? qsTr("Height") : root.disabledTooltip
|
tooltip: heightSpinBox.enabled ? qsTr("Height") : root.disabledAnchoredTooltip
|
||||||
enabled: heightSpinBox.enabled
|
enabled: heightSpinBox.enabled
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
@@ -118,12 +118,15 @@ Rectangle {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
anchors.left: home.right
|
anchors.left: home.right
|
||||||
anchors.leftMargin: 10
|
anchors.leftMargin: 10
|
||||||
width: 160
|
width: 170
|
||||||
|
|
||||||
runTarget: backend?.runTargetIndex
|
runTarget: backend?.runTargetIndex
|
||||||
runManagerState: backend?.runManagerState
|
runManagerState: backend?.runManagerState
|
||||||
|
runManagerProgress: backend?.runManagerProgress
|
||||||
|
runManagerError: backend?.runManagerError
|
||||||
|
|
||||||
onClicked: backend.toggleRunning()
|
onClicked: backend.toggleRunning()
|
||||||
|
onCancelClicked: backend.cancelRunning()
|
||||||
onRunTargetSelected: function(targetName) { backend.selectRunTarget(targetName) }
|
onRunTargetSelected: function(targetName) { backend.selectRunTarget(targetName) }
|
||||||
onOpenRunTargets: backend.openDeviceManager()
|
onOpenRunTargets: backend.openDeviceManager()
|
||||||
}
|
}
|
||||||
|
@@ -2,6 +2,8 @@
|
|||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
|
import QtQuick.Shapes
|
||||||
|
import QtQuick.Layouts
|
||||||
import QtQuick.Templates as T
|
import QtQuick.Templates as T
|
||||||
|
|
||||||
import StudioTheme as StudioTheme
|
import StudioTheme as StudioTheme
|
||||||
@@ -17,11 +19,15 @@ Item {
|
|||||||
property bool hover: primaryButton.hover || menuButton.hover
|
property bool hover: primaryButton.hover || menuButton.hover
|
||||||
|
|
||||||
signal clicked()
|
signal clicked()
|
||||||
|
signal cancelClicked()
|
||||||
signal runTargetSelected(targetId: string)
|
signal runTargetSelected(targetId: string)
|
||||||
signal openRunTargets()
|
signal openRunTargets()
|
||||||
|
|
||||||
property int runTarget: 0
|
property int runTarget: 0 // index
|
||||||
|
property string runTargetName
|
||||||
property int runManagerState: RunManager.NotRunning
|
property int runManagerState: RunManager.NotRunning
|
||||||
|
property int runManagerProgress: 0
|
||||||
|
property string runManagerError
|
||||||
|
|
||||||
property int menuWidth: Math.max(160, root.width)
|
property int menuWidth: Math.max(160, root.width)
|
||||||
|
|
||||||
@@ -33,6 +39,11 @@ Item {
|
|||||||
return runManagerModel.data(modelIndex, RunManagerModel.Enabled)
|
return runManagerModel.data(modelIndex, RunManagerModel.Enabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getRunTargetName(index: int): string {
|
||||||
|
let modelIndex = runManagerModel.index(index, 0)
|
||||||
|
return runManagerModel.data(modelIndex, "targetName")
|
||||||
|
}
|
||||||
|
|
||||||
ToolTipArea {
|
ToolTipArea {
|
||||||
id: toolTipArea
|
id: toolTipArea
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
@@ -42,16 +53,85 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onRunTargetChanged: {
|
onRunTargetChanged: {
|
||||||
|
root.runTargetName = root.getRunTargetName(root.runTarget)
|
||||||
primaryButton.enabled = root.isRunTargetEnabled(root.runTarget)
|
primaryButton.enabled = root.isRunTargetEnabled(root.runTarget)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
component ProgressCircle: Shape {
|
||||||
|
id: shape
|
||||||
|
|
||||||
|
property real from: 0
|
||||||
|
property real to: 100
|
||||||
|
property bool indeterminate: false
|
||||||
|
property real value: 0.5
|
||||||
|
|
||||||
|
property int strokeWidth: 4
|
||||||
|
|
||||||
|
property int radiusX: (shape.width - shape.strokeWidth) / 2
|
||||||
|
property int radiusY: (shape.height - shape.strokeWidth) / 2
|
||||||
|
|
||||||
|
width: 20
|
||||||
|
height: 20
|
||||||
|
preferredRendererType: Shape.CurveRenderer
|
||||||
|
|
||||||
|
ShapePath {
|
||||||
|
id: background
|
||||||
|
strokeColor: "gray"
|
||||||
|
strokeWidth: shape.strokeWidth
|
||||||
|
fillColor: "transparent"
|
||||||
|
capStyle: ShapePath.FlatCap
|
||||||
|
|
||||||
|
PathAngleArc {
|
||||||
|
radiusX: shape.radiusX
|
||||||
|
radiusY: shape.radiusY
|
||||||
|
centerX: shape.width / 2
|
||||||
|
centerY: shape.height / 2
|
||||||
|
startAngle: 0
|
||||||
|
sweepAngle: 360
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ShapePath {
|
||||||
|
id: foreground
|
||||||
|
strokeColor: StudioTheme.Values.themeInteraction
|
||||||
|
strokeWidth: shape.strokeWidth
|
||||||
|
fillColor: "transparent"
|
||||||
|
capStyle: ShapePath.FlatCap
|
||||||
|
|
||||||
|
PathAngleArc {
|
||||||
|
radiusX: shape.radiusX
|
||||||
|
radiusY: shape.radiusY
|
||||||
|
centerX: shape.width / 2
|
||||||
|
centerY: shape.height / 2
|
||||||
|
startAngle: -90
|
||||||
|
sweepAngle: shape.indeterminate ? 90 : 360 * shape.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Indeterminate rotation animation
|
||||||
|
RotationAnimation on rotation {
|
||||||
|
loops: Animation.Infinite
|
||||||
|
from: 0
|
||||||
|
to: 360
|
||||||
|
running: shape.indeterminate
|
||||||
|
duration: 2000
|
||||||
|
|
||||||
|
onStopped: shape.rotation = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: runManagerModel
|
target: runManagerModel
|
||||||
|
|
||||||
function onModelReset() {
|
function onModelReset() {
|
||||||
|
root.runTargetName = root.getRunTargetName(root.runTarget)
|
||||||
primaryButton.enabled = root.isRunTargetEnabled(root.runTarget)
|
primaryButton.enabled = root.isRunTargetEnabled(root.runTarget)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
readonly property bool showProgress: root.runManagerState === RunManager.Packing
|
||||||
|
|| root.runManagerState === RunManager.Sending
|
||||||
|
|| root.runManagerState === RunManager.Starting
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
T.AbstractButton {
|
T.AbstractButton {
|
||||||
id: primaryButton
|
id: primaryButton
|
||||||
@@ -94,47 +174,95 @@ Item {
|
|||||||
width: primaryButton.width
|
width: primaryButton.width
|
||||||
height: primaryButton.height
|
height: primaryButton.height
|
||||||
|
|
||||||
Row {
|
RowLayout {
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
anchors.leftMargin: 8
|
anchors.leftMargin: 8
|
||||||
|
anchors.rightMargin: 8
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
spacing: 8
|
spacing: 8
|
||||||
|
|
||||||
T.Label {
|
Item {
|
||||||
|
width: 20
|
||||||
height: primaryButton.height
|
height: primaryButton.height
|
||||||
font.family: StudioTheme.Constants.iconFont.family
|
|
||||||
font.pixelSize: primaryButton.style.baseIconFontSize
|
ProgressCircle {
|
||||||
verticalAlignment: Text.AlignVCenter
|
anchors.centerIn: parent
|
||||||
horizontalAlignment: Text.AlignHCenter
|
visible: root.showProgress
|
||||||
color: {
|
indeterminate: root.runManagerState === RunManager.Packing
|
||||||
if (root.runManagerState === RunManager.NotRunning)
|
|| root.runManagerState === RunManager.Starting
|
||||||
return primaryButton.press ? primaryButton.style.text.idle
|
value: root.runManagerProgress / 100
|
||||||
: primaryButton.hover ? "#2eff68" // running green
|
|
||||||
: "#649a5d" // idle green
|
|
||||||
else
|
|
||||||
return primaryButton.press ? primaryButton.style.text.idle
|
|
||||||
: primaryButton.hover ? "#cc3c34" // recording red
|
|
||||||
: "#6a4242" // idle red
|
|
||||||
}
|
}
|
||||||
|
|
||||||
text: {
|
T.Label {
|
||||||
if (root.runManagerState === RunManager.NotRunning)
|
visible: !root.showProgress
|
||||||
return StudioTheme.Constants.playOutline_medium
|
height: primaryButton.height
|
||||||
else
|
|
||||||
return StudioTheme.Constants.stop_medium
|
font.family: StudioTheme.Constants.iconFont.family
|
||||||
|
font.pixelSize: primaryButton.style.baseIconFontSize
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
color: {
|
||||||
|
if (root.runManagerState === RunManager.NotRunning)
|
||||||
|
return primaryButton.press ? primaryButton.style.text.idle
|
||||||
|
: primaryButton.hover ? "#2eff68" // running green
|
||||||
|
: "#649a5d" // idle green
|
||||||
|
else
|
||||||
|
return primaryButton.press ? primaryButton.style.text.idle
|
||||||
|
: primaryButton.hover ? "#cc3c34" // recording red
|
||||||
|
: "#6a4242" // idle red
|
||||||
|
}
|
||||||
|
|
||||||
|
text: {
|
||||||
|
if (root.runManagerState === RunManager.NotRunning)
|
||||||
|
return StudioTheme.Constants.playOutline_medium
|
||||||
|
else
|
||||||
|
return StudioTheme.Constants.stop_medium
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
T.Label {
|
T.Label {
|
||||||
|
Layout.fillWidth: true
|
||||||
height: primaryButton.height
|
height: primaryButton.height
|
||||||
color: primaryButton.enabled ? primaryButton.style.text.idle
|
color: primaryButton.enabled ? primaryButton.style.text.idle
|
||||||
: primaryButton.style.text.disabled
|
: primaryButton.style.text.disabled
|
||||||
font.pixelSize: primaryButton.style.baseFontSize
|
font.pixelSize: primaryButton.style.baseFontSize
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignLeft
|
||||||
|
elide: Text.ElideMiddle
|
||||||
text: {
|
text: {
|
||||||
let index = runManagerModel.index(root.runTarget, 0)
|
if (root.runManagerState === RunManager.Packing)
|
||||||
return runManagerModel.data(index, "targetName")
|
return qsTr("Packing")
|
||||||
|
else if (root.runManagerState === RunManager.Sending)
|
||||||
|
return qsTr("Sending")
|
||||||
|
else if (root.runManagerState === RunManager.Starting)
|
||||||
|
return qsTr("Starting")
|
||||||
|
else
|
||||||
|
return root.runTargetName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
T.Label {
|
||||||
|
visible: root.showProgress || root.runManagerError
|
||||||
|
height: primaryButton.height
|
||||||
|
|
||||||
|
font.family: StudioTheme.Constants.iconFont.family
|
||||||
|
font.pixelSize: StudioTheme.Values.mediumFontSize
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
|
||||||
|
color: root.runManagerError ? StudioTheme.Values.themeError
|
||||||
|
: primaryButton.style.text.idle
|
||||||
|
text: root.runManagerError ? StudioTheme.Constants.error_medium
|
||||||
|
: StudioTheme.Constants.close_small
|
||||||
|
|
||||||
|
ToolTipArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
acceptedButtons: Qt.LeftButton
|
||||||
|
tooltip: root.runManagerError
|
||||||
|
|
||||||
|
onClicked: root.cancelClicked()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -256,6 +384,7 @@ Item {
|
|||||||
|
|
||||||
checkable: false
|
checkable: false
|
||||||
checked: window.visible
|
checked: window.visible
|
||||||
|
enabled: root.runManagerState === RunManager.NotRunning
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (window.visible) {
|
if (window.visible) {
|
||||||
|
@@ -77,10 +77,7 @@ public:
|
|||||||
template<typename String>
|
template<typename String>
|
||||||
friend void convertToString(String &string, BasicId id)
|
friend void convertToString(String &string, BasicId id)
|
||||||
{
|
{
|
||||||
if (id.isNull())
|
NanotraceHR::convertToString(string, id.id);
|
||||||
NanotraceHR::convertToString(string, "invalid null");
|
|
||||||
else
|
|
||||||
NanotraceHR::convertToString(string, id.internalId());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
friend bool compareId(BasicId first, BasicId second) { return first.id == second.id; }
|
friend bool compareId(BasicId first, BasicId second) { return first.id == second.id; }
|
||||||
@@ -146,8 +143,10 @@ public:
|
|||||||
template<typename String>
|
template<typename String>
|
||||||
friend void convertToString(String &string, CompoundBasicId id)
|
friend void convertToString(String &string, CompoundBasicId id)
|
||||||
{
|
{
|
||||||
convertToString(string, id.mainId());
|
int mainId = id;
|
||||||
convertToString(string, id.contextId());
|
int contextId = id >> 32;
|
||||||
|
convertToString(string, mainId);
|
||||||
|
convertToString(string, contextId);
|
||||||
}
|
}
|
||||||
|
|
||||||
friend bool compareId(CompoundBasicId first, CompoundBasicId second)
|
friend bool compareId(CompoundBasicId first, CompoundBasicId second)
|
||||||
|
@@ -748,15 +748,22 @@ extend_qtc_plugin(QmlDesigner
|
|||||||
|
|
||||||
extend_qtc_plugin(QmlDesigner
|
extend_qtc_plugin(QmlDesigner
|
||||||
CONDITION TARGET Qt::WebSockets
|
CONDITION TARGET Qt::WebSockets
|
||||||
|
DEFINES QT_WEBSOCKET_ENABLED
|
||||||
|
DEPENDS
|
||||||
|
Qt::WebSockets
|
||||||
|
)
|
||||||
|
|
||||||
|
extend_qtc_plugin(QmlDesigner
|
||||||
SOURCES_PREFIX components/devicesharing
|
SOURCES_PREFIX components/devicesharing
|
||||||
DEPENDS
|
DEPENDS
|
||||||
QtCreator::QrCodeGenerator Qt::WebSockets
|
QtCreator::QrCodeGenerator
|
||||||
SOURCES
|
SOURCES
|
||||||
device.cpp device.h
|
device.cpp device.h
|
||||||
deviceinfo.cpp deviceinfo.h
|
deviceinfo.cpp deviceinfo.h
|
||||||
devicemanager.cpp devicemanager.h
|
devicemanager.cpp devicemanager.h
|
||||||
devicemanagermodel.cpp devicemanagermodel.h
|
devicemanagermodel.cpp devicemanagermodel.h
|
||||||
devicemanagerwidget.cpp devicemanagerwidget.h
|
devicemanagerwidget.cpp devicemanagerwidget.h
|
||||||
|
websocketmock.h
|
||||||
)
|
)
|
||||||
|
|
||||||
extend_qtc_plugin(QmlDesigner
|
extend_qtc_plugin(QmlDesigner
|
||||||
@@ -774,7 +781,6 @@ extend_qtc_plugin(QmlDesigner
|
|||||||
PUBLIC_DEFINES DVCONNECTOR_ENABLED
|
PUBLIC_DEFINES DVCONNECTOR_ENABLED
|
||||||
SOURCES
|
SOURCES
|
||||||
dvconnector.cpp dvconnector.h
|
dvconnector.cpp dvconnector.h
|
||||||
resourcegeneratorproxy.cpp resourcegeneratorproxy.h
|
|
||||||
)
|
)
|
||||||
|
|
||||||
add_qtc_plugin(assetexporterplugin
|
add_qtc_plugin(assetexporterplugin
|
||||||
|
@@ -19,127 +19,13 @@
|
|||||||
|
|
||||||
#include <qtsupport/qtkitaspect.h>
|
#include <qtsupport/qtkitaspect.h>
|
||||||
|
|
||||||
#include <utils/qtcassert.h>
|
|
||||||
#include <utils/qtcprocess.h>
|
|
||||||
|
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QProgressDialog>
|
#include <QProgressDialog>
|
||||||
#include <QTemporaryFile>
|
|
||||||
#include <QXmlStreamWriter>
|
|
||||||
#include <QtConcurrent>
|
#include <QtConcurrent>
|
||||||
|
|
||||||
using namespace Utils;
|
using namespace Utils;
|
||||||
|
|
||||||
namespace QmlDesigner::ResourceGenerator {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
void generateMenuEntry(QObject *parent)
|
|
||||||
{
|
|
||||||
const Core::Context projectContext(QmlProjectManager::Constants::QML_PROJECT_ID);
|
|
||||||
// ToDo: move this to QtCreator and add tr to the string then
|
|
||||||
auto action = new QAction(Tr::tr("QmlDesigner::GenerateResource", "Generate QRC Resource File..."),
|
|
||||||
parent);
|
|
||||||
action->setEnabled(ProjectExplorer::ProjectManager::startupProject() != nullptr);
|
|
||||||
// todo make it more intelligent when it gets enabled
|
|
||||||
QObject::connect(ProjectExplorer::ProjectManager::instance(),
|
|
||||||
&ProjectExplorer::ProjectManager::startupProjectChanged,
|
|
||||||
[action]() {
|
|
||||||
if (auto buildSystem = QmlProjectManager::QmlBuildSystem::getStartupBuildSystem())
|
|
||||||
action->setEnabled(!buildSystem->qtForMCUs());
|
|
||||||
});
|
|
||||||
|
|
||||||
Core::Command *cmd = Core::ActionManager::registerAction(action, "QmlProject.CreateResource");
|
|
||||||
QObject::connect(action, &QAction::triggered, []() {
|
|
||||||
auto project = ProjectExplorer::ProjectManager::startupProject();
|
|
||||||
QTC_ASSERT(project, return);
|
|
||||||
const FilePath projectPath = project->projectFilePath().parentDir();
|
|
||||||
auto qrcFilePath = Core::DocumentManager::getSaveFileNameWithExtension(
|
|
||||||
Tr::tr("QmlDesigner::GenerateResource", "Save Project as QRC File"),
|
|
||||||
projectPath.pathAppended(project->displayName() + ".qrc"),
|
|
||||||
Tr::tr("QmlDesigner::GenerateResource", "QML Resource File (*.qrc)"));
|
|
||||||
|
|
||||||
if (qrcFilePath.toUrlishString().isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
createQrcFile(qrcFilePath);
|
|
||||||
|
|
||||||
Core::AsynchronousMessageBox::information(
|
|
||||||
Tr::tr("QmlDesigner::GenerateResource", "Success"),
|
|
||||||
Tr::tr("QmlDesigner::GenerateResource", "Successfully generated QRC resource file\n %1")
|
|
||||||
.arg(qrcFilePath.toUrlishString()));
|
|
||||||
});
|
|
||||||
|
|
||||||
// ToDo: move this to QtCreator and add tr to the string then
|
|
||||||
auto rccAction = new QAction(Tr::tr("QmlDesigner::GenerateResource",
|
|
||||||
"Generate Deployable Package..."),
|
|
||||||
parent);
|
|
||||||
rccAction->setEnabled(ProjectExplorer::ProjectManager::startupProject() != nullptr);
|
|
||||||
QObject::connect(ProjectExplorer::ProjectManager::instance(),
|
|
||||||
&ProjectExplorer::ProjectManager::startupProjectChanged,
|
|
||||||
[rccAction]() {
|
|
||||||
rccAction->setEnabled(ProjectExplorer::ProjectManager::startupProject());
|
|
||||||
});
|
|
||||||
|
|
||||||
Core::Command *cmd2 = Core::ActionManager::registerAction(rccAction,
|
|
||||||
"QmlProject.CreateRCCResource");
|
|
||||||
QObject::connect(rccAction, &QAction::triggered, []() {
|
|
||||||
auto project = ProjectExplorer::ProjectManager::startupProject();
|
|
||||||
QTC_ASSERT(project, return);
|
|
||||||
const FilePath projectPath = project->projectFilePath().parentDir();
|
|
||||||
const FilePath qmlrcFilePath = Core::DocumentManager::getSaveFileNameWithExtension(
|
|
||||||
Tr::tr("QmlDesigner::GenerateResource", "Save Project as Resource"),
|
|
||||||
projectPath.pathAppended(project->displayName() + ".qmlrc"),
|
|
||||||
"QML Resource File (*.qmlrc);;Resource File (*.rcc)");
|
|
||||||
|
|
||||||
if (qmlrcFilePath.toUrlishString().isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
QProgressDialog progress;
|
|
||||||
progress.setLabelText(Tr::tr("QmlDesigner::GenerateResource",
|
|
||||||
"Generating deployable package. Please wait..."));
|
|
||||||
progress.setRange(0, 0);
|
|
||||||
progress.setWindowModality(Qt::WindowModal);
|
|
||||||
progress.setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
|
|
||||||
progress.setCancelButton(nullptr);
|
|
||||||
progress.show();
|
|
||||||
|
|
||||||
QFuture<bool> future = QtConcurrent::run(
|
|
||||||
[qmlrcFilePath]() { return createQmlrcFile(qmlrcFilePath); });
|
|
||||||
|
|
||||||
while (!future.isFinished())
|
|
||||||
QCoreApplication::processEvents();
|
|
||||||
|
|
||||||
progress.close();
|
|
||||||
|
|
||||||
if (future.isCanceled()) {
|
|
||||||
qDebug() << "Operation canceled by user";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!future.result()) {
|
|
||||||
Core::MessageManager::writeDisrupting(
|
|
||||||
Tr::tr("QmlDesigner::GenerateResource", "Failed to generate deployable package!"));
|
|
||||||
QMessageBox msgBox;
|
|
||||||
msgBox.setWindowTitle(Tr::tr("QmlDesigner::GenerateResource", "Error"));
|
|
||||||
msgBox.setText(Tr::tr("QmlDesigner::GenerateResource",
|
|
||||||
"Failed to generate deployable package!\n\nPlease check "
|
|
||||||
"the output pane for more information."));
|
|
||||||
msgBox.exec();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QMessageBox msgBox;
|
|
||||||
msgBox.setWindowTitle(Tr::tr("QmlDesigner::GenerateResource", "Success"));
|
|
||||||
msgBox.setText(
|
|
||||||
Tr::tr("QmlDesigner::GenerateResource", "Successfully generated deployable package"));
|
|
||||||
msgBox.exec();
|
|
||||||
});
|
|
||||||
|
|
||||||
Core::ActionContainer *exportMenu = Core::ActionManager::actionContainer(
|
|
||||||
QmlProjectManager::Constants::EXPORT_MENU);
|
|
||||||
exportMenu->addAction(cmd, QmlProjectManager::Constants::G_EXPORT_GENERATE);
|
|
||||||
exportMenu->addAction(cmd2, QmlProjectManager::Constants::G_EXPORT_GENERATE);
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList getProjectFileList()
|
QStringList getProjectFileList()
|
||||||
{
|
{
|
||||||
const ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject();
|
const ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject();
|
||||||
@@ -156,12 +42,163 @@ QStringList getProjectFileList()
|
|||||||
return selectedFileList;
|
return selectedFileList;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool createQrcFile(const FilePath &qrcFilePath)
|
ResourceGenerator::ResourceGenerator(QObject *parent)
|
||||||
|
: QObject(parent)
|
||||||
|
{
|
||||||
|
connect(&m_rccProcess, &Utils::Process::done, this, [this]() {
|
||||||
|
const int exitCode = m_rccProcess.exitCode();
|
||||||
|
if (exitCode != 0) {
|
||||||
|
Core::MessageManager::writeDisrupting(Tr::tr("\"%1\" failed (exit code %2).")
|
||||||
|
.arg(m_rccProcess.commandLine().toUserOutput())
|
||||||
|
.arg(m_rccProcess.exitCode()));
|
||||||
|
emit errorOccurred(Tr::tr("Failed to generate deployable package!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_rccProcess.exitStatus() != QProcess::NormalExit) {
|
||||||
|
Core::MessageManager::writeDisrupting(
|
||||||
|
Tr::tr("\"%1\" crashed.").arg(m_rccProcess.commandLine().toUserOutput()));
|
||||||
|
emit errorOccurred(Tr::tr("Failed to generate deployable package!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit qmlrcCreated(m_qmlrcFilePath);
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(&m_rccProcess, &Utils::Process::textOnStandardError, this, [](const QString &text) {
|
||||||
|
Core::MessageManager::writeFlashing(QString::fromLocal8Bit(text.toLocal8Bit()));
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(&m_rccProcess, &Utils::Process::textOnStandardOutput, this, [](const QString &text) {
|
||||||
|
Core::MessageManager::writeFlashing(QString::fromLocal8Bit(text.toLocal8Bit()));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceGenerator::generateMenuEntry(QObject *parent)
|
||||||
|
{
|
||||||
|
const Core::Context projectContext(QmlProjectManager::Constants::QML_PROJECT_ID);
|
||||||
|
// ToDo: move this to QtCreator and add tr to the string then
|
||||||
|
auto action = new QAction(Tr::tr("Generate QRC Resource File..."), parent);
|
||||||
|
action->setEnabled(ProjectExplorer::ProjectManager::startupProject() != nullptr);
|
||||||
|
// todo make it more intelligent when it gets enabled
|
||||||
|
QObject::connect(ProjectExplorer::ProjectManager::instance(),
|
||||||
|
&ProjectExplorer::ProjectManager::startupProjectChanged,
|
||||||
|
[action]() {
|
||||||
|
if (auto buildSystem = QmlProjectManager::QmlBuildSystem::getStartupBuildSystem())
|
||||||
|
action->setEnabled(!buildSystem->qtForMCUs());
|
||||||
|
});
|
||||||
|
|
||||||
|
Core::Command *cmd = Core::ActionManager::registerAction(action, "QmlProject.CreateResource");
|
||||||
|
QObject::connect(action, &QAction::triggered, []() {
|
||||||
|
auto project = ProjectExplorer::ProjectManager::startupProject();
|
||||||
|
QTC_ASSERT(project, return);
|
||||||
|
const FilePath projectPath = project->projectFilePath().parentDir();
|
||||||
|
auto qrcFilePath = Core::DocumentManager::getSaveFileNameWithExtension(
|
||||||
|
Tr::tr("Save Project as QRC File"),
|
||||||
|
projectPath.pathAppended(project->displayName() + ".qrc"),
|
||||||
|
Tr::tr("QML Resource File (*.qrc)"));
|
||||||
|
|
||||||
|
if (qrcFilePath.toUrlishString().isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
ResourceGenerator resourceGenerator;
|
||||||
|
resourceGenerator.createQrc(qrcFilePath);
|
||||||
|
|
||||||
|
Core::AsynchronousMessageBox::information(
|
||||||
|
Tr::tr("QmlDesigner::GenerateResource", "Success"),
|
||||||
|
Tr::tr("QmlDesigner::GenerateResource", "Successfully generated QRC resource file\n %1")
|
||||||
|
.arg(qrcFilePath.toUrlishString()));
|
||||||
|
});
|
||||||
|
|
||||||
|
// ToDo: move this to QtCreator and add tr to the string then
|
||||||
|
auto rccAction = new QAction(Tr::tr("Generate Deployable Package..."), parent);
|
||||||
|
rccAction->setEnabled(ProjectExplorer::ProjectManager::startupProject() != nullptr);
|
||||||
|
QObject::connect(ProjectExplorer::ProjectManager::instance(),
|
||||||
|
&ProjectExplorer::ProjectManager::startupProjectChanged,
|
||||||
|
[rccAction]() {
|
||||||
|
rccAction->setEnabled(ProjectExplorer::ProjectManager::startupProject());
|
||||||
|
});
|
||||||
|
|
||||||
|
Core::Command *cmd2 = Core::ActionManager::registerAction(rccAction,
|
||||||
|
"QmlProject.CreateRCCResource");
|
||||||
|
QObject::connect(rccAction, &QAction::triggered, []() {
|
||||||
|
auto project = ProjectExplorer::ProjectManager::startupProject();
|
||||||
|
QTC_ASSERT(project, return);
|
||||||
|
const FilePath projectPath = project->projectFilePath().parentDir();
|
||||||
|
const FilePath qmlrcFilePath = Core::DocumentManager::getSaveFileNameWithExtension(
|
||||||
|
Tr::tr("Save Project as Resource"),
|
||||||
|
projectPath.pathAppended(project->displayName() + ".qmlrc"),
|
||||||
|
"QML Resource File (*.qmlrc);;Resource File (*.rcc)");
|
||||||
|
|
||||||
|
if (qmlrcFilePath.toUrlishString().isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
QProgressDialog progress;
|
||||||
|
progress.setLabelText(Tr::tr("Generating deployable package. Please wait..."));
|
||||||
|
progress.setRange(0, 0);
|
||||||
|
progress.setWindowModality(Qt::WindowModal);
|
||||||
|
progress.setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
|
||||||
|
progress.setCancelButton(nullptr);
|
||||||
|
progress.show();
|
||||||
|
|
||||||
|
QFuture<bool> future = QtConcurrent::run([qmlrcFilePath]() {
|
||||||
|
ResourceGenerator resourceGenerator;
|
||||||
|
return resourceGenerator.createQmlrcWithPath(qmlrcFilePath);
|
||||||
|
});
|
||||||
|
|
||||||
|
while (!future.isFinished())
|
||||||
|
QCoreApplication::processEvents();
|
||||||
|
|
||||||
|
progress.close();
|
||||||
|
|
||||||
|
if (future.isCanceled()) {
|
||||||
|
qDebug() << "Operation canceled by user";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!future.result()) {
|
||||||
|
Core::MessageManager::writeDisrupting(Tr::tr("Failed to generate deployable package!"));
|
||||||
|
QMessageBox msgBox;
|
||||||
|
msgBox.setWindowTitle(Tr::tr("Error"));
|
||||||
|
msgBox.setText(Tr::tr("Failed to generate deployable package!\n\nPlease check "
|
||||||
|
"the output pane for more information."));
|
||||||
|
msgBox.exec();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMessageBox msgBox;
|
||||||
|
msgBox.setWindowTitle(Tr::tr("Success"));
|
||||||
|
msgBox.setText(Tr::tr("Successfully generated deployable package"));
|
||||||
|
msgBox.exec();
|
||||||
|
});
|
||||||
|
|
||||||
|
Core::ActionContainer *exportMenu = Core::ActionManager::actionContainer(
|
||||||
|
QmlProjectManager::Constants::EXPORT_MENU);
|
||||||
|
exportMenu->addAction(cmd, QmlProjectManager::Constants::G_EXPORT_GENERATE);
|
||||||
|
exportMenu->addAction(cmd2, QmlProjectManager::Constants::G_EXPORT_GENERATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<Utils::FilePath> ResourceGenerator::createQrc(const QString &projectName)
|
||||||
|
{
|
||||||
|
const ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject();
|
||||||
|
const FilePath projectPath = project->projectFilePath().parentDir();
|
||||||
|
const FilePath qrcFilePath = projectPath.pathAppended(projectName + ".qrc");
|
||||||
|
|
||||||
|
if (!createQrc(qrcFilePath))
|
||||||
|
return {};
|
||||||
|
|
||||||
|
return qrcFilePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ResourceGenerator::createQrc(const Utils::FilePath &qrcFilePath)
|
||||||
{
|
{
|
||||||
QFile qrcFile(qrcFilePath.toUrlishString());
|
QFile qrcFile(qrcFilePath.toUrlishString());
|
||||||
|
|
||||||
if (!qrcFile.open(QIODeviceBase::WriteOnly | QIODevice::Truncate))
|
if (!qrcFile.open(QIODeviceBase::WriteOnly | QIODevice::Truncate)) {
|
||||||
|
Core::MessageManager::writeDisrupting(
|
||||||
|
Tr::tr("Failed to open file to write QRC XML: %1").arg(qrcFilePath.toString()));
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
QXmlStreamWriter writer(&qrcFile);
|
QXmlStreamWriter writer(&qrcFile);
|
||||||
writer.setAutoFormatting(true);
|
writer.setAutoFormatting(true);
|
||||||
@@ -180,12 +217,74 @@ bool createQrcFile(const FilePath &qrcFilePath)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool createQmlrcFile(const FilePath &qmlrcFilePath)
|
void ResourceGenerator::createQmlrcAsyncWithName(const QString &projectName)
|
||||||
{
|
{
|
||||||
const FilePath tempQrcFile = qmlrcFilePath.parentDir().pathAppended("temp.qrc");
|
if (m_rccProcess.state() != QProcess::NotRunning) {
|
||||||
if (!createQrcFile(tempQrcFile))
|
Core::MessageManager::writeDisrupting(Tr::tr("Resource generator is already running."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject();
|
||||||
|
const FilePath projectPath = project->projectFilePath().parentDir();
|
||||||
|
const FilePath qmlrcFilePath = projectPath.pathAppended(projectName + ".qmlrc");
|
||||||
|
|
||||||
|
createQmlrcAsyncWithPath(qmlrcFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceGenerator::createQmlrcAsyncWithPath(const FilePath &qmlrcFilePath)
|
||||||
|
{
|
||||||
|
if (m_rccProcess.state() != QProcess::NotRunning) {
|
||||||
|
Core::MessageManager::writeDisrupting(Tr::tr("Resource generator is already running."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_qmlrcFilePath = qmlrcFilePath;
|
||||||
|
const FilePath tempQrcFile = m_qmlrcFilePath.parentDir().pathAppended("temp.qrc");
|
||||||
|
if (!createQrc(tempQrcFile))
|
||||||
|
return;
|
||||||
|
|
||||||
|
runRcc(qmlrcFilePath, tempQrcFile, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<Utils::FilePath> ResourceGenerator::createQmlrcWithName(const QString &projectName)
|
||||||
|
{
|
||||||
|
const ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject();
|
||||||
|
const FilePath projectPath = project->projectFilePath().parentDir();
|
||||||
|
const FilePath qmlrcFilePath = projectPath.pathAppended(projectName + ".qmlrc");
|
||||||
|
|
||||||
|
if (!createQmlrcWithPath(qmlrcFilePath))
|
||||||
|
return {};
|
||||||
|
|
||||||
|
return qmlrcFilePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ResourceGenerator::createQmlrcWithPath(const FilePath &qmlrcFilePath)
|
||||||
|
{
|
||||||
|
if (m_rccProcess.state() != QProcess::NotRunning) {
|
||||||
|
Core::MessageManager::writeDisrupting(Tr::tr("Resource generator is already running."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_qmlrcFilePath = qmlrcFilePath;
|
||||||
|
const FilePath tempQrcFile = m_qmlrcFilePath.parentDir().pathAppended("temp.qrc");
|
||||||
|
if (!createQrc(tempQrcFile))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
bool retVal = true;
|
||||||
|
if (!runRcc(qmlrcFilePath, tempQrcFile)) {
|
||||||
|
retVal = false;
|
||||||
|
if (qmlrcFilePath.exists())
|
||||||
|
qmlrcFilePath.removeFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
tempQrcFile.removeFile();
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ResourceGenerator::runRcc(const FilePath &qmlrcFilePath,
|
||||||
|
const Utils::FilePath &qrcFilePath,
|
||||||
|
const bool runAsync)
|
||||||
|
{
|
||||||
const ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject();
|
const ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject();
|
||||||
const QtSupport::QtVersion *qtVersion = QtSupport::QtKitAspect::qtVersion(
|
const QtSupport::QtVersion *qtVersion = QtSupport::QtKitAspect::qtVersion(
|
||||||
project->activeTarget()->kit());
|
project->activeTarget()->kit());
|
||||||
@@ -193,8 +292,7 @@ bool createQmlrcFile(const FilePath &qmlrcFilePath)
|
|||||||
|
|
||||||
const FilePath rccBinary = qtVersion->rccFilePath();
|
const FilePath rccBinary = qtVersion->rccFilePath();
|
||||||
|
|
||||||
Utils::Process rccProcess;
|
m_rccProcess.setWorkingDirectory(project->projectDirectory());
|
||||||
rccProcess.setWorkingDirectory(project->projectDirectory());
|
|
||||||
|
|
||||||
const QStringList arguments = {"--binary",
|
const QStringList arguments = {"--binary",
|
||||||
"--no-zstd",
|
"--no-zstd",
|
||||||
@@ -204,46 +302,36 @@ bool createQmlrcFile(const FilePath &qmlrcFilePath)
|
|||||||
"30",
|
"30",
|
||||||
"--output",
|
"--output",
|
||||||
qmlrcFilePath.toUrlishString(),
|
qmlrcFilePath.toUrlishString(),
|
||||||
tempQrcFile.toUrlishString()};
|
qrcFilePath.toUrlishString()};
|
||||||
|
|
||||||
rccProcess.setCommand({rccBinary, arguments});
|
m_rccProcess.setCommand({rccBinary, arguments});
|
||||||
rccProcess.start();
|
m_rccProcess.start();
|
||||||
if (!rccProcess.waitForStarted()) {
|
if (!m_rccProcess.waitForStarted()) {
|
||||||
Core::MessageManager::writeDisrupting(
|
Core::MessageManager::writeDisrupting(
|
||||||
Tr::tr("QmlDesigner::GenerateResource", "Unable to generate resource file: %1")
|
Tr::tr("QmlDesigner::GenerateResource", "Unable to generate resource file: %1")
|
||||||
.arg(qmlrcFilePath.toUrlishString()));
|
.arg(qmlrcFilePath.toUrlishString()));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray stdOut;
|
if (!runAsync) {
|
||||||
QByteArray stdErr;
|
QByteArray stdOut;
|
||||||
if (!rccProcess.readDataFromProcess(&stdOut, &stdErr)) {
|
QByteArray stdErr;
|
||||||
rccProcess.stop();
|
if (!m_rccProcess.readDataFromProcess(&stdOut, &stdErr)) {
|
||||||
Core::MessageManager::writeDisrupting(
|
m_rccProcess.stop();
|
||||||
Tr::tr("QmlDesigner::GenerateResource", "A timeout occurred running \"%1\".")
|
Core::MessageManager::writeDisrupting(Tr::tr("A timeout occurred running \"%1\".")
|
||||||
.arg(rccProcess.commandLine().toUserOutput()));
|
.arg(m_rccProcess.commandLine().toUserOutput()));
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_rccProcess.exitStatus() != QProcess::NormalExit || m_rccProcess.exitCode() != 0)
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!stdOut.trimmed().isEmpty())
|
|
||||||
Core::MessageManager::writeFlashing(QString::fromLocal8Bit(stdOut));
|
|
||||||
|
|
||||||
if (!stdErr.trimmed().isEmpty())
|
|
||||||
Core::MessageManager::writeFlashing(QString::fromLocal8Bit(stdErr));
|
|
||||||
|
|
||||||
if (rccProcess.exitStatus() != QProcess::NormalExit) {
|
|
||||||
Core::MessageManager::writeDisrupting(Tr::tr("QmlDesigner::GenerateResource", "\"%1\" crashed.")
|
|
||||||
.arg(rccProcess.commandLine().toUserOutput()));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (rccProcess.exitCode() != 0) {
|
|
||||||
Core::MessageManager::writeDisrupting(
|
|
||||||
Tr::tr("QmlDesigner::GenerateResource", "\"%1\" failed (exit code %2).")
|
|
||||||
.arg(rccProcess.commandLine().toUserOutput())
|
|
||||||
.arg(rccProcess.exitCode()));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace QmlDesigner::ResourceGenerator
|
void ResourceGenerator::cancel()
|
||||||
|
{
|
||||||
|
m_rccProcess.kill();
|
||||||
|
}
|
||||||
|
} // namespace QmlDesigner
|
||||||
|
@@ -3,15 +3,41 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <utils/filepath.h>
|
|
||||||
|
|
||||||
#include <qmldesignercomponents_global.h>
|
#include <qmldesignercomponents_global.h>
|
||||||
|
#include <utils/filepath.h>
|
||||||
|
#include <utils/qtcprocess.h>
|
||||||
|
|
||||||
namespace QmlDesigner::ResourceGenerator {
|
namespace QmlDesigner {
|
||||||
|
class ResourceGenerator : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
ResourceGenerator(QObject *parent = nullptr);
|
||||||
|
static void generateMenuEntry(QObject *parent);
|
||||||
|
|
||||||
QMLDESIGNERCOMPONENTS_EXPORT void generateMenuEntry(QObject *parent);
|
Q_INVOKABLE bool createQrc(const Utils::FilePath &qrcFilePath);
|
||||||
QMLDESIGNERCOMPONENTS_EXPORT QStringList getProjectFileList();
|
Q_INVOKABLE std::optional<Utils::FilePath> createQrc(const QString &projectName = "share");
|
||||||
QMLDESIGNERCOMPONENTS_EXPORT bool createQrcFile(const Utils::FilePath &qrcFilePath);
|
|
||||||
QMLDESIGNERCOMPONENTS_EXPORT bool createQmlrcFile(const Utils::FilePath &qmlrcFilePath);
|
|
||||||
|
|
||||||
} // namespace QmlDesigner::ResourceGenerator
|
Q_INVOKABLE bool createQmlrcWithPath(const Utils::FilePath &qmlrcFilePath);
|
||||||
|
Q_INVOKABLE std::optional<Utils::FilePath> createQmlrcWithName(
|
||||||
|
const QString &projectName = "share");
|
||||||
|
Q_INVOKABLE void createQmlrcAsyncWithPath(const Utils::FilePath &qmlrcFilePath);
|
||||||
|
Q_INVOKABLE void createQmlrcAsyncWithName(const QString &projectName = "share");
|
||||||
|
|
||||||
|
Q_INVOKABLE void cancel();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Utils::Process m_rccProcess;
|
||||||
|
Utils::FilePath m_qmlrcFilePath;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool runRcc(const Utils::FilePath &qmlrcFilePath,
|
||||||
|
const Utils::FilePath &qrcFilePath,
|
||||||
|
const bool runAsync = false);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void errorOccurred(const QString &error);
|
||||||
|
void qmlrcCreated(const Utils::FilePath &filePath);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace QmlDesigner
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
#include "collectionmodel.h"
|
#include "collectionmodel.h"
|
||||||
|
#include <designsystem/dsstore.h>
|
||||||
#include <designsystem/dsthemegroup.h>
|
#include <designsystem/dsthemegroup.h>
|
||||||
#include <designsystem/dsthememanager.h>
|
#include <designsystem/dsthememanager.h>
|
||||||
|
|
||||||
@@ -9,12 +10,28 @@
|
|||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
CollectionModel::CollectionModel(DSThemeManager *collection)
|
CollectionModel::CollectionModel(DSThemeManager *collection, const DSStore *store)
|
||||||
: m_collection(collection)
|
: m_collection(collection)
|
||||||
|
, m_store(store)
|
||||||
{
|
{
|
||||||
updateCache();
|
updateCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QStringList CollectionModel::themeNameList() const
|
||||||
|
{
|
||||||
|
QStringList themeNames(m_themeIdList.size());
|
||||||
|
std::transform(m_themeIdList.begin(), m_themeIdList.end(), themeNames.begin(), [this](ThemeId id) {
|
||||||
|
return QString::fromLatin1(m_collection->themeName(id));
|
||||||
|
});
|
||||||
|
return themeNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CollectionModel::setActiveTheme(const QString &themeName)
|
||||||
|
{
|
||||||
|
if (const auto themeId = m_collection->themeId(themeName.toLatin1()))
|
||||||
|
m_collection->setActiveTheme(*themeId);
|
||||||
|
}
|
||||||
|
|
||||||
int CollectionModel::columnCount(const QModelIndex &parent) const
|
int CollectionModel::columnCount(const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
return parent.isValid() ? 0 : static_cast<int>(m_collection->themeCount());
|
return parent.isValid() ? 0 : static_cast<int>(m_collection->themeCount());
|
||||||
@@ -32,13 +49,23 @@ QVariant CollectionModel::data(const QModelIndex &index, int role) const
|
|||||||
if (!property)
|
if (!property)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
|
const QVariant propertyValue = property->value.toString();
|
||||||
|
const QVariant displayValue = property->isBinding
|
||||||
|
? m_store->resolvedDSBinding(propertyValue.toString()).value
|
||||||
|
: property->value;
|
||||||
|
|
||||||
switch (role) {
|
switch (role) {
|
||||||
case Qt::DisplayRole:
|
case Qt::DisplayRole:
|
||||||
return property->value.toString();
|
case Roles::ResolvedValueRole:
|
||||||
case static_cast<int>(Roles::GroupRole):
|
return displayValue;
|
||||||
|
case Roles::PropertyValueRole:
|
||||||
|
return propertyValue;
|
||||||
|
case Roles::GroupRole:
|
||||||
return QVariant::fromValue<GroupType>(groupType);
|
return QVariant::fromValue<GroupType>(groupType);
|
||||||
case static_cast<int>(Roles::BindingRole):
|
case Roles::BindingRole:
|
||||||
return property->isBinding;
|
return property->isBinding;
|
||||||
|
case Roles::ActiveThemeRole:
|
||||||
|
return m_collection->activeTheme() == themeId;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
@@ -64,18 +91,26 @@ int CollectionModel::rowCount(const QModelIndex &parent) const
|
|||||||
|
|
||||||
QVariant CollectionModel::headerData(int section, Qt::Orientation orientation, int role) const
|
QVariant CollectionModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||||
{
|
{
|
||||||
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
|
if (orientation == Qt::Horizontal) {
|
||||||
return QString::fromLatin1(m_collection->themeName(findThemeId(section)));
|
auto themeId = findThemeId(section);
|
||||||
|
switch (role) {
|
||||||
|
case Qt::DisplayRole:
|
||||||
|
return QString::fromLatin1(m_collection->themeName(themeId));
|
||||||
|
case Roles::ActiveThemeRole:
|
||||||
|
return m_collection->activeTheme() == themeId;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (orientation == Qt::Vertical) {
|
if (orientation == Qt::Vertical) {
|
||||||
if (auto propInfo = findPropertyName(section)) {
|
if (auto propInfo = findPropertyName(section)) {
|
||||||
if (role == Qt::DisplayRole)
|
if (role == Qt::DisplayRole)
|
||||||
return QString::fromLatin1(propInfo->second);
|
return QString::fromLatin1(propInfo->second);
|
||||||
if (role == static_cast<int>(Roles::GroupRole))
|
if (role == Roles::GroupRole)
|
||||||
return QVariant::fromValue<GroupType>(propInfo->first);
|
return QVariant::fromValue<GroupType>(propInfo->first);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,8 +122,11 @@ Qt::ItemFlags CollectionModel::flags(const QModelIndex &index) const
|
|||||||
QHash<int, QByteArray> CollectionModel::roleNames() const
|
QHash<int, QByteArray> CollectionModel::roleNames() const
|
||||||
{
|
{
|
||||||
auto roles = QAbstractItemModel::roleNames();
|
auto roles = QAbstractItemModel::roleNames();
|
||||||
roles.insert(static_cast<int>(Roles::GroupRole), "group");
|
roles.insert(Roles::ResolvedValueRole, "resolvedValue");
|
||||||
roles.insert(static_cast<int>(Roles::BindingRole), "isBinding");
|
roles.insert(Roles::GroupRole, "group");
|
||||||
|
roles.insert(Roles::BindingRole, "isBinding");
|
||||||
|
roles.insert(Roles::ActiveThemeRole, "isActive");
|
||||||
|
roles.insert(Roles::PropertyValueRole, "propertyValue");
|
||||||
return roles;
|
return roles;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,6 +144,7 @@ bool CollectionModel::insertColumns([[maybe_unused]] int column, int count, cons
|
|||||||
beginResetModel();
|
beginResetModel();
|
||||||
updateCache();
|
updateCache();
|
||||||
endResetModel();
|
endResetModel();
|
||||||
|
emit themeNameChanged();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -122,6 +161,7 @@ bool CollectionModel::removeColumns(int column, int count, const QModelIndex &pa
|
|||||||
|
|
||||||
updateCache();
|
updateCache();
|
||||||
endResetModel();
|
endResetModel();
|
||||||
|
emit themeNameChanged();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,25 +230,26 @@ bool CollectionModel::setHeaderData(int section,
|
|||||||
const QVariant &value,
|
const QVariant &value,
|
||||||
int role)
|
int role)
|
||||||
{
|
{
|
||||||
if (role != Qt::EditRole)
|
if (role != Qt::EditRole || section < 0
|
||||||
return false;
|
|| (orientation == Qt::Horizontal && section >= columnCount())
|
||||||
|
|
||||||
if (section < 0 || (orientation == Qt::Horizontal && section >= columnCount())
|
|
||||||
|| (orientation == Qt::Vertical && section >= rowCount())) {
|
|| (orientation == Qt::Vertical && section >= rowCount())) {
|
||||||
return false; // Out of bounds
|
return false; // Out of bounds
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto &newName = value.toString().toUtf8();
|
const auto &newName = value.toString().toUtf8();
|
||||||
bool success = false;
|
bool success = false;
|
||||||
if (orientation == Qt::Horizontal) {
|
if (orientation == Qt::Vertical) {
|
||||||
// Theme
|
|
||||||
success = m_collection->renameTheme(findThemeId(section), newName);
|
|
||||||
} else {
|
|
||||||
// Property Name
|
// Property Name
|
||||||
if (auto propInfo = findPropertyName(section)) {
|
if (auto propInfo = findPropertyName(section)) {
|
||||||
auto [groupType, propName] = *propInfo;
|
auto [groupType, propName] = *propInfo;
|
||||||
success = m_collection->renameProperty(groupType, propName, newName);
|
success = m_collection->renameProperty(groupType, propName, newName);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Theme
|
||||||
|
const auto themeId = findThemeId(section);
|
||||||
|
success = m_collection->renameTheme(themeId, newName);
|
||||||
|
if (success)
|
||||||
|
emit themeNameChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
|
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
class DSThemeManager;
|
class DSThemeManager;
|
||||||
|
class DSStore;
|
||||||
using PropInfo = std::pair<GroupType, PropertyName>;
|
using PropInfo = std::pair<GroupType, PropertyName>;
|
||||||
|
|
||||||
class CollectionModel : public QAbstractItemModel
|
class CollectionModel : public QAbstractItemModel
|
||||||
@@ -17,9 +18,20 @@ class CollectionModel : public QAbstractItemModel
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum class Roles { GroupRole = Qt::UserRole + 1, BindingRole };
|
enum Roles {
|
||||||
|
GroupRole = Qt::UserRole + 1,
|
||||||
|
BindingRole,
|
||||||
|
ActiveThemeRole,
|
||||||
|
ResolvedValueRole,
|
||||||
|
PropertyValueRole
|
||||||
|
};
|
||||||
|
|
||||||
CollectionModel(DSThemeManager *collection);
|
Q_PROPERTY(QStringList themeNames READ themeNameList NOTIFY themeNameChanged FINAL)
|
||||||
|
|
||||||
|
CollectionModel(DSThemeManager *collection, const DSStore *store);
|
||||||
|
|
||||||
|
QStringList themeNameList() const;
|
||||||
|
Q_INVOKABLE void setActiveTheme(const QString &themeName);
|
||||||
|
|
||||||
// QAbstractItemModel Interface
|
// QAbstractItemModel Interface
|
||||||
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
@@ -52,12 +64,16 @@ public:
|
|||||||
const QVariant &value,
|
const QVariant &value,
|
||||||
int role = Qt::EditRole) override;
|
int role = Qt::EditRole) override;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void themeNameChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ThemeId findThemeId(int column) const;
|
ThemeId findThemeId(int column) const;
|
||||||
std::optional<PropInfo> findPropertyName(int row) const;
|
std::optional<PropInfo> findPropertyName(int row) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DSThemeManager *m_collection = nullptr;
|
DSThemeManager *m_collection = nullptr;
|
||||||
|
const DSStore *m_store;
|
||||||
|
|
||||||
// cache
|
// cache
|
||||||
std::vector<ThemeId> m_themeIdList;
|
std::vector<ThemeId> m_themeIdList;
|
||||||
|
@@ -74,7 +74,8 @@ QStringList DesignSystemInterface::collections() const
|
|||||||
CollectionModel *DesignSystemInterface::createModel(const QString &typeName, DSThemeManager *collection)
|
CollectionModel *DesignSystemInterface::createModel(const QString &typeName, DSThemeManager *collection)
|
||||||
{
|
{
|
||||||
auto [newItr, success] = m_models.try_emplace(typeName,
|
auto [newItr, success] = m_models.try_emplace(typeName,
|
||||||
std::make_unique<CollectionModel>(collection));
|
std::make_unique<CollectionModel>(collection,
|
||||||
|
m_store));
|
||||||
if (success) {
|
if (success) {
|
||||||
// Otherwise the model will be deleted by the QML engine.
|
// Otherwise the model will be deleted by the QML engine.
|
||||||
QQmlEngine::setObjectOwnership(newItr->second.get(), QQmlEngine::CppOwnership);
|
QQmlEngine::setObjectOwnership(newItr->second.get(), QQmlEngine::CppOwnership);
|
||||||
|
@@ -154,7 +154,7 @@ DVConnector::DVConnector(QObject *parent)
|
|||||||
});
|
});
|
||||||
|
|
||||||
connect(&m_resourceGenerator,
|
connect(&m_resourceGenerator,
|
||||||
&ResourceGeneratorProxy::resourceFileCreated,
|
&ResourceGenerator::qmlrcCreated,
|
||||||
this,
|
this,
|
||||||
[this](const std::optional<Utils::FilePath> &resourcePath) {
|
[this](const std::optional<Utils::FilePath> &resourcePath) {
|
||||||
emit projectIsUploading();
|
emit projectIsUploading();
|
||||||
@@ -162,12 +162,10 @@ DVConnector::DVConnector(QObject *parent)
|
|||||||
uploadProject(projectName, resourcePath->toString());
|
uploadProject(projectName, resourcePath->toString());
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(&m_resourceGenerator,
|
connect(&m_resourceGenerator, &ResourceGenerator::errorOccurred, [this](const QString &errorString) {
|
||||||
&ResourceGeneratorProxy::errorOccurred,
|
qCWarning(deploymentPluginLog) << "Error occurred while packing the project";
|
||||||
[this](const QString &errorString) {
|
emit projectPackingFailed(errorString);
|
||||||
qCWarning(deploymentPluginLog) << "Error occurred while packing the project";
|
});
|
||||||
emit projectPackingFailed(errorString);
|
|
||||||
});
|
|
||||||
|
|
||||||
fetchUserInfo();
|
fetchUserInfo();
|
||||||
}
|
}
|
||||||
@@ -220,7 +218,7 @@ void DVConnector::projectList()
|
|||||||
void DVConnector::uploadCurrentProject()
|
void DVConnector::uploadCurrentProject()
|
||||||
{
|
{
|
||||||
QString projectName = ProjectExplorer::ProjectManager::startupProject()->displayName();
|
QString projectName = ProjectExplorer::ProjectManager::startupProject()->displayName();
|
||||||
m_resourceGenerator.createResourceFileAsync(projectName);
|
m_resourceGenerator.createQmlrcAsyncWithName(projectName);
|
||||||
emit projectIsPacking();
|
emit projectIsPacking();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -9,7 +9,7 @@
|
|||||||
#include <QWebEngineProfile>
|
#include <QWebEngineProfile>
|
||||||
#include <QWebEngineView>
|
#include <QWebEngineView>
|
||||||
|
|
||||||
#include "resourcegeneratorproxy.h"
|
#include <qmldesigner/components/componentcore/resourcegenerator.h>
|
||||||
|
|
||||||
namespace QmlDesigner::DesignViewer {
|
namespace QmlDesigner::DesignViewer {
|
||||||
|
|
||||||
@@ -99,7 +99,7 @@ private:
|
|||||||
QByteArray m_userInfo;
|
QByteArray m_userInfo;
|
||||||
|
|
||||||
// other internals
|
// other internals
|
||||||
ResourceGeneratorProxy m_resourceGenerator;
|
ResourceGenerator m_resourceGenerator;
|
||||||
|
|
||||||
struct ReplyEvaluatorData
|
struct ReplyEvaluatorData
|
||||||
{
|
{
|
||||||
|
@@ -1,65 +0,0 @@
|
|||||||
// Copyright (C) 2024 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
|
||||||
|
|
||||||
#include "resourcegeneratorproxy.h"
|
|
||||||
|
|
||||||
#include <QStandardPaths>
|
|
||||||
#include <QTemporaryFile>
|
|
||||||
#include <QXmlStreamReader>
|
|
||||||
#include <QtConcurrent>
|
|
||||||
|
|
||||||
#include <qtsupport/baseqtversion.h>
|
|
||||||
#include <qtsupport/qtkitaspect.h>
|
|
||||||
|
|
||||||
#include <coreplugin/messagemanager.h>
|
|
||||||
|
|
||||||
#include <projectexplorer/project.h>
|
|
||||||
#include <projectexplorer/projectexplorerconstants.h>
|
|
||||||
#include <projectexplorer/projectmanager.h>
|
|
||||||
#include <projectexplorer/target.h>
|
|
||||||
|
|
||||||
#include <utils/qtcprocess.h>
|
|
||||||
|
|
||||||
#include <qmldesigner/components/componentcore/resourcegenerator.h>
|
|
||||||
|
|
||||||
namespace QmlDesigner::DesignViewer {
|
|
||||||
|
|
||||||
ResourceGeneratorProxy::~ResourceGeneratorProxy()
|
|
||||||
{
|
|
||||||
if (m_future.isRunning()) {
|
|
||||||
m_future.cancel();
|
|
||||||
m_future.waitForFinished();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResourceGeneratorProxy::createResourceFileAsync(const QString &projectName)
|
|
||||||
{
|
|
||||||
m_future = QtConcurrent::run([&]() {
|
|
||||||
const std::optional<Utils::FilePath> filePath = createResourceFileSync(projectName);
|
|
||||||
|
|
||||||
if (!filePath || filePath->isEmpty()) {
|
|
||||||
emit errorOccurred("Failed to create resource file");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
emit resourceFileCreated(filePath.value());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<Utils::FilePath> ResourceGeneratorProxy::createResourceFileSync(const QString &projectName)
|
|
||||||
{
|
|
||||||
const auto project = ProjectExplorer::ProjectManager::startupProject();
|
|
||||||
std::optional<Utils::FilePath> resourcePath = project->projectDirectory().pathAppended(
|
|
||||||
projectName + ".qmlrc");
|
|
||||||
|
|
||||||
const bool retVal = ResourceGenerator::createQmlrcFile(resourcePath.value());
|
|
||||||
|
|
||||||
if (!retVal || resourcePath->fileSize() == 0) {
|
|
||||||
Core::MessageManager::writeDisrupting(tr("Failed to create resource file"));
|
|
||||||
resourcePath.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
return resourcePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace QmlDesigner::DesignViewer
|
|
@@ -1,28 +0,0 @@
|
|||||||
// Copyright (C) 2024 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <utils/filepath.h>
|
|
||||||
|
|
||||||
#include <QFuture>
|
|
||||||
|
|
||||||
namespace QmlDesigner::DesignViewer {
|
|
||||||
|
|
||||||
class ResourceGeneratorProxy : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
~ResourceGeneratorProxy();
|
|
||||||
Q_INVOKABLE void createResourceFileAsync(const QString &projectName = "share");
|
|
||||||
Q_INVOKABLE std::optional<Utils::FilePath> createResourceFileSync(const QString &projectName = "share");
|
|
||||||
|
|
||||||
private:
|
|
||||||
QFuture<void> m_future;
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void errorOccurred(const QString &error);
|
|
||||||
void resourceFileCreated(const Utils::FilePath &filePath);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace QmlDesigner::DesignViewer
|
|
@@ -5,7 +5,8 @@
|
|||||||
|
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QLatin1String>
|
#include <QLatin1String>
|
||||||
#include <QThreadPool>
|
|
||||||
|
#include "websocketmock.h"
|
||||||
|
|
||||||
namespace QmlDesigner::DeviceShare {
|
namespace QmlDesigner::DeviceShare {
|
||||||
|
|
||||||
@@ -20,17 +21,24 @@ constexpr auto stopRunningProject = "stopRunningProject"_L1;
|
|||||||
namespace PackageFromDevice {
|
namespace PackageFromDevice {
|
||||||
using namespace Qt::Literals;
|
using namespace Qt::Literals;
|
||||||
constexpr auto deviceInfo = "deviceInfo"_L1;
|
constexpr auto deviceInfo = "deviceInfo"_L1;
|
||||||
|
constexpr auto projectReceivingProgress = "projectReceivingProgress"_L1;
|
||||||
|
constexpr auto projectStarting = "projectStarting"_L1;
|
||||||
constexpr auto projectRunning = "projectRunning"_L1;
|
constexpr auto projectRunning = "projectRunning"_L1;
|
||||||
constexpr auto projectStopped = "projectStopped"_L1;
|
constexpr auto projectStopped = "projectStopped"_L1;
|
||||||
constexpr auto projectLogs = "projectLogs"_L1;
|
constexpr auto projectLogs = "projectLogs"_L1;
|
||||||
}; // namespace PackageFromDevice
|
}; // namespace PackageFromDevice
|
||||||
|
|
||||||
Device::Device(const DeviceInfo &deviceInfo, const DeviceSettings &deviceSettings, QObject *parent)
|
Device::Device(const QString designStudioId,
|
||||||
|
const DeviceInfo &deviceInfo,
|
||||||
|
const DeviceSettings &deviceSettings,
|
||||||
|
QObject *parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
, m_deviceInfo(deviceInfo)
|
, m_deviceInfo(deviceInfo)
|
||||||
, m_deviceSettings(deviceSettings)
|
, m_deviceSettings(deviceSettings)
|
||||||
, m_socket(nullptr)
|
, m_socket(nullptr)
|
||||||
, m_socketWasConnected(false)
|
, m_socketWasConnected(false)
|
||||||
|
, m_socketManuallyClosed(false)
|
||||||
|
, m_designStudioId(designStudioId)
|
||||||
{
|
{
|
||||||
qCDebug(deviceSharePluginLog) << "initial device info:" << m_deviceInfo;
|
qCDebug(deviceSharePluginLog) << "initial device info:" << m_deviceInfo;
|
||||||
|
|
||||||
@@ -38,40 +46,33 @@ Device::Device(const DeviceInfo &deviceInfo, const DeviceSettings &deviceSetting
|
|||||||
m_socket->setOutgoingFrameSize(128000);
|
m_socket->setOutgoingFrameSize(128000);
|
||||||
connect(m_socket.data(), &QWebSocket::textMessageReceived, this, &Device::processTextMessage);
|
connect(m_socket.data(), &QWebSocket::textMessageReceived, this, &Device::processTextMessage);
|
||||||
connect(m_socket.data(), &QWebSocket::disconnected, this, [this]() {
|
connect(m_socket.data(), &QWebSocket::disconnected, this, [this]() {
|
||||||
m_reconnectTimer.start();
|
if (m_socketManuallyClosed) {
|
||||||
|
m_socketManuallyClosed = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_reconnectTimer.start(m_reconnectTimeout);
|
||||||
if (!m_socketWasConnected)
|
if (!m_socketWasConnected)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_socketWasConnected = false;
|
m_socketWasConnected = false;
|
||||||
m_pingTimer.stop();
|
stopPingPong();
|
||||||
m_pongTimer.stop();
|
|
||||||
emit disconnected(m_deviceSettings.deviceId());
|
emit disconnected(m_deviceSettings.deviceId());
|
||||||
});
|
});
|
||||||
connect(m_socket.data(), &QWebSocket::connected, this, [this]() {
|
connect(m_socket.data(), &QWebSocket::connected, this, [this]() {
|
||||||
m_socketWasConnected = true;
|
m_socketWasConnected = true;
|
||||||
m_reconnectTimer.stop();
|
m_reconnectTimer.stop();
|
||||||
m_pingTimer.start();
|
restartPingPong();
|
||||||
sendDesignStudioReady(m_deviceSettings.deviceId());
|
sendDesignStudioReady();
|
||||||
emit connected(m_deviceSettings.deviceId());
|
emit connected(m_deviceSettings.deviceId());
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(m_socket.data(), &QWebSocket::bytesWritten, this, [this](qint64 bytes) {
|
|
||||||
if (m_lastProjectSize == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_lastProjectSentSize += bytes;
|
|
||||||
const float percentage = ((float) m_lastProjectSentSize * 100.0) / (float) m_lastProjectSize;
|
|
||||||
|
|
||||||
if (percentage != 100.0)
|
|
||||||
emit projectSendingProgress(m_deviceSettings.deviceId(), percentage);
|
|
||||||
|
|
||||||
if (m_lastProjectSentSize >= m_lastProjectSize)
|
|
||||||
m_lastProjectSize = 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
m_reconnectTimer.setSingleShot(true);
|
m_reconnectTimer.setSingleShot(true);
|
||||||
m_reconnectTimer.setInterval(m_reconnectTimeout);
|
connect(&m_reconnectTimer, &QTimer::timeout, this, [this]() { reconnect(); });
|
||||||
connect(&m_reconnectTimer, &QTimer::timeout, this, &Device::reconnect);
|
|
||||||
|
m_sendTimer.setSingleShot(true);
|
||||||
|
m_sendTimer.setInterval(10);
|
||||||
|
connect(&m_sendTimer, &QTimer::timeout, this, &Device::sendProjectDataInternal, Qt::UniqueConnection);
|
||||||
|
|
||||||
initPingPong();
|
initPingPong();
|
||||||
reconnect();
|
reconnect();
|
||||||
@@ -114,10 +115,23 @@ void Device::initPingPong()
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::reconnect()
|
void Device::stopPingPong()
|
||||||
{
|
{
|
||||||
if (m_socket->state() == QAbstractSocket::ConnectedState)
|
m_pingTimer.stop();
|
||||||
m_socket->close();
|
m_pongTimer.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Device::restartPingPong()
|
||||||
|
{
|
||||||
|
m_pingTimer.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Device::reconnect(const QString &closeMessage)
|
||||||
|
{
|
||||||
|
if (m_socket && m_socket->isValid() && m_socket->state() == QAbstractSocket::ConnectedState) {
|
||||||
|
m_socket->close(QWebSocketProtocol::CloseCodeNormal, closeMessage);
|
||||||
|
m_socketManuallyClosed = true;
|
||||||
|
}
|
||||||
|
|
||||||
QUrl url(QStringLiteral("ws://%1:%2").arg(m_deviceSettings.ipAddress()).arg(40000));
|
QUrl url(QStringLiteral("ws://%1:%2").arg(m_deviceSettings.ipAddress()).arg(40000));
|
||||||
m_socket->open(url);
|
m_socket->open(url);
|
||||||
@@ -146,19 +160,63 @@ void Device::setDeviceSettings(const DeviceSettings &deviceSettings)
|
|||||||
reconnect();
|
reconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Device::sendDesignStudioReady(const QString &uuid)
|
bool Device::sendDesignStudioReady()
|
||||||
{
|
{
|
||||||
return sendTextMessage(PackageToDevice::designStudioReady, uuid);
|
QJsonObject data;
|
||||||
|
data["designStudioID"] = m_designStudioId;
|
||||||
|
data["commVersion"] = 1;
|
||||||
|
return sendTextMessage(PackageToDevice::designStudioReady, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Device::sendProjectNotification(const int &projectSize)
|
bool Device::sendProjectNotification(const int &projectSize, const QString &qtVersion)
|
||||||
{
|
{
|
||||||
return sendTextMessage(PackageToDevice::projectData, projectSize);
|
QJsonObject projectInfo;
|
||||||
|
projectInfo["projectSize"] = projectSize;
|
||||||
|
projectInfo["qtVersion"] = qtVersion;
|
||||||
|
|
||||||
|
return sendTextMessage(PackageToDevice::projectData, projectInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Device::sendProjectData(const QByteArray &data)
|
bool Device::sendProjectData(const QByteArray &data, const QString &qtVersion)
|
||||||
{
|
{
|
||||||
return sendBinaryMessage(data);
|
if (!isConnected())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
sendProjectNotification(data.size(), qtVersion);
|
||||||
|
|
||||||
|
m_sendProject = true;
|
||||||
|
m_projectData = data;
|
||||||
|
m_totalSentSize = 0;
|
||||||
|
m_lastSentProgress = 0;
|
||||||
|
|
||||||
|
m_sendTimer.start();
|
||||||
|
stopPingPong();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Device::sendProjectDataInternal()
|
||||||
|
{
|
||||||
|
if (!isConnected())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!m_sendProject) {
|
||||||
|
sendTextMessage(PackageToDevice::stopRunningProject);
|
||||||
|
restartPingPong();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int chunkSize = 1024 * 50; // 50KB
|
||||||
|
|
||||||
|
const QByteArray chunk = m_projectData.mid(m_totalSentSize, chunkSize);
|
||||||
|
m_socket->sendBinaryMessage(chunk);
|
||||||
|
m_socket->flush();
|
||||||
|
|
||||||
|
m_totalSentSize += chunk.size();
|
||||||
|
if (m_totalSentSize < m_projectData.size())
|
||||||
|
m_sendTimer.start();
|
||||||
|
else
|
||||||
|
restartPingPong();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Device::sendProjectStopped()
|
bool Device::sendProjectStopped()
|
||||||
@@ -186,16 +244,12 @@ bool Device::sendTextMessage(const QLatin1String &dataType, const QJsonValue &da
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Device::sendBinaryMessage(const QByteArray &data)
|
void Device::abortProjectTransmission()
|
||||||
{
|
{
|
||||||
if (!isConnected())
|
if (!isConnected())
|
||||||
return false;
|
return;
|
||||||
|
|
||||||
m_lastProjectSize = data.size();
|
m_sendProject = false;
|
||||||
m_lastProjectSentSize = 0;
|
|
||||||
sendProjectNotification(m_lastProjectSize);
|
|
||||||
m_socket->sendBinaryMessage(data);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::processTextMessage(const QString &data)
|
void Device::processTextMessage(const QString &data)
|
||||||
@@ -213,7 +267,7 @@ void Device::processTextMessage(const QString &data)
|
|||||||
if (dataType == PackageFromDevice::deviceInfo) {
|
if (dataType == PackageFromDevice::deviceInfo) {
|
||||||
QJsonObject deviceInfo = jsonObj.value("data").toObject();
|
QJsonObject deviceInfo = jsonObj.value("data").toObject();
|
||||||
m_deviceInfo.setJsonObject(deviceInfo);
|
m_deviceInfo.setJsonObject(deviceInfo);
|
||||||
emit deviceInfoReady(m_deviceSettings.ipAddress(), m_deviceSettings.deviceId());
|
emit deviceInfoReady(m_deviceSettings.deviceId());
|
||||||
} else if (dataType == PackageFromDevice::projectRunning) {
|
} else if (dataType == PackageFromDevice::projectRunning) {
|
||||||
qCDebug(deviceSharePluginLog) << "Project started on device" << m_deviceSettings.deviceId();
|
qCDebug(deviceSharePluginLog) << "Project started on device" << m_deviceSettings.deviceId();
|
||||||
emit projectStarted(m_deviceSettings.deviceId());
|
emit projectStarted(m_deviceSettings.deviceId());
|
||||||
@@ -221,7 +275,15 @@ void Device::processTextMessage(const QString &data)
|
|||||||
qCDebug(deviceSharePluginLog) << "Project stopped on device" << m_deviceSettings.deviceId();
|
qCDebug(deviceSharePluginLog) << "Project stopped on device" << m_deviceSettings.deviceId();
|
||||||
emit projectStopped(m_deviceSettings.deviceId());
|
emit projectStopped(m_deviceSettings.deviceId());
|
||||||
} else if (dataType == PackageFromDevice::projectLogs) {
|
} else if (dataType == PackageFromDevice::projectLogs) {
|
||||||
emit projectLogsReceived(m_deviceSettings.deviceId(), jsonObj.value("data").toString());
|
const QString logs = jsonObj.value("data").toString();
|
||||||
|
qCDebug(deviceSharePluginLog) << "Device Log:" << m_deviceSettings.deviceId() << logs;
|
||||||
|
emit projectLogsReceived(m_deviceSettings.deviceId(), logs);
|
||||||
|
} else if (dataType == PackageFromDevice::projectStarting) {
|
||||||
|
qCDebug(deviceSharePluginLog) << "Project starting on device" << m_deviceSettings.deviceId();
|
||||||
|
emit projectStarting(m_deviceSettings.deviceId());
|
||||||
|
} else if (dataType == PackageFromDevice::projectReceivingProgress) {
|
||||||
|
const int progress = jsonObj.value("data").toInt();
|
||||||
|
emit projectSendingProgress(m_deviceSettings.deviceId(), progress);
|
||||||
} else {
|
} else {
|
||||||
qCDebug(deviceSharePluginLog) << "Invalid JSON message:" << jsonObj;
|
qCDebug(deviceSharePluginLog) << "Invalid JSON message:" << jsonObj;
|
||||||
}
|
}
|
||||||
|
@@ -4,17 +4,20 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QWebSocket>
|
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
#include "deviceinfo.h"
|
#include "deviceinfo.h"
|
||||||
|
|
||||||
|
class QWebSocket;
|
||||||
namespace QmlDesigner::DeviceShare {
|
namespace QmlDesigner::DeviceShare {
|
||||||
|
|
||||||
class Device : public QObject
|
class Device : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
Device(const DeviceInfo &deviceInfo = {},
|
Device(const QString designStudioId,
|
||||||
|
const DeviceInfo &deviceInfo = {},
|
||||||
const DeviceSettings &deviceSettings = {},
|
const DeviceSettings &deviceSettings = {},
|
||||||
QObject *parent = nullptr);
|
QObject *parent = nullptr);
|
||||||
~Device();
|
~Device();
|
||||||
@@ -26,13 +29,13 @@ public:
|
|||||||
void setDeviceSettings(const DeviceSettings &deviceSettings);
|
void setDeviceSettings(const DeviceSettings &deviceSettings);
|
||||||
|
|
||||||
// device communication
|
// device communication
|
||||||
bool sendDesignStudioReady(const QString &uuid);
|
bool sendProjectData(const QByteArray &data, const QString &qtVersion);
|
||||||
bool sendProjectData(const QByteArray &data);
|
|
||||||
bool sendProjectStopped();
|
bool sendProjectStopped();
|
||||||
|
void abortProjectTransmission();
|
||||||
|
|
||||||
// socket
|
// socket
|
||||||
bool isConnected() const;
|
bool isConnected() const;
|
||||||
void reconnect();
|
void reconnect(const QString &closeMessage = QString());
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void processTextMessage(const QString &data);
|
void processTextMessage(const QString &data);
|
||||||
@@ -43,28 +46,39 @@ private:
|
|||||||
|
|
||||||
QScopedPointer<QWebSocket> m_socket;
|
QScopedPointer<QWebSocket> m_socket;
|
||||||
bool m_socketWasConnected;
|
bool m_socketWasConnected;
|
||||||
|
bool m_socketManuallyClosed;
|
||||||
|
|
||||||
QTimer m_reconnectTimer;
|
QTimer m_reconnectTimer;
|
||||||
QTimer m_pingTimer;
|
QTimer m_pingTimer;
|
||||||
QTimer m_pongTimer;
|
QTimer m_pongTimer;
|
||||||
|
QTimer m_sendTimer;
|
||||||
|
|
||||||
int m_lastProjectSize;
|
std::atomic<bool> m_sendProject;
|
||||||
int m_lastProjectSentSize;
|
QByteArray m_projectData;
|
||||||
|
int m_totalSentSize;
|
||||||
|
int m_lastSentProgress;
|
||||||
|
|
||||||
|
const QString m_designStudioId;
|
||||||
|
|
||||||
static constexpr int m_reconnectTimeout = 5000;
|
static constexpr int m_reconnectTimeout = 5000;
|
||||||
static constexpr int m_pingTimeout = 10000;
|
static constexpr int m_pingTimeout = 10000;
|
||||||
static constexpr int m_pongTimeout = 30000;
|
static constexpr int m_pongTimeout = 30000;
|
||||||
|
|
||||||
void initPingPong();
|
void initPingPong();
|
||||||
bool sendProjectNotification(const int &projectSize);
|
void stopPingPong();
|
||||||
|
void restartPingPong();
|
||||||
|
void sendProjectDataInternal();
|
||||||
|
bool sendDesignStudioReady();
|
||||||
|
bool sendProjectNotification(const int &projectSize, const QString &qtVersion);
|
||||||
bool sendTextMessage(const QLatin1String &dataType, const QJsonValue &data = QJsonValue());
|
bool sendTextMessage(const QLatin1String &dataType, const QJsonValue &data = QJsonValue());
|
||||||
bool sendBinaryMessage(const QByteArray &data);
|
bool sendBinaryMessage(const QByteArray &data);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void connected(const QString &deviceId);
|
void connected(const QString &deviceId);
|
||||||
void disconnected(const QString &deviceId);
|
void disconnected(const QString &deviceId);
|
||||||
void deviceInfoReady(const QString &deviceIp, const QString &deviceId);
|
void deviceInfoReady(const QString &deviceId);
|
||||||
void projectSendingProgress(const QString &deviceId, const int progress);
|
void projectSendingProgress(const QString &deviceId, const int progress);
|
||||||
|
void projectStarting(const QString &deviceId);
|
||||||
void projectStarted(const QString &deviceId);
|
void projectStarted(const QString &deviceId);
|
||||||
void projectStopped(const QString &deviceId);
|
void projectStopped(const QString &deviceId);
|
||||||
void projectLogsReceived(const QString &deviceId, const QString &logs);
|
void projectLogsReceived(const QString &deviceId, const QString &logs);
|
||||||
|
@@ -127,6 +127,11 @@ void DeviceInfo::setScreenHeight(const int &screenHeight)
|
|||||||
m_data[keyScreenHeight] = screenHeight;
|
m_data[keyScreenHeight] = screenHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DeviceInfo::setSelfId(const QString &selfId)
|
||||||
|
{
|
||||||
|
m_data[keySelfId] = selfId;
|
||||||
|
}
|
||||||
|
|
||||||
void DeviceInfo::setAppVersion(const QString &appVersion)
|
void DeviceInfo::setAppVersion(const QString &appVersion)
|
||||||
{
|
{
|
||||||
m_data[keyAppVersion] = appVersion;
|
m_data[keyAppVersion] = appVersion;
|
||||||
|
@@ -27,7 +27,7 @@ protected:
|
|||||||
class DeviceSettings : public IDeviceData
|
class DeviceSettings : public IDeviceData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DeviceSettings() = default;
|
using IDeviceData::IDeviceData;
|
||||||
|
|
||||||
// Getters
|
// Getters
|
||||||
bool active() const;
|
bool active() const;
|
||||||
@@ -51,7 +51,7 @@ private:
|
|||||||
class DeviceInfo : public IDeviceData
|
class DeviceInfo : public IDeviceData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DeviceInfo() = default;
|
using IDeviceData::IDeviceData;
|
||||||
|
|
||||||
// Getters
|
// Getters
|
||||||
QString os() const;
|
QString os() const;
|
||||||
@@ -76,7 +76,7 @@ private:
|
|||||||
static constexpr char keyOsVersion[] = "osVersion";
|
static constexpr char keyOsVersion[] = "osVersion";
|
||||||
static constexpr char keyScreenWidth[] = "screenWidth";
|
static constexpr char keyScreenWidth[] = "screenWidth";
|
||||||
static constexpr char keyScreenHeight[] = "screenHeight";
|
static constexpr char keyScreenHeight[] = "screenHeight";
|
||||||
static constexpr char keySelfId[] = "selfId";
|
static constexpr char keySelfId[] = "deviceId";
|
||||||
static constexpr char keyArchitecture[] = "architecture";
|
static constexpr char keyArchitecture[] = "architecture";
|
||||||
static constexpr char keyAppVersion[] = "appVersion";
|
static constexpr char keyAppVersion[] = "appVersion";
|
||||||
};
|
};
|
||||||
|
@@ -2,65 +2,73 @@
|
|||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
#include "devicemanager.h"
|
#include "devicemanager.h"
|
||||||
|
#include "device.h"
|
||||||
#include "devicemanagerwidget.h"
|
#include "devicemanagerwidget.h"
|
||||||
|
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
|
#include <QLatin1String>
|
||||||
#include <QNetworkDatagram>
|
#include <QNetworkDatagram>
|
||||||
#include <QNetworkInterface>
|
#include <QNetworkInterface>
|
||||||
|
#include <QUdpSocket>
|
||||||
|
|
||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
|
#include <projectexplorer/kitaspect.h>
|
||||||
|
#include <projectexplorer/target.h>
|
||||||
|
#include <qmldesigner/qmldesignerplugin.h>
|
||||||
|
#include <qtsupport/qtkitaspect.h>
|
||||||
|
|
||||||
namespace QmlDesigner::DeviceShare {
|
namespace QmlDesigner::DeviceShare {
|
||||||
|
|
||||||
|
namespace JsonKeys {
|
||||||
|
using namespace Qt::Literals;
|
||||||
|
constexpr auto devices = "devices"_L1;
|
||||||
|
constexpr auto designStudioId = "designStudioId"_L1;
|
||||||
|
constexpr auto deviceInfo = "deviceInfo"_L1;
|
||||||
|
constexpr auto deviceSettings = "deviceSettings"_L1;
|
||||||
|
} // namespace JsonKeys
|
||||||
|
|
||||||
DeviceManager::DeviceManager(QObject *parent)
|
DeviceManager::DeviceManager(QObject *parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
|
, m_currentState(OpTypes::Stopped)
|
||||||
|
, m_processInterrupted(false)
|
||||||
{
|
{
|
||||||
QFileInfo fileInfo(Core::ICore::settings()->fileName());
|
QFileInfo fileInfo(Core::ICore::settings()->fileName());
|
||||||
m_settingsPath = fileInfo.absolutePath() + "/device_manager.json";
|
m_settingsPath = fileInfo.absolutePath() + "/device_manager.json";
|
||||||
readSettings();
|
readSettings();
|
||||||
if (m_uuid.isEmpty()) {
|
|
||||||
m_uuid = QUuid::createUuid().toString(QUuid::WithoutBraces);
|
|
||||||
writeSettings();
|
|
||||||
}
|
|
||||||
initUdpDiscovery();
|
initUdpDiscovery();
|
||||||
|
|
||||||
|
connect(&m_resourceGenerator,
|
||||||
|
&QmlDesigner::ResourceGenerator::errorOccurred,
|
||||||
|
this,
|
||||||
|
[this](const QString &error) {
|
||||||
|
qCDebug(deviceSharePluginLog) << "ResourceGenerator error:" << error;
|
||||||
|
handleError(ErrTypes::ProjectPackingError, m_currentDeviceId, error);
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(&m_resourceGenerator,
|
||||||
|
&QmlDesigner::ResourceGenerator::qmlrcCreated,
|
||||||
|
this,
|
||||||
|
&DeviceManager::projectPacked);
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceManager::~DeviceManager() = default;
|
DeviceManager::~DeviceManager() = default;
|
||||||
|
|
||||||
void DeviceManager::initUdpDiscovery()
|
void DeviceManager::initUdpDiscovery()
|
||||||
{
|
{
|
||||||
const QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces();
|
QSharedPointer<QUdpSocket> udpSocket = QSharedPointer<QUdpSocket>::create();
|
||||||
for (const QNetworkInterface &interface : interfaces) {
|
bool retVal = udpSocket->bind(QHostAddress::AnyIPv4, 53452, QUdpSocket::ShareAddress);
|
||||||
if (interface.flags().testFlag(QNetworkInterface::IsUp)
|
if (!retVal) {
|
||||||
&& interface.flags().testFlag(QNetworkInterface::IsRunning)) {
|
qCWarning(deviceSharePluginLog) << "UDP:: Failed to bind to UDP port 53452 on AnyIPv4"
|
||||||
for (const QNetworkAddressEntry &entry : interface.addressEntries()) {
|
<< ". Error:" << udpSocket->errorString();
|
||||||
if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol) {
|
return;
|
||||||
QSharedPointer<QUdpSocket> udpSocket = QSharedPointer<QUdpSocket>::create();
|
|
||||||
connect(udpSocket.data(),
|
|
||||||
&QUdpSocket::readyRead,
|
|
||||||
this,
|
|
||||||
&DeviceManager::incomingDatagram);
|
|
||||||
|
|
||||||
bool retVal = udpSocket->bind(entry.ip(), 53452, QUdpSocket::ShareAddress);
|
|
||||||
|
|
||||||
if (!retVal) {
|
|
||||||
qCWarning(deviceSharePluginLog)
|
|
||||||
<< "UDP:: Failed to bind to UDP port 53452 on" << entry.ip().toString()
|
|
||||||
<< "on interface" << interface.name()
|
|
||||||
<< ". Error:" << udpSocket->errorString();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
qCDebug(deviceSharePluginLog) << "UDP:: Listening on" << entry.ip().toString()
|
|
||||||
<< "port" << udpSocket->localPort();
|
|
||||||
m_udpSockets.append(udpSocket);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
connect(udpSocket.data(), &QUdpSocket::readyRead, this, &DeviceManager::incomingDatagram);
|
||||||
|
|
||||||
|
qCDebug(deviceSharePluginLog) << "UDP:: Listening on AnyIPv4 port" << udpSocket->localPort();
|
||||||
|
m_udpSockets.append(udpSocket);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeviceManager::incomingDatagram()
|
void DeviceManager::incomingDatagram()
|
||||||
@@ -80,16 +88,20 @@ void DeviceManager::incomingDatagram()
|
|||||||
|
|
||||||
const QString id = message["id"].toString();
|
const QString id = message["id"].toString();
|
||||||
const QString ip = datagram.senderAddress().toString();
|
const QString ip = datagram.senderAddress().toString();
|
||||||
qCDebug(deviceSharePluginLog) << "Qt UI VIewer found at" << ip << "with id" << id;
|
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
for (const auto &device : m_devices) {
|
for (const auto &device : m_devices) {
|
||||||
if (device->deviceInfo().selfId() == id) {
|
if (device->deviceInfo().selfId() == id) {
|
||||||
|
found = true;
|
||||||
if (device->deviceSettings().ipAddress() != ip) {
|
if (device->deviceSettings().ipAddress() != ip) {
|
||||||
qCDebug(deviceSharePluginLog) << "Updating IP address for device" << id;
|
qCDebug(deviceSharePluginLog) << "Updating IP address for device" << id;
|
||||||
setDeviceIP(id, ip);
|
setDeviceIP(device->deviceSettings().deviceId(), ip);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
qCDebug(deviceSharePluginLog) << "Qt UI VIewer discovered at" << ip << "with id" << id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,13 +111,13 @@ void DeviceManager::writeSettings()
|
|||||||
QJsonArray devices;
|
QJsonArray devices;
|
||||||
for (const auto &device : m_devices) {
|
for (const auto &device : m_devices) {
|
||||||
QJsonObject deviceInfo;
|
QJsonObject deviceInfo;
|
||||||
deviceInfo.insert("deviceInfo", device->deviceInfo().jsonObject());
|
deviceInfo.insert(JsonKeys::deviceInfo, device->deviceInfo().jsonObject());
|
||||||
deviceInfo.insert("deviceSettings", device->deviceSettings().jsonObject());
|
deviceInfo.insert(JsonKeys::deviceSettings, device->deviceSettings().jsonObject());
|
||||||
devices.append(deviceInfo);
|
devices.append(deviceInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
root.insert("devices", devices);
|
root.insert(JsonKeys::devices, devices);
|
||||||
root.insert("uuid", m_uuid);
|
root.insert(JsonKeys::designStudioId, m_designStudioId);
|
||||||
|
|
||||||
QJsonDocument doc(root);
|
QJsonDocument doc(root);
|
||||||
QFile file(m_settingsPath);
|
QFile file(m_settingsPath);
|
||||||
@@ -127,15 +139,17 @@ void DeviceManager::readSettings()
|
|||||||
}
|
}
|
||||||
|
|
||||||
QJsonDocument doc = QJsonDocument::fromJson(file.readAll());
|
QJsonDocument doc = QJsonDocument::fromJson(file.readAll());
|
||||||
m_uuid = doc.object()["uuid"].toString();
|
m_designStudioId = doc.object()[JsonKeys::designStudioId].toString();
|
||||||
QJsonArray devices = doc.object()["devices"].toArray();
|
if (m_designStudioId.isEmpty()) {
|
||||||
|
m_designStudioId = QUuid::createUuid().toString(QUuid::WithoutBraces);
|
||||||
|
writeSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonArray devices = doc.object()[JsonKeys::devices].toArray();
|
||||||
for (const QJsonValue &deviceInfoJson : devices) {
|
for (const QJsonValue &deviceInfoJson : devices) {
|
||||||
DeviceInfo deviceInfo;
|
DeviceInfo deviceInfo{deviceInfoJson.toObject()[JsonKeys::deviceInfo].toObject()};
|
||||||
DeviceSettings deviceSettings;
|
DeviceSettings deviceSettings{deviceInfoJson.toObject()[JsonKeys::deviceSettings].toObject()};
|
||||||
deviceInfo.setJsonObject(deviceInfoJson.toObject()["deviceInfo"].toObject());
|
initDevice(deviceInfo, deviceSettings);
|
||||||
deviceSettings.setJsonObject(deviceInfoJson.toObject()["deviceSettings"].toObject());
|
|
||||||
auto device = initDevice(deviceInfo, deviceSettings);
|
|
||||||
m_devices.append(device);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -267,60 +281,68 @@ bool DeviceManager::addDevice(const QString &ip)
|
|||||||
deviceSettings.setAlias(generateDeviceAlias());
|
deviceSettings.setAlias(generateDeviceAlias());
|
||||||
deviceSettings.setDeviceId(QUuid::createUuid().toString(QUuid::WithoutBraces));
|
deviceSettings.setDeviceId(QUuid::createUuid().toString(QUuid::WithoutBraces));
|
||||||
|
|
||||||
auto device = initDevice({}, deviceSettings);
|
initDevice({}, deviceSettings);
|
||||||
m_devices.append(device);
|
|
||||||
writeSettings();
|
writeSettings();
|
||||||
emit deviceAdded(deviceSettings.deviceId());
|
emit deviceAdded(deviceSettings.deviceId());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QSharedPointer<Device> DeviceManager::initDevice(const DeviceInfo &deviceInfo,
|
void DeviceManager::initDevice(const DeviceInfo &deviceInfo, const DeviceSettings &deviceSettings)
|
||||||
const DeviceSettings &deviceSettings)
|
|
||||||
{
|
{
|
||||||
QSharedPointer<Device> device = QSharedPointer<Device>(new Device{deviceInfo, deviceSettings},
|
QSharedPointer<Device> device = QSharedPointer<Device>(new Device{m_designStudioId,
|
||||||
|
deviceInfo,
|
||||||
|
deviceSettings},
|
||||||
&QObject::deleteLater);
|
&QObject::deleteLater);
|
||||||
|
QString deviceId = device->deviceSettings().deviceId();
|
||||||
connect(device.data(), &Device::deviceInfoReady, this, &DeviceManager::deviceInfoReceived);
|
connect(device.data(), &Device::deviceInfoReady, this, &DeviceManager::deviceInfoReceived);
|
||||||
connect(device.data(), &Device::disconnected, this, &DeviceManager::deviceDisconnected);
|
connect(device.data(), &Device::disconnected, this, [this](const QString &deviceId) {
|
||||||
|
qCDebug(deviceSharePluginLog) << "Device" << deviceId << "disconnected";
|
||||||
|
emit deviceOffline(deviceId);
|
||||||
|
handleError(ErrTypes::NoError, deviceId);
|
||||||
|
});
|
||||||
connect(device.data(), &Device::projectSendingProgress, this, &DeviceManager::projectSendingProgress);
|
connect(device.data(), &Device::projectSendingProgress, this, &DeviceManager::projectSendingProgress);
|
||||||
connect(device.data(), &Device::projectStarted, this, &DeviceManager::projectStarted);
|
|
||||||
connect(device.data(), &Device::projectStopped, this, &DeviceManager::projectStopped);
|
|
||||||
|
|
||||||
connect(device.data(),
|
connect(device.data(), &Device::projectStarting, this, [this](const QString &deviceId) {
|
||||||
&Device::projectLogsReceived,
|
m_currentState = OpTypes::Starting;
|
||||||
this,
|
emit projectStarting(deviceId);
|
||||||
[this](const QString deviceId, const QString &logs) {
|
});
|
||||||
qCDebug(deviceSharePluginLog) << "Log:" << deviceId << logs;
|
|
||||||
emit projectLogsReceived(deviceId, logs);
|
|
||||||
});
|
|
||||||
|
|
||||||
return device;
|
connect(device.data(), &Device::projectStarted, this, [this](const QString &deviceId) {
|
||||||
|
m_currentState = OpTypes::Running;
|
||||||
|
emit projectStarted(deviceId);
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(device.data(), &Device::projectStopped, this, [this](const QString &deviceId) {
|
||||||
|
handleError(ErrTypes::NoError, deviceId);
|
||||||
|
});
|
||||||
|
connect(device.data(), &Device::projectLogsReceived, this, &DeviceManager::projectLogsReceived);
|
||||||
|
|
||||||
|
m_devices.append(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeviceManager::deviceInfoReceived(const QString &deviceIp, const QString &deviceId)
|
void DeviceManager::deviceInfoReceived(const QString &deviceId)
|
||||||
{
|
{
|
||||||
auto newDevIt = std::find_if(m_devices.begin(),
|
auto newDevice = findDevice(deviceId);
|
||||||
m_devices.end(),
|
const QString selfId = newDevice->deviceInfo().selfId();
|
||||||
[deviceId, deviceIp](const auto &device) {
|
const QString deviceIp = newDevice->deviceSettings().ipAddress();
|
||||||
return device->deviceSettings().deviceId() == deviceId
|
|
||||||
&& device->deviceSettings().ipAddress() == deviceIp;
|
|
||||||
});
|
|
||||||
auto oldDevIt = std::find_if(m_devices.begin(),
|
auto oldDevIt = std::find_if(m_devices.begin(),
|
||||||
m_devices.end(),
|
m_devices.end(),
|
||||||
[deviceId, deviceIp](const auto &device) {
|
[selfId, deviceIp](const auto &device) {
|
||||||
return device->deviceSettings().deviceId() == deviceId
|
return device->deviceInfo().selfId() == selfId
|
||||||
&& device->deviceSettings().ipAddress() != deviceIp;
|
&& device->deviceSettings().ipAddress() != deviceIp;
|
||||||
});
|
});
|
||||||
|
|
||||||
// if there are 2 devices with the same ID but different IPs, remove the old one
|
// if there are 2 devices with the same ID but different IPs, remove the old one
|
||||||
// aka: merge devices with the same ID
|
// aka: merge devices with the same ID
|
||||||
if (oldDevIt != m_devices.end()) {
|
if (oldDevIt != m_devices.end()) {
|
||||||
QSharedPointer<Device> oldDevice = *oldDevIt;
|
auto oldDevice = *oldDevIt;
|
||||||
QSharedPointer<Device> newDevice = *newDevIt;
|
const QString alias = oldDevice->deviceSettings().alias();
|
||||||
DeviceSettings deviceSettings = oldDevice->deviceSettings();
|
m_devices.removeOne(*oldDevIt);
|
||||||
deviceSettings.setIpAddress(newDevice->deviceSettings().ipAddress());
|
DeviceSettings settings = newDevice->deviceSettings();
|
||||||
newDevice->setDeviceSettings(deviceSettings);
|
settings.setAlias(alias);
|
||||||
m_devices.removeOne(oldDevice);
|
newDevice->setDeviceSettings(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
writeSettings();
|
writeSettings();
|
||||||
@@ -328,16 +350,6 @@ void DeviceManager::deviceInfoReceived(const QString &deviceIp, const QString &d
|
|||||||
emit deviceOnline(deviceId);
|
emit deviceOnline(deviceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeviceManager::deviceDisconnected(const QString &deviceId)
|
|
||||||
{
|
|
||||||
auto device = findDevice(deviceId);
|
|
||||||
if (!device)
|
|
||||||
return;
|
|
||||||
|
|
||||||
qCDebug(deviceSharePluginLog) << "Device" << deviceId << "disconnected";
|
|
||||||
emit deviceOffline(deviceId);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeviceManager::removeDevice(const QString &deviceId)
|
void DeviceManager::removeDevice(const QString &deviceId)
|
||||||
{
|
{
|
||||||
auto device = findDevice(deviceId);
|
auto device = findDevice(deviceId);
|
||||||
@@ -360,29 +372,119 @@ void DeviceManager::removeDeviceAt(int index)
|
|||||||
emit deviceRemoved(deviceId);
|
emit deviceRemoved(deviceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DeviceManager::sendProjectFile(const QString &deviceId, const QString &projectFile)
|
void DeviceManager::handleError(const ErrTypes &errType, const QString &deviceId, const QString &error)
|
||||||
{
|
{
|
||||||
auto device = findDevice(deviceId);
|
if (!m_processInterrupted) {
|
||||||
if (!device)
|
if (errType != ErrTypes::NoError)
|
||||||
return false;
|
qCWarning(deviceSharePluginLog) << "Handling error" << error << "for device" << deviceId;
|
||||||
|
|
||||||
QFile file(projectFile);
|
switch (errType) {
|
||||||
if (!file.open(QIODevice::ReadOnly)) {
|
case ErrTypes::InternalError:
|
||||||
qCWarning(deviceSharePluginLog) << "Failed to open project file" << projectFile;
|
emit internalError(deviceId, error);
|
||||||
return false;
|
break;
|
||||||
|
case ErrTypes::ProjectPackingError:
|
||||||
|
emit projectPackingError(deviceId, error);
|
||||||
|
break;
|
||||||
|
case ErrTypes::ProjectSendingError:
|
||||||
|
emit projectSendingError(deviceId, error);
|
||||||
|
break;
|
||||||
|
case ErrTypes::ProjectStartError:
|
||||||
|
emit projectStartingError(deviceId, error);
|
||||||
|
break;
|
||||||
|
case ErrTypes::NoError:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
qCDebug(deviceSharePluginLog) << "Sending project file to device" << deviceId;
|
m_processInterrupted = false;
|
||||||
return device->sendProjectData(file.readAll());
|
m_currentQtKitVersion.clear();
|
||||||
|
m_currentDeviceId.clear();
|
||||||
|
m_currentState = OpTypes::Stopped;
|
||||||
|
emit projectStopped(deviceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DeviceManager::stopRunningProject(const QString &deviceId)
|
void DeviceManager::runProject(const QString &deviceId)
|
||||||
{
|
{
|
||||||
auto device = findDevice(deviceId);
|
auto device = findDevice(deviceId);
|
||||||
if (!device)
|
if (!device) {
|
||||||
return false;
|
handleError(ErrTypes::InternalError, deviceId, "Device not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
return device->sendProjectStopped();
|
if (m_currentState != OpTypes::Stopped) {
|
||||||
|
qCDebug(deviceSharePluginLog) << "Another operation is in progress";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_currentQtKitVersion.clear();
|
||||||
|
ProjectExplorer::Target *target = QmlDesignerPlugin::instance()->currentDesignDocument()->currentTarget();
|
||||||
|
if (target && target->kit()) {
|
||||||
|
if (QtSupport::QtVersion *qtVer = QtSupport::QtKitAspect::qtVersion(target->kit()))
|
||||||
|
m_currentQtKitVersion = qtVer->qtVersion().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_currentState = OpTypes::Packing;
|
||||||
|
m_currentDeviceId = deviceId;
|
||||||
|
m_resourceGenerator.createQmlrcAsyncWithName();
|
||||||
|
emit projectPacking(deviceId);
|
||||||
|
qCDebug(deviceSharePluginLog) << "Packing project for device" << deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceManager::projectPacked(const Utils::FilePath &filePath)
|
||||||
|
{
|
||||||
|
qCDebug(deviceSharePluginLog) << "Project packed" << filePath.toString();
|
||||||
|
emit projectSendingProgress(m_currentDeviceId, 0);
|
||||||
|
|
||||||
|
m_currentState = OpTypes::Sending;
|
||||||
|
qCDebug(deviceSharePluginLog) << "Sending project file to device" << m_currentDeviceId;
|
||||||
|
QFile file(filePath.toString());
|
||||||
|
|
||||||
|
if (!file.open(QIODevice::ReadOnly)) {
|
||||||
|
handleError(ErrTypes::ProjectSendingError, m_currentDeviceId, "Failed to open project file");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProjectExplorer::Target *target = QmlDesignerPlugin::instance()->currentDesignDocument()->currentTarget();
|
||||||
|
if (target && target->kit()) {
|
||||||
|
if (QtSupport::QtVersion *qtVer = QtSupport::QtKitAspect::qtVersion(target->kit()))
|
||||||
|
m_currentQtKitVersion = qtVer->qtVersion().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!findDevice(m_currentDeviceId)->sendProjectData(file.readAll(), m_currentQtKitVersion)) {
|
||||||
|
handleError(ErrTypes::ProjectSendingError, m_currentDeviceId, "Failed to send project file");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceManager::stopProject()
|
||||||
|
{
|
||||||
|
auto device = findDevice(m_currentDeviceId);
|
||||||
|
if (!device) {
|
||||||
|
handleError(ErrTypes::InternalError, m_currentDeviceId, "Device not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_processInterrupted = true;
|
||||||
|
switch (m_currentState) {
|
||||||
|
case OpTypes::Stopped:
|
||||||
|
qCWarning(deviceSharePluginLog) << "No project is running";
|
||||||
|
return;
|
||||||
|
case OpTypes::Packing:
|
||||||
|
qCDebug(deviceSharePluginLog) << "Canceling project packing";
|
||||||
|
m_resourceGenerator.cancel();
|
||||||
|
break;
|
||||||
|
case OpTypes::Sending:
|
||||||
|
qCDebug(deviceSharePluginLog) << "Cancelling project sending";
|
||||||
|
device->abortProjectTransmission();
|
||||||
|
break;
|
||||||
|
case OpTypes::Starting:
|
||||||
|
case OpTypes::Running:
|
||||||
|
qCDebug(deviceSharePluginLog) << "Stopping project on device" << m_currentDeviceId;
|
||||||
|
device->sendProjectStopped();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit projectStopping(m_currentDeviceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceManagerWidget *DeviceManager::widget()
|
DeviceManagerWidget *DeviceManager::widget()
|
||||||
|
@@ -3,14 +3,17 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <qmldesigner/components/componentcore/resourcegenerator.h>
|
||||||
|
|
||||||
|
#include "deviceinfo.h"
|
||||||
|
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
#include <QUdpSocket>
|
|
||||||
#include <QWebSocketServer>
|
|
||||||
|
|
||||||
#include "device.h"
|
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
class QUdpSocket;
|
||||||
|
QT_END_NAMESPACE
|
||||||
namespace QmlDesigner::DeviceShare {
|
namespace QmlDesigner::DeviceShare {
|
||||||
|
class Device;
|
||||||
class DeviceManagerWidget;
|
class DeviceManagerWidget;
|
||||||
|
|
||||||
class DeviceManager : public QObject
|
class DeviceManager : public QObject
|
||||||
@@ -36,8 +39,10 @@ public:
|
|||||||
bool addDevice(const QString &ip);
|
bool addDevice(const QString &ip);
|
||||||
void removeDevice(const QString &deviceId);
|
void removeDevice(const QString &deviceId);
|
||||||
void removeDeviceAt(int index);
|
void removeDeviceAt(int index);
|
||||||
bool sendProjectFile(const QString &deviceId, const QString &projectFile);
|
|
||||||
bool stopRunningProject(const QString &deviceId);
|
// project management functions
|
||||||
|
void runProject(const QString &deviceId); // async
|
||||||
|
void stopProject(); // async
|
||||||
|
|
||||||
DeviceManagerWidget *widget();
|
DeviceManagerWidget *widget();
|
||||||
|
|
||||||
@@ -48,7 +53,22 @@ private:
|
|||||||
|
|
||||||
// settings
|
// settings
|
||||||
QString m_settingsPath;
|
QString m_settingsPath;
|
||||||
QString m_uuid;
|
QString m_designStudioId;
|
||||||
|
|
||||||
|
enum class ErrTypes {
|
||||||
|
NoError,
|
||||||
|
InternalError,
|
||||||
|
ProjectPackingError,
|
||||||
|
ProjectSendingError,
|
||||||
|
ProjectStartError
|
||||||
|
};
|
||||||
|
enum class OpTypes { Stopped, Packing, Sending, Starting, Running };
|
||||||
|
OpTypes m_currentState;
|
||||||
|
QString m_currentDeviceId;
|
||||||
|
QString m_currentQtKitVersion;
|
||||||
|
bool m_processInterrupted;
|
||||||
|
|
||||||
|
QmlDesigner::ResourceGenerator m_resourceGenerator;
|
||||||
|
|
||||||
QPointer<DeviceManagerWidget> m_widget;
|
QPointer<DeviceManagerWidget> m_widget;
|
||||||
|
|
||||||
@@ -59,16 +79,21 @@ private:
|
|||||||
void incomingConnection();
|
void incomingConnection();
|
||||||
void readSettings();
|
void readSettings();
|
||||||
void writeSettings();
|
void writeSettings();
|
||||||
QSharedPointer<Device> initDevice(const DeviceInfo &deviceInfo = DeviceInfo(),
|
void initDevice(const DeviceInfo &deviceInfo = DeviceInfo(),
|
||||||
const DeviceSettings &deviceSettings = DeviceSettings());
|
const DeviceSettings &deviceSettings = DeviceSettings());
|
||||||
|
|
||||||
// device signals
|
// device signals
|
||||||
void deviceInfoReceived(const QString &deviceIp, const QString &deviceId);
|
void deviceInfoReceived(const QString &deviceId);
|
||||||
void deviceDisconnected(const QString &deviceId);
|
|
||||||
|
|
||||||
QSharedPointer<Device> findDevice(const QString &deviceId) const;
|
QSharedPointer<Device> findDevice(const QString &deviceId) const;
|
||||||
QString generateDeviceAlias() const;
|
QString generateDeviceAlias() const;
|
||||||
|
|
||||||
|
// internal functions
|
||||||
|
void projectPacked(const Utils::FilePath &filePath);
|
||||||
|
void handleError(const ErrTypes &errType,
|
||||||
|
const QString &deviceId,
|
||||||
|
const QString &error = QString());
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void deviceAdded(const QString &deviceId);
|
void deviceAdded(const QString &deviceId);
|
||||||
void deviceRemoved(const QString &deviceId);
|
void deviceRemoved(const QString &deviceId);
|
||||||
@@ -77,10 +102,19 @@ signals:
|
|||||||
void deviceActivated(const QString &deviceId);
|
void deviceActivated(const QString &deviceId);
|
||||||
void deviceDeactivated(const QString &deviceId);
|
void deviceDeactivated(const QString &deviceId);
|
||||||
void deviceAliasChanged(const QString &deviceId);
|
void deviceAliasChanged(const QString &deviceId);
|
||||||
|
|
||||||
|
void projectPacking(const QString &deviceId);
|
||||||
|
void projectPackingError(const QString &deviceId, const QString &error);
|
||||||
void projectSendingProgress(const QString &deviceId, const int percentage);
|
void projectSendingProgress(const QString &deviceId, const int percentage);
|
||||||
|
void projectSendingError(const QString &deviceId, const QString &error);
|
||||||
|
void projectStarting(const QString &deviceId);
|
||||||
|
void projectStartingError(const QString &deviceId, const QString &error);
|
||||||
void projectStarted(const QString &deviceId);
|
void projectStarted(const QString &deviceId);
|
||||||
|
void projectStopping(const QString &deviceId);
|
||||||
void projectStopped(const QString &deviceId);
|
void projectStopped(const QString &deviceId);
|
||||||
void projectLogsReceived(const QString &deviceId, const QString &logs);
|
void projectLogsReceived(const QString &deviceId, const QString &logs);
|
||||||
|
|
||||||
|
void internalError(const QString &deviceId, const QString &error);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QmlDesigner::DeviceShare
|
} // namespace QmlDesigner::DeviceShare
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
#include "devicemanagermodel.h"
|
#include "devicemanagermodel.h"
|
||||||
|
#include "device.h"
|
||||||
#include "devicemanager.h"
|
#include "devicemanager.h"
|
||||||
|
|
||||||
namespace QmlDesigner::DeviceShare {
|
namespace QmlDesigner::DeviceShare {
|
||||||
|
@@ -0,0 +1,45 @@
|
|||||||
|
// Copyright (C) 2024 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef QT_WEBSOCKET_ENABLED
|
||||||
|
#include <QWebSocket>
|
||||||
|
#else
|
||||||
|
#include <QAbstractSocket>
|
||||||
|
|
||||||
|
// QWebSocket mock.
|
||||||
|
// It is used to avoid linking against QtWebSockets.
|
||||||
|
namespace QWebSocketProtocol {
|
||||||
|
enum CloseCode { CloseCodeNormal = 1000 };
|
||||||
|
enum Version { Unknown = 0, Version13 = 13 };
|
||||||
|
} // namespace QWebSocketProtocol
|
||||||
|
|
||||||
|
class QWebSocket : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
QWebSocket() = default;
|
||||||
|
~QWebSocket() = default;
|
||||||
|
|
||||||
|
void setOutgoingFrameSize(int) {}
|
||||||
|
void setParent(QObject *) {}
|
||||||
|
void open(const QUrl &) {}
|
||||||
|
void close() {}
|
||||||
|
void close(QWebSocketProtocol::CloseCode, const QString &) {}
|
||||||
|
void abort() {}
|
||||||
|
void flush() {}
|
||||||
|
void ping() {}
|
||||||
|
bool isValid() {return true;}
|
||||||
|
QAbstractSocket::SocketState state() {return QAbstractSocket::ConnectedState;}
|
||||||
|
void sendTextMessage(const QString &){}
|
||||||
|
void sendBinaryMessage(const QByteArray &){}
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void pong(quint64, const QByteArray &);
|
||||||
|
void textMessageReceived(const QString &);
|
||||||
|
void disconnected();
|
||||||
|
void connected();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // QT_WEBSOCKETS_LIB
|
@@ -8,9 +8,7 @@
|
|||||||
|
|
||||||
#include <qmldesigner/qmldesignerplugin.h>
|
#include <qmldesigner/qmldesignerplugin.h>
|
||||||
|
|
||||||
#ifdef DVCONNECTOR_ENABLED
|
#include <devicesharing/device.h>
|
||||||
#include <resourcegeneratorproxy.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
@@ -61,7 +59,75 @@ RunManager::RunManager(DeviceShare::DeviceManager &deviceManager)
|
|||||||
this,
|
this,
|
||||||
&RunManager::udpateTargets);
|
&RunManager::udpateTargets);
|
||||||
|
|
||||||
// TODO If device going offline is currently running force stop
|
// If device going offline is currently running force stop
|
||||||
|
connect(&m_deviceManager,
|
||||||
|
&DeviceShare::DeviceManager::deviceOffline,
|
||||||
|
this,
|
||||||
|
[this](const QString &deviceId) {
|
||||||
|
qCDebug(runManagerLog) << "Device offline." << deviceId;
|
||||||
|
|
||||||
|
if (m_runningTargets.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto findRunningTarget = [&](const auto &runningTarget) {
|
||||||
|
return std::visit(overloaded{[](const QPointer<ProjectExplorer::RunControl>) {
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
[&](const QString &arg) { return arg == deviceId; }},
|
||||||
|
runningTarget);
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto it = std::ranges::find_if(m_runningTargets, findRunningTarget);
|
||||||
|
|
||||||
|
if (it != m_runningTargets.end()) {
|
||||||
|
std::visit(overloaded{[](const QPointer<ProjectExplorer::RunControl>) {},
|
||||||
|
[&](const QString &) { m_deviceManager.stopProject(); }},
|
||||||
|
*it);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Packing
|
||||||
|
connect(&m_deviceManager,
|
||||||
|
&DeviceShare::DeviceManager::projectPacking,
|
||||||
|
this,
|
||||||
|
[this](const QString &deviceId) {
|
||||||
|
qCDebug(runManagerLog) << "Project packing." << deviceId;
|
||||||
|
setState(TargetState::Packing);
|
||||||
|
});
|
||||||
|
connect(&m_deviceManager,
|
||||||
|
&DeviceShare::DeviceManager::projectPackingError,
|
||||||
|
this,
|
||||||
|
&RunManager::handleError);
|
||||||
|
|
||||||
|
// Sending
|
||||||
|
connect(&m_deviceManager,
|
||||||
|
&DeviceShare::DeviceManager::projectSendingProgress,
|
||||||
|
this,
|
||||||
|
[this](const QString &deviceId, const int percentage) {
|
||||||
|
qCDebug(runManagerLog) << "Project sending." << deviceId << percentage;
|
||||||
|
setProgress(percentage);
|
||||||
|
setState(TargetState::Sending);
|
||||||
|
});
|
||||||
|
connect(&m_deviceManager,
|
||||||
|
&DeviceShare::DeviceManager::projectSendingError,
|
||||||
|
this,
|
||||||
|
&RunManager::handleError);
|
||||||
|
|
||||||
|
// Starting
|
||||||
|
connect(&m_deviceManager,
|
||||||
|
&DeviceShare::DeviceManager::projectStarting,
|
||||||
|
this,
|
||||||
|
[this](const QString &deviceId) {
|
||||||
|
qCDebug(runManagerLog) << "Project starting." << deviceId;
|
||||||
|
setState(TargetState::Starting);
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(&m_deviceManager,
|
||||||
|
&DeviceShare::DeviceManager::projectStartingError,
|
||||||
|
this,
|
||||||
|
&RunManager::handleError);
|
||||||
|
|
||||||
|
connect(&m_deviceManager, &DeviceShare::DeviceManager::internalError, this, &RunManager::handleError);
|
||||||
|
|
||||||
// Connect Android/Device run/stop project signals
|
// Connect Android/Device run/stop project signals
|
||||||
connect(&m_deviceManager,
|
connect(&m_deviceManager,
|
||||||
@@ -72,8 +138,7 @@ RunManager::RunManager(DeviceShare::DeviceManager &deviceManager)
|
|||||||
|
|
||||||
m_runningTargets.append(deviceId);
|
m_runningTargets.append(deviceId);
|
||||||
|
|
||||||
m_state = TargetState::Running;
|
setState(TargetState::Running);
|
||||||
emit stateChanged();
|
|
||||||
});
|
});
|
||||||
connect(&m_deviceManager,
|
connect(&m_deviceManager,
|
||||||
&DeviceShare::DeviceManager::projectStopped,
|
&DeviceShare::DeviceManager::projectStopped,
|
||||||
@@ -95,8 +160,7 @@ RunManager::RunManager(DeviceShare::DeviceManager &deviceManager)
|
|||||||
if (!m_runningTargets.isEmpty())
|
if (!m_runningTargets.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_state = TargetState::NotRunning;
|
setState(TargetState::NotRunning);
|
||||||
emit stateChanged();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Connect Creator run/stop project signals
|
// Connect Creator run/stop project signals
|
||||||
@@ -109,8 +173,7 @@ RunManager::RunManager(DeviceShare::DeviceManager &deviceManager)
|
|||||||
|
|
||||||
m_runningTargets.append(QPointer(runControl));
|
m_runningTargets.append(QPointer(runControl));
|
||||||
|
|
||||||
m_state = TargetState::Running;
|
setState(TargetState::Running);
|
||||||
emit stateChanged();
|
|
||||||
});
|
});
|
||||||
connect(projectExplorerPlugin,
|
connect(projectExplorerPlugin,
|
||||||
&ProjectExplorer::ProjectExplorerPlugin::runControlStoped,
|
&ProjectExplorer::ProjectExplorerPlugin::runControlStoped,
|
||||||
@@ -132,8 +195,7 @@ RunManager::RunManager(DeviceShare::DeviceManager &deviceManager)
|
|||||||
if (!m_runningTargets.isEmpty())
|
if (!m_runningTargets.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_state = TargetState::NotRunning;
|
setState(TargetState::NotRunning);
|
||||||
emit stateChanged();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
udpateTargets();
|
udpateTargets();
|
||||||
@@ -180,10 +242,7 @@ void RunManager::toggleCurrentTarget()
|
|||||||
if (!arg.isNull())
|
if (!arg.isNull())
|
||||||
arg.get()->initiateStop();
|
arg.get()->initiateStop();
|
||||||
},
|
},
|
||||||
[](const QString arg) {
|
[](const QString &) { deviceManager()->stopProject(); }},
|
||||||
if (!arg.isEmpty())
|
|
||||||
deviceManager()->stopRunningProject(arg);
|
|
||||||
}},
|
|
||||||
runningTarget);
|
runningTarget);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -199,9 +258,16 @@ void RunManager::toggleCurrentTarget()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setError("");
|
||||||
|
|
||||||
std::visit([&](const auto &arg) { arg.run(); }, *target);
|
std::visit([&](const auto &arg) { arg.run(); }, *target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RunManager::cancelCurrentTarget()
|
||||||
|
{
|
||||||
|
deviceManager()->stopProject();
|
||||||
|
}
|
||||||
|
|
||||||
int RunManager::currentTargetIndex() const
|
int RunManager::currentTargetIndex() const
|
||||||
{
|
{
|
||||||
return runTargetIndex(m_currentTargetId);
|
return runTargetIndex(m_currentTargetId);
|
||||||
@@ -230,6 +296,45 @@ bool RunManager::selectRunTarget(const QString &targetName)
|
|||||||
return selectRunTarget(Utils::Id::fromString(targetName));
|
return selectRunTarget(Utils::Id::fromString(targetName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RunManager::setState(TargetState state)
|
||||||
|
{
|
||||||
|
if (state == m_state)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_state = state;
|
||||||
|
emit stateChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
RunManager::TargetState RunManager::state() const
|
||||||
|
{
|
||||||
|
return m_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RunManager::setProgress(int progress)
|
||||||
|
{
|
||||||
|
m_progress = progress;
|
||||||
|
emit progressChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
int RunManager::progress() const
|
||||||
|
{
|
||||||
|
return m_progress;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RunManager::setError(const QString &error)
|
||||||
|
{
|
||||||
|
if (error == m_error)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_error = error;
|
||||||
|
emit errorChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString &RunManager::error() const
|
||||||
|
{
|
||||||
|
return m_error;
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<Target> RunManager::runTarget(Utils::Id targetId) const
|
std::optional<Target> RunManager::runTarget(Utils::Id targetId) const
|
||||||
{
|
{
|
||||||
auto find_id = [&](const auto &target) {
|
auto find_id = [&](const auto &target) {
|
||||||
@@ -260,6 +365,13 @@ int RunManager::runTargetIndex(Utils::Id targetId) const
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RunManager::handleError(const QString &deviceId, const QString &error)
|
||||||
|
{
|
||||||
|
qCDebug(runManagerLog) << "Error" << deviceId << error;
|
||||||
|
setError(error);
|
||||||
|
setState(TargetState::NotRunning);
|
||||||
|
}
|
||||||
|
|
||||||
QString NormalTarget::name() const
|
QString NormalTarget::name() const
|
||||||
{
|
{
|
||||||
return "Default";
|
return "Default";
|
||||||
@@ -306,8 +418,8 @@ AndroidTarget::AndroidTarget(const QString &deviceId)
|
|||||||
|
|
||||||
QString AndroidTarget::name() const
|
QString AndroidTarget::name() const
|
||||||
{
|
{
|
||||||
if (auto devcieSettings = deviceManager()->deviceSettings(m_deviceId))
|
if (auto deviceSettings = deviceManager()->deviceSettings(m_deviceId))
|
||||||
return devcieSettings->alias();
|
return deviceSettings->alias();
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@@ -329,10 +441,8 @@ void AndroidTarget::run() const
|
|||||||
{
|
{
|
||||||
if (!ProjectExplorer::ProjectExplorerPlugin::saveModifiedFiles())
|
if (!ProjectExplorer::ProjectExplorerPlugin::saveModifiedFiles())
|
||||||
return;
|
return;
|
||||||
#ifdef DVCONNECTOR_ENABLED
|
|
||||||
auto qmlrcPath = DesignViewer::ResourceGeneratorProxy().createResourceFileSync();
|
deviceManager()->runProject(m_deviceId);
|
||||||
deviceManager()->sendProjectFile(m_deviceId, qmlrcPath->toString());
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
@@ -54,7 +54,7 @@ class RunManager : public QObject
|
|||||||
public:
|
public:
|
||||||
explicit RunManager(DeviceShare::DeviceManager &deviceManager);
|
explicit RunManager(DeviceShare::DeviceManager &deviceManager);
|
||||||
|
|
||||||
enum TargetState { Running, NotRunning };
|
enum TargetState { Packing, Sending, Starting, Running, NotRunning };
|
||||||
Q_ENUM(TargetState)
|
Q_ENUM(TargetState)
|
||||||
|
|
||||||
void udpateTargets();
|
void udpateTargets();
|
||||||
@@ -62,18 +62,28 @@ public:
|
|||||||
const QList<Target> targets() const;
|
const QList<Target> targets() const;
|
||||||
|
|
||||||
void toggleCurrentTarget();
|
void toggleCurrentTarget();
|
||||||
|
void cancelCurrentTarget();
|
||||||
|
|
||||||
int currentTargetIndex() const;
|
int currentTargetIndex() const;
|
||||||
|
|
||||||
bool selectRunTarget(Utils::Id id);
|
bool selectRunTarget(Utils::Id id);
|
||||||
bool selectRunTarget(const QString &targetName);
|
bool selectRunTarget(const QString &targetName);
|
||||||
|
|
||||||
TargetState state() const { return m_state; }
|
void setState(TargetState state);
|
||||||
|
TargetState state() const;
|
||||||
|
|
||||||
|
void setProgress(int progress);
|
||||||
|
int progress() const;
|
||||||
|
|
||||||
|
void setError(const QString &error);
|
||||||
|
const QString &error() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::optional<Target> runTarget(Utils::Id targetId) const;
|
std::optional<Target> runTarget(Utils::Id targetId) const;
|
||||||
int runTargetIndex(Utils::Id targetId) const;
|
int runTargetIndex(Utils::Id targetId) const;
|
||||||
|
|
||||||
|
void handleError(const QString &deviceId, const QString &error);
|
||||||
|
|
||||||
DeviceShare::DeviceManager &m_deviceManager;
|
DeviceShare::DeviceManager &m_deviceManager;
|
||||||
|
|
||||||
QList<Target> m_targets;
|
QList<Target> m_targets;
|
||||||
@@ -82,11 +92,15 @@ private:
|
|||||||
QList<RunningTarget> m_runningTargets;
|
QList<RunningTarget> m_runningTargets;
|
||||||
|
|
||||||
TargetState m_state = TargetState::NotRunning;
|
TargetState m_state = TargetState::NotRunning;
|
||||||
|
int m_progress = 0;
|
||||||
|
QString m_error;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void runTargetChanged();
|
void runTargetChanged();
|
||||||
void stateChanged();
|
void stateChanged();
|
||||||
void targetsChanged();
|
void targetsChanged();
|
||||||
|
void progressChanged();
|
||||||
|
void errorChanged();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
@@ -489,6 +489,14 @@ ToolBarBackend::ToolBarBackend(QObject *parent)
|
|||||||
&RunManager::stateChanged,
|
&RunManager::stateChanged,
|
||||||
this,
|
this,
|
||||||
&ToolBarBackend::runManagerStateChanged);
|
&ToolBarBackend::runManagerStateChanged);
|
||||||
|
connect(&QmlDesignerPlugin::runManager(),
|
||||||
|
&RunManager::progressChanged,
|
||||||
|
this,
|
||||||
|
&ToolBarBackend::runManagerProgressChanged);
|
||||||
|
connect(&QmlDesignerPlugin::runManager(),
|
||||||
|
&RunManager::errorChanged,
|
||||||
|
this,
|
||||||
|
&ToolBarBackend::runManagerErrorChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ToolBarBackend::registerDeclarativeType()
|
void ToolBarBackend::registerDeclarativeType()
|
||||||
@@ -713,6 +721,11 @@ void ToolBarBackend::toggleRunning()
|
|||||||
QmlDesignerPlugin::runManager().toggleCurrentTarget();
|
QmlDesignerPlugin::runManager().toggleCurrentTarget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ToolBarBackend::cancelRunning()
|
||||||
|
{
|
||||||
|
QmlDesignerPlugin::runManager().cancelCurrentTarget();
|
||||||
|
}
|
||||||
|
|
||||||
bool ToolBarBackend::canGoBack() const
|
bool ToolBarBackend::canGoBack() const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(designModeWidget(), return false);
|
QTC_ASSERT(designModeWidget(), return false);
|
||||||
@@ -901,6 +914,16 @@ int ToolBarBackend::runManagerState() const
|
|||||||
return QmlDesignerPlugin::runManager().state();
|
return QmlDesignerPlugin::runManager().state();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ToolBarBackend::runManagerProgress() const
|
||||||
|
{
|
||||||
|
return QmlDesignerPlugin::runManager().progress();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ToolBarBackend::runManagerError() const
|
||||||
|
{
|
||||||
|
return QmlDesignerPlugin::runManager().error();
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DVCONNECTOR_ENABLED
|
#ifdef DVCONNECTOR_ENABLED
|
||||||
DesignViewer::DVConnector *ToolBarBackend::designViewerConnector()
|
DesignViewer::DVConnector *ToolBarBackend::designViewerConnector()
|
||||||
{
|
{
|
||||||
|
@@ -128,6 +128,8 @@ class ToolBarBackend : public QObject
|
|||||||
|
|
||||||
Q_PROPERTY(int runTargetIndex READ runTargetIndex NOTIFY runTargetIndexChanged)
|
Q_PROPERTY(int runTargetIndex READ runTargetIndex NOTIFY runTargetIndexChanged)
|
||||||
Q_PROPERTY(int runManagerState READ runManagerState NOTIFY runManagerStateChanged)
|
Q_PROPERTY(int runManagerState READ runManagerState NOTIFY runManagerStateChanged)
|
||||||
|
Q_PROPERTY(int runManagerProgress READ runManagerProgress NOTIFY runManagerProgressChanged)
|
||||||
|
Q_PROPERTY(QString runManagerError READ runManagerError NOTIFY runManagerErrorChanged)
|
||||||
|
|
||||||
#ifdef DVCONNECTOR_ENABLED
|
#ifdef DVCONNECTOR_ENABLED
|
||||||
Q_PROPERTY(DesignViewer::DVConnector *designViewerConnector READ designViewerConnector CONSTANT)
|
Q_PROPERTY(DesignViewer::DVConnector *designViewerConnector READ designViewerConnector CONSTANT)
|
||||||
@@ -155,6 +157,7 @@ public:
|
|||||||
Q_INVOKABLE void openDeviceManager();
|
Q_INVOKABLE void openDeviceManager();
|
||||||
Q_INVOKABLE void selectRunTarget(const QString &targetName);
|
Q_INVOKABLE void selectRunTarget(const QString &targetName);
|
||||||
Q_INVOKABLE void toggleRunning();
|
Q_INVOKABLE void toggleRunning();
|
||||||
|
Q_INVOKABLE void cancelRunning();
|
||||||
|
|
||||||
bool canGoBack() const;
|
bool canGoBack() const;
|
||||||
bool canGoForward() const;
|
bool canGoForward() const;
|
||||||
@@ -190,6 +193,8 @@ public:
|
|||||||
|
|
||||||
int runTargetIndex() const;
|
int runTargetIndex() const;
|
||||||
int runManagerState() const;
|
int runManagerState() const;
|
||||||
|
int runManagerProgress() const;
|
||||||
|
QString runManagerError() const;
|
||||||
|
|
||||||
#ifdef DVCONNECTOR_ENABLED
|
#ifdef DVCONNECTOR_ENABLED
|
||||||
DesignViewer::DVConnector *designViewerConnector();
|
DesignViewer::DVConnector *designViewerConnector();
|
||||||
@@ -217,6 +222,8 @@ signals:
|
|||||||
|
|
||||||
void runTargetIndexChanged();
|
void runTargetIndexChanged();
|
||||||
void runManagerStateChanged();
|
void runManagerStateChanged();
|
||||||
|
void runManagerProgressChanged();
|
||||||
|
void runManagerErrorChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setupWorkspaces();
|
void setupWorkspaces();
|
||||||
|
@@ -15,12 +15,12 @@
|
|||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
template<typename Timer>
|
template<typename Timer>
|
||||||
class DirectoryPathCompressor
|
class DirectoryPathCompressor final
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DirectoryPathCompressor() { m_timer.setSingleShot(true); }
|
DirectoryPathCompressor() { m_timer.setSingleShot(true); }
|
||||||
|
|
||||||
virtual ~DirectoryPathCompressor() = default;
|
~DirectoryPathCompressor() = default;
|
||||||
|
|
||||||
void addSourceContextId(SourceContextId sourceContextId)
|
void addSourceContextId(SourceContextId sourceContextId)
|
||||||
{
|
{
|
||||||
@@ -34,12 +34,18 @@ public:
|
|||||||
restartTimer();
|
restartTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
SourceContextIds takeSourceContextIds() { return std::move(m_sourceContextIds); }
|
const SourceContextIds &sourceContextIds() { return m_sourceContextIds; }
|
||||||
|
|
||||||
virtual void setCallback(std::function<void(QmlDesigner::SourceContextIds &&)> &&callback)
|
virtual void setCallback(std::function<void(const QmlDesigner::SourceContextIds &)> &&callback)
|
||||||
{
|
{
|
||||||
QObject::connect(&m_timer, &Timer::timeout, [this, callback = std::move(callback)] {
|
if (connection)
|
||||||
callback(takeSourceContextIds());
|
QObject::disconnect(connection);
|
||||||
|
connection = QObject::connect(&m_timer, &Timer::timeout, [this, callback = std::move(callback)] {
|
||||||
|
try {
|
||||||
|
callback(m_sourceContextIds);
|
||||||
|
m_sourceContextIds.clear();
|
||||||
|
} catch (const std::exception &) {
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,8 +59,22 @@ public:
|
|||||||
return m_timer;
|
return m_timer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct ConnectionGuard
|
||||||
|
{
|
||||||
|
~ConnectionGuard()
|
||||||
|
{
|
||||||
|
if (connection)
|
||||||
|
QObject::disconnect(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
QMetaObject::Connection &connection;
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SourceContextIds m_sourceContextIds;
|
SourceContextIds m_sourceContextIds;
|
||||||
|
QMetaObject::Connection connection;
|
||||||
|
ConnectionGuard connectionGuard{connection};
|
||||||
Timer m_timer;
|
Timer m_timer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -49,14 +49,10 @@ public:
|
|||||||
&FileSystemWatcher::directoryChanged,
|
&FileSystemWatcher::directoryChanged,
|
||||||
[&](const QString &path) { compressChangedDirectoryPath(path); });
|
[&](const QString &path) { compressChangedDirectoryPath(path); });
|
||||||
|
|
||||||
m_directoryPathCompressor.setCallback([&](QmlDesigner::SourceContextIds &&sourceContextIds) {
|
m_directoryPathCompressor.setCallback(
|
||||||
addChangedPathForFilePath(std::move(sourceContextIds));
|
[&](const QmlDesigner::SourceContextIds &sourceContextIds) {
|
||||||
});
|
addChangedPathForFilePath(sourceContextIds);
|
||||||
}
|
});
|
||||||
|
|
||||||
~ProjectStoragePathWatcher()
|
|
||||||
{
|
|
||||||
m_directoryPathCompressor.setCallback([&](SourceContextIds &&) {});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateIdPaths(const std::vector<IdPaths> &idPaths) override
|
void updateIdPaths(const std::vector<IdPaths> &idPaths) override
|
||||||
@@ -324,7 +320,7 @@ public:
|
|||||||
m_pathCache.sourceContextId(Utils::PathString{path}));
|
m_pathCache.sourceContextId(Utils::PathString{path}));
|
||||||
}
|
}
|
||||||
|
|
||||||
WatcherEntries watchedEntriesForPaths(QmlDesigner::SourceContextIds &&sourceContextIds)
|
WatcherEntries watchedEntriesForPaths(const QmlDesigner::SourceContextIds &sourceContextIds)
|
||||||
{
|
{
|
||||||
WatcherEntries foundEntries;
|
WatcherEntries foundEntries;
|
||||||
foundEntries.reserve(m_watchedEntries.size());
|
foundEntries.reserve(m_watchedEntries.size());
|
||||||
@@ -375,10 +371,10 @@ public:
|
|||||||
return idPaths;
|
return idPaths;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addChangedPathForFilePath(SourceContextIds &&sourceContextIds)
|
void addChangedPathForFilePath(const SourceContextIds &sourceContextIds)
|
||||||
{
|
{
|
||||||
if (m_notifier) {
|
if (m_notifier) {
|
||||||
WatcherEntries foundEntries = watchedEntriesForPaths(std::move(sourceContextIds));
|
WatcherEntries foundEntries = watchedEntriesForPaths(sourceContextIds);
|
||||||
|
|
||||||
SourceIds watchedSourceIds = watchedPaths(foundEntries);
|
SourceIds watchedSourceIds = watchedPaths(foundEntries);
|
||||||
|
|
||||||
|
@@ -248,6 +248,28 @@ QStringList DSStore::collectionNames() const
|
|||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ThemeProperty DSStore::resolvedDSBinding(QStringView binding) const
|
||||||
|
{
|
||||||
|
const auto parts = binding.split('.', Qt::SkipEmptyParts);
|
||||||
|
if (parts.size() != 3)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
const auto &collectionName = parts[0];
|
||||||
|
auto itr = m_collections.find(collectionName.toString());
|
||||||
|
if (itr == m_collections.end())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
const DSThemeManager &boundCollection = itr->second;
|
||||||
|
const auto &propertyName = parts[2].toLatin1();
|
||||||
|
if (const auto group = boundCollection.groupType(propertyName)) {
|
||||||
|
auto property = boundCollection.property(boundCollection.activeTheme(), *group, propertyName);
|
||||||
|
if (property)
|
||||||
|
return property->isBinding ? resolvedDSBinding(property->value.toString()) : *property;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
QString DSStore::uniqueCollectionName(const QString &hint) const
|
QString DSStore::uniqueCollectionName(const QString &hint) const
|
||||||
{
|
{
|
||||||
return UniqueName::generateTypeName(hint, "Collection", [this](const QString &t) {
|
return UniqueName::generateTypeName(hint, "Collection", [this](const QString &t) {
|
||||||
|
@@ -38,6 +38,8 @@ public:
|
|||||||
std::optional<Utils::FilePath> moduleDirPath() const;
|
std::optional<Utils::FilePath> moduleDirPath() const;
|
||||||
QStringList collectionNames() const;
|
QStringList collectionNames() const;
|
||||||
|
|
||||||
|
ThemeProperty resolvedDSBinding(QStringView binding) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString uniqueCollectionName(const QString &hint) const;
|
QString uniqueCollectionName(const QString &hint) const;
|
||||||
std::optional<QString> loadCollection(const QString &typeName, const Utils::FilePath &qmlFilePath);
|
std::optional<QString> loadCollection(const QString &typeName, const Utils::FilePath &qmlFilePath);
|
||||||
|
@@ -199,7 +199,7 @@ void DSThemeGroup::decorate(ThemeId theme, ModelNode themeNode, bool wrapInGroup
|
|||||||
for (auto &[propName, values] : m_values) {
|
for (auto &[propName, values] : m_values) {
|
||||||
auto themeValue = values.find(theme);
|
auto themeValue = values.find(theme);
|
||||||
if (themeValue != values.end())
|
if (themeValue != values.end())
|
||||||
addProperty(targetNode, propName, themeValue->second);
|
addProperty(targetNode, propName, themeValue->second, wrapInGroups);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,21 +224,18 @@ std::vector<PropertyName> DSThemeGroup::propertyNames() const
|
|||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSThemeGroup::addProperty(ModelNode n, PropertyNameView propName, const PropertyData &data) const
|
void DSThemeGroup::addProperty(ModelNode n, PropertyNameView propName, const PropertyData &data, bool createNewProperty) const
|
||||||
{
|
{
|
||||||
auto metaInfo = n.model()->metaInfo(n.type());
|
|
||||||
const bool propDefined = metaInfo.property(propName).isValid();
|
|
||||||
|
|
||||||
const auto typeName = groupTypeName(m_type);
|
const auto typeName = groupTypeName(m_type);
|
||||||
if (data.isBinding) {
|
if (data.isBinding) {
|
||||||
if (propDefined)
|
if (!createNewProperty)
|
||||||
n.bindingProperty(propName).setExpression(data.value.toString());
|
n.bindingProperty(propName).setExpression(data.value.toString());
|
||||||
else if (auto bindingProp = n.bindingProperty(propName))
|
else if (auto bindingProp = n.bindingProperty(propName))
|
||||||
bindingProp.setDynamicTypeNameAndExpression(*typeName, data.value.toString());
|
bindingProp.setDynamicTypeNameAndExpression(*typeName, data.value.toString());
|
||||||
else
|
else
|
||||||
qCDebug(dsLog) << "Assigning invalid binding" << propName << n.id();
|
qCDebug(dsLog) << "Assigning invalid binding" << propName << n.id();
|
||||||
} else {
|
} else {
|
||||||
if (propDefined)
|
if (!createNewProperty)
|
||||||
n.variantProperty(propName).setValue(data.value);
|
n.variantProperty(propName).setValue(data.value);
|
||||||
else if (auto nodeProp = n.variantProperty(propName))
|
else if (auto nodeProp = n.variantProperty(propName))
|
||||||
nodeProp.setDynamicTypeNameAndValue(*typeName, data.value);
|
nodeProp.setDynamicTypeNameAndValue(*typeName, data.value);
|
||||||
|
@@ -54,7 +54,7 @@ public:
|
|||||||
std::vector<PropertyName> propertyNames() const;
|
std::vector<PropertyName> propertyNames() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void addProperty(ModelNode n, PropertyNameView propName, const PropertyData &data) const;
|
void addProperty(ModelNode n, PropertyNameView propName, const PropertyData &data, bool createNewProperty) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const GroupType m_type;
|
const GroupType m_type;
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user