Merge "Merge remote-tracking branch 'origin/6.0'"

This commit is contained in:
The Qt Project
2021-11-19 11:15:43 +00:00
82 changed files with 706 additions and 229 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -1,6 +1,6 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2019 The Qt Company Ltd. ** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/ ** Contact: https://www.qt.io/licensing/
** **
** This file is part of the Qt Creator documentation. ** This file is part of the Qt Creator documentation.
@@ -76,10 +76,23 @@
Click a line to view where a memory leak Click a line to view where a memory leak
occurred and a stack trace that shows what caused it. occurred and a stack trace that shows what caused it.
As an alternative to collecting data, you can select \inlineimage open.png
to load an external log file in XML format into the \uicontrol Memcheck
view.
\image qtcreator-valgrind-memcheck.png "Memcheck view" \image qtcreator-valgrind-memcheck.png "Memcheck view"
Move the mouse on a row to view more information about the function. Move the mouse on a row to view more information about the function.
To move between rows, select \inlineimage prev.png
or \inlineimage next.png
.
To filter the results, select \inlineimage filtericon.png
, and then select the types of issues to display in the view. You
can view and hide definite and possible memory leaks, uninitialized
values, invalid calls to \c free(), and external errors.
For more information about using Memcheck, see For more information about using Memcheck, see
\l{http://valgrind.org/docs/manual/quick-start.html#quick-start.mcrun} \l{http://valgrind.org/docs/manual/quick-start.html#quick-start.mcrun}
{Interpreting Memcheck's Output} in the Valgrind documentation. {Interpreting Memcheck's Output} in the Valgrind documentation.
@@ -90,6 +103,13 @@
separately for each project in the \l{Specifying Run Settings}{run settings} separately for each project in the \l{Specifying Run Settings}{run settings}
of the project. of the project.
To specify global settings for Valgrind, select \uicontrol Tools >
\uicontrol Options > \uicontrol Analyzer. The \uicontrol
{Memcheck Memory Analysis Options} group contains Memcheck options.
In \uicontrol {Extra Memcheck arguments}, specify additional arguments
for launching the executable.
Stack traces can get quite large and confusing, and therefore, reading them Stack traces can get quite large and confusing, and therefore, reading them
from the bottom up can help. If the stack trace is not big enough or it is from the bottom up can help. If the stack trace is not big enough or it is
too big, select \uicontrol Tools > \uicontrol Options > \uicontrol Analyzer too big, select \uicontrol Tools > \uicontrol Options > \uicontrol Analyzer
@@ -160,26 +180,7 @@
You can run Callgrind on a remote Linux machine or device from any You can run Callgrind on a remote Linux machine or device from any
development machine. development machine.
To analyze applications: \section1 Building Apps for Profiling
\list 1
\li In the \uicontrol Projects mode, select a release build configuration.
\li Select \uicontrol Debug to open the \uicontrol Debug mode, and then
select \uicontrol Callgrind on the toolbar.
\li Select the
\inlineimage qtcreator-analyze-start-button.png "Start button"
button to start the application.
\li Use the application to analyze it.
\li Select the \inlineimage stop_small.png "Stop button"
button to view the results of the analysis in the \uicontrol Profile
view.
\endlist
Callgrind records the call history of functions that are executed when the Callgrind records the call history of functions that are executed when the
application is run. It collects the number of instructions that are application is run. It collects the number of instructions that are
@@ -188,10 +189,6 @@
also use cache simulation or branch prediction to gather information about also use cache simulation or branch prediction to gather information about
the runtime behavior of an application. the runtime behavior of an application.
Double-click a function to view information about the calling functions in
the \uicontrol Callers view and about the called functions in the \uicontrol Callees
view.
Since the run-time characteristics of debug and release Since the run-time characteristics of debug and release
\l{glossary-build-config}{build configurations} \l{glossary-build-config}{build configurations}
differ significantly, analytical findings for one build configuration may differ significantly, analytical findings for one build configuration may
@@ -207,12 +204,84 @@
options for GCC are: \c{-g -O2}. It is options for GCC are: \c{-g -O2}. It is
advisable to use such a setup for Callgrind profiling. advisable to use such a setup for Callgrind profiling.
\section1 Collecting Data
\image qtcreator-valgrind-callgrind.png "Profile view" To analyze applications:
To view the data in KCachegrind, select the \inlineimage kcachegrind.png \list 1
(\uicontrol {Open Results in KCachegrind}) button on the toolbar. \QC
launches KCachegrind and loads the data into it for visualization. \li In the \uicontrol Projects mode, select a release build configuration.
\li Select \uicontrol Debug to open the \uicontrol Debug mode, and then
select \uicontrol Callgrind on the toolbar.
\image qtcreator-valgrind-callgrind-toolbar.png "Callgrind view toolbar"
\li Select the
\inlineimage qtcreator-analyze-start-button.png "Start button"
button to start the application.
\li Use the application to analyze it.
\li Select the \inlineimage stop_small.png "Stop button"
button to view the results of the analysis in the
\uicontrol Functions view.
\endlist
Select \inlineimage icons/pause-icon.png
to speed up program execution during profiling by pausing event
logging. No events are counted while logging is paused.
Select \inlineimage reload_gray.png
to reset all event counters.
Select \inlineimage clean_pane_small.png
to discard all collected data.
Select \inlineimage kcachegrind.png
to view the data in KCachegrind. \QC launches KCachegrind
and loads the data into it for visualization.
\section1 Viewing Collected Data
The results of the analysis are displayed in the \uicontrol Callgrind views.
You can detach views and move them around. To revert the changes, select
\uicontrol Views > \uicontrol {Reset to Default Layout}.
Select \uicontrol Views to show and hide views and view
titles. The \uicontrol Visualization view is hidden by
default. Select \inlineimage redo.png
to refresh the data displayed in it when it is shown.
As an alternative to collecting data, you can select \inlineimage open.png
to load an external log file into the \uicontrol Callgrind views.
\image qtcreator-valgrind-callgrind.png "Callgrind views"
Enter a string in the \uicontrol Filter field to filter the results.
Move the cursor on a function in the \uicontrol Functions view for more
information about it.
Double-click a function to view information about the calling functions in
the \uicontrol Callers view and about the called functions in the
\uicontrol Callees view.
Select \inlineimage prev.png
or \inlineimage next.png
To move between functions in the \uicontrol Callee view.
To set the cost format, select \uicontrol $. You can view absolute
or relative costs, as well as relative costs to parent. Select
\inlineimage filtericon.png
to view only profiling info that originated from the project.
To properly handle recursive or circular function calls, enable cycle
detection by selecting \uicontrol O.
To remove template parameter lists when displaying function names, select
\uicontrol <>.
\section1 Selecting Profiling Options \section1 Selecting Profiling Options
@@ -220,7 +289,7 @@
separately for each project in the \l{Specifying Run Settings}{run settings} separately for each project in the \l{Specifying Run Settings}{run settings}
of the project. of the project.
To specify settings for Valgrind, select \uicontrol Tools > To specify global settings for Valgrind, select \uicontrol Tools >
\uicontrol Options > \uicontrol Analyzer. The \uicontrol \uicontrol Options > \uicontrol Analyzer. The \uicontrol
{Callgrind Profiling Options} group contains Callgrind options. {Callgrind Profiling Options} group contains Callgrind options.
@@ -229,12 +298,21 @@
In the \uicontrol {KCachegrind executable} field, enter the path to the In the \uicontrol {KCachegrind executable} field, enter the path to the
KCachegrind executable to launch. KCachegrind executable to launch.
In the \uicontrol {Result view: Minimum event cost} In \uicontrol {Extra Callgrind arguments}, specify additional arguments
field, limit the amount of results the profiler gives you to increase for launching the executable.
profiler performance.
You can collect information about the system call times and the number of In the \uicontrol {Result view: Minimum event cost} and
global bus events of the event type \c Ge that are executed. \uicontrol {Visualization: Minimum event cost} fields,
limit the amount of results the profiler presents and
visualizes to increase profiler performance.
To show additional information about events in tooltips, select
\uicontrol {Show additional information for events in tooltips}.
To collect information about the system call times, select
\uicontrol {Collect system call time}. To collect the number of
global bus events of the event type \c Ge that are executed,
select \uicontrol {Collect global bus events}.
\section2 Enabling Full Cache Simulation \section2 Enabling Full Cache Simulation

View File

@@ -47,4 +47,7 @@
The \uicontrol {Conan install} field displays the effective The \uicontrol {Conan install} field displays the effective
build command. You can add arguments for the command in the build command. You can add arguments for the command in the
\uicontrol {Additional arguments} field. \uicontrol {Additional arguments} field.
Select \uicontrol {Build missing} to build packages from source if binary
packages are not found.
*/ */

View File

@@ -50,7 +50,9 @@
sources. Because the client has a local cache for package storage, you can sources. Because the client has a local cache for package storage, you can
work offline, as long as no new packages are needed from remote servers. work offline, as long as no new packages are needed from remote servers.
To use Conan, install it by using the Qt installer. To use Conan, install it by using the Qt installer or the tools provided by
your operating system. For example, on Windows, you can use the
\c {choco install conan} or \{pip install conan} command.
To enable the experimental Conan plugin, select \uicontrol Help > To enable the experimental Conan plugin, select \uicontrol Help >
\uicontrol {About Plugins} > \uicontrol Utilities > \uicontrol Conan. \uicontrol {About Plugins} > \uicontrol Utilities > \uicontrol Conan.
@@ -63,4 +65,7 @@
Then, you must edit the build settings of the project to specify the Then, you must edit the build settings of the project to specify the
location of the file and the contents of the Conan install command. location of the file and the contents of the Conan install command.
For more information, see \l {Conan Build Steps}. For more information, see \l {Conan Build Steps}.
Alternatively, you can automatically set up the Conan package manager for
use with CMake. For more information, see \l{Using CMake with Conan}.
*/ */

View File

@@ -57,6 +57,10 @@
\image qtcreator-find-references-to-symbol-under-cursor.png "Search results for finding references to symbols" \image qtcreator-find-references-to-symbol-under-cursor.png "Search results for finding references to symbols"
To view the same results color-coded according to the access type, such as
read, write, or declaration, select \uicontrol Tools > \uicontrol {C++} >
\uicontrol {Find References with Access Type}.
\note You can also select \uicontrol Edit > \uicontrol {Find/Replace} > \note You can also select \uicontrol Edit > \uicontrol {Find/Replace} >
\uicontrol {Advanced Find} > \uicontrol {C++ Symbols} to search for \uicontrol {Advanced Find} > \uicontrol {C++ Symbols} to search for
classes, functions, enums, and declarations (including type aliases) either classes, functions, enums, and declarations (including type aliases) either

View File

@@ -29,7 +29,7 @@
\title Meson Build Configuration \title Meson Build Configuration
\image qtcreator-meson-build-settings.png \image qtcreator-meson-build-settings.png "Meson build settings"
Settings are grouped by category by Meson. All items are user modifiable Settings are grouped by category by Meson. All items are user modifiable
except \c backend which is forced to Ninja, \c {buildtype}, \c debug as well except \c backend which is forced to Ninja, \c {buildtype}, \c debug as well
@@ -45,6 +45,8 @@
\note Any modified setting will remain in bold until \uicontrol \note Any modified setting will remain in bold until \uicontrol
{Apply configuration changes} is selected. {Apply configuration changes} is selected.
For more information about using Meson, see \l{Setting Up Meson}.
\section1 Meson Build Steps \section1 Meson Build Steps
\QC builds Meson projects by running \c {ninja -v target}. \QC builds Meson projects by running \c {ninja -v target}.
@@ -52,7 +54,7 @@
You can add arguments and targets for the build command in You can add arguments and targets for the build command in
\uicontrol {Build Steps}. \uicontrol {Build Steps}.
\image qtcreator-meson-build-steps.png \image qtcreator-meson-build-steps.png "Meson build steps"
The build errors and warnings are parsed and displayed in the The build errors and warnings are parsed and displayed in the
\uicontrol Issues output pane. \uicontrol Issues output pane.
@@ -62,7 +64,7 @@
When building with Meson, you can add arguments and targets for the clean When building with Meson, you can add arguments and targets for the clean
command in \uicontrol {Clean Steps}. command in \uicontrol {Clean Steps}.
\image qtcreator-meson-clean-steps.png \image qtcreator-meson-clean-steps.png "Meson clean steps"
The build errors and warnings are parsed and displayed in the The build errors and warnings are parsed and displayed in the
\uicontrol Issues output pane. \uicontrol Issues output pane.

View File

@@ -73,7 +73,7 @@
\uicontrol Tools > \uicontrol Options > \uicontrol Kits > \uicontrol Kits \uicontrol Tools > \uicontrol Options > \uicontrol Kits > \uicontrol Kits
tab to add the Meson and Ninja tools to a build and run kit: tab to add the Meson and Ninja tools to a build and run kit:
\image qtcreator-kits.png \image qtcreator-kits-meson.png "Setting Meson executable in Kit options"
For more information, see \l {Adding Kits}. For more information, see \l {Adding Kits}.

View File

@@ -89,9 +89,13 @@
\QC project wizard templates create Qt Quick projects that can be compiled \QC project wizard templates create Qt Quick projects that can be compiled
because they are set up to use the Qt Resource System. To compile QML code, because they are set up to use the Qt Resource System. To compile QML code,
select \uicontrol Enable in the \uicontrol {Use qmlcachegen} field. To select \uicontrol Enable in the \uicontrol {Qt Quick Compiler} field. To
use default settings, select \uicontrol {Leave at Default}. use default settings, select \uicontrol {Leave at Default}.
You can specify default behavior for compiling QML code in \uicontrol Tools
> \uicontrol Options > \uicontrol {Build & Run} > \uicontrol Qmake >
\uicontrol {Use qmlcachegen}.
\section1 qmake Build Steps \section1 qmake Build Steps
\QC builds qmake projects by running the \c make or \c nmake command from \QC builds qmake projects by running the \c make or \c nmake command from
@@ -109,6 +113,9 @@
\uicontrol {Override MAKEFLAGS} check box to override existing MAKEFLAGS \uicontrol {Override MAKEFLAGS} check box to override existing MAKEFLAGS
variables. variables.
Select \uicontrol {Disable in subdirectories} to execute the build step
only for a top-level build.
Select \uicontrol {Add Build Step} > \uicontrol {IncrediBuild for Linux} or Select \uicontrol {Add Build Step} > \uicontrol {IncrediBuild for Linux} or
\uicontrol {IncrediBuild for Windows} to accelerate builds by using \uicontrol {IncrediBuild for Windows} to accelerate builds by using
\l{IncrediBuild Build Configuration}{IncrediBuild}. \l{IncrediBuild Build Configuration}{IncrediBuild}.

View File

@@ -54,18 +54,6 @@
\list \list
\li GNU Compiler Collection (GCC) is a compiler for Linux and
\macos.
\li \MinGW (Minimalist GNU for Windows) is a native software port of GCC
and GNU Binutils for use in the development of native Microsoft
Windows applications on Windows. \MinGW is distributed together with
\QC and Qt for Windows.
\li ICC (Intel C++ Compiler) is a group of C and C++ compilers.
Only the GCC-compatible variant, available for Linux and \macos,
is currently supported by \QC.
\li Clang is a C, C++, Objective C, and Objective C++ front-end for the \li Clang is a C, C++, Objective C, and Objective C++ front-end for the
LLVM compiler for Windows, Linux, and \macos. LLVM compiler for Windows, Linux, and \macos.
@@ -73,6 +61,21 @@
is an alternative command-line interface to Clang that is compatible is an alternative command-line interface to Clang that is compatible
with the Visual C++ compiler, \c cl.exe. with the Visual C++ compiler, \c cl.exe.
\li GNU Compiler Collection (GCC) is a compiler for Linux and
\macos.
\li ICC (Intel C++ Compiler) is a group of C and C++ compilers.
Only the GCC-compatible variant, available for Linux and \macos,
is currently supported by \QC.
\li \MinGW (Minimalist GNU for Windows) is a native software port of GCC
and GNU Binutils for use in the development of native Microsoft
Windows applications on Windows. \MinGW is distributed together with
\QC and Qt for Windows.
\li MSVC (Microsoft Visual C++ Compiler) is a C++ compiler that is
installed with Microsoft Visual Studio.
\li Nim is the Nim Compiler for Windows, Linux, and \macos. \li Nim is the Nim Compiler for Windows, Linux, and \macos.
\li QCC is the interface for compiling C++ applications for QNX. \li QCC is the interface for compiling C++ applications for QNX.
@@ -100,6 +103,9 @@
\endlist \endlist
The emscripten compiler is tool chain for compiling to
\l{Building Applications for the Web}{WebAssembly}.
\section1 Redetecting Compilers \section1 Redetecting Compilers
When \QC finds an x86_64 GCC compiler, it sets up an instance for the native When \QC finds an x86_64 GCC compiler, it sets up an instance for the native
@@ -118,31 +124,37 @@
to the directory where the compiler is located and select to the directory where the compiler is located and select
the application binary interface (ABI) version from the list of available the application binary interface (ABI) version from the list of available
versions. You can also create a custom ABI definition. versions. You can also create a custom ABI definition.
For QCC, also specify the path to the QNX Software Development Platform (SDP). For QCC, also specify the path to the QNX Software Development Platform
(SDP) in the \uicontrol {SPD path} field.
To enable Microsoft Visual C++ Compilers (MSVC) and clang-cl to find system To enable Microsoft Visual C++ Compilers (MSVC) and clang-cl to find system
headers, libraries, and the linker, \QC executes them inside a command headers, libraries, and the linker, \QC executes them inside a command
prompt where the environment has been set up using \c {vcvarsall.bat}. For prompt where the environment has been set up using \c {vcvarsall.bat}. For
these compilers, you also specify the path to the script that sets up the these compilers, you also specify the path to the script that sets up the
command prompt. command prompt in the \uicontrol Initialization field.
You specify the compiler to use for each kit in \uicontrol Tools > You specify the compiler to use for each kit in \uicontrol Tools >
\uicontrol Options > \uicontrol Kits. \uicontrol Options > \uicontrol Kits.
To add C or C++ compilers: To add a C or C++ compiler, select \uicontrol Tools > \uicontrol Options >
\uicontrol Kits > \uicontrol Compilers > \uicontrol Add. Select a compiler
in the list, and then select \uicontrol C or \uicontrol C++.
\list 1 To clone the selected compiler, select \uicontrol Clone.
\li Select \uicontrol Tools > \uicontrol Options > The settings to specify depend on the compiler:
\uicontrol Kits > \uicontrol Compilers > \uicontrol Add,
then select a compiler in the list, and then select \uicontrol C or
\uicontrol C++ to add a C or C++ compiler.
To clone the selected compiler, select \uicontrol Clone. \list
\li In the \uicontrol Name field, enter a name for the compiler to \li In the \uicontrol Name field, enter a name for the compiler to
identify it in \QC. identify it in \QC.
\image qtcreator-options-cpp-compilers.png "Adding a clang-cl compiler"
\li In the \uicontrol Initialization field, select the
\c {vcvarsall.bat} file for setting up the command
prompt to use.
\li In the \uicontrol {Compiler path} field, enter the path to the \li In the \uicontrol {Compiler path} field, enter the path to the
directory where the compiler is located. directory where the compiler is located.
@@ -154,7 +166,16 @@
the linker that specify the architecture on the target platform. the linker that specify the architecture on the target platform.
The linker flags are used only when building with Qbs. The linker flags are used only when building with Qbs.
The other settings to specify depend on the compiler. \image qtcreator-options-clang-compilers.png "Adding a Clang compiler"
\li In the \uicontrol {Parent toolchain} field, select a \MinGW
compiler, which is needed because Clang does not have its own
standard library.
\li In the \uicontrol {SPD path} field, specify the path to the QNX
Software Development Platform (SDP).
\image qtcreator-options-qcc-compilers.png "Adding a QCC compiler"
\li In the \uicontrol ABI field, provide an identification for the \li In the \uicontrol ABI field, provide an identification for the
target architecture. This is used to warn about ABI mismatches target architecture. This is used to warn about ABI mismatches

View File

@@ -48,6 +48,9 @@
more information, see \l{Using the Performance Analyzer}. To use default more information, see \l{Using the Performance Analyzer}. To use default
settings, select \uicontrol {Leave at Default}. settings, select \uicontrol {Leave at Default}.
For more information about the QML and Qt Quick options, see
\l{Compiling QML}.
For more information about configuring Qbs, see \l{Setting Up Qbs}. For more information about configuring Qbs, see \l{Setting Up Qbs}.
\section1 Qbs Build Steps \section1 Qbs Build Steps

View File

@@ -1,6 +1,6 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2017 The Qt Company Ltd. ** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/ ** Contact: https://www.qt.io/licensing/
** **
** This file is part of the Qt Creator documentation. ** This file is part of the Qt Creator documentation.
@@ -45,9 +45,19 @@
\image qtcreator-analyzer-settings.png "Valgrind Settings" \image qtcreator-analyzer-settings.png "Valgrind Settings"
\li In \uicontrol {Valgrind executable}, specify the path to the
Valgrind executable.
\li In \uicontrol {Valgrind arguments}, specify additional arguments
for Valgrind.
\li In \uicontrol {Detect self-modifying code}, select whether to
detect self-modifying code and where to detect it: only on stack,
everywhere, or everywhere except in file-backend mappings.
\endlist \endlist
For more information about the settings, see: For more information about the CallGrind and MemCheck settings, see:
\list \list

View File

@@ -212,7 +212,8 @@
\list 1 \list 1
\li Select \uicontrol Change next to the \li In \uicontrol Tools > \uicontrol Options > \uicontrol Kits, select
the kit, and then select \uicontrol Change next to the
\uicontrol {Additional Qbs Profile Settings} field to open the \uicontrol {Additional Qbs Profile Settings} field to open the
\uicontrol {Custom Properties} dialog. \uicontrol {Custom Properties} dialog.

View File

@@ -102,6 +102,7 @@
\li \l{Developing Qt Quick Applications} \li \l{Developing Qt Quick Applications}
\list \list
\li \l {Creating Qt Quick Projects} \li \l {Creating Qt Quick Projects}
\li \l {Using \QMLD}
\li \l {Converting UI Projects to Applications} \li \l {Converting UI Projects to Applications}
\li \l {UI Files} \li \l {UI Files}
\li \l {Using QML Modules with Plugins} \li \l {Using QML Modules with Plugins}

View File

@@ -61,6 +61,11 @@
You can use wizards to create Qt Quick projects. You can use wizards to create Qt Quick projects.
\li \l {Using \QMLD}
You can enable the \QMLD plugin to visually edit
\l{UI Files}{UI files} (.ui.qml).
\li \l {Converting UI Projects to Applications} \li \l {Converting UI Projects to Applications}
Qt Quick UI projects (.qmlproject) are useful for creating user Qt Quick UI projects (.qmlproject) are useful for creating user
@@ -73,7 +78,7 @@
If you switch between \QC and \QDS or cooperate with designers on If you switch between \QC and \QDS or cooperate with designers on
a project, you might encounter .ui.qml files. They are intended to a project, you might encounter .ui.qml files. They are intended to
be edited in \QDS only, so you need to be careful not to break the be edited in \QDS only, so you need to be careful not to break the
code. code. To visually edit the files in \QC, enable the \QMLD plugin.
\li \l{Using QML Modules with Plugins} \li \l{Using QML Modules with Plugins}

View File

@@ -32,7 +32,7 @@
/*! /*!
\previouspage creator-visual-editor.html \previouspage creator-visual-editor.html
\page quick-projects.html \page quick-projects.html
\nextpage quick-converting-ui-projects.html \nextpage creator-qtquickdesigner-plugin.html
\title Creating Qt Quick Projects \title Creating Qt Quick Projects

View File

@@ -0,0 +1,55 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Creator documentation.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Free Documentation License Usage
** Alternatively, this file may be used under the terms of the GNU Free
** Documentation License version 1.3 as published by the Free Software
** Foundation and appearing in the file included in the packaging of
** this file. Please review the following information to ensure
** the GNU Free Documentation License version 1.3 requirements
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
**
****************************************************************************/
/*!
\page creator-qtquickdesigner-plugin.html
\previouspage quick-projects.html
\nextpage quick-converting-ui-projects.html
\title Using \QMLD
We recommend that you use a separate visual editor,
\l{Qt Design Studio Manual}{\QDS} to open and edit
\l{UI Files}{UI files} (.ui.qml).
However, you can enable the \QMLD plugin in \QC for editing
UI files. The functionality is restricted and not all \QDS
features are supported.
To use \QMLD, switch to the \uicontrol Design mode when a ui.qml or or .qml
file is open.
For more information about using \QMLD, see \l{Qt Design Studio Manual}.
\section1 Enabling the \QMLD Plugin
To enable the \QMLD plugin:
\list 1
\li Select \uicontrol Help > \uicontrol {About Plugins} >
\uicontrol {Qt Quick} > \uicontrol {QmlDesigner}.
\li Select \uicontrol {Restart Now} to restart \QC and load the plugin.
\endlist
*/

View File

@@ -40,8 +40,11 @@
layers that are imported into \QDS as separate files. layers that are imported into \QDS as separate files.
\li Use descriptive and unique IDs to avoid duplicate asset names and IDs \li Use descriptive and unique IDs to avoid duplicate asset names and IDs
in the generated UI. in the generated UI.
\li Use XD Components and instances to reuse the UI elements.
\endlist \endlist
\note Although \QBXD preserves the XD Component and instance's relationship, overrides
and states are not yet supported.
To use the fonts that you use in Adobe XD also in \QDS, you need to import To use the fonts that you use in Adobe XD also in \QDS, you need to import
them to \QDS as assets. \QDS deploys them to devices when you preview the them to \QDS as assets. \QDS deploys them to devices when you preview the
@@ -60,11 +63,15 @@
The following design elements might not be exported as expected. The following design elements might not be exported as expected.
\list \list
\li Components \li Component states
\li Component overrides
\li Prototype \li Prototype
\li Repeat Grid \li Repeat Grid
\endlist \endlist
\note Adobe XD's plugin API support is incomplete. Specifically, the support
for XD Components is limited. This might change in the future and \QBXD might
extend the XD Component support.
\section2 Using Artboards \section2 Using Artboards
@@ -120,6 +127,8 @@
properties will be ignored if \uicontrol {Component} is defined properties will be ignored if \uicontrol {Component} is defined
for a text layer, but explicit properties defined in the \uicontrol for a text layer, but explicit properties defined in the \uicontrol
{Properties} field will be applied. {Properties} field will be applied.
\li Select the \uicontrol {Render Text} check box to render the text layer
as an image
\li In the \uicontrol {Imports} field, enter additional import statements \li In the \uicontrol {Imports} field, enter additional import statements
to have them added to the generated code file. For example, to use to have them added to the generated code file. For example, to use
Qt Quick Controls 2.3, you need the import statement Qt Quick Controls 2.3, you need the import statement
@@ -134,10 +143,13 @@
bounding rectangle. bounding rectangle.
\li Select the \uicontrol Visible check box to determine the visibility \li Select the \uicontrol Visible check box to determine the visibility
of the layer in the generated UI in \QDS. of the layer in the generated UI in \QDS.
\li Select \uicontrol Export to export the document into a .qtbridge \li Select \uicontrol Export to launch the export dialog to export the document
archive. into a .qtbridge archive.
\endlist \endlist
\note XD Components can not be skipped and Text layers can only be merged when
\uicontrol {Render Text} is selected.
\section2 Export Defaults \section2 Export Defaults
@@ -145,9 +157,9 @@
By default: By default:
\list \list
\li Artboards are exported as \e components. \li Artboards and XD Components are exported as \e components.
\li Immediate children of an Artboard and Text layers are exported as \li Component instances, Text layers and immediate children of an Artboard
\e child. are exported as \e child.
\li Any layer not falling under the aforementioned criteria is exported \li Any layer not falling under the aforementioned criteria is exported
as \e merged. as \e merged.
\li Images are exported as PNGs by default with no Hi-DPI images. \li Images are exported as PNGs by default with no Hi-DPI images.

View File

@@ -893,19 +893,31 @@ void Qt5InformationNodeInstanceServer::doRender3DEditView()
// Key number is selected so that it is unlikely to conflict other ImageContainer use. // Key number is selected so that it is unlikely to conflict other ImageContainer use.
auto imgContainer = ImageContainer(-1, renderImage, 2100000000); auto imgContainer = ImageContainer(-1, renderImage, 2100000000);
// send the rendered image to creator process // If we have only one or no render queued, send the result to the creator side.
nodeInstanceClient()->handlePuppetToCreatorCommand({PuppetToCreatorCommand::Render3DView, // Otherwise, we'll hold on that until we have rendered all pending frames to ensure sent
QVariant::fromValue(imgContainer)}); // results are correct.
if (m_need3DEditViewRender <= 1) {
nodeInstanceClient()->handlePuppetToCreatorCommand({PuppetToCreatorCommand::Render3DView,
QVariant::fromValue(imgContainer)});
#ifdef QUICK3D_PARTICLES_MODULE
if (m_need3DEditViewRender == 0 && ViewConfig::isParticleViewMode()
&& m_particleAnimationDriver && m_particleAnimationDriver->isAnimating()) {
m_need3DEditViewRender = 1;
}
#endif
}
if (m_need3DEditViewRender > 0) { if (m_need3DEditViewRender > 0) {
m_render3DEditViewTimer.start(0); // We queue another render even if the requested render count was one, because another
// render is needed to ensure gizmo geometries are properly updated.
// Note that while in theory this seems that we shouldn't need to send the image to
// creator side when m_need3DEditViewRender is one, we need to do it to ensure
// smooth operation when objects are moved via drag, which triggers new renders
// continueously.
m_render3DEditViewTimer.start(17); // 16.67ms = ~60fps, rounds up to 17
--m_need3DEditViewRender; --m_need3DEditViewRender;
} }
#ifdef QUICK3D_PARTICLES_MODULE
if (ViewConfig::isParticleViewMode()
&& m_particleAnimationDriver && m_particleAnimationDriver->isAnimating()) {
m_need3DEditViewRender++;
}
#endif
#ifdef FPS_COUNTER #ifdef FPS_COUNTER
// Force constant rendering for accurate fps count // Force constant rendering for accurate fps count
if (!m_render3DEditViewTimer.isActive()) if (!m_render3DEditViewTimer.isActive())
@@ -1981,8 +1993,8 @@ void Qt5InformationNodeInstanceServer::view3DAction(const View3DActionCommand &c
break; break;
case View3DActionCommand::CameraToggle: case View3DActionCommand::CameraToggle:
updatedState.insert("usePerspective", command.isEnabled()); updatedState.insert("usePerspective", command.isEnabled());
// It can take a couple frames to properly update icon gizmo positions, so render 3 frames // It can take a couple frames to properly update icon gizmo positions
renderCount = 3; renderCount = 2;
break; break;
case View3DActionCommand::OrientationToggle: case View3DActionCommand::OrientationToggle:
updatedState.insert("globalOrientation", command.isEnabled()); updatedState.insert("globalOrientation", command.isEnabled());
@@ -1994,11 +2006,9 @@ void Qt5InformationNodeInstanceServer::view3DAction(const View3DActionCommand &c
updatedState.insert("showGrid", command.isEnabled()); updatedState.insert("showGrid", command.isEnabled());
break; break;
#ifdef QUICK3D_PARTICLES_MODULE #ifdef QUICK3D_PARTICLES_MODULE
case View3DActionCommand::Edit3DParticleModeToggle:
updatedState.insert("enableParticleViewMode", command.isEnabled());
break;
case View3DActionCommand::ParticlesPlay: case View3DActionCommand::ParticlesPlay:
m_particleAnimationPlaying = command.isEnabled(); m_particleAnimationPlaying = command.isEnabled();
updatedState.insert("particlePlay", command.isEnabled());
if (m_particleAnimationPlaying) { if (m_particleAnimationPlaying) {
m_particleAnimationDriver->reset(); m_particleAnimationDriver->reset();
m_particleAnimationDriver->restart(); m_particleAnimationDriver->restart();
@@ -2230,8 +2240,8 @@ void Qt5InformationNodeInstanceServer::update3DViewState(const Update3dViewState
auto helper = qobject_cast<QmlDesigner::Internal::GeneralHelper *>(m_3dHelper); auto helper = qobject_cast<QmlDesigner::Internal::GeneralHelper *>(m_3dHelper);
if (helper) if (helper)
helper->storeToolState(helper->globalStateId(), helper->rootSizeKey(), QVariant(command.size()), 0); helper->storeToolState(helper->globalStateId(), helper->rootSizeKey(), QVariant(command.size()), 0);
// Queue three renders to make sure icon gizmos update properly // Queue two renders to make sure all gizmos update properly
render3DEditView(3); render3DEditView(2);
} }
} }
#else #else

View File

@@ -127,6 +127,7 @@ Item {
Image { Image {
id: statusIcon id: statusIcon
Layout.alignment: Qt.AlignTop
asynchronous: false asynchronous: false
} }
@@ -191,25 +192,29 @@ Item {
SC.ComboBox { // Screen Size ComboBox SC.ComboBox { // Screen Size ComboBox
id: screenSizeComboBox id: screenSizeComboBox
actionIndicatorVisible: false actionIndicatorVisible: false
currentIndex: 1 currentIndex: -1
model: screenSizeModel model: screenSizeModel
textRole: "display" textRole: "display"
width: parent.width width: parent.width
font.pixelSize: DialogValues.defaultPixelSize font.pixelSize: DialogValues.defaultPixelSize
onActivated: (index) => { onActivated: (index) => {
// NOTE: item 0 is activated when the screenSizeModel is reset dialogBox.setScreenSizeIndex(index);
dialogBox.setScreenSizeIndex(index);
var r = screenSizeModel.screenSizes(index); var size = screenSizeModel.screenSizes(index);
widthField.realValue = r.width; widthField.realValue = size.width;
heightField.realValue = r.height; heightField.realValue = size.height;
} }
Connections { Connections {
target: screenSizeModel target: screenSizeModel
function onModelReset() { function onModelReset() {
screenSizeComboBox.activated(screenSizeComboBox.currentIndex) var newIndex = screenSizeComboBox.currentIndex > -1
? screenSizeComboBox.currentIndex
: dialogBox.screenSizeIndex()
screenSizeComboBox.currentIndex = newIndex
screenSizeComboBox.activated(newIndex)
} }
} }
} // Screen Size ComboBox } // Screen Size ComboBox

View File

@@ -134,6 +134,7 @@ GridView {
width: DialogValues.projectItemWidth width: DialogValues.projectItemWidth
height: DialogValues.projectItemHeight height: DialogValues.projectItemHeight
background: null
function fontIconCode(index) { function fontIconCode(index) {
var code = projectModel.fontIconCode(index) var code = projectModel.fontIconCode(index)

View File

@@ -155,8 +155,8 @@ DStoolTipText=ffdadada
DSUnimportedModuleColor=ffe33c2e DSUnimportedModuleColor=ffe33c2e
DSBackgroundColorAlternate=alternateBackground DSBackgroundColorAlternate=ff323232
DSBackgroundColorNormal=normalBackground DSBackgroundColorNormal=ff1f1f1f
;DS controls theme END ;DS controls theme END

View File

@@ -146,8 +146,8 @@ DStoolTipText=ffdadada
DSUnimportedModuleColor=ffe33c2e DSUnimportedModuleColor=ffe33c2e
DSBackgroundColorAlternate=alternateBackground DSBackgroundColorAlternate=ffeaeaea
DSBackgroundColorNormal=normalBackground DSBackgroundColorNormal=ffd8d8d8
;DS controls theme END ;DS controls theme END

View File

@@ -160,8 +160,8 @@ DStoolTipText=ffdadada
DSUnimportedModuleColor=ffe33c2e DSUnimportedModuleColor=ffe33c2e
DSBackgroundColorAlternate=alternateBackground DSBackgroundColorAlternate=ffeaeaea
DSBackgroundColorNormal=normalBackground DSBackgroundColorNormal=ffd8d8d8
;DS controls theme END ;DS controls theme END

View File

@@ -159,8 +159,8 @@ DStoolTipText=ffdadada
DSUnimportedModuleColor=ffe33c2e DSUnimportedModuleColor=ffe33c2e
DSBackgroundColorAlternate=alternateBackground DSBackgroundColorAlternate=ff323232
DSBackgroundColorNormal=normalBackground DSBackgroundColorNormal=ff1f1f1f
;DS controls theme END ;DS controls theme END

View File

@@ -155,8 +155,8 @@ DStoolTipText=ffdadada
DSUnimportedModuleColor=ffe33c2e DSUnimportedModuleColor=ffe33c2e
DSBackgroundColorAlternate=alternateBackground DSBackgroundColorAlternate=ffeaeaea
DSBackgroundColorNormal=normalBackground DSBackgroundColorNormal=ffd8d8d8
;DS controls theme END ;DS controls theme END

View File

@@ -153,8 +153,8 @@ DStoolTipText=ffdadada
DSUnimportedModuleColor=ffe33c2e DSUnimportedModuleColor=ffe33c2e
DSBackgroundColorAlternate=alternateBackground DSBackgroundColorAlternate=ff323232
DSBackgroundColorNormal=normalBackground DSBackgroundColorNormal=ff1f1f1f
;DS controls theme END ;DS controls theme END

View File

@@ -209,7 +209,7 @@ void ContextPaneWidgetRectangle::onColorNoneClicked()
if (ui->colorNone->isChecked()) { if (ui->colorNone->isChecked()) {
ui->colorGradient->setEnabled(isGradientEditingEnabled()); ui->colorGradient->setEnabled(isGradientEditingEnabled());
emit removeAndChangeProperty(QLatin1String("gradient"), QLatin1String("color"), emit removeAndChangeProperty(QLatin1String("gradient"), QLatin1String("color"),
QLatin1String("transparent"), true); QLatin1String("\"transparent\""), true);
} }
ui->colorGradient->setEnabled(isGradientEditingEnabled()); ui->colorGradient->setEnabled(isGradientEditingEnabled());
} }

View File

@@ -1324,6 +1324,7 @@ QAction *BoolAspect::action()
auto act = BaseAspect::action(); // Creates it. auto act = BaseAspect::action(); // Creates it.
act->setCheckable(true); act->setCheckable(true);
act->setChecked(value()); act->setChecked(value());
act->setToolTip(toolTip());
connect(act, &QAction::triggered, this, [this](bool newValue) { connect(act, &QAction::triggered, this, [this](bool newValue) {
// The check would be nice to have in simple conditions, but if we // The check would be nice to have in simple conditions, but if we
// have an action that's used both on a settings page and as action // have an action that's used both on a settings page and as action

View File

@@ -61,6 +61,7 @@ public:
Ui::ProjectIntroPage m_ui; Ui::ProjectIntroPage m_ui;
bool m_complete = false; bool m_complete = false;
QRegularExpressionValidator m_projectNameValidator; QRegularExpressionValidator m_projectNameValidator;
QString m_projectNameValidatorUserMessage;
bool m_forceSubProject = false; bool m_forceSubProject = false;
FilePaths m_projectDirectories; FilePaths m_projectDirectories;
}; };
@@ -124,10 +125,11 @@ void ProjectIntroPage::setFilePath(const FilePath &path)
d->m_ui.pathChooser->setFilePath(path); d->m_ui.pathChooser->setFilePath(path);
} }
void ProjectIntroPage::setProjectNameRegularExpression(const QRegularExpression &regEx) void ProjectIntroPage::setProjectNameRegularExpression(const QRegularExpression &regEx, const QString &userErrorMessage)
{ {
Q_ASSERT_X(regEx.isValid(), Q_FUNC_INFO, qPrintable(regEx.errorString())); Q_ASSERT_X(regEx.isValid(), Q_FUNC_INFO, qPrintable(regEx.errorString()));
d->m_projectNameValidator.setRegularExpression(regEx); d->m_projectNameValidator.setRegularExpression(regEx);
d->m_projectNameValidatorUserMessage = userErrorMessage;
} }
void ProjectIntroPage::setProjectName(const QString &name) void ProjectIntroPage::setProjectName(const QString &name)
@@ -263,8 +265,10 @@ bool ProjectIntroPage::validateProjectName(const QString &name, QString *errorMe
// a more detailed error message // a more detailed error message
if (validatorState != QValidator::Acceptable && (pos == -1 || pos >= name.count())) { if (validatorState != QValidator::Acceptable && (pos == -1 || pos >= name.count())) {
if (errorMessage) { if (errorMessage) {
*errorMessage = tr("Name does not match \"%1\".").arg( if (d->m_projectNameValidatorUserMessage.isEmpty())
d->m_projectNameValidator.regularExpression().pattern()); *errorMessage = tr("Project name is invalid.");
else
*errorMessage = d->m_projectNameValidatorUserMessage;
} }
return false; return false;
} }

View File

@@ -80,7 +80,7 @@ public slots:
void setProjectName(const QString &name); void setProjectName(const QString &name);
void setDescription(const QString &description); void setDescription(const QString &description);
void setUseAsDefaultPath(bool u); void setUseAsDefaultPath(bool u);
void setProjectNameRegularExpression(const QRegularExpression &regEx); void setProjectNameRegularExpression(const QRegularExpression &regEx, const QString &userErrorMessage);
private: private:
void slotChanged(); void slotChanged();

View File

@@ -75,7 +75,8 @@ ApkInfo::ApkInfo() :
ProjectExplorer::Constants::ANDROID_ABI_ARMEABI_V7A}), ProjectExplorer::Constants::ANDROID_ABI_ARMEABI_V7A}),
appId(APP_ID), appId(APP_ID),
uploadDir("/data/local/tmp/" APP_ID "/"), uploadDir("/data/local/tmp/" APP_ID "/"),
activityId(APP_ID "/org.qtproject.qt5.android.bindings.QtActivity"), // TODO Add possibility to run Qt5 built version of Qt Design Viewer
activityId(APP_ID "/org.qtproject.qt.android.bindings.QtActivity"),
name("Qt Design Viewer") name("Qt Design Viewer")
{ {
} }

View File

@@ -227,7 +227,10 @@ void ChooseDirectoryPage::initializePage()
"The files in the Android package source directory are copied to the build directory's " "The files in the Android package source directory are copied to the build directory's "
"Android directory and the default files are overwritten.")); "Android directory and the default files are overwritten."));
m_androidPackageSourceDir->setFilePath(bti.projectFilePath / "android"); const FilePath projectPath = bti.projectFilePath.isFile()
? bti.projectFilePath.parentDir() : bti.projectFilePath;
m_androidPackageSourceDir->setFilePath(projectPath / "android");
connect(m_androidPackageSourceDir, &PathChooser::rawPathChanged, connect(m_androidPackageSourceDir, &PathChooser::rawPathChanged,
this, &ChooseDirectoryPage::checkPackageSourceDir); this, &ChooseDirectoryPage::checkPackageSourceDir);
} else { } else {

View File

@@ -1096,7 +1096,7 @@ public:
const QString &type = {}); const QString &type = {});
void handleSemanticTokens(TextDocument *doc, const QList<ExpandedSemanticToken> &tokens, void handleSemanticTokens(TextDocument *doc, const QList<ExpandedSemanticToken> &tokens,
int version); int version, bool force);
enum class AstCallbackMode { SyncIfPossible, AlwaysAsync }; enum class AstCallbackMode { SyncIfPossible, AlwaysAsync };
using TextDocOrFile = const Utils::variant<const TextDocument *, Utils::FilePath>; using TextDocOrFile = const Utils::variant<const TextDocument *, Utils::FilePath>;
@@ -1294,8 +1294,8 @@ ClangdClient::ClangdClient(Project *project, const Utils::FilePath &jsonDbDir)
setDiagnosticsHandlers(textMarkCreator, hideDiagsHandler); setDiagnosticsHandlers(textMarkCreator, hideDiagsHandler);
setSymbolStringifier(displayNameFromDocumentSymbol); setSymbolStringifier(displayNameFromDocumentSymbol);
setSemanticTokensHandler([this](TextDocument *doc, const QList<ExpandedSemanticToken> &tokens, setSemanticTokensHandler([this](TextDocument *doc, const QList<ExpandedSemanticToken> &tokens,
int version) { int version, bool force) {
d->handleSemanticTokens(doc, tokens, version); d->handleSemanticTokens(doc, tokens, version, force);
}); });
hoverHandler()->setHelpItemProvider([this](const HoverRequest::Response &response, hoverHandler()->setHelpItemProvider([this](const HoverRequest::Response &response,
const DocumentUri &uri) { const DocumentUri &uri) {
@@ -2659,7 +2659,7 @@ static void semanticHighlighter(QFutureInterface<HighlightingResult> &future,
// in the semantic tokens nor in the AST. // in the semantic tokens nor in the AST.
void ClangdClient::Private::handleSemanticTokens(TextDocument *doc, void ClangdClient::Private::handleSemanticTokens(TextDocument *doc,
const QList<ExpandedSemanticToken> &tokens, const QList<ExpandedSemanticToken> &tokens,
int version) int version, bool force)
{ {
SubtaskTimer t(highlightingTimer); SubtaskTimer t(highlightingTimer);
qCDebug(clangdLog) << "handling LSP tokens" << doc->filePath() << tokens.size(); qCDebug(clangdLog) << "handling LSP tokens" << doc->filePath() << tokens.size();
@@ -2670,7 +2670,7 @@ void ClangdClient::Private::handleSemanticTokens(TextDocument *doc,
} }
const auto previous = previousTokens.find(doc); const auto previous = previousTokens.find(doc);
if (previous != previousTokens.end()) { if (previous != previousTokens.end()) {
if (previous->first == tokens && previous->second == version) { if (!force && previous->first == tokens && previous->second == version) {
qCDebug(clangdLogHighlight) << "tokens and version same as last time; nothing to do"; qCDebug(clangdLogHighlight) << "tokens and version same as last time; nothing to do";
return; return;
} }
@@ -3669,12 +3669,11 @@ void ExtraHighlightingResultsCollector::visitNode(const AstNode &node)
if (m_future.isCanceled()) if (m_future.isCanceled())
return; return;
switch (node.fileStatus(m_filePath)) { switch (node.fileStatus(m_filePath)) {
case AstNode::FileStatus::Foreign:
return;
case AstNode::FileStatus::Ours: case AstNode::FileStatus::Ours:
case AstNode::FileStatus::Unknown: case AstNode::FileStatus::Unknown:
collectFromNode(node); collectFromNode(node);
[[fallthrough]]; [[fallthrough]];
case AstNode::FileStatus::Foreign:
case ClangCodeModel::Internal::AstNode::FileStatus::Mixed: { case ClangCodeModel::Internal::AstNode::FileStatus::Mixed: {
const auto children = node.children(); const auto children = node.children();
if (!children) if (!children)

View File

@@ -1252,6 +1252,10 @@ void ClangdTestHighlighting::test_data()
QTest::newRow("simple return") << 841 << 12 << 841 << 15 << QList<int>{C_LOCAL} << 0; QTest::newRow("simple return") << 841 << 12 << 841 << 15 << QList<int>{C_LOCAL} << 0;
QTest::newRow("lambda parameter") << 847 << 49 << 847 << 52 QTest::newRow("lambda parameter") << 847 << 49 << 847 << 52
<< QList<int>{C_PARAMETER, C_DECLARATION} << 0; << QList<int>{C_PARAMETER, C_DECLARATION} << 0;
QTest::newRow("string literal passed to macro from same file") << 853 << 32 << 853 << 38
<< QList<int>{C_STRING} << 0;
QTest::newRow("string literal passed to macro from header file") << 854 << 32 << 854 << 38
<< QList<int>{C_STRING} << 0;
} }
void ClangdTestHighlighting::test() void ClangdTestHighlighting::test()

View File

@@ -846,3 +846,10 @@ void testConstRefAutoLambdaArgs()
{ {
useContainer(FooPtrVector(), [](const auto &arg) {}); useContainer(FooPtrVector(), [](const auto &arg) {});
} }
#define USE_STRING(s) (s)
void useString()
{
const char *s = USE_STRING("TEXT");
s = USE_STRING_FROM_HEADER("TEXT");
}

View File

@@ -0,0 +1 @@
#define USE_STRING_FROM_HEADER(s) (s)

View File

@@ -41,6 +41,7 @@
#include <projectexplorer/projectexplorer.h> #include <projectexplorer/projectexplorer.h>
#include <projectexplorer/runconfiguration.h> #include <projectexplorer/runconfiguration.h>
#include <projectexplorer/target.h> #include <projectexplorer/target.h>
#include <projectexplorer/xcodebuildparser.h>
#include <utils/algorithm.h> #include <utils/algorithm.h>
#include <utils/layoutbuilder.h> #include <utils/layoutbuilder.h>
@@ -285,6 +286,13 @@ void CMakeBuildStep::setupOutputFormatter(Utils::OutputFormatter *formatter)
formatter->addLineParser(progressParser); formatter->addLineParser(progressParser);
cmakeParser->setSourceDirectory(project()->projectDirectory().toString()); cmakeParser->setSourceDirectory(project()->projectDirectory().toString());
formatter->addLineParsers({cmakeParser, new GnuMakeParser}); formatter->addLineParsers({cmakeParser, new GnuMakeParser});
ToolChain *tc = ToolChainKitAspect::cxxToolChain(kit());
OutputTaskParser *xcodeBuildParser = nullptr;
if (tc && tc->targetAbi().os() == Abi::DarwinOS) {
xcodeBuildParser = new XcodebuildParser;
formatter->addLineParser(xcodeBuildParser);
progressParser->setRedirectionDetector(xcodeBuildParser);
}
const QList<Utils::OutputLineParser *> additionalParsers = kit()->createOutputParsers(); const QList<Utils::OutputLineParser *> additionalParsers = kit()->createOutputParsers();
for (Utils::OutputLineParser * const p : additionalParsers) for (Utils::OutputLineParser * const p : additionalParsers)
p->setRedirectionDetector(progressParser); p->setRedirectionDetector(progressParser);

View File

@@ -1014,7 +1014,7 @@ const QList<BuildTargetInfo> CMakeBuildSystem::appTargets() const
BuildTargetInfo bti; BuildTargetInfo bti;
bti.displayName = ct.title; bti.displayName = ct.title;
bti.targetFilePath = ct.executable; bti.targetFilePath = ct.executable;
bti.projectFilePath = ct.sourceDirectory.stringAppended("/"); bti.projectFilePath = ct.sourceDirectory.cleanPath();
bti.workingDirectory = ct.workingDirectory; bti.workingDirectory = ct.workingDirectory;
bti.buildKey = buildKey; bti.buildKey = buildKey;
bti.usesTerminal = !ct.linksToQtGui; bti.usesTerminal = !ct.linksToQtGui;

View File

@@ -159,7 +159,6 @@ CMakeConfigItem::Type CMakeConfigItem::typeStringToType(const QByteArray &type)
if (type == "INTERNAL") if (type == "INTERNAL")
return CMakeConfigItem::INTERNAL; return CMakeConfigItem::INTERNAL;
QTC_CHECK(type == "UNINITIALIZED");
return CMakeConfigItem::UNINITIALIZED; return CMakeConfigItem::UNINITIALIZED;
} }

View File

@@ -87,6 +87,7 @@ const char ZOOM_OUT[] = "QtCreator.ZoomOut";
const char ZOOM_RESET[] = "QtCreator.ZoomReset"; const char ZOOM_RESET[] = "QtCreator.ZoomReset";
const char NEW[] = "QtCreator.New"; const char NEW[] = "QtCreator.New";
const char NEW_FILE[] = "QtCreator.NewFile";
const char OPEN[] = "QtCreator.Open"; const char OPEN[] = "QtCreator.Open";
const char OPEN_WITH[] = "QtCreator.OpenWith"; const char OPEN_WITH[] = "QtCreator.OpenWith";
const char REVERTTOSAVED[] = "QtCreator.RevertToSaved"; const char REVERTTOSAVED[] = "QtCreator.RevertToSaved";

View File

@@ -54,6 +54,9 @@ static LocatorWidget *locatorWidget()
{ {
static QPointer<LocatorPopup> popup; static QPointer<LocatorPopup> popup;
QWidget *window = ICore::dialogParent()->window(); QWidget *window = ICore::dialogParent()->window();
// if that is a popup, try to find a better one
if (window->windowFlags() & Qt::Popup && window->parentWidget())
window = window->parentWidget()->window();
if (auto *widget = Aggregation::query<LocatorWidget>(window)) { if (auto *widget = Aggregation::query<LocatorWidget>(window)) {
if (popup) if (popup)
popup->close(); popup->close();

View File

@@ -360,21 +360,40 @@ void LocatorPopup::updateWindow()
bool LocatorPopup::event(QEvent *event) bool LocatorPopup::event(QEvent *event)
{ {
if (event->type() == QEvent::ParentChange) if (event->type() == QEvent::ParentChange) {
updateWindow(); updateWindow();
else if (event->type() == QEvent::Show) } else if (event->type() == QEvent::Show) {
// make sure the popup has correct position before it becomes visible // make sure the popup has correct position before it becomes visible
doUpdateGeometry(); doUpdateGeometry();
else if (event->type() == QEvent::LayoutRequest) } else if (event->type() == QEvent::LayoutRequest) {
// completion list resizes after first items are shown --> LayoutRequest // completion list resizes after first items are shown --> LayoutRequest
QMetaObject::invokeMethod(this, &LocatorPopup::doUpdateGeometry, Qt::QueuedConnection); QMetaObject::invokeMethod(this, &LocatorPopup::doUpdateGeometry, Qt::QueuedConnection);
} else if (event->type() == QEvent::ShortcutOverride) {
// if we (the popup) has focus, we need to handle escape manually (Windows)
auto ke = static_cast<QKeyEvent *>(event);
if (ke->modifiers() == Qt::NoModifier && ke->key() == Qt::Key_Escape)
event->accept();
} else if (event->type() == QEvent::KeyPress) {
// if we (the popup) has focus, we need to handle escape manually (Windows)
auto ke = static_cast<QKeyEvent *>(event);
if (ke->modifiers() == Qt::NoModifier && ke->key() == Qt::Key_Escape)
hide();
}
return QWidget::event(event); return QWidget::event(event);
} }
bool LocatorPopup::eventFilter(QObject *watched, QEvent *event) bool LocatorPopup::eventFilter(QObject *watched, QEvent *event)
{ {
if (watched == m_window && event->type() == QEvent::Resize) if (watched == m_tree && event->type() == QEvent::FocusOut) {
// if the tree had focus and another application is brought to foreground,
// we need to hide the popup because it otherwise stays on top of
// everything else (even other applications) (Windows)
auto fe = static_cast<QFocusEvent *>(event);
if (fe->reason() == Qt::ActiveWindowFocusReason && !QApplication::activeWindow())
hide();
} else if (watched == m_window && event->type() == QEvent::Resize) {
doUpdateGeometry(); doUpdateGeometry();
}
return QWidget::eventFilter(watched, event); return QWidget::eventFilter(watched, event);
} }
@@ -412,6 +431,7 @@ LocatorPopup::LocatorPopup(LocatorWidget *locatorWidget, QWidget *parent)
m_tree->setFrameStyle(QFrame::NoFrame); // tool tip already includes a frame m_tree->setFrameStyle(QFrame::NoFrame); // tool tip already includes a frame
m_tree->setModel(locatorWidget->model()); m_tree->setModel(locatorWidget->model());
m_tree->setTextElideMode(Qt::ElideMiddle); m_tree->setTextElideMode(Qt::ElideMiddle);
m_tree->installEventFilter(this);
auto layout = new QVBoxLayout; auto layout = new QVBoxLayout;
layout->setSizeConstraint(QLayout::SetMinimumSize); layout->setSizeConstraint(QLayout::SetMinimumSize);

View File

@@ -527,7 +527,9 @@ void MainWindow::registerDefaultActions()
// New File Action // New File Action
QIcon icon = QIcon::fromTheme(QLatin1String("document-new"), Utils::Icons::NEWFILE.icon()); QIcon icon = QIcon::fromTheme(QLatin1String("document-new"), Utils::Icons::NEWFILE.icon());
QString newActionText = isQtDesignStudio() ? tr("&New Project...") : tr("&New File or Project...");
const bool isQDS = isQtDesignStudio();
const QString newActionText = isQDS ? tr("&New Project...") : tr("&New File or Project...");
m_newAction = new QAction(icon, newActionText, this); m_newAction = new QAction(icon, newActionText, this);
cmd = ActionManager::registerAction(m_newAction, Constants::NEW); cmd = ActionManager::registerAction(m_newAction, Constants::NEW);
cmd->setDefaultKeySequence(QKeySequence::New); cmd->setDefaultKeySequence(QKeySequence::New);
@@ -541,6 +543,24 @@ void MainWindow::registerDefaultActions()
} }
}); });
if (isQDS) {
auto action = new QAction(icon, tr("New File..."), this);
cmd = ActionManager::registerAction(action, Constants::NEW_FILE);
mfile->addAction(cmd, Constants::G_FILE_NEW);
connect(action, &QAction::triggered, this, []() {
if (!ICore::isNewItemDialogRunning()) {
ICore::showNewItemDialog(
tr("New File", "Title of dialog"),
Utils::filtered(Core::IWizardFactory::allWizardFactories(),
Utils::equal(&Core::IWizardFactory::kind,
Core::IWizardFactory::FileWizard)),
FilePath());
} else {
ICore::raiseWindow(ICore::newItemDialog());
}
});
}
// Open Action // Open Action
icon = QIcon::fromTheme(QLatin1String("document-open"), Utils::Icons::OPENFILE.icon()); icon = QIcon::fromTheme(QLatin1String("document-open"), Utils::Icons::OPENFILE.icon());
m_openAction = new QAction(icon, tr("&Open File or Project..."), this); m_openAction = new QAction(icon, tr("&Open File or Project..."), this);

View File

@@ -834,6 +834,7 @@ QToolButton *PerspectivePrivate::setupToolButton(QAction *action)
auto toolButton = new QToolButton(m_innerToolBar); auto toolButton = new QToolButton(m_innerToolBar);
toolButton->setProperty("panelwidget", true); toolButton->setProperty("panelwidget", true);
toolButton->setDefaultAction(action); toolButton->setDefaultAction(action);
toolButton->setToolTip(action->toolTip());
m_innerToolBarLayout->addWidget(toolButton); m_innerToolBarLayout->addWidget(toolButton);
return toolButton; return toolButton;
} }

View File

@@ -34,8 +34,6 @@
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
enum { debug = 0 };
namespace Debugger { namespace Debugger {
namespace Internal { namespace Internal {

View File

@@ -136,10 +136,15 @@ void LanguageClientManager::clientStarted(Client *client)
qCDebug(Log) << "client started: " << client->name() << client; qCDebug(Log) << "client started: " << client->name() << client;
QTC_ASSERT(managerInstance, return); QTC_ASSERT(managerInstance, return);
QTC_ASSERT(client, return); QTC_ASSERT(client, return);
if (managerInstance->m_shuttingDown) if (managerInstance->m_shuttingDown) {
clientFinished(client); clientFinished(client);
else return;
client->initialize(); }
client->initialize();
const QList<TextEditor::TextDocument *> &clientDocs
= managerInstance->m_clientForDocument.keys(client);
for (TextEditor::TextDocument *document : clientDocs)
client->openDocument(document);
} }
void LanguageClientManager::clientFinished(Client *client) void LanguageClientManager::clientFinished(Client *client)

View File

@@ -261,7 +261,7 @@ void SemanticTokenSupport::updateSemanticTokens(TextDocument *textDocument)
void SemanticTokenSupport::rehighlight() void SemanticTokenSupport::rehighlight()
{ {
for (const Utils::FilePath &filePath : m_tokens.keys()) for (const Utils::FilePath &filePath : m_tokens.keys())
highlight(filePath); highlight(filePath, true);
} }
void addModifiers(int key, void addModifiers(int key,
@@ -369,6 +369,8 @@ void SemanticTokenSupport::setAdditionalTokenTypeStyles(
SemanticRequestTypes SemanticTokenSupport::supportedSemanticRequests(TextDocument *document) const SemanticRequestTypes SemanticTokenSupport::supportedSemanticRequests(TextDocument *document) const
{ {
if (!m_client->documentOpen(document))
return SemanticRequestType::None;
auto supportedRequests = [&](const QJsonObject &options) -> SemanticRequestTypes { auto supportedRequests = [&](const QJsonObject &options) -> SemanticRequestTypes {
TextDocumentRegistrationOptions docOptions(options); TextDocumentRegistrationOptions docOptions(options);
if (docOptions.isValid() if (docOptions.isValid()
@@ -472,7 +474,7 @@ void SemanticTokenSupport::handleSemanticTokensDelta(
highlight(filePath); highlight(filePath);
} }
void SemanticTokenSupport::highlight(const Utils::FilePath &filePath) void SemanticTokenSupport::highlight(const Utils::FilePath &filePath, bool force)
{ {
TextDocument *doc = TextDocument::textDocumentForFilePath(filePath); TextDocument *doc = TextDocument::textDocumentForFilePath(filePath);
if (!doc || LanguageClientManager::clientForDocument(doc) != m_client) if (!doc || LanguageClientManager::clientForDocument(doc) != m_client)
@@ -515,7 +517,7 @@ void SemanticTokenSupport::highlight(const Utils::FilePath &filePath)
} }
} }
m_tokensHandler(doc, expandedTokens, versionedTokens.version); m_tokensHandler(doc, expandedTokens, versionedTokens.version, force);
return; return;
} }
int line = 1; int line = 1;

View File

@@ -56,7 +56,7 @@ inline bool operator==(const ExpandedSemanticToken &t1, const ExpandedSemanticTo
&& t1.type == t2.type && t1.modifiers == t2.modifiers; && t1.type == t2.type && t1.modifiers == t2.modifiers;
} }
using SemanticTokensHandler = std::function<void(TextEditor::TextDocument *, using SemanticTokensHandler = std::function<void(TextEditor::TextDocument *,
const QList<ExpandedSemanticToken> &, int)>; const QList<ExpandedSemanticToken> &, int, bool)>;
namespace SemanticHighligtingSupport { namespace SemanticHighligtingSupport {
@@ -99,7 +99,7 @@ private:
void handleSemanticTokensDelta(const Utils::FilePath &filePath, void handleSemanticTokensDelta(const Utils::FilePath &filePath,
const LanguageServerProtocol::SemanticTokensDeltaResult &result, const LanguageServerProtocol::SemanticTokensDeltaResult &result,
int documentVersion); int documentVersion);
void highlight(const Utils::FilePath &filePath); void highlight(const Utils::FilePath &filePath, bool force = false);
void updateFormatHash(); void updateFormatHash();
void currentEditorChanged(); void currentEditorChanged();
void onCurrentEditorChanged(Core::IEditor *editor); void onCurrentEditorChanged(Core::IEditor *editor);

View File

@@ -1046,7 +1046,7 @@ bool McuSupportOptions::kitUpToDate(const Kit *kit, const McuTarget *mcuTarget,
const McuPackage *qtForMCUsSdkPackage) const McuPackage *qtForMCUsSdkPackage)
{ {
return kitQulVersion(kit) == mcuTarget->qulVersion() && return kitQulVersion(kit) == mcuTarget->qulVersion() &&
kitDependencyPath(kit, qtForMCUsSdkPackage->environmentVariableName()) == qtForMCUsSdkPackage->path(); kitDependencyPath(kit, qtForMCUsSdkPackage->environmentVariableName()).toUserOutput() == qtForMCUsSdkPackage->path().toUserOutput();
} }
void McuSupportOptions::deletePackagesAndTargets() void McuSupportOptions::deletePackagesAndTargets()

View File

@@ -195,6 +195,7 @@ bool KitsPageFactory::validateData(Utils::Id typeId, const QVariant &data, QStri
// -------------------------------------------------------------------- // --------------------------------------------------------------------
static const char KEY_PROJECT_NAME_VALIDATOR[] = "projectNameValidator"; static const char KEY_PROJECT_NAME_VALIDATOR[] = "projectNameValidator";
static const char KEY_PROJECT_NAME_VALIDATOR_USER_MESSAGE[] = "trProjectNameValidatorUserMessage";
ProjectPageFactory::ProjectPageFactory() ProjectPageFactory::ProjectPageFactory()
{ {
@@ -215,10 +216,13 @@ Utils::WizardPage *ProjectPageFactory::create(JsonWizard *wizard, Utils::Id type
page->setDescription(wizard->expander()->expand(description)); page->setDescription(wizard->expander()->expand(description));
QString projectNameValidator QString projectNameValidator
= tmp.value(QLatin1String(KEY_PROJECT_NAME_VALIDATOR)).toString(); = tmp.value(QLatin1String(KEY_PROJECT_NAME_VALIDATOR)).toString();
QString projectNameValidatorUserMessage
= JsonWizardFactory::localizedString(tmp.value(QLatin1String(KEY_PROJECT_NAME_VALIDATOR_USER_MESSAGE)));
if (!projectNameValidator.isEmpty()) { if (!projectNameValidator.isEmpty()) {
QRegularExpression regularExpression(projectNameValidator); QRegularExpression regularExpression(projectNameValidator);
if (regularExpression.isValid()) if (regularExpression.isValid())
page->setProjectNameRegularExpression(regularExpression); page->setProjectNameRegularExpression(regularExpression, projectNameValidatorUserMessage);
} }
return page; return page;

View File

@@ -54,13 +54,14 @@ XcodebuildParser::XcodebuildParser()
OutputLineParser::Result XcodebuildParser::handleLine(const QString &line, OutputFormat type) OutputLineParser::Result XcodebuildParser::handleLine(const QString &line, OutputFormat type)
{ {
static const QStringList notesPatterns({"note: Build preparation complete",
"note: Building targets in parallel",
"note: Planning build"});
const QString lne = rightTrimmed(line); const QString lne = rightTrimmed(line);
if (type == StdOutFormat) { if (type == StdOutFormat) {
QRegularExpressionMatch match = m_buildRe.match(line); QRegularExpressionMatch match = m_buildRe.match(line);
if (match.hasMatch()) { if (match.hasMatch() || notesPatterns.contains(lne)) {
m_xcodeBuildParserState = InXcodebuild; m_xcodeBuildParserState = InXcodebuild;
m_lastTarget = match.captured(2);
m_lastProject = match.captured(3);
return Status::Done; return Status::Done;
} }
if (m_xcodeBuildParserState == InXcodebuild if (m_xcodeBuildParserState == InXcodebuild
@@ -89,7 +90,6 @@ OutputLineParser::Result XcodebuildParser::handleLine(const QString &line, Outpu
if (match.hasMatch()) { if (match.hasMatch()) {
++m_fatalErrorCount; ++m_fatalErrorCount;
m_xcodeBuildParserState = UnknownXcodebuildState; m_xcodeBuildParserState = UnknownXcodebuildState;
// unfortunately the m_lastTarget, m_lastProject might not be in sync
scheduleTask(CompileTask(Task::Error, tr("Xcodebuild failed.")), 1); scheduleTask(CompileTask(Task::Error, tr("Xcodebuild failed.")), 1);
} }
if (m_xcodeBuildParserState == OutsideXcodebuild) if (m_xcodeBuildParserState == OutsideXcodebuild)
@@ -193,6 +193,19 @@ void ProjectExplorerPlugin::testXcodebuildParserParsing_data()
<< Tasks() << Tasks()
<< QString() << QString()
<< XcodebuildParser::OutsideXcodebuild; << XcodebuildParser::OutsideXcodebuild;
QTest::newRow("switch outside->in->outside (new)")
<< XcodebuildParser::OutsideXcodebuild
<< QString::fromLatin1("outside\n"
"note: Build preparation complete\n"
"in xcodebuild\n"
"in xcodebuild2\n"
"** BUILD SUCCEEDED **\n"
"outside2")
<< OutputParserTester::STDOUT
<< QString::fromLatin1("outside\noutside2\n") << QString::fromLatin1("in xcodebuild\nin xcodebuild2\n")
<< Tasks()
<< QString()
<< XcodebuildParser::OutsideXcodebuild;
QTest::newRow("switch Unknown->in->outside") QTest::newRow("switch Unknown->in->outside")
<< XcodebuildParser::UnknownXcodebuildState << XcodebuildParser::UnknownXcodebuildState
<< QString::fromLatin1("unknown\n" << QString::fromLatin1("unknown\n"

View File

@@ -56,8 +56,6 @@ private:
const QRegularExpression m_successRe; const QRegularExpression m_successRe;
const QRegularExpression m_buildRe; const QRegularExpression m_buildRe;
XcodebuildStatus m_xcodeBuildParserState = OutsideXcodebuild; XcodebuildStatus m_xcodeBuildParserState = OutsideXcodebuild;
QString m_lastTarget;
QString m_lastProject;
#if defined WITH_TESTS #if defined WITH_TESTS
friend class XcodebuildParserTester; friend class XcodebuildParserTester;

View File

@@ -229,7 +229,10 @@ void ProFileEditorWidget::findLinkAt(const QTextCursor &cursor,
QDir dir(textDocument()->filePath().toFileInfo().absolutePath()); QDir dir(textDocument()->filePath().toFileInfo().absolutePath());
QString fileName = dir.filePath(buffer); QString fileName = dir.filePath(buffer);
QFileInfo fi(fileName); QFileInfo fi(fileName);
if (fi.exists()) { if (Utils::HostOsInfo::isWindowsHost() && fileName.startsWith("//")) {
// Windows network paths are not supported here since checking for their existence can
// lock the gui thread. See: QTCREATORBUG-26579
} else if (fi.exists()) {
if (fi.isDir()) { if (fi.isDir()) {
QDir subDir(fi.absoluteFilePath()); QDir subDir(fi.absoluteFilePath());
QString subProject = subDir.filePath(subDir.dirName() + QLatin1String(".pro")); QString subProject = subDir.filePath(subDir.dirName() + QLatin1String(".pro"));

View File

@@ -108,6 +108,7 @@ void Edit3DView::updateActiveScene3D(const QVariantMap &sceneState)
const QString orientationKey = QStringLiteral("globalOrientation"); const QString orientationKey = QStringLiteral("globalOrientation");
const QString editLightKey = QStringLiteral("showEditLight"); const QString editLightKey = QStringLiteral("showEditLight");
const QString gridKey = QStringLiteral("showGrid"); const QString gridKey = QStringLiteral("showGrid");
const QString particlesPlayKey = QStringLiteral("particlePlay");
if (sceneState.contains(sceneKey)) { if (sceneState.contains(sceneKey)) {
qint32 newActiveScene = sceneState[sceneKey].value<qint32>(); qint32 newActiveScene = sceneState[sceneKey].value<qint32>();
@@ -151,6 +152,11 @@ void Edit3DView::updateActiveScene3D(const QVariantMap &sceneState)
m_showGridAction->action()->setChecked(sceneState[gridKey].toBool()); m_showGridAction->action()->setChecked(sceneState[gridKey].toBool());
else else
m_showGridAction->action()->setChecked(false); m_showGridAction->action()->setChecked(false);
if (sceneState.contains(particlesPlayKey))
m_particlesPlayAction->action()->setChecked(sceneState[particlesPlayKey].toBool());
else
m_particlesPlayAction->action()->setChecked(true);
} }
void Edit3DView::modelAttached(Model *model) void Edit3DView::modelAttached(Model *model)

View File

@@ -101,7 +101,7 @@ bool SubComponentManager::addImport(const Import &import, int index)
} }
if (importExists) { if (importExists) {
if (index == -1) if (index == -1 || index > m_imports.size())
m_imports.append(import); m_imports.append(import);
else else
m_imports.insert(index, import); m_imports.insert(index, import);

View File

@@ -32,6 +32,7 @@
#include <qmldom/qqmldomtop_p.h> #include <qmldom/qqmldomtop_p.h>
#include <filesystem>
#include <QDateTime> #include <QDateTime>
namespace QmlDesigner { namespace QmlDesigner {
@@ -53,30 +54,28 @@ Storage::Version convertVersion(QmlDom::Version version)
Utils::PathString convertUri(const QString &uri) Utils::PathString convertUri(const QString &uri)
{ {
Utils::PathString path{QStringView{uri.begin() + 7, uri.end()}}; QStringView localPath{uri.begin() + 7, uri.end()};
if (path.endsWith("/."))
return path;
if (path.endsWith("/")) {
path += ".";
return path;
}
path += "/."; std::filesystem::path path{
return path; std::u16string_view{localPath.utf16(), static_cast<std::size_t>(localPath.size())}};
auto x = std::filesystem::weakly_canonical(path);
return Utils::PathString{x.generic_string()};
} }
void addImports(Storage::Imports &imports, void addImports(Storage::Imports &imports,
const QList<QmlDom::Import> &qmlImports, const QList<QmlDom::Import> &qmlImports,
SourceId sourceId, SourceId sourceId,
SourceContextId sourceContextId, const QString &directoryPath,
QmlDocumentParser::PathCache &pathCache,
QmlDocumentParser::ProjectStorage &storage) QmlDocumentParser::ProjectStorage &storage)
{ {
for (const QmlDom::Import &qmlImport : qmlImports) { for (const QmlDom::Import &qmlImport : qmlImports) {
if (qmlImport.uri == u"file://.") { if (qmlImport.uri == u"file://.") {
auto moduleId = storage.moduleId(pathCache.sourceContextPath(sourceContextId)); auto moduleId = storage.moduleId(Utils::PathString{directoryPath});
imports.emplace_back(moduleId, Storage::Version{}, sourceId); imports.emplace_back(moduleId, Storage::Version{}, sourceId);
} else if (qmlImport.uri.startsWith(u"file://")) { } else if (qmlImport.uri.startsWith(u"file://")) {
auto x = convertUri(qmlImport.uri);
auto moduleId = storage.moduleId(convertUri(qmlImport.uri)); auto moduleId = storage.moduleId(convertUri(qmlImport.uri));
imports.emplace_back(moduleId, Storage::Version{}, sourceId); imports.emplace_back(moduleId, Storage::Version{}, sourceId);
} else { } else {
@@ -144,7 +143,7 @@ void addEnumeraton(Storage::Type &type, const QmlDom::Component &component)
Storage::Type QmlDocumentParser::parse(const QString &sourceContent, Storage::Type QmlDocumentParser::parse(const QString &sourceContent,
Storage::Imports &imports, Storage::Imports &imports,
SourceId sourceId, SourceId sourceId,
SourceContextId sourceContextId) const QString &directoryPath)
{ {
Storage::Type type; Storage::Type type;
@@ -155,9 +154,11 @@ Storage::Type QmlDocumentParser::parse(const QString &sourceContent,
QmlDom::DomItem items; QmlDom::DomItem items;
QString filePath{directoryPath + "/foo.qml"};
environment.loadFile( environment.loadFile(
{}, filePath,
{}, filePath,
sourceContent, sourceContent,
QDateTime{}, QDateTime{},
[&](QmlDom::Path, const QmlDom::DomItem &, const QmlDom::DomItem &newItems) { [&](QmlDom::Path, const QmlDom::DomItem &, const QmlDom::DomItem &newItems) {
@@ -185,7 +186,7 @@ Storage::Type QmlDocumentParser::parse(const QString &sourceContent,
type.prototype = Storage::ImportedType{Utils::SmallString{qmlObject.name()}}; type.prototype = Storage::ImportedType{Utils::SmallString{qmlObject.name()}};
addImports(imports, qmlFile->imports(), sourceId, sourceContextId, m_pathCache, m_storage); addImports(imports, qmlFile->imports(), sourceId, directoryPath, m_storage);
addPropertyDeclarations(type, qmlObject); addPropertyDeclarations(type, qmlObject);
addFunctionAndSignalDeclarations(type, qmlObject); addFunctionAndSignalDeclarations(type, qmlObject);

View File

@@ -46,18 +46,16 @@ public:
using ProjectStorage = QmlDesigner::ProjectStorage<Sqlite::Database>; using ProjectStorage = QmlDesigner::ProjectStorage<Sqlite::Database>;
using PathCache = QmlDesigner::SourcePathCache<ProjectStorage, NonLockingMutex>; using PathCache = QmlDesigner::SourcePathCache<ProjectStorage, NonLockingMutex>;
QmlDocumentParser(PathCache &pathCache, ProjectStorage &storage) QmlDocumentParser(ProjectStorage &storage)
: m_pathCache{pathCache} : m_storage{storage}
, m_storage{storage}
{} {}
virtual Storage::Type parse(const QString &sourceContent, Storage::Type parse(const QString &sourceContent,
Storage::Imports &imports, Storage::Imports &imports,
SourceId sourceId, SourceId sourceId,
SourceContextId sourceContextId); const QString &directoryPath);
private: private:
PathCache &m_pathCache;
ProjectStorage &m_storage; ProjectStorage &m_storage;
}; };
} // namespace QmlDesigner } // namespace QmlDesigner

View File

@@ -40,6 +40,7 @@
#include <utils/fileutils.h> #include <utils/fileutils.h>
#include <QAction> #include <QAction>
#include <QMessageBox>
#include <QtConcurrent> #include <QtConcurrent>
#include <QRegularExpression> #include <QRegularExpression>
#include <QStringList> #include <QStringList>
@@ -56,13 +57,26 @@ bool operator==(const GeneratableFile &left, const GeneratableFile &right)
return (left.filePath == right.filePath && left.content == right.content); return (left.filePath == right.filePath && left.content == right.content);
} }
enum ProjectDirectoryError {
NoError = 0,
MissingContentDir = 1<<1,
MissingImportDir = 1<<2,
MissingCppDir = 1<<3,
MissingMainCMake = 1<<4,
MissingMainQml = 1<<5,
MissingAppMainQml = 1<<6,
MissingQmlModules = 1<<7,
MissingMainCpp = 1<<8,
MissingMainCppHeader = 1<<9
};
QVector<GeneratableFile> queuedFiles; QVector<GeneratableFile> queuedFiles;
void generateMenuEntry() void generateMenuEntry()
{ {
Core::ActionContainer *buildMenu = Core::ActionContainer *buildMenu =
Core::ActionManager::actionContainer(ProjectExplorer::Constants::M_BUILDPROJECT); Core::ActionManager::actionContainer(ProjectExplorer::Constants::M_BUILDPROJECT);
auto action = new QAction("Generate CMakeLists.txt files"); auto action = new QAction(QCoreApplication::tr("Generate CMakeLists.txt Files"));
QObject::connect(action, &QAction::triggered, GenerateCmake::onGenerateCmakeLists); QObject::connect(action, &QAction::triggered, GenerateCmake::onGenerateCmakeLists);
Core::Command *cmd = Core::ActionManager::registerAction(action, "QmlProject.CreateCMakeLists"); Core::Command *cmd = Core::ActionManager::registerAction(action, "QmlProject.CreateCMakeLists");
buildMenu->addAction(cmd, ProjectExplorer::Constants::G_BUILD_RUN); buildMenu->addAction(cmd, ProjectExplorer::Constants::G_BUILD_RUN);
@@ -76,8 +90,16 @@ void generateMenuEntry()
void onGenerateCmakeLists() void onGenerateCmakeLists()
{ {
queuedFiles.clear();
FilePath rootDir = ProjectExplorer::SessionManager::startupProject()->projectDirectory(); FilePath rootDir = ProjectExplorer::SessionManager::startupProject()->projectDirectory();
int projectDirErrors = isProjectCorrectlyFormed(rootDir);
if (projectDirErrors != NoError) {
showProjectDirErrorDialog(projectDirErrors);
if (isErrorFatal(projectDirErrors))
return;
}
queuedFiles.clear();
GenerateCmakeLists::generateCmakes(rootDir); GenerateCmakeLists::generateCmakes(rootDir);
GenerateEntryPoints::generateMainCpp(rootDir); GenerateEntryPoints::generateMainCpp(rootDir);
GenerateEntryPoints::generateMainQml(rootDir); GenerateEntryPoints::generateMainQml(rootDir);
@@ -85,6 +107,57 @@ void onGenerateCmakeLists()
writeQueuedFiles(); writeQueuedFiles();
} }
bool isErrorFatal(int error)
{
if (error & MissingContentDir ||
error & MissingImportDir ||
error & MissingCppDir ||
error & MissingAppMainQml)
return true;
return false;
}
const char DIRNAME_CONTENT[] = "content";
const char DIRNAME_IMPORT[] = "imports";
const char DIRNAME_CPP[] = "src";
const char FILENAME_CMAKELISTS[] = "CMakeLists.txt";
const char FILENAME_APPMAINQML[] = "App.qml";
const char FILENAME_MAINQML[] = "main.qml";
const char FILENAME_MAINCPP[] = "main.cpp";
const char FILENAME_MAINCPP_HEADER[] = "import_qml_plugins.h";
const char FILENAME_MODULES[] = "qmlmodules";
int isProjectCorrectlyFormed(const FilePath &rootDir)
{
int errors = NoError;
if (!rootDir.pathAppended(DIRNAME_CONTENT).exists())
errors |= MissingContentDir;
if (!rootDir.pathAppended(DIRNAME_CONTENT).pathAppended(FILENAME_APPMAINQML).exists())
errors |= MissingAppMainQml;
if (!rootDir.pathAppended(DIRNAME_IMPORT).exists())
errors |= MissingImportDir;
if (!rootDir.pathAppended(DIRNAME_CPP).exists())
errors |= MissingCppDir;
if (!rootDir.pathAppended(DIRNAME_CPP).pathAppended(FILENAME_MAINCPP).exists())
errors |= MissingMainCpp;
if (!rootDir.pathAppended(DIRNAME_CPP).pathAppended(FILENAME_MAINCPP_HEADER).exists())
errors |= MissingMainCppHeader;
if (!rootDir.pathAppended(FILENAME_CMAKELISTS).exists())
errors |= MissingMainCMake;
if (!rootDir.pathAppended(FILENAME_MODULES).exists())
errors |= MissingQmlModules;
if (!rootDir.pathAppended(FILENAME_MAINQML).exists())
errors |= MissingMainQml;
return errors;
}
void removeUnconfirmedQueuedFiles(const Utils::FilePaths confirmedFiles) void removeUnconfirmedQueuedFiles(const Utils::FilePaths confirmedFiles)
{ {
QtConcurrent::blockingFilter(queuedFiles, [confirmedFiles](const GeneratableFile &qf) { QtConcurrent::blockingFilter(queuedFiles, [confirmedFiles](const GeneratableFile &qf) {
@@ -92,6 +165,65 @@ void removeUnconfirmedQueuedFiles(const Utils::FilePaths confirmedFiles)
}); });
} }
const QString WARNING_MISSING_STRUCTURE_FATAL = QCoreApplication::tr(
"The project is not properly structured for automatically generating CMake files.\n\nAborting process.\n\nThe following files or directories are missing:\n\n%1");
const QString WARNING_MISSING_STRUCTURE_NONFATAL = QCoreApplication::tr(
"The project is not properly structured for automatically generating CMake files.\n\nThe following files will be created:\n\n%1");
const QString WARNING_TITLE_FATAL = QCoreApplication::tr(
"Cannot Generate CMake Files");
const QString WARNING_TITLE_NONFATAL = QCoreApplication::tr(
"Problems with Generating CMake Files");
void showProjectDirErrorDialog(int error)
{
QString fatalList;
QString nonFatalList;
if (error & MissingContentDir)
fatalList.append(QString(DIRNAME_CONTENT) + "\n");
if (error & MissingAppMainQml)
fatalList.append(QString(DIRNAME_CONTENT)
+ QDir::separator()
+ QString(FILENAME_APPMAINQML)
+ "\n");
if (error & MissingCppDir)
fatalList.append(QString(DIRNAME_CPP) + "\n");
if (error & MissingImportDir)
fatalList.append(QString(DIRNAME_IMPORT) + "\n");
if (error & MissingMainCMake)
nonFatalList.append(QString(FILENAME_CMAKELISTS) + "\n");
if (error & MissingQmlModules)
nonFatalList.append(QString(FILENAME_MODULES) + "\n");
if (error & MissingMainQml)
nonFatalList.append(QString(FILENAME_MAINQML) + "\n");
if (error & MissingMainCpp)
nonFatalList.append(QString(DIRNAME_CPP)
+ QDir::separator()
+ QString(FILENAME_MAINCPP)
+ "\n");
if (error & MissingMainCppHeader)
nonFatalList.append(QString(DIRNAME_CPP)
+ QDir::separator()
+ QString(FILENAME_MAINCPP_HEADER)
+ "\n");
bool isFatal = isErrorFatal(error);
if (isFatal) {
QMessageBox::critical(nullptr,
WARNING_TITLE_FATAL,
WARNING_MISSING_STRUCTURE_FATAL.arg(fatalList + nonFatalList));
}
else {
QMessageBox::warning(nullptr,
WARNING_TITLE_NONFATAL,
WARNING_MISSING_STRUCTURE_NONFATAL.arg(nonFatalList));
}
}
bool showConfirmationDialog(const Utils::FilePath &rootDir) bool showConfirmationDialog(const Utils::FilePath &rootDir)
{ {
Utils::FilePaths files; Utils::FilePaths files;
@@ -114,6 +246,7 @@ bool queueFile(const FilePath &filePath, const QString &fileContent)
GeneratableFile file; GeneratableFile file;
file.filePath = filePath; file.filePath = filePath;
file.content = fileContent; file.content = fileContent;
file.fileExists = filePath.exists();
queuedFiles.append(file); queuedFiles.append(file);
return true; return true;
@@ -159,9 +292,10 @@ QStringList moduleNames;
const QDir::Filters FILES_ONLY = QDir::Files; const QDir::Filters FILES_ONLY = QDir::Files;
const QDir::Filters DIRS_ONLY = QDir::Dirs|QDir::Readable|QDir::NoDotAndDotDot; const QDir::Filters DIRS_ONLY = QDir::Dirs|QDir::Readable|QDir::NoDotAndDotDot;
const char CMAKEFILENAME[] = "CMakeLists.txt";
const char QMLDIRFILENAME[] = "qmldir"; const char QMLDIRFILENAME[] = "qmldir";
const char MODULEFILENAME[] = "qmlmodules";
const char MAIN_CMAKEFILE_TEMPLATE_PATH[] = ":/boilerplatetemplates/qmlprojectmaincmakelists.tpl";
const char QMLMODULES_FILE_TEMPLATE_PATH[] = ":/boilerplatetemplates/qmlprojectmodules.tpl";
bool generateCmakes(const FilePath &rootDir) bool generateCmakes(const FilePath &rootDir)
{ {
@@ -177,9 +311,6 @@ bool generateCmakes(const FilePath &rootDir)
return true; return true;
} }
const char MAIN_CMAKEFILE_TEMPLATE_PATH[] = ":/boilerplatetemplates/qmlprojectmaincmakelists.tpl";
const char QMLMODULES_FILE_TEMPLATE_PATH[] = ":/boilerplatetemplates/qmlprojectmodules.tpl";
void generateMainCmake(const FilePath &rootDir) void generateMainCmake(const FilePath &rootDir)
{ {
//TODO startupProject() may be a terrible way to try to get "current project". It's not necessarily the same thing at all. //TODO startupProject() may be a terrible way to try to get "current project". It's not necessarily the same thing at all.
@@ -194,7 +325,7 @@ void generateMainCmake(const FilePath &rootDir)
modulesAsPlugins.append(" " + moduleName + "plugin\n"); modulesAsPlugins.append(" " + moduleName + "plugin\n");
QString moduleFileContent = GenerateCmake::readTemplate(QMLMODULES_FILE_TEMPLATE_PATH).arg(appName).arg(modulesAsPlugins); QString moduleFileContent = GenerateCmake::readTemplate(QMLMODULES_FILE_TEMPLATE_PATH).arg(appName).arg(modulesAsPlugins);
GenerateCmake::queueFile(rootDir.pathAppended(MODULEFILENAME), moduleFileContent); GenerateCmake::queueFile(rootDir.pathAppended(GenerateCmake::FILENAME_MODULES), moduleFileContent);
} }
const char DO_NOT_EDIT_FILE_COMMENT[] = "### This file is automatically generated by Qt Design Studio.\n### Do not change\n\n"; const char DO_NOT_EDIT_FILE_COMMENT[] = "### This file is automatically generated by Qt Design Studio.\n### Do not change\n\n";
@@ -336,14 +467,14 @@ QStringList getDirectoryTreeResources(const FilePath &dir)
void queueCmakeFile(const FilePath &dir, const QString &content) void queueCmakeFile(const FilePath &dir, const QString &content)
{ {
FilePath filePath = dir.pathAppended(CMAKEFILENAME); FilePath filePath = dir.pathAppended(GenerateCmake::FILENAME_CMAKELISTS);
GenerateCmake::queueFile(filePath, content); GenerateCmake::queueFile(filePath, content);
} }
bool isFileBlacklisted(const QString &fileName) bool isFileBlacklisted(const QString &fileName)
{ {
return (!fileName.compare(QMLDIRFILENAME) || return (!fileName.compare(QMLDIRFILENAME) ||
!fileName.compare(CMAKEFILENAME)); !fileName.compare(GenerateCmake::FILENAME_CMAKELISTS));
} }
} }
@@ -358,18 +489,15 @@ bool generateEntryPointFiles(const FilePath &dir)
} }
const char MAIN_CPPFILE_TEMPLATE_PATH[] = ":/boilerplatetemplates/qmlprojectmaincpp.tpl"; const char MAIN_CPPFILE_TEMPLATE_PATH[] = ":/boilerplatetemplates/qmlprojectmaincpp.tpl";
const char MAIN_CPPFILE_DIR[] = "src";
const char MAIN_CPPFILE_NAME[] = "main.cpp";
const char MAIN_CPPFILE_HEADER_TEMPLATE_PATH[] = ":/boilerplatetemplates/qmlprojectmaincppheader.tpl"; const char MAIN_CPPFILE_HEADER_TEMPLATE_PATH[] = ":/boilerplatetemplates/qmlprojectmaincppheader.tpl";
const char MAIN_CPPFILE_HEADER_NAME[] = "import_qml_plugins.h";
const char MAIN_CPPFILE_HEADER_PLUGIN_LINE[] = "Q_IMPORT_QML_PLUGIN(%1)\n"; const char MAIN_CPPFILE_HEADER_PLUGIN_LINE[] = "Q_IMPORT_QML_PLUGIN(%1)\n";
bool generateMainCpp(const FilePath &dir) bool generateMainCpp(const FilePath &dir)
{ {
FilePath srcDir = dir.pathAppended(MAIN_CPPFILE_DIR); FilePath srcDir = dir.pathAppended(GenerateCmake::DIRNAME_CPP);
QString cppContent = GenerateCmake::readTemplate(MAIN_CPPFILE_TEMPLATE_PATH); QString cppContent = GenerateCmake::readTemplate(MAIN_CPPFILE_TEMPLATE_PATH);
FilePath cppFilePath = srcDir.pathAppended(MAIN_CPPFILE_NAME); FilePath cppFilePath = srcDir.pathAppended(GenerateCmake::FILENAME_MAINCPP);
bool cppOk = GenerateCmake::queueFile(cppFilePath, cppContent); bool cppOk = GenerateCmake::queueFile(cppFilePath, cppContent);
QString modulesAsPlugins; QString modulesAsPlugins;
@@ -379,19 +507,18 @@ bool generateMainCpp(const FilePath &dir)
QString headerContent = GenerateCmake::readTemplate(MAIN_CPPFILE_HEADER_TEMPLATE_PATH) QString headerContent = GenerateCmake::readTemplate(MAIN_CPPFILE_HEADER_TEMPLATE_PATH)
.arg(modulesAsPlugins); .arg(modulesAsPlugins);
FilePath headerFilePath = srcDir.pathAppended(MAIN_CPPFILE_HEADER_NAME); FilePath headerFilePath = srcDir.pathAppended(GenerateCmake::FILENAME_MAINCPP_HEADER);
bool headerOk = GenerateCmake::queueFile(headerFilePath, headerContent); bool headerOk = GenerateCmake::queueFile(headerFilePath, headerContent);
return cppOk && headerOk; return cppOk && headerOk;
} }
const char MAIN_QMLFILE_PATH[] = ":/boilerplatetemplates/qmlprojectmainqml.tpl"; const char MAIN_QMLFILE_TEMPLATE_PATH[] = ":/boilerplatetemplates/qmlprojectmainqml.tpl";
const char MAIN_QMLFILE_NAME[] = "main.qml";
bool generateMainQml(const FilePath &dir) bool generateMainQml(const FilePath &dir)
{ {
QString content = GenerateCmake::readTemplate(MAIN_QMLFILE_PATH); QString content = GenerateCmake::readTemplate(MAIN_QMLFILE_TEMPLATE_PATH);
FilePath filePath = dir.pathAppended(MAIN_QMLFILE_NAME); FilePath filePath = dir.pathAppended(GenerateCmake::FILENAME_MAINQML);
return GenerateCmake::queueFile(filePath, content); return GenerateCmake::queueFile(filePath, content);
} }

View File

@@ -34,13 +34,17 @@ namespace GenerateCmake {
struct GeneratableFile { struct GeneratableFile {
Utils::FilePath filePath; Utils::FilePath filePath;
QString content; QString content;
bool fileExists;
}; };
bool operator==(const GeneratableFile &left, const GeneratableFile &right); bool operator==(const GeneratableFile &left, const GeneratableFile &right);
void generateMenuEntry(); void generateMenuEntry();
void onGenerateCmakeLists(); void onGenerateCmakeLists();
bool isErrorFatal(int error);
int isProjectCorrectlyFormed(const Utils::FilePath &rootDir);
void removeUnconfirmedQueuedFiles(const Utils::FilePaths confirmedFiles); void removeUnconfirmedQueuedFiles(const Utils::FilePaths confirmedFiles);
void showProjectDirErrorDialog(int error);
bool showConfirmationDialog(const Utils::FilePath &rootDir); bool showConfirmationDialog(const Utils::FilePath &rootDir);
bool queueFile(const Utils::FilePath &filePath, const QString &fileContent); bool queueFile(const Utils::FilePath &filePath, const QString &fileContent);
bool writeFile(const GeneratableFile &file); bool writeFile(const GeneratableFile &file);

View File

@@ -222,8 +222,8 @@ QmlPreviewPluginPrivate::QmlPreviewPluginPrivate(QmlPreviewPlugin *parent)
bool skipDeploy = false; bool skipDeploy = false;
const Kit *kit = SessionManager::startupTarget()->kit(); const Kit *kit = SessionManager::startupTarget()->kit();
if (SessionManager::startupTarget() && kit) if (SessionManager::startupTarget() && kit)
skipDeploy = kit-> skipDeploy = kit->supportedPlatforms().contains(Android::Constants::ANDROID_DEVICE_TYPE)
supportedPlatforms().contains(Android::Constants::ANDROID_DEVICE_TYPE); || DeviceTypeKitAspect::deviceTypeId(kit) == Android::Constants::ANDROID_DEVICE_TYPE;
ProjectExplorerPlugin::runStartupProject(Constants::QML_PREVIEW_RUN_MODE, skipDeploy); ProjectExplorerPlugin::runStartupProject(Constants::QML_PREVIEW_RUN_MODE, skipDeploy);
}); });
menu->addAction( menu->addAction(

View File

@@ -44,6 +44,7 @@
#include <extensionsystem/pluginspec.h> #include <extensionsystem/pluginspec.h>
#include <utils/infobar.h> #include <utils/infobar.h>
#include <utils/qtcprocess.h>
#include <QMessageBox> #include <QMessageBox>
#include <QPushButton> #include <QPushButton>
@@ -91,13 +92,14 @@ QmlProjectPlugin::~QmlProjectPlugin()
void QmlProjectPlugin::openQDS(const Utils::FilePath &fileName) void QmlProjectPlugin::openQDS(const Utils::FilePath &fileName)
{ {
const QString &qdsPath = QmlProjectPlugin::qdsInstallationEntry(); const Utils::FilePath &qdsPath = QmlProjectPlugin::qdsInstallationEntry();
bool qdsStarted = false; bool qdsStarted = false;
//-a and -client arguments help to append project to open design studio application //-a and -client arguments help to append project to open design studio application
if (Utils::HostOsInfo::isMacHost()) if (Utils::HostOsInfo::isMacHost())
qdsStarted = QProcess::startDetached("/usr/bin/open", {"-a", qdsPath, fileName.toString()}); qdsStarted = Utils::QtcProcess::startDetached(
{"/usr/bin/open", {"-a", qdsPath.path(), fileName.toString()}});
else else
qdsStarted = QProcess::startDetached(qdsPath, {"-client", fileName.toString()}); qdsStarted = Utils::QtcProcess::startDetached({qdsPath, {"-client", fileName.toString()}});
if (!qdsStarted) { if (!qdsStarted) {
QMessageBox::warning(Core::ICore::dialogParent(), QMessageBox::warning(Core::ICore::dialogParent(),
@@ -106,17 +108,17 @@ void QmlProjectPlugin::openQDS(const Utils::FilePath &fileName)
} }
} }
QString QmlProjectPlugin::qdsInstallationEntry() Utils::FilePath QmlProjectPlugin::qdsInstallationEntry()
{ {
QSettings *settings = Core::ICore::settings(); QSettings *settings = Core::ICore::settings();
const QString qdsInstallationEntry = "QML/Designer/DesignStudioInstallation"; //set in installer const QString qdsInstallationEntry = "QML/Designer/DesignStudioInstallation"; //set in installer
return settings->value(qdsInstallationEntry).toString(); return Utils::FilePath::fromUserInput(settings->value(qdsInstallationEntry).toString());
} }
bool QmlProjectPlugin::qdsInstallationExists() bool QmlProjectPlugin::qdsInstallationExists()
{ {
return Utils::FilePath::fromString(qdsInstallationEntry()).exists(); return qdsInstallationEntry().exists();
} }
Utils::FilePath findQmlProject(const Utils::FilePath &folder) Utils::FilePath findQmlProject(const Utils::FilePath &folder)

View File

@@ -41,7 +41,7 @@ public:
~QmlProjectPlugin() final; ~QmlProjectPlugin() final;
static void openQDS(const Utils::FilePath &fileName); static void openQDS(const Utils::FilePath &fileName);
static QString qdsInstallationEntry(); static Utils::FilePath qdsInstallationEntry();
static bool qdsInstallationExists(); static bool qdsInstallationExists();
private: private:

View File

@@ -101,7 +101,7 @@ QdsNewDialog::QdsNewDialog(QWidget *parent)
QObject::connect(&m_wizard, &WizardHandler::projectCanBeCreated, this, &QdsNewDialog::onProjectCanBeCreatedChanged); QObject::connect(&m_wizard, &WizardHandler::projectCanBeCreated, this, &QdsNewDialog::onProjectCanBeCreatedChanged);
QObject::connect(&m_wizard, &WizardHandler::wizardCreationFailed, this, [this]() { QObject::connect(&m_wizard, &WizardHandler::wizardCreationFailed, this, [this]() {
QMessageBox::critical(m_dialog, "New project", "Failed to initialize data"); QMessageBox::critical(m_dialog, tr("New project"), tr("Failed to initialize data"));
reject(); reject();
delete this; delete this;
}); });
@@ -195,6 +195,11 @@ void QdsNewDialog::setScreenSizeIndex(int index)
m_qmlScreenSizeIndex = index; m_qmlScreenSizeIndex = index;
} }
int QdsNewDialog::screenSizeIndex() const
{
return m_wizard.screenSizeIndex();
}
void QdsNewDialog::setTargetQtVersion(int index) void QdsNewDialog::setTargetQtVersion(int index)
{ {
m_wizard.setTargetQtVersionIndex(index); m_wizard.setTargetQtVersionIndex(index);

View File

@@ -66,6 +66,7 @@ public:
Q_INVOKABLE QString currentProjectQmlPath() const; Q_INVOKABLE QString currentProjectQmlPath() const;
Q_INVOKABLE void setScreenSizeIndex(int index); // called when ComboBox item is "activated" Q_INVOKABLE void setScreenSizeIndex(int index); // called when ComboBox item is "activated"
Q_INVOKABLE int screenSizeIndex() const;
Q_INVOKABLE void setTargetQtVersion(int index); Q_INVOKABLE void setTargetQtVersion(int index);
Q_INVOKABLE QString chooseProjectLocation(); Q_INVOKABLE QString chooseProjectLocation();

View File

@@ -174,6 +174,15 @@ void WizardHandler::setScreenSizeIndex(int index)
cbfield->selectRow(index); cbfield->selectRow(index);
} }
int WizardHandler::screenSizeIndex() const
{
auto *field = m_detailsPage->jsonField("ScreenFactor");
auto *cbfield = dynamic_cast<ProjectExplorer::ComboBoxField *>(field);
QTC_ASSERT(cbfield, return -1);
return cbfield->selectedRow();
}
void WizardHandler::setTargetQtVersionIndex(int index) void WizardHandler::setTargetQtVersionIndex(int index)
{ {
auto *field = m_detailsPage->jsonField("TargetQtVersion"); auto *field = m_detailsPage->jsonField("TargetQtVersion");

View File

@@ -50,6 +50,7 @@ public:
//TODO: location should not be needed in reset() -- only when creating the project //TODO: location should not be needed in reset() -- only when creating the project
void reset(const ProjectItem &projectInfo, int projectSelection, const Utils::FilePath &location); void reset(const ProjectItem &projectInfo, int projectSelection, const Utils::FilePath &location);
void setScreenSizeIndex(int index); void setScreenSizeIndex(int index);
int screenSizeIndex() const;
void setTargetQtVersionIndex(int index); void setTargetQtVersionIndex(int index);
bool haveTargetQtVersion() const; bool haveTargetQtVersion() const;
void setStyleIndex(int index); void setStyleIndex(int index);

View File

@@ -55,14 +55,20 @@ static FilePath pythonInterpreter(const Environment &env)
return {}; return {};
} }
static CommandLine emrunCommand(Target *target, const QString &browser, const QString &port) static FilePath htmlFileInDir(const FilePath &dir)
{ {
if (BuildConfiguration *bc = target->activeBuildConfiguration()) { const FilePaths htmlFiles = dir.dirEntries(QStringList("*.html"), QDir::Files);
return htmlFiles.isEmpty() ? FilePath() : htmlFiles.first();
}
static CommandLine emrunCommand(const RunConfiguration *rc, const QString &browser,
const QString &port)
{
if (BuildConfiguration *bc = rc->target()->activeBuildConfiguration()) {
const Environment env = bc->environment(); const Environment env = bc->environment();
const FilePath emrun = env.searchInPath("emrun"); const FilePath emrun = env.searchInPath("emrun");
const FilePath emrunPy = emrun.absolutePath().pathAppended(emrun.baseName() + ".py"); const FilePath emrunPy = emrun.absolutePath().pathAppended(emrun.baseName() + ".py");
const FilePath html = const FilePath html = htmlFileInDir(bc->buildDirectory());
bc->buildDirectory().pathAppended(target->project()->displayName() + ".html");
return CommandLine(pythonInterpreter(env), { return CommandLine(pythonInterpreter(env), {
emrunPy.path(), emrunPy.path(),
@@ -91,8 +97,8 @@ public:
effectiveEmrunCall->setDisplayStyle(StringAspect::TextEditDisplay); effectiveEmrunCall->setDisplayStyle(StringAspect::TextEditDisplay);
effectiveEmrunCall->setReadOnly(true); effectiveEmrunCall->setReadOnly(true);
setUpdater([target, effectiveEmrunCall, webBrowserAspect] { setUpdater([this, effectiveEmrunCall, webBrowserAspect] {
effectiveEmrunCall->setValue(emrunCommand(target, effectiveEmrunCall->setValue(emrunCommand(this,
webBrowserAspect->currentBrowser(), webBrowserAspect->currentBrowser(),
"<port>").toUserOutput()); "<port>").toUserOutput());
}); });
@@ -122,7 +128,7 @@ public:
setStarter([this, runControl, portsGatherer] { setStarter([this, runControl, portsGatherer] {
Runnable r; Runnable r;
r.command = emrunCommand(runControl->target(), r.command = emrunCommand(runControl->runConfiguration(),
runControl->aspect<WebBrowserSelectionAspect>()->currentBrowser(), runControl->aspect<WebBrowserSelectionAspect>()->currentBrowser(),
QString::number(portsGatherer->findEndPoint().port())); QString::number(portsGatherer->findEndPoint().port()));
SimpleTargetRunner::doStart(r, {}); SimpleTargetRunner::doStart(r, {});

View File

@@ -129,17 +129,17 @@ protected:
QmlDesigner::ProjectStorage<Sqlite::Database> storage{database, database.isInitialized()}; QmlDesigner::ProjectStorage<Sqlite::Database> storage{database, database.isInitialized()};
QmlDesigner::SourcePathCache<QmlDesigner::ProjectStorage<Sqlite::Database>> sourcePathCache{ QmlDesigner::SourcePathCache<QmlDesigner::ProjectStorage<Sqlite::Database>> sourcePathCache{
storage}; storage};
QmlDesigner::QmlDocumentParser parser{sourcePathCache, storage}; QmlDesigner::QmlDocumentParser parser{storage};
Storage::Imports imports; Storage::Imports imports;
SourceId qmlFileSourceId{sourcePathCache.sourceId("path/to/qmlfile.qml")}; SourceId qmlFileSourceId{sourcePathCache.sourceId("path/to/qmlfile.qml")};
SourceContextId qmlFileSourceContextId{sourcePathCache.sourceContextId(qmlFileSourceId)}; SourceContextId qmlFileSourceContextId{sourcePathCache.sourceContextId(qmlFileSourceId)};
SourceId directorySourceId{sourcePathCache.sourceId("path/to/.")}; QString directoryPath{"/path/to"};
ModuleId directoryModuleId{&directorySourceId}; ModuleId directoryModuleId{storage.moduleId("/path/to")};
}; };
TEST_F(QmlDocumentParser, Prototype) TEST_F(QmlDocumentParser, Prototype)
{ {
auto type = parser.parse("Example{}", imports, qmlFileSourceId, qmlFileSourceContextId); auto type = parser.parse("Example{}", imports, qmlFileSourceId, directoryPath);
ASSERT_THAT(type, HasPrototype(Storage::ImportedType("Example"))); ASSERT_THAT(type, HasPrototype(Storage::ImportedType("Example")));
} }
@@ -150,7 +150,7 @@ TEST_F(QmlDocumentParser, DISABLED_QualifiedPrototype)
auto type = parser.parse("import Example as Example\n Example.Item{}", auto type = parser.parse("import Example as Example\n Example.Item{}",
imports, imports,
qmlFileSourceId, qmlFileSourceId,
qmlFileSourceContextId); directoryPath);
ASSERT_THAT(type, ASSERT_THAT(type,
HasPrototype(Storage::QualifiedImportedType( HasPrototype(Storage::QualifiedImportedType(
@@ -159,10 +159,7 @@ TEST_F(QmlDocumentParser, DISABLED_QualifiedPrototype)
TEST_F(QmlDocumentParser, Properties) TEST_F(QmlDocumentParser, Properties)
{ {
auto type = parser.parse("Example{\n property int foo\n}", auto type = parser.parse("Example{\n property int foo\n}", imports, qmlFileSourceId, directoryPath);
imports,
qmlFileSourceId,
qmlFileSourceContextId);
ASSERT_THAT(type.propertyDeclarations, ASSERT_THAT(type.propertyDeclarations,
UnorderedElementsAre(IsPropertyDeclaration("foo", UnorderedElementsAre(IsPropertyDeclaration("foo",
@@ -170,16 +167,18 @@ TEST_F(QmlDocumentParser, Properties)
Storage::PropertyDeclarationTraits::None))); Storage::PropertyDeclarationTraits::None)));
} }
TEST_F(QmlDocumentParser, DISABLED_Imports) TEST_F(QmlDocumentParser, Imports)
{ {
ModuleId fooDirectoryModuleId = storage.moduleId("path/to/foo/."); ModuleId fooDirectoryModuleId = storage.moduleId("/path/foo");
ModuleId qmlModuleId = storage.moduleId("QML"); ModuleId qmlModuleId = storage.moduleId("QML");
ModuleId qtQmlModuleId = storage.moduleId("QtQml"); ModuleId qtQmlModuleId = storage.moduleId("QtQml");
ModuleId qtQuickModuleId = storage.moduleId("QtQuick"); ModuleId qtQuickModuleId = storage.moduleId("QtQuick");
auto type = parser.parse("import QtQuick\n import \"../foo\"\nExample{}", auto type = parser.parse(R"(import QtQuick
import "../foo"
Example{})",
imports, imports,
qmlFileSourceId, qmlFileSourceId,
qmlFileSourceContextId); directoryPath);
ASSERT_THAT(imports, ASSERT_THAT(imports,
UnorderedElementsAre( UnorderedElementsAre(
@@ -196,7 +195,7 @@ TEST_F(QmlDocumentParser, Functions)
"Example{\n function someScript(x, y) {}\n function otherFunction() {}\n}", "Example{\n function someScript(x, y) {}\n function otherFunction() {}\n}",
imports, imports,
qmlFileSourceId, qmlFileSourceId,
qmlFileSourceContextId); directoryPath);
ASSERT_THAT(type.functionDeclarations, ASSERT_THAT(type.functionDeclarations,
UnorderedElementsAre(AllOf(IsFunctionDeclaration("otherFunction", ""), UnorderedElementsAre(AllOf(IsFunctionDeclaration("otherFunction", ""),
@@ -212,7 +211,7 @@ TEST_F(QmlDocumentParser, Signals)
auto type = parser.parse("Example{\n signal someSignal(int x, real y)\n signal signal2()\n}", auto type = parser.parse("Example{\n signal someSignal(int x, real y)\n signal signal2()\n}",
imports, imports,
qmlFileSourceId, qmlFileSourceId,
qmlFileSourceContextId); directoryPath);
ASSERT_THAT(type.signalDeclarations, ASSERT_THAT(type.signalDeclarations,
UnorderedElementsAre(AllOf(IsSignalDeclaration("someSignal"), UnorderedElementsAre(AllOf(IsSignalDeclaration("someSignal"),
@@ -229,7 +228,7 @@ TEST_F(QmlDocumentParser, Enumeration)
"State{On,Off}\n}", "State{On,Off}\n}",
imports, imports,
qmlFileSourceId, qmlFileSourceId,
qmlFileSourceContextId); directoryPath);
ASSERT_THAT(type.enumerationDeclarations, ASSERT_THAT(type.enumerationDeclarations,
UnorderedElementsAre( UnorderedElementsAre(