Merge remote-tracking branch 'origin/7.0'

Conflicts:
	src/plugins/qmlprojectmanager/qmlprojectplugin.cpp

Change-Id: I14030f58303839e706af892dd12a67566e3bed68
This commit is contained in:
Eike Ziller
2022-05-18 13:07:59 +02:00
89 changed files with 2011 additions and 791 deletions

View File

@ -8,7 +8,7 @@ on:
env:
QT_VERSION: 6.2.3
CLANG_VERSION: 14.0.0
CLANG_VERSION: 14.0.3
ELFUTILS_VERSION: 0.175
CMAKE_VERSION: 3.21.1
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)
# Linux 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)
if(TARGET Crashpad::Crashpad)
set(BUILD_WITH_CRASHPAD ON)

View File

@ -57,25 +57,9 @@ find_path(CRASHPAD_GEN_DIR
"${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)
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)
@ -93,18 +77,16 @@ if(Crashpad_FOUND)
set_target_properties(Crashpad::Crashpad PROPERTIES
IMPORTED_LOCATION "${CRASHPAD_LIB_DIR}/client/client.lib")
elseif(APPLE)
find_library(FWbsm bsm)
find_library(FWAppKit AppKit)
find_library(FWIOKit IOKit)
find_library(FWSecurity Security)
target_link_libraries(Crashpad::Crashpad INTERFACE
"${CRASHPAD_LIB_DIR}/third_party/mini_chromium/mini_chromium/base/libbase.a"
"${CRASHPAD_LIB_DIR}/util/libutil.a"
"${CRASHPAD_LIB_DIR}/util/libmig_output.a"
"${CRASHPAD_LIB_DIR}/client/libclient.a"
"${CRASHPAD_OBJ_DIR}/mig_output.child_portServer.o"
"${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"
"${CRASHPAD_LIB_DIR}/client/libcommon.a"
${FWbsm} ${FWAppKit} ${FWIOKit} ${FWSecurity})
set_target_properties(Crashpad::Crashpad PROPERTIES
IMPORTED_LOCATION "${CRASHPAD_LIB_DIR}/client/libclient.a")

View File

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

View File

@ -7,7 +7,7 @@ instructions:
variableValue: "RelWithDebInfo"
- type: EnvironmentVariable
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
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
QML modules may use plugins to expose components defined in C++ to QML
applications. \QC cannot load the plugins to determine the details of
the contained components, and therefore, the modules must provide extra type
information for code completion and the semantic checks to work correctly.
\l{Defining a QML Module}{QML modules} may use \l{Creating C++ Plugins for QML}
{C++ plugins} to expose components defined in C++ to QML applications.
To create a QML module
To create a QML
\if defined(qtdesignstudio)
and make it appear in the \l Components view:
module and make it appear in the \l Components view:
\else
:
module:
\endif
\list 1
@ -97,26 +95,13 @@
\c .metainfo file is in place.
\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
Ideally, QML modules have a \c{plugins.qmltypes} file in the same directory
as the \c qmldir file. The \c qmltypes file contains a description of the
components exported by the module's plugins and is loaded by \QC when the
module is imported.
When \l{Defining QML Types from C++}{registering QML types}, make sure that
the QML module has a \c{plugins.qmltypes} file. Ideally, it should be located
in the same directory as the \c qmldir file. The \c qmltypes file contains a
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}.
@ -127,7 +112,6 @@
However, this automatic dumping is a fallback mechanism with many points of
failure and you cannot rely upon it.
\if defined(qtcreator)
\section1 Importing 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.
\else
\if defined(qtdesignstudio)
\section1 Running QML Modules in Design Mode
A QML emulation layer (also called QML Puppet) is used in the
@ -169,7 +153,7 @@
by an application or edited in the \uicontrol Design mode.
If you want to use a different module in the \uicontrol Design mode
than in your actual application for example to mockup C++ items,
than in your actual application for example to mockup C++ items,
you can use \c{QML_DESIGNER_IMPORT_PATH}
in the \c{.pro} file (for qmake projects), or declare and set the property
\c qmlDesignerImportPaths in your product (for Qbs projects).

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
You can use \QBF to export designs from Figma to \e {.metadata}
format that you can \l{Importing 2D Assets}{import} to projects in \QDS.
You can use \QBF to export designs from Figma to a \e {.qtbridge}
archive that you can \l{Importing 2D Assets}{import} to projects in \QDS.
\image studio-figma-export.png

View File

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

View File

@ -55,48 +55,47 @@
\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
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,
you can merge the changes into existing QML files without overwriting the
changes you have made in \QDS. For more information, see
\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
information about the options you have, see
\l {Creating Projects}.
To import assets exported in \QB to \QDS projects:
To import the exported assets to \QDS projects:
\list 1
\li Select \uicontrol File > \uicontrol {New Project} >
\uicontrol General > \uicontrol {Qt Quick Application - Empty} >
\uicontrol Choose, and follow the instructions of the wizard to
create an empty project.
\uicontrol General > \uicontrol {Empty}. Add \uicontrol {Details} about
the project and select \uicontrol Create.
\li In \uicontrol Projects, double-click \e Screen01.ui.qml to move to
the Design mode.
\li Select \uicontrol Assets > \inlineimage icons/plus.png
.
\li Select the folder where you exported the assets.
\li Select \uicontrol {Exported Assets (*.metadata)} in the dropdown
menu to filter \e .metadata files.
\li Select a \e .metadata file to import, and then select
\uicontrol Open.
\li Select \uicontrol {Compressed Metadata (*.qtbridge)} or
\uicontrol {Exported Metadata (*.metadata)} in the dropdown menu to
filter the exported files.
\li Select a the file to import and then select \uicontrol Open.
\li Select \uicontrol Details next to the
\uicontrol {Metadata Import Paths} field to display the path where
the metadata is imported from.
\image studio-import-metadata.png "Asset Import dialog"
\uicontrol {Import Paths} field to display the path where the exported
assets are imported from.
\image studio-asset-import.png "Asset Import dialog"
\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.
\li In the \uicontrol QML field, you can change the folder to copy the
QML files to.
\li In the \uicontrol Assets field, you can change the folder to copy
the image files to.
\li Select the \uicontrol {Create sub directory for each metadata}
check box to copy the directory structure from the metadata file
to \QDS.
\li Select the \uicontrol {Create sub directory} check box to import the
assets in a sub directory inside \uicontrol {Export Paths}.
\li Deselect the \uicontrol {Import assets} check box if you only want
to create QML files.
\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
assets before and want to merge the changes into existing 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
might take a little while for complex projects.
\endlist
The imported assets are displayed in \uicontrol Assets
as PNG images. The components that you specified in the design tool are
displayed in \uicontrol Components > \uicontrol {My Components} as well as
in the \uicontrol Projects view as separate QML files. To start using them,
The imported assets are displayed in \uicontrol Assets as images.
The components that you specified in the design tool are displayed in
\uicontrol Components > \uicontrol {My Components} as well as in the
\uicontrol Projects view as separate QML files. To use them,
drag-and-drop them from \uicontrol Components to \uicontrol {Form Editor} or
\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
\uicontrol {Asset Import} dialog while importing, fix the issues in
design tool and export the assets again.

View File

@ -263,32 +263,44 @@ def qdump__Utils__Environment(d, value):
qdump__Utils__NameValueDictionary(d, value)
def qdump__Utils__DictKey(d, value):
d.putStringValue(value["name"])
def qdump__Utils__NameValueDictionary(d, value):
dptr = d.extractPointer(value["m_values"])
(ref, n) = d.split('ii', dptr)
d.check(0 <= n and n <= 100 * 1000 * 1000)
d.check(-1 <= ref and ref < 100000)
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)
d.check(0 <= n and n <= 100 * 1000 * 1000)
d.check(-1 <= ref and ref < 100000)
d.putItemCount(n)
if d.isExpanded():
if n > 10000:
n = 10000
d.putItemCount(n)
if d.isExpanded():
if n > 10000:
n = 10000
typeCode = 'ppp@{%s}@{%s}' % ("Utils::DictKey", "QString")
typeCode = 'ppp@{%s}@{%s}' % ("Utils::DictKey", "@QPair<@QString,bool>")
def helper(node):
(p, left, right, padding1, key, padding2, value) = d.split(typeCode, node)
if left:
for res in helper(left):
yield res
yield (key["name"], value)
if right:
for res in helper(right):
yield res
def helper(node):
(p, left, right, padding1, key, padding2, value) = d.split(typeCode, node)
if left:
for res in helper(left):
yield res
yield (key["name"], value)
if right:
for res in helper(right):
yield res
with Children(d, n):
for (pair, i) in zip(helper(dptr + 8), range(n)):
d.putPairItem(i, pair, 'key', 'value')
with Children(d, n):
for (pair, i) in zip(helper(dptr + 8), range(n)):
d.putPairItem(i, pair, 'key', 'value')
def qdump__Utf8String(d, value):

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -59,9 +59,6 @@ Item {
var complexSuffixes = rootView.supportedAssetSuffixes(true);
for (const u of drag.urls) {
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()
if (simpleSuffixes.includes(ext))
root.dropSimpleExtFiles.push(url)

View File

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

View File

@ -92,7 +92,6 @@ StudioControls.ComboBox {
onValueFromBackendChanged: colorLogic.invalidate()
function invalidate() {
if (comboBox.block)
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: {
if (!comboBox.__isCompleted)
return

View File

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

View File

@ -29,7 +29,7 @@ import HelperWidgets 2.0
import StudioControls 1.0 as StudioControls
StudioControls.ComboBox {
id: comboBox
id: root
property variant backendValue
property color textColor: colorLogic.textColor
@ -39,17 +39,17 @@ StudioControls.ComboBox {
labelColor: colorLogic.textColor
editable: true
onTextColorChanged: setColor()
onTextColorChanged: root.setColor()
FileResourcesModel {
id: fileModel
modelNodeBackendProperty: modelNodeBackend
filter: comboBox.fontFilter
filter: root.fontFilter
}
function createFontLoader(fontUrl) {
return Qt.createQmlObject('import QtQuick 2.0; FontLoader { source: "' + fontUrl + '"; }',
comboBox, "dynamicFontLoader")
root, "dynamicFontLoader")
}
function setupModel() {
@ -63,80 +63,83 @@ StudioControls.ComboBox {
// Remove duplicate family names
familyNames = [...new Set(familyNames)]
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 {
id: extFuncLogic
backendValue: comboBox.backendValue
backendValue: root.backendValue
}
actionIndicator.icon.color: extFuncLogic.color
actionIndicator.icon.text: extFuncLogic.glyph
actionIndicator.onClicked: extFuncLogic.show()
actionIndicator.forceVisible: extFuncLogic.menuVisible
actionIndicator.visible: comboBox.showExtendedFunctionButton
actionIndicator.visible: root.showExtendedFunctionButton
ColorLogic {
id: colorLogic
property string textValue: comboBox.backendValue.valueToString
backendValue: comboBox.backendValue
onTextValueChanged: comboBox.editText = colorLogic.textValue
property string textValue: root.backendValue.valueToString
backendValue: root.backendValue
onTextValueChanged: root.editText = colorLogic.textValue
}
onAccepted: {
if (backendValue === undefined)
if (root.backendValue === undefined)
return
if (editText === "")
if (root.editText === "")
return
if (backendValue.value !== editText)
backendValue.value = editText;
if (root.backendValue.value !== root.editText)
root.backendValue.value = root.editText
}
onActivated: {
if (backendValue === undefined)
onCompressedActivated: function(index, reason) { root.handleActivate(index) }
function handleActivate(index)
{
if (root.backendValue === undefined)
return
if (editText === "")
if (root.editText === "")
return
var indexText = comboBox.textAt(index)
var indexText = root.textAt(index)
if (backendValue.value !== indexText)
backendValue.value = indexText
if (root.backendValue.value !== indexText)
root.backendValue.value = indexText
}
Connections {
target: modelNodeBackend
function onSelectionChanged() {
comboBox.editText = backendValue.value
setupModel()
root.editText = root.backendValue.value
root.setupModel()
}
}
Component.onCompleted: {
setupModel()
root.setupModel()
// 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
comboBox.children[i].anchors.rightMargin = 34
comboBox.children[i].anchors.leftMargin = 18
for (var i = 0; i < root.children.length; i++) {
if (root.children[i].text !== undefined) {
root.children[i].color = root.textColor
root.children[i].anchors.rightMargin = 34
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
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 writeAsExpression: false
property bool __dirty: false
property bool showTranslateCheckBox: true
property bool showExtendedFunctionButton: true
property string context
actionIndicator.visible: showExtendedFunctionButton
property bool __dirty: false
signal commitData
property string context
color: lineEdit.edit ? StudioTheme.Values.themeTextColor : colorLogic.textColor
actionIndicator.visible: lineEdit.showExtendedFunctionButton
translationIndicatorVisible: lineEdit.showTranslateCheckBox
function setTranslateExpression() {
if (translateFunction() === "qsTranslate") {
backendValue.expression = translateFunction()
+ "(\"" + backendValue.getTranslationContext()
+ "\", " + "\"" + escapeString(text) + "\")"
lineEdit.backendValue.expression = translateFunction()
+ "(\"" + lineEdit.backendValue.getTranslationContext()
+ "\", " + "\"" + lineEdit.escapeString(lineEdit.text) + "\")"
} 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 {
id: extFuncLogic
backendValue: lineEdit.backendValue
@ -79,60 +86,58 @@ StudioControls.TextField {
if (colorLogic.valueFromBackend === undefined) {
lineEdit.text = ""
} else {
if (writeValueManually)
if (lineEdit.writeValueManually)
lineEdit.text = convertColorToString(colorLogic.valueFromBackend)
else
lineEdit.text = colorLogic.valueFromBackend
}
__dirty = false
lineEdit.__dirty = false
}
}
onTextChanged: {
__dirty = true
}
onTextChanged: lineEdit.__dirty = true
Connections {
target: modelNodeBackend
function onSelectionToBeChanged() {
if (__dirty && !writeValueManually) {
if (writeAsExpression)
lineEdit.backendValue.expression = text
if (lineEdit.__dirty && !lineEdit.writeValueManually) {
if (lineEdit.writeAsExpression)
lineEdit.backendValue.expression = lineEdit.text
else
lineEdit.backendValue.value = text
} else if (__dirty) {
lineEdit.backendValue.value = lineEdit.text
} else if (lineEdit.__dirty) {
commitData()
}
__dirty = false
lineEdit.__dirty = false
}
}
onEditingFinished: {
if (writeValueManually)
if (lineEdit.writeValueManually)
return
if (!__dirty)
if (!lineEdit.__dirty)
return
if (backendValue.isTranslated) {
setTranslateExpression()
if (lineEdit.backendValue.isTranslated) {
lineEdit.setTranslateExpression()
} else {
if (writeAsExpression) {
if (lineEdit.backendValue.expression !== text)
lineEdit.backendValue.expression = text
} else if (lineEdit.backendValue.value !== text) {
lineEdit.backendValue.value = text
if (lineEdit.writeAsExpression) {
if (lineEdit.backendValue.expression !== lineEdit.text)
lineEdit.backendValue.expression = lineEdit.text
} else if (lineEdit.backendValue.value !== lineEdit.text) {
lineEdit.backendValue.value = lineEdit.text
}
}
__dirty = false
lineEdit.__dirty = false
}
property bool isTranslated: colorLogic.backendValue === undefined ? false
: colorLogic.backendValue.isTranslated
translationIndicator.onClicked: {
if (translationIndicator.checked) {
if (lineEdit.translationIndicator.checked) {
setTranslateExpression()
} else {
var textValue = lineEdit.text
@ -141,7 +146,8 @@ StudioControls.TextField {
colorLogic.evaluate()
}
property variant backendValueValueInternal: backendValue === undefined ? 0 : backendValue.value
property variant backendValueValueInternal: lineEdit.backendValue === undefined ? 0
: lineEdit.backendValue.value
onBackendValueValueInternalChanged: {
if (lineEdit.backendValue === undefined)
lineEdit.translationIndicator.checked = false
@ -155,15 +161,4 @@ StudioControls.TextField {
else
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
Row {
id: urlChooser
id: root
property variant backendValue
property color textColor: colorLogic.highlight ? colorLogic.textColor
@ -47,22 +47,24 @@ Row {
FileResourcesModel {
id: fileModel
modelNodeBackendProperty: modelNodeBackend
filter: urlChooser.filter
filter: root.filter
}
ColorLogic {
id: colorLogic
backendValue: urlChooser.backendValue
backendValue: root.backendValue
}
StudioControls.ComboBox {
StudioControls.FilterComboBox {
id: comboBox
property ListModel items: ListModel {}
property ListModel listModel: ListModel {}
implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ StudioTheme.Values.actionIndicatorWidth
width: implicitWidth
allowUserInput: true
// 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.
property int hoverIndex: -1
@ -70,7 +72,7 @@ Row {
ToolTip {
id: toolTip
visible: comboBox.hover && toolTip.text !== ""
text: urlChooser.backendValue.valueToString
text: root.backendValue.valueToString
delay: StudioTheme.Values.toolTipDelay
height: StudioTheme.Values.toolTipHeight
background: Rectangle {
@ -88,27 +90,39 @@ Row {
delegate: ItemDelegate {
required property string fullPath
required property string name
required property int group
required property int index
id: delegateItem
width: parent.width
id: delegateRoot
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
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 {
id: itemDelegateIconArea
width: delegateItem.height
height: delegateItem.height
width: delegateRoot.height
height: delegateRoot.height
Label {
id: itemDelegateIcon
text: StudioTheme.Constants.tickIcon
color: delegateItem.highlighted ? StudioTheme.Values.themeTextSelectedTextColor
color: delegateRoot.highlighted ? StudioTheme.Values.themeTextSelectedTextColor
: StudioTheme.Values.themeTextColor
font.family: StudioTheme.Constants.iconFont.family
font.pixelSize: StudioTheme.Values.spinControlIconSizeMulti
visible: comboBox.currentIndex === index ? true : false
visible: comboBox.currentIndex === delegateRoot.DelegateModel.itemsIndex ? true
: false
anchors.fill: parent
renderType: Text.NativeRendering
horizontalAlignment: Text.AlignHCenter
@ -119,7 +133,7 @@ Row {
contentItem: Text {
leftPadding: itemDelegateIconArea.width
text: name
color: delegateItem.highlighted ? StudioTheme.Values.themeTextSelectedTextColor
color: delegateRoot.highlighted ? StudioTheme.Values.themeTextSelectedTextColor
: StudioTheme.Values.themeTextColor
font: comboBox.font
elide: Text.ElideRight
@ -127,17 +141,17 @@ Row {
}
background: Rectangle {
id: itemDelegateBackground
x: 0
y: 0
width: delegateItem.width
height: delegateItem.height
color: delegateItem.highlighted ? StudioTheme.Values.themeInteraction : "transparent"
width: delegateRoot.width
height: delegateRoot.height
color: delegateRoot.highlighted ? StudioTheme.Values.themeInteraction
: "transparent"
}
ToolTip {
id: itemToolTip
visible: delegateItem.hovered && comboBox.highlightedIndex === index
visible: delegateRoot.hovered && comboBox.highlightedIndex === index
text: fullPath
delay: StudioTheme.Values.toolTipDelay
height: StudioTheme.Values.toolTipHeight
@ -161,7 +175,7 @@ Row {
ExtendedFunctionLogic {
id: extFuncLogic
backendValue: urlChooser.backendValue
backendValue: root.backendValue
onReseted: comboBox.editText = ""
}
@ -181,20 +195,15 @@ Row {
// Takes into account applied bindings
property string textValue: {
if (urlChooser.backendValue.isBound)
return urlChooser.backendValue.expression
if (root.backendValue.isBound)
return root.backendValue.expression
var fullPath = urlChooser.backendValue.valueToString
var fullPath = root.backendValue.valueToString
return fullPath.substr(fullPath.lastIndexOf('/') + 1)
}
onTextValueChanged: comboBox.setCurrentText(comboBox.textValue)
editable: true
textRole: "name"
valueRole: "fullPath"
model: comboBox.items
onModelChanged: {
if (!comboBox.isComplete)
return
@ -206,20 +215,14 @@ Row {
if (!comboBox.isComplete)
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
var index = comboBox.find(inputValue)
let index = comboBox.find(inputValue)
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
// 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
root.backendValue.value = inputValue
comboBox.dirty = false
}
@ -234,14 +237,16 @@ Row {
}
function handleActivate(index) {
if (urlChooser.backendValue === undefined || !comboBox.isComplete)
if (root.backendValue === undefined || !comboBox.isComplete)
return
if (index === -1) // select first item if index is invalid
index = 0
let inputValue = comboBox.editText
if (urlChooser.backendValue.value !== comboBox.items.get(index).fullPath)
urlChooser.backendValue.value = comboBox.items.get(index).fullPath
if (index >= 0)
inputValue = comboBox.items.get(index).model.fullPath
if (root.backendValue.value !== inputValue)
root.backendValue.value = inputValue
comboBox.dirty = false
}
@ -250,7 +255,7 @@ Row {
// 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 = urlChooser.textColor
comboBox.children[i].color = root.textColor
comboBox.children[i].anchors.rightMargin = 34
}
}
@ -261,36 +266,44 @@ Row {
function createModel() {
// 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) {
for (var i = 0; i < urlChooser.defaultItems.length; ++i) {
comboBox.items.append({
fullPath: urlChooser.defaultItems[i],
name: urlChooser.defaultItems[i]
if (root.defaultItems !== undefined) {
for (var i = 0; i < root.defaultItems.length; ++i) {
comboBox.listModel.append({
fullPath: root.defaultItems[i],
name: root.defaultItems[i],
group: 0
})
}
}
for (var j = 0; j < fileModel.fullPathModel.length; ++j) {
comboBox.items.append({
comboBox.listModel.append({
fullPath: fileModel.fullPathModel[j],
name: fileModel.fileNameModel[j]
name: fileModel.fileNameModel[j],
group: 1
})
}
comboBox.model = Qt.binding(function() { return comboBox.listModel })
}
Connections {
target: fileModel
function onFullPathModelChanged() {
urlChooser.createModel()
root.createModel()
comboBox.setCurrentText(comboBox.textValue)
}
}
onDefaultItemsChanged: urlChooser.createModel()
onDefaultItemsChanged: root.createModel()
Component.onCompleted: urlChooser.createModel()
Component.onCompleted: root.createModel()
function indexOf(model, criteria) {
for (var i = 0; i < model.count; ++i) {
@ -305,16 +318,16 @@ Row {
function onStateChanged(state) {
// update currentIndex when the popup opens to override the default behavior in super classes
// that selects currentIndex based on values in the combo box.
if (comboBox.popup.opened && !urlChooser.backendValue.isBound) {
var index = urlChooser.indexOf(comboBox.items,
if (comboBox.popup.opened && !root.backendValue.isBound) {
var index = root.indexOf(comboBox.items,
function(item) {
return item.fullPath === urlChooser.backendValue.value
return item.fullPath === root.backendValue.value
})
if (index !== -1) {
comboBox.currentIndex = 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 {
icon: StudioTheme.Constants.addFile
iconColor: urlChooser.textColor
iconColor: root.textColor
onClicked: {
fileModel.openFileDialog()
if (fileModel.fileName !== "")
urlChooser.backendValue.value = fileModel.fileName
root.backendValue.value = fileModel.fileName
}
}
}

View File

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

View File

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

View File

@ -73,13 +73,13 @@ TextInput {
acceptedButtons: Qt.LeftButton
cursorShape: Qt.PointingHandCursor
onPressed: function(mouse) {
if (textInput.readOnly) {
if (!textInput.myControl.editable) {
if (myControl.popup.opened) {
myControl.popup.close()
myControl.focus = false
} else {
myControl.forceActiveFocus()
myControl.popup.open()
myControl.forceActiveFocus()
}
} else {
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 string preFocusText: ""
signal realValueModified
signal compressedRealValueModified
signal dragStarted
@ -162,6 +164,8 @@ T.SpinBox {
validator: doubleValidator
function handleEditingFinished() {
mySpinBox.focus = false
// Keep the dirty state before calling setValueFromInput(),
// it will be set to false (cleared) internally
var valueModified = mySpinBox.dirty
@ -174,7 +178,7 @@ T.SpinBox {
mySpinBox.compressedRealValueModified()
}
onEditingFinished: handleEditingFinished()
onEditingFinished: spinBoxInput.handleEditingFinished()
onTextEdited: mySpinBox.dirty = true
}
@ -281,7 +285,7 @@ T.SpinBox {
id: myTimer
repeat: false
running: false
interval: 200
interval: 400
onTriggered: mySpinBox.compressedRealValueModified()
}
@ -306,8 +310,10 @@ T.SpinBox {
}
onDisplayTextChanged: spinBoxInput.text = mySpinBox.displayText
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()
}
}
Keys.onPressed: function(event) {
@ -333,8 +339,11 @@ T.SpinBox {
mySpinBox.realStepSize = currStepSize
}
if (event.key === Qt.Key_Escape)
mySpinBox.focus = false
if (event.key === Qt.Key_Escape) {
spinBoxInput.text = mySpinBox.preFocusText
mySpinBox.dirty = true
spinBoxInput.handleEditingFinished()
}
}
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
T.TextField {
id: myTextField
id: root
property alias actionIndicator: actionIndicator
property alias translationIndicator: translationIndicator
// This property is used to indicate the global hover state
property bool hover: (actionIndicator.hover || mouseArea.containsMouse
|| translationIndicator.hover) && myTextField.enabled
property bool edit: myTextField.activeFocus
|| translationIndicator.hover) && root.enabled
property bool edit: root.activeFocus
property alias actionIndicatorVisible: actionIndicator.visible
property real __actionIndicatorWidth: StudioTheme.Values.actionIndicatorWidth
@ -46,6 +46,8 @@ T.TextField {
property real __translationIndicatorWidth: StudioTheme.Values.translationIndicatorWidth
property real __translationIndicatorHeight: StudioTheme.Values.translationIndicatorHeight
property string preFocusText: ""
horizontalAlignment: Qt.AlignLeft
verticalAlignment: Qt.AlignVCenter
@ -78,7 +80,7 @@ T.TextField {
cursorShape: Qt.PointingHandCursor
onPressed: function(mouse) {
if (mouse.button === Qt.RightButton)
contextMenu.popup(myTextField)
contextMenu.popup(root)
mouse.accepted = false
}
@ -86,43 +88,50 @@ T.TextField {
onPersistentSelectionChanged: {
if (!persistentSelection)
myTextField.deselect()
root.deselect()
}
ContextMenu {
id: contextMenu
myTextEdit: myTextField
myTextEdit: root
}
onActiveFocusChanged: {
if (root.activeFocus)
root.preFocusText = root.text
}
onEditChanged: {
if (myTextField.edit)
if (root.edit)
contextMenu.close()
}
onEditingFinished: root.focus = false
ActionIndicator {
id: actionIndicator
myControl: myTextField
myControl: root
x: 0
y: 0
width: actionIndicator.visible ? myTextField.__actionIndicatorWidth : 0
height: actionIndicator.visible ? myTextField.__actionIndicatorHeight : 0
width: actionIndicator.visible ? root.__actionIndicatorWidth : 0
height: actionIndicator.visible ? root.__actionIndicatorHeight : 0
}
Text {
id: placeholder
x: myTextField.leftPadding
y: myTextField.topPadding
width: myTextField.width - (myTextField.leftPadding + myTextField.rightPadding)
height: myTextField.height - (myTextField.topPadding + myTextField.bottomPadding)
x: root.leftPadding
y: root.topPadding
width: root.width - (root.leftPadding + root.rightPadding)
height: root.height - (root.topPadding + root.bottomPadding)
text: myTextField.placeholderText
font: myTextField.font
color: myTextField.placeholderTextColor
verticalAlignment: myTextField.verticalAlignment
visible: !myTextField.length && !myTextField.preeditText
&& (!myTextField.activeFocus || myTextField.horizontalAlignment !== Qt.AlignHCenter)
text: root.placeholderText
font: root.font
color: root.placeholderTextColor
verticalAlignment: root.verticalAlignment
visible: !root.length && !root.preeditText
&& (!root.activeFocus || root.horizontalAlignment !== Qt.AlignHCenter)
elide: Text.ElideRight
renderType: myTextField.renderType
renderType: root.renderType
}
background: Rectangle {
@ -131,14 +140,14 @@ T.TextField {
border.color: StudioTheme.Values.themeControlOutline
border.width: StudioTheme.Values.border
x: actionIndicator.width
width: myTextField.width - actionIndicator.width
height: myTextField.height
width: root.width - actionIndicator.width
height: root.height
}
TranslationIndicator {
id: translationIndicator
myControl: myTextField
x: myTextField.width - translationIndicator.width
myControl: root
x: root.width - translationIndicator.width
width: translationIndicator.visible ? __translationIndicatorWidth : 0
height: translationIndicator.visible ? __translationIndicatorHeight : 0
}
@ -146,15 +155,14 @@ T.TextField {
states: [
State {
name: "default"
when: myTextField.enabled && !myTextField.hover
&& !myTextField.edit
when: root.enabled && !root.hover && !root.edit
PropertyChanges {
target: textFieldBackground
color: StudioTheme.Values.themeControlBackground
border.color: StudioTheme.Values.themeControlOutline
}
PropertyChanges {
target: myTextField
target: root
color: StudioTheme.Values.themeTextColor
placeholderTextColor: StudioTheme.Values.themePlaceholderTextColor
}
@ -165,15 +173,15 @@ T.TextField {
},
State {
name: "globalHover"
when: (actionIndicator.hover || translationIndicator.hover) && !myTextField.edit
&& myTextField.enabled
when: (actionIndicator.hover || translationIndicator.hover) && !root.edit
&& root.enabled
PropertyChanges {
target: textFieldBackground
color: StudioTheme.Values.themeControlBackgroundGlobalHover
border.color: StudioTheme.Values.themeControlOutline
}
PropertyChanges {
target: myTextField
target: root
color: StudioTheme.Values.themeTextColor
placeholderTextColor: StudioTheme.Values.themePlaceholderTextColor
}
@ -181,28 +189,28 @@ T.TextField {
State {
name: "hover"
when: mouseArea.containsMouse && !actionIndicator.hover && !translationIndicator.hover
&& !myTextField.edit && myTextField.enabled
&& !root.edit && root.enabled
PropertyChanges {
target: textFieldBackground
color: StudioTheme.Values.themeControlBackgroundHover
border.color: StudioTheme.Values.themeControlOutline
}
PropertyChanges {
target: myTextField
target: root
color: StudioTheme.Values.themeTextColor
placeholderTextColor: StudioTheme.Values.themePlaceholderTextColor
}
},
State {
name: "edit"
when: myTextField.edit
when: root.edit
PropertyChanges {
target: textFieldBackground
color: StudioTheme.Values.themeControlBackgroundInteraction
border.color: StudioTheme.Values.themeControlOutlineInteraction
}
PropertyChanges {
target: myTextField
target: root
color: StudioTheme.Values.themeTextColor
placeholderTextColor: StudioTheme.Values.themePlaceholderTextColorInteraction
}
@ -213,14 +221,14 @@ T.TextField {
},
State {
name: "disable"
when: !myTextField.enabled
when: !root.enabled
PropertyChanges {
target: textFieldBackground
color: StudioTheme.Values.themeControlBackgroundDisabled
border.color: StudioTheme.Values.themeControlOutlineDisabled
}
PropertyChanges {
target: myTextField
target: root
color: StudioTheme.Values.themeTextColorDisabled
placeholderTextColor: StudioTheme.Values.themeTextColorDisabled
}
@ -228,7 +236,9 @@ T.TextField {
]
Keys.onPressed: function(event) {
if (event.key === Qt.Key_Escape)
myTextField.focus = false
if (event.key === Qt.Key_Escape) {
root.text = root.preFocusText
root.focus = false
}
}
}

View File

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

View File

@ -406,11 +406,6 @@ QStringList lastSessionArgument()
#ifdef ENABLE_CRASHPAD
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;
// Cache directory that will store crashpad information and minidumps

View File

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

View File

@ -436,6 +436,13 @@ static bool hideAnalyzeMenu()
.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,
const std::function<void()> &onTriggered)
{
@ -922,7 +929,9 @@ DebuggerPluginPrivate::DebuggerPluginPrivate(const QStringList &arguments)
m_visibleStartAction.setAction(&m_startAction);
m_visibleStartAction.setObjectName("Debug"); // used for UI introduction
ModeManager::addAction(&m_visibleStartAction, /*priority*/ 90);
if (!hideDebugMenu())
ModeManager::addAction(&m_visibleStartAction, /*priority*/ 90);
m_undisturbableAction.setIcon(interruptIcon(false));
m_undisturbableAction.setEnabled(false);

View File

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

View File

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

View File

@ -96,8 +96,10 @@ void MacroOptionsWidget::createTable()
Core::Command *command =
Core::ActionManager::command(base.withSuffix(macro->displayName()));
if (command && command->action())
macroItem->setText(2, command->action()->shortcut().toString());
if (command && command->action()) {
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
{
const QString fileName = tcd.compilerPath.completeBaseName();
if ((tcd.language == Constants::C_LANGUAGE_ID && (fileName.startsWith("gcc")
|| fileName.endsWith("gcc")
|| fileName == "cc"))
|| (tcd.language == Constants::CXX_LANGUAGE_ID && (fileName.startsWith("g++")
|| fileName.endsWith("g++")
|| fileName == "c++"))) {
const QString resolvedSymlinksFileName = tcd.compilerPath.resolveSymlinks().completeBaseName();
const bool isCCompiler = tcd.language == Constants::C_LANGUAGE_ID
&& (fileName.startsWith("gcc")
|| fileName.endsWith("gcc")
|| (fileName == "cc" && !resolvedSymlinksFileName.contains("clang")));
const bool isCxxCompiler = tcd.language == Constants::CXX_LANGUAGE_ID
&& (fileName.startsWith("g++")
|| fileName.endsWith("g++")
|| (fileName == "c++" && !resolvedSymlinksFileName.contains("clang")));
if (isCCompiler || isCxxCompiler) {
return autoDetectToolChain(tcd, [](const ToolChain *tc) {
return tc->targetAbi().osFlavor() != Abi::WindowsMSysFlavor;
});
@ -1765,9 +1772,18 @@ Toolchains ClangToolChainFactory::autoDetect(const ToolchainDetector &detector)
Toolchains ClangToolChainFactory::detectForImport(const ToolChainDescription &tcd) const
{
const QString fileName = tcd.compilerPath.toString();
if ((tcd.language == Constants::C_LANGUAGE_ID && fileName.startsWith("clang") && !fileName.startsWith("clang++"))
|| (tcd.language == Constants::CXX_LANGUAGE_ID && fileName.startsWith("clang++"))) {
const QString fileName = tcd.compilerPath.completeBaseName();
const QString resolvedSymlinksFileName = tcd.compilerPath.resolveSymlinks().completeBaseName();
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 {};
@ -2023,7 +2039,7 @@ Toolchains LinuxIccToolChainFactory::autoDetect(const ToolchainDetector &detecto
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")) ||
(tcd.language == Constants::C_LANGUAGE_ID && fileName.startsWith("icc"))) {
return autoDetectToolChain(tcd);

View File

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

View File

@ -36,19 +36,24 @@
#include <coreplugin/icore.h>
#include <utils/filesystemwatcher.h>
#include <utils/stylehelper.h>
#include <QCheckBox>
#include <QDebug>
#include <QDir>
#include <QDirIterator>
#include <QElapsedTimer>
#include <QFont>
#include <QImageReader>
#include <QLoggingCategory>
#include <QMessageBox>
#include <QMetaProperty>
#include <QPainter>
#include <QRawFont>
#include <QRegularExpression>
#include <QMessageBox>
#include <QCheckBox>
#include <utils/stylehelper.h>
#include <utils/filesystemwatcher.h>
static Q_LOGGING_CATEGORY(assetsLibraryBenchmark, "qtc.assetsLibrary.setRoot", QtWarningMsg)
namespace QmlDesigner {
@ -298,6 +303,12 @@ void AssetsLibraryModel::refresh()
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"};
m_fileSystemWatcher->clear();
@ -345,6 +356,8 @@ void AssetsLibraryModel::setRootPath(const QString &path)
return isEmpty;
};
qCInfo(assetsLibraryBenchmark) << "directories parsed:" << time.elapsed();
if (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
endResetModel();
qCInfo(assetsLibraryBenchmark) << "model reset:" << time.elapsed();
}
void AssetsLibraryModel::setSearchText(const QString &searchText)

View File

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

View File

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

View File

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

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
// the document in that case.
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()) {
QDataStream stream(data);
stream >> m_itemLibraryEntry;

View File

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

View File

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

View File

@ -36,6 +36,7 @@
#include <nodemetainfo.h>
#include <projectexplorer/project.h>
#include <projectexplorer/session.h>
#include "qmldesignerconstants.h"
#include "qmldesignerplugin.h"
#include <utils/algorithm.h>
#include <utils/qtcassert.h>
@ -515,9 +516,9 @@ QMimeData *ItemLibraryModel::getMimeData(const ItemLibraryEntry &itemLibraryEntr
QByteArray data;
QDataStream stream(&data, QIODevice::WriteOnly);
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;
}

View File

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

View File

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

View File

@ -36,6 +36,7 @@
#include <bindingproperty.h>
#include <designmodecontext.h>
#include <designersettings.h>
#include <itemlibraryinfo.h>
#include <nodeproperty.h>
#include <nodelistproperty.h>
#include <variantproperty.h>
@ -57,8 +58,9 @@
#include <utils/stylehelper.h>
#include <QHeaderView>
#include <QTimer>
#include <QMimeData>
#include <QPixmap>
#include <QTimer>
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,
const QList<ModelNode> &nodeList, const QList<QVariant> &data)
{

View File

@ -92,6 +92,9 @@ public:
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 handleChangedExport(const ModelNode &modelNode, bool exported);

View File

@ -294,7 +294,7 @@ void PropertyEditorQmlBackend::createPropertyEditorValue(const QmlObjectNode &qm
valueObject = new PropertyEditorValue(&backendValuesPropertyMap());
QObject::connect(valueObject, &PropertyEditorValue::valueChanged, &backendValuesPropertyMap(), &DesignerPropertyMap::valueChanged);
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);
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));
}
void PropertyEditorValue::exportPopertyAsAlias()
void PropertyEditorValue::exportPropertyAsAlias()
{
emit exportPopertyAsAliasRequested(nameAsQString());
emit exportPropertyAsAliasRequested(nameAsQString());
}
bool PropertyEditorValue::hasPropertyAlias() const

View File

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

View File

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

View File

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

View File

@ -229,6 +229,9 @@ public:
virtual void updateImport3DSupport(const QVariantMap &supportMap);
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);
NodeInstanceView *nodeInstanceView() const;

View File

@ -129,6 +129,9 @@ public:
QString generateNewId(const QString &prefixName) const;
QString generateNewId(const QString &prefixName, const QString &fallbackPrefix) const;
void startDrag(QMimeData *mimeData, const QString iconPath = {});
void endDrag();
protected:
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
{
return QmlDesigner::toModelNodeList(nodeList, const_cast<AbstractView*>(this));

View File

@ -67,6 +67,7 @@
#include <utils/algorithm.h>
#include <QDrag>
#include <QRegularExpression>
/*!
@ -588,6 +589,16 @@ void ModelPrivate::notifyImport3DSupportChanged(const QVariantMap &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()
{
notifyNodeInstanceViewLast([&](AbstractView *view) { view->rewriterBeginTransaction(); });
@ -1492,6 +1503,22 @@ QString Model::generateNewId(const QString &prefixName, const QString &fallbackP
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
{
return generateNewId(prefixName, QStringLiteral("element"));

View File

@ -183,6 +183,9 @@ public:
void notifyModelNodePreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap);
void notifyImport3DSupportChanged(const QVariantMap &supportMap);
void notifyDragStarted(QMimeData *mimeData);
void notifyDragEnded();
void setDocumentMessages(const QList<DocumentMessage> &errors, const QList<DocumentMessage> &warnings);
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 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
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())
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"));
if (importPathsProperty.isValid()) {
QStringList list = importPathsProperty.value.toStringList();

View File

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

View File

@ -118,21 +118,38 @@ QmlProject::QmlProject(const Utils::FilePath &fileName)
disconnect(m_openFileConnection);
if (target && success) {
Utils::FilePaths uiFiles = getUiQmlFilesForFolder(projectDirectory()
+ "/content");
if (uiFiles.isEmpty())
uiFiles = getUiQmlFilesForFolder(projectDirectory());
if (!uiFiles.isEmpty()) {
Utils::FilePath currentFile;
if (auto cd = Core::EditorManager::currentDocument())
currentFile = cd->filePath();
auto target = activeTarget();
if (!target)
return;
if (currentFile.isEmpty() || !isKnownFile(currentFile))
QTimer::singleShot(1000, [uiFiles]() {
Core::EditorManager::openEditor(uiFiles.first(),
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()
+ "/content");
if (uiFiles.isEmpty())
uiFiles = getUiQmlFilesForFolder(projectDirectory());
if (!uiFiles.isEmpty()) {
Utils::FilePath currentFile;
if (auto cd = Core::EditorManager::currentDocument())
currentFile = cd->filePath();
if (currentFile.isEmpty() || !isKnownFile(currentFile))
QTimer::singleShot(1000, [uiFiles]() {
Core::EditorManager::openEditor(uiFiles.first(),
Utils::Id());
});
}
}
}
});
@ -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)
{
ParseGuard guard = guardParsingRun();
@ -266,11 +335,68 @@ QString QmlBuildSystem::mainFile() const
return QString();
}
QString QmlBuildSystem::mainUiFile() const
{
if (m_projectItem)
return m_projectItem->mainUiFile();
return QString();
}
Utils::FilePath QmlBuildSystem::mainFilePath() const
{
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
{
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)
{
if (dynamic_cast<QmlProjectNode *>(context)) {
if (oldFilePath.endsWith(mainFile())) {
setMainFile(newFilePath.toString());
// 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;
}
// 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);
}
if (oldFilePath.endsWith(mainFile()))
return setMainFileInProjectFile(newFilePath);
if (oldFilePath.endsWith(mainUiFile()))
return setMainUiFileInProjectFile(newFilePath);
return true;
}

View File

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

View File

@ -30,16 +30,23 @@
#include "qmlprojectrunconfiguration.h"
#include "projectfilecontenttools.h"
#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/coreconstants.h>
#include <coreplugin/designmode.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/fileiconprovider.h>
#include <coreplugin/icore.h>
#include <coreplugin/messagebox.h>
#include <coreplugin/modemanager.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/projectmanager.h>
#include <projectexplorer/projectnodes.h>
#include <projectexplorer/projecttree.h>
#include <projectexplorer/runcontrol.h>
#include <projectexplorer/session.h>
#include <projectexplorer/target.h>
#include <qmljs/qmljsmodelmanagerinterface.h>
@ -54,11 +61,12 @@
#include <utils/fileutils.h>
#include <utils/qtcprocess.h>
#include <QAction>
#include <QDesktopServices>
#include <QMessageBox>
#include <QPointer>
#include <QPushButton>
#include <QTimer>
#include <QPointer>
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)
{
Q_UNUSED(errorMessage)
d = new QmlProjectPluginPrivate;
if (!qmlDesignerEnabled()) {
if (!qmlDesignerEnabled())
initializeQmlLandingPage();
}
ProjectManager::registerProjectType<QmlProject>(QmlJSTools::Constants::QMLPROJECT_MIMETYPE);
Core::FileIconProvider::registerIconOverlayForSuffix(":/qmlproject/images/qmlproject.png",
"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;
}

View File

@ -196,17 +196,6 @@ void FileDownloader::probeUrl()
});
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())
return;
@ -383,7 +372,6 @@ void FileExtractor::extract()
Utils::Archive *archive = new Utils::Archive(m_sourceFile, m_targetPath);
QTC_ASSERT(archive->isValid(), delete archive; return);
archive->setParent(this);
m_timer.start();
qint64 bytesBefore = QStorageInfo(m_targetPath.toFileInfo().dir()).bytesAvailable();
@ -423,7 +411,8 @@ void FileExtractor::extract()
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_timer.stop();
@ -436,3 +425,76 @@ void FileExtractor::extract()
});
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;
QFile m_tempFile;
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:
QQuickWidget *m_modeWidget = nullptr;
DataModelDownloader *m_dataModelDownloader = nullptr;
};
void StudioWelcomePlugin::closeSplashScreen()
@ -596,6 +597,28 @@ WelcomeMode::WelcomeMode()
{
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",
Utils::Theme::IconsBaseColor}});
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());
const QString welcomePagePath = Core::ICore::resourcePath("qmldesigner/welcomepage").toString();
m_modeWidget->engine()->addImportPath(welcomePagePath + "/imports");
m_modeWidget->engine()->addImportPath(m_dataModelDownloader->targetFolder().toString());
m_modeWidget->setSource(QUrl::fromLocalFile(welcomePagePath + "/main.qml"));
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.
Second - some of the test suites/test cases expect a build of Qt 4.8.7 to be available:
[ 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
Second - 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
use installations of the official opensource Qt packages. Just install the Qt version for the
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.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).
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:
@ -58,12 +36,12 @@ This folder must contain the following:
* a subfolder called 'creator-test-data'
* 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
* 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.
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
working would be 'U.S. International - PC', while pure 'U.S.' had problems.

View File

@ -4,31 +4,6 @@
<qtcreator>
<data>
<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">
<value type="bool" key="PE.Profile.AutoDetected">false</value>
<value type="QString" key="PE.Profile.AutoDetectionSource"></value>
@ -55,32 +30,7 @@
</valuemap>
</data>
<data>
<variable>Profile.2</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>
<variable>Profile.1</variable>
<valuemap type="QVariantMap">
<value type="bool" key="PE.Profile.AutoDetected">false</value>
<value type="QString" key="PE.Profile.AutoDetectionSource"></value>
@ -108,7 +58,7 @@
</data>
<data>
<variable>Profile.Count</variable>
<value type="int">4</value>
<value type="int">2</value>
</data>
<data>
<variable>Profile.Default</variable>

View File

@ -4,16 +4,6 @@
<qtcreator>
<data>
<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">
<value type="int" key="Id">9</value>
<value type="QString" key="Name">Qt %{Qt:Version} (SQUISH_DEFAULT_COMPILER)</value>
@ -23,7 +13,7 @@
</valuemap>
</data>
<data>
<variable>QtVersion.2</variable>
<variable>QtVersion.1</variable>
<valuemap type="QVariantMap">
<value type="int" key="Id">11</value>
<value type="QString" key="Name">Qt %{Qt:Version} (SQUISH_DEFAULT_COMPILER)</value>

View File

@ -4,52 +4,6 @@
<qtcreator>
<data>
<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">
<value type="bool" key="PE.Profile.AutoDetected">false</value>
<value type="QString" key="PE.Profile.AutoDetectionSource"></value>
@ -73,7 +27,7 @@
</valuemap>
</data>
<data>
<variable>Profile.3</variable>
<variable>Profile.1</variable>
<valuemap type="QVariantMap">
<value type="bool" key="PE.Profile.AutoDetected">false</value>
<value type="QString" key="PE.Profile.AutoDetectionSource"></value>
@ -97,7 +51,7 @@
</valuemap>
</data>
<data>
<variable>Profile.4</variable>
<variable>Profile.2</variable>
<valuemap type="QVariantMap">
<value type="bool" key="PE.Profile.AutoDetected">false</value>
<value type="QString" key="PE.Profile.AutoDetectionSource"></value>
@ -126,7 +80,7 @@
</data>
<data>
<variable>Profile.Count</variable>
<value type="int">5</value>
<value type="int">3</value>
</data>
<data>
<variable>Profile.Default</variable>

View File

@ -4,16 +4,6 @@
<qtcreator>
<data>
<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">
<value type="int" key="Id">13</value>
<value type="QString" key="Name">Qt %{Qt:Version} (SQUISH_DEFAULT_COMPILER)</value>
@ -23,7 +13,7 @@
</valuemap>
</data>
<data>
<variable>QtVersion.2</variable>
<variable>QtVersion.1</variable>
<valuemap type="QVariantMap">
<value type="int" key="Id">15</value>
<value type="QString" key="Name">Qt %{Qt:Version} (SQUISH_DEFAULT_COMPILER)</value>
@ -33,7 +23,7 @@
</valuemap>
</data>
<data>
<variable>QtVersion.3</variable>
<variable>QtVersion.2</variable>
<valuemap type="QVariantMap">
<value type="int" key="Id">17</value>
<value type="QString" key="Name">Qt %{Qt:Version} (SQUISH_DEFAULT_COMPILER)</value>

View File

@ -4,34 +4,6 @@
<qtcreator>
<data>
<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">
<value type="bool" key="PE.Profile.AutoDetected">false</value>
<value type="QString" key="PE.Profile.AutoDetectionSource"></value>
@ -59,7 +31,7 @@
</valuemap>
</data>
<data>
<variable>Profile.2</variable>
<variable>Profile.1</variable>
<valuemap type="QVariantMap">
<value type="bool" key="PE.Profile.AutoDetected">false</value>
<value type="QString" key="PE.Profile.AutoDetectionSource"></value>
@ -70,8 +42,7 @@
<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">
<valuemap type="QVariantMap" key="PE.Profile.ToolChainsV3">
<value type="QByteArray" key="C">{ce3a8004-e9ae-46f2-b62d-d7daf69435ca}</value>
<value type="QByteArray" key="Cxx">{3df7c776-a480-4a04-9099-6c75adac2dca}</value>
</valuemap>
@ -87,7 +58,7 @@
</valuemap>
</data>
<data>
<variable>Profile.3</variable>
<variable>Profile.2</variable>
<valuemap type="QVariantMap">
<value type="bool" key="PE.Profile.AutoDetected">false</value>
<value type="QString" key="PE.Profile.AutoDetectionSource"></value>
@ -116,7 +87,7 @@
</data>
<data>
<variable>Profile.Count</variable>
<value type="int">4</value>
<value type="int">3</value>
</data>
<data>
<variable>Profile.Default</variable>

View File

@ -4,16 +4,6 @@
<qtcreator>
<data>
<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">
<value type="int" key="Id">22</value>
<value type="QString" key="Name">Qt %{Qt:Version} (mingw491_32)</value>
@ -23,7 +13,7 @@
</valuemap>
</data>
<data>
<variable>QtVersion.2</variable>
<variable>QtVersion.1</variable>
<valuemap type="QVariantMap">
<value type="int" key="Id">24</value>
<value type="QString" key="Name">Qt %{Qt:Version} (msvc2017_64)</value>
@ -33,7 +23,7 @@
</valuemap>
</data>
<data>
<variable>QtVersion.3</variable>
<variable>QtVersion.2</variable>
<valuemap type="QVariantMap">
<value type="int" key="Id">26</value>
<value type="QString" key="Name">Qt %{Qt:Version} (msvc2015)</value>

View File

@ -19,18 +19,6 @@
</data>
<data>
<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">
<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>
@ -47,12 +35,18 @@
</valuemap>
</data>
<data>
<variable>ToolChain.3</variable>
<variable>ToolChain.2</variable>
<valuemap type="QVariantMap">
<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.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.Id">ProjectExplorer.ToolChain.Msvc:{ce3a8004-e9ae-46f2-b62d-d7daf69435ca}</value>
<value type="int" key="ProjectExplorer.ToolChain.Language">1</value>
@ -60,7 +54,7 @@
</valuemap>
</data>
<data>
<variable>ToolChain.4</variable>
<variable>ToolChain.3</variable>
<valuemap type="QVariantMap">
<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>
@ -73,7 +67,7 @@
</valuemap>
</data>
<data>
<variable>ToolChain.5</variable>
<variable>ToolChain.4</variable>
<valuemap type="QVariantMap">
<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>
@ -86,23 +80,18 @@
</valuemap>
</data>
<data>
<variable>ToolChain.6</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>
<variable>ToolChain.5</variable>
<valuemap type="QVariantMap">
<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.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.Id">ProjectExplorer.ToolChain.Msvc:{3df7c776-a480-4a04-9099-6c75adac2dca}</value>
<value type="int" key="ProjectExplorer.ToolChain.Language">2</value>
@ -111,7 +100,7 @@
</data>
<data>
<variable>ToolChain.Count</variable>
<value type="int">8</value>
<value type="int">6</value>
</data>
<data>
<variable>Version</variable>

View File

@ -190,13 +190,12 @@ def verifyBuildConfig(currentTarget, configName, shouldBeDebug=False, enableShad
# it will wait here until compilation of the debug libraries has finished.
runCMakeButton = ("{type='QPushButton' text='Run CMake' unnamed='1' "
"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')
if selectFromCombo(qmlDebuggingCombo, 'Enable'):
if buildSystem is None or buildSystem == "CMake": # re-run cmake to apply
clickButton(waitForObject(runCMakeButton))
elif buildSystem == "qmake": # Don't rebuild now
clickButton(waitForObject(":QML Debugging.No_QPushButton", 5000))
qmlDebuggingCombo = findObject(':Qt Creator.QML debugging and profiling:_QComboBox')
if selectFromCombo(qmlDebuggingCombo, 'Enable'):
if buildSystem is None or buildSystem == "CMake": # re-run cmake to apply
clickButton(waitForObject(runCMakeButton))
elif buildSystem == "qmake": # Don't rebuild now
clickButton(waitForObject(":QML Debugging.No_QPushButton", 5000))
try:
problemFound = waitForObject("{window=':Qt Creator_Core::Internal::MainWindow' "
"type='QLabel' name='problemLabel' visible='1'}", 1000)
@ -205,14 +204,13 @@ def verifyBuildConfig(currentTarget, configName, shouldBeDebug=False, enableShad
except:
pass
else:
if currentTarget not in (Targets.DESKTOP_4_8_7_DEFAULT, Targets.EMBEDDED_LINUX):
qmlDebuggingCombo = findObject(':Qt Creator.QML debugging and profiling:_QComboBox')
if selectFromCombo(qmlDebuggingCombo, "Disable"):
test.log("Qml debugging libraries are available - unchecked qml debugging.")
if buildSystem is None or buildSystem == "CMake": # re-run cmake to apply
clickButton(waitForObject(runCMakeButton))
elif buildSystem == "qmake": # Don't rebuild now
clickButton(waitForObject(":QML Debugging.No_QPushButton", 5000))
qmlDebuggingCombo = findObject(':Qt Creator.QML debugging and profiling:_QComboBox')
if selectFromCombo(qmlDebuggingCombo, "Disable"):
test.log("Qml debugging libraries are available - unchecked qml debugging.")
if buildSystem is None or buildSystem == "CMake": # re-run cmake to apply
clickButton(waitForObject(runCMakeButton))
elif buildSystem == "qmake": # Don't rebuild now
clickButton(waitForObject(":QML Debugging.No_QPushButton", 5000))
clickButton(waitForObject(":scrollArea.Details_Utils::DetailsButton"))
switchViewTo(ViewConstants.EDIT)

View File

@ -30,37 +30,27 @@ except ImportError:
# for easier re-usage (because Python hasn't an enum type)
class Targets:
ALL_TARGETS = tuple(range(5))
ALL_TARGETS = tuple(range(3))
(DESKTOP_4_8_7_DEFAULT,
EMBEDDED_LINUX,
DESKTOP_5_4_1_GCC,
(DESKTOP_5_4_1_GCC,
DESKTOP_5_10_1_DEFAULT,
DESKTOP_5_14_1_DEFAULT) = ALL_TARGETS
__TARGET_NAME_DICT__ = dict(zip(ALL_TARGETS,
["Desktop 4.8.7 default",
"Embedded Linux",
"Desktop 5.4.1 GCC",
["Desktop 5.4.1 GCC",
"Desktop 5.10.1 default",
"Desktop 5.14.1 default"]))
@staticmethod
def availableTargetClasses(ignoreValidity=False):
availableTargets = set(Targets.ALL_TARGETS)
if not qt4Available and not ignoreValidity:
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':
if platform.system() == 'Darwin':
availableTargets.remove(Targets.DESKTOP_5_4_1_GCC)
return availableTargets
@staticmethod
def desktopTargetClasses():
desktopTargets = Targets.availableTargetClasses()
desktopTargets.discard(Targets.EMBEDDED_LINUX)
return desktopTargets
return Targets.availableTargetClasses()
@staticmethod
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 checks turns tests in the function on if set to True
# 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, withoutQt4=False):
def __selectQtVersionDesktop__(buildSystem, checks, available=None):
wanted = Targets.desktopTargetClasses()
if withoutQt4:
wanted.discard(Targets.DESKTOP_4_8_7_DEFAULT)
checkedTargets = __chooseTargets__(wanted, available)
if checks:
for target in checkedTargets:
@ -183,9 +180,8 @@ def __selectQtVersionDesktop__(buildSystem, checks, available=None, withoutQt4=F
objectMap.realName(detailsWidget)))
verifyChecked(cbObject % ("Minimum Size Release",
objectMap.realName(detailsWidget)))
elif (buildSystem == "qmake"
and target not in (Targets.DESKTOP_4_8_7_DEFAULT, Targets.EMBEDDED_LINUX)):
verifyChecked(cbObject % ("Profile", objectMap.realName(detailsWidget)))
elif buildSystem == "qmake":
verifyChecked(cbObject % ("Profile", objectMap.realName(detailsWidget)))
clickButton(detailsButton)
clickButton(waitForObject(":Next_QPushButton"))
@ -207,11 +203,6 @@ def __verifyFileCreation__(path, expectedFiles):
def __modifyAvailableTargets__(available, requiredQt, asStrings=False):
versionFinder = re.compile("^Desktop (\\d{1}\.\\d{1,2}\.\\d{1,2}).*$")
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:
if asStrings:
item = currentItem
@ -260,7 +251,7 @@ def createProject_Qt_GUI(path, projectName, checks=True, addToVersionControl="<N
clickButton(waitForObject(":Next_QPushButton"))
__createProjectHandleTranslationSelection__()
__selectQtVersionDesktop__(buildSystem, checks, available, True)
__selectQtVersionDesktop__(buildSystem, checks, available)
expectedFiles = []
if checks:
@ -540,12 +531,6 @@ def __getSupportedPlatforms__(text, templateName, getAsStrings=False, ignoreVali
supports = text[text.find('Supported Platforms'):].split(":")[1].strip().split("\n")
result = set()
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]))
if platform.system() != 'Darwin':
result.add(Targets.DESKTOP_5_4_1_GCC)

View File

@ -40,12 +40,6 @@ except ImportError:
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 = ''
SettingsPath = []
tmpSettingsDir = ''
@ -237,6 +231,23 @@ def substituteCdb(settingsDir):
__substitute__(debuggers, "SQUISH_DEBUGGER_BITNESS", 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):
if platform.system() == 'Linux':
supportedABIs = filter(lambda x: 'linux' in x, supportedABIs)
@ -331,6 +342,7 @@ def copySettingsToTmpDir(destination=None, omitFiles=[]):
substituteDefaultCompiler(tmpSettingsDir)
elif platform.system() in ('Windows', 'Microsoft'):
substituteCdb(tmpSettingsDir)
substituteMsvcPaths(tmpSettingsDir)
substituteUnchosenTargetABIs(tmpSettingsDir)
SettingsPath = ['-settingspath', '"%s"' % tmpSettingsDir]

View File

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

View File

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