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

This commit is contained in:
The Qt Project
2022-05-18 13:19:44 +00:00
89 changed files with 2011 additions and 791 deletions

View File

@@ -8,7 +8,7 @@ on:
env: env:
QT_VERSION: 6.2.3 QT_VERSION: 6.2.3
CLANG_VERSION: 14.0.0 CLANG_VERSION: 14.0.3
ELFUTILS_VERSION: 0.175 ELFUTILS_VERSION: 0.175
CMAKE_VERSION: 3.21.1 CMAKE_VERSION: 3.21.1
NINJA_VERSION: 1.10.2 NINJA_VERSION: 1.10.2

View File

@@ -107,7 +107,7 @@ set(CRASHPAD_BACKEND_URL "" CACHE STRING "Crashpad backend URL")
set(BUILD_WITH_CRASHPAD OFF) set(BUILD_WITH_CRASHPAD OFF)
# Linux is not supported for now # Linux is not supported for now
# x86_64;arm64 is not supported for now # x86_64;arm64 is not supported for now
if(CRASHPAD_BACKEND_URL AND (WIN32 OR (APPLE AND NOT "${CMAKE_OSX_ARCHITECTURES}" STREQUAL "x86_64;arm64"))) if(CRASHPAD_BACKEND_URL AND (WIN32 OR APPLE)) # Linux is not supported for now
find_package(Crashpad QUIET) find_package(Crashpad QUIET)
if(TARGET Crashpad::Crashpad) if(TARGET Crashpad::Crashpad)
set(BUILD_WITH_CRASHPAD ON) set(BUILD_WITH_CRASHPAD ON)

View File

@@ -57,25 +57,9 @@ find_path(CRASHPAD_GEN_DIR
"${CMAKE_PREFIX_PATH}" "${CMAKE_PREFIX_PATH}"
) )
if(APPLE)
find_path(CRASHPAD_OBJ_DIR
NAMES mig_output.child_portServer.o
PATH_SUFFIXES gen/util/mach
HINTS
"${CRASHPAD_OBJECT_DIR}"
"${CRASHPAD_LIB_DIR}/out/Default"
"${CMAKE_PREFIX_PATH}"
)
set(CRASHPAD_APPLE_VARS CRASHPAD_OBJ_DIR CRASHPAD_GEN_DIR)
find_library(FWbsm bsm)
find_library(FWAppKit AppKit)
find_library(FWIOKit IOKit)
find_library(FWSecurity Security)
endif()
include(FindPackageHandleStandardArgs) include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Crashpad DEFAULT_MSG find_package_handle_standard_args(Crashpad DEFAULT_MSG
CRASHPAD_BIN_DIR CRASHPAD_INCLUDE_DIR CRASHPAD_LIB_DIR ${CRASHPAD_APPLE_VARS} CRASHPAD_BIN_DIR CRASHPAD_INCLUDE_DIR CRASHPAD_LIB_DIR
) )
if(Crashpad_FOUND) if(Crashpad_FOUND)
@@ -93,18 +77,16 @@ if(Crashpad_FOUND)
set_target_properties(Crashpad::Crashpad PROPERTIES set_target_properties(Crashpad::Crashpad PROPERTIES
IMPORTED_LOCATION "${CRASHPAD_LIB_DIR}/client/client.lib") IMPORTED_LOCATION "${CRASHPAD_LIB_DIR}/client/client.lib")
elseif(APPLE) elseif(APPLE)
find_library(FWbsm bsm)
find_library(FWAppKit AppKit)
find_library(FWIOKit IOKit)
find_library(FWSecurity Security)
target_link_libraries(Crashpad::Crashpad INTERFACE target_link_libraries(Crashpad::Crashpad INTERFACE
"${CRASHPAD_LIB_DIR}/third_party/mini_chromium/mini_chromium/base/libbase.a" "${CRASHPAD_LIB_DIR}/third_party/mini_chromium/mini_chromium/base/libbase.a"
"${CRASHPAD_LIB_DIR}/util/libutil.a" "${CRASHPAD_LIB_DIR}/util/libutil.a"
"${CRASHPAD_LIB_DIR}/util/libmig_output.a"
"${CRASHPAD_LIB_DIR}/client/libclient.a" "${CRASHPAD_LIB_DIR}/client/libclient.a"
"${CRASHPAD_OBJ_DIR}/mig_output.child_portServer.o" "${CRASHPAD_LIB_DIR}/client/libcommon.a"
"${CRASHPAD_OBJ_DIR}/mig_output.child_portUser.o"
"${CRASHPAD_OBJ_DIR}/mig_output.excServer.o"
"${CRASHPAD_OBJ_DIR}/mig_output.excUser.o"
"${CRASHPAD_OBJ_DIR}/mig_output.mach_excServer.o"
"${CRASHPAD_OBJ_DIR}/mig_output.mach_excUser.o"
"${CRASHPAD_OBJ_DIR}/mig_output.notifyServer.o"
"${CRASHPAD_OBJ_DIR}/mig_output.notifyUser.o"
${FWbsm} ${FWAppKit} ${FWIOKit} ${FWSecurity}) ${FWbsm} ${FWAppKit} ${FWIOKit} ${FWSecurity})
set_target_properties(Crashpad::Crashpad PROPERTIES set_target_properties(Crashpad::Crashpad PROPERTIES
IMPORTED_LOCATION "${CRASHPAD_LIB_DIR}/client/libclient.a") IMPORTED_LOCATION "${CRASHPAD_LIB_DIR}/client/libclient.a")

View File

@@ -335,6 +335,10 @@ function(find_dependent_plugins varName)
set(_RESULT ${ARGN}) set(_RESULT ${ARGN})
foreach(i ${ARGN}) foreach(i ${ARGN})
if(NOT TARGET ${i})
continue()
endif()
set(_dep)
get_property(_dep TARGET "${i}" PROPERTY _arg_DEPENDS) get_property(_dep TARGET "${i}" PROPERTY _arg_DEPENDS)
if (_dep) if (_dep)
find_dependent_plugins(_REC ${_dep}) find_dependent_plugins(_REC ${_dep})

View File

@@ -7,7 +7,7 @@ instructions:
variableValue: "RelWithDebInfo" variableValue: "RelWithDebInfo"
- type: EnvironmentVariable - type: EnvironmentVariable
variableName: LLVM_BASE_URL variableName: LLVM_BASE_URL
variableValue: http://master.qt.io/development_releases/prebuilt/libclang/libclang-release_14.0.0-based variableValue: http://master.qt.io/development_releases/prebuilt/libclang/libclang-release_14.0.3-based
- type: Group - type: Group
instructions: instructions:

83
dist/changes-7.0.2.md vendored Normal file
View File

@@ -0,0 +1,83 @@
Qt Creator 7.0.2
================
Qt Creator version 7.0.2 contains bug fixes.
The most important changes are listed in this document. For a complete list of
changes, see the Git log for the Qt Creator sources that you can check out from
the public Git repository. For example:
git clone git://code.qt.io/qt-creator/qt-creator.git
git log --cherry-pick --pretty=oneline origin/v7.0.1..v7.0.2
General
-------
### Locator
* Fixed saving of command history of `Execute` filter
Editing
-------
* Fixed that actions could be applied to wrong editor after switching split
(QTCREATORBUG-27479)
### C++
* Fixed wrong `__cplusplus` value for older GCC versions
* ClangFormat
* Fixed disappearing settings drop down (QTCREATORBUG-26948)
### Language Client
* Fixed crash with function argument and quick fix hints (QTCREATORBUG-27404)
* Fixed selection in `Outline` view
* Fixed `Sort Alphabetically` for outline dropdown
Projects
--------
* Fixed crash with `Recent Projects` (QTCREATORBUG-27399)
* Fixed that `-include` flags were ignored by code model (QTCREATORBUG-27450)
### CMake
* Fixed crash when cancelling progress indicator (QTCREATORBUG-27499)
* Fixed application of build directory after `Browse` (QTCREATORBUG-27407)
Debugging
---------
* Fixed pretty printer for `QFile` in Qt 6.3
Platforms
---------
### macOS
* Fixed compilier identification of `cc` and `c++` (QTCREATORBUG-27523)
Credits for these changes go to:
--------------------------------
Alessandro Portale
Artem Sokolovskii
Brook Cronin
Christian Kandeler
Christian Stenger
Cristian Adam
David Schulz
Eike Ziller
Henning Gruendl
Jaroslaw Kobus
Kai Uwe Broulik
Knud Dollereder
Leena Miettinen
Mahmoud Badri
Mats Honkamaa
Miikka Heikkinen
Orgad Shaneh
Robert Löhning
Thomas Hartmann
Tim Jenssen
Vikas Pachdha

View File

@@ -41,16 +41,14 @@
\title Using QML Modules with Plugins \title Using QML Modules with Plugins
QML modules may use plugins to expose components defined in C++ to QML \l{Defining a QML Module}{QML modules} may use \l{Creating C++ Plugins for QML}
applications. \QC cannot load the plugins to determine the details of {C++ plugins} to expose components defined in C++ to QML applications.
the contained components, and therefore, the modules must provide extra type
information for code completion and the semantic checks to work correctly.
To create a QML module To create a QML
\if defined(qtdesignstudio) \if defined(qtdesignstudio)
and make it appear in the \l Components view: module and make it appear in the \l Components view:
\else \else
: module:
\endif \endif
\list 1 \list 1
@@ -97,26 +95,13 @@
\c .metainfo file is in place. \c .metainfo file is in place.
\endif \endif
\if defined(qtcreator)
\section1 Registering QML Types
When you write a QML module or use QML from a C++ application, and the C++
is a part of your qmake project, you typically register new types with the
\c qmlRegisterType() function or expose some class instances with
\l{QQmlContext::setContextProperty()}. The \QC C++ code model now scans for
these calls and tells the QML code model about them. This means that properties
are displayed during code completion and the JavaScript code checker does not
complain about unknown types. However, this works only when the source code
is available, and therefore, you must explicitly generate type information
for QML modules with plugins before distributing them.
\endif
\section1 Generating Type Description Files \section1 Generating Type Description Files
Ideally, QML modules have a \c{plugins.qmltypes} file in the same directory When \l{Defining QML Types from C++}{registering QML types}, make sure that
as the \c qmldir file. The \c qmltypes file contains a description of the the QML module has a \c{plugins.qmltypes} file. Ideally, it should be located
components exported by the module's plugins and is loaded by \QC when the in the same directory as the \c qmldir file. The \c qmltypes file contains a
module is imported. description of the components exported by the module's plugins and is loaded
by \QC when the module is imported.
For more information, see \l{Type Description Files}. For more information, see \l{Type Description Files}.
@@ -127,7 +112,6 @@
However, this automatic dumping is a fallback mechanism with many points of However, this automatic dumping is a fallback mechanism with many points of
failure and you cannot rely upon it. failure and you cannot rely upon it.
\if defined(qtcreator)
\section1 Importing QML Modules \section1 Importing QML Modules
By default, \QC will look in the QML import path of Qt for QML modules. By default, \QC will look in the QML import path of Qt for QML modules.
@@ -145,7 +129,7 @@
The import path affects all the targets built by the CMake project. The import path affects all the targets built by the CMake project.
\else \if defined(qtdesignstudio)
\section1 Running QML Modules in Design Mode \section1 Running QML Modules in Design Mode
A QML emulation layer (also called QML Puppet) is used in the A QML emulation layer (also called QML Puppet) is used in the

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 51 KiB

View File

@@ -32,8 +32,8 @@
\title Exporting Designs from Figma \title Exporting Designs from Figma
You can use \QBF to export designs from Figma to \e {.metadata} You can use \QBF to export designs from Figma to a \e {.qtbridge}
format that you can \l{Importing 2D Assets}{import} to projects in \QDS. archive that you can \l{Importing 2D Assets}{import} to projects in \QDS.
\image studio-figma-export.png \image studio-figma-export.png

View File

@@ -128,9 +128,8 @@
\li When the exporting is done, select \uicontrol OK. \li When the exporting is done, select \uicontrol OK.
\endlist \endlist
\QBF exports everything into a single archive. Before importing the design \QBF exports everything into a .qtbridge archive. You can import the archive
into \QDS, you have to manually extract the archive. Then you can import the into a project in \QDS, as described in \l{Importing 2D Assets}.
\e .metainfo into a project in \QDS, as described in \l{Importing 2D Assets}.
\section1 Export Settings \section1 Export Settings

View File

@@ -55,48 +55,47 @@
\image studio-imported-assets.png "UI imported into Qt Design Studio" \image studio-imported-assets.png "UI imported into Qt Design Studio"
\QB enables you to export assets and then import them to a \QDS project \QB enables you to export assets and then import them to a \QDS project
as image and QML files for editing in \l {Form Editor}. If you make changes as images and QML files for editing in \l {Form Editor}. If you make changes
to your design in the design tool that you originally used to create it, to your design in the design tool that you originally used to create it,
you can merge the changes into existing QML files without overwriting the you can merge the changes into existing QML files without overwriting the
changes you have made in \QDS. For more information, see changes you have made in \QDS. For more information, see
\l {Exporting from Design Tools}. \l {Exporting from Design Tools}.
\note Attempting to import assets exported on another system might fail. \QB exports the designs either as an archive(.qtbridge) or as images with
a .metadata file. \QDS support both formats.
The following instructions use an empty project as an example. For more The following instructions use an empty project as an example. For more
information about the options you have, see information about the options you have, see
\l {Creating Projects}. \l {Creating Projects}.
To import assets exported in \QB to \QDS projects: To import the exported assets to \QDS projects:
\list 1 \list 1
\li Select \uicontrol File > \uicontrol {New Project} > \li Select \uicontrol File > \uicontrol {New Project} >
\uicontrol General > \uicontrol {Qt Quick Application - Empty} > \uicontrol General > \uicontrol {Empty}. Add \uicontrol {Details} about
\uicontrol Choose, and follow the instructions of the wizard to the project and select \uicontrol Create.
create an empty project.
\li In \uicontrol Projects, double-click \e Screen01.ui.qml to move to \li In \uicontrol Projects, double-click \e Screen01.ui.qml to move to
the Design mode. the Design mode.
\li Select \uicontrol Assets > \inlineimage icons/plus.png \li Select \uicontrol Assets > \inlineimage icons/plus.png
. .
\li Select the folder where you exported the assets. \li Select the folder where you exported the assets.
\li Select \uicontrol {Exported Assets (*.metadata)} in the dropdown \li Select \uicontrol {Compressed Metadata (*.qtbridge)} or
menu to filter \e .metadata files. \uicontrol {Exported Metadata (*.metadata)} in the dropdown menu to
\li Select a \e .metadata file to import, and then select filter the exported files.
\uicontrol Open. \li Select a the file to import and then select \uicontrol Open.
\li Select \uicontrol Details next to the \li Select \uicontrol Details next to the
\uicontrol {Metadata Import Paths} field to display the path where \uicontrol {Import Paths} field to display the path where the exported
the metadata is imported from. assets are imported from.
\image studio-import-metadata.png "Asset Import dialog" \image studio-asset-import.png "Asset Import dialog"
\li Select \uicontrol Details next to the \li Select \uicontrol Details next to the
\uicontrol {QML/Asset Export Paths} field to display the paths to \uicontrol {Export Paths} field to display the paths to
copy the assets to. copy the assets to.
\li In the \uicontrol QML field, you can change the folder to copy the \li In the \uicontrol QML field, you can change the folder to copy the
QML files to. QML files to.
\li In the \uicontrol Assets field, you can change the folder to copy \li In the \uicontrol Assets field, you can change the folder to copy
the image files to. the image files to.
\li Select the \uicontrol {Create sub directory for each metadata} \li Select the \uicontrol {Create sub directory} check box to import the
check box to copy the directory structure from the metadata file assets in a sub directory inside \uicontrol {Export Paths}.
to \QDS.
\li Deselect the \uicontrol {Import assets} check box if you only want \li Deselect the \uicontrol {Import assets} check box if you only want
to create QML files. to create QML files.
\li Deselect the \uicontrol {Generate QML} check box if you only \li Deselect the \uicontrol {Generate QML} check box if you only
@@ -104,26 +103,21 @@
\li Select the \uicontrol {Merge QML} check box if you have imported the \li Select the \uicontrol {Merge QML} check box if you have imported the
assets before and want to merge the changes into existing QML files assets before and want to merge the changes into existing QML files
instead of overwriting the existing files. See \l {Merging QML Files}. instead of overwriting the existing files. See \l {Merging QML Files}.
\li Select the \uicontrol {Round off coordinates} check box to round off
the position and dimension values to integers in the generated QML files.
\li Select the \uicontrol {Save Logs} check box to write the export logs
to a text file inside the directory selected in \uicontrol QML export path.
\li Select \uicontrol Import to import the QML files and assets. This \li Select \uicontrol Import to import the QML files and assets. This
might take a little while for complex projects. might take a little while for complex projects.
\endlist \endlist
The imported assets are displayed in \uicontrol Assets The imported assets are displayed in \uicontrol Assets as images.
as PNG images. The components that you specified in the design tool are The components that you specified in the design tool are displayed in
displayed in \uicontrol Components > \uicontrol {My Components} as well as \uicontrol Components > \uicontrol {My Components} as well as in the
in the \uicontrol Projects view as separate QML files. To start using them, \uicontrol Projects view as separate QML files. To use them,
drag-and-drop them from \uicontrol Components to \uicontrol {Form Editor} or drag-and-drop them from \uicontrol Components to \uicontrol {Form Editor} or
\l Navigator. \l Navigator.
\note The layer that was the bottom layer in the design tool becames the top
layer in \uicontrol Navigator to reflect the QML code model. You
can view the QML code in \l{Text Editor}.
After importing the metadata files, wait a few moments to allow all
imported assets to appear in your project files before selecting your
metadata filename from \uicontrol Assets > \inlineimage icons/plus.png
.
If asset importer conflicts, warnings, and errors are displayed in the If asset importer conflicts, warnings, and errors are displayed in the
\uicontrol {Asset Import} dialog while importing, fix the issues in \uicontrol {Asset Import} dialog while importing, fix the issues in
design tool and export the assets again. design tool and export the assets again.

View File

@@ -263,8 +263,20 @@ def qdump__Utils__Environment(d, value):
qdump__Utils__NameValueDictionary(d, value) qdump__Utils__NameValueDictionary(d, value)
def qdump__Utils__DictKey(d, value):
d.putStringValue(value["name"])
def qdump__Utils__NameValueDictionary(d, value): def qdump__Utils__NameValueDictionary(d, value):
dptr = d.extractPointer(value["m_values"]) dptr = d.extractPointer(value)
if d.qtVersion() >= 0x60000:
if dptr == 0:
d.putItemCount(0)
return
m = value['d']['d']['m']
d.putItem(m)
d.putBetterType('Utils::NameValueDictionary')
else: # Qt5
(ref, n) = d.split('ii', dptr) (ref, n) = d.split('ii', dptr)
d.check(0 <= n and n <= 100 * 1000 * 1000) d.check(0 <= n and n <= 100 * 1000 * 1000)
d.check(-1 <= ref and ref < 100000) d.check(-1 <= ref and ref < 100000)
@@ -274,7 +286,7 @@ def qdump__Utils__NameValueDictionary(d, value):
if n > 10000: if n > 10000:
n = 10000 n = 10000
typeCode = 'ppp@{%s}@{%s}' % ("Utils::DictKey", "QString") typeCode = 'ppp@{%s}@{%s}' % ("Utils::DictKey", "@QPair<@QString,bool>")
def helper(node): def helper(node):
(p, left, right, padding1, key, padding2, value) = d.split(typeCode, node) (p, left, right, padding1, key, padding2, value) = d.split(typeCode, node)

View File

@@ -39,6 +39,8 @@ Node {
// Note: Only one instance of HelperGrid is supported, as the geometry names are fixed // Note: Only one instance of HelperGrid is supported, as the geometry names are fixed
Model { // Main grid lines Model { // Main grid lines
castsShadows: false
receivesShadows: false
geometry: GridGeometry { geometry: GridGeometry {
id: gridGeometry id: gridGeometry
name: "3D Edit View Helper Grid" name: "3D Edit View Helper Grid"
@@ -55,6 +57,8 @@ Node {
} }
Model { // Subdivision lines Model { // Subdivision lines
castsShadows: false
receivesShadows: false
geometry: GridGeometry { geometry: GridGeometry {
lines: gridGeometry.lines lines: gridGeometry.lines
step: gridGeometry.step step: gridGeometry.step
@@ -73,6 +77,8 @@ Node {
} }
Model { // Z Axis Model { // Z Axis
castsShadows: false
receivesShadows: false
geometry: GridGeometry { geometry: GridGeometry {
lines: gridGeometry.lines lines: gridGeometry.lines
step: gridGeometry.step step: gridGeometry.step
@@ -89,6 +95,8 @@ Node {
] ]
} }
Model { // X Axis Model { // X Axis
castsShadows: false
receivesShadows: false
eulerRotation.z: 90 eulerRotation.z: 90
geometry: GridGeometry { geometry: GridGeometry {
lines: gridGeometry.lines lines: gridGeometry.lines

View File

@@ -54,6 +54,9 @@ Node {
visible: selectionBox.targetNode && !selectionBoxGeometry.isEmpty visible: selectionBox.targetNode && !selectionBoxGeometry.isEmpty
castsShadows: false
receivesShadows: false
materials: [ materials: [
DefaultMaterial { DefaultMaterial {
diffuseColor: "#fff600" diffuseColor: "#fff600"

View File

@@ -40,6 +40,8 @@ Node {
Model { // Main grid lines Model { // Main grid lines
readonly property bool _edit3dLocked: true // Make this non-pickable readonly property bool _edit3dLocked: true // Make this non-pickable
castsShadows: false
receivesShadows: false
geometry: GridGeometry { geometry: GridGeometry {
id: gridGeometry id: gridGeometry
name: "3D Edit View Helper Grid" name: "3D Edit View Helper Grid"
@@ -57,6 +59,8 @@ Node {
Model { // Subdivision lines Model { // Subdivision lines
readonly property bool _edit3dLocked: true // Make this non-pickable readonly property bool _edit3dLocked: true // Make this non-pickable
castsShadows: false
receivesShadows: false
geometry: GridGeometry { geometry: GridGeometry {
lines: gridGeometry.lines lines: gridGeometry.lines
step: gridGeometry.step step: gridGeometry.step
@@ -76,6 +80,8 @@ Node {
Model { // Z Axis Model { // Z Axis
readonly property bool _edit3dLocked: true // Make this non-pickable readonly property bool _edit3dLocked: true // Make this non-pickable
castsShadows: false
receivesShadows: false
geometry: GridGeometry { geometry: GridGeometry {
lines: gridGeometry.lines lines: gridGeometry.lines
step: gridGeometry.step step: gridGeometry.step
@@ -93,6 +99,8 @@ Node {
} }
Model { // X Axis Model { // X Axis
readonly property bool _edit3dLocked: true // Make this non-pickable readonly property bool _edit3dLocked: true // Make this non-pickable
castsShadows: false
receivesShadows: false
eulerRotation.z: 90 eulerRotation.z: 90
geometry: GridGeometry { geometry: GridGeometry {
lines: gridGeometry.lines lines: gridGeometry.lines

View File

@@ -55,6 +55,9 @@ Node {
visible: selectionBox.targetNode && !selectionBoxGeometry.isEmpty visible: selectionBox.targetNode && !selectionBoxGeometry.isEmpty
castsShadows: false
receivesShadows: false
materials: [ materials: [
DefaultMaterial { DefaultMaterial {
diffuseColor: "#fff600" diffuseColor: "#fff600"

View File

@@ -1610,7 +1610,7 @@ void NodeInstanceServer::addAnimation(QQuickAbstractAnimation *animation)
m_animations.push_back(animation); m_animations.push_back(animation);
QQuickPropertyAnimation *panim = qobject_cast<QQuickPropertyAnimation *>(animation); QQuickPropertyAnimation *panim = qobject_cast<QQuickPropertyAnimation *>(animation);
if (panim) { if (panim && panim->target()) {
QObject *target = panim->target(); QObject *target = panim->target();
QString property = panim->property(); QString property = panim->property();
QVariant value = target->property(qPrintable(baseProperty(property))); QVariant value = target->property(qPrintable(baseProperty(property)));

View File

@@ -534,7 +534,7 @@ void Qt5InformationNodeInstanceServer::handleParticleSystemDeselected()
for (auto a : anim) { for (auto a : anim) {
a->stop(); a->stop();
QQuickPropertyAnimation *panim = qobject_cast<QQuickPropertyAnimation *>(a); QQuickPropertyAnimation *panim = qobject_cast<QQuickPropertyAnimation *>(a);
if (panim) if (panim && panim->target())
panim->target()->setProperty(qPrintable(baseProperty(panim->property())), animationDefaultValue(i)); panim->target()->setProperty(qPrintable(baseProperty(panim->property())), animationDefaultValue(i));
i++; i++;
} }

View File

@@ -135,7 +135,7 @@ void Qt5RenderNodeInstanceServer::collectItemChangesAndSendChangeCommands()
if (rootNodeInstance().isSubclassOf("QQuick3DNode") && rootNodeInstance().contentItem() if (rootNodeInstance().isSubclassOf("QQuick3DNode") && rootNodeInstance().contentItem()
&& DesignerSupport::isDirty(rootNodeInstance().contentItem(), && DesignerSupport::isDirty(rootNodeInstance().contentItem(),
DesignerSupport::ContentUpdateMask) DesignerSupport::AllMask)
&& nodeInstanceClient()->bytesToWrite() < 10000) { && nodeInstanceClient()->bytesToWrite() < 10000) {
Internal::QuickItemNodeInstance::updateDirtyNode(rootNodeInstance().contentItem()); Internal::QuickItemNodeInstance::updateDirtyNode(rootNodeInstance().contentItem());
nodeInstanceClient()->pixmapChanged(createPixmapChangedCommand({rootNodeInstance()})); nodeInstanceClient()->pixmapChanged(createPixmapChangedCommand({rootNodeInstance()}));

View File

@@ -59,9 +59,6 @@ Item {
var complexSuffixes = rootView.supportedAssetSuffixes(true); var complexSuffixes = rootView.supportedAssetSuffixes(true);
for (const u of drag.urls) { for (const u of drag.urls) {
var url = u.toString(); var url = u.toString();
if (url.startsWith("file:///")) // remove file scheme (happens on Windows)
url = url.substr(8)
var ext = '*.' + url.slice(url.lastIndexOf('.') + 1).toLowerCase() var ext = '*.' + url.slice(url.lastIndexOf('.') + 1).toLowerCase()
if (simpleSuffixes.includes(ext)) if (simpleSuffixes.includes(ext))
root.dropSimpleExtFiles.push(url) root.dropSimpleExtFiles.push(url)

View File

@@ -143,7 +143,8 @@ Section {
PropertyLabel { PropertyLabel {
text: qsTr("Style name") text: qsTr("Style name")
tooltip: qsTr("Font's style.") tooltip: qsTr("Font's style.")
blockedByTemplate: !styleNameComboBox.enabled enabled: styleNameComboBox.model.length
blockedByTemplate: !backendValue.isAvailable
} }
SecondColumnLayout { SecondColumnLayout {
@@ -156,7 +157,7 @@ Section {
backendValue: getBackendValue("styleName") backendValue: getBackendValue("styleName")
model: styleNamesForFamily(fontComboBox.familyName) model: styleNamesForFamily(fontComboBox.familyName)
valueType: ComboBox.String valueType: ComboBox.String
enabled: backendValue.isAvailable enabled: backendValue.isAvailable && styleNameComboBox.model.length
} }
ExpandingSpacer {} ExpandingSpacer {}

View File

@@ -92,7 +92,6 @@ StudioControls.ComboBox {
onValueFromBackendChanged: colorLogic.invalidate() onValueFromBackendChanged: colorLogic.invalidate()
function invalidate() { function invalidate() {
if (comboBox.block) if (comboBox.block)
return return
@@ -140,6 +139,21 @@ StudioControls.ComboBox {
} }
} }
onAccepted: {
if (!comboBox.__isCompleted)
return
let inputValue = comboBox.editText
let index = comboBox.find(inputValue)
if (index !== -1)
inputValue = comboBox.textAt(index)
comboBox.backendValue.value = inputValue
comboBox.dirty = false
}
onCompressedActivated: { onCompressedActivated: {
if (!comboBox.__isCompleted) if (!comboBox.__isCompleted)
return return

View File

@@ -131,7 +131,7 @@ Item {
checkable: true checkable: true
onTriggered: { onTriggered: {
if (checked) if (checked)
backendValue.exportPopertyAsAlias() backendValue.exportPropertyAsAlias()
else else
backendValue.removeAliasExport() backendValue.removeAliasExport()
} }

View File

@@ -29,7 +29,7 @@ import HelperWidgets 2.0
import StudioControls 1.0 as StudioControls import StudioControls 1.0 as StudioControls
StudioControls.ComboBox { StudioControls.ComboBox {
id: comboBox id: root
property variant backendValue property variant backendValue
property color textColor: colorLogic.textColor property color textColor: colorLogic.textColor
@@ -39,17 +39,17 @@ StudioControls.ComboBox {
labelColor: colorLogic.textColor labelColor: colorLogic.textColor
editable: true editable: true
onTextColorChanged: setColor() onTextColorChanged: root.setColor()
FileResourcesModel { FileResourcesModel {
id: fileModel id: fileModel
modelNodeBackendProperty: modelNodeBackend modelNodeBackendProperty: modelNodeBackend
filter: comboBox.fontFilter filter: root.fontFilter
} }
function createFontLoader(fontUrl) { function createFontLoader(fontUrl) {
return Qt.createQmlObject('import QtQuick 2.0; FontLoader { source: "' + fontUrl + '"; }', return Qt.createQmlObject('import QtQuick 2.0; FontLoader { source: "' + fontUrl + '"; }',
comboBox, "dynamicFontLoader") root, "dynamicFontLoader")
} }
function setupModel() { function setupModel() {
@@ -63,80 +63,83 @@ StudioControls.ComboBox {
// Remove duplicate family names // Remove duplicate family names
familyNames = [...new Set(familyNames)] familyNames = [...new Set(familyNames)]
familyNames.sort() familyNames.sort()
comboBox.model = familyNames root.model = familyNames
root.currentIndex = root.find(root.backendValue.value)
} }
onModelChanged: editText = comboBox.backendValue.valueToString function setColor() {
// Hack to style the text input
for (var i = 0; i < root.children.length; i++) {
if (root.children[i].text !== undefined) {
root.children[i].color = root.textColor
}
}
}
onModelChanged: root.editText = root.backendValue.valueToString
ExtendedFunctionLogic { ExtendedFunctionLogic {
id: extFuncLogic id: extFuncLogic
backendValue: comboBox.backendValue backendValue: root.backendValue
} }
actionIndicator.icon.color: extFuncLogic.color actionIndicator.icon.color: extFuncLogic.color
actionIndicator.icon.text: extFuncLogic.glyph actionIndicator.icon.text: extFuncLogic.glyph
actionIndicator.onClicked: extFuncLogic.show() actionIndicator.onClicked: extFuncLogic.show()
actionIndicator.forceVisible: extFuncLogic.menuVisible actionIndicator.forceVisible: extFuncLogic.menuVisible
actionIndicator.visible: comboBox.showExtendedFunctionButton actionIndicator.visible: root.showExtendedFunctionButton
ColorLogic { ColorLogic {
id: colorLogic id: colorLogic
property string textValue: comboBox.backendValue.valueToString property string textValue: root.backendValue.valueToString
backendValue: comboBox.backendValue backendValue: root.backendValue
onTextValueChanged: comboBox.editText = colorLogic.textValue onTextValueChanged: root.editText = colorLogic.textValue
} }
onAccepted: { onAccepted: {
if (backendValue === undefined) if (root.backendValue === undefined)
return return
if (editText === "") if (root.editText === "")
return return
if (backendValue.value !== editText) if (root.backendValue.value !== root.editText)
backendValue.value = editText; root.backendValue.value = root.editText
} }
onActivated: { onCompressedActivated: function(index, reason) { root.handleActivate(index) }
if (backendValue === undefined)
function handleActivate(index)
{
if (root.backendValue === undefined)
return return
if (editText === "") if (root.editText === "")
return return
var indexText = comboBox.textAt(index) var indexText = root.textAt(index)
if (backendValue.value !== indexText) if (root.backendValue.value !== indexText)
backendValue.value = indexText root.backendValue.value = indexText
} }
Connections { Connections {
target: modelNodeBackend target: modelNodeBackend
function onSelectionChanged() { function onSelectionChanged() {
comboBox.editText = backendValue.value root.editText = root.backendValue.value
setupModel() root.setupModel()
} }
} }
Component.onCompleted: { Component.onCompleted: {
setupModel() root.setupModel()
// Hack to style the text input // Hack to style the text input
for (var i = 0; i < comboBox.children.length; i++) { for (var i = 0; i < root.children.length; i++) {
if (comboBox.children[i].text !== undefined) { if (root.children[i].text !== undefined) {
comboBox.children[i].color = comboBox.textColor root.children[i].color = root.textColor
comboBox.children[i].anchors.rightMargin = 34 root.children[i].anchors.rightMargin = 34
comboBox.children[i].anchors.leftMargin = 18 root.children[i].anchors.leftMargin = 18
} }
} }
} }
function setColor() {
// Hack to style the text input
for (var i = 0; i < comboBox.children.length; i++) {
if (comboBox.children[i].text !== undefined) {
comboBox.children[i].color = comboBox.textColor
}
}
}
} }

View File

@@ -32,36 +32,43 @@ StudioControls.TextField {
id: lineEdit id: lineEdit
property variant backendValue property variant backendValue
property color borderColor: "#222"
property color highlightColor: "orange"
color: lineEdit.edit ? StudioTheme.Values.themeTextColor : colorLogic.textColor
property bool showTranslateCheckBox: true
translationIndicatorVisible: showTranslateCheckBox
property bool writeValueManually: false property bool writeValueManually: false
property bool writeAsExpression: false property bool writeAsExpression: false
property bool __dirty: false property bool showTranslateCheckBox: true
property bool showExtendedFunctionButton: true property bool showExtendedFunctionButton: true
property string context
actionIndicator.visible: showExtendedFunctionButton property bool __dirty: false
signal commitData signal commitData
property string context color: lineEdit.edit ? StudioTheme.Values.themeTextColor : colorLogic.textColor
actionIndicator.visible: lineEdit.showExtendedFunctionButton
translationIndicatorVisible: lineEdit.showTranslateCheckBox
function setTranslateExpression() { function setTranslateExpression() {
if (translateFunction() === "qsTranslate") { if (translateFunction() === "qsTranslate") {
backendValue.expression = translateFunction() lineEdit.backendValue.expression = translateFunction()
+ "(\"" + backendValue.getTranslationContext() + "(\"" + lineEdit.backendValue.getTranslationContext()
+ "\", " + "\"" + escapeString(text) + "\")" + "\", " + "\"" + lineEdit.escapeString(lineEdit.text) + "\")"
} else { } else {
backendValue.expression = translateFunction() + "(\"" + escapeString(text) + "\")" lineEdit.backendValue.expression = translateFunction()
+ "(\"" + lineEdit.escapeString(lineEdit.text) + "\")"
} }
} }
function escapeString(string) {
var str = string
str = str.replace(/\\/g, "\\\\")
str.replace(/\"/g, "\\\"")
str = str.replace(/\t/g, "\\t")
str = str.replace(/\r/g, "\\r")
str = str.replace(/\n/g, '\\n')
return str
}
ExtendedFunctionLogic { ExtendedFunctionLogic {
id: extFuncLogic id: extFuncLogic
backendValue: lineEdit.backendValue backendValue: lineEdit.backendValue
@@ -79,60 +86,58 @@ StudioControls.TextField {
if (colorLogic.valueFromBackend === undefined) { if (colorLogic.valueFromBackend === undefined) {
lineEdit.text = "" lineEdit.text = ""
} else { } else {
if (writeValueManually) if (lineEdit.writeValueManually)
lineEdit.text = convertColorToString(colorLogic.valueFromBackend) lineEdit.text = convertColorToString(colorLogic.valueFromBackend)
else else
lineEdit.text = colorLogic.valueFromBackend lineEdit.text = colorLogic.valueFromBackend
} }
__dirty = false lineEdit.__dirty = false
} }
} }
onTextChanged: { onTextChanged: lineEdit.__dirty = true
__dirty = true
}
Connections { Connections {
target: modelNodeBackend target: modelNodeBackend
function onSelectionToBeChanged() { function onSelectionToBeChanged() {
if (__dirty && !writeValueManually) { if (lineEdit.__dirty && !lineEdit.writeValueManually) {
if (writeAsExpression) if (lineEdit.writeAsExpression)
lineEdit.backendValue.expression = text lineEdit.backendValue.expression = lineEdit.text
else else
lineEdit.backendValue.value = text lineEdit.backendValue.value = lineEdit.text
} else if (__dirty) { } else if (lineEdit.__dirty) {
commitData() commitData()
} }
__dirty = false lineEdit.__dirty = false
} }
} }
onEditingFinished: { onEditingFinished: {
if (writeValueManually) if (lineEdit.writeValueManually)
return return
if (!__dirty) if (!lineEdit.__dirty)
return return
if (backendValue.isTranslated) { if (lineEdit.backendValue.isTranslated) {
setTranslateExpression() lineEdit.setTranslateExpression()
} else { } else {
if (writeAsExpression) { if (lineEdit.writeAsExpression) {
if (lineEdit.backendValue.expression !== text) if (lineEdit.backendValue.expression !== lineEdit.text)
lineEdit.backendValue.expression = text lineEdit.backendValue.expression = lineEdit.text
} else if (lineEdit.backendValue.value !== text) { } else if (lineEdit.backendValue.value !== lineEdit.text) {
lineEdit.backendValue.value = text lineEdit.backendValue.value = lineEdit.text
} }
} }
__dirty = false lineEdit.__dirty = false
} }
property bool isTranslated: colorLogic.backendValue === undefined ? false property bool isTranslated: colorLogic.backendValue === undefined ? false
: colorLogic.backendValue.isTranslated : colorLogic.backendValue.isTranslated
translationIndicator.onClicked: { translationIndicator.onClicked: {
if (translationIndicator.checked) { if (lineEdit.translationIndicator.checked) {
setTranslateExpression() setTranslateExpression()
} else { } else {
var textValue = lineEdit.text var textValue = lineEdit.text
@@ -141,7 +146,8 @@ StudioControls.TextField {
colorLogic.evaluate() colorLogic.evaluate()
} }
property variant backendValueValueInternal: backendValue === undefined ? 0 : backendValue.value property variant backendValueValueInternal: lineEdit.backendValue === undefined ? 0
: lineEdit.backendValue.value
onBackendValueValueInternalChanged: { onBackendValueValueInternalChanged: {
if (lineEdit.backendValue === undefined) if (lineEdit.backendValue === undefined)
lineEdit.translationIndicator.checked = false lineEdit.translationIndicator.checked = false
@@ -155,15 +161,4 @@ StudioControls.TextField {
else else
lineEdit.translationIndicator.checked = lineEdit.backendValue.isTranslated lineEdit.translationIndicator.checked = lineEdit.backendValue.isTranslated
} }
function escapeString(string) {
var str = string
str = str.replace(/\\/g, "\\\\")
str.replace(/\"/g, "\\\"")
str = str.replace(/\t/g, "\\t")
str = str.replace(/\r/g, "\\r")
str = str.replace(/\n/g, '\\n')
return str
}
} }

View File

@@ -32,7 +32,7 @@ import StudioTheme 1.0 as StudioTheme
import QtQuickDesignerTheme 1.0 import QtQuickDesignerTheme 1.0
Row { Row {
id: urlChooser id: root
property variant backendValue property variant backendValue
property color textColor: colorLogic.highlight ? colorLogic.textColor property color textColor: colorLogic.highlight ? colorLogic.textColor
@@ -47,22 +47,24 @@ Row {
FileResourcesModel { FileResourcesModel {
id: fileModel id: fileModel
modelNodeBackendProperty: modelNodeBackend modelNodeBackendProperty: modelNodeBackend
filter: urlChooser.filter filter: root.filter
} }
ColorLogic { ColorLogic {
id: colorLogic id: colorLogic
backendValue: urlChooser.backendValue backendValue: root.backendValue
} }
StudioControls.ComboBox { StudioControls.FilterComboBox {
id: comboBox id: comboBox
property ListModel items: ListModel {} property ListModel listModel: ListModel {}
implicitWidth: StudioTheme.Values.singleControlColumnWidth implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ StudioTheme.Values.actionIndicatorWidth + StudioTheme.Values.actionIndicatorWidth
width: implicitWidth width: implicitWidth
allowUserInput: true
// Note: highlightedIndex property isn't used because it has no setter and it doesn't reset // Note: highlightedIndex property isn't used because it has no setter and it doesn't reset
// when the combobox is closed by focusing on some other control. // when the combobox is closed by focusing on some other control.
property int hoverIndex: -1 property int hoverIndex: -1
@@ -70,7 +72,7 @@ Row {
ToolTip { ToolTip {
id: toolTip id: toolTip
visible: comboBox.hover && toolTip.text !== "" visible: comboBox.hover && toolTip.text !== ""
text: urlChooser.backendValue.valueToString text: root.backendValue.valueToString
delay: StudioTheme.Values.toolTipDelay delay: StudioTheme.Values.toolTipDelay
height: StudioTheme.Values.toolTipHeight height: StudioTheme.Values.toolTipHeight
background: Rectangle { background: Rectangle {
@@ -88,27 +90,39 @@ Row {
delegate: ItemDelegate { delegate: ItemDelegate {
required property string fullPath required property string fullPath
required property string name required property string name
required property int group
required property int index required property int index
id: delegateItem id: delegateRoot
width: parent.width width: comboBox.popup.width - comboBox.popup.leftPadding - comboBox.popup.rightPadding
- (comboBox.popupScrollBar.visible ? comboBox.popupScrollBar.contentItem.implicitWidth + 2
: 0) // TODO Magic number
height: StudioTheme.Values.height - 2 * StudioTheme.Values.border height: StudioTheme.Values.height - 2 * StudioTheme.Values.border
padding: 0 padding: 0
highlighted: comboBox.highlightedIndex === index hoverEnabled: true
highlighted: comboBox.highlightedIndex === delegateRoot.DelegateModel.itemsIndex
onHoveredChanged: {
if (delegateRoot.hovered && !comboBox.popupMouseArea.active)
comboBox.setHighlightedIndexItems(delegateRoot.DelegateModel.itemsIndex)
}
onClicked: comboBox.selectItem(delegateRoot.DelegateModel.itemsIndex)
indicator: Item { indicator: Item {
id: itemDelegateIconArea id: itemDelegateIconArea
width: delegateItem.height width: delegateRoot.height
height: delegateItem.height height: delegateRoot.height
Label { Label {
id: itemDelegateIcon id: itemDelegateIcon
text: StudioTheme.Constants.tickIcon text: StudioTheme.Constants.tickIcon
color: delegateItem.highlighted ? StudioTheme.Values.themeTextSelectedTextColor color: delegateRoot.highlighted ? StudioTheme.Values.themeTextSelectedTextColor
: StudioTheme.Values.themeTextColor : StudioTheme.Values.themeTextColor
font.family: StudioTheme.Constants.iconFont.family font.family: StudioTheme.Constants.iconFont.family
font.pixelSize: StudioTheme.Values.spinControlIconSizeMulti font.pixelSize: StudioTheme.Values.spinControlIconSizeMulti
visible: comboBox.currentIndex === index ? true : false visible: comboBox.currentIndex === delegateRoot.DelegateModel.itemsIndex ? true
: false
anchors.fill: parent anchors.fill: parent
renderType: Text.NativeRendering renderType: Text.NativeRendering
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
@@ -119,7 +133,7 @@ Row {
contentItem: Text { contentItem: Text {
leftPadding: itemDelegateIconArea.width leftPadding: itemDelegateIconArea.width
text: name text: name
color: delegateItem.highlighted ? StudioTheme.Values.themeTextSelectedTextColor color: delegateRoot.highlighted ? StudioTheme.Values.themeTextSelectedTextColor
: StudioTheme.Values.themeTextColor : StudioTheme.Values.themeTextColor
font: comboBox.font font: comboBox.font
elide: Text.ElideRight elide: Text.ElideRight
@@ -127,17 +141,17 @@ Row {
} }
background: Rectangle { background: Rectangle {
id: itemDelegateBackground
x: 0 x: 0
y: 0 y: 0
width: delegateItem.width width: delegateRoot.width
height: delegateItem.height height: delegateRoot.height
color: delegateItem.highlighted ? StudioTheme.Values.themeInteraction : "transparent" color: delegateRoot.highlighted ? StudioTheme.Values.themeInteraction
: "transparent"
} }
ToolTip { ToolTip {
id: itemToolTip id: itemToolTip
visible: delegateItem.hovered && comboBox.highlightedIndex === index visible: delegateRoot.hovered && comboBox.highlightedIndex === index
text: fullPath text: fullPath
delay: StudioTheme.Values.toolTipDelay delay: StudioTheme.Values.toolTipDelay
height: StudioTheme.Values.toolTipHeight height: StudioTheme.Values.toolTipHeight
@@ -161,7 +175,7 @@ Row {
ExtendedFunctionLogic { ExtendedFunctionLogic {
id: extFuncLogic id: extFuncLogic
backendValue: urlChooser.backendValue backendValue: root.backendValue
onReseted: comboBox.editText = "" onReseted: comboBox.editText = ""
} }
@@ -181,20 +195,15 @@ Row {
// Takes into account applied bindings // Takes into account applied bindings
property string textValue: { property string textValue: {
if (urlChooser.backendValue.isBound) if (root.backendValue.isBound)
return urlChooser.backendValue.expression return root.backendValue.expression
var fullPath = urlChooser.backendValue.valueToString var fullPath = root.backendValue.valueToString
return fullPath.substr(fullPath.lastIndexOf('/') + 1) return fullPath.substr(fullPath.lastIndexOf('/') + 1)
} }
onTextValueChanged: comboBox.setCurrentText(comboBox.textValue) onTextValueChanged: comboBox.setCurrentText(comboBox.textValue)
editable: true
textRole: "name"
valueRole: "fullPath"
model: comboBox.items
onModelChanged: { onModelChanged: {
if (!comboBox.isComplete) if (!comboBox.isComplete)
return return
@@ -206,20 +215,14 @@ Row {
if (!comboBox.isComplete) if (!comboBox.isComplete)
return return
var inputValue = comboBox.editText let inputValue = comboBox.editText
// Check if value set by user matches with a name in the model then pick the full path // Check if value set by user matches with a name in the model then pick the full path
var index = comboBox.find(inputValue) let index = comboBox.find(inputValue)
if (index !== -1) if (index !== -1)
inputValue = comboBox.items.get(index).fullPath inputValue = comboBox.items.get(index).model.fullPath
// Get the currently assigned backend value, extract its file name and compare it to the root.backendValue.value = inputValue
// input value. If they differ the new value needs to be set.
var currentValue = urlChooser.backendValue.value
var fileName = currentValue.substr(currentValue.lastIndexOf('/') + 1);
if (fileName !== inputValue)
urlChooser.backendValue.value = inputValue
comboBox.dirty = false comboBox.dirty = false
} }
@@ -234,14 +237,16 @@ Row {
} }
function handleActivate(index) { function handleActivate(index) {
if (urlChooser.backendValue === undefined || !comboBox.isComplete) if (root.backendValue === undefined || !comboBox.isComplete)
return return
if (index === -1) // select first item if index is invalid let inputValue = comboBox.editText
index = 0
if (urlChooser.backendValue.value !== comboBox.items.get(index).fullPath) if (index >= 0)
urlChooser.backendValue.value = comboBox.items.get(index).fullPath inputValue = comboBox.items.get(index).model.fullPath
if (root.backendValue.value !== inputValue)
root.backendValue.value = inputValue
comboBox.dirty = false comboBox.dirty = false
} }
@@ -250,7 +255,7 @@ Row {
// Hack to style the text input // Hack to style the text input
for (var i = 0; i < comboBox.children.length; i++) { for (var i = 0; i < comboBox.children.length; i++) {
if (comboBox.children[i].text !== undefined) { if (comboBox.children[i].text !== undefined) {
comboBox.children[i].color = urlChooser.textColor comboBox.children[i].color = root.textColor
comboBox.children[i].anchors.rightMargin = 34 comboBox.children[i].anchors.rightMargin = 34
} }
} }
@@ -261,36 +266,44 @@ Row {
function createModel() { function createModel() {
// Build the combobox model // Build the combobox model
comboBox.items.clear() comboBox.listModel.clear()
// While adding items to the model this binding needs to be interrupted, otherwise the
// update function of the SortFilterModel is triggered every time on append() which makes
// QtDS very slow. This will happen when selecting different items in the scene.
comboBox.model = {}
if (urlChooser.defaultItems !== undefined) { if (root.defaultItems !== undefined) {
for (var i = 0; i < urlChooser.defaultItems.length; ++i) { for (var i = 0; i < root.defaultItems.length; ++i) {
comboBox.items.append({ comboBox.listModel.append({
fullPath: urlChooser.defaultItems[i], fullPath: root.defaultItems[i],
name: urlChooser.defaultItems[i] name: root.defaultItems[i],
group: 0
}) })
} }
} }
for (var j = 0; j < fileModel.fullPathModel.length; ++j) { for (var j = 0; j < fileModel.fullPathModel.length; ++j) {
comboBox.items.append({ comboBox.listModel.append({
fullPath: fileModel.fullPathModel[j], fullPath: fileModel.fullPathModel[j],
name: fileModel.fileNameModel[j] name: fileModel.fileNameModel[j],
group: 1
}) })
} }
comboBox.model = Qt.binding(function() { return comboBox.listModel })
} }
Connections { Connections {
target: fileModel target: fileModel
function onFullPathModelChanged() { function onFullPathModelChanged() {
urlChooser.createModel() root.createModel()
comboBox.setCurrentText(comboBox.textValue) comboBox.setCurrentText(comboBox.textValue)
} }
} }
onDefaultItemsChanged: urlChooser.createModel() onDefaultItemsChanged: root.createModel()
Component.onCompleted: urlChooser.createModel() Component.onCompleted: root.createModel()
function indexOf(model, criteria) { function indexOf(model, criteria) {
for (var i = 0; i < model.count; ++i) { for (var i = 0; i < model.count; ++i) {
@@ -305,16 +318,16 @@ Row {
function onStateChanged(state) { function onStateChanged(state) {
// update currentIndex when the popup opens to override the default behavior in super classes // update currentIndex when the popup opens to override the default behavior in super classes
// that selects currentIndex based on values in the combo box. // that selects currentIndex based on values in the combo box.
if (comboBox.popup.opened && !urlChooser.backendValue.isBound) { if (comboBox.popup.opened && !root.backendValue.isBound) {
var index = urlChooser.indexOf(comboBox.items, var index = root.indexOf(comboBox.items,
function(item) { function(item) {
return item.fullPath === urlChooser.backendValue.value return item.fullPath === root.backendValue.value
}) })
if (index !== -1) { if (index !== -1) {
comboBox.currentIndex = index comboBox.currentIndex = index
comboBox.hoverIndex = index comboBox.hoverIndex = index
comboBox.editText = comboBox.items.get(index).name comboBox.editText = comboBox.items.get(index).model.name
} }
} }
} }
@@ -324,11 +337,11 @@ Row {
IconIndicator { IconIndicator {
icon: StudioTheme.Constants.addFile icon: StudioTheme.Constants.addFile
iconColor: urlChooser.textColor iconColor: root.textColor
onClicked: { onClicked: {
fileModel.openFileDialog() fileModel.openFileDialog()
if (fileModel.fileName !== "") if (fileModel.fileName !== "")
urlChooser.backendValue.value = fileModel.fileName root.backendValue.value = fileModel.fileName
} }
} }
} }

View File

@@ -50,16 +50,16 @@ Rectangle {
id: checkIndicatorMouseArea id: checkIndicatorMouseArea
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
onPressed: { onClicked: {
if (myControl.activeFocus)
myControl.focus = false
if (myPopup.opened) { if (myPopup.opened) {
myPopup.close() myPopup.close()
} else { } else {
myPopup.open() myPopup.open()
myPopup.forceActiveFocus() myPopup.forceActiveFocus()
} }
if (myControl.activeFocus)
myControl.focus = false
} }
} }

View File

@@ -65,6 +65,11 @@ T.ComboBox {
comboBoxPopup.close() comboBoxPopup.close()
} }
onActiveFocusChanged: {
if (myComboBox.activeFocus)
comboBoxInput.preFocusText = myComboBox.editText
}
ActionIndicator { ActionIndicator {
id: actionIndicator id: actionIndicator
myControl: myComboBox myControl: myComboBox
@@ -76,19 +81,22 @@ T.ComboBox {
contentItem: ComboBoxInput { contentItem: ComboBoxInput {
id: comboBoxInput id: comboBoxInput
property string preFocusText: ""
myControl: myComboBox myControl: myComboBox
text: myComboBox.editText text: myComboBox.editText
onEditingFinished: { onEditingFinished: {
comboBoxInput.deselect() comboBoxInput.deselect()
comboBoxInput.focus = false comboBoxInput.focus = false
myComboBox.focus = false
// Only trigger the signal, if the value was modified // Only trigger the signal, if the value was modified
if (myComboBox.dirty) { if (myComboBox.dirty) {
myTimer.stop() myTimer.stop()
myComboBox.dirty = false myComboBox.dirty = false
myComboBox.compressedActivated(myComboBox.find(myComboBox.editText), myComboBox.accepted()
ComboBox.ActivatedReason.EditingFinished)
} }
} }
onTextEdited: myComboBox.dirty = true onTextEdited: myComboBox.dirty = true
@@ -276,7 +284,7 @@ T.ComboBox {
PropertyChanges { PropertyChanges {
target: comboBoxBackground target: comboBoxBackground
color: StudioTheme.Values.themeControlBackgroundInteraction color: StudioTheme.Values.themeControlBackgroundInteraction
border.color: StudioTheme.Values.themeControlOutline border.color: StudioTheme.Values.themeControlOutlineInteraction
} }
StateChangeScript { StateChangeScript {
script: comboBoxPopup.close() script: comboBoxPopup.close()
@@ -312,7 +320,10 @@ T.ComboBox {
] ]
Keys.onPressed: function(event) { Keys.onPressed: function(event) {
if (event.key === Qt.Key_Escape) if (event.key === Qt.Key_Escape) {
myComboBox.editText = comboBoxInput.preFocusText
myComboBox.dirty = true
myComboBox.focus = false myComboBox.focus = false
} }
} }
}

View File

@@ -73,13 +73,13 @@ TextInput {
acceptedButtons: Qt.LeftButton acceptedButtons: Qt.LeftButton
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onPressed: function(mouse) { onPressed: function(mouse) {
if (textInput.readOnly) { if (!textInput.myControl.editable) {
if (myControl.popup.opened) { if (myControl.popup.opened) {
myControl.popup.close() myControl.popup.close()
myControl.focus = false myControl.focus = false
} else { } else {
myControl.forceActiveFocus()
myControl.popup.open() myControl.popup.open()
myControl.forceActiveFocus()
} }
} else { } else {
textInput.forceActiveFocus() textInput.forceActiveFocus()

View File

@@ -0,0 +1,752 @@
/****************************************************************************
**
** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Quick 3D.
**
** $QT_BEGIN_LICENSE:GPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 or (at your option) any later version
** approved by the KDE Free Qt Foundation. The licenses are as published by
** the Free Software Foundation and appearing in the file LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
import QtQuick
import QtQuick.Templates as T
import StudioTheme 1.0 as StudioTheme
Item {
id: root
enum Interaction { None, TextEdit, Key }
property int currentInteraction: FilterComboBox.Interaction.None
property alias model: sortFilterModel.model
property alias items: sortFilterModel.items
property alias delegate: sortFilterModel.delegate
property alias font: textInput.font
// This indicates if the value was committed or the user is still editing
property bool editing: false
// This is the actual filter that is applied on the model
property string filter: ""
property bool filterActive: root.filter !== ""
// Accept arbitrary input or only items from the model
property bool allowUserInput: false
property alias editText: textInput.text
property int highlightedIndex: -1 // items index
property int currentIndex: -1 // items index
property string autocompleteString: ""
property bool __isCompleted: false
property alias actionIndicator: actionIndicator
// This property is used to indicate the global hover state
property bool hover: actionIndicator.hover || textInput.hover || checkIndicator.hover
property alias edit: textInput.edit
property alias open: popup.visible
property alias actionIndicatorVisible: actionIndicator.visible
property real __actionIndicatorWidth: StudioTheme.Values.actionIndicatorWidth
property real __actionIndicatorHeight: StudioTheme.Values.actionIndicatorHeight
property bool dirty: false // user modification flag
property bool escapePressed: false
signal accepted()
signal activated(int index)
signal compressedActivated(int index, int reason)
enum ActivatedReason { EditingFinished, Other }
property alias popup: popup
property alias popupScrollBar: popupScrollBar
property alias popupMouseArea: popupMouseArea
width: StudioTheme.Values.defaultControlWidth
height: StudioTheme.Values.defaultControlHeight
implicitHeight: StudioTheme.Values.defaultControlHeight
function selectItem(itemsIndex) {
textInput.text = sortFilterModel.items.get(itemsIndex).model.name
root.currentIndex = itemsIndex
root.finishEditing()
root.activated(itemsIndex)
}
function submitValue() {
if (!root.allowUserInput) {
// If input isn't according to any item in the model, don't finish editing
if (root.highlightedIndex === -1)
return
root.selectItem(root.highlightedIndex)
} else {
root.currentIndex = -1
// Only trigger the signal, if the value was modified
if (root.dirty) {
myTimer.stop()
root.dirty = false
root.editText = root.editText.trim()
}
root.finishEditing()
root.accepted()
}
}
function finishEditing() {
root.editing = false
root.filter = ""
root.autocompleteString = ""
textInput.focus = false // Remove focus from text field
popup.close()
}
function increaseVisibleIndex() {
let numItems = sortFilterModel.visibleGroup.count
if (!numItems)
return
if (root.highlightedIndex === -1) // Nothing is selected
root.setHighlightedIndexVisible(0)
else {
let currentVisibleIndex = sortFilterModel.items.get(root.highlightedIndex).visibleIndex
++currentVisibleIndex
if (currentVisibleIndex > numItems - 1)
currentVisibleIndex = 0
root.setHighlightedIndexVisible(currentVisibleIndex)
}
}
function decreaseVisibleIndex() {
let numItems = sortFilterModel.visibleGroup.count
if (!numItems)
return
if (root.highlightedIndex === -1) // Nothing is selected
root.setHighlightedIndexVisible(numItems - 1)
else {
let currentVisibleIndex = sortFilterModel.items.get(root.highlightedIndex).visibleIndex
--currentVisibleIndex
if (currentVisibleIndex < 0)
currentVisibleIndex = numItems - 1
root.setHighlightedIndexVisible(currentVisibleIndex)
}
}
function updateHighlightedIndex() {
// Check if current index is still part of the filtered list, if not set it to 0
if (root.highlightedIndex !== -1 && !sortFilterModel.items.get(root.highlightedIndex).inVisible) {
root.setHighlightedIndexVisible(0)
} else {
// Needs to be set in order for ListView to keep its currenIndex up to date, so
// scroll position gets updated according to the higlighted item
root.setHighlightedIndexItems(root.highlightedIndex)
}
}
function setHighlightedIndexItems(itemsIndex) { // items group index
root.highlightedIndex = itemsIndex
if (itemsIndex === -1)
listView.currentIndex = -1
else
listView.currentIndex = sortFilterModel.items.get(itemsIndex).visibleIndex
}
function setHighlightedIndexVisible(visibleIndex) { // visible group index
if (visibleIndex === -1)
root.highlightedIndex = -1
else
root.highlightedIndex = sortFilterModel.visibleGroup.get(visibleIndex).itemsIndex
listView.currentIndex = visibleIndex
}
function updateAutocomplete() {
if (root.highlightedIndex === -1)
root.autocompleteString = ""
else {
let suggestion = sortFilterModel.items.get(root.highlightedIndex).model.name
root.autocompleteString = suggestion.substring(textInput.text.length)
}
}
// TODO is this already case insensitiv?!
function find(text) {
for (let i = 0; i < sortFilterModel.items.count; ++i)
if (sortFilterModel.items.get(i).model.name === text)
return i
return -1
}
Timer {
id: myTimer
property int activatedIndex
repeat: false
running: false
interval: 100
onTriggered: root.compressedActivated(myTimer.activatedIndex,
ComboBox.ActivatedReason.Other)
}
onActivated: function(index) {
myTimer.activatedIndex = index
myTimer.restart()
}
onHighlightedIndexChanged: {
if (root.editing || (root.editText === "" && root.allowUserInput))
root.updateAutocomplete()
}
DelegateModel {
id: noMatchesModel
model: ListModel {
ListElement { name: "No matches" }
}
delegate: ItemDelegate {
id: noMatchesDelegate
width: popup.width - popup.leftPadding - popup.rightPadding
- (popupScrollBar.visible ? popupScrollBar.contentItem.implicitWidth + 2
: 0) // TODO Magic number
height: StudioTheme.Values.height - 2 * StudioTheme.Values.border
padding: 0
contentItem: Text {
leftPadding: StudioTheme.Values.inputHorizontalPadding
text: name
font.italic: true
color: StudioTheme.Values.themeTextColor
elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter
}
background: Rectangle {
x: 0
y: 0
width: noMatchesDelegate.width
height: noMatchesDelegate.height
color: "transparent"
}
}
}
SortFilterModel {
id: sortFilterModel
filterAcceptsItem: function(item) {
return item.name.toLowerCase().startsWith(root.filter.toLowerCase())
}
lessThan: function(left, right) {
if (left.group === right.group) {
return left.name.toLowerCase().localeCompare(right.name.toLowerCase())
}
return left.group - right.group
}
delegate: ItemDelegate {
id: delegateRoot
width: popup.width - popup.leftPadding - popup.rightPadding
- (popupScrollBar.visible ? popupScrollBar.contentItem.implicitWidth + 2
: 0) // TODO Magic number
height: StudioTheme.Values.height - 2 * StudioTheme.Values.border
padding: 0
hoverEnabled: true
highlighted: root.highlightedIndex === delegateRoot.DelegateModel.itemsIndex
onHoveredChanged: {
if (delegateRoot.hovered && !popupMouseArea.active)
root.setHighlightedIndexItems(delegateRoot.DelegateModel.itemsIndex)
}
onClicked: root.selectItem(delegateRoot.DelegateModel.itemsIndex)
indicator: Item {
id: itemDelegateIconArea
width: delegateRoot.height
height: delegateRoot.height
T.Label {
id: itemDelegateIcon
text: StudioTheme.Constants.tickIcon
color: delegateRoot.highlighted ? StudioTheme.Values.themeTextSelectedTextColor
: StudioTheme.Values.themeTextColor
font.family: StudioTheme.Constants.iconFont.family
font.pixelSize: StudioTheme.Values.spinControlIconSizeMulti
visible: root.currentIndex === delegateRoot.DelegateModel.itemsIndex ? true
: false
anchors.fill: parent
renderType: Text.NativeRendering
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
contentItem: Text {
leftPadding: itemDelegateIconArea.width
text: name
color: delegateRoot.highlighted ? StudioTheme.Values.themeTextSelectedTextColor
: StudioTheme.Values.themeTextColor
font: textInput.font
elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter
}
background: Rectangle {
x: 0
y: 0
width: delegateRoot.width
height: delegateRoot.height
color: delegateRoot.highlighted ? StudioTheme.Values.themeInteraction
: "transparent"
}
}
onUpdated: {
if (!root.__isCompleted)
return
if (sortFilterModel.count === 0)
root.setHighlightedIndexVisible(-1)
else {
if (root.highlightedIndex === -1 && !root.allowUserInput)
root.setHighlightedIndexVisible(0)
}
}
}
Row {
ActionIndicator {
id: actionIndicator
myControl: root
x: 0
y: 0
width: actionIndicator.visible ? root.__actionIndicatorWidth : 0
height: actionIndicator.visible ? root.__actionIndicatorHeight : 0
}
TextInput {
id: textInput
property bool hover: textInputMouseArea.containsMouse && textInput.enabled
property bool edit: textInput.activeFocus
property string preFocusText: ""
x: 0
y: 0
z: 2
width: root.width - actionIndicator.width
height: root.height
leftPadding: StudioTheme.Values.inputHorizontalPadding
rightPadding: StudioTheme.Values.inputHorizontalPadding + checkIndicator.width
+ StudioTheme.Values.border
horizontalAlignment: Qt.AlignLeft
verticalAlignment: Qt.AlignVCenter
color: StudioTheme.Values.themeTextColor
selectionColor: StudioTheme.Values.themeTextSelectionColor
selectedTextColor: StudioTheme.Values.themeTextSelectedTextColor
selectByMouse: true
clip: true
Rectangle {
id: textInputBackground
z: -1
width: textInput.width
height: textInput.height
color: StudioTheme.Values.themeControlBackground
border.color: StudioTheme.Values.themeControlOutline
border.width: StudioTheme.Values.border
}
MouseArea {
id: textInputMouseArea
anchors.fill: parent
enabled: true
hoverEnabled: true
propagateComposedEvents: true
acceptedButtons: Qt.LeftButton
cursorShape: Qt.PointingHandCursor
onPressed: function(mouse) {
textInput.forceActiveFocus()
mouse.accepted = false
}
// Stop scrollable views from scrolling while ComboBox is in edit mode and the mouse
// pointer is on top of it. We might add wheel selection in the future.
onWheel: function(wheel) {
wheel.accepted = root.edit
}
}
onEditingFinished: {
if (root.escapePressed) {
root.escapePressed = false
root.editText = textInput.preFocusText
} else {
if (root.currentInteraction === FilterComboBox.Interaction.TextEdit) {
if (root.dirty)
root.submitValue()
} else if (root.currentInteraction === FilterComboBox.Interaction.Key) {
root.selectItem(root.highlightedIndex)
}
}
sortFilterModel.update()
}
onTextEdited: {
root.currentInteraction = FilterComboBox.Interaction.TextEdit
root.editing = true
popupMouseArea.active = true
root.dirty = true
if (textInput.text !== "")
root.filter = textInput.text
else {
root.filter = ""
root.autocompleteString = ""
}
if (!popup.visible)
popup.open()
sortFilterModel.update()
if (!root.allowUserInput)
root.updateHighlightedIndex()
else
root.setHighlightedIndexVisible(-1)
root.updateAutocomplete()
}
onActiveFocusChanged: {
if (textInput.activeFocus) {
popup.open()
textInput.preFocusText = textInput.text
} else
popup.close()
}
states: [
State {
name: "default"
when: root.enabled && !textInput.edit && !root.hover && !root.open
PropertyChanges {
target: textInputBackground
color: StudioTheme.Values.themeControlBackground
}
PropertyChanges {
target: textInputMouseArea
cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton
}
},
State {
name: "globalHover"
when: root.hover && !textInput.hover && !textInput.edit && !root.open
PropertyChanges {
target: textInputBackground
color: StudioTheme.Values.themeControlBackgroundGlobalHover
}
},
State {
name: "hover"
when: textInput.hover && root.hover && !textInput.edit
PropertyChanges {
target: textInputBackground
color: StudioTheme.Values.themeControlBackgroundHover
}
},
State {
name: "edit"
when: root.edit
PropertyChanges {
target: textInputBackground
color: StudioTheme.Values.themeControlBackgroundInteraction
border.color: StudioTheme.Values.themeControlOutlineInteraction
}
PropertyChanges {
target: textInputMouseArea
cursorShape: Qt.IBeamCursor
acceptedButtons: Qt.NoButton
}
},
State {
name: "disable"
when: !root.enabled
PropertyChanges {
target: textInputBackground
color: StudioTheme.Values.themeControlBackgroundDisabled
}
PropertyChanges {
target: textInput
color: StudioTheme.Values.themeTextColorDisabled
}
}
]
Text {
visible: root.autocompleteString !== ""
text: root.autocompleteString
x: textInput.leftPadding + textMetrics.advanceWidth
y: (textInput.height - Math.ceil(textMetrics.height)) / 2
color: "gray" // TODO proper color value
font: textInput.font
renderType: textInput.renderType
}
TextMetrics {
id: textMetrics
font: textInput.font
text: textInput.text
}
Rectangle {
id: checkIndicator
property bool hover: checkIndicatorMouseArea.containsMouse && checkIndicator.enabled
property bool pressed: checkIndicatorMouseArea.containsPress
property bool checked: popup.visible
x: textInput.width - checkIndicator.width - StudioTheme.Values.border
y: StudioTheme.Values.border
width: StudioTheme.Values.height - StudioTheme.Values.border
height: textInput.height - (StudioTheme.Values.border * 2)
color: StudioTheme.Values.themeControlBackground
border.width: 0
MouseArea {
id: checkIndicatorMouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: {
if (popup.visible)
popup.close()
else
popup.open()
if (!textInput.activeFocus) {
textInput.forceActiveFocus()
textInput.selectAll()
}
}
}
T.Label {
id: checkIndicatorIcon
anchors.fill: parent
color: StudioTheme.Values.themeTextColor
text: StudioTheme.Constants.upDownSquare2
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.pixelSize: StudioTheme.Values.sliderControlSizeMulti
font.family: StudioTheme.Constants.iconFont.family
}
states: [
State {
name: "default"
when: root.enabled && checkIndicator.enabled && !root.edit
&& !checkIndicator.hover && !root.hover
&& !checkIndicator.checked
PropertyChanges {
target: checkIndicator
color: StudioTheme.Values.themeControlBackground
}
},
State {
name: "globalHover"
when: root.enabled && checkIndicator.enabled
&& !checkIndicator.hover && root.hover && !root.edit
&& !checkIndicator.checked
PropertyChanges {
target: checkIndicator
color: StudioTheme.Values.themeControlBackgroundGlobalHover
}
},
State {
name: "hover"
when: root.enabled && checkIndicator.enabled
&& checkIndicator.hover && root.hover && !checkIndicator.pressed
&& !checkIndicator.checked
PropertyChanges {
target: checkIndicator
color: StudioTheme.Values.themeControlBackgroundHover
}
},
State {
name: "check"
when: checkIndicator.checked
PropertyChanges {
target: checkIndicatorIcon
color: StudioTheme.Values.themeIconColor
}
PropertyChanges {
target: checkIndicator
color: StudioTheme.Values.themeInteraction
}
},
State {
name: "press"
when: root.enabled && checkIndicator.enabled
&& checkIndicator.pressed
PropertyChanges {
target: checkIndicatorIcon
color: StudioTheme.Values.themeIconColor
}
PropertyChanges {
target: checkIndicator
color: StudioTheme.Values.themeInteraction
}
},
State {
name: "disable"
when: !root.enabled
PropertyChanges {
target: checkIndicator
color: StudioTheme.Values.themeControlBackgroundDisabled
}
PropertyChanges {
target: checkIndicatorIcon
color: StudioTheme.Values.themeTextColorDisabled
}
}
]
}
}
}
T.Popup {
id: popup
x: textInput.x + StudioTheme.Values.border
y: textInput.height
width: textInput.width - (StudioTheme.Values.border * 2)
height: Math.min(popup.contentItem.implicitHeight + popup.topPadding + popup.bottomPadding,
root.Window.height - popup.topMargin - popup.bottomMargin,
StudioTheme.Values.maxComboBoxPopupHeight)
padding: StudioTheme.Values.border
margins: 0 // If not defined margin will be -1
closePolicy: T.Popup.NoAutoClose
contentItem: ListView {
id: listView
clip: true
implicitHeight: listView.contentHeight
highlightMoveVelocity: -1
boundsBehavior: Flickable.StopAtBounds
flickDeceleration: 10000
model: {
if (popup.visible)
return sortFilterModel.count ? sortFilterModel : noMatchesModel
return null
}
ScrollBar.vertical: ScrollBar {
id: popupScrollBar
visible: listView.height < listView.contentHeight
}
}
background: Rectangle {
color: StudioTheme.Values.themePopupBackground
border.width: 0
}
onOpened: {
// Reset the highlightedIndex of ListView as binding with condition didn't work
if (root.highlightedIndex !== -1)
root.setHighlightedIndexItems(root.highlightedIndex)
}
onAboutToShow: {
// Select first item in list
if (root.highlightedIndex === -1 && sortFilterModel.count && !root.allowUserInput)
root.setHighlightedIndexVisible(0)
}
MouseArea {
// This is MouseArea is intended to block the hovered property of an ItemDelegate
// when the ListView changes due to Key interaction.
id: popupMouseArea
property bool active: true
anchors.fill: parent
enabled: popup.visible && popupMouseArea.active
hoverEnabled: true
onPositionChanged: { popupMouseArea.active = false }
}
}
Keys.onDownPressed: {
if (!sortFilterModel.visibleGroup.count)
return
root.currentInteraction = FilterComboBox.Interaction.Key
root.increaseVisibleIndex()
popupMouseArea.active = true
}
Keys.onUpPressed: {
if (!sortFilterModel.visibleGroup.count)
return
root.currentInteraction = FilterComboBox.Interaction.Key
root.decreaseVisibleIndex()
popupMouseArea.active = true
}
Keys.onEscapePressed: {
root.escapePressed = true
root.finishEditing()
}
Component.onCompleted: {
let index = root.find(root.editText)
root.currentIndex = index
root.highlightedIndex = index // TODO might not be intended
root.__isCompleted = true
}
}

View File

@@ -79,6 +79,8 @@ T.SpinBox {
property alias compressedValueTimer: myTimer property alias compressedValueTimer: myTimer
property string preFocusText: ""
signal realValueModified signal realValueModified
signal compressedRealValueModified signal compressedRealValueModified
signal dragStarted signal dragStarted
@@ -162,6 +164,8 @@ T.SpinBox {
validator: doubleValidator validator: doubleValidator
function handleEditingFinished() { function handleEditingFinished() {
mySpinBox.focus = false
// Keep the dirty state before calling setValueFromInput(), // Keep the dirty state before calling setValueFromInput(),
// it will be set to false (cleared) internally // it will be set to false (cleared) internally
var valueModified = mySpinBox.dirty var valueModified = mySpinBox.dirty
@@ -174,7 +178,7 @@ T.SpinBox {
mySpinBox.compressedRealValueModified() mySpinBox.compressedRealValueModified()
} }
onEditingFinished: handleEditingFinished() onEditingFinished: spinBoxInput.handleEditingFinished()
onTextEdited: mySpinBox.dirty = true onTextEdited: mySpinBox.dirty = true
} }
@@ -281,7 +285,7 @@ T.SpinBox {
id: myTimer id: myTimer
repeat: false repeat: false
running: false running: false
interval: 200 interval: 400
onTriggered: mySpinBox.compressedRealValueModified() onTriggered: mySpinBox.compressedRealValueModified()
} }
@@ -306,9 +310,11 @@ T.SpinBox {
} }
onDisplayTextChanged: spinBoxInput.text = mySpinBox.displayText onDisplayTextChanged: spinBoxInput.text = mySpinBox.displayText
onActiveFocusChanged: { onActiveFocusChanged: {
if (mySpinBox.activeFocus) // QTBUG-75862 && mySpinBox.focusReason === Qt.TabFocusReason) if (mySpinBox.activeFocus) { // QTBUG-75862 && mySpinBox.focusReason === Qt.TabFocusReason)
mySpinBox.preFocusText = spinBoxInput.text
spinBoxInput.selectAll() spinBoxInput.selectAll()
} }
}
Keys.onPressed: function(event) { Keys.onPressed: function(event) {
if (event.key === Qt.Key_Up || event.key === Qt.Key_Down) { if (event.key === Qt.Key_Up || event.key === Qt.Key_Down) {
@@ -333,8 +339,11 @@ T.SpinBox {
mySpinBox.realStepSize = currStepSize mySpinBox.realStepSize = currStepSize
} }
if (event.key === Qt.Key_Escape) if (event.key === Qt.Key_Escape) {
mySpinBox.focus = false spinBoxInput.text = mySpinBox.preFocusText
mySpinBox.dirty = true
spinBoxInput.handleEditingFinished()
}
} }
function clamp(v, lo, hi) { function clamp(v, lo, hi) {

View File

@@ -0,0 +1,86 @@
/****************************************************************************
**
** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Quick 3D.
**
** $QT_BEGIN_LICENSE:GPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 or (at your option) any later version
** approved by the KDE Free Qt Foundation. The licenses are as published by
** the Free Software Foundation and appearing in the file LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
import QtQuick
import QtQml.Models
DelegateModel {
id: delegateModel
property var visibleGroup: visibleItems
property var lessThan: function(left, right) { return true }
property var filterAcceptsItem: function(item) { return true }
signal updated()
function update() {
if (delegateModel.items.count > 0) {
delegateModel.items.setGroups(0, delegateModel.items.count, "items")
}
// Filter items
var visible = []
for (var i = 0; i < delegateModel.items.count; ++i) {
var item = delegateModel.items.get(i)
if (delegateModel.filterAcceptsItem(item.model)) {
visible.push(item)
}
}
// Sort the list of visible items
visible.sort(function(a, b) {
return delegateModel.lessThan(a.model, b.model);
});
// Add all items to the visible group
for (i = 0; i < visible.length; ++i) {
item = visible[i]
item.inVisible = true
if (item.visibleIndex !== i) {
visibleItems.move(item.visibleIndex, i, 1)
}
}
delegateModel.updated()
}
items.onChanged: delegateModel.update()
onLessThanChanged: delegateModel.update()
onFilterAcceptsItemChanged: delegateModel.update()
groups: DelegateModelGroup {
id: visibleItems
name: "visible"
includeByDefault: false
}
filterOnGroup: "visible"
}

View File

@@ -28,15 +28,15 @@ import QtQuick.Templates 2.15 as T
import StudioTheme 1.0 as StudioTheme import StudioTheme 1.0 as StudioTheme
T.TextField { T.TextField {
id: myTextField id: root
property alias actionIndicator: actionIndicator property alias actionIndicator: actionIndicator
property alias translationIndicator: translationIndicator property alias translationIndicator: translationIndicator
// This property is used to indicate the global hover state // This property is used to indicate the global hover state
property bool hover: (actionIndicator.hover || mouseArea.containsMouse property bool hover: (actionIndicator.hover || mouseArea.containsMouse
|| translationIndicator.hover) && myTextField.enabled || translationIndicator.hover) && root.enabled
property bool edit: myTextField.activeFocus property bool edit: root.activeFocus
property alias actionIndicatorVisible: actionIndicator.visible property alias actionIndicatorVisible: actionIndicator.visible
property real __actionIndicatorWidth: StudioTheme.Values.actionIndicatorWidth property real __actionIndicatorWidth: StudioTheme.Values.actionIndicatorWidth
@@ -46,6 +46,8 @@ T.TextField {
property real __translationIndicatorWidth: StudioTheme.Values.translationIndicatorWidth property real __translationIndicatorWidth: StudioTheme.Values.translationIndicatorWidth
property real __translationIndicatorHeight: StudioTheme.Values.translationIndicatorHeight property real __translationIndicatorHeight: StudioTheme.Values.translationIndicatorHeight
property string preFocusText: ""
horizontalAlignment: Qt.AlignLeft horizontalAlignment: Qt.AlignLeft
verticalAlignment: Qt.AlignVCenter verticalAlignment: Qt.AlignVCenter
@@ -78,7 +80,7 @@ T.TextField {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onPressed: function(mouse) { onPressed: function(mouse) {
if (mouse.button === Qt.RightButton) if (mouse.button === Qt.RightButton)
contextMenu.popup(myTextField) contextMenu.popup(root)
mouse.accepted = false mouse.accepted = false
} }
@@ -86,43 +88,50 @@ T.TextField {
onPersistentSelectionChanged: { onPersistentSelectionChanged: {
if (!persistentSelection) if (!persistentSelection)
myTextField.deselect() root.deselect()
} }
ContextMenu { ContextMenu {
id: contextMenu id: contextMenu
myTextEdit: myTextField myTextEdit: root
}
onActiveFocusChanged: {
if (root.activeFocus)
root.preFocusText = root.text
} }
onEditChanged: { onEditChanged: {
if (myTextField.edit) if (root.edit)
contextMenu.close() contextMenu.close()
} }
onEditingFinished: root.focus = false
ActionIndicator { ActionIndicator {
id: actionIndicator id: actionIndicator
myControl: myTextField myControl: root
x: 0 x: 0
y: 0 y: 0
width: actionIndicator.visible ? myTextField.__actionIndicatorWidth : 0 width: actionIndicator.visible ? root.__actionIndicatorWidth : 0
height: actionIndicator.visible ? myTextField.__actionIndicatorHeight : 0 height: actionIndicator.visible ? root.__actionIndicatorHeight : 0
} }
Text { Text {
id: placeholder id: placeholder
x: myTextField.leftPadding x: root.leftPadding
y: myTextField.topPadding y: root.topPadding
width: myTextField.width - (myTextField.leftPadding + myTextField.rightPadding) width: root.width - (root.leftPadding + root.rightPadding)
height: myTextField.height - (myTextField.topPadding + myTextField.bottomPadding) height: root.height - (root.topPadding + root.bottomPadding)
text: myTextField.placeholderText text: root.placeholderText
font: myTextField.font font: root.font
color: myTextField.placeholderTextColor color: root.placeholderTextColor
verticalAlignment: myTextField.verticalAlignment verticalAlignment: root.verticalAlignment
visible: !myTextField.length && !myTextField.preeditText visible: !root.length && !root.preeditText
&& (!myTextField.activeFocus || myTextField.horizontalAlignment !== Qt.AlignHCenter) && (!root.activeFocus || root.horizontalAlignment !== Qt.AlignHCenter)
elide: Text.ElideRight elide: Text.ElideRight
renderType: myTextField.renderType renderType: root.renderType
} }
background: Rectangle { background: Rectangle {
@@ -131,14 +140,14 @@ T.TextField {
border.color: StudioTheme.Values.themeControlOutline border.color: StudioTheme.Values.themeControlOutline
border.width: StudioTheme.Values.border border.width: StudioTheme.Values.border
x: actionIndicator.width x: actionIndicator.width
width: myTextField.width - actionIndicator.width width: root.width - actionIndicator.width
height: myTextField.height height: root.height
} }
TranslationIndicator { TranslationIndicator {
id: translationIndicator id: translationIndicator
myControl: myTextField myControl: root
x: myTextField.width - translationIndicator.width x: root.width - translationIndicator.width
width: translationIndicator.visible ? __translationIndicatorWidth : 0 width: translationIndicator.visible ? __translationIndicatorWidth : 0
height: translationIndicator.visible ? __translationIndicatorHeight : 0 height: translationIndicator.visible ? __translationIndicatorHeight : 0
} }
@@ -146,15 +155,14 @@ T.TextField {
states: [ states: [
State { State {
name: "default" name: "default"
when: myTextField.enabled && !myTextField.hover when: root.enabled && !root.hover && !root.edit
&& !myTextField.edit
PropertyChanges { PropertyChanges {
target: textFieldBackground target: textFieldBackground
color: StudioTheme.Values.themeControlBackground color: StudioTheme.Values.themeControlBackground
border.color: StudioTheme.Values.themeControlOutline border.color: StudioTheme.Values.themeControlOutline
} }
PropertyChanges { PropertyChanges {
target: myTextField target: root
color: StudioTheme.Values.themeTextColor color: StudioTheme.Values.themeTextColor
placeholderTextColor: StudioTheme.Values.themePlaceholderTextColor placeholderTextColor: StudioTheme.Values.themePlaceholderTextColor
} }
@@ -165,15 +173,15 @@ T.TextField {
}, },
State { State {
name: "globalHover" name: "globalHover"
when: (actionIndicator.hover || translationIndicator.hover) && !myTextField.edit when: (actionIndicator.hover || translationIndicator.hover) && !root.edit
&& myTextField.enabled && root.enabled
PropertyChanges { PropertyChanges {
target: textFieldBackground target: textFieldBackground
color: StudioTheme.Values.themeControlBackgroundGlobalHover color: StudioTheme.Values.themeControlBackgroundGlobalHover
border.color: StudioTheme.Values.themeControlOutline border.color: StudioTheme.Values.themeControlOutline
} }
PropertyChanges { PropertyChanges {
target: myTextField target: root
color: StudioTheme.Values.themeTextColor color: StudioTheme.Values.themeTextColor
placeholderTextColor: StudioTheme.Values.themePlaceholderTextColor placeholderTextColor: StudioTheme.Values.themePlaceholderTextColor
} }
@@ -181,28 +189,28 @@ T.TextField {
State { State {
name: "hover" name: "hover"
when: mouseArea.containsMouse && !actionIndicator.hover && !translationIndicator.hover when: mouseArea.containsMouse && !actionIndicator.hover && !translationIndicator.hover
&& !myTextField.edit && myTextField.enabled && !root.edit && root.enabled
PropertyChanges { PropertyChanges {
target: textFieldBackground target: textFieldBackground
color: StudioTheme.Values.themeControlBackgroundHover color: StudioTheme.Values.themeControlBackgroundHover
border.color: StudioTheme.Values.themeControlOutline border.color: StudioTheme.Values.themeControlOutline
} }
PropertyChanges { PropertyChanges {
target: myTextField target: root
color: StudioTheme.Values.themeTextColor color: StudioTheme.Values.themeTextColor
placeholderTextColor: StudioTheme.Values.themePlaceholderTextColor placeholderTextColor: StudioTheme.Values.themePlaceholderTextColor
} }
}, },
State { State {
name: "edit" name: "edit"
when: myTextField.edit when: root.edit
PropertyChanges { PropertyChanges {
target: textFieldBackground target: textFieldBackground
color: StudioTheme.Values.themeControlBackgroundInteraction color: StudioTheme.Values.themeControlBackgroundInteraction
border.color: StudioTheme.Values.themeControlOutlineInteraction border.color: StudioTheme.Values.themeControlOutlineInteraction
} }
PropertyChanges { PropertyChanges {
target: myTextField target: root
color: StudioTheme.Values.themeTextColor color: StudioTheme.Values.themeTextColor
placeholderTextColor: StudioTheme.Values.themePlaceholderTextColorInteraction placeholderTextColor: StudioTheme.Values.themePlaceholderTextColorInteraction
} }
@@ -213,14 +221,14 @@ T.TextField {
}, },
State { State {
name: "disable" name: "disable"
when: !myTextField.enabled when: !root.enabled
PropertyChanges { PropertyChanges {
target: textFieldBackground target: textFieldBackground
color: StudioTheme.Values.themeControlBackgroundDisabled color: StudioTheme.Values.themeControlBackgroundDisabled
border.color: StudioTheme.Values.themeControlOutlineDisabled border.color: StudioTheme.Values.themeControlOutlineDisabled
} }
PropertyChanges { PropertyChanges {
target: myTextField target: root
color: StudioTheme.Values.themeTextColorDisabled color: StudioTheme.Values.themeTextColorDisabled
placeholderTextColor: StudioTheme.Values.themeTextColorDisabled placeholderTextColor: StudioTheme.Values.themeTextColorDisabled
} }
@@ -228,7 +236,9 @@ T.TextField {
] ]
Keys.onPressed: function(event) { Keys.onPressed: function(event) {
if (event.key === Qt.Key_Escape) if (event.key === Qt.Key_Escape) {
myTextField.focus = false root.text = root.preFocusText
root.focus = false
}
} }
} }

View File

@@ -8,6 +8,7 @@ CheckIndicator 1.0 CheckIndicator.qml
ComboBox 1.0 ComboBox.qml ComboBox 1.0 ComboBox.qml
ComboBoxInput 1.0 ComboBoxInput.qml ComboBoxInput 1.0 ComboBoxInput.qml
ContextMenu 1.0 ContextMenu.qml ContextMenu 1.0 ContextMenu.qml
FilterComboBox 1.0 FilterComboBox.qml
InfinityLoopIndicator 1.0 InfinityLoopIndicator.qml InfinityLoopIndicator 1.0 InfinityLoopIndicator.qml
ItemDelegate 1.0 ItemDelegate.qml ItemDelegate 1.0 ItemDelegate.qml
LinkIndicator2D 1.0 LinkIndicator2D.qml LinkIndicator2D 1.0 LinkIndicator2D.qml
@@ -30,6 +31,7 @@ SectionLabel 1.0 SectionLabel.qml
SectionLayout 1.0 SectionLayout.qml SectionLayout 1.0 SectionLayout.qml
Slider 1.0 Slider.qml Slider 1.0 Slider.qml
SliderPopup 1.0 SliderPopup.qml SliderPopup 1.0 SliderPopup.qml
SortFilterModel 1.0 SortFilterModel.qml
SpinBox 1.0 SpinBox.qml SpinBox 1.0 SpinBox.qml
SpinBoxIndicator 1.0 SpinBoxIndicator.qml SpinBoxIndicator 1.0 SpinBoxIndicator.qml
SpinBoxInput 1.0 SpinBoxInput.qml SpinBoxInput 1.0 SpinBoxInput.qml

View File

@@ -406,11 +406,6 @@ QStringList lastSessionArgument()
#ifdef ENABLE_CRASHPAD #ifdef ENABLE_CRASHPAD
bool startCrashpad(const QString &libexecPath, bool crashReportingEnabled) bool startCrashpad(const QString &libexecPath, bool crashReportingEnabled)
{ {
if (QSysInfo::currentCpuArchitecture() == "arm64") {
qDebug() << "The crashpad_handler binary does not work on arm64 properly. So it is disabled for now.";
return false;
}
using namespace crashpad; using namespace crashpad;
// Cache directory that will store crashpad information and minidumps // Cache directory that will store crashpad information and minidumps

View File

@@ -702,6 +702,7 @@ void CMakeBuildSystem::updateFileSystemNodes()
addCMakeLists(newRoot.get(), std::move(fileNodes)); addCMakeLists(newRoot.get(), std::move(fileNodes));
} }
if (m_allFiles)
addFileSystemNodes(newRoot.get(), m_allFiles); addFileSystemNodes(newRoot.get(), m_allFiles);
setRootProjectNode(std::move(newRoot)); setRootProjectNode(std::move(newRoot));

View File

@@ -436,6 +436,13 @@ static bool hideAnalyzeMenu()
.toBool(); .toBool();
} }
static bool hideDebugMenu()
{
return Core::ICore::settings()
->value(ProjectExplorer::Constants::SETTINGS_MENU_HIDE_DEBUG, false)
.toBool();
}
QAction *addAction(const QObject *parent, QMenu *menu, const QString &display, bool on, QAction *addAction(const QObject *parent, QMenu *menu, const QString &display, bool on,
const std::function<void()> &onTriggered) const std::function<void()> &onTriggered)
{ {
@@ -922,6 +929,8 @@ DebuggerPluginPrivate::DebuggerPluginPrivate(const QStringList &arguments)
m_visibleStartAction.setAction(&m_startAction); m_visibleStartAction.setAction(&m_startAction);
m_visibleStartAction.setObjectName("Debug"); // used for UI introduction m_visibleStartAction.setObjectName("Debug"); // used for UI introduction
if (!hideDebugMenu())
ModeManager::addAction(&m_visibleStartAction, /*priority*/ 90); ModeManager::addAction(&m_visibleStartAction, /*priority*/ 90);
m_undisturbableAction.setIcon(interruptIcon(false)); m_undisturbableAction.setIcon(interruptIcon(false));

View File

@@ -95,6 +95,7 @@ IAssistProposal *LanguageClientQuickFixAssistProcessor::perform(const AssistInte
handleCodeActionResponse(response); handleCodeActionResponse(response);
}); });
m_client->addAssistProcessor(this);
m_client->requestCodeActions(request); m_client->requestCodeActions(request);
m_currentRequest = request.id(); m_currentRequest = request.id();
return nullptr; return nullptr;

View File

@@ -280,10 +280,15 @@ void MacroManager::startMacro()
foreach (IMacroHandler *handler, d->handlers) foreach (IMacroHandler *handler, d->handlers)
handler->startRecording(d->currentMacro); handler->startRecording(d->currentMacro);
QString endShortcut = Core::ActionManager::command(Constants::END_MACRO)->keySequence().toString(); const QString endShortcut = Core::ActionManager::command(Constants::END_MACRO)
QString executeShortcut = Core::ActionManager::command(Constants::EXECUTE_LAST_MACRO)->keySequence().toString(); ->keySequence()
QString help = tr("Macro mode. Type \"%1\" to stop recording and \"%2\" to play the macro.") .toString(QKeySequence::NativeText);
.arg(endShortcut).arg(executeShortcut); const QString executeShortcut = Core::ActionManager::command(Constants::EXECUTE_LAST_MACRO)
->keySequence()
.toString(QKeySequence::NativeText);
const QString help
= tr("Macro mode. Type \"%1\" to stop recording and \"%2\" to play the macro.")
.arg(endShortcut, executeShortcut);
Core::EditorManager::showEditorStatusBar(Constants::M_STATUS_BUFFER, help, Core::EditorManager::showEditorStatusBar(Constants::M_STATUS_BUFFER, help,
tr("Stop Recording Macro"), tr("Stop Recording Macro"),
this, [this] { endMacro(); }); this, [this] { endMacro(); });

View File

@@ -96,8 +96,10 @@ void MacroOptionsWidget::createTable()
Core::Command *command = Core::Command *command =
Core::ActionManager::command(base.withSuffix(macro->displayName())); Core::ActionManager::command(base.withSuffix(macro->displayName()));
if (command && command->action()) if (command && command->action()) {
macroItem->setText(2, command->action()->shortcut().toString()); macroItem->setText(2,
command->action()->shortcut().toString(QKeySequence::NativeText));
}
} }
} }
} }

View File

@@ -1079,12 +1079,19 @@ Toolchains GccToolChainFactory::autoDetect(const ToolchainDetector &detector) co
Toolchains GccToolChainFactory::detectForImport(const ToolChainDescription &tcd) const Toolchains GccToolChainFactory::detectForImport(const ToolChainDescription &tcd) const
{ {
const QString fileName = tcd.compilerPath.completeBaseName(); const QString fileName = tcd.compilerPath.completeBaseName();
if ((tcd.language == Constants::C_LANGUAGE_ID && (fileName.startsWith("gcc") const QString resolvedSymlinksFileName = tcd.compilerPath.resolveSymlinks().completeBaseName();
const bool isCCompiler = tcd.language == Constants::C_LANGUAGE_ID
&& (fileName.startsWith("gcc")
|| fileName.endsWith("gcc") || fileName.endsWith("gcc")
|| fileName == "cc")) || (fileName == "cc" && !resolvedSymlinksFileName.contains("clang")));
|| (tcd.language == Constants::CXX_LANGUAGE_ID && (fileName.startsWith("g++")
const bool isCxxCompiler = tcd.language == Constants::CXX_LANGUAGE_ID
&& (fileName.startsWith("g++")
|| fileName.endsWith("g++") || fileName.endsWith("g++")
|| fileName == "c++"))) { || (fileName == "c++" && !resolvedSymlinksFileName.contains("clang")));
if (isCCompiler || isCxxCompiler) {
return autoDetectToolChain(tcd, [](const ToolChain *tc) { return autoDetectToolChain(tcd, [](const ToolChain *tc) {
return tc->targetAbi().osFlavor() != Abi::WindowsMSysFlavor; return tc->targetAbi().osFlavor() != Abi::WindowsMSysFlavor;
}); });
@@ -1765,9 +1772,18 @@ Toolchains ClangToolChainFactory::autoDetect(const ToolchainDetector &detector)
Toolchains ClangToolChainFactory::detectForImport(const ToolChainDescription &tcd) const Toolchains ClangToolChainFactory::detectForImport(const ToolChainDescription &tcd) const
{ {
const QString fileName = tcd.compilerPath.toString(); const QString fileName = tcd.compilerPath.completeBaseName();
if ((tcd.language == Constants::C_LANGUAGE_ID && fileName.startsWith("clang") && !fileName.startsWith("clang++")) const QString resolvedSymlinksFileName = tcd.compilerPath.resolveSymlinks().completeBaseName();
|| (tcd.language == Constants::CXX_LANGUAGE_ID && fileName.startsWith("clang++"))) {
const bool isCCompiler = tcd.language == Constants::C_LANGUAGE_ID
&& ((fileName.startsWith("clang") && !fileName.startsWith("clang++"))
|| (fileName == "cc" && resolvedSymlinksFileName.contains("clang")));
const bool isCxxCompiler = tcd.language == Constants::CXX_LANGUAGE_ID
&& (fileName.startsWith("clang++")
|| (fileName == "c++" && resolvedSymlinksFileName.contains("clang")));
if (isCCompiler || isCxxCompiler) {
return autoDetectToolChain(tcd); return autoDetectToolChain(tcd);
} }
return {}; return {};
@@ -2023,7 +2039,7 @@ Toolchains LinuxIccToolChainFactory::autoDetect(const ToolchainDetector &detecto
Toolchains LinuxIccToolChainFactory::detectForImport(const ToolChainDescription &tcd) const Toolchains LinuxIccToolChainFactory::detectForImport(const ToolChainDescription &tcd) const
{ {
const QString fileName = tcd.compilerPath.toString(); const QString fileName = tcd.compilerPath.completeBaseName();
if ((tcd.language == Constants::CXX_LANGUAGE_ID && fileName.startsWith("icpc")) || if ((tcd.language == Constants::CXX_LANGUAGE_ID && fileName.startsWith("icpc")) ||
(tcd.language == Constants::C_LANGUAGE_ID && fileName.startsWith("icc"))) { (tcd.language == Constants::C_LANGUAGE_ID && fileName.startsWith("icc"))) {
return autoDetectToolChain(tcd); return autoDetectToolChain(tcd);

View File

@@ -1340,6 +1340,7 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
dd->m_modeBarBuildAction->initialize(cmd->action()); dd->m_modeBarBuildAction->initialize(cmd->action());
dd->m_modeBarBuildAction->setAttribute(ProxyAction::UpdateText); dd->m_modeBarBuildAction->setAttribute(ProxyAction::UpdateText);
dd->m_modeBarBuildAction->setAction(cmd->action()); dd->m_modeBarBuildAction->setAction(cmd->action());
if (!hideBuildMenu())
ModeManager::addAction(dd->m_modeBarBuildAction, Constants::P_ACTION_BUILDPROJECT); ModeManager::addAction(dd->m_modeBarBuildAction, Constants::P_ACTION_BUILDPROJECT);
// build for run config // build for run config

View File

@@ -36,19 +36,24 @@
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <utils/filesystemwatcher.h>
#include <utils/stylehelper.h>
#include <QCheckBox>
#include <QDebug> #include <QDebug>
#include <QDir> #include <QDir>
#include <QDirIterator> #include <QDirIterator>
#include <QElapsedTimer>
#include <QFont> #include <QFont>
#include <QImageReader> #include <QImageReader>
#include <QLoggingCategory>
#include <QMessageBox>
#include <QMetaProperty> #include <QMetaProperty>
#include <QPainter> #include <QPainter>
#include <QRawFont> #include <QRawFont>
#include <QRegularExpression> #include <QRegularExpression>
#include <QMessageBox>
#include <QCheckBox> static Q_LOGGING_CATEGORY(assetsLibraryBenchmark, "qtc.assetsLibrary.setRoot", QtWarningMsg)
#include <utils/stylehelper.h>
#include <utils/filesystemwatcher.h>
namespace QmlDesigner { namespace QmlDesigner {
@@ -298,6 +303,12 @@ void AssetsLibraryModel::refresh()
void AssetsLibraryModel::setRootPath(const QString &path) void AssetsLibraryModel::setRootPath(const QString &path)
{ {
QElapsedTimer time;
if (assetsLibraryBenchmark().isInfoEnabled())
time.start();
qCInfo(assetsLibraryBenchmark) << "start:" << time.elapsed();
static const QStringList ignoredTopLevelDirs {"imports", "asset_imports"}; static const QStringList ignoredTopLevelDirs {"imports", "asset_imports"};
m_fileSystemWatcher->clear(); m_fileSystemWatcher->clear();
@@ -345,6 +356,8 @@ void AssetsLibraryModel::setRootPath(const QString &path)
return isEmpty; return isEmpty;
}; };
qCInfo(assetsLibraryBenchmark) << "directories parsed:" << time.elapsed();
if (m_assetsDir) if (m_assetsDir)
delete m_assetsDir; delete m_assetsDir;
@@ -360,6 +373,8 @@ void AssetsLibraryModel::setRootPath(const QString &path)
m_assetsDir->setDirVisible(!noAssets); // if there are no assets, hide all empty asset folders m_assetsDir->setDirVisible(!noAssets); // if there are no assets, hide all empty asset folders
endResetModel(); endResetModel();
qCInfo(assetsLibraryBenchmark) << "model reset:" << time.elapsed();
} }
void AssetsLibraryModel::setSearchText(const QString &searchText) void AssetsLibraryModel::setSearchText(const QString &searchText)

View File

@@ -87,7 +87,7 @@ bool AssetsLibraryWidget::eventFilter(QObject *obj, QEvent *event)
auto drag = new QDrag(this); auto drag = new QDrag(this);
drag->setPixmap(m_assetsIconProvider->requestPixmap(m_assetsToDrag[0], nullptr, {128, 128})); drag->setPixmap(m_assetsIconProvider->requestPixmap(m_assetsToDrag[0], nullptr, {128, 128}));
QMimeData *mimeData = new QMimeData; QMimeData *mimeData = new QMimeData;
mimeData->setData("application/vnd.bauhaus.libraryresource", m_assetsToDrag.join(',').toUtf8()); mimeData->setData(Constants::MIME_TYPE_ASSETS, m_assetsToDrag.join(',').toUtf8());
drag->setMimeData(mimeData); drag->setMimeData(mimeData);
drag->exec(); drag->exec();
drag->deleteLater(); drag->deleteLater();
@@ -213,26 +213,32 @@ void AssetsLibraryWidget::handleAddAsset()
addResources({}); addResources({});
} }
void AssetsLibraryWidget::handleExtFilesDrop(const QStringList &simpleFilesPaths, void AssetsLibraryWidget::handleExtFilesDrop(const QList<QUrl> &simpleFilePaths,
const QStringList &complexFilesPaths, const QList<QUrl> &complexFilePaths,
const QString &targetDirPath) const QString &targetDirPath)
{ {
if (!simpleFilesPaths.isEmpty()) { auto toLocalFile = [](const QUrl &url) { return url.toLocalFile(); };
QStringList simpleFilePathStrings = Utils::transform<QStringList>(simpleFilePaths, toLocalFile);
QStringList complexFilePathStrings = Utils::transform<QStringList>(complexFilePaths,
toLocalFile);
if (!simpleFilePathStrings.isEmpty()) {
if (targetDirPath.isEmpty()) { if (targetDirPath.isEmpty()) {
addResources(simpleFilesPaths); addResources(simpleFilePathStrings);
} else { } else {
AddFilesResult result = ModelNodeOperations::addFilesToProject(simpleFilesPaths, AddFilesResult result = ModelNodeOperations::addFilesToProject(simpleFilePathStrings,
targetDirPath); targetDirPath);
if (result == AddFilesResult::Failed) { if (result == AddFilesResult::Failed) {
Core::AsynchronousMessageBox::warning(tr("Failed to Add Files"), Core::AsynchronousMessageBox::warning(tr("Failed to Add Files"),
tr("Could not add %1 to project.") tr("Could not add %1 to project.")
.arg(simpleFilesPaths.join(' '))); .arg(simpleFilePathStrings.join(' ')));
} }
} }
} }
if (!complexFilesPaths.empty()) if (!complexFilePathStrings.empty())
addResources(complexFilesPaths); addResources(complexFilePathStrings);
} }
QSet<QString> AssetsLibraryWidget::supportedAssetSuffixes(bool complex) QSet<QString> AssetsLibraryWidget::supportedAssetSuffixes(bool complex)
@@ -301,25 +307,25 @@ QPair<QString, QByteArray> AssetsLibraryWidget::getAssetTypeAndData(const QStrin
if (!suffix.isEmpty()) { if (!suffix.isEmpty()) {
if (AssetsLibraryModel::supportedImageSuffixes().contains(suffix)) { if (AssetsLibraryModel::supportedImageSuffixes().contains(suffix)) {
// Data: Image format (suffix) // Data: Image format (suffix)
return {"application/vnd.bauhaus.libraryresource.image", suffix.toUtf8()}; return {Constants::MIME_TYPE_ASSET_IMAGE, suffix.toUtf8()};
} else if (AssetsLibraryModel::supportedFontSuffixes().contains(suffix)) { } else if (AssetsLibraryModel::supportedFontSuffixes().contains(suffix)) {
// Data: Font family name // Data: Font family name
QRawFont font(assetPath, 10); QRawFont font(assetPath, 10);
QString fontFamily = font.isValid() ? font.familyName() : ""; QString fontFamily = font.isValid() ? font.familyName() : "";
return {"application/vnd.bauhaus.libraryresource.font", fontFamily.toUtf8()}; return {Constants::MIME_TYPE_ASSET_FONT, fontFamily.toUtf8()};
} else if (AssetsLibraryModel::supportedShaderSuffixes().contains(suffix)) { } else if (AssetsLibraryModel::supportedShaderSuffixes().contains(suffix)) {
// Data: shader type, frament (f) or vertex (v) // Data: shader type, frament (f) or vertex (v)
return {"application/vnd.bauhaus.libraryresource.shader", return {Constants::MIME_TYPE_ASSET_SHADER,
AssetsLibraryModel::supportedFragmentShaderSuffixes().contains(suffix) ? "f" : "v"}; AssetsLibraryModel::supportedFragmentShaderSuffixes().contains(suffix) ? "f" : "v"};
} else if (AssetsLibraryModel::supportedAudioSuffixes().contains(suffix)) { } else if (AssetsLibraryModel::supportedAudioSuffixes().contains(suffix)) {
// No extra data for sounds // No extra data for sounds
return {"application/vnd.bauhaus.libraryresource.sound", {}}; return {Constants::MIME_TYPE_ASSET_SOUND, {}};
} else if (AssetsLibraryModel::supportedVideoSuffixes().contains(suffix)) { } else if (AssetsLibraryModel::supportedVideoSuffixes().contains(suffix)) {
// No extra data for videos // No extra data for videos
return {"application/vnd.bauhaus.libraryresource.video", {}}; return {Constants::MIME_TYPE_ASSET_VIDEO, {}};
} else if (AssetsLibraryModel::supportedTexture3DSuffixes().contains(suffix)) { } else if (AssetsLibraryModel::supportedTexture3DSuffixes().contains(suffix)) {
// Data: Image format (suffix) // Data: Image format (suffix)
return {"application/vnd.bauhaus.libraryresource.texture3d", suffix.toUtf8()}; return {Constants::MIME_TYPE_ASSET_TEXTURE3D, suffix.toUtf8()};
} }
} }
return {}; return {};

View File

@@ -79,8 +79,8 @@ public:
Q_INVOKABLE void startDragAsset(const QStringList &assetPaths, const QPointF &mousePos); Q_INVOKABLE void startDragAsset(const QStringList &assetPaths, const QPointF &mousePos);
Q_INVOKABLE void handleAddAsset(); Q_INVOKABLE void handleAddAsset();
Q_INVOKABLE void handleSearchfilterChanged(const QString &filterText); Q_INVOKABLE void handleSearchfilterChanged(const QString &filterText);
Q_INVOKABLE void handleExtFilesDrop(const QStringList &simpleFilesPaths, Q_INVOKABLE void handleExtFilesDrop(const QList<QUrl> &simpleFilePaths,
const QStringList &complexFilesPaths, const QList<QUrl> &complexFilePaths,
const QString &targetDirPath = {}); const QString &targetDirPath = {});
Q_INVOKABLE QSet<QString> supportedAssetSuffixes(bool complex); Q_INVOKABLE QSet<QString> supportedAssetSuffixes(bool complex);

View File

@@ -214,11 +214,10 @@ QmlTimeline CurveEditorView::activeTimeline() const
if (node.hasVariantProperty("enabled") if (node.hasVariantProperty("enabled")
&& node.variantProperty("enabled").value().toBool()) && node.variantProperty("enabled").value().toBool())
return QmlTimeline(node); return QmlTimeline(node);
}
}
return {}; return {};
} }
}
}
for (const ModelNode &node : allModelNodesOfType("QtQuick.Timeline.Timeline")) { for (const ModelNode &node : allModelNodesOfType("QtQuick.Timeline.Timeline")) {
if (QmlTimeline::isValidQmlTimeline(node) && state.affectsModelNode(node)) { if (QmlTimeline::isValidQmlTimeline(node) && state.affectsModelNode(node)) {
@@ -226,7 +225,8 @@ QmlTimeline CurveEditorView::activeTimeline() const
if (!propertyChanges.isValid()) if (!propertyChanges.isValid())
continue; continue;
if (node.hasVariantProperty("enabled") && node.variantProperty("enabled").value().toBool()) if (propertyChanges.modelNode().hasProperty("enabled") &&
propertyChanges.modelNode().variantProperty("enabled").value().toBool())
return QmlTimeline(node); return QmlTimeline(node);
} }
} }

View File

@@ -169,7 +169,7 @@ void Edit3DCanvas::dragEnterEvent(QDragEnterEvent *e)
// Allow drop when there is no valid active scene, as the drop goes under the root node of // Allow drop when there is no valid active scene, as the drop goes under the root node of
// the document in that case. // the document in that case.
if (!node.isValid() || !ModelNode::isThisOrAncestorLocked(node)) { if (!node.isValid() || !ModelNode::isThisOrAncestorLocked(node)) {
QByteArray data = e->mimeData()->data(QStringLiteral("application/vnd.bauhaus.itemlibraryinfo")); QByteArray data = e->mimeData()->data(Constants::MIME_TYPE_ITEM_LIBRARY_INFO);
if (!data.isEmpty()) { if (!data.isEmpty()) {
QDataStream stream(data); QDataStream stream(data);
stream >> m_itemLibraryEntry; stream >> m_itemLibraryEntry;

View File

@@ -24,12 +24,12 @@
****************************************************************************/ ****************************************************************************/
#include "abstractformeditortool.h" #include "abstractformeditortool.h"
#include "assetslibrarywidget.h"
#include "formeditorscene.h"
#include "formeditorview.h" #include "formeditorview.h"
#include "formeditorwidget.h" #include "formeditorwidget.h"
#include "formeditorscene.h" #include "modelnodecontextmenu.h"
#include "assetslibrarywidget.h" #include "qmldesignerconstants.h"
#include <modelnodecontextmenu.h>
#include <QDebug> #include <QDebug>
#include <QGraphicsSceneDragDropEvent> #include <QGraphicsSceneDragDropEvent>
@@ -236,20 +236,20 @@ void AbstractFormEditorTool::dropEvent(const QList<QGraphicsItem*> &/*itemList*/
void AbstractFormEditorTool::dragEnterEvent(const QList<QGraphicsItem*> &itemList, QGraphicsSceneDragDropEvent *event) void AbstractFormEditorTool::dragEnterEvent(const QList<QGraphicsItem*> &itemList, QGraphicsSceneDragDropEvent *event)
{ {
bool hasValidAssets = false; bool hasValidAssets = false;
if (event->mimeData()->hasFormat("application/vnd.bauhaus.libraryresource")) { if (event->mimeData()->hasFormat(Constants::MIME_TYPE_ASSETS)) {
const QStringList assetPaths = QString::fromUtf8(event->mimeData() const QStringList assetPaths = QString::fromUtf8(event->mimeData()
->data("application/vnd.bauhaus.libraryresource")).split(","); ->data(Constants::MIME_TYPE_ASSETS)).split(',');
for (const QString &assetPath : assetPaths) { for (const QString &assetPath : assetPaths) {
QString assetType = AssetsLibraryWidget::getAssetTypeAndData(assetPath).first; QString assetType = AssetsLibraryWidget::getAssetTypeAndData(assetPath).first;
if (assetType == "application/vnd.bauhaus.libraryresource.image" if (assetType == Constants::MIME_TYPE_ASSET_IMAGE
|| assetType == "application/vnd.bauhaus.libraryresource.font") { || assetType == Constants::MIME_TYPE_ASSET_FONT) {
hasValidAssets = true; hasValidAssets = true;
break; break;
} }
} }
} }
if (event->mimeData()->hasFormat(QLatin1String("application/vnd.bauhaus.itemlibraryinfo")) || hasValidAssets) { if (event->mimeData()->hasFormat(Constants::MIME_TYPE_ITEM_LIBRARY_INFO) || hasValidAssets) {
event->accept(); event->accept();
view()->changeToDragTool(); view()->changeToDragTool();
view()->currentTool()->dragEnterEvent(itemList, event); view()->currentTool()->dragEnterEvent(itemList, event);

View File

@@ -31,6 +31,7 @@
#include <metainfo.h> #include <metainfo.h>
#include <nodehints.h> #include <nodehints.h>
#include <rewritingexception.h> #include <rewritingexception.h>
#include "qmldesignerconstants.h"
#include <QDebug> #include <QDebug>
#include <QGraphicsSceneMouseEvent> #include <QGraphicsSceneMouseEvent>
@@ -219,9 +220,7 @@ void DragTool::abort()
static ItemLibraryEntry itemLibraryEntryFromMimeData(const QMimeData *mimeData) static ItemLibraryEntry itemLibraryEntryFromMimeData(const QMimeData *mimeData)
{ {
QByteArray data = mimeData->data(QStringLiteral("application/vnd.bauhaus.itemlibraryinfo")); QDataStream stream(mimeData->data(Constants::MIME_TYPE_ITEM_LIBRARY_INFO));
QDataStream stream(data);
ItemLibraryEntry itemLibraryEntry; ItemLibraryEntry itemLibraryEntry;
stream >> itemLibraryEntry; stream >> itemLibraryEntry;
@@ -236,7 +235,7 @@ static bool canBeDropped(const QMimeData *mimeData)
static bool hasItemLibraryInfo(const QMimeData *mimeData) static bool hasItemLibraryInfo(const QMimeData *mimeData)
{ {
return mimeData->hasFormat(QStringLiteral("application/vnd.bauhaus.itemlibraryinfo")); return mimeData->hasFormat(Constants::MIME_TYPE_ITEM_LIBRARY_INFO);
} }
void DragTool::dropEvent(const QList<QGraphicsItem *> &/*itemList*/, QGraphicsSceneDragDropEvent *event) void DragTool::dropEvent(const QList<QGraphicsItem *> &/*itemList*/, QGraphicsSceneDragDropEvent *event)
@@ -326,12 +325,12 @@ void DragTool::createDragNodes(const QMimeData *mimeData, const QPointF &scenePo
scenePosition); scenePosition);
} else { } else {
const QStringList assetPaths = QString::fromUtf8(mimeData const QStringList assetPaths = QString::fromUtf8(mimeData
->data("application/vnd.bauhaus.libraryresource")).split(","); ->data(Constants::MIME_TYPE_ASSETS)).split(',');
for (const QString &assetPath : assetPaths) { for (const QString &assetPath : assetPaths) {
QString assetType = AssetsLibraryWidget::getAssetTypeAndData(assetPath).first; QString assetType = AssetsLibraryWidget::getAssetTypeAndData(assetPath).first;
if (assetType == "application/vnd.bauhaus.libraryresource.image") if (assetType == Constants::MIME_TYPE_ASSET_IMAGE)
createQmlItemNodeFromImage(assetPath, targetContainerQmlItemNode, scenePosition); createQmlItemNodeFromImage(assetPath, targetContainerQmlItemNode, scenePosition);
else if (assetType == "application/vnd.bauhaus.libraryresource.font") else if (assetType == Constants::MIME_TYPE_ASSET_FONT)
createQmlItemNodeFromFont(assetPath, targetContainerQmlItemNode, scenePosition); createQmlItemNodeFromFont(assetPath, targetContainerQmlItemNode, scenePosition);
} }

View File

@@ -36,6 +36,7 @@
#include <nodemetainfo.h> #include <nodemetainfo.h>
#include <projectexplorer/project.h> #include <projectexplorer/project.h>
#include <projectexplorer/session.h> #include <projectexplorer/session.h>
#include "qmldesignerconstants.h"
#include "qmldesignerplugin.h" #include "qmldesignerplugin.h"
#include <utils/algorithm.h> #include <utils/algorithm.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
@@ -515,9 +516,9 @@ QMimeData *ItemLibraryModel::getMimeData(const ItemLibraryEntry &itemLibraryEntr
QByteArray data; QByteArray data;
QDataStream stream(&data, QIODevice::WriteOnly); QDataStream stream(&data, QIODevice::WriteOnly);
stream << itemLibraryEntry; stream << itemLibraryEntry;
mimeData->setData(QStringLiteral("application/vnd.bauhaus.itemlibraryinfo"), data); mimeData->setData(Constants::MIME_TYPE_ITEM_LIBRARY_INFO, data);
mimeData->removeFormat(QStringLiteral("text/plain")); mimeData->removeFormat("text/plain");
return mimeData; return mimeData;
} }

View File

@@ -40,7 +40,6 @@
#include "modelnodeoperations.h" #include "modelnodeoperations.h"
#include <metainfo.h> #include <metainfo.h>
#include <model.h> #include <model.h>
#include <navigatorwidget.h>
#include <rewritingexception.h> #include <rewritingexception.h>
#include <qmldesignerconstants.h> #include <qmldesignerconstants.h>
#include <qmldesignerplugin.h> #include <qmldesignerplugin.h>
@@ -89,6 +88,9 @@ static QString propertyEditorResourcesPath()
bool ItemLibraryWidget::eventFilter(QObject *obj, QEvent *event) bool ItemLibraryWidget::eventFilter(QObject *obj, QEvent *event)
{ {
auto document = QmlDesignerPlugin::instance()->currentDesignDocument();
Model *model = document ? document->documentModel() : nullptr;
if (event->type() == QEvent::FocusOut) { if (event->type() == QEvent::FocusOut) {
if (obj == m_itemsWidget.data()) if (obj == m_itemsWidget.data())
QMetaObject::invokeMethod(m_itemsWidget->rootObject(), "closeContextMenu"); QMetaObject::invokeMethod(m_itemsWidget->rootObject(), "closeContextMenu");
@@ -115,33 +117,19 @@ bool ItemLibraryWidget::eventFilter(QObject *obj, QEvent *event)
} }
} }
} }
QWidget *view = QmlDesignerPlugin::instance()->viewManager().widget("Navigator");
if (view) { if (model) {
NavigatorWidget *navView = qobject_cast<NavigatorWidget *>(view); model->startDrag(m_itemLibraryModel->getMimeData(entry),
if (navView) { Utils::StyleHelper::dpiSpecificImageFile(entry.libraryEntryIconPath()));
navView->setDragType(entry.typeName());
navView->update();
} }
}
auto drag = new QDrag(this);
drag->setPixmap(Utils::StyleHelper::dpiSpecificImageFile(entry.libraryEntryIconPath()));
drag->setMimeData(m_itemLibraryModel->getMimeData(entry));
drag->exec();
drag->deleteLater();
m_itemToDrag = {}; m_itemToDrag = {};
} }
} }
} else if (event->type() == QMouseEvent::MouseButtonRelease) { } else if (event->type() == QMouseEvent::MouseButtonRelease) {
m_itemToDrag = {}; m_itemToDrag = {};
QWidget *view = QmlDesignerPlugin::instance()->viewManager().widget("Navigator"); if (model)
if (view) { model->endDrag();
NavigatorWidget *navView = qobject_cast<NavigatorWidget *>(view);
if (navView) {
navView->setDragType("");
navView->update();
}
}
} }
return QObject::eventFilter(obj, event); return QObject::eventFilter(obj, event);

View File

@@ -27,6 +27,7 @@
#include "navigatorview.h" #include "navigatorview.h"
#include "navigatorwidget.h" #include "navigatorwidget.h"
#include "choosefrompropertylistdialog.h" #include "choosefrompropertylistdialog.h"
#include "qmldesignerconstants.h"
#include "qmldesignerplugin.h" #include "qmldesignerplugin.h"
#include "assetslibrarywidget.h" #include "assetslibrarywidget.h"
@@ -71,7 +72,7 @@ namespace QmlDesigner {
static QList<ModelNode> modelNodesFromMimeData(const QMimeData *mineData, AbstractView *view) static QList<ModelNode> modelNodesFromMimeData(const QMimeData *mineData, AbstractView *view)
{ {
QByteArray encodedModelNodeData = mineData->data(QLatin1String("application/vnd.modelnode.list")); QByteArray encodedModelNodeData = mineData->data(Constants::MIME_TYPE_MODELNODE_LIST);
QDataStream modelNodeStream(&encodedModelNodeData, QIODevice::ReadOnly); QDataStream modelNodeStream(&encodedModelNodeData, QIODevice::ReadOnly);
QList<ModelNode> modelNodeList; QList<ModelNode> modelNodeList;
@@ -465,9 +466,9 @@ void NavigatorTreeModel::setView(NavigatorView *view)
QStringList NavigatorTreeModel::mimeTypes() const QStringList NavigatorTreeModel::mimeTypes() const
{ {
const static QStringList types({"application/vnd.modelnode.list", const static QStringList types({Constants::MIME_TYPE_MODELNODE_LIST,
"application/vnd.bauhaus.itemlibraryinfo", Constants::MIME_TYPE_ITEM_LIBRARY_INFO,
"application/vnd.bauhaus.libraryresource"}); Constants::MIME_TYPE_ASSETS});
return types; return types;
} }
@@ -490,7 +491,7 @@ QMimeData *NavigatorTreeModel::mimeData(const QModelIndexList &modelIndexList) c
} }
} }
mimeData->setData("application/vnd.modelnode.list", encodedModelNodeData); mimeData->setData(Constants::MIME_TYPE_MODELNODE_LIST, encodedModelNodeData);
return mimeData; return mimeData;
} }
@@ -560,10 +561,10 @@ bool NavigatorTreeModel::dropMimeData(const QMimeData *mimeData,
widget->setDragType(""); widget->setDragType("");
if (dropModelIndex.model() == this) { if (dropModelIndex.model() == this) {
if (mimeData->hasFormat("application/vnd.bauhaus.itemlibraryinfo")) { if (mimeData->hasFormat(Constants::MIME_TYPE_ITEM_LIBRARY_INFO)) {
handleItemLibraryItemDrop(mimeData, rowNumber, dropModelIndex); handleItemLibraryItemDrop(mimeData, rowNumber, dropModelIndex);
} else if (mimeData->hasFormat("application/vnd.bauhaus.libraryresource")) { } else if (mimeData->hasFormat(Constants::MIME_TYPE_ASSETS)) {
const QStringList assetsPaths = QString::fromUtf8(mimeData->data("application/vnd.bauhaus.libraryresource")).split(","); const QStringList assetsPaths = QString::fromUtf8(mimeData->data(Constants::MIME_TYPE_ASSETS)).split(',');
NodeAbstractProperty targetProperty; NodeAbstractProperty targetProperty;
const QModelIndex rowModelIndex = dropModelIndex.sibling(dropModelIndex.row(), 0); const QModelIndex rowModelIndex = dropModelIndex.sibling(dropModelIndex.row(), 0);
@@ -579,9 +580,9 @@ bool NavigatorTreeModel::dropMimeData(const QMimeData *mimeData,
QSet<QString> neededImports; QSet<QString> neededImports;
for (const QString &assetPath : assetsPaths) { for (const QString &assetPath : assetsPaths) {
QString assetType = AssetsLibraryWidget::getAssetTypeAndData(assetPath).first; QString assetType = AssetsLibraryWidget::getAssetTypeAndData(assetPath).first;
if (assetType == "application/vnd.bauhaus.libraryresource.shader") if (assetType == Constants::MIME_TYPE_ASSET_SHADER)
neededImports.insert("QtQuick3D"); neededImports.insert("QtQuick3D");
else if (assetType == "application/vnd.bauhaus.libraryresource.sound") else if (assetType == Constants::MIME_TYPE_ASSET_SOUND)
neededImports.insert("QtMultimedia"); neededImports.insert("QtMultimedia");
if (neededImports.size() == 2) if (neededImports.size() == 2)
@@ -598,20 +599,20 @@ bool NavigatorTreeModel::dropMimeData(const QMimeData *mimeData,
auto assetTypeAndData = AssetsLibraryWidget::getAssetTypeAndData(assetPath); auto assetTypeAndData = AssetsLibraryWidget::getAssetTypeAndData(assetPath);
QString assetType = assetTypeAndData.first; QString assetType = assetTypeAndData.first;
QString assetData = QString::fromUtf8(assetTypeAndData.second); QString assetData = QString::fromUtf8(assetTypeAndData.second);
if (assetType == "application/vnd.bauhaus.libraryresource.image") { if (assetType == Constants::MIME_TYPE_ASSET_IMAGE) {
currNode = handleItemLibraryImageDrop(assetPath, targetProperty, currNode = handleItemLibraryImageDrop(assetPath, targetProperty,
rowModelIndex, moveNodesAfter); rowModelIndex, moveNodesAfter);
} else if (assetType == "application/vnd.bauhaus.libraryresource.font") { } else if (assetType == Constants::MIME_TYPE_ASSET_FONT) {
currNode = handleItemLibraryFontDrop(assetData, // assetData is fontFamily currNode = handleItemLibraryFontDrop(assetData, // assetData is fontFamily
targetProperty, rowModelIndex); targetProperty, rowModelIndex);
} else if (assetType == "application/vnd.bauhaus.libraryresource.shader") { } else if (assetType == Constants::MIME_TYPE_ASSET_SHADER) {
currNode = handleItemLibraryShaderDrop(assetPath, assetData == "f", currNode = handleItemLibraryShaderDrop(assetPath, assetData == "f",
targetProperty, rowModelIndex, targetProperty, rowModelIndex,
moveNodesAfter); moveNodesAfter);
} else if (assetType == "application/vnd.bauhaus.libraryresource.sound") { } else if (assetType == Constants::MIME_TYPE_ASSET_SOUND) {
currNode = handleItemLibrarySoundDrop(assetPath, targetProperty, currNode = handleItemLibrarySoundDrop(assetPath, targetProperty,
rowModelIndex); rowModelIndex);
} else if (assetType == "application/vnd.bauhaus.libraryresource.texture3d") { } else if (assetType == Constants::MIME_TYPE_ASSET_TEXTURE3D) {
currNode = handleItemLibraryTexture3dDrop(assetPath, targetProperty, currNode = handleItemLibraryTexture3dDrop(assetPath, targetProperty,
rowModelIndex, moveNodesAfter); rowModelIndex, moveNodesAfter);
} }
@@ -627,7 +628,7 @@ bool NavigatorTreeModel::dropMimeData(const QMimeData *mimeData,
m_view->setSelectedModelNodes(addedNodes); m_view->setSelectedModelNodes(addedNodes);
} }
} }
} else if (mimeData->hasFormat("application/vnd.modelnode.list")) { } else if (mimeData->hasFormat(Constants::MIME_TYPE_MODELNODE_LIST)) {
handleInternalDrop(mimeData, rowNumber, dropModelIndex); handleInternalDrop(mimeData, rowNumber, dropModelIndex);
} }
} }
@@ -673,7 +674,7 @@ void NavigatorTreeModel::handleItemLibraryItemDrop(const QMimeData *mimeData, in
NodeAbstractProperty targetProperty; NodeAbstractProperty targetProperty;
const ItemLibraryEntry itemLibraryEntry = const ItemLibraryEntry itemLibraryEntry =
createItemLibraryEntryFromMimeData(mimeData->data("application/vnd.bauhaus.itemlibraryinfo")); createItemLibraryEntryFromMimeData(mimeData->data(Constants::MIME_TYPE_ITEM_LIBRARY_INFO));
const NodeHints hints = NodeHints::fromItemLibraryEntry(itemLibraryEntry); const NodeHints hints = NodeHints::fromItemLibraryEntry(itemLibraryEntry);

View File

@@ -36,6 +36,7 @@
#include <bindingproperty.h> #include <bindingproperty.h>
#include <designmodecontext.h> #include <designmodecontext.h>
#include <designersettings.h> #include <designersettings.h>
#include <itemlibraryinfo.h>
#include <nodeproperty.h> #include <nodeproperty.h>
#include <nodelistproperty.h> #include <nodelistproperty.h>
#include <variantproperty.h> #include <variantproperty.h>
@@ -57,8 +58,9 @@
#include <utils/stylehelper.h> #include <utils/stylehelper.h>
#include <QHeaderView> #include <QHeaderView>
#include <QTimer> #include <QMimeData>
#include <QPixmap> #include <QPixmap>
#include <QTimer>
static inline void setScenePos(const QmlDesigner::ModelNode &modelNode,const QPointF &pos) static inline void setScenePos(const QmlDesigner::ModelNode &modelNode,const QPointF &pos)
{ {
@@ -263,6 +265,25 @@ void NavigatorView::bindingPropertiesChanged(const QList<BindingProperty> & prop
} }
} }
void NavigatorView::dragStarted(QMimeData *mimeData)
{
if (mimeData->hasFormat(Constants::MIME_TYPE_ITEM_LIBRARY_INFO)) {
QByteArray data = mimeData->data(Constants::MIME_TYPE_ITEM_LIBRARY_INFO);
QDataStream stream(data);
ItemLibraryEntry itemLibraryEntry;
stream >> itemLibraryEntry;
m_widget->setDragType(itemLibraryEntry.typeName());
m_widget->update();
}
}
void NavigatorView::dragEnded()
{
m_widget->setDragType("");
m_widget->update();
}
void NavigatorView::customNotification(const AbstractView *view, const QString &identifier, void NavigatorView::customNotification(const AbstractView *view, const QString &identifier,
const QList<ModelNode> &nodeList, const QList<QVariant> &data) const QList<ModelNode> &nodeList, const QList<QVariant> &data)
{ {

View File

@@ -92,6 +92,9 @@ public:
void bindingPropertiesChanged(const QList<BindingProperty> &propertyList, PropertyChangeFlags) override; void bindingPropertiesChanged(const QList<BindingProperty> &propertyList, PropertyChangeFlags) override;
void dragStarted(QMimeData *mimeData) override;
void dragEnded() override;
void customNotification(const AbstractView *view, const QString &identifier, const QList<ModelNode> &nodeList, const QList<QVariant> &data) override; void customNotification(const AbstractView *view, const QString &identifier, const QList<ModelNode> &nodeList, const QList<QVariant> &data) override;
void handleChangedExport(const ModelNode &modelNode, bool exported); void handleChangedExport(const ModelNode &modelNode, bool exported);

View File

@@ -294,7 +294,7 @@ void PropertyEditorQmlBackend::createPropertyEditorValue(const QmlObjectNode &qm
valueObject = new PropertyEditorValue(&backendValuesPropertyMap()); valueObject = new PropertyEditorValue(&backendValuesPropertyMap());
QObject::connect(valueObject, &PropertyEditorValue::valueChanged, &backendValuesPropertyMap(), &DesignerPropertyMap::valueChanged); QObject::connect(valueObject, &PropertyEditorValue::valueChanged, &backendValuesPropertyMap(), &DesignerPropertyMap::valueChanged);
QObject::connect(valueObject, &PropertyEditorValue::expressionChanged, propertyEditor, &PropertyEditorView::changeExpression); QObject::connect(valueObject, &PropertyEditorValue::expressionChanged, propertyEditor, &PropertyEditorView::changeExpression);
QObject::connect(valueObject, &PropertyEditorValue::exportPopertyAsAliasRequested, propertyEditor, &PropertyEditorView::exportPopertyAsAlias); QObject::connect(valueObject, &PropertyEditorValue::exportPropertyAsAliasRequested, propertyEditor, &PropertyEditorView::exportPropertyAsAlias);
QObject::connect(valueObject, &PropertyEditorValue::removeAliasExportRequested, propertyEditor, &PropertyEditorView::removeAliasExport); QObject::connect(valueObject, &PropertyEditorValue::removeAliasExportRequested, propertyEditor, &PropertyEditorView::removeAliasExport);
backendValuesPropertyMap().insert(QString::fromUtf8(propertyName), QVariant::fromValue(valueObject)); backendValuesPropertyMap().insert(QString::fromUtf8(propertyName), QVariant::fromValue(valueObject));
} }

View File

@@ -367,9 +367,9 @@ void PropertyEditorValue::setEnumeration(const QString &scope, const QString &na
setValueWithEmit(QVariant::fromValue(newEnumeration)); setValueWithEmit(QVariant::fromValue(newEnumeration));
} }
void PropertyEditorValue::exportPopertyAsAlias() void PropertyEditorValue::exportPropertyAsAlias()
{ {
emit exportPopertyAsAliasRequested(nameAsQString()); emit exportPropertyAsAliasRequested(nameAsQString());
} }
bool PropertyEditorValue::hasPropertyAlias() const bool PropertyEditorValue::hasPropertyAlias() const

View File

@@ -130,7 +130,7 @@ public:
static void registerDeclarativeTypes(); static void registerDeclarativeTypes();
Q_INVOKABLE void exportPopertyAsAlias(); Q_INVOKABLE void exportPropertyAsAlias();
Q_INVOKABLE bool hasPropertyAlias() const; Q_INVOKABLE bool hasPropertyAlias() const;
Q_INVOKABLE bool isAttachedProperty() const; Q_INVOKABLE bool isAttachedProperty() const;
Q_INVOKABLE void removeAliasExport(); Q_INVOKABLE void removeAliasExport();
@@ -153,7 +153,7 @@ signals:
void valueChangedQml(); void valueChangedQml();
void expressionChanged(const QString &name); void expressionChanged(const QString &name);
void exportPopertyAsAliasRequested(const QString &name); void exportPropertyAsAliasRequested(const QString &name);
void removeAliasExportRequested(const QString &name); void removeAliasExportRequested(const QString &name);
void modelStateChanged(); void modelStateChanged();

View File

@@ -256,6 +256,9 @@ void PropertyEditorView::changeExpression(const QString &propertyName)
if (noValidSelection()) if (noValidSelection())
return; return;
QScopeGuard unlock([&](){ m_locked = false; });
m_locked = true;
executeInTransaction("PropertyEditorView::changeExpression", [this, name](){ executeInTransaction("PropertyEditorView::changeExpression", [this, name](){
PropertyName underscoreName(name); PropertyName underscoreName(name);
underscoreName.replace('.', '_'); underscoreName.replace('.', '_');
@@ -317,13 +320,13 @@ void PropertyEditorView::changeExpression(const QString &propertyName)
return; return;
} }
if (qmlObjectNode->expression(name) != value->expression() || !qmlObjectNode->propertyAffectedByCurrentState(name)) if (qmlObjectNode->expression(name) != value->expression()
|| !qmlObjectNode->propertyAffectedByCurrentState(name))
qmlObjectNode->setBindingProperty(name, value->expression()); qmlObjectNode->setBindingProperty(name, value->expression());
}); /* end of transaction */ }); /* end of transaction */
} }
void PropertyEditorView::exportPopertyAsAlias(const QString &name) void PropertyEditorView::exportPropertyAsAlias(const QString &name)
{ {
if (name.isNull()) if (name.isNull())
return; return;
@@ -334,7 +337,7 @@ void PropertyEditorView::exportPopertyAsAlias(const QString &name)
if (noValidSelection()) if (noValidSelection())
return; return;
executeInTransaction("PropertyEditorView::exportPopertyAsAlias", [this, name](){ executeInTransaction("PropertyEditorView::exportPropertyAsAlias", [this, name](){
const QString id = m_selectedNode.validId(); const QString id = m_selectedNode.validId();
QString upperCasePropertyName = name; QString upperCasePropertyName = name;
upperCasePropertyName.replace(0, 1, upperCasePropertyName.at(0).toUpper()); upperCasePropertyName.replace(0, 1, upperCasePropertyName.at(0).toUpper());
@@ -362,7 +365,7 @@ void PropertyEditorView::removeAliasExport(const QString &name)
if (noValidSelection()) if (noValidSelection())
return; return;
executeInTransaction("PropertyEditorView::exportPopertyAsAlias", [this, name](){ executeInTransaction("PropertyEditorView::exportPropertyAsAlias", [this, name](){
const QString id = m_selectedNode.validId(); const QString id = m_selectedNode.validId();
for (const BindingProperty &property : rootModelNode().bindingProperties()) for (const BindingProperty &property : rootModelNode().bindingProperties())
@@ -692,6 +695,9 @@ void PropertyEditorView::variantPropertiesChanged(const QList<VariantProperty>&
void PropertyEditorView::bindingPropertiesChanged(const QList<BindingProperty>& propertyList, PropertyChangeFlags /*propertyChange*/) void PropertyEditorView::bindingPropertiesChanged(const QList<BindingProperty>& propertyList, PropertyChangeFlags /*propertyChange*/)
{ {
if (locked())
return;
if (noValidSelection()) if (noValidSelection())
return; return;

View File

@@ -89,7 +89,7 @@ public:
void changeValue(const QString &name); void changeValue(const QString &name);
void changeExpression(const QString &name); void changeExpression(const QString &name);
void exportPopertyAsAlias(const QString &name); void exportPropertyAsAlias(const QString &name);
void removeAliasExport(const QString &name); void removeAliasExport(const QString &name);
bool locked() const; bool locked() const;

View File

@@ -229,6 +229,9 @@ public:
virtual void updateImport3DSupport(const QVariantMap &supportMap); virtual void updateImport3DSupport(const QVariantMap &supportMap);
virtual void modelNodePreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap); virtual void modelNodePreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap);
virtual void dragStarted(QMimeData *mimeData);
virtual void dragEnded();
void changeRootNodeType(const TypeName &type, int majorVersion, int minorVersion); void changeRootNodeType(const TypeName &type, int majorVersion, int minorVersion);
NodeInstanceView *nodeInstanceView() const; NodeInstanceView *nodeInstanceView() const;

View File

@@ -129,6 +129,9 @@ public:
QString generateNewId(const QString &prefixName) const; QString generateNewId(const QString &prefixName) const;
QString generateNewId(const QString &prefixName, const QString &fallbackPrefix) const; QString generateNewId(const QString &prefixName, const QString &fallbackPrefix) const;
void startDrag(QMimeData *mimeData, const QString iconPath = {});
void endDrag();
protected: protected:
Model(); Model();

View File

@@ -396,6 +396,9 @@ void AbstractView::modelNodePreviewPixmapChanged(const ModelNode & /*node*/, con
{ {
} }
void AbstractView::dragStarted(QMimeData * /*mimeData*/) {}
void AbstractView::dragEnded() {}
QList<ModelNode> AbstractView::toModelNodeList(const QList<Internal::InternalNode::Pointer> &nodeList) const QList<ModelNode> AbstractView::toModelNodeList(const QList<Internal::InternalNode::Pointer> &nodeList) const
{ {
return QmlDesigner::toModelNodeList(nodeList, const_cast<AbstractView*>(this)); return QmlDesigner::toModelNodeList(nodeList, const_cast<AbstractView*>(this));

View File

@@ -67,6 +67,7 @@
#include <utils/algorithm.h> #include <utils/algorithm.h>
#include <QDrag>
#include <QRegularExpression> #include <QRegularExpression>
/*! /*!
@@ -588,6 +589,16 @@ void ModelPrivate::notifyImport3DSupportChanged(const QVariantMap &supportMap)
notifyInstanceChanges([&](AbstractView *view) { view->updateImport3DSupport(supportMap); }); notifyInstanceChanges([&](AbstractView *view) { view->updateImport3DSupport(supportMap); });
} }
void ModelPrivate::notifyDragStarted(QMimeData *mimeData)
{
notifyInstanceChanges([&](AbstractView *view) { view->dragStarted(mimeData); });
}
void ModelPrivate::notifyDragEnded()
{
notifyInstanceChanges([&](AbstractView *view) { view->dragEnded(); });
}
void ModelPrivate::notifyRewriterBeginTransaction() void ModelPrivate::notifyRewriterBeginTransaction()
{ {
notifyNodeInstanceViewLast([&](AbstractView *view) { view->rewriterBeginTransaction(); }); notifyNodeInstanceViewLast([&](AbstractView *view) { view->rewriterBeginTransaction(); });
@@ -1492,6 +1503,22 @@ QString Model::generateNewId(const QString &prefixName, const QString &fallbackP
return newId; return newId;
} }
void Model::startDrag(QMimeData *mimeData, const QString iconPath)
{
d->notifyDragStarted(mimeData);
auto drag = new QDrag(this);
drag->setPixmap(iconPath);
drag->setMimeData(mimeData);
drag->exec();
drag->deleteLater();
}
void Model::endDrag()
{
d->notifyDragEnded();
}
QString Model::generateNewId(const QString &prefixName) const QString Model::generateNewId(const QString &prefixName) const
{ {
return generateNewId(prefixName, QStringLiteral("element")); return generateNewId(prefixName, QStringLiteral("element"));

View File

@@ -183,6 +183,9 @@ public:
void notifyModelNodePreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap); void notifyModelNodePreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap);
void notifyImport3DSupportChanged(const QVariantMap &supportMap); void notifyImport3DSupportChanged(const QVariantMap &supportMap);
void notifyDragStarted(QMimeData *mimeData);
void notifyDragEnded();
void setDocumentMessages(const QList<DocumentMessage> &errors, const QList<DocumentMessage> &warnings); void setDocumentMessages(const QList<DocumentMessage> &errors, const QList<DocumentMessage> &warnings);
void notifyRewriterBeginTransaction(); void notifyRewriterBeginTransaction();

View File

@@ -85,6 +85,16 @@ const char QUICK_3D_ASSET_IMPORT_DATA_OPTIONS_KEY[] = "import_options";
const char QUICK_3D_ASSET_IMPORT_DATA_SOURCE_KEY[] = "source_scene"; const char QUICK_3D_ASSET_IMPORT_DATA_SOURCE_KEY[] = "source_scene";
const char DEFAULT_ASSET_IMPORT_FOLDER[] = "/asset_imports"; const char DEFAULT_ASSET_IMPORT_FOLDER[] = "/asset_imports";
const char MIME_TYPE_ITEM_LIBRARY_INFO[] = "application/vnd.qtdesignstudio.itemlibraryinfo";
const char MIME_TYPE_ASSETS[] = "application/vnd.qtdesignstudio.assets";
const char MIME_TYPE_ASSET_IMAGE[] = "application/vnd.qtdesignstudio.asset.image";
const char MIME_TYPE_ASSET_FONT[] = "application/vnd.qtdesignstudio.asset.font";
const char MIME_TYPE_ASSET_SHADER[] = "application/vnd.qtdesignstudio.asset.shader";
const char MIME_TYPE_ASSET_SOUND[] = "application/vnd.qtdesignstudio.asset.sound";
const char MIME_TYPE_ASSET_VIDEO[] = "application/vnd.qtdesignstudio.asset.video";
const char MIME_TYPE_ASSET_TEXTURE3D[] = "application/vnd.qtdesignstudio.asset.texture3d";
const char MIME_TYPE_MODELNODE_LIST[] = "application/vnd.qtdesignstudio.modelnode.list";
// Menus // Menus
const char M_VIEW_WORKSPACES[] = "QmlDesigner.Menu.View.Workspaces"; const char M_VIEW_WORKSPACES[] = "QmlDesigner.Menu.View.Workspaces";

View File

@@ -91,6 +91,10 @@ QmlProjectItem *QmlProjectFileFormat::parseProjectFile(const Utils::FilePath &fi
if (mainFileProperty.isValid()) if (mainFileProperty.isValid())
projectItem->setMainFile(mainFileProperty.value.toString()); projectItem->setMainFile(mainFileProperty.value.toString());
const auto mainUiFileProperty = rootNode->property(QLatin1String("mainUiFile"));
if (mainUiFileProperty.isValid())
projectItem->setMainUiFile(mainUiFileProperty.value.toString());
const auto importPathsProperty = rootNode->property(QLatin1String("importPaths")); const auto importPathsProperty = rootNode->property(QLatin1String("importPaths"));
if (importPathsProperty.isValid()) { if (importPathsProperty.isValid()) {
QStringList list = importPathsProperty.value.toStringList(); QStringList list = importPathsProperty.value.toStringList();

View File

@@ -81,6 +81,9 @@ public:
QString mainFile() const { return m_mainFile; } QString mainFile() const { return m_mainFile; }
void setMainFile(const QString &mainFilePath) { m_mainFile = mainFilePath; } void setMainFile(const QString &mainFilePath) { m_mainFile = mainFilePath; }
QString mainUiFile() const { return m_mainUiFile; }
void setMainUiFile(const QString &mainUiFilePath) { m_mainUiFile = mainUiFilePath; }
bool widgetApp() const { return m_widgetApp; } bool widgetApp() const { return m_widgetApp; }
void setWidgetApp(bool widgetApp) { m_widgetApp = widgetApp; } void setWidgetApp(bool widgetApp) { m_widgetApp = widgetApp; }
@@ -107,6 +110,7 @@ protected:
QStringList m_supportedLanguages; QStringList m_supportedLanguages;
QString m_primaryLanguage; QString m_primaryLanguage;
QString m_mainFile; QString m_mainFile;
QString m_mainUiFile;
Utils::EnvironmentItems m_environment; Utils::EnvironmentItems m_environment;
QVector<QmlProjectContentItem *> m_content; // content property QVector<QmlProjectContentItem *> m_content; // content property
bool m_forceFreeType = false; bool m_forceFreeType = false;

View File

@@ -118,6 +118,22 @@ QmlProject::QmlProject(const Utils::FilePath &fileName)
disconnect(m_openFileConnection); disconnect(m_openFileConnection);
if (target && success) { if (target && success) {
auto target = activeTarget();
if (!target)
return;
auto qmlBuildSystem = qobject_cast<QmlProjectManager::QmlBuildSystem *>(
target->buildSystem());
const Utils::FilePath mainUiFile = qmlBuildSystem->mainUiFilePath();
if (mainUiFile.completeSuffix() == "qi.qml" && mainUiFile.exists()) {
QTimer::singleShot(1000, [mainUiFile]() {
Core::EditorManager::openEditor(mainUiFile,
Utils::Id());
});
} else {
Utils::FilePaths uiFiles = getUiQmlFilesForFolder(projectDirectory() Utils::FilePaths uiFiles = getUiQmlFilesForFolder(projectDirectory()
+ "/content"); + "/content");
if (uiFiles.isEmpty()) if (uiFiles.isEmpty())
@@ -135,6 +151,7 @@ QmlProject::QmlProject(const Utils::FilePath &fileName)
}); });
} }
} }
}
}); });
} }
} }
@@ -236,6 +253,58 @@ void QmlBuildSystem::parseProject(RefreshOptions options)
} }
} }
bool QmlBuildSystem::setFileSettingInProjectFile(const QString &setting, const Utils::FilePath &mainFilePath, const QString &oldFile)
{
// make sure to change it also in the qmlproject file
const Utils::FilePath qmlProjectFilePath = project()->projectFilePath();
Core::FileChangeBlocker fileChangeBlocker(qmlProjectFilePath);
const QList<Core::IEditor *> editors = Core::DocumentModel::editorsForFilePath(qmlProjectFilePath);
TextEditor::TextDocument *document = nullptr;
if (!editors.isEmpty()) {
document = qobject_cast<TextEditor::TextDocument*>(editors.first()->document());
if (document && document->isModified())
if (!Core::DocumentManager::saveDocument(document))
return false;
}
QString fileContent;
QString error;
Utils::TextFileFormat textFileFormat;
const QTextCodec *codec = QTextCodec::codecForName("UTF-8"); // qml files are defined to be utf-8
if (Utils::TextFileFormat::readFile(qmlProjectFilePath, codec, &fileContent, &textFileFormat, &error)
!= Utils::TextFileFormat::ReadSuccess) {
qWarning() << "Failed to read file" << qmlProjectFilePath << ":" << error;
}
const QString settingQmlCode = setting + ":";
QDir projectDir = project()->projectFilePath().toDir();
projectDir.cdUp();
const QString relativePath = projectDir.relativeFilePath(mainFilePath.toString());
if (fileContent.indexOf(settingQmlCode) < 0) {
QString addedText = QString("\n %1 \"%2\"\n").arg(settingQmlCode).arg(relativePath);
auto index = fileContent.lastIndexOf("}");
fileContent.insert(index, addedText);
} else {
QString originalFileName = oldFile;
originalFileName.replace(".", "\\.");
const QRegularExpression expression(QString("%1\\s*\"(%2)\"").arg(settingQmlCode).arg(originalFileName));
const QRegularExpressionMatch match = expression.match(fileContent);
fileContent.replace(match.capturedStart(1),
match.capturedLength(1),
relativePath);
}
if (!textFileFormat.writeFile(qmlProjectFilePath, fileContent, &error))
qWarning() << "Failed to write file" << qmlProjectFilePath << ":" << error;
refresh(Everything);
return true;
}
void QmlBuildSystem::refresh(RefreshOptions options) void QmlBuildSystem::refresh(RefreshOptions options)
{ {
ParseGuard guard = guardParsingRun(); ParseGuard guard = guardParsingRun();
@@ -266,11 +335,68 @@ QString QmlBuildSystem::mainFile() const
return QString(); return QString();
} }
QString QmlBuildSystem::mainUiFile() const
{
if (m_projectItem)
return m_projectItem->mainUiFile();
return QString();
}
Utils::FilePath QmlBuildSystem::mainFilePath() const Utils::FilePath QmlBuildSystem::mainFilePath() const
{ {
return projectDirectory().pathAppended(mainFile()); return projectDirectory().pathAppended(mainFile());
} }
Utils::FilePath QmlBuildSystem::mainUiFilePath() const
{
return projectDirectory().pathAppended(mainUiFile());
}
bool QmlBuildSystem::setMainFileInProjectFile(const Utils::FilePath &newMainFilePath)
{
return setFileSettingInProjectFile("mainFile", newMainFilePath, mainFile());
}
bool QmlBuildSystem::setMainUiFileInProjectFile(const Utils::FilePath &newMainUiFilePath)
{
return setMainUiFileInMainFile(newMainUiFilePath)
&& setFileSettingInProjectFile("mainUiFile", newMainUiFilePath, mainUiFile());
}
bool QmlBuildSystem::setMainUiFileInMainFile(const Utils::FilePath &newMainUiFilePath)
{
Core::FileChangeBlocker fileChangeBlocker(mainFilePath());
const QList<Core::IEditor *> editors = Core::DocumentModel::editorsForFilePath(mainFilePath());
TextEditor::TextDocument *document = nullptr;
if (!editors.isEmpty()) {
document = qobject_cast<TextEditor::TextDocument*>(editors.first()->document());
if (document && document->isModified())
if (!Core::DocumentManager::saveDocument(document))
return false;
}
QString fileContent;
QString error;
Utils::TextFileFormat textFileFormat;
const QTextCodec *codec = QTextCodec::codecForName("UTF-8"); // qml files are defined to be utf-8
if (Utils::TextFileFormat::readFile(mainFilePath(), codec, &fileContent, &textFileFormat, &error)
!= Utils::TextFileFormat::ReadSuccess) {
qWarning() << "Failed to read file" << mainFilePath() << ":" << error;
}
const QString currentMain = QString("%1 {").arg(mainUiFilePath().baseName());
const QString newMain = QString("%1 {").arg(newMainUiFilePath.baseName());
if (fileContent.contains(currentMain))
fileContent.replace(currentMain, newMain);
if (!textFileFormat.writeFile(mainFilePath(), fileContent, &error))
qWarning() << "Failed to write file" << mainFilePath() << ":" << error;
return true;
}
bool QmlBuildSystem::qtForMCUs() const bool QmlBuildSystem::qtForMCUs() const
{ {
if (m_projectItem) if (m_projectItem)
@@ -646,43 +772,10 @@ bool QmlBuildSystem::deleteFiles(Node *context, const FilePaths &filePaths)
bool QmlBuildSystem::renameFile(Node * context, const FilePath &oldFilePath, const FilePath &newFilePath) bool QmlBuildSystem::renameFile(Node * context, const FilePath &oldFilePath, const FilePath &newFilePath)
{ {
if (dynamic_cast<QmlProjectNode *>(context)) { if (dynamic_cast<QmlProjectNode *>(context)) {
if (oldFilePath.endsWith(mainFile())) { if (oldFilePath.endsWith(mainFile()))
setMainFile(newFilePath.toString()); return setMainFileInProjectFile(newFilePath);
if (oldFilePath.endsWith(mainUiFile()))
// make sure to change it also in the qmlproject file return setMainUiFileInProjectFile(newFilePath);
const Utils::FilePath qmlProjectFilePath = project()->projectFilePath();
Core::FileChangeBlocker fileChangeBlocker(qmlProjectFilePath);
const QList<Core::IEditor *> editors = Core::DocumentModel::editorsForFilePath(qmlProjectFilePath);
TextEditor::TextDocument *document = nullptr;
if (!editors.isEmpty()) {
document = qobject_cast<TextEditor::TextDocument*>(editors.first()->document());
if (document && document->isModified())
if (!Core::DocumentManager::saveDocument(document))
return false;
}
QString fileContent;
QString error;
Utils::TextFileFormat textFileFormat;
const QTextCodec *codec = QTextCodec::codecForName("UTF-8"); // qml files are defined to be utf-8
if (Utils::TextFileFormat::readFile(qmlProjectFilePath, codec, &fileContent, &textFileFormat, &error)
!= Utils::TextFileFormat::ReadSuccess) {
qWarning() << "Failed to read file" << qmlProjectFilePath << ":" << error;
}
// find the mainFile and do the file name with brackets in a capture group and mask the . with \.
QString originalFileName = oldFilePath.fileName();
originalFileName.replace(".", "\\.");
const QRegularExpression expression(QString("mainFile:\\s*\"(%1)\"").arg(originalFileName));
const QRegularExpressionMatch match = expression.match(fileContent);
fileContent.replace(match.capturedStart(1), match.capturedLength(1), newFilePath.fileName());
if (!textFileFormat.writeFile(qmlProjectFilePath, fileContent, &error))
qWarning() << "Failed to write file" << qmlProjectFilePath << ":" << error;
refresh(Everything);
}
return true; return true;
} }

View File

@@ -77,7 +77,13 @@ public:
Utils::FilePath canonicalProjectDir() const; Utils::FilePath canonicalProjectDir() const;
QString mainFile() const; QString mainFile() const;
QString mainUiFile() const;
Utils::FilePath mainFilePath() const; Utils::FilePath mainFilePath() const;
Utils::FilePath mainUiFilePath() const;
bool setMainFileInProjectFile(const Utils::FilePath &newMainFilePath);
bool setMainUiFileInProjectFile(const Utils::FilePath &newMainUiFilePath);
bool setMainUiFileInMainFile(const Utils::FilePath &newMainUiFilePath);
bool qtForMCUs() const; bool qtForMCUs() const;
bool qt6Project() const; bool qt6Project() const;
@@ -116,6 +122,10 @@ public:
void parseProject(RefreshOptions options); void parseProject(RefreshOptions options);
private: private:
bool setFileSettingInProjectFile(const QString &setting,
const Utils::FilePath &mainFilePath,
const QString &oldFile);
std::unique_ptr<QmlProjectItem> m_projectItem; std::unique_ptr<QmlProjectItem> m_projectItem;
Utils::FilePath m_canonicalProjectDir; Utils::FilePath m_canonicalProjectDir;
bool m_blockFilesUpdate = false; bool m_blockFilesUpdate = false;

View File

@@ -30,16 +30,23 @@
#include "qmlprojectrunconfiguration.h" #include "qmlprojectrunconfiguration.h"
#include "projectfilecontenttools.h" #include "projectfilecontenttools.h"
#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/coreconstants.h> #include <coreplugin/coreconstants.h>
#include <coreplugin/designmode.h> #include <coreplugin/designmode.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/fileiconprovider.h> #include <coreplugin/fileiconprovider.h>
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <coreplugin/messagebox.h> #include <coreplugin/messagebox.h>
#include <coreplugin/modemanager.h> #include <coreplugin/modemanager.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/projectmanager.h> #include <projectexplorer/projectmanager.h>
#include <projectexplorer/projectnodes.h>
#include <projectexplorer/projecttree.h>
#include <projectexplorer/runcontrol.h> #include <projectexplorer/runcontrol.h>
#include <projectexplorer/session.h> #include <projectexplorer/session.h>
#include <projectexplorer/target.h>
#include <qmljs/qmljsmodelmanagerinterface.h> #include <qmljs/qmljsmodelmanagerinterface.h>
@@ -54,11 +61,12 @@
#include <utils/fileutils.h> #include <utils/fileutils.h>
#include <utils/qtcprocess.h> #include <utils/qtcprocess.h>
#include <QAction>
#include <QDesktopServices> #include <QDesktopServices>
#include <QMessageBox> #include <QMessageBox>
#include <QPointer>
#include <QPushButton> #include <QPushButton>
#include <QTimer> #include <QTimer>
#include <QPointer>
using namespace ProjectExplorer; using namespace ProjectExplorer;
@@ -230,19 +238,124 @@ void QmlProjectPlugin::openInQDSWithProject(const Utils::FilePath &filePath)
} }
} }
static QmlBuildSystem *qmlBuildSystemforFileNode(const FileNode *fileNode)
{
if (!fileNode)
return nullptr;
if (QmlProject *qmlProject = qobject_cast<QmlProject*>(fileNode->getProject())) {
auto target = qmlProject->activeTarget();
if (!target)
return nullptr;
return qobject_cast<QmlProjectManager::QmlBuildSystem *>(target->buildSystem());
}
return nullptr;
}
bool QmlProjectPlugin::initialize(const QStringList &, QString *errorMessage) bool QmlProjectPlugin::initialize(const QStringList &, QString *errorMessage)
{ {
Q_UNUSED(errorMessage) Q_UNUSED(errorMessage)
d = new QmlProjectPluginPrivate; d = new QmlProjectPluginPrivate;
if (!qmlDesignerEnabled()) { if (!qmlDesignerEnabled())
initializeQmlLandingPage(); initializeQmlLandingPage();
}
ProjectManager::registerProjectType<QmlProject>(QmlJSTools::Constants::QMLPROJECT_MIMETYPE); ProjectManager::registerProjectType<QmlProject>(QmlJSTools::Constants::QMLPROJECT_MIMETYPE);
Core::FileIconProvider::registerIconOverlayForSuffix(":/qmlproject/images/qmlproject.png", Core::FileIconProvider::registerIconOverlayForSuffix(":/qmlproject/images/qmlproject.png",
"qmlproject"); "qmlproject");
if (QmlProject::isQtDesignStudio()) {
Core::ActionContainer *menu = Core::ActionManager::actionContainer(
ProjectExplorer::Constants::M_FILECONTEXT);
QAction *mainfileAction = new QAction(tr("Set as main .qml file"), this);
mainfileAction->setEnabled(false);
connect(mainfileAction, &QAction::triggered, this, []() {
const Node *currentNode = ProjectTree::currentNode();
if (!currentNode || !currentNode->asFileNode()
|| currentNode->asFileNode()->fileType() != FileType::QML)
return;
const Utils::FilePath file = currentNode->filePath();
QmlBuildSystem *buildSystem = qmlBuildSystemforFileNode(currentNode->asFileNode());
if (buildSystem)
buildSystem->setMainFileInProjectFile(file);
});
menu->addAction(Core::ActionManager::registerAction(
mainfileAction,
"QmlProject.setMainFile",
Core::Context(ProjectExplorer::Constants::C_PROJECT_TREE)),
ProjectExplorer::Constants::G_FILE_OTHER);
mainfileAction->setVisible(false);
connect(ProjectTree::instance(),
&ProjectTree::currentNodeChanged,
mainfileAction,
[mainfileAction](Node *node) {
const FileNode *fileNode = node ? node->asFileNode() : nullptr;
const bool isVisible = fileNode && fileNode->fileType() == FileType::QML
&& fileNode->filePath().completeSuffix() == "qml";
mainfileAction->setVisible(isVisible);
if (!isVisible)
return;
QmlBuildSystem *buildSystem = qmlBuildSystemforFileNode(fileNode);
if (buildSystem)
mainfileAction->setEnabled(buildSystem->mainFilePath()
!= fileNode->filePath());
});
QAction *mainUifileAction = new QAction(tr("Set as main .ui.qml file"), this);
mainUifileAction->setEnabled(false);
connect(mainUifileAction, &QAction::triggered, this, []() {
const Node *currentNode = ProjectTree::currentNode();
if (!currentNode || !currentNode->asFileNode()
|| currentNode->asFileNode()->fileType() != FileType::QML)
return;
const Utils::FilePath file = currentNode->filePath();
QmlBuildSystem *buildSystem = qmlBuildSystemforFileNode(currentNode->asFileNode());
if (buildSystem)
buildSystem->setMainUiFileInProjectFile(file);
});
menu->addAction(Core::ActionManager::registerAction(
mainUifileAction,
"QmlProject.setMainUIFile",
Core::Context(ProjectExplorer::Constants::C_PROJECT_TREE)),
ProjectExplorer::Constants::G_FILE_OTHER);
mainUifileAction->setVisible(false);
connect(ProjectTree::instance(),
&ProjectTree::currentNodeChanged,
mainUifileAction,
[mainUifileAction](Node *node) {
const FileNode *fileNode = node ? node->asFileNode() : nullptr;
const bool isVisible = fileNode && fileNode->fileType() == FileType::QML
&& fileNode->filePath().completeSuffix() == "ui.qml";
mainUifileAction->setVisible(isVisible);
if (!isVisible)
return;
QmlBuildSystem *buildSystem = qmlBuildSystemforFileNode(fileNode);
if (buildSystem)
mainUifileAction->setEnabled(buildSystem->mainUiFilePath()
!= fileNode->filePath());
});
}
return true; return true;
} }

View File

@@ -196,17 +196,6 @@ void FileDownloader::probeUrl()
}); });
QNetworkReply::connect(reply, &QNetworkReply::finished, this, [this, reply]() { QNetworkReply::connect(reply, &QNetworkReply::finished, this, [this, reply]() {
QQmlData *data = QQmlData::get(this, false);
if (!data) {
qDebug() << Q_FUNC_INFO << "FileDownloader is nullptr.";
return;
}
if (QQmlData::wasDeleted(this)) {
qDebug() << Q_FUNC_INFO << "FileDownloader was deleted.";
return;
}
if (reply->error()) if (reply->error())
return; return;
@@ -383,7 +372,6 @@ void FileExtractor::extract()
Utils::Archive *archive = new Utils::Archive(m_sourceFile, m_targetPath); Utils::Archive *archive = new Utils::Archive(m_sourceFile, m_targetPath);
QTC_ASSERT(archive->isValid(), delete archive; return); QTC_ASSERT(archive->isValid(), delete archive; return);
archive->setParent(this);
m_timer.start(); m_timer.start();
qint64 bytesBefore = QStorageInfo(m_targetPath.toFileInfo().dir()).bytesAvailable(); qint64 bytesBefore = QStorageInfo(m_targetPath.toFileInfo().dir()).bytesAvailable();
@@ -423,7 +411,8 @@ void FileExtractor::extract()
emit detailedTextChanged(); emit detailedTextChanged();
}); });
QObject::connect(archive, &Utils::Archive::finished, this, [this](bool ret) { QObject::connect(archive, &Utils::Archive::finished, this, [this, archive](bool ret) {
delete archive;
m_finished = ret; m_finished = ret;
m_timer.stop(); m_timer.stop();
@@ -436,3 +425,76 @@ void FileExtractor::extract()
}); });
archive->unarchive(); archive->unarchive();
} }
static Utils::FilePath tempFilePath()
{
QStandardPaths::StandardLocation location = QStandardPaths::CacheLocation;
return Utils::FilePath::fromString(QStandardPaths::writableLocation(location))
.pathAppended("QtDesignStudio");
}
DataModelDownloader::DataModelDownloader(QObject * /* parent */)
{
auto fileInfo = targetFolder().toFileInfo();
m_birthTime = fileInfo.birthTime();
m_exists = fileInfo.exists();
}
void DataModelDownloader::start()
{
m_fileDownloader.setUrl(QUrl::fromUserInput(
"https://download.qt.io/learning/examples/qtdesignstudio/dataImports.zip"));
connect(&m_fileDownloader, &FileDownloader::availableChanged, this, [this]() {
m_available = m_fileDownloader.available();
emit availableChanged();
if (!m_available) {
qWarning() << m_fileDownloader.url() << "failed to download";
return;
}
if (!m_forceDownload && m_fileDownloader.lastModified() < m_birthTime)
return;
m_fileDownloader.start();
connect(&m_fileDownloader, &FileDownloader::finishedChanged, this, [this]() {
if (m_fileDownloader.finished()) {
const Utils::FilePath archiveFile = Utils::FilePath::fromString(
m_fileDownloader.tempFile());
QTC_ASSERT(Utils::Archive::supportsFile(archiveFile), return );
auto archive = new Utils::Archive(archiveFile, tempFilePath());
QTC_ASSERT(archive->isValid(), delete archive; return );
QObject::connect(archive, &Utils::Archive::finished, this, [this, archive](bool ret) {
QTC_CHECK(ret);
delete archive;
emit finished();
});
archive->unarchive();
}
});
});
}
bool DataModelDownloader::exists() const
{
return m_exists;
}
bool DataModelDownloader::available() const
{
return m_available;
}
Utils::FilePath DataModelDownloader::targetFolder() const
{
return Utils::FilePath::fromUserInput(tempFilePath().toString() + "/" + "dataImports");
}
void DataModelDownloader::setForceDownload(bool b)
{
m_forceDownload = b;
}

View File

@@ -154,5 +154,29 @@ private:
int m_progress = 0; int m_progress = 0;
QFile m_tempFile; QFile m_tempFile;
QDateTime m_lastModified; QDateTime m_lastModified;
bool m_available; bool m_available = false;
};
class DataModelDownloader : public QObject
{
Q_OBJECT
public:
explicit DataModelDownloader(QObject *parent = nullptr);
void start();
bool exists() const;
bool available() const;
Utils::FilePath targetFolder() const;
void setForceDownload(bool b);
signals:
void finished();
void availableChanged();
private:
FileDownloader m_fileDownloader;
QDateTime m_birthTime;
bool m_exists = false;
bool m_available = false;
bool m_forceDownload = false;
}; };

View File

@@ -447,6 +447,7 @@ public:
private: private:
QQuickWidget *m_modeWidget = nullptr; QQuickWidget *m_modeWidget = nullptr;
DataModelDownloader *m_dataModelDownloader = nullptr;
}; };
void StudioWelcomePlugin::closeSplashScreen() void StudioWelcomePlugin::closeSplashScreen()
@@ -596,6 +597,28 @@ WelcomeMode::WelcomeMode()
{ {
setDisplayName(tr("Welcome")); setDisplayName(tr("Welcome"));
const QString welcomePagePath = Core::ICore::resourcePath("qmldesigner/welcomepage").toString();
m_dataModelDownloader = new DataModelDownloader(this);
if (!m_dataModelDownloader->exists()) { //Fallback if data cannot be downloaded
Utils::FileUtils::copyRecursively(Utils::FilePath::fromUserInput(welcomePagePath
+ "/dataImports"),
m_dataModelDownloader->targetFolder());
m_dataModelDownloader->setForceDownload(true);
}
Utils::FilePath readme = Utils::FilePath::fromUserInput(welcomePagePath
+ "/dataImports/readme.txt");
if (!readme.exists()) // Only downloads contain the readme
m_dataModelDownloader->setForceDownload(true);
m_dataModelDownloader->start();
connect(m_dataModelDownloader, &DataModelDownloader::finished, this, [this](){
auto source = m_modeWidget->source();
m_modeWidget->engine()->clearComponentCache();
m_modeWidget->setSource(source);
});
const Utils::Icon FLAT({{":/studiowelcome/images/mode_welcome_mask.png", const Utils::Icon FLAT({{":/studiowelcome/images/mode_welcome_mask.png",
Utils::Theme::IconsBaseColor}}); Utils::Theme::IconsBaseColor}});
const Utils::Icon FLAT_ACTIVE({{":/studiowelcome/images/mode_welcome_mask.png", const Utils::Icon FLAT_ACTIVE({{":/studiowelcome/images/mode_welcome_mask.png",
@@ -640,8 +663,8 @@ WelcomeMode::WelcomeMode()
m_modeWidget->engine()->addImportPath(Core::ICore::resourcePath("qmldesigner/propertyEditorQmlSources/imports").toString()); m_modeWidget->engine()->addImportPath(Core::ICore::resourcePath("qmldesigner/propertyEditorQmlSources/imports").toString());
const QString welcomePagePath = Core::ICore::resourcePath("qmldesigner/welcomepage").toString();
m_modeWidget->engine()->addImportPath(welcomePagePath + "/imports"); m_modeWidget->engine()->addImportPath(welcomePagePath + "/imports");
m_modeWidget->engine()->addImportPath(m_dataModelDownloader->targetFolder().toString());
m_modeWidget->setSource(QUrl::fromLocalFile(welcomePagePath + "/main.qml")); m_modeWidget->setSource(QUrl::fromLocalFile(welcomePagePath + "/main.qml"));
QShortcut *updateShortcut = nullptr; QShortcut *updateShortcut = nullptr;

View File

@@ -4,29 +4,7 @@ Squish tests inside this folder have several prerequisites to get them running.
First - and most important - you have to own a valid Squish license. At least Squish 6.0 is required. First - and most important - you have to own a valid Squish license. At least Squish 6.0 is required.
Second - some of the test suites/test cases expect a build of Qt 4.8.7 to be available: Second - some of the test suites/test cases expect Qt versions to be installed in their default
[ this is optional and if Qt4 is not available some Qt5 will be tried to use instead ]
1. Download the source code from:
* Windows: https://download.qt.io/archive/qt/4.8/4.8.7/qt-everywhere-opensource-src-4.8.7.zip
* Other: https://download.qt.io/archive/qt/4.8/4.8.7/qt-everywhere-opensource-src-4.8.7.tar.gz
2. Extract the contents of the archive's directory qt-everywhere-opensource-src-4.8.7 to:
* Windows: C:\Qt\Qt4.8.7
* Other: $HOME/Qt4.8.7
3. Apply the changes from patch.txt next to this README.
4. In the directory you extracted the sources to, configure Qt:
* Windows (MSVC2013 32 bit):
.\configure.exe -opensource -developer-build -confirm-license -debug-and-release -nomake tests -nomake examples -nomake demos -no-webkit -no-phonon
* Linux (gcc < 6):
./configure -opensource -developer-build -confirm-license -debug-and-release -nomake tests -nomake examples -nomake demos -no-webkit -no-phonon
* macOS:
./configure -opensource -developer-build -confirm-license -debug-and-release -nomake tests -nomake examples -nomake demos -no-webkit -no-phonon -sdk <PATH_TO_INSTALLED_MACOSX_SDK>
5. Make:
* Windows (do not use jom):
nmake
* Other:
make -j<number of available cores>
Third - some of the test suites/test cases expect Qt versions to be installed in their default
locations. On Linux/macOS this is ~/Qt5.x.1 and on Windows this is C:\Qt\Qt5.x.1. It's easiest to locations. On Linux/macOS this is ~/Qt5.x.1 and on Windows this is C:\Qt\Qt5.x.1. It's easiest to
use installations of the official opensource Qt packages. Just install the Qt version for the use installations of the official opensource Qt packages. Just install the Qt version for the
respective toolchain with the components (if available): respective toolchain with the components (if available):
@@ -50,7 +28,7 @@ Qt 5.4.1 (gcc)
Qt 5.10.1 (MSVC2015, 32 bit) Qt 5.10.1 (MSVC2015, 32 bit)
Qt 5.14.1 (MSVC2017, 64 bit) Qt 5.14.1 (MSVC2017, 64 bit)
Fourth - you'll have to provide some additional repositories. Third - you'll have to provide some additional repositories.
These additional repositories are located inside ~/squish-data or C:\Users\<user>\squish-data (depending on the OS you're on). These additional repositories are located inside ~/squish-data or C:\Users\<user>\squish-data (depending on the OS you're on).
You can also just provide them inside a different folder and specify the folder with the environment variable SYSTEST_SRCPATH. You can also just provide them inside a different folder and specify the folder with the environment variable SYSTEST_SRCPATH.
This folder must contain the following: This folder must contain the following:
@@ -58,12 +36,12 @@ This folder must contain the following:
* a subfolder called 'creator-test-data' * a subfolder called 'creator-test-data'
* a speedcrunch 0.11 repository (or source copy) inside 'creator-test-data' named 'speedcrunch' * a speedcrunch 0.11 repository (or source copy) inside 'creator-test-data' named 'speedcrunch'
Fifth - you'll have to make sure that some needed tools are available (no matter on which OS you're on). Fourth - you'll have to make sure that some needed tools are available (no matter on which OS you're on).
* cmake 3.14 or newer * cmake 3.14 or newer
* wget or curl, capable of HTTPS * wget or curl, capable of HTTPS
Normally it should be okay to just install them as usual and add their executables' path(s) to the PATH variable. Normally it should be okay to just install them as usual and add their executables' path(s) to the PATH variable.
Sixth - Qt Creator must be built on a Qt without Qt WebEngine or Qt WebKit. Fifth - Qt Creator must be built on a Qt without Qt WebEngine or Qt WebKit.
On macOS make sure you are using the correct keyboard layout to avoid problems when using keyboard interaction. Tested and known to be On macOS make sure you are using the correct keyboard layout to avoid problems when using keyboard interaction. Tested and known to be
working would be 'U.S. International - PC', while pure 'U.S.' had problems. working would be 'U.S. International - PC', while pure 'U.S.' had problems.

View File

@@ -4,31 +4,6 @@
<qtcreator> <qtcreator>
<data> <data>
<variable>Profile.0</variable> <variable>Profile.0</variable>
<valuemap type="QVariantMap">
<value type="bool" key="PE.Profile.AutoDetected">false</value>
<valuemap type="QVariantMap" key="PE.Profile.Data">
<value type="QString" key="Android.GdbServer.Information"></value>
<value type="QString" key="Debugger.Information">{70e26273-2c0b-4534-bbc0-eb6ca670821a}</value>
<value type="QString" key="PE.Profile.Device">{7c5a3673-e300-4286-9666-0f86d3e3dc38}</value>
<value type="QByteArray" key="PE.Profile.DeviceType">GenericLinuxOsType</value>
<value type="QString" key="PE.Profile.SysRoot"></value>
<value type="QString" key="PE.Profile.ToolChain">ProjectExplorer.ToolChain.Gcc:{c3f59b87-6997-4bd8-8067-ee04dc536371}</value>
<valuemap type="QVariantMap" key="PE.Profile.ToolChains">
<value type="QByteArray" key="C">{461bb8dc-22ff-461f-82fe-ebe8b21b697f}</value>
<value type="QString" key="Cxx">ProjectExplorer.ToolChain.Gcc:{c3f59b87-6997-4bd8-8067-ee04dc536371}</value>
</valuemap>
<value type="QString" key="QtPM4.mkSpecInformation"></value>
<value type="int" key="QtSupport.QtInformation">2</value>
</valuemap>
<value type="QString" key="PE.Profile.Icon">:///DESKTOP///</value>
<value type="QString" key="PE.Profile.Id">{f16848fc-b615-43b5-b0cc-16a9f57fb573}</value>
<valuelist type="QVariantList" key="PE.Profile.MutableInfo"/>
<value type="QString" key="PE.Profile.Name">Embedded Linux</value>
<value type="bool" key="PE.Profile.SDK">false</value>
</valuemap>
</data>
<data>
<variable>Profile.1</variable>
<valuemap type="QVariantMap"> <valuemap type="QVariantMap">
<value type="bool" key="PE.Profile.AutoDetected">false</value> <value type="bool" key="PE.Profile.AutoDetected">false</value>
<value type="QString" key="PE.Profile.AutoDetectionSource"></value> <value type="QString" key="PE.Profile.AutoDetectionSource"></value>
@@ -55,32 +30,7 @@
</valuemap> </valuemap>
</data> </data>
<data> <data>
<variable>Profile.2</variable> <variable>Profile.1</variable>
<valuemap type="QVariantMap">
<value type="bool" key="PE.Profile.AutoDetected">false</value>
<valuemap type="QVariantMap" key="PE.Profile.Data">
<value type="QString" key="Android.GdbServer.Information"></value>
<value type="QString" key="Debugger.Information">{2f514661-b9f7-4f83-8822-a9a9d0699600}</value>
<value type="QString" key="PE.Profile.Device">Desktop Device</value>
<value type="QByteArray" key="PE.Profile.DeviceType">Desktop</value>
<value type="QString" key="PE.Profile.SysRoot"></value>
<value type="QString" key="PE.Profile.ToolChain">ProjectExplorer.ToolChain.Gcc:{c3f59b87-6997-4bd8-8067-ee04dc536371}</value>
<valuemap type="QVariantMap" key="PE.Profile.ToolChains">
<value type="QByteArray" key="C">{461bb8dc-22ff-461f-82fe-ebe8b21b697f}</value>
<value type="QString" key="Cxx">ProjectExplorer.ToolChain.Gcc:{c3f59b87-6997-4bd8-8067-ee04dc536371}</value>
</valuemap>
<value type="QString" key="QtPM4.mkSpecInformation"></value>
<value type="int" key="QtSupport.QtInformation">2</value>
</valuemap>
<value type="QString" key="PE.Profile.Icon">:///DESKTOP///</value>
<value type="QString" key="PE.Profile.Id">{1dcb5509-1670-470d-80a5-8a988f36e4e2}</value>
<valuelist type="QVariantList" key="PE.Profile.MutableInfo"/>
<value type="QString" key="PE.Profile.Name">Desktop 4.8.7 default</value>
<value type="bool" key="PE.Profile.SDK">false</value>
</valuemap>
</data>
<data>
<variable>Profile.3</variable>
<valuemap type="QVariantMap"> <valuemap type="QVariantMap">
<value type="bool" key="PE.Profile.AutoDetected">false</value> <value type="bool" key="PE.Profile.AutoDetected">false</value>
<value type="QString" key="PE.Profile.AutoDetectionSource"></value> <value type="QString" key="PE.Profile.AutoDetectionSource"></value>
@@ -108,7 +58,7 @@
</data> </data>
<data> <data>
<variable>Profile.Count</variable> <variable>Profile.Count</variable>
<value type="int">4</value> <value type="int">2</value>
</data> </data>
<data> <data>
<variable>Profile.Default</variable> <variable>Profile.Default</variable>

View File

@@ -4,16 +4,6 @@
<qtcreator> <qtcreator>
<data> <data>
<variable>QtVersion.0</variable> <variable>QtVersion.0</variable>
<valuemap type="QVariantMap">
<value type="int" key="Id">2</value>
<value type="QString" key="Name">Desktop Qt 4.8 for GCC</value>
<value type="QString" key="QMakePath">~/Qt4.8.7/bin/qmake</value>
<value type="QString" key="QtVersion.Type">Qt4ProjectManager.QtVersion.Desktop</value>
<value type="bool" key="isAutodetected">false</value>
</valuemap>
</data>
<data>
<variable>QtVersion.1</variable>
<valuemap type="QVariantMap"> <valuemap type="QVariantMap">
<value type="int" key="Id">9</value> <value type="int" key="Id">9</value>
<value type="QString" key="Name">Qt %{Qt:Version} (SQUISH_DEFAULT_COMPILER)</value> <value type="QString" key="Name">Qt %{Qt:Version} (SQUISH_DEFAULT_COMPILER)</value>
@@ -23,7 +13,7 @@
</valuemap> </valuemap>
</data> </data>
<data> <data>
<variable>QtVersion.2</variable> <variable>QtVersion.1</variable>
<valuemap type="QVariantMap"> <valuemap type="QVariantMap">
<value type="int" key="Id">11</value> <value type="int" key="Id">11</value>
<value type="QString" key="Name">Qt %{Qt:Version} (SQUISH_DEFAULT_COMPILER)</value> <value type="QString" key="Name">Qt %{Qt:Version} (SQUISH_DEFAULT_COMPILER)</value>

View File

@@ -4,52 +4,6 @@
<qtcreator> <qtcreator>
<data> <data>
<variable>Profile.0</variable> <variable>Profile.0</variable>
<valuemap type="QVariantMap">
<value type="bool" key="PE.Profile.AutoDetected">false</value>
<valuemap type="QVariantMap" key="PE.Profile.Data">
<value type="QString" key="Android.GdbServer.Information"></value>
<value type="QString" key="Debugger.Information">{70e26273-2c0b-4534-bbc0-eb6ca670821a}</value>
<value type="QString" key="PE.Profile.Device">{7c5a3673-e300-4286-9666-0f86d3e3dc38}</value>
<value type="QByteArray" key="PE.Profile.DeviceType">GenericLinuxOsType</value>
<value type="QString" key="PE.Profile.SysRoot"></value>
<value type="QString" key="PE.Profile.ToolChain">ProjectExplorer.ToolChain.Gcc:{c3f59b87-6997-4bd8-8067-ee04dc536371}</value>
<valuemap type="QVariantMap" key="PE.Profile.ToolChains">
<value type="QByteArray" key="C">{7bfd4fd4-e64a-417f-b10f-20602e1719d1}</value>
<value type="QString" key="Cxx">ProjectExplorer.ToolChain.Gcc:{c3f59b87-6997-4bd8-8067-ee04dc536371}</value>
</valuemap>
<value type="QString" key="QtPM4.mkSpecInformation"></value>
<value type="int" key="QtSupport.QtInformation">2</value>
</valuemap>
<value type="QString" key="PE.Profile.Icon">:///DESKTOP///</value>
<value type="QString" key="PE.Profile.Id">{f16848fc-b615-43b5-b0cc-16a9f57fb573}</value>
<valuelist type="QVariantList" key="PE.Profile.MutableInfo"/>
<value type="QString" key="PE.Profile.Name">Embedded Linux</value>
<value type="bool" key="PE.Profile.SDK">false</value>
</valuemap>
</data>
<data>
<variable>Profile.1</variable>
<valuemap type="QVariantMap">
<value type="bool" key="PE.Profile.AutoDetected">false</value>
<valuemap type="QVariantMap" key="PE.Profile.Data">
<value type="QString" key="Android.GdbServer.Information"></value>
<value type="QString" key="Debugger.Information">{70e26273-2c0b-4534-bbc0-eb6ca670821a}</value>
<value type="QString" key="PE.Profile.Device">Desktop Device</value>
<value type="QByteArray" key="PE.Profile.DeviceType">Desktop</value>
<value type="QString" key="PE.Profile.SysRoot"></value>
<value type="QString" key="PE.Profile.ToolChain">ProjectExplorer.ToolChain.Gcc:{c3f59b87-6997-4bd8-8067-ee04dc536371}</value>
<value type="QString" key="QtPM4.mkSpecInformation"></value>
<value type="int" key="QtSupport.QtInformation">2</value>
</valuemap>
<value type="QString" key="PE.Profile.Icon">:///DESKTOP///</value>
<value type="QString" key="PE.Profile.Id">{1dcb5509-1670-470d-80a5-8a988f36e4e2}</value>
<valuelist type="QVariantList" key="PE.Profile.MutableInfo"/>
<value type="QString" key="PE.Profile.Name">Desktop 4.8.7 default</value>
<value type="bool" key="PE.Profile.SDK">false</value>
</valuemap>
</data>
<data>
<variable>Profile.2</variable>
<valuemap type="QVariantMap"> <valuemap type="QVariantMap">
<value type="bool" key="PE.Profile.AutoDetected">false</value> <value type="bool" key="PE.Profile.AutoDetected">false</value>
<value type="QString" key="PE.Profile.AutoDetectionSource"></value> <value type="QString" key="PE.Profile.AutoDetectionSource"></value>
@@ -73,7 +27,7 @@
</valuemap> </valuemap>
</data> </data>
<data> <data>
<variable>Profile.3</variable> <variable>Profile.1</variable>
<valuemap type="QVariantMap"> <valuemap type="QVariantMap">
<value type="bool" key="PE.Profile.AutoDetected">false</value> <value type="bool" key="PE.Profile.AutoDetected">false</value>
<value type="QString" key="PE.Profile.AutoDetectionSource"></value> <value type="QString" key="PE.Profile.AutoDetectionSource"></value>
@@ -97,7 +51,7 @@
</valuemap> </valuemap>
</data> </data>
<data> <data>
<variable>Profile.4</variable> <variable>Profile.2</variable>
<valuemap type="QVariantMap"> <valuemap type="QVariantMap">
<value type="bool" key="PE.Profile.AutoDetected">false</value> <value type="bool" key="PE.Profile.AutoDetected">false</value>
<value type="QString" key="PE.Profile.AutoDetectionSource"></value> <value type="QString" key="PE.Profile.AutoDetectionSource"></value>
@@ -126,7 +80,7 @@
</data> </data>
<data> <data>
<variable>Profile.Count</variable> <variable>Profile.Count</variable>
<value type="int">5</value> <value type="int">3</value>
</data> </data>
<data> <data>
<variable>Profile.Default</variable> <variable>Profile.Default</variable>

View File

@@ -4,16 +4,6 @@
<qtcreator> <qtcreator>
<data> <data>
<variable>QtVersion.0</variable> <variable>QtVersion.0</variable>
<valuemap type="QVariantMap">
<value type="int" key="Id">2</value>
<value type="QString" key="Name">Desktop Qt 4.8 for GCC</value>
<value type="QString" key="QMakePath">~/Qt4.8.7/bin/qmake</value>
<value type="QString" key="QtVersion.Type">Qt4ProjectManager.QtVersion.Desktop</value>
<value type="bool" key="isAutodetected">false</value>
</valuemap>
</data>
<data>
<variable>QtVersion.1</variable>
<valuemap type="QVariantMap"> <valuemap type="QVariantMap">
<value type="int" key="Id">13</value> <value type="int" key="Id">13</value>
<value type="QString" key="Name">Qt %{Qt:Version} (SQUISH_DEFAULT_COMPILER)</value> <value type="QString" key="Name">Qt %{Qt:Version} (SQUISH_DEFAULT_COMPILER)</value>
@@ -23,7 +13,7 @@
</valuemap> </valuemap>
</data> </data>
<data> <data>
<variable>QtVersion.2</variable> <variable>QtVersion.1</variable>
<valuemap type="QVariantMap"> <valuemap type="QVariantMap">
<value type="int" key="Id">15</value> <value type="int" key="Id">15</value>
<value type="QString" key="Name">Qt %{Qt:Version} (SQUISH_DEFAULT_COMPILER)</value> <value type="QString" key="Name">Qt %{Qt:Version} (SQUISH_DEFAULT_COMPILER)</value>
@@ -33,7 +23,7 @@
</valuemap> </valuemap>
</data> </data>
<data> <data>
<variable>QtVersion.3</variable> <variable>QtVersion.2</variable>
<valuemap type="QVariantMap"> <valuemap type="QVariantMap">
<value type="int" key="Id">17</value> <value type="int" key="Id">17</value>
<value type="QString" key="Name">Qt %{Qt:Version} (SQUISH_DEFAULT_COMPILER)</value> <value type="QString" key="Name">Qt %{Qt:Version} (SQUISH_DEFAULT_COMPILER)</value>

View File

@@ -4,34 +4,6 @@
<qtcreator> <qtcreator>
<data> <data>
<variable>Profile.0</variable> <variable>Profile.0</variable>
<valuemap type="QVariantMap">
<value type="bool" key="PE.Profile.AutoDetected">false</value>
<value type="QString" key="PE.Profile.AutoDetectionSource"></value>
<valuemap type="QVariantMap" key="PE.Profile.Data">
<value type="QString" key="Android.GdbServer.Information"></value>
<value type="QString" key="Debugger.Information">{1b25f20a-d584-4fb7-85b3-74dd15b82f6f}</value>
<value type="QString" key="PE.Profile.Device">Desktop Device</value>
<value type="QByteArray" key="PE.Profile.DeviceType">Desktop</value>
<valuelist type="QVariantList" key="PE.Profile.Environment"/>
<value type="QString" key="PE.Profile.SysRoot"></value>
<value type="QString" key="PE.Profile.ToolChain">{7ca0887f-a9a5-4251-aba6-560a15595d20}</value>
<valuemap type="QVariantMap" key="PE.Profile.ToolChains">
<value type="QByteArray" key="C">{d35e7a1a-5ab8-4fd6-8a2c-634846c669bb}</value>
<value type="QString" key="Cxx">{7ca0887f-a9a5-4251-aba6-560a15595d20}</value>
</valuemap>
<value type="QString" key="QtPM4.mkSpecInformation"></value>
<value type="int" key="QtSupport.QtInformation">2</value>
</valuemap>
<value type="QString" key="PE.Profile.Icon">:///DESKTOP///</value>
<value type="QString" key="PE.Profile.Id">{9b35bbe6-25a7-4cce-ba07-487c795f5265}</value>
<valuelist type="QVariantList" key="PE.Profile.MutableInfo"/>
<value type="QString" key="PE.Profile.Name">Desktop 4.8.7 default</value>
<value type="bool" key="PE.Profile.SDK">false</value>
<valuelist type="QVariantList" key="PE.Profile.StickyInfo"/>
</valuemap>
</data>
<data>
<variable>Profile.1</variable>
<valuemap type="QVariantMap"> <valuemap type="QVariantMap">
<value type="bool" key="PE.Profile.AutoDetected">false</value> <value type="bool" key="PE.Profile.AutoDetected">false</value>
<value type="QString" key="PE.Profile.AutoDetectionSource"></value> <value type="QString" key="PE.Profile.AutoDetectionSource"></value>
@@ -59,7 +31,7 @@
</valuemap> </valuemap>
</data> </data>
<data> <data>
<variable>Profile.2</variable> <variable>Profile.1</variable>
<valuemap type="QVariantMap"> <valuemap type="QVariantMap">
<value type="bool" key="PE.Profile.AutoDetected">false</value> <value type="bool" key="PE.Profile.AutoDetected">false</value>
<value type="QString" key="PE.Profile.AutoDetectionSource"></value> <value type="QString" key="PE.Profile.AutoDetectionSource"></value>
@@ -70,8 +42,7 @@
<value type="QByteArray" key="PE.Profile.DeviceType">Desktop</value> <value type="QByteArray" key="PE.Profile.DeviceType">Desktop</value>
<valuelist type="QVariantList" key="PE.Profile.Environment"/> <valuelist type="QVariantList" key="PE.Profile.Environment"/>
<value type="QString" key="PE.Profile.SysRoot"></value> <value type="QString" key="PE.Profile.SysRoot"></value>
<value type="QString" key="PE.Profile.ToolChain">{7ca0887f-a9a5-4251-aba6-560a15595d20}</value> <valuemap type="QVariantMap" key="PE.Profile.ToolChainsV3">
<valuemap type="QVariantMap" key="PE.Profile.ToolChains">
<value type="QByteArray" key="C">{ce3a8004-e9ae-46f2-b62d-d7daf69435ca}</value> <value type="QByteArray" key="C">{ce3a8004-e9ae-46f2-b62d-d7daf69435ca}</value>
<value type="QByteArray" key="Cxx">{3df7c776-a480-4a04-9099-6c75adac2dca}</value> <value type="QByteArray" key="Cxx">{3df7c776-a480-4a04-9099-6c75adac2dca}</value>
</valuemap> </valuemap>
@@ -87,7 +58,7 @@
</valuemap> </valuemap>
</data> </data>
<data> <data>
<variable>Profile.3</variable> <variable>Profile.2</variable>
<valuemap type="QVariantMap"> <valuemap type="QVariantMap">
<value type="bool" key="PE.Profile.AutoDetected">false</value> <value type="bool" key="PE.Profile.AutoDetected">false</value>
<value type="QString" key="PE.Profile.AutoDetectionSource"></value> <value type="QString" key="PE.Profile.AutoDetectionSource"></value>
@@ -116,7 +87,7 @@
</data> </data>
<data> <data>
<variable>Profile.Count</variable> <variable>Profile.Count</variable>
<value type="int">4</value> <value type="int">3</value>
</data> </data>
<data> <data>
<variable>Profile.Default</variable> <variable>Profile.Default</variable>

View File

@@ -4,16 +4,6 @@
<qtcreator> <qtcreator>
<data> <data>
<variable>QtVersion.0</variable> <variable>QtVersion.0</variable>
<valuemap type="QVariantMap">
<value type="int" key="Id">2</value>
<value type="QString" key="Name">Qt 4.8 for Desktop - MSVC2013</value>
<value type="QString" key="QMakePath">C:/Qt/Qt4.8.7/bin/qmake.exe</value>
<value type="QString" key="QtVersion.Type">Qt4ProjectManager.QtVersion.Desktop</value>
<value type="bool" key="isAutodetected">false</value>
</valuemap>
</data>
<data>
<variable>QtVersion.1</variable>
<valuemap type="QVariantMap"> <valuemap type="QVariantMap">
<value type="int" key="Id">22</value> <value type="int" key="Id">22</value>
<value type="QString" key="Name">Qt %{Qt:Version} (mingw491_32)</value> <value type="QString" key="Name">Qt %{Qt:Version} (mingw491_32)</value>
@@ -23,7 +13,7 @@
</valuemap> </valuemap>
</data> </data>
<data> <data>
<variable>QtVersion.2</variable> <variable>QtVersion.1</variable>
<valuemap type="QVariantMap"> <valuemap type="QVariantMap">
<value type="int" key="Id">24</value> <value type="int" key="Id">24</value>
<value type="QString" key="Name">Qt %{Qt:Version} (msvc2017_64)</value> <value type="QString" key="Name">Qt %{Qt:Version} (msvc2017_64)</value>
@@ -33,7 +23,7 @@
</valuemap> </valuemap>
</data> </data>
<data> <data>
<variable>QtVersion.3</variable> <variable>QtVersion.2</variable>
<valuemap type="QVariantMap"> <valuemap type="QVariantMap">
<value type="int" key="Id">26</value> <value type="int" key="Id">26</value>
<value type="QString" key="Name">Qt %{Qt:Version} (msvc2015)</value> <value type="QString" key="Name">Qt %{Qt:Version} (msvc2015)</value>

View File

@@ -19,18 +19,6 @@
</data> </data>
<data> <data>
<variable>ToolChain.1</variable> <variable>ToolChain.1</variable>
<valuemap type="QVariantMap">
<value type="QString" key="ProjectExplorer.MsvcToolChain.SupportedAbi">x86-windows-msvc2013-pe-32bit</value>
<value type="QString" key="ProjectExplorer.MsvcToolChain.VarsBat">C:/Program Files (x86)/Microsoft Visual Studio 12.0/VC/vcvarsall.bat</value>
<value type="QString" key="ProjectExplorer.MsvcToolChain.VarsBatArg">x86</value>
<value type="bool" key="ProjectExplorer.ToolChain.Autodetect">true</value>
<value type="QString" key="ProjectExplorer.ToolChain.DisplayName">Microsoft Visual C++ Compiler 12.0 (x86)</value>
<value type="QString" key="ProjectExplorer.ToolChain.Id">ProjectExplorer.ToolChain.Msvc:{d35e7a1a-5ab8-4fd6-8a2c-634846c669bb}</value>
<value type="int" key="ProjectExplorer.ToolChain.Language">1</value>
</valuemap>
</data>
<data>
<variable>ToolChain.2</variable>
<valuemap type="QVariantMap"> <valuemap type="QVariantMap">
<value type="QString" key="ProjectExplorer.GccToolChain.OriginalTargetTriple">i686-w64-mingw32</value> <value type="QString" key="ProjectExplorer.GccToolChain.OriginalTargetTriple">i686-w64-mingw32</value>
<value type="QString" key="ProjectExplorer.GccToolChain.Path">C:/Qt/Qt5.4.1/Tools/mingw491_32/bin/gcc.exe</value> <value type="QString" key="ProjectExplorer.GccToolChain.Path">C:/Qt/Qt5.4.1/Tools/mingw491_32/bin/gcc.exe</value>
@@ -47,12 +35,18 @@
</valuemap> </valuemap>
</data> </data>
<data> <data>
<variable>ToolChain.3</variable> <variable>ToolChain.2</variable>
<valuemap type="QVariantMap"> <valuemap type="QVariantMap">
<value type="QString" key="ProjectExplorer.MsvcToolChain.SupportedAbi">x86-windows-msvc2017-pe-64bit</value> <value type="QString" key="ProjectExplorer.MsvcToolChain.SupportedAbi">x86-windows-msvc2017-pe-64bit</value>
<value type="QString" key="ProjectExplorer.MsvcToolChain.VarsBat">C:/Program Files (x86)/Microsoft Visual Studio/2017/Community/VC/Auxiliary/Build/vcvarsall.bat</value> <value type="QString" key="ProjectExplorer.MsvcToolChain.VarsBat">C:/Program Files (x86)/Microsoft Visual Studio/2017/Community/VC/Auxiliary/Build/vcvarsall.bat</value>
<value type="QString" key="ProjectExplorer.MsvcToolChain.VarsBatArg">amd64</value> <value type="QString" key="ProjectExplorer.MsvcToolChain.VarsBatArg">amd64</value>
<value type="bool" key="ProjectExplorer.ToolChain.Autodetect">false</value> <valuelist type="QVariantList" key="ProjectExplorer.MsvcToolChain.environmentModifications">
<valuelist type="QVariantList">
<value type="QString">PATH</value>
<value type="int">0</value>
<value type="QString">SQUISH_MSVC2017_PATH</value>
</valuelist>
</valuelist>
<value type="QString" key="ProjectExplorer.ToolChain.DisplayName">MSVC2017 (amd64)</value> <value type="QString" key="ProjectExplorer.ToolChain.DisplayName">MSVC2017 (amd64)</value>
<value type="QString" key="ProjectExplorer.ToolChain.Id">ProjectExplorer.ToolChain.Msvc:{ce3a8004-e9ae-46f2-b62d-d7daf69435ca}</value> <value type="QString" key="ProjectExplorer.ToolChain.Id">ProjectExplorer.ToolChain.Msvc:{ce3a8004-e9ae-46f2-b62d-d7daf69435ca}</value>
<value type="int" key="ProjectExplorer.ToolChain.Language">1</value> <value type="int" key="ProjectExplorer.ToolChain.Language">1</value>
@@ -60,7 +54,7 @@
</valuemap> </valuemap>
</data> </data>
<data> <data>
<variable>ToolChain.4</variable> <variable>ToolChain.3</variable>
<valuemap type="QVariantMap"> <valuemap type="QVariantMap">
<value type="QString" key="ProjectExplorer.MsvcToolChain.SupportedAbi">x86-windows-msvc2015-pe-32bit</value> <value type="QString" key="ProjectExplorer.MsvcToolChain.SupportedAbi">x86-windows-msvc2015-pe-32bit</value>
<value type="QString" key="ProjectExplorer.MsvcToolChain.VarsBat">C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/vcvarsall.bat</value> <value type="QString" key="ProjectExplorer.MsvcToolChain.VarsBat">C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/vcvarsall.bat</value>
@@ -73,7 +67,7 @@
</valuemap> </valuemap>
</data> </data>
<data> <data>
<variable>ToolChain.5</variable> <variable>ToolChain.4</variable>
<valuemap type="QVariantMap"> <valuemap type="QVariantMap">
<value type="QString" key="ProjectExplorer.MsvcToolChain.SupportedAbi">x86-windows-msvc2015-pe-32bit</value> <value type="QString" key="ProjectExplorer.MsvcToolChain.SupportedAbi">x86-windows-msvc2015-pe-32bit</value>
<value type="QString" key="ProjectExplorer.MsvcToolChain.VarsBat">C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/vcvarsall.bat</value> <value type="QString" key="ProjectExplorer.MsvcToolChain.VarsBat">C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/vcvarsall.bat</value>
@@ -86,23 +80,18 @@
</valuemap> </valuemap>
</data> </data>
<data> <data>
<variable>ToolChain.6</variable> <variable>ToolChain.5</variable>
<valuemap type="QVariantMap">
<value type="QString" key="ProjectExplorer.MsvcToolChain.SupportedAbi">x86-windows-msvc2013-pe-32bit</value>
<value type="QString" key="ProjectExplorer.MsvcToolChain.VarsBat">C:/Program Files (x86)/Microsoft Visual Studio 12.0/VC/vcvarsall.bat</value>
<value type="QString" key="ProjectExplorer.MsvcToolChain.VarsBatArg">x86</value>
<value type="bool" key="ProjectExplorer.ToolChain.Autodetect">true</value>
<value type="QString" key="ProjectExplorer.ToolChain.DisplayName">Microsoft Visual C++ Compiler 12.0 (x86)</value>
<value type="QString" key="ProjectExplorer.ToolChain.Id">ProjectExplorer.ToolChain.Msvc:{7ca0887f-a9a5-4251-aba6-560a15595d20}</value>
</valuemap>
</data>
<data>
<variable>ToolChain.7</variable>
<valuemap type="QVariantMap"> <valuemap type="QVariantMap">
<value type="QString" key="ProjectExplorer.MsvcToolChain.SupportedAbi">x86-windows-msvc2017-pe-64bit</value> <value type="QString" key="ProjectExplorer.MsvcToolChain.SupportedAbi">x86-windows-msvc2017-pe-64bit</value>
<value type="QString" key="ProjectExplorer.MsvcToolChain.VarsBat">C:/Program Files (x86)/Microsoft Visual Studio/2017/Community/VC/Auxiliary/Build/vcvarsall.bat</value> <value type="QString" key="ProjectExplorer.MsvcToolChain.VarsBat">C:/Program Files (x86)/Microsoft Visual Studio/2017/Community/VC/Auxiliary/Build/vcvarsall.bat</value>
<value type="QString" key="ProjectExplorer.MsvcToolChain.VarsBatArg">amd64</value> <value type="QString" key="ProjectExplorer.MsvcToolChain.VarsBatArg">amd64</value>
<value type="bool" key="ProjectExplorer.ToolChain.Autodetect">false</value> <valuelist type="QVariantList" key="ProjectExplorer.MsvcToolChain.environmentModifications">
<valuelist type="QVariantList">
<value type="QString">PATH</value>
<value type="int">0</value>
<value type="QString">SQUISH_MSVC2017_PATH</value>
</valuelist>
</valuelist>
<value type="QString" key="ProjectExplorer.ToolChain.DisplayName">MSVC2017 (amd64)</value> <value type="QString" key="ProjectExplorer.ToolChain.DisplayName">MSVC2017 (amd64)</value>
<value type="QString" key="ProjectExplorer.ToolChain.Id">ProjectExplorer.ToolChain.Msvc:{3df7c776-a480-4a04-9099-6c75adac2dca}</value> <value type="QString" key="ProjectExplorer.ToolChain.Id">ProjectExplorer.ToolChain.Msvc:{3df7c776-a480-4a04-9099-6c75adac2dca}</value>
<value type="int" key="ProjectExplorer.ToolChain.Language">2</value> <value type="int" key="ProjectExplorer.ToolChain.Language">2</value>
@@ -111,7 +100,7 @@
</data> </data>
<data> <data>
<variable>ToolChain.Count</variable> <variable>ToolChain.Count</variable>
<value type="int">8</value> <value type="int">6</value>
</data> </data>
<data> <data>
<variable>Version</variable> <variable>Version</variable>

View File

@@ -190,7 +190,6 @@ def verifyBuildConfig(currentTarget, configName, shouldBeDebug=False, enableShad
# it will wait here until compilation of the debug libraries has finished. # it will wait here until compilation of the debug libraries has finished.
runCMakeButton = ("{type='QPushButton' text='Run CMake' unnamed='1' " runCMakeButton = ("{type='QPushButton' text='Run CMake' unnamed='1' "
"window=':Qt Creator_Core::Internal::MainWindow'}") "window=':Qt Creator_Core::Internal::MainWindow'}")
if currentTarget not in (Targets.DESKTOP_4_8_7_DEFAULT, Targets.EMBEDDED_LINUX):
qmlDebuggingCombo = findObject(':Qt Creator.QML debugging and profiling:_QComboBox') qmlDebuggingCombo = findObject(':Qt Creator.QML debugging and profiling:_QComboBox')
if selectFromCombo(qmlDebuggingCombo, 'Enable'): if selectFromCombo(qmlDebuggingCombo, 'Enable'):
if buildSystem is None or buildSystem == "CMake": # re-run cmake to apply if buildSystem is None or buildSystem == "CMake": # re-run cmake to apply
@@ -205,7 +204,6 @@ def verifyBuildConfig(currentTarget, configName, shouldBeDebug=False, enableShad
except: except:
pass pass
else: else:
if currentTarget not in (Targets.DESKTOP_4_8_7_DEFAULT, Targets.EMBEDDED_LINUX):
qmlDebuggingCombo = findObject(':Qt Creator.QML debugging and profiling:_QComboBox') qmlDebuggingCombo = findObject(':Qt Creator.QML debugging and profiling:_QComboBox')
if selectFromCombo(qmlDebuggingCombo, "Disable"): if selectFromCombo(qmlDebuggingCombo, "Disable"):
test.log("Qml debugging libraries are available - unchecked qml debugging.") test.log("Qml debugging libraries are available - unchecked qml debugging.")

View File

@@ -30,37 +30,27 @@ except ImportError:
# for easier re-usage (because Python hasn't an enum type) # for easier re-usage (because Python hasn't an enum type)
class Targets: class Targets:
ALL_TARGETS = tuple(range(5)) ALL_TARGETS = tuple(range(3))
(DESKTOP_4_8_7_DEFAULT, (DESKTOP_5_4_1_GCC,
EMBEDDED_LINUX,
DESKTOP_5_4_1_GCC,
DESKTOP_5_10_1_DEFAULT, DESKTOP_5_10_1_DEFAULT,
DESKTOP_5_14_1_DEFAULT) = ALL_TARGETS DESKTOP_5_14_1_DEFAULT) = ALL_TARGETS
__TARGET_NAME_DICT__ = dict(zip(ALL_TARGETS, __TARGET_NAME_DICT__ = dict(zip(ALL_TARGETS,
["Desktop 4.8.7 default", ["Desktop 5.4.1 GCC",
"Embedded Linux",
"Desktop 5.4.1 GCC",
"Desktop 5.10.1 default", "Desktop 5.10.1 default",
"Desktop 5.14.1 default"])) "Desktop 5.14.1 default"]))
@staticmethod @staticmethod
def availableTargetClasses(ignoreValidity=False): def availableTargetClasses(ignoreValidity=False):
availableTargets = set(Targets.ALL_TARGETS) availableTargets = set(Targets.ALL_TARGETS)
if not qt4Available and not ignoreValidity: if platform.system() == 'Darwin':
availableTargets.remove(Targets.DESKTOP_4_8_7_DEFAULT)
if not (qt4Available or ignoreValidity) or platform.system() in ('Windows', 'Microsoft'):
availableTargets.remove(Targets.EMBEDDED_LINUX)
elif platform.system() == 'Darwin':
availableTargets.remove(Targets.DESKTOP_5_4_1_GCC) availableTargets.remove(Targets.DESKTOP_5_4_1_GCC)
return availableTargets return availableTargets
@staticmethod @staticmethod
def desktopTargetClasses(): def desktopTargetClasses():
desktopTargets = Targets.availableTargetClasses() return Targets.availableTargetClasses()
desktopTargets.discard(Targets.EMBEDDED_LINUX)
return desktopTargets
@staticmethod @staticmethod
def getStringForTarget(target): def getStringForTarget(target):

View File

@@ -161,11 +161,8 @@ def __createProjectHandleQtQuickSelection__(minimumQtVersion):
# param buildSystem is a string holding the build system selected for the project # param buildSystem is a string holding the build system selected for the project
# param checks turns tests in the function on if set to True # param checks turns tests in the function on if set to True
# param available a list holding the available targets # param available a list holding the available targets
# withoutQt4 if True Qt4 will get unchecked / not selected while checking the targets def __selectQtVersionDesktop__(buildSystem, checks, available=None):
def __selectQtVersionDesktop__(buildSystem, checks, available=None, withoutQt4=False):
wanted = Targets.desktopTargetClasses() wanted = Targets.desktopTargetClasses()
if withoutQt4:
wanted.discard(Targets.DESKTOP_4_8_7_DEFAULT)
checkedTargets = __chooseTargets__(wanted, available) checkedTargets = __chooseTargets__(wanted, available)
if checks: if checks:
for target in checkedTargets: for target in checkedTargets:
@@ -183,8 +180,7 @@ def __selectQtVersionDesktop__(buildSystem, checks, available=None, withoutQt4=F
objectMap.realName(detailsWidget))) objectMap.realName(detailsWidget)))
verifyChecked(cbObject % ("Minimum Size Release", verifyChecked(cbObject % ("Minimum Size Release",
objectMap.realName(detailsWidget))) objectMap.realName(detailsWidget)))
elif (buildSystem == "qmake" elif buildSystem == "qmake":
and target not in (Targets.DESKTOP_4_8_7_DEFAULT, Targets.EMBEDDED_LINUX)):
verifyChecked(cbObject % ("Profile", objectMap.realName(detailsWidget))) verifyChecked(cbObject % ("Profile", objectMap.realName(detailsWidget)))
clickButton(detailsButton) clickButton(detailsButton)
clickButton(waitForObject(":Next_QPushButton")) clickButton(waitForObject(":Next_QPushButton"))
@@ -207,11 +203,6 @@ def __verifyFileCreation__(path, expectedFiles):
def __modifyAvailableTargets__(available, requiredQt, asStrings=False): def __modifyAvailableTargets__(available, requiredQt, asStrings=False):
versionFinder = re.compile("^Desktop (\\d{1}\.\\d{1,2}\.\\d{1,2}).*$") versionFinder = re.compile("^Desktop (\\d{1}\.\\d{1,2}\.\\d{1,2}).*$")
tmp = list(available) # we need a deep copy tmp = list(available) # we need a deep copy
if Qt5Path.toVersionTuple(requiredQt) > (4,8,7) and qt4Available:
toBeRemoved = Targets.EMBEDDED_LINUX
if asStrings:
toBeRemoved = Targets.getStringForTarget(toBeRemoved)
available.discard(toBeRemoved)
for currentItem in tmp: for currentItem in tmp:
if asStrings: if asStrings:
item = currentItem item = currentItem
@@ -260,7 +251,7 @@ def createProject_Qt_GUI(path, projectName, checks=True, addToVersionControl="<N
clickButton(waitForObject(":Next_QPushButton")) clickButton(waitForObject(":Next_QPushButton"))
__createProjectHandleTranslationSelection__() __createProjectHandleTranslationSelection__()
__selectQtVersionDesktop__(buildSystem, checks, available, True) __selectQtVersionDesktop__(buildSystem, checks, available)
expectedFiles = [] expectedFiles = []
if checks: if checks:
@@ -540,12 +531,6 @@ def __getSupportedPlatforms__(text, templateName, getAsStrings=False, ignoreVali
supports = text[text.find('Supported Platforms'):].split(":")[1].strip().split("\n") supports = text[text.find('Supported Platforms'):].split(":")[1].strip().split("\n")
result = set() result = set()
if 'Desktop' in supports: if 'Desktop' in supports:
if (version == None or version < "5.0") and not templateName.startswith("Qt Quick"):
neverIgnoreValidity = templateName in ("Qt Custom Designer Widget", "Code Snippet", "Subdirs Project")
if qt4Available or ignoreValidity and not neverIgnoreValidity:
result.add(Targets.DESKTOP_4_8_7_DEFAULT)
if platform.system() in ("Linux", "Darwin"):
result.add(Targets.EMBEDDED_LINUX)
result = result.union(set([Targets.DESKTOP_5_10_1_DEFAULT, Targets.DESKTOP_5_14_1_DEFAULT])) result = result.union(set([Targets.DESKTOP_5_10_1_DEFAULT, Targets.DESKTOP_5_14_1_DEFAULT]))
if platform.system() != 'Darwin': if platform.system() != 'Darwin':
result.add(Targets.DESKTOP_5_4_1_GCC) result.add(Targets.DESKTOP_5_4_1_GCC)

View File

@@ -40,12 +40,6 @@ except ImportError:
import builtins as __builtin__ # Python 3 import builtins as __builtin__ # Python 3
# ensure global variables are defined before including shared scripts
qt4Path = os.path.expanduser("~/Qt4.8.7")
if platform.system() in ('Windows', 'Microsoft'):
qt4Path = "C:\\Qt\\Qt4.8.7"
qt4Available = os.path.exists(qt4Path)
srcPath = '' srcPath = ''
SettingsPath = [] SettingsPath = []
tmpSettingsDir = '' tmpSettingsDir = ''
@@ -237,6 +231,23 @@ def substituteCdb(settingsDir):
__substitute__(debuggers, "SQUISH_DEBUGGER_BITNESS", bitness) __substitute__(debuggers, "SQUISH_DEBUGGER_BITNESS", bitness)
test.log("Injected architecture '%s' and bitness '%s' in cdb path..." % (architecture, bitness)) test.log("Injected architecture '%s' and bitness '%s' in cdb path..." % (architecture, bitness))
def substituteMsvcPaths(settingsDir):
for msvcFlavor in ["Community", "BuildTools"]:
try:
msvc2017Path = os.path.join("C:\\Program Files (x86)", "Microsoft Visual Studio",
"2017", msvcFlavor, "VC", "Tools", "MSVC")
msvc2017Path = os.path.join(msvc2017Path, os.listdir(msvc2017Path)[0], "bin",
"HostX64", "x64")
__substitute__(os.path.join(settingsDir, "QtProject", 'qtcreator', 'toolchains.xml'),
"SQUISH_MSVC2017_PATH", msvc2017Path)
return
except:
continue
test.warning("PATH variable for MSVC2017 could not be set, some tests will fail.",
"Please make sure that MSVC2017 is installed correctly.")
def __guessABI__(supportedABIs, use64Bit): def __guessABI__(supportedABIs, use64Bit):
if platform.system() == 'Linux': if platform.system() == 'Linux':
supportedABIs = filter(lambda x: 'linux' in x, supportedABIs) supportedABIs = filter(lambda x: 'linux' in x, supportedABIs)
@@ -331,6 +342,7 @@ def copySettingsToTmpDir(destination=None, omitFiles=[]):
substituteDefaultCompiler(tmpSettingsDir) substituteDefaultCompiler(tmpSettingsDir)
elif platform.system() in ('Windows', 'Microsoft'): elif platform.system() in ('Windows', 'Microsoft'):
substituteCdb(tmpSettingsDir) substituteCdb(tmpSettingsDir)
substituteMsvcPaths(tmpSettingsDir)
substituteUnchosenTargetABIs(tmpSettingsDir) substituteUnchosenTargetABIs(tmpSettingsDir)
SettingsPath = ['-settingspath', '"%s"' % tmpSettingsDir] SettingsPath = ['-settingspath', '"%s"' % tmpSettingsDir]

View File

@@ -41,7 +41,6 @@ def main():
return return
# open example project, supports only Qt 5 # open example project, supports only Qt 5
targets = Targets.desktopTargetClasses() targets = Targets.desktopTargetClasses()
targets.discard(Targets.DESKTOP_4_8_7_DEFAULT)
targets.discard(Targets.DESKTOP_5_4_1_GCC) targets.discard(Targets.DESKTOP_5_4_1_GCC)
openQmakeProject(examplePath, targets) openQmakeProject(examplePath, targets)
# build and wait until finished - on all build configurations # build and wait until finished - on all build configurations

View File

@@ -47,7 +47,6 @@ def main():
if not startCreatorVerifyingClang(useClang): if not startCreatorVerifyingClang(useClang):
continue continue
createProject_Qt_Console(tempDir(), "SquishProject") createProject_Qt_Console(tempDir(), "SquishProject")
# by default Qt4 is selected, use a Qt5 kit instead
selectBuildConfig(Targets.DESKTOP_5_10_1_DEFAULT, "Debug") selectBuildConfig(Targets.DESKTOP_5_10_1_DEFAULT, "Debug")
checkCodeModelSettings(useClang) checkCodeModelSettings(useClang)
selectFromLocator("main.cpp") selectFromLocator("main.cpp")