From 40caa8a4ba97ce7677cb26a7e4d4176baad99db6 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Tue, 1 Feb 2022 14:58:47 +0100 Subject: [PATCH 01/94] Squish: Make presence of Qt4 optional MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is hard to build Qt4 nowadays. Any machine set up today won't be able to build it without hazzle. So, make it optional inside the Squish tests to avoid fails and fatals. Use a different available Qt instead. Change-Id: I151d809f4fada8047a30940a183f913af2a1a691 Reviewed-by: Reviewed-by: Robert Löhning --- tests/system/README | 1 + tests/system/shared/classes.py | 2 ++ tests/system/shared/project.py | 8 ++++++-- tests/system/shared/qtcreator.py | 2 ++ tests/system/suite_CSUP/tst_CSUP03/test.py | 6 ++++-- tests/system/suite_HELP/tst_HELP04/test.py | 3 ++- tests/system/suite_general/tst_build_speedcrunch/test.py | 5 ++++- tests/system/suite_general/tst_openqt_creator/test.py | 5 ++++- 8 files changed, 25 insertions(+), 7 deletions(-) diff --git a/tests/system/README b/tests/system/README index 05fe472d5ad..61847485fbf 100644 --- a/tests/system/README +++ b/tests/system/README @@ -5,6 +5,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 diff --git a/tests/system/shared/classes.py b/tests/system/shared/classes.py index a96a7e2d6e0..fefee33b53a 100644 --- a/tests/system/shared/classes.py +++ b/tests/system/shared/classes.py @@ -52,6 +52,8 @@ class Targets: availableTargets.remove(Targets.EMBEDDED_LINUX) elif platform.system() == 'Darwin': availableTargets.remove(Targets.DESKTOP_5_4_1_GCC) + if not qt4Available: + availableTargets.remove(Targets.DESKTOP_4_8_7_DEFAULT) return availableTargets @staticmethod diff --git a/tests/system/shared/project.py b/tests/system/shared/project.py index e8ee09bda9d..04ea8220acb 100644 --- a/tests/system/shared/project.py +++ b/tests/system/shared/project.py @@ -69,7 +69,10 @@ def openCmakeProject(projectPath, buildDir): invokeMenuItem("File", "Open File or Project...") selectFromFileDialog(projectPath) __chooseTargets__([]) # uncheck all - __chooseTargets__([Targets.DESKTOP_4_8_7_DEFAULT], additionalFunc=additionalFunction) + targetToChoose = Targets.DESKTOP_4_8_7_DEFAULT # FIXME make the intended target a parameter + if not qt4Available: + targetToChoose = Targets.DESKTOP_5_14_1_DEFAULT + __chooseTargets__([targetToChoose], additionalFunc=additionalFunction) clickButton(waitForObject(":Qt Creator.Configure Project_QPushButton")) return True @@ -511,7 +514,8 @@ def __getSupportedPlatforms__(text, templateName, getAsStrings=False): result = set() if 'Desktop' in supports: if (version == None or version < "5.0") and not templateName.startswith("Qt Quick 2"): - result.add(Targets.DESKTOP_4_8_7_DEFAULT) + if qt4Available: + 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])) diff --git a/tests/system/shared/qtcreator.py b/tests/system/shared/qtcreator.py index 0618ce273da..f7ea2a2c609 100644 --- a/tests/system/shared/qtcreator.py +++ b/tests/system/shared/qtcreator.py @@ -339,6 +339,8 @@ elif platform.system() == 'Darwin': else: origSettingsDir = os.path.join(origSettingsDir, "unix") +qt4Available = os.path.exists(qt4Path) + srcPath = os.getenv("SYSTEST_SRCPATH", os.path.expanduser(os.path.join("~", "squish-data"))) # the following only doesn't work if the test ends in an exception diff --git a/tests/system/suite_CSUP/tst_CSUP03/test.py b/tests/system/suite_CSUP/tst_CSUP03/test.py index 53b532c05de..a20ac19ea4f 100644 --- a/tests/system/suite_CSUP/tst_CSUP03/test.py +++ b/tests/system/suite_CSUP/tst_CSUP03/test.py @@ -78,8 +78,10 @@ def main(): continue if not startCreatorVerifyingClang(useClang): continue - projectName = createNewNonQtProject(tempDir(), "project-csup03", - [Targets.DESKTOP_4_8_7_DEFAULT]) + targetToChoose = Targets.DESKTOP_4_8_7_DEFAULT + if not qt4Available: + targetToChoose = Targets.DESKTOP_5_14_1_DEFAULT + projectName = createNewNonQtProject(tempDir(), "project-csup03", [targetToChoose]) checkCodeModelSettings(useClang) openDocument("%s.Sources.main\\.cpp" % projectName) editor = getEditorForFileSuffix("main.cpp") diff --git a/tests/system/suite_HELP/tst_HELP04/test.py b/tests/system/suite_HELP/tst_HELP04/test.py index 18e3ee45639..83941679b9f 100644 --- a/tests/system/suite_HELP/tst_HELP04/test.py +++ b/tests/system/suite_HELP/tst_HELP04/test.py @@ -69,7 +69,8 @@ def main(): startQC() if not startedWithoutPluginError(): return - addHelpDocumentation([os.path.join(qt4Path, "doc", "qch", "qt.qch")]) + if qt4Available: + addHelpDocumentation([os.path.join(qt4Path, "doc", "qch", "qt.qch")]) # switch to help mode switchViewTo(ViewConstants.HELP) # verify that search widget is accessible diff --git a/tests/system/suite_general/tst_build_speedcrunch/test.py b/tests/system/suite_general/tst_build_speedcrunch/test.py index 8ba749b1680..e98a9b0e9a5 100644 --- a/tests/system/suite_general/tst_build_speedcrunch/test.py +++ b/tests/system/suite_general/tst_build_speedcrunch/test.py @@ -41,7 +41,10 @@ def main(): startQC() if not startedWithoutPluginError(): return - openQmakeProject(SpeedCrunchPath, [Targets.DESKTOP_4_8_7_DEFAULT]) + targetToChoose = Targets.DESKTOP_4_8_7_DEFAULT + if not qt4Available: + targetToChoose = Targets.DESKTOP_5_14_1_DEFAULT + openQmakeProject(SpeedCrunchPath, [targetToChoose]) waitForProjectParsing() fancyToolButton = waitForObject(":*Qt Creator_Core::Internal::FancyToolButton") diff --git a/tests/system/suite_general/tst_openqt_creator/test.py b/tests/system/suite_general/tst_openqt_creator/test.py index ad1f4b52a25..6ff0bfb345e 100644 --- a/tests/system/suite_general/tst_openqt_creator/test.py +++ b/tests/system/suite_general/tst_openqt_creator/test.py @@ -36,7 +36,10 @@ def main(): return runButton = findObject(':*Qt Creator.Run_Core::Internal::FancyToolButton') - openQmakeProject(pathSpeedcrunch, [Targets.DESKTOP_4_8_7_DEFAULT]) + targetToChoose = Targets.DESKTOP_4_8_7_DEFAULT + if not qt4Available: + targetToChoose = Targets.DESKTOP_5_14_1_DEFAULT + openQmakeProject(pathSpeedcrunch, [targetToChoose]) # Wait for parsing to complete waitFor("runButton.enabled", 30000) # Starting before opening, because this is where Creator froze (QTCREATORBUG-10733) From 28a295b005f684acb06b7b9d453dbe96eaa558d1 Mon Sep 17 00:00:00 2001 From: Mats Honkamaa Date: Wed, 2 Feb 2022 14:47:53 +0200 Subject: [PATCH 02/94] Doc: Update create project docs Add information about the Recent tab in the create project wizard. Task-number: QDS-5967 Change-Id: If52f96635c04529706007094aa0dbcc98c5be240 Reviewed-by: Leena Miettinen --- .../images/simplekeyboard-project-details.png | Bin 11440 -> 20310 bytes .../images/studio-project-wizards.png | Bin 111408 -> 98163 bytes .../src/qtdesignstudio-projects.qdoc | 4 ++++ 3 files changed, 4 insertions(+) diff --git a/doc/qtdesignstudio/examples/doc/images/simplekeyboard-project-details.png b/doc/qtdesignstudio/examples/doc/images/simplekeyboard-project-details.png index d8cc017a4d043b1e0785296d3fd4ff6d7a61b9e9..b4c67f7a88aaddb76060d6c59e651f6f0ad0e94c 100644 GIT binary patch literal 20310 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 JF6*2UngHx)fPnx2 literal 11440 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 GLK6TEaktaqG=q)|k+n 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 X@y-7h8FMl)Ffe$!`njxgN@xNAB~I1J literal 111408 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 L)z4*}Q$iB}L`wB- diff --git a/doc/qtdesignstudio/src/qtdesignstudio-projects.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-projects.qdoc index de7f7150d35..f8368e90baf 100644 --- a/doc/qtdesignstudio/src/qtdesignstudio-projects.qdoc +++ b/doc/qtdesignstudio/src/qtdesignstudio-projects.qdoc @@ -62,6 +62,10 @@ \li Category \li Wizard Preset \li Purpose + \row + \li Recents + \li + \li Lists the most recent presets that you have used. \row \li {1,2} General \li Empty From 4e10170ccdebab968d6eef47a61143b584f7903a Mon Sep 17 00:00:00 2001 From: Mats Honkamaa Date: Thu, 3 Feb 2022 10:07:06 +0200 Subject: [PATCH 03/94] Update loginui examples folder names Folder names need to start with capital letter. Task-number: QDS-6160 Change-Id: I5a77e693f9bfe0d85775a7b1e71ad9d0081025a2 Reviewed-by: Leena Miettinen --- .../Loginui1.qmlproject} | 0 .../content/EntryField.ui.qml | 0 .../content/PushButton.ui.qml | 0 .../{loginui1 => Loginui1}/content/Screen01.ui.qml | 0 .../content/images/adventurePage.jpg | Bin .../content/images/qt_logo_green_128x128px.png | Bin .../imports/loginui1/Constants.qml | 0 .../imports/loginui1/EventListModel.qml | 0 .../imports/loginui1/EventListSimulator.qml | 0 .../{loginui1 => Loginui1}/imports/loginui1/qmldir | 0 .../{loginui1 => Loginui1}/src/app_environment.h | 0 .../{loginui1 => Loginui1}/src/import_qml_plugins.h | 0 .../examples/{loginui1 => Loginui1}/src/main.cpp | 0 .../{loginui2 => Loginui2}/Loginui2.qmlproject | 0 .../{loginui2 => Loginui2}/content/Screen01.ui.qml | 0 .../{loginui3 => Loginui3}/Loginui3.qmlproject | 0 .../{loginui3 => Loginui3}/content/Screen01.ui.qml | 0 .../{loginui4 => Loginui4}/Loginui4.qmlproject | 0 .../{loginui4 => Loginui4}/content/Screen01.ui.qml | 0 doc/qtdesignstudio/examples/doc/loginui1.qdoc | 6 +++--- doc/qtdesignstudio/examples/doc/loginui3.qdoc | 2 +- doc/qtdesignstudio/examples/doc/loginui4.qdoc | 4 ++-- 22 files changed, 6 insertions(+), 6 deletions(-) rename doc/qtdesignstudio/examples/{loginui1/loginui1.qmlproject => Loginui1/Loginui1.qmlproject} (100%) rename doc/qtdesignstudio/examples/{loginui1 => Loginui1}/content/EntryField.ui.qml (100%) rename doc/qtdesignstudio/examples/{loginui1 => Loginui1}/content/PushButton.ui.qml (100%) rename doc/qtdesignstudio/examples/{loginui1 => Loginui1}/content/Screen01.ui.qml (100%) rename doc/qtdesignstudio/examples/{loginui1 => Loginui1}/content/images/adventurePage.jpg (100%) rename doc/qtdesignstudio/examples/{loginui1 => Loginui1}/content/images/qt_logo_green_128x128px.png (100%) rename doc/qtdesignstudio/examples/{loginui1 => Loginui1}/imports/loginui1/Constants.qml (100%) rename doc/qtdesignstudio/examples/{loginui1 => Loginui1}/imports/loginui1/EventListModel.qml (100%) rename doc/qtdesignstudio/examples/{loginui1 => Loginui1}/imports/loginui1/EventListSimulator.qml (100%) rename doc/qtdesignstudio/examples/{loginui1 => Loginui1}/imports/loginui1/qmldir (100%) rename doc/qtdesignstudio/examples/{loginui1 => Loginui1}/src/app_environment.h (100%) rename doc/qtdesignstudio/examples/{loginui1 => Loginui1}/src/import_qml_plugins.h (100%) rename doc/qtdesignstudio/examples/{loginui1 => Loginui1}/src/main.cpp (100%) rename doc/qtdesignstudio/examples/{loginui2 => Loginui2}/Loginui2.qmlproject (100%) rename doc/qtdesignstudio/examples/{loginui2 => Loginui2}/content/Screen01.ui.qml (100%) rename doc/qtdesignstudio/examples/{loginui3 => Loginui3}/Loginui3.qmlproject (100%) rename doc/qtdesignstudio/examples/{loginui3 => Loginui3}/content/Screen01.ui.qml (100%) rename doc/qtdesignstudio/examples/{loginui4 => Loginui4}/Loginui4.qmlproject (100%) rename doc/qtdesignstudio/examples/{loginui4 => Loginui4}/content/Screen01.ui.qml (100%) diff --git a/doc/qtdesignstudio/examples/loginui1/loginui1.qmlproject b/doc/qtdesignstudio/examples/Loginui1/Loginui1.qmlproject similarity index 100% rename from doc/qtdesignstudio/examples/loginui1/loginui1.qmlproject rename to doc/qtdesignstudio/examples/Loginui1/Loginui1.qmlproject diff --git a/doc/qtdesignstudio/examples/loginui1/content/EntryField.ui.qml b/doc/qtdesignstudio/examples/Loginui1/content/EntryField.ui.qml similarity index 100% rename from doc/qtdesignstudio/examples/loginui1/content/EntryField.ui.qml rename to doc/qtdesignstudio/examples/Loginui1/content/EntryField.ui.qml diff --git a/doc/qtdesignstudio/examples/loginui1/content/PushButton.ui.qml b/doc/qtdesignstudio/examples/Loginui1/content/PushButton.ui.qml similarity index 100% rename from doc/qtdesignstudio/examples/loginui1/content/PushButton.ui.qml rename to doc/qtdesignstudio/examples/Loginui1/content/PushButton.ui.qml diff --git a/doc/qtdesignstudio/examples/loginui1/content/Screen01.ui.qml b/doc/qtdesignstudio/examples/Loginui1/content/Screen01.ui.qml similarity index 100% rename from doc/qtdesignstudio/examples/loginui1/content/Screen01.ui.qml rename to doc/qtdesignstudio/examples/Loginui1/content/Screen01.ui.qml diff --git a/doc/qtdesignstudio/examples/loginui1/content/images/adventurePage.jpg b/doc/qtdesignstudio/examples/Loginui1/content/images/adventurePage.jpg similarity index 100% rename from doc/qtdesignstudio/examples/loginui1/content/images/adventurePage.jpg rename to doc/qtdesignstudio/examples/Loginui1/content/images/adventurePage.jpg diff --git a/doc/qtdesignstudio/examples/loginui1/content/images/qt_logo_green_128x128px.png b/doc/qtdesignstudio/examples/Loginui1/content/images/qt_logo_green_128x128px.png similarity index 100% rename from doc/qtdesignstudio/examples/loginui1/content/images/qt_logo_green_128x128px.png rename to doc/qtdesignstudio/examples/Loginui1/content/images/qt_logo_green_128x128px.png diff --git a/doc/qtdesignstudio/examples/loginui1/imports/loginui1/Constants.qml b/doc/qtdesignstudio/examples/Loginui1/imports/loginui1/Constants.qml similarity index 100% rename from doc/qtdesignstudio/examples/loginui1/imports/loginui1/Constants.qml rename to doc/qtdesignstudio/examples/Loginui1/imports/loginui1/Constants.qml diff --git a/doc/qtdesignstudio/examples/loginui1/imports/loginui1/EventListModel.qml b/doc/qtdesignstudio/examples/Loginui1/imports/loginui1/EventListModel.qml similarity index 100% rename from doc/qtdesignstudio/examples/loginui1/imports/loginui1/EventListModel.qml rename to doc/qtdesignstudio/examples/Loginui1/imports/loginui1/EventListModel.qml diff --git a/doc/qtdesignstudio/examples/loginui1/imports/loginui1/EventListSimulator.qml b/doc/qtdesignstudio/examples/Loginui1/imports/loginui1/EventListSimulator.qml similarity index 100% rename from doc/qtdesignstudio/examples/loginui1/imports/loginui1/EventListSimulator.qml rename to doc/qtdesignstudio/examples/Loginui1/imports/loginui1/EventListSimulator.qml diff --git a/doc/qtdesignstudio/examples/loginui1/imports/loginui1/qmldir b/doc/qtdesignstudio/examples/Loginui1/imports/loginui1/qmldir similarity index 100% rename from doc/qtdesignstudio/examples/loginui1/imports/loginui1/qmldir rename to doc/qtdesignstudio/examples/Loginui1/imports/loginui1/qmldir diff --git a/doc/qtdesignstudio/examples/loginui1/src/app_environment.h b/doc/qtdesignstudio/examples/Loginui1/src/app_environment.h similarity index 100% rename from doc/qtdesignstudio/examples/loginui1/src/app_environment.h rename to doc/qtdesignstudio/examples/Loginui1/src/app_environment.h diff --git a/doc/qtdesignstudio/examples/loginui1/src/import_qml_plugins.h b/doc/qtdesignstudio/examples/Loginui1/src/import_qml_plugins.h similarity index 100% rename from doc/qtdesignstudio/examples/loginui1/src/import_qml_plugins.h rename to doc/qtdesignstudio/examples/Loginui1/src/import_qml_plugins.h diff --git a/doc/qtdesignstudio/examples/loginui1/src/main.cpp b/doc/qtdesignstudio/examples/Loginui1/src/main.cpp similarity index 100% rename from doc/qtdesignstudio/examples/loginui1/src/main.cpp rename to doc/qtdesignstudio/examples/Loginui1/src/main.cpp diff --git a/doc/qtdesignstudio/examples/loginui2/Loginui2.qmlproject b/doc/qtdesignstudio/examples/Loginui2/Loginui2.qmlproject similarity index 100% rename from doc/qtdesignstudio/examples/loginui2/Loginui2.qmlproject rename to doc/qtdesignstudio/examples/Loginui2/Loginui2.qmlproject diff --git a/doc/qtdesignstudio/examples/loginui2/content/Screen01.ui.qml b/doc/qtdesignstudio/examples/Loginui2/content/Screen01.ui.qml similarity index 100% rename from doc/qtdesignstudio/examples/loginui2/content/Screen01.ui.qml rename to doc/qtdesignstudio/examples/Loginui2/content/Screen01.ui.qml diff --git a/doc/qtdesignstudio/examples/loginui3/Loginui3.qmlproject b/doc/qtdesignstudio/examples/Loginui3/Loginui3.qmlproject similarity index 100% rename from doc/qtdesignstudio/examples/loginui3/Loginui3.qmlproject rename to doc/qtdesignstudio/examples/Loginui3/Loginui3.qmlproject diff --git a/doc/qtdesignstudio/examples/loginui3/content/Screen01.ui.qml b/doc/qtdesignstudio/examples/Loginui3/content/Screen01.ui.qml similarity index 100% rename from doc/qtdesignstudio/examples/loginui3/content/Screen01.ui.qml rename to doc/qtdesignstudio/examples/Loginui3/content/Screen01.ui.qml diff --git a/doc/qtdesignstudio/examples/loginui4/Loginui4.qmlproject b/doc/qtdesignstudio/examples/Loginui4/Loginui4.qmlproject similarity index 100% rename from doc/qtdesignstudio/examples/loginui4/Loginui4.qmlproject rename to doc/qtdesignstudio/examples/Loginui4/Loginui4.qmlproject diff --git a/doc/qtdesignstudio/examples/loginui4/content/Screen01.ui.qml b/doc/qtdesignstudio/examples/Loginui4/content/Screen01.ui.qml similarity index 100% rename from doc/qtdesignstudio/examples/loginui4/content/Screen01.ui.qml rename to doc/qtdesignstudio/examples/Loginui4/content/Screen01.ui.qml diff --git a/doc/qtdesignstudio/examples/doc/loginui1.qdoc b/doc/qtdesignstudio/examples/doc/loginui1.qdoc index 78bc2192b56..4e6a6f11b42 100644 --- a/doc/qtdesignstudio/examples/doc/loginui1.qdoc +++ b/doc/qtdesignstudio/examples/doc/loginui1.qdoc @@ -24,7 +24,7 @@ ****************************************************************************/ /*! - \example loginui1 + \example Loginui1 \ingroup gstutorials \nextpage {Log In UI - Positioning} @@ -231,7 +231,7 @@ adds the following \e import statements to the UI files (.ui.qml) that it creates: - \quotefromfile Loginui1/Content/Screen01.ui.qml + \quotefromfile Loginui1/content/Screen01.ui.qml \skipto import \printuntil Controls @@ -334,7 +334,7 @@ To be able to use the functionality of the Button control, the wizard template adds the following \e import statements to the \e EntryField.ui.qml file: - \quotefromfile Loginui1/Content/EntryField.ui.qml + \quotefromfile Loginui1/content/EntryField.ui.qml \skipto import \printuntil Controls diff --git a/doc/qtdesignstudio/examples/doc/loginui3.qdoc b/doc/qtdesignstudio/examples/doc/loginui3.qdoc index 999215d90b1..75ac69e399e 100644 --- a/doc/qtdesignstudio/examples/doc/loginui3.qdoc +++ b/doc/qtdesignstudio/examples/doc/loginui3.qdoc @@ -24,7 +24,7 @@ ****************************************************************************/ /*! - \example loginui3 + \example Loginui3 \ingroup gstutorials \title Log In UI - States diff --git a/doc/qtdesignstudio/examples/doc/loginui4.qdoc b/doc/qtdesignstudio/examples/doc/loginui4.qdoc index a6a1ad77d4a..6a43e55b009 100644 --- a/doc/qtdesignstudio/examples/doc/loginui4.qdoc +++ b/doc/qtdesignstudio/examples/doc/loginui4.qdoc @@ -24,7 +24,7 @@ ****************************************************************************/ /*! - \example loginui4 + \example Loginui4 \ingroup gstutorials \title Log In UI - Timeline @@ -312,7 +312,7 @@ the following \e import statement to the UI files where it uses the components: - \quotefromfile Loginui4/Content/Screen01.ui.qml + \quotefromfile Loginui4/content/Screen01.ui.qml \skipto QtQuick.Timeline \printuntil 1.0 From 4e716c0db5cc61ba6357f66c8ea6bb648d6304db Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 3 Feb 2022 08:52:11 +0100 Subject: [PATCH 04/94] Squish: Fix unknown global variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Amends 40caa8a4ba97ce7. Change-Id: I014210c2035fa0a69ca273718df726a523a23786 Reviewed-by: Robert Löhning --- tests/system/shared/qtcreator.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/system/shared/qtcreator.py b/tests/system/shared/qtcreator.py index f7ea2a2c609..4c9646ffb6d 100644 --- a/tests/system/shared/qtcreator.py +++ b/tests/system/shared/qtcreator.py @@ -39,6 +39,13 @@ try: 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 = '' @@ -329,18 +336,14 @@ def copySettingsToTmpDir(destination=None, omitFiles=[]): # current dir is directory holding qtcreator.py origSettingsDir = os.path.abspath(os.path.join(os.getcwd(), "..", "..", "settings")) -qt4Path = os.path.expanduser("~/Qt4.8.7") if platform.system() in ('Windows', 'Microsoft'): - qt4Path = "C:\\Qt\\Qt4.8.7" origSettingsDir = os.path.join(origSettingsDir, "windows") elif platform.system() == 'Darwin': origSettingsDir = os.path.join(origSettingsDir, "mac") else: origSettingsDir = os.path.join(origSettingsDir, "unix") -qt4Available = os.path.exists(qt4Path) - srcPath = os.getenv("SYSTEST_SRCPATH", os.path.expanduser(os.path.join("~", "squish-data"))) # the following only doesn't work if the test ends in an exception From b8b5687f21dc6d4f4ef01cd68cb9e29d09779189 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20L=C3=B6hning?= Date: Thu, 3 Feb 2022 12:58:02 +0100 Subject: [PATCH 05/94] Squish: Fix availableTargetClasses() Amends 40caa8a4ba97ce7. Change-Id: Ib48a70fa641c5d3c65f53aad2dd1ce8fd3abce54 Reviewed-by: Christian Stenger Reviewed-by: --- tests/system/shared/classes.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/system/shared/classes.py b/tests/system/shared/classes.py index fefee33b53a..d43c15a63a3 100644 --- a/tests/system/shared/classes.py +++ b/tests/system/shared/classes.py @@ -48,12 +48,12 @@ class Targets: @staticmethod def availableTargetClasses(): availableTargets = set(Targets.ALL_TARGETS) - if platform.system() in ('Windows', 'Microsoft'): + if not qt4Available: + availableTargets.remove(Targets.DESKTOP_4_8_7_DEFAULT) + if not qt4Available or platform.system() in ('Windows', 'Microsoft'): availableTargets.remove(Targets.EMBEDDED_LINUX) elif platform.system() == 'Darwin': availableTargets.remove(Targets.DESKTOP_5_4_1_GCC) - if not qt4Available: - availableTargets.remove(Targets.DESKTOP_4_8_7_DEFAULT) return availableTargets @staticmethod From 363849a3724e8ec9fd2f54c3834b675b5a85d701 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 7 Feb 2022 13:35:03 +0100 Subject: [PATCH 06/94] CMakePM: Also show type of options in configuration tooltips Change-Id: Ie6b6b270c83d7c5df117c16d637f362e8c01eaad Reviewed-by: Eike Ziller --- src/plugins/cmakeprojectmanager/configmodel.cpp | 3 +++ src/plugins/cmakeprojectmanager/configmodel.h | 16 ++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/plugins/cmakeprojectmanager/configmodel.cpp b/src/plugins/cmakeprojectmanager/configmodel.cpp index 190ffbc9120..4815e2f0bd1 100644 --- a/src/plugins/cmakeprojectmanager/configmodel.cpp +++ b/src/plugins/cmakeprojectmanager/configmodel.cpp @@ -623,6 +623,9 @@ QString ConfigModelTreeItem::toolTip() const "

Not in CMakeCache.txt

"); } } + tooltip << QCoreApplication::translate("CMakeProjectManager", + "

Type: %1

") + .arg(dataItem->typeDisplay()); return tooltip.join(""); } diff --git a/src/plugins/cmakeprojectmanager/configmodel.h b/src/plugins/cmakeprojectmanager/configmodel.h index 83e34d191b5..11e4153b076 100644 --- a/src/plugins/cmakeprojectmanager/configmodel.h +++ b/src/plugins/cmakeprojectmanager/configmodel.h @@ -85,6 +85,22 @@ public: } } + QString typeDisplay() const { + switch (type) { + case DataItem::BOOLEAN: + return "BOOL"; + case DataItem::FILE: + return "FILEPATH"; + case DataItem::DIRECTORY: + return "PATH"; + case DataItem::STRING: + return "STRING"; + case DataItem::UNKNOWN: + break; + } + return "UNINITIALIZED"; + } + CMakeConfigItem toCMakeConfigItem() const { CMakeConfigItem cmi; cmi.key = key.toUtf8(); From c6643dad654bf506420eacf1168cd3659fab3aee Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 7 Feb 2022 17:01:09 +0100 Subject: [PATCH 07/94] CMakeProjectManager: Some code cosmetics Move non-exported classed to Internal namespace, move some functions out-of-line. Change-Id: I3a2135104d09c0c3f799c5b8d795c93059b1ae95 Reviewed-by: Cristian Adam --- .../cmakebuildconfiguration.cpp | 14 +-- .../cmakeprojectmanager/configmodel.cpp | 94 ++++++++++++++++++- src/plugins/cmakeprojectmanager/configmodel.h | 87 ++--------------- .../configmodelitemdelegate.cpp | 6 +- .../configmodelitemdelegate.h | 2 + 5 files changed, 111 insertions(+), 92 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index 0acbd3ddc27..fd249886941 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -121,8 +121,8 @@ private: void updateAdvancedCheckBox(); void updateFromKit(); void updateConfigurationStateIndex(int index); - CMakeProjectManager::CMakeConfig getQmlDebugCxxFlags(); - CMakeProjectManager::CMakeConfig getSigningFlagsChanges(); + CMakeConfig getQmlDebugCxxFlags(); + CMakeConfig getSigningFlagsChanges(); void updateSelection(); void updateConfigurationStateSelection(); @@ -695,19 +695,19 @@ void CMakeBuildSettingsWidget::updateButtonState() ni.inCMakeCache = i.inCMakeCache; ni.values = i.values; switch (i.type) { - case CMakeProjectManager::ConfigModel::DataItem::BOOLEAN: + case ConfigModel::DataItem::BOOLEAN: ni.type = CMakeConfigItem::BOOL; break; - case CMakeProjectManager::ConfigModel::DataItem::FILE: + case ConfigModel::DataItem::FILE: ni.type = CMakeConfigItem::FILEPATH; break; - case CMakeProjectManager::ConfigModel::DataItem::DIRECTORY: + case ConfigModel::DataItem::DIRECTORY: ni.type = CMakeConfigItem::PATH; break; - case CMakeProjectManager::ConfigModel::DataItem::STRING: + case ConfigModel::DataItem::STRING: ni.type = CMakeConfigItem::STRING; break; - case CMakeProjectManager::ConfigModel::DataItem::UNKNOWN: + case ConfigModel::DataItem::UNKNOWN: default: ni.type = CMakeConfigItem::UNINITIALIZED; break; diff --git a/src/plugins/cmakeprojectmanager/configmodel.cpp b/src/plugins/cmakeprojectmanager/configmodel.cpp index 4815e2f0bd1..0e680ad56e3 100644 --- a/src/plugins/cmakeprojectmanager/configmodel.cpp +++ b/src/plugins/cmakeprojectmanager/configmodel.cpp @@ -35,12 +35,103 @@ #include namespace CMakeProjectManager { +namespace Internal { + +// DataItem + +ConfigModel::DataItem::DataItem(const CMakeConfigItem &cmi) +{ + key = QString::fromUtf8(cmi.key); + value = QString::fromUtf8(cmi.value); + description = QString::fromUtf8(cmi.documentation); + values = cmi.values; + inCMakeCache = cmi.inCMakeCache; + + isAdvanced = cmi.isAdvanced; + isInitial = cmi.isInitial; + isHidden = cmi.type == CMakeConfigItem::INTERNAL || cmi.type == CMakeConfigItem::STATIC; + + setType(cmi.type); +} + +void ConfigModel::DataItem::setType(CMakeConfigItem::Type cmt) +{ + switch (cmt) { + case CMakeConfigItem::FILEPATH: + type = FILE; + break; + case CMakeConfigItem::PATH: + type = DIRECTORY; + break; + case CMakeConfigItem::BOOL: + type = BOOLEAN; + break; + case CMakeConfigItem::STRING: + type = STRING; + break; + default: + type = UNKNOWN; + break; + } +} + +QString ConfigModel::DataItem::typeDisplay() const +{ + switch (type) { + case DataItem::BOOLEAN: + return "BOOL"; + case DataItem::FILE: + return "FILEPATH"; + case DataItem::DIRECTORY: + return "PATH"; + case DataItem::STRING: + return "STRING"; + case DataItem::UNKNOWN: + break; + } + return "UNINITIALIZED"; +} + +CMakeConfigItem ConfigModel::DataItem::toCMakeConfigItem() const +{ + CMakeConfigItem cmi; + cmi.key = key.toUtf8(); + cmi.value = value.toUtf8(); + switch (type) { + case DataItem::BOOLEAN: + cmi.type = CMakeConfigItem::BOOL; + break; + case DataItem::FILE: + cmi.type = CMakeConfigItem::FILEPATH; + break; + case DataItem::DIRECTORY: + cmi.type = CMakeConfigItem::PATH; + break; + case DataItem::STRING: + cmi.type = CMakeConfigItem::STRING; + break; + case DataItem::UNKNOWN: + cmi.type = CMakeConfigItem::UNINITIALIZED; + break; + } + cmi.isUnset = isUnset; + cmi.isAdvanced = isAdvanced; + cmi.isInitial = isInitial; + cmi.values = values; + cmi.documentation = description.toUtf8(); + + return cmi; +} + +// ConfigModel ConfigModel::ConfigModel(QObject *parent) : Utils::TreeModel<>(parent) { setHeader({tr("Key"), tr("Value")}); } +ConfigModel::~ConfigModel() = default; + QVariant ConfigModel::data(const QModelIndex &idx, int role) const { // Hide/show groups according to "isAdvanced" setting: @@ -76,8 +167,6 @@ bool ConfigModel::setData(const QModelIndex &idx, const QVariant &data, int role return res; } -ConfigModel::~ConfigModel() = default; - void ConfigModel::appendConfiguration(const QString &key, const QString &value, const ConfigModel::DataItem::Type type, bool isInitial, @@ -454,7 +543,6 @@ QString ConfigModel::InternalDataItem::currentValue() const return isUserChanged ? newValue : value; } -namespace Internal { ConfigModelTreeItem::~ConfigModelTreeItem() = default; diff --git a/src/plugins/cmakeprojectmanager/configmodel.h b/src/plugins/cmakeprojectmanager/configmodel.h index 11e4153b076..95b1ae383db 100644 --- a/src/plugins/cmakeprojectmanager/configmodel.h +++ b/src/plugins/cmakeprojectmanager/configmodel.h @@ -32,8 +32,9 @@ #include namespace CMakeProjectManager { +namespace Internal { -namespace Internal { class ConfigModelTreeItem; } +class ConfigModelTreeItem; class ConfigModel : public Utils::TreeModel<> { @@ -46,90 +47,18 @@ public: }; struct DataItem { - bool operator == (const DataItem& other) const { + bool operator==(const DataItem &other) const { return key == other.key && isInitial == other.isInitial; } DataItem() {} - DataItem(const CMakeConfigItem &cmi) { - key = QString::fromUtf8(cmi.key); - value = QString::fromUtf8(cmi.value); - description = QString::fromUtf8(cmi.documentation); - values = cmi.values; - inCMakeCache = cmi.inCMakeCache; + DataItem(const CMakeConfigItem &cmi); - isAdvanced = cmi.isAdvanced; - isInitial = cmi.isInitial; - isHidden = cmi.type == CMakeConfigItem::INTERNAL || cmi.type == CMakeConfigItem::STATIC; + void setType(CMakeConfigItem::Type cmt); - setType(cmi.type); - } + QString typeDisplay() const; - void setType(CMakeConfigItem::Type cmt) { - switch (cmt) { - case CMakeConfigItem::FILEPATH: - type = FILE; - break; - case CMakeConfigItem::PATH: - type = DIRECTORY; - break; - case CMakeConfigItem::BOOL: - type = BOOLEAN; - break; - case CMakeConfigItem::STRING: - type = STRING; - break; - default: - type = UNKNOWN; - break; - } - } - - QString typeDisplay() const { - switch (type) { - case DataItem::BOOLEAN: - return "BOOL"; - case DataItem::FILE: - return "FILEPATH"; - case DataItem::DIRECTORY: - return "PATH"; - case DataItem::STRING: - return "STRING"; - case DataItem::UNKNOWN: - break; - } - return "UNINITIALIZED"; - } - - CMakeConfigItem toCMakeConfigItem() const { - CMakeConfigItem cmi; - cmi.key = key.toUtf8(); - cmi.value = value.toUtf8(); - switch (type) { - case DataItem::BOOLEAN: - cmi.type = CMakeConfigItem::BOOL; - break; - case DataItem::FILE: - cmi.type = CMakeConfigItem::FILEPATH; - break; - case DataItem::DIRECTORY: - cmi.type = CMakeConfigItem::PATH; - break; - case DataItem::STRING: - cmi.type = CMakeConfigItem::STRING; - break; - case DataItem::UNKNOWN: - cmi.type = CMakeConfigItem::UNINITIALIZED; - break; - } - cmi.isUnset = isUnset; - cmi.isAdvanced = isAdvanced; - cmi.isInitial = isInitial; - cmi.values = values; - cmi.documentation = description.toUtf8(); - - return cmi; - } + CMakeConfigItem toCMakeConfigItem() const; enum Type { BOOLEAN, FILE, DIRECTORY, STRING, UNKNOWN}; @@ -214,8 +143,6 @@ private: friend class Internal::ConfigModelTreeItem; }; -namespace Internal { - class ConfigModelTreeItem : public Utils::TreeItem { public: diff --git a/src/plugins/cmakeprojectmanager/configmodelitemdelegate.cpp b/src/plugins/cmakeprojectmanager/configmodelitemdelegate.cpp index cacea4cb855..c09a6cd0d56 100644 --- a/src/plugins/cmakeprojectmanager/configmodelitemdelegate.cpp +++ b/src/plugins/cmakeprojectmanager/configmodelitemdelegate.cpp @@ -33,6 +33,7 @@ #include namespace CMakeProjectManager { +namespace Internal { ConfigModelItemDelegate::ConfigModelItemDelegate(const Utils::FilePath &base, QObject* parent) : QStyledItemDelegate(parent) @@ -131,8 +132,8 @@ void ConfigModelItemDelegate::setModelData(QWidget *editor, QAbstractItemModel * QStyledItemDelegate::setModelData(editor, model, index); } -QSize CMakeProjectManager::ConfigModelItemDelegate::sizeHint(const QStyleOptionViewItem &option, - const QModelIndex &index) const +QSize ConfigModelItemDelegate::sizeHint(const QStyleOptionViewItem &option, + const QModelIndex &index) const { static int height = -1; if (height < 0) { @@ -154,5 +155,6 @@ QSize CMakeProjectManager::ConfigModelItemDelegate::sizeHint(const QStyleOptionV return QSize(100, height); } +} // namespace Internal } // namespace CMakeProjectManager diff --git a/src/plugins/cmakeprojectmanager/configmodelitemdelegate.h b/src/plugins/cmakeprojectmanager/configmodelitemdelegate.h index 1c6d5927918..f6cacd57614 100644 --- a/src/plugins/cmakeprojectmanager/configmodelitemdelegate.h +++ b/src/plugins/cmakeprojectmanager/configmodelitemdelegate.h @@ -32,6 +32,7 @@ #include namespace CMakeProjectManager { +namespace Internal { class ConfigModelItemDelegate : public QStyledItemDelegate { @@ -51,4 +52,5 @@ private: Utils::FilePath m_base; }; +} // namespace Internal } // namespace CMakeProjectManager From 347265a9693682128145bb33ba99058cc4dfc3b0 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 7 Feb 2022 17:04:26 +0100 Subject: [PATCH 08/94] CMakePM: Use more direct access to SourceDirectoryAspect Change-Id: Ifc91b13fcdc9c42ad4a9521656a2bf63e08aaf78 Reviewed-by: Cristian Adam --- src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index fd249886941..2f4c082c70e 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -1633,12 +1633,12 @@ BuildSystem *CMakeBuildConfiguration::buildSystem() const void CMakeBuildConfiguration::setSourceDirectory(const FilePath &path) { - aspect()->setValue(path.toString()); + aspect()->setFilePath(path); } FilePath CMakeBuildConfiguration::sourceDirectory() const { - return FilePath::fromString(aspect()->value()); + return aspect()->filePath(); } QString CMakeBuildConfiguration::cmakeBuildType() const From 4f4d34bc5e0bb7445fb9a7e54d50c49d775ad765 Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Mon, 7 Feb 2022 18:33:35 +0100 Subject: [PATCH 09/94] QmlDesigner: Add missing color enum Change-Id: Ie72912393ff2ffedea8c9ddb3a4a97023fad001a Reviewed-by: Alessandro Portale --- src/libs/utils/theme/theme.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/utils/theme/theme.h b/src/libs/utils/theme/theme.h index 07f57bfa455..05839823188 100644 --- a/src/libs/utils/theme/theme.h +++ b/src/libs/utils/theme/theme.h @@ -310,6 +310,7 @@ public: DSerrorColor, DSwarningColor, DSdisabledColor, + DSinteractionHover, DScontrolBackground, DScontrolBackgroundInteraction, DScontrolBackgroundDisabled, From f132b09c4b28c41c18a1246047fae95df2e26039 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Fri, 4 Feb 2022 18:53:55 +0100 Subject: [PATCH 10/94] QmlDesigner: Use QmlProject::isQtDesignStudio() Use QmlProject::isQtDesignStudio() instead of checking various settings sources in order to determine which product is currently running. Change-Id: I3f08eb147e7dbbde3e2984d63c39d48c12530aaa Reviewed-by: Reviewed-by: Thomas Hartmann --- .../components/componentcore/designeractionmanager.cpp | 4 ++-- .../components/connectioneditor/connectionviewwidget.cpp | 3 ++- .../qmldesigner/components/navigator/navigatortreemodel.cpp | 4 +++- src/plugins/qmldesigner/designersettings.cpp | 1 - src/plugins/qmldesigner/designersettings.h | 1 - src/plugins/qmldesigner/qmldesignerplugin.cpp | 6 ++++-- src/plugins/qmldesigner/settingspage.cpp | 4 +++- 7 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp index e160f030dbf..959ba6772f0 100644 --- a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp +++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp @@ -50,6 +50,7 @@ #include #include +#include #include #include #include @@ -1471,8 +1472,7 @@ void DesignerActionManager::createDefaultDesignerActions() &singleSelection, &singleSelection)); - const bool standaloneMode - = Core::ICore::settings()->value(DesignerSettingsKey::STANDALONE_MODE).toBool(); + const bool standaloneMode = QmlProjectManager::QmlProject::isQtDesignStudio(); if (!standaloneMode) { addDesignerAction(new ModelNodeContextMenuAction(goToImplementationCommandId, diff --git a/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.cpp b/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.cpp index 2967b89da7a..de64139cb91 100644 --- a/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.cpp +++ b/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.cpp @@ -44,6 +44,7 @@ #include #include +#include #include #include @@ -97,7 +98,7 @@ ConnectionViewWidget::ConnectionViewWidget(QWidget *parent) : auto settings = QmlDesignerPlugin::instance()->settings(); - if (!settings.value(DesignerSettingsKey::STANDALONE_MODE).toBool()) + if (!QmlProjectManager::QmlProject::isQtDesignStudio()) ui->tabBar->addTab(tr("Backends", "Title of dynamic properties view")); ui->tabBar->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed); diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp index 7e7b650da82..8a8547a84a4 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp @@ -47,6 +47,8 @@ #include +#include + #include #include #include @@ -226,7 +228,7 @@ QVariant NavigatorTreeModel::data(const QModelIndex &index, int role) const } else if (role == Qt::ToolTipRole) { if (currentQmlObjectNode.hasError()) { QString errorString = currentQmlObjectNode.error(); - if (DesignerSettings::getValue(DesignerSettingsKey::STANDALONE_MODE).toBool() + if (QmlProjectManager::QmlProject::isQtDesignStudio() && currentQmlObjectNode.isRootNode()) { errorString.append(QString("\n%1").arg(tr("Changing the setting \"%1\" might solve the issue.").arg( tr("Use QML emulation layer that is built with the selected Qt")))); diff --git a/src/plugins/qmldesigner/designersettings.cpp b/src/plugins/qmldesigner/designersettings.cpp index 8ecaaa6edd9..aad91e06b48 100644 --- a/src/plugins/qmldesigner/designersettings.cpp +++ b/src/plugins/qmldesigner/designersettings.cpp @@ -74,7 +74,6 @@ void DesignerSettings::fromSettings(QSettings *settings) restoreValue(settings, DesignerSettingsKey::IGNORE_DEVICE_PIXEL_RATIO, false); restoreValue(settings, DesignerSettingsKey::NAVIGATOR_SHOW_ONLY_VISIBLE_ITEMS, true); restoreValue(settings, DesignerSettingsKey::NAVIGATOR_REVERSE_ITEM_ORDER, false); - restoreValue(settings, DesignerSettingsKey::STANDALONE_MODE, false); restoreValue(settings, DesignerSettingsKey::ENABLE_TIMELINEVIEW, true); restoreValue(settings, DesignerSettingsKey::COLOR_PALETTE_RECENT, QStringList()); restoreValue(settings, DesignerSettingsKey::COLOR_PALETTE_FAVORITE, QStringList()); diff --git a/src/plugins/qmldesigner/designersettings.h b/src/plugins/qmldesigner/designersettings.h index bb25e2e04c9..2fbc09f248c 100644 --- a/src/plugins/qmldesigner/designersettings.h +++ b/src/plugins/qmldesigner/designersettings.h @@ -64,7 +64,6 @@ const char NAVIGATOR_SHOW_ONLY_VISIBLE_ITEMS[] = "NavigatorShowOnlyVisibleItems" const char NAVIGATOR_REVERSE_ITEM_ORDER[] = "NavigatorReverseItemOrder"; const char REFORMAT_UI_QML_FILES[] = "ReformatUiQmlFiles"; /* These settings are not exposed in ui. */ const char IGNORE_DEVICE_PIXEL_RATIO[] = "IgnoreDevicePixelRaio"; /* The settings can be used to turn off the feature, if there are serious issues */ -const char STANDALONE_MODE[] = "StandAloneMode"; const char SHOW_DEBUG_SETTINGS[] = "ShowDebugSettings"; const char ENABLE_TIMELINEVIEW[] = "EnableTimelineView"; const char COLOR_PALETTE_RECENT[] = "ColorPaletteRecent"; diff --git a/src/plugins/qmldesigner/qmldesignerplugin.cpp b/src/plugins/qmldesigner/qmldesignerplugin.cpp index 35f21ced65a..ec4957bcc9d 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.cpp +++ b/src/plugins/qmldesigner/qmldesignerplugin.cpp @@ -53,6 +53,8 @@ #include +#include + #include #include #include @@ -224,7 +226,7 @@ bool QmlDesignerPlugin::initialize(const QStringList & /*arguments*/, QString *e if (!Utils::HostOsInfo::canCreateOpenGLContext(errorMessage)) return false; d = new QmlDesignerPluginPrivate; - if (DesignerSettings::getValue(DesignerSettingsKey::STANDALONE_MODE).toBool()) + if (QmlProjectManager::QmlProject::isQtDesignStudio()) GenerateResource::generateMenuEntry(); GenerateCmake::generateMenuEntry(); @@ -308,7 +310,7 @@ bool QmlDesignerPlugin::delayedInitialize() d->viewManager.registerFormEditorTool(std::make_unique()); d->viewManager.registerFormEditorTool(std::make_unique()); - if (DesignerSettings::getValue(DesignerSettingsKey::STANDALONE_MODE).toBool()) + if (QmlProjectManager::QmlProject::isQtDesignStudio()) emitUsageStatistics("StandaloneMode"); return true; diff --git a/src/plugins/qmldesigner/settingspage.cpp b/src/plugins/qmldesigner/settingspage.cpp index 30e06946d85..23e0a948067 100644 --- a/src/plugins/qmldesigner/settingspage.cpp +++ b/src/plugins/qmldesigner/settingspage.cpp @@ -37,6 +37,8 @@ #include #include +#include + #include #include @@ -252,7 +254,7 @@ void SettingsPageWidget::setSettings(const DesignerSettings &settings) m_ui.askBeforeDeletingAssetCheckBox->setChecked(settings.value( DesignerSettingsKey::ASK_BEFORE_DELETING_ASSET).toBool()); - const auto standaloneMode = settings.value(DesignerSettingsKey::STANDALONE_MODE).toBool(); + const bool standaloneMode = QmlProjectManager::QmlProject::isQtDesignStudio(); #ifdef QT_DEBUG const auto showDebugSettings = true; #else From ccad4fa924d225f424321d5e07fec3d2ede63a71 Mon Sep 17 00:00:00 2001 From: Aaron Barany Date: Fri, 4 Feb 2022 17:11:00 -0800 Subject: [PATCH 11/94] CMake: Better detect imported tool locations On some systems IMPORTED_LOCATION isn't set, but configuration-specific locations like IMPORTED_LOCATION_RELEASE are. In these cases, fall back to the location of the release build if the default isn't found. Fixes the build on Arch Linux. Change-Id: Iff87a8356302a260b2ac5f959f835d1cdf8a5c65 Reviewed-by: Eike Ziller --- cmake/FindQt5.cmake | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmake/FindQt5.cmake b/cmake/FindQt5.cmake index 1931bf019c2..a48e293e416 100644 --- a/cmake/FindQt5.cmake +++ b/cmake/FindQt5.cmake @@ -83,6 +83,10 @@ foreach(tool qmake lrelease lupdate moc rcc qhelpgenerator) if (TARGET Qt6::${tool} AND NOT TARGET Qt5::${tool}) add_executable(Qt5::${tool} IMPORTED GLOBAL) get_target_property(imported_location Qt6::${tool} IMPORTED_LOCATION) + # handle separate tools for each configuration + if (NOT imported_location) + get_target_property(imported_location Qt6::${tool} IMPORTED_LOCATION_RELEASE) + endif() set_target_properties(Qt5::${tool} PROPERTIES IMPORTED_LOCATION "${imported_location}") endif() endforeach() From 03a0ed07863490676695c2b7e89f82ec2837b493 Mon Sep 17 00:00:00 2001 From: Aaron Barany Date: Fri, 4 Feb 2022 16:37:59 -0800 Subject: [PATCH 12/94] Debugger: Use queued connection for menu actions Pass the parent calling object to the addAction() functions and use a queued connection. This prevents the following sequence of events: 1. The menu is dismissed when selecting a menu item. 2. The deletion gets queued via deleteLater(). 2. The onTriggered action gets invoked and opens a dialog box. 3. The dialog box triggers the events to be processed. 4. The menu is deleted when processing the events, while still in the event function to handle the dismissal. This only affected the watch menu since the others were leaked. Added cleanup handlers for the other debugger menus to avoid leaking them. Task-number: QTCREATORBUG-26989 Change-Id: Ifa2c52d7bea884c55d43fa545e3e2870301e4052 Reviewed-by: hjk --- src/plugins/debugger/breakhandler.cpp | 28 ++++---- src/plugins/debugger/debuggercore.h | 9 +-- src/plugins/debugger/debuggerplugin.cpp | 27 +++++--- src/plugins/debugger/moduleshandler.cpp | 19 +++--- .../debugger/peripheralregisterhandler.cpp | 17 ++--- src/plugins/debugger/registerhandler.cpp | 18 ++--- src/plugins/debugger/stackhandler.cpp | 19 +++--- src/plugins/debugger/watchhandler.cpp | 66 +++++++++---------- 8 files changed, 110 insertions(+), 93 deletions(-) diff --git a/src/plugins/debugger/breakhandler.cpp b/src/plugins/debugger/breakhandler.cpp index 35b1c30449d..0b577eb6e57 100644 --- a/src/plugins/debugger/breakhandler.cpp +++ b/src/plugins/debugger/breakhandler.cpp @@ -1615,9 +1615,9 @@ bool BreakHandler::contextMenuEvent(const ItemViewEvent &ev) auto menu = new QMenu; - addAction(menu, tr("Add Breakpoint..."), true, &BreakpointManager::executeAddBreakpointDialog); + addAction(this, menu, tr("Add Breakpoint..."), true, &BreakpointManager::executeAddBreakpointDialog); - addAction(menu, tr("Delete Selected Breakpoints"), + addAction(this, menu, tr("Delete Selected Breakpoints"), !selectedBreakpoints.isEmpty(), [selectedBreakpoints] { for (Breakpoint bp : selectedBreakpoints) { @@ -1629,7 +1629,7 @@ bool BreakHandler::contextMenuEvent(const ItemViewEvent &ev) } }); - addAction(menu, tr("Edit Selected Breakpoints..."), + addAction(this, menu, tr("Edit Selected Breakpoints..."), !selectedBreakpoints.isEmpty(), [this, selectedBreakpoints, ev] { editBreakpoints(selectedBreakpoints, ev.view()); }); @@ -1645,7 +1645,7 @@ bool BreakHandler::contextMenuEvent(const ItemViewEvent &ev) // bp.setThreadSpec(threadId); // }); - addAction(menu, + addAction(this, menu, selectedBreakpoints.size() > 1 ? breakpointsEnabled ? tr("Disable Selected Breakpoints") : tr("Enable Selected Breakpoints") : breakpointsEnabled ? tr("Disable Breakpoint") : tr("Enable Breakpoint"), @@ -1659,7 +1659,7 @@ bool BreakHandler::contextMenuEvent(const ItemViewEvent &ev) } ); - addAction(menu, + addAction(this, menu, selectedLocations.size() > 1 ? locationsEnabled ? tr("Disable Selected Locations") : tr("Enable Selected Locations") : locationsEnabled ? tr("Disable Location") : tr("Enable Location"), @@ -1672,7 +1672,7 @@ bool BreakHandler::contextMenuEvent(const ItemViewEvent &ev) menu->addSeparator(); - addAction(menu, tr("Delete All Breakpoints"), + addAction(this, menu, tr("Delete All Breakpoints"), rowCount() > 0, &BreakpointManager::executeDeleteAllBreakpointsDialog); @@ -1687,7 +1687,7 @@ bool BreakHandler::contextMenuEvent(const ItemViewEvent &ev) breakpointsInFile.append(findBreakpointByIndex(index)); } } - addAction(menu, tr("Delete Breakpoints of \"%1\"").arg(file), + addAction(this, menu, tr("Delete Breakpoints of \"%1\"").arg(file), tr("Delete Breakpoints of File"), breakpointsInFile.size() > 1, [breakpointsInFile] { @@ -1700,6 +1700,7 @@ bool BreakHandler::contextMenuEvent(const ItemViewEvent &ev) menu->addAction(debuggerSettings()->useToolTipsInBreakpointsView.action()); menu->addAction(debuggerSettings()->settingsDialog.action()); + connect(menu, &QMenu::aboutToHide, menu, &QObject::deleteLater); menu->popup(ev.globalPos()); return true; @@ -2640,20 +2641,20 @@ bool BreakpointManager::contextMenuEvent(const ItemViewEvent &ev) auto menu = new QMenu; - addAction(menu, tr("Add Breakpoint..."), true, &BreakpointManager::executeAddBreakpointDialog); + addAction(this, menu, tr("Add Breakpoint..."), true, &BreakpointManager::executeAddBreakpointDialog); - addAction(menu, tr("Delete Selected Breakpoints"), + addAction(this, menu, tr("Delete Selected Breakpoints"), !selectedBreakpoints.isEmpty(), [selectedBreakpoints] { for (GlobalBreakpoint gbp : selectedBreakpoints) gbp->deleteBreakpoint(); }); - addAction(menu, tr("Edit Selected Breakpoints..."), + addAction(this, menu, tr("Edit Selected Breakpoints..."), !selectedBreakpoints.isEmpty(), [this, selectedBreakpoints, ev] { editBreakpoints(selectedBreakpoints, ev.view()); }); - addAction(menu, + addAction(this, menu, selectedBreakpoints.size() > 1 ? breakpointsEnabled ? tr("Disable Selected Breakpoints") : tr("Enable Selected Breakpoints") : breakpointsEnabled ? tr("Disable Breakpoint") : tr("Enable Breakpoint"), @@ -2666,7 +2667,7 @@ bool BreakpointManager::contextMenuEvent(const ItemViewEvent &ev) menu->addSeparator(); - addAction(menu, tr("Delete All Breakpoints"), + addAction(this, menu, tr("Delete All Breakpoints"), rowCount() > 0, &BreakpointManager::executeDeleteAllBreakpointsDialog); @@ -2682,7 +2683,7 @@ bool BreakpointManager::contextMenuEvent(const ItemViewEvent &ev) }); } } - addAction(menu, tr("Delete Breakpoints of \"%1\"").arg(file.toUserOutput()), + addAction(this, menu, tr("Delete Breakpoints of \"%1\"").arg(file.toUserOutput()), tr("Delete Breakpoints of File"), breakpointsInFile.size() > 1, [breakpointsInFile] { @@ -2695,6 +2696,7 @@ bool BreakpointManager::contextMenuEvent(const ItemViewEvent &ev) menu->addAction(debuggerSettings()->useToolTipsInBreakpointsView.action()); menu->addAction(debuggerSettings()->settingsDialog.action()); + connect(menu, &QMenu::aboutToHide, menu, &QObject::deleteLater); menu->popup(ev.globalPos()); return true; diff --git a/src/plugins/debugger/debuggercore.h b/src/plugins/debugger/debuggercore.h index bd228b2560f..e4123d3cdd5 100644 --- a/src/plugins/debugger/debuggercore.h +++ b/src/plugins/debugger/debuggercore.h @@ -32,6 +32,7 @@ #include QT_BEGIN_NAMESPACE +class QObject; class QWidget; class QMenu; class QAction; @@ -53,12 +54,12 @@ void openTextEditor(const QString &titlePattern, const QString &contents); bool isTestRun(); -QAction *addAction(QMenu *menu, const QString &display, bool on, +QAction *addAction(const QObject *parent, QMenu *menu, const QString &display, bool on, const std::function &onTriggered = {}); -QAction *addAction(QMenu *menu, const QString &d1, const QString &d2, bool on, +QAction *addAction(const QObject *parent, QMenu *menu, const QString &d1, const QString &d2, bool on, const std::function &onTriggered); -QAction *addCheckableAction(QMenu *menu, const QString &display, bool on, bool checked, - const std::function &onTriggered); +QAction *addCheckableAction(const QObject *parent, QMenu *menu, const QString &display, bool on, + bool checked, const std::function &onTriggered); // Qt's various build paths for unpatched versions QStringList qtBuildPaths(); diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index ae727383d26..cec08760aab 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -428,25 +428,33 @@ static QIcon interruptIcon(bool toolBarStyle) return toolBarStyle ? iconToolBar : icon; } -QAction *addAction(QMenu *menu, const QString &display, bool on, +QAction *addAction(const QObject *parent, QMenu *menu, const QString &display, bool on, const std::function &onTriggered) { QAction *act = menu->addAction(display); act->setEnabled(on); - QObject::connect(act, &QAction::triggered, onTriggered); + // Always queue the connection to prevent the following sequence of events if the menu cleans + // itself up on dismissal: + // 1. The menu is dismissed when selecting a menu item. + // 2. The deletion gets queued via deleteLater(). + // 2. The onTriggered action gets invoked and opens a dialog box. + // 3. The dialog box triggers the events to be processed. + // 4. The menu is deleted when processing the events, while still in the event function to + // handle the dismissal. + QObject::connect(act, &QAction::triggered, parent, onTriggered, Qt::QueuedConnection); return act; }; -QAction *addAction(QMenu *menu, const QString &d1, const QString &d2, bool on, +QAction *addAction(const QObject *parent, QMenu *menu, const QString &d1, const QString &d2, bool on, const std::function &onTriggered) { - return on ? addAction(menu, d1, true, onTriggered) : addAction(menu, d2, false); + return on ? addAction(parent, menu, d1, true, onTriggered) : addAction(parent, menu, d2, false); }; -QAction *addCheckableAction(QMenu *menu, const QString &display, bool on, bool checked, - const std::function &onTriggered) +QAction *addCheckableAction(const QObject *parent, QMenu *menu, const QString &display, bool on, + bool checked, const std::function &onTriggered) { - QAction *act = addAction(menu, display, on, onTriggered); + QAction *act = addAction(parent, menu, display, on, onTriggered); act->setCheckable(true); act->setChecked(checked); return act; @@ -1186,8 +1194,9 @@ DebuggerPluginPrivate::DebuggerPluginPrivate(const QStringList &arguments) this, &DebuggerPluginPrivate::updateBreakMenuItem); // Application interaction - connect(debuggerSettings()->settingsDialog.action(), &QAction::triggered, - [] { ICore::showOptionsDialog(DEBUGGER_COMMON_SETTINGS_ID); }); + // Use a queued connection so the dialog isn't triggered in the same event. + connect(debuggerSettings()->settingsDialog.action(), &QAction::triggered, this, + [] { ICore::showOptionsDialog(DEBUGGER_COMMON_SETTINGS_ID); }, Qt::QueuedConnection); m_perspective.useSubPerspectiveSwitcher(EngineManager::engineChooser()); m_perspective.addToolBarAction(&m_startAction); diff --git a/src/plugins/debugger/moduleshandler.cpp b/src/plugins/debugger/moduleshandler.cpp index e894042c2d8..a040c7f1feb 100644 --- a/src/plugins/debugger/moduleshandler.cpp +++ b/src/plugins/debugger/moduleshandler.cpp @@ -179,51 +179,52 @@ bool ModulesModel::contextMenuEvent(const ItemViewEvent &ev) auto menu = new QMenu; - addAction(menu, tr("Update Module List"), + addAction(this, menu, tr("Update Module List"), enabled && canReload, [this] { engine->reloadModules(); }); - addAction(menu, tr("Show Source Files for Module \"%1\"").arg(moduleName), + addAction(this, menu, tr("Show Source Files for Module \"%1\"").arg(moduleName), tr("Show Source Files for Module"), moduleNameValid && enabled && canReload, [this, modulePath] { engine->loadSymbols(modulePath); }); // FIXME: Dependencies only available on Windows, when "depends" is installed. - addAction(menu, tr("Show Dependencies of \"%1\"").arg(moduleName), + addAction(this, menu, tr("Show Dependencies of \"%1\"").arg(moduleName), tr("Show Dependencies"), moduleNameValid && !moduleName.isEmpty() && HostOsInfo::isWindowsHost(), [modulePath] { QtcProcess::startDetached({{"depends"}, {modulePath}}); }); - addAction(menu, tr("Load Symbols for All Modules"), + addAction(this, menu, tr("Load Symbols for All Modules"), enabled && canLoadSymbols, [this] { engine->loadAllSymbols(); }); - addAction(menu, tr("Examine All Modules"), + addAction(this, menu, tr("Examine All Modules"), enabled && canLoadSymbols, [this] { engine->examineModules(); }); - addAction(menu, tr("Load Symbols for Module \"%1\"").arg(moduleName), + addAction(this, menu, tr("Load Symbols for Module \"%1\"").arg(moduleName), tr("Load Symbols for Module"), moduleNameValid && canLoadSymbols, [this, modulePath] { engine->loadSymbols(modulePath); }); - addAction(menu, tr("Edit File \"%1\"").arg(moduleName), + addAction(this, menu, tr("Edit File \"%1\"").arg(moduleName), tr("Edit File"), moduleNameValid, [this, modulePath] { engine->gotoLocation(FilePath::fromString(modulePath)); }); - addAction(menu, tr("Show Symbols in File \"%1\"").arg(moduleName), + addAction(this, menu, tr("Show Symbols in File \"%1\"").arg(moduleName), tr("Show Symbols"), canShowSymbols && moduleNameValid, [this, modulePath] { engine->requestModuleSymbols(modulePath); }); - addAction(menu, tr("Show Sections in File \"%1\"").arg(moduleName), + addAction(this, menu, tr("Show Sections in File \"%1\"").arg(moduleName), tr("Show Sections"), canShowSymbols && moduleNameValid, [this, modulePath] { engine->requestModuleSections(modulePath); }); menu->addAction(debuggerSettings()->settingsDialog.action()); + connect(menu, &QMenu::aboutToHide, menu, &QObject::deleteLater); menu->popup(ev.globalPos()); return true; } diff --git a/src/plugins/debugger/peripheralregisterhandler.cpp b/src/plugins/debugger/peripheralregisterhandler.cpp index 3f466ab1805..2cdf51c9773 100644 --- a/src/plugins/debugger/peripheralregisterhandler.cpp +++ b/src/plugins/debugger/peripheralregisterhandler.cpp @@ -799,6 +799,7 @@ bool PeripheralRegisterHandler::contextMenuEvent(const ItemViewEvent &ev) } menu->addAction(debuggerSettings()->settingsDialog.action()); + connect(menu, &QMenu::aboutToHide, menu, &QObject::deleteLater); menu->popup(ev.globalPos()); return true; } @@ -841,7 +842,7 @@ QMenu *PeripheralRegisterHandler::createRegisterFormatMenu( // Hexadecimal action. const auto hexAct = addCheckableAction( - fmtMenu, tr("Hexadecimal"), on, + this, fmtMenu, tr("Hexadecimal"), on, fmt == PeripheralRegisterFormat::Hexadecimal, [item] { item->m_reg.format = PeripheralRegisterFormat::Hexadecimal; @@ -851,7 +852,7 @@ QMenu *PeripheralRegisterHandler::createRegisterFormatMenu( // Decimal action. const auto decAct = addCheckableAction( - fmtMenu, tr("Decimal"), on, + this, fmtMenu, tr("Decimal"), on, fmt == PeripheralRegisterFormat::Decimal, [item] { item->m_reg.format = PeripheralRegisterFormat::Decimal; @@ -861,7 +862,7 @@ QMenu *PeripheralRegisterHandler::createRegisterFormatMenu( // Octal action. const auto octAct = addCheckableAction( - fmtMenu, tr("Octal"), on, + this, fmtMenu, tr("Octal"), on, fmt == PeripheralRegisterFormat::Octal, [item] { item->m_reg.format = PeripheralRegisterFormat::Octal; @@ -871,7 +872,7 @@ QMenu *PeripheralRegisterHandler::createRegisterFormatMenu( // Binary action. const auto binAct = addCheckableAction( - fmtMenu, tr("Binary"), on, + this, fmtMenu, tr("Binary"), on, fmt == PeripheralRegisterFormat::Binary, [item] { item->m_reg.format = PeripheralRegisterFormat::Binary; @@ -895,7 +896,7 @@ QMenu *PeripheralRegisterHandler::createRegisterFieldFormatMenu( // Hexadecimal action. const auto hexAct = addCheckableAction( - fmtMenu, tr("Hexadecimal"), on, + this, fmtMenu, tr("Hexadecimal"), on, fmt == PeripheralRegisterFormat::Hexadecimal, [item] { item->m_fld.format = PeripheralRegisterFormat::Hexadecimal; @@ -905,7 +906,7 @@ QMenu *PeripheralRegisterHandler::createRegisterFieldFormatMenu( // Decimal action. const auto decAct = addCheckableAction( - fmtMenu, tr("Decimal"), on, + this, fmtMenu, tr("Decimal"), on, fmt == PeripheralRegisterFormat::Decimal, [item] { item->m_fld.format = PeripheralRegisterFormat::Decimal; @@ -915,7 +916,7 @@ QMenu *PeripheralRegisterHandler::createRegisterFieldFormatMenu( // Octal action. const auto octAct = addCheckableAction( - fmtMenu, tr("Octal"), on, + this, fmtMenu, tr("Octal"), on, fmt == PeripheralRegisterFormat::Octal, [item] { item->m_fld.format = PeripheralRegisterFormat::Octal; @@ -925,7 +926,7 @@ QMenu *PeripheralRegisterHandler::createRegisterFieldFormatMenu( // Binary action. const auto binAct = addCheckableAction( - fmtMenu, tr("Binary"), on, + this, fmtMenu, tr("Binary"), on, fmt == PeripheralRegisterFormat::Binary, [item] { item->m_fld.format = PeripheralRegisterFormat::Binary; diff --git a/src/plugins/debugger/registerhandler.cpp b/src/plugins/debugger/registerhandler.cpp index 7ed8af63001..1dbafd23f3a 100644 --- a/src/plugins/debugger/registerhandler.cpp +++ b/src/plugins/debugger/registerhandler.cpp @@ -764,14 +764,14 @@ bool RegisterHandler::contextMenuEvent(const ItemViewEvent &ev) auto menu = new QMenu; - addAction(menu, tr("Reload Register Listing"), + addAction(this, menu, tr("Reload Register Listing"), m_engine->hasCapability(RegisterCapability) && (state == InferiorStopOk || state == InferiorUnrunnable), [this] { m_engine->reloadRegisters(); }); menu->addSeparator(); - addAction(menu, tr("Open Memory View at Value of Register %1 0x%2") + addAction(this, menu, tr("Open Memory View at Value of Register %1 0x%2") .arg(registerName).arg(address, 0, 16), tr("Open Memory View at Value of Register"), address, @@ -784,7 +784,7 @@ bool RegisterHandler::contextMenuEvent(const ItemViewEvent &ev) m_engine->openMemoryView(data); }); - addAction(menu, tr("Open Memory Editor at 0x%1").arg(address, 0, 16), + addAction(this, menu, tr("Open Memory Editor at 0x%1").arg(address, 0, 16), tr("Open Memory Editor"), address && actionsEnabled && m_engine->hasCapability(ShowMemoryCapability), [this, registerName, address] { @@ -796,12 +796,12 @@ bool RegisterHandler::contextMenuEvent(const ItemViewEvent &ev) m_engine->openMemoryView(data); }); - addAction(menu, tr("Open Disassembler at 0x%1").arg(address, 0, 16), + addAction(this, menu, tr("Open Disassembler at 0x%1").arg(address, 0, 16), tr("Open Disassembler"), address && m_engine->hasCapability(DisassemblerCapability), [this, address] { m_engine->openDisassemblerView(Location(address)); }); - addAction(menu, tr("Open Disassembler..."), + addAction(this, menu, tr("Open Disassembler..."), m_engine->hasCapability(DisassemblerCapability), [this, address] { AddressDialog dialog; @@ -820,9 +820,10 @@ bool RegisterHandler::contextMenuEvent(const ItemViewEvent &ev) : HexadecimalFormat; auto addFormatAction = - [menu, currentFormat, registerItem](const QString &display, RegisterFormat format) { - addCheckableAction(menu, display, registerItem, currentFormat == format, - [registerItem, format] { + [this, menu, currentFormat, registerItem]( + const QString &display, RegisterFormat format) { + addCheckableAction(this, menu, display, registerItem, currentFormat == format, + [registerItem, format] { registerItem->m_format = format; registerItem->update(); }); @@ -834,6 +835,7 @@ bool RegisterHandler::contextMenuEvent(const ItemViewEvent &ev) addFormatAction(tr("Binary"), BinaryFormat); menu->addAction(debuggerSettings()->settingsDialog.action()); + connect(menu, &QMenu::aboutToHide, menu, &QObject::deleteLater); menu->popup(ev.globalPos()); return true; } diff --git a/src/plugins/debugger/stackhandler.cpp b/src/plugins/debugger/stackhandler.cpp index 488c6649b10..c42c196b09f 100644 --- a/src/plugins/debugger/stackhandler.cpp +++ b/src/plugins/debugger/stackhandler.cpp @@ -457,24 +457,24 @@ bool StackHandler::contextMenuEvent(const ItemViewEvent &ev) menu->addAction(debuggerSettings()->expandStack.action()); - addAction(menu, tr("Copy Contents to Clipboard"), true, [ev] { + addAction(this, menu, tr("Copy Contents to Clipboard"), true, [ev] { copyTextToClipboard(selectedText(ev.view(), true)); }); - addAction(menu, tr("Copy Selection to Clipboard"), true, [ev] { + addAction(this, menu, tr("Copy Selection to Clipboard"), true, [ev] { copyTextToClipboard(selectedText(ev.view(), false)); }); - addAction(menu, tr("Save as Task File..."), true, [this] { saveTaskFile(); }); + addAction(this, menu, tr("Save as Task File..."), true, [this] { saveTaskFile(); }); if (m_engine->hasCapability(CreateFullBacktraceCapability)) menu->addAction(debuggerSettings()->createFullBacktrace.action()); if (m_engine->hasCapability(AdditionalQmlStackCapability)) - addAction(menu, tr("Load QML Stack"), true, [this] { m_engine->loadAdditionalQmlStack(); }); + addAction(this, menu, tr("Load QML Stack"), true, [this] { m_engine->loadAdditionalQmlStack(); }); if (m_engine->hasCapability(ShowMemoryCapability)) - addAction(menu, tr("Open Memory Editor at 0x%1").arg(address, 0, 16), + addAction(this, menu, tr("Open Memory Editor at 0x%1").arg(address, 0, 16), tr("Open Memory Editor"), address, [this, row, frame, address] { @@ -488,12 +488,12 @@ bool StackHandler::contextMenuEvent(const ItemViewEvent &ev) }); if (m_engine->hasCapability(DisassemblerCapability)) { - addAction(menu, tr("Open Disassembler at 0x%1").arg(address, 0, 16), + addAction(this, menu, tr("Open Disassembler at 0x%1").arg(address, 0, 16), tr("Open Disassembler"), address, [this, frame] { m_engine->openDisassemblerView(frame); }); - addAction(menu, tr("Open Disassembler at Address..."), true, + addAction(this, menu, tr("Open Disassembler at Address..."), true, [this, address] { AddressDialog dialog; if (address) @@ -502,7 +502,7 @@ bool StackHandler::contextMenuEvent(const ItemViewEvent &ev) m_engine->openDisassemblerView(Location(dialog.address())); }); - addAction(menu, tr("Disassemble Function..."), true, + addAction(this, menu, tr("Disassemble Function..."), true, [this] { const StackFrame frame = inputFunctionForDisassembly(); if (!frame.function.isEmpty()) @@ -511,13 +511,14 @@ bool StackHandler::contextMenuEvent(const ItemViewEvent &ev) } if (m_engine->hasCapability(ShowModuleSymbolsCapability)) { - addAction(menu, tr("Try to Load Unknown Symbols"), true, + addAction(this, menu, tr("Try to Load Unknown Symbols"), true, [this] { m_engine->loadSymbolsForStack(); }); } menu->addSeparator(); menu->addAction(debuggerSettings()->useToolTipsInStackView.action()); menu->addAction(debuggerSettings()->settingsDialog.action()); + connect(menu, &QMenu::aboutToHide, menu, &QObject::deleteLater); menu->popup(ev.globalPos()); return true; } diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index bc1e57206c1..8818ceb4fd3 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -1720,24 +1720,24 @@ bool WatchModel::contextMenuEvent(const ItemViewEvent &ev) auto menu = new QMenu; - addAction(menu, tr("Add New Expression Evaluator..."), + addAction(this, menu, tr("Add New Expression Evaluator..."), canHandleWatches && canInsertWatches, [this] { inputNewExpression(); }); - addAction(menu, addWatchActionText(exp), + addAction(this, menu, addWatchActionText(exp), // Suppress for top-level watchers. canHandleWatches && !exp.isEmpty() && item && !(item->level() == 2 && item->isWatcher()), [this, exp, name] { m_handler->watchExpression(exp, name); }); - addAction(menu, removeWatchActionText(exp), + addAction(this, menu, removeWatchActionText(exp), canRemoveWatches && !exp.isEmpty() && item && item->isWatcher(), [this, item] { removeWatchItem(item); }); - addAction(menu, tr("Remove All Expression Evaluators"), + addAction(this, menu, tr("Remove All Expression Evaluators"), canRemoveWatches && !WatchHandler::watchedExpressions().isEmpty(), [this] { clearWatches(); }); - addAction(menu, tr("Select Widget to Add into Expression Evaluator"), + addAction(this, menu, tr("Select Widget to Add into Expression Evaluator"), state == InferiorRunOk && m_engine->hasCapability(WatchWidgetsCapability), [this] { grabWidget(); }); @@ -1757,7 +1757,7 @@ bool WatchModel::contextMenuEvent(const ItemViewEvent &ev) menu->addMenu(createBreakpointMenu(item, menu)); menu->addSeparator(); - addAction(menu, tr("Expand All Children"), item, [this, name = item ? item->iname : QString()] { + addAction(this, menu, tr("Expand All Children"), item, [this, name = item ? item->iname : QString()] { m_expandedINames.insert(name); if (auto item = findItem(name)) { item->forFirstLevelChildren( @@ -1766,7 +1766,7 @@ bool WatchModel::contextMenuEvent(const ItemViewEvent &ev) } }); - addAction(menu, tr("Collapse All Children"), item, [this, name = item ? item->iname : QString()] { + addAction(this, menu, tr("Collapse All Children"), item, [this, name = item ? item->iname : QString()] { if (auto item = findItem(name)) { item->forFirstLevelChildren( [this](WatchItem *child) { m_expandedINames.remove(child->iname); }); @@ -1774,15 +1774,15 @@ bool WatchModel::contextMenuEvent(const ItemViewEvent &ev) } }); - addAction(menu, tr("Close Editor Tooltips"), + addAction(this, menu, tr("Close Editor Tooltips"), m_engine->toolTipManager()->hasToolTips(), [this] { m_engine->toolTipManager()->closeAllToolTips(); }); - addAction(menu, tr("Copy View Contents to Clipboard"), + addAction(this, menu, tr("Copy View Contents to Clipboard"), true, [this] { copyToClipboard(editorContents()); }); - addAction(menu, + addAction(this, menu, tr("Copy Current Value to Clipboard"), item, [this, name = item ? item->iname : QString()] { @@ -1794,7 +1794,7 @@ bool WatchModel::contextMenuEvent(const ItemViewEvent &ev) // selectionModel()->hasSelection(), // [this] { copyToClipboard(editorContents(selectionModel()->selectedRows())); }); - addAction(menu, tr("Open View Contents in Editor"), + addAction(this, menu, tr("Open View Contents in Editor"), m_engine->debuggerActionsEnabled(), [this] { Internal::openTextEditor(tr("Locals & Expressions"), editorContents()); }); @@ -1827,7 +1827,7 @@ QMenu *WatchModel::createBreakpointMenu(WatchItem *item, QWidget *parent) const bool canSetWatchpoint = m_engine->hasCapability(WatchpointByAddressCapability); const bool createPointerActions = item->origaddr && item->origaddr != item->address; - act = addAction(menu, tr("Add Data Breakpoint at Object's Address (0x%1)").arg(item->address, 0, 16), + act = addAction(this, menu, tr("Add Data Breakpoint at Object's Address (0x%1)").arg(item->address, 0, 16), tr("Add Data Breakpoint"), canSetWatchpoint && item->address, [bh, item] { bh->setWatchpointAtAddress(item->address, item->size); }); @@ -1836,7 +1836,7 @@ QMenu *WatchModel::createBreakpointMenu(WatchItem *item, QWidget *parent) act->setChecked(bh->findWatchpoint(bp)); act->setToolTip(tr("Stop the program when the data at the address is modified.")); - act = addAction(menu, tr("Add Data Breakpoint at Pointer's Address (0x%1)").arg(item->origaddr, 0, 16), + act = addAction(this, menu, tr("Add Data Breakpoint at Pointer's Address (0x%1)").arg(item->origaddr, 0, 16), tr("Add Data Breakpoint at Pointer's Address"), canSetWatchpoint && item->address && createPointerActions, // FIXME: an approximation. This should be target's sizeof(void) @@ -1847,7 +1847,7 @@ QMenu *WatchModel::createBreakpointMenu(WatchItem *item, QWidget *parent) act->setChecked(bh->findWatchpoint(bp)); } - act = addAction(menu, tr("Add Data Breakpoint at Expression \"%1\"").arg(item->name), + act = addAction(this, menu, tr("Add Data Breakpoint at Expression \"%1\"").arg(item->name), tr("Add Data Breakpoint at Expression"), m_engine->hasCapability(WatchpointByExpressionCapability) && !item->name.isEmpty(), [bh, item] { bh->setWatchpointAtExpression(item->name); }); @@ -1869,37 +1869,37 @@ QMenu *WatchModel::createMemoryMenu(WatchItem *item, QWidget *parent) QPoint pos = QPoint(100, 100); // ev->globalPos - addAction(menu, tr("Open Memory View at Object's Address (0x%1)").arg(item->address, 0, 16), + addAction(this, menu, tr("Open Memory View at Object's Address (0x%1)").arg(item->address, 0, 16), tr("Open Memory View at Object's Address"), item->address, [this, item, pos] { addVariableMemoryView(true, item, false, pos); }); - addAction(menu, tr("Open Memory View at Pointer's Address (0x%1)").arg(item->origaddr, 0, 16), + addAction(this, menu, tr("Open Memory View at Pointer's Address (0x%1)").arg(item->origaddr, 0, 16), tr("Open Memory View at Pointer's Address"), createPointerActions, [this, item, pos] { addVariableMemoryView(true, item, true, pos); }); - addAction(menu, tr("Open Memory View Showing Stack Layout"), + addAction(this, menu, tr("Open Memory View Showing Stack Layout"), true, [this, pos] { addStackLayoutMemoryView(true, pos); }); menu->addSeparator(); - addAction(menu, tr("Open Memory Editor at Object's Address (0x%1)").arg(item->address, 0, 16), + addAction(this, menu, tr("Open Memory Editor at Object's Address (0x%1)").arg(item->address, 0, 16), tr("Open Memory Editor at Object's Address"), item->address, [this, item, pos] { addVariableMemoryView(false, item, false, pos); }); - addAction(menu, tr("Open Memory Editor at Pointer's Address (0x%1)").arg(item->origaddr, 0, 16), + addAction(this, menu, tr("Open Memory Editor at Pointer's Address (0x%1)").arg(item->origaddr, 0, 16), tr("Open Memory Editor at Pointer's Address"), createPointerActions, [this, item, pos] { addVariableMemoryView(false, item, true, pos); }); - addAction(menu, tr("Open Memory Editor Showing Stack Layout"), + addAction(this, menu, tr("Open Memory Editor Showing Stack Layout"), true, [this, pos] { addStackLayoutMemoryView(false, pos); }); - addAction(menu, tr("Open Memory Editor..."), + addAction(this, menu, tr("Open Memory Editor..."), true, [this, item] { AddressDialog dialog; @@ -1918,7 +1918,7 @@ QMenu *WatchModel::createMemoryMenu(WatchItem *item, QWidget *parent) void WatchModel::addCharsPrintableMenu(QMenu *menu) { auto addBaseChangeAction = [this, menu](const QString &text, int base) { - addCheckableAction(menu, text, true, theUnprintableBase == base, [this, base] { + addCheckableAction(this, menu, text, true, theUnprintableBase == base, [this, base] { theUnprintableBase = base; emit layoutChanged(); // FIXME }); @@ -1954,13 +1954,13 @@ QMenu *WatchModel::createFormatMenu(WatchItem *item, QWidget *parent) const QString spacer = " "; menu->addSeparator(); - addAction(menu, tr("Change Display for Object Named \"%1\":").arg(iname), false); + addAction(this, menu, tr("Change Display for Object Named \"%1\":").arg(iname), false); QString msg = (individualFormat == AutomaticFormat && typeFormat != AutomaticFormat) ? tr("Use Format for Type (Currently %1)").arg(nameForFormat(typeFormat)) : QString(tr("Use Display Format Based on Type") + ' '); - addCheckableAction(menu, spacer + msg, true, individualFormat == AutomaticFormat, + addCheckableAction(this, menu, spacer + msg, true, individualFormat == AutomaticFormat, [this, iname] { // FIXME: Extend to multi-selection. //const QModelIndexList active = activeRows(); @@ -1971,23 +1971,23 @@ QMenu *WatchModel::createFormatMenu(WatchItem *item, QWidget *parent) }); for (int format : alternativeFormats) { - addCheckableAction(menu, spacer + nameForFormat(format), true, format == individualFormat, + addCheckableAction(this, menu, spacer + nameForFormat(format), true, format == individualFormat, [this, format, iname] { setIndividualFormat(iname, format); m_engine->updateLocals(); }); } - addAction(menu, tr("Reset All Individual Formats"), true, [this]() { + addAction(this, menu, tr("Reset All Individual Formats"), true, [this]() { theIndividualFormats.clear(); saveFormats(); m_engine->updateLocals(); }); menu->addSeparator(); - addAction(menu, tr("Change Display for Type \"%1\":").arg(item->type), false); + addAction(this, menu, tr("Change Display for Type \"%1\":").arg(item->type), false); - addCheckableAction(menu, spacer + tr("Automatic"), true, typeFormat == AutomaticFormat, + addCheckableAction(this, menu, spacer + tr("Automatic"), true, typeFormat == AutomaticFormat, [this, item] { //const QModelIndexList active = activeRows(); //for (const QModelIndex &idx : active) @@ -1997,14 +1997,14 @@ QMenu *WatchModel::createFormatMenu(WatchItem *item, QWidget *parent) }); for (int format : alternativeFormats) { - addCheckableAction(menu, spacer + nameForFormat(format), true, format == typeFormat, + addCheckableAction(this, menu, spacer + nameForFormat(format), true, format == typeFormat, [this, format, item] { setTypeFormat(item->type, format); m_engine->updateLocals(); }); } - addAction(menu, tr("Reset All Formats for Types"), true, [this]() { + addAction(this, menu, tr("Reset All Formats for Types"), true, [this]() { theTypeFormats.clear(); saveFormats(); m_engine->updateLocals(); @@ -2046,9 +2046,9 @@ QMenu *WatchModel::createFormatMenuForManySelected(const WatchItemSet &items, QW const QString spacer = " "; menu->addSeparator(); - addAction(menu, tr("Change Display for Objects"), false); + addAction(this, menu, tr("Change Display for Objects"), false); QString msg = QString(tr("Use Display Format Based on Type")); - addCheckableAction(menu, spacer + msg, true, false, + addCheckableAction(this, menu, spacer + msg, true, false, [this, items] { setItemsFormat(items, AutomaticFormat); m_engine->updateLocals(); @@ -2061,7 +2061,7 @@ QMenu *WatchModel::createFormatMenuForManySelected(const WatchItemSet &items, QW if (formatName.isEmpty()) continue; - addCheckableAction(menu, spacer + formatName, + addCheckableAction(this, menu, spacer + formatName, it.value() == countOfSelectItems, false, [this, format, items] { From 80dee0fd32b31e068226f65f87a0619c34d50d19 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Mon, 7 Feb 2022 17:59:14 +0100 Subject: [PATCH 13/94] Doc: Describe using system editor by default ...for files of a particular MIME type. Task-number: QTCREATORBUG-13880 Task-number: QTCREATORBUG-26610 Change-Id: I6866849b861c124b7a4e028a4ee62b7ad47239aa Reviewed-by: Eike Ziller --- doc/qtcreator/images/qtcreator-mime-types.png | Bin 15660 -> 16678 bytes .../creator-only/creator-mime-types.qdoc | 5 +++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/qtcreator/images/qtcreator-mime-types.png b/doc/qtcreator/images/qtcreator-mime-types.png index e91bbb8c64421fb7ced4b4ce2f83b58c86e91305..26687cdf23df4be197107da60fe1ee9e0424c8e3 100644 GIT binary patch literal 16678 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 literal 15660 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 diff --git a/doc/qtcreator/src/editors/creator-only/creator-mime-types.qdoc b/doc/qtcreator/src/editors/creator-only/creator-mime-types.qdoc index 6c4bf3803e5..5fefdd89317 100644 --- a/doc/qtcreator/src/editors/creator-only/creator-mime-types.qdoc +++ b/doc/qtcreator/src/editors/creator-only/creator-mime-types.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2022 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Creator documentation. @@ -78,7 +78,8 @@ \li In \uicontrol Handler, double-click the editor name to display a context-menu where you can select another editor to open the file in by default. The menu is available only if alternative suitable - editors are available. + editors are available. Select \uicontrol {System Editor} to use + the system's default editor for files of this type by default. \li In \uicontrol Patterns, add the filename extension for the type of files that you want to identify as having this MIME type. From 0d17063e826b137ea00d40c01eca2924e895b8fd Mon Sep 17 00:00:00 2001 From: Xiaofeng Wang Date: Mon, 7 Feb 2022 13:45:11 +0800 Subject: [PATCH 14/94] macOS: use string array to be compatible with both bash and zsh By default, zsh does not split words in string by spaces. See https://zsh.sourceforge.io/FAQ/zshfaq03.html Change-Id: I167bae2af628be5b2fc9429a090628b6049f7ce4 Reviewed-by: Reviewed-by: Eike Ziller --- share/qtcreator/scripts/openTerminal.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/share/qtcreator/scripts/openTerminal.py b/share/qtcreator/scripts/openTerminal.py index bae549ca9fa..a0347c08674 100755 --- a/share/qtcreator/scripts/openTerminal.py +++ b/share/qtcreator/scripts/openTerminal.py @@ -42,9 +42,9 @@ def clean_environment_script(): 'TERM_SESSION_ID']) return r''' function ignore() { - local keys="''' + env_to_keep + '''" + local keys=(''' + env_to_keep + ''') local v=$1 - for e in $keys; do [[ "$e" == "$v" ]] && return 0; done + for e in "${keys[@]}"; do [[ "$e" == "$v" ]] && return 0; done } while read -r line; do key=$(echo $line | /usr/bin/cut -d '=' -f 1) From f308bb3cae27027a3b8bee1ae2b58e9a44195d3d Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 8 Feb 2022 07:52:47 +0100 Subject: [PATCH 15/94] Debugger: Fix value assignment in locals and expressions For booleans and numbers. Change-Id: I5ff1660faee1bf0ed21211d5fe98462f660fb417 Reviewed-by: Reviewed-by: Christian Stenger --- src/plugins/debugger/qml/qmlengine.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp index b071ca6eb1b..db0df2dd232 100644 --- a/src/plugins/debugger/qml/qmlengine.cpp +++ b/src/plugins/debugger/qml/qmlengine.cpp @@ -795,9 +795,15 @@ void QmlEngine::assignValueInDebugger(WatchItem *item, const QString &expression, const QVariant &editValue) { if (!expression.isEmpty()) { - QVariant value = (editValue.type() == QVariant::String) - ? QVariant('"' + editValue.toString().replace('"', "\\\"") + '"') - : editValue; + QTC_CHECK(editValue.type() == QVariant::String); + QVariant value; + QString val = editValue.toString(); + if (item->type == "boolean") + value = val != "false" && val != "0"; + else if (item->type == "number") + value = val.toDouble(); + else + value = QString('"' + val.replace('"', "\\\"") + '"'); if (item->isInspect()) { d->inspectorAgent.assignValue(item, expression, value); From 57afbae5438d15741e29c8a0ffc19276a420478a Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 7 Feb 2022 17:21:02 +0100 Subject: [PATCH 16/94] CMakeProjectManager: Move some markup out of translated strings Eases the pain of translators. Change-Id: I7327958ee0628698ab326b3c8d6518d3330b83dd Reviewed-by: Eike Ziller Reviewed-by: --- .../cmakeprojectmanager/configmodel.cpp | 34 ++++++++----------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/configmodel.cpp b/src/plugins/cmakeprojectmanager/configmodel.cpp index 0e680ad56e3..73f6f1e2280 100644 --- a/src/plugins/cmakeprojectmanager/configmodel.cpp +++ b/src/plugins/cmakeprojectmanager/configmodel.cpp @@ -30,7 +30,6 @@ #include #include -#include #include #include @@ -602,7 +601,7 @@ QVariant ConfigModelTreeItem::data(int column, int role) const case Qt::DisplayRole: if (column == 0) return dataItem->key.isEmpty() - ? QCoreApplication::translate("CMakeProjectManager::ConfigModel", "") + ? ConfigModel::tr("") : dataItem->key; return value; case Qt::EditRole: @@ -688,33 +687,28 @@ QString ConfigModelTreeItem::toolTip() const if (!dataItem->description.isEmpty()) tooltip << dataItem->description; + const QString pattern = "

%1 %2

"; if (dataItem->isInitial) { if (!dataItem->kitValue.isEmpty()) - tooltip << QCoreApplication::translate("CMakeProjectManager", "

Kit: %1

") - .arg(dataItem->kitValue); + tooltip << pattern.arg(ConfigModel::tr("Kit:")).arg(dataItem->kitValue); - tooltip << QCoreApplication::translate("CMakeProjectManager", - "

Initial Configuration: %1

") - .arg(dataItem->currentValue()); + tooltip << pattern.arg(ConfigModel::tr("Initial Configuration:")).arg(dataItem->currentValue()); } else { - if (!dataItem->initialValue.isEmpty()) - tooltip << QCoreApplication::translate("CMakeProjectManager", - "

Initial Configuration: %1

") - .arg(dataItem->initialValue); + if (!dataItem->initialValue.isEmpty()) { + tooltip << pattern.arg(ConfigModel::tr("Initial Configuration:")) + .arg(dataItem->initialValue); + } if (dataItem->inCMakeCache) { - tooltip << QCoreApplication::translate("CMakeProjectManager", - "

Current Configuration: %1

") - .arg(dataItem->currentValue()); + tooltip << pattern.arg(ConfigModel::tr("Current Configuration:")) + .arg(dataItem->currentValue()); } else { - tooltip << QCoreApplication::translate("CMakeProjectManager", - "

Not in CMakeCache.txt

"); + tooltip << pattern.arg(ConfigModel::tr("Not in CMakeCache.txt")).arg(QString()); } } - tooltip << QCoreApplication::translate("CMakeProjectManager", - "

Type: %1

") - .arg(dataItem->typeDisplay()); - return tooltip.join(""); + tooltip << pattern.arg(ConfigModel::tr("Type:")).arg(dataItem->typeDisplay()); + + return tooltip.join(QString()); } QString ConfigModelTreeItem::currentValue() const From a8092c97081351d9f52a5bd81663b41ba11edb84 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 7 Feb 2022 12:25:10 +0100 Subject: [PATCH 17/94] Doc: Add a hint on what to do when stuck with older CMake versions Change-Id: Ia68b0ae94f69eca8fd674d7537f35af1b0f685bb Reviewed-by: Reviewed-by: Leena Miettinen --- .../src/cmake/creator-projects-cmake.qdoc | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/doc/qtcreator/src/cmake/creator-projects-cmake.qdoc b/doc/qtcreator/src/cmake/creator-projects-cmake.qdoc index 0258564a0b0..5cac40c6372 100644 --- a/doc/qtcreator/src/cmake/creator-projects-cmake.qdoc +++ b/doc/qtcreator/src/cmake/creator-projects-cmake.qdoc @@ -72,6 +72,26 @@ \QC requires CMake's \l{https://cmake.org/cmake/help/latest/manual/cmake-file-api.7.html} {file-based API}, and therefore you'll need CMake version 3.14, or later. + For systems with older versions of CMake, only workarounds are available: + \list + + \li For CMake version 3.5 or later it is possible to generate a + \l{https://cmake.org/cmake/help/latest/variable/CMAKE_EXPORT_COMPILE_COMMANDS.html}{compilation database} + and open that in \QC, as described in \l{Using Compilation Databases}. + + \li Create an ad-hoc project file for a qmake build using + \c{qmake -project} and \l{Opening Projects}{open} that in \QC. + Be aware that this is typically + not compilable without further manual changes. + + \li Manually create an ad-hoc project file for a + \l{Setting Up a Generic Project}{generic project} and + open that in \QC. Be aware this is typically + not compilable without further manual changes. + + \endlist + + To view and specify settings for CMake: \list 1 From 210334218bf14a619c0248495b278f3972fcc3b9 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 20 Jan 2022 15:49:10 +0100 Subject: [PATCH 18/94] Add change log for Qt Creator 7 Change-Id: I7e624e6dc6d6a8e0bd8974511724d9c2d24ce738 Reviewed-by: Leena Miettinen --- dist/changes-7.0.0.md | 228 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 228 insertions(+) create mode 100644 dist/changes-7.0.0.md diff --git a/dist/changes-7.0.0.md b/dist/changes-7.0.0.md new file mode 100644 index 00000000000..a9c98815a54 --- /dev/null +++ b/dist/changes-7.0.0.md @@ -0,0 +1,228 @@ +Qt Creator 7 +============ + +Qt Creator version 7 contains bug fixes and new features. + +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/6.0..v7.0.0 + +General +------- + +* Gave `Welcome` a fresh look +* Split `New File or Project` into `New File` and `New Project` +* Added optional notification of new Qt releases available in the online + installer (QTCREATORBUG-26708) +* Added `Show in File System View` to more context menus, like `Show in + Explorer/Finder` +* Added `Tools > Debug Qt Creator > Show Logs` for viewing Qt Creator debug logs +* Moved C++ code model and language client inspectors to `Tools > Debug Qt + Creator` + +Editing +------- + +* Added action for selecting all search results in a document +* Added support for choosing external editor as default editor + (QTCREATORBUG-13880) +* Fixed copy action in text editing macros (QTCREATORBUG-26363) + +### C++ + +* Switched to Clangd by default (QTCREATORBUG-22917) +* Fixed that compilation errors appeared below code model errors in `Issues` + pane (QTCREATORBUG-23655) +* Fixed that duplication files did not adapt header guard (QTCREATORBUG-26654) +* Fixed highlighting and indentation of raw string literals (QTCREATORBUG-26211) +* Fixed performance issue in global indexer (QTCREATORBUG-26841) +* clang-format + * Moved settings to `Code Style` editor + * Added synchronization between `clang-format` settings and custom code style +* Clangd + * Added memory usage inspector to language client inspector + * Added highlighting of `Q_PROPERTY` declarations + * Improved display of diagnostic messages + * Fixed access type categorization for functions + +### QML + +* Updated parser to latest Qt version +* Fixed that application directory was not searched for QML modules + (QTCREATORBUG-24987) + +### Python + +* Added Python specific language server settings + +### Language Server Protocol + +* Removed support for outdated semantic highlighting protocol proposal + (QTCREATORBUG-26624) +* Fixed that outdated diagnostic could be shown (QTCREATORBUG-26585) +* Fixed issue with re-highlighting (QTCREATORBUG-26624) + +### FakeVim + +* Added support for backslashes in substitute command (QTCREATORBUG-26955) + +Projects +-------- + +* Added option to override GCC target triple (QTCREATORBUG-26913) +* Added multiple selection to `Issues` pane (QTCREATORBUG-25547, + QTCREATORBUG-26720) +* Improved automatic (re-)detection of toolchains (QTCREATORBUG-26460) +* Fixed unnecessary toolchain calls at startup + +### CMake + +* Removed grouping of CMake cache variables (QTCREATORBUG-26218) +* Made it possible to stop CMake with button in build configuration +* Renamed `Initial Parameters` to `Initial Configuration` and moved into tabbed + view with `Current Configuration` +* Added field for passing additional CMake options to kit, initial, and current + configuration (QTCREATORBUG-26826) +* Added button for editing kit CMake configuration directly from build + configuration +* Added hint for mismatches between kit, initial, and current configuration +* Added context menu actions for resolving mismatches between kit, initial and + current configuration +* Added `Help` to context menu for variable names + +### Generic + +* Added support for precompiled headers (QTCREATORBUG-26532) + +### Autotools + +* Fixed parsing of `SUBDIRS` + +Debugging +--------- + +* Added debugging helper for `std::variant`, `boost::container::devector`, and + `boost::small_vector` +* Added debugging helper for `QStringView` (QTCREATORBUG-20918) +* Added `Char Code Integer`, `Hexadecimal Float`, and `Normalized, with + Power-of-Two Exponent` display formats (QTCREATORBUG-22849, + QTCREATORBUG-26793) +* Added shortcut for disabling and enabling breakpoints (QTCREATORBUG-26788) + +Analyzer +-------- + +### QML + +* Added support for profiling QtQuick3D (QTBUG-98146) + +Version Control Systems +----------------------- + +### Git + +* Added support for filtering log by author +* Added handling of `HOMEDRIVE` and `HOMEPATH` on Windows +* Fixed that conflicts with deleted files could not be resolved + (QTCREATORBUG-26994) + +Test Integration +---------------- + +### QTest + +* Added option for maximum number of warnings (QTCREATORBUG-26637) + +### Qt Quick + +* Added option for setup code to wizard (QTCREATORBUG-26741) + +Platforms +--------- + +### macOS + +* Fixed that macOS dark mode was not used for dark themes (QTCREATORBUG-22477) +* Fixed that user applications inherited access permissions from Qt Creator + (QTCREATORBUG-26743) + +### Android + +* Added option for default NDK (QTCREATORBUG-21755, QTCREATORBUG-22389, + QTCREATORBUG-24248, QTCREATORBUG-26281) +* Fixed that `Include prebuilt OpenSSL libraries` could add it to the wrong + `.pro` file (QTCREATORBUG-24255) +* Fixed debugging of devices with upper case identifier with LLDB + (QTCREATORBUG-26709) +* Fixed detection of available NDK platforms for recent NDKs + (QTCREATORBUG-26772) + +### Remote Linux + +* Fixed UI state after stopping remote applications (QTCREATORBUG-26848) + +### WebAssembly + +* Improved browser selection (QTCREATORBUG-25028, QTCREATORBUG-26559) +* Fixed running CMake-based Qt Quick applications with Qt 6.2 + (QTCREATORBUG-26562) + +### MCU + +* Added support for Renesas Flash Programmer (UL-5082) + +### Docker + +* Added experimental support for macOS hosts + +Credits for these changes go to: +-------------------------------- +Aaron Barany +Alessandro Portale +Alexander Drozdov +Allan Sandfeld Jensen +André Pönitz +Anton Alimoff +Artem Sokolovskii +Assam Boudjelthia +Christiaan Janssen +Christian Kandeler +Christian Stenger +Cristian Adam +Cristián Maureira-Fredes +David Schulz +Eike Ziller +Fawzi Mohamed +Henning Gruendl +Huixiong Cao +Janne Koskinen +Jaroslaw Kobus +Jean-Michaël Celerier +Jere Tuliniemi +Joerg Kreuzberger +Kai Köhne +Katarina Behrens +Knud Dollereder +Leena Miettinen +Mahmoud Badri +Marco Bubke +Maximilian Goldstein +Miikka Heikkinen +Morten Johan Sørvig +Orgad Shaneh +Petar Perisin +Piotr Mikolajczyk +Robert Löhning +Samuel Ghinet +Tasuku Suzuki +Thomas Hartmann +Tim Jenssen +Tony Leinonen +Topi Reinio +Tor Arne Vestbø +Ulf Hermann +Ville Nummela +XutaxKamay From 8c7eee4ff75f1d438743f6c5a6f0798acef64afa Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Mon, 7 Feb 2022 14:18:49 +0100 Subject: [PATCH 19/94] Core: Fix "reactiveness" of FindToolBar The recently added "Select All" button needs to be included in the width calculation. If the find buttons switch to icon mode, "Select All" gets hidden. Also, if the replace buttons are visible, they define whether all buttons are shwon in full text or get hidden. No icon mode at all in that case. Change-Id: Ie85a68c7f7c3f1a6ca51ed3f91d64124eeb7aa1a Reviewed-by: Eike Ziller --- src/plugins/coreplugin/find/findtoolbar.cpp | 32 ++++++++++++++------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/src/plugins/coreplugin/find/findtoolbar.cpp b/src/plugins/coreplugin/find/findtoolbar.cpp index f7345f28c9c..ccfd99e9859 100644 --- a/src/plugins/coreplugin/find/findtoolbar.cpp +++ b/src/plugins/coreplugin/find/findtoolbar.cpp @@ -437,6 +437,8 @@ void FindToolBar::updateToolBar() m_ui.findPreviousButton->setVisible(showAllControls); m_ui.findNextButton->setEnabled(enabled); m_ui.findNextButton->setVisible(showAllControls); + m_ui.selectAllButton->setVisible(style == ControlStyle::Text + && m_currentDocumentFind->supportsSelectAll()); m_ui.horizontalSpacer->changeSize((showAllControls ? FINDBUTTON_SPACER_WIDTH : 0), 0, QSizePolicy::Expanding, QSizePolicy::Ignored); m_ui.findButtonLayout->invalidate(); // apply spacer change @@ -768,10 +770,25 @@ FindToolBar::ControlStyle FindToolBar::controlStyle(bool replaceIsVisible) { const Qt::ToolButtonStyle currentFindButtonStyle = m_ui.findNextButton->toolButtonStyle(); const int fullWidth = width(); + + if (replaceIsVisible) { + // Since the replace buttons do not collapse to icons, they have precedence, here. + const int replaceFixedWidth = m_ui.replaceLabel->sizeHint().width() + + m_ui.replaceButton->sizeHint().width() + + m_ui.replaceNextButton->sizeHint().width() + + m_ui.replaceAllButton->sizeHint().width() + + m_ui.advancedButton->sizeHint().width(); + return fullWidth - replaceFixedWidth >= MINIMUM_WIDTH_FOR_COMPLEX_LAYOUT ? + ControlStyle::Text : ControlStyle::Hidden; + } + const auto findWidth = [this] { + const int selectAllWidth = m_currentDocumentFind->supportsSelectAll() ? + m_ui.selectAllButton->sizeHint().width() : 0; return m_ui.findLabel->sizeHint().width() + m_ui.findNextButton->sizeHint().width() - + m_ui.findPreviousButton->sizeHint().width() + FINDBUTTON_SPACER_WIDTH - + m_ui.close->sizeHint().width(); + + m_ui.findPreviousButton->sizeHint().width() + + selectAllWidth + FINDBUTTON_SPACER_WIDTH + + m_ui.close->sizeHint().width(); }; setFindButtonStyle(Qt::ToolButtonTextOnly); const int findWithTextWidth = findWidth(); @@ -782,15 +799,8 @@ FindToolBar::ControlStyle FindToolBar::controlStyle(bool replaceIsVisible) return ControlStyle::Hidden; if (fullWidth - findWithTextWidth < MINIMUM_WIDTH_FOR_COMPLEX_LAYOUT) return ControlStyle::Icon; - if (!replaceIsVisible) - return ControlStyle::Text; - const int replaceFixedWidth = m_ui.replaceLabel->sizeHint().width() - + m_ui.replaceButton->sizeHint().width() - + m_ui.replaceNextButton->sizeHint().width() - + m_ui.replaceAllButton->sizeHint().width() - + m_ui.advancedButton->sizeHint().width(); - return fullWidth - replaceFixedWidth >= MINIMUM_WIDTH_FOR_COMPLEX_LAYOUT ? ControlStyle::Text - : ControlStyle::Hidden; + + return ControlStyle::Text; } void FindToolBar::setFindButtonStyle(Qt::ToolButtonStyle style) From a89e43d502676185a07502df1ccef0ad2f27647b Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 8 Feb 2022 12:59:15 +0100 Subject: [PATCH 20/94] ScreenshotCropper: Compile with namespaces Change-Id: I5c3516071327a2f70bbbac84cc94e9acdecd2673 Reviewed-by: Christian Stenger --- src/tools/screenshotcropper/screenshotcropperwindow.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tools/screenshotcropper/screenshotcropperwindow.h b/src/tools/screenshotcropper/screenshotcropperwindow.h index 19f9a9fcf67..1ba13b685ca 100644 --- a/src/tools/screenshotcropper/screenshotcropperwindow.h +++ b/src/tools/screenshotcropper/screenshotcropperwindow.h @@ -29,7 +29,9 @@ #include #include +QT_BEGIN_NAMESPACE namespace Ui { class ScreenShotCropperWindow; } +QT_END_NAMESPACE class ScreenShotCropperWindow : public QMainWindow { From 5c9e64a2a436a2792b75b24ac9cf4ae90e1d4adc Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Tue, 8 Feb 2022 13:08:22 +0100 Subject: [PATCH 21/94] QmlDesigner: Increase delay for text editor This increases the delay from 400ms to 800ms until the model and GUI is synced with the QML code. This means the user has to stop typing for 800ms until the form editor and property editor are updated. Change-Id: Ia250dec39cd8051d25619310024b718ad1cf9815 Reviewed-by: Thomas Hartmann --- src/plugins/qmldesigner/designercore/model/rewriterview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/designercore/model/rewriterview.cpp b/src/plugins/qmldesigner/designercore/model/rewriterview.cpp index 051c449e21a..1fc05f10c04 100644 --- a/src/plugins/qmldesigner/designercore/model/rewriterview.cpp +++ b/src/plugins/qmldesigner/designercore/model/rewriterview.cpp @@ -88,7 +88,7 @@ RewriterView::RewriterView(DifferenceHandling differenceHandling, QObject *paren m_textToModelMerger(new Internal::TextToModelMerger(this)) { m_amendTimer.setSingleShot(true); - m_amendTimer.setInterval(400); + m_amendTimer.setInterval(800); connect(&m_amendTimer, &QTimer::timeout, this, &RewriterView::amendQmlText); QmlJS::ModelManagerInterface *modelManager = QmlJS::ModelManagerInterface::instance(); From 3926e708a9474d53848ef64ce7d71656a48bc558 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Mon, 7 Feb 2022 17:27:36 +0100 Subject: [PATCH 22/94] Doc: Update info on Android settings Fixes: QTCREATORBUG-26672 Change-Id: Ifaf9f28b485f965302bca9aa2ec2a308b96d4b34 Reviewed-by: Assam Boudjelthia --- .../qtcreator-android-cmake-settings.png | Bin 15855 -> 10073 bytes ...tcreator-android-sdk-manager-arguments.png | Bin 0 -> 9060 bytes .../images/qtcreator-android-sdk-manager.png | Bin 8740 -> 10398 bytes .../images/qtcreator-options-android-main.png | Bin 15736 -> 18155 bytes .../qtcreator-options-android-sdk-tools.png | Bin 15511 -> 22305 bytes doc/qtcreator/src/android/androiddev.qdoc | 25 ++++++++++++------ .../src/android/deploying-android.qdoc | 12 ++++----- 7 files changed, 23 insertions(+), 14 deletions(-) create mode 100644 doc/qtcreator/images/qtcreator-android-sdk-manager-arguments.png diff --git a/doc/qtcreator/images/qtcreator-android-cmake-settings.png b/doc/qtcreator/images/qtcreator-android-cmake-settings.png index e02c77c38bc302fd94b431cc7d3fd2c063c784ba..bbe680a02693f2b248bb0550847ee4a89af2457d 100644 GIT binary patch literal 10073 zcmeAS@N?(olHy`uVBq!ia0y~yU|PVyz;KI$iGhLPTSdAI1B1GPr;B4q#jUq|r>hVHXM=c*$HahD(}Y;9lw4JAt})l2wnb=_OTphQ zn^bpdg)k~DaQ`KA+%L4@^NgaPqh5PHU903=Vz1y+wt3?o{yTrq?p`p=6{q_5l zo`3oBrG!82*X(yQng5*oc+rr7f#HQ=UAyxI7dCeG`E|c$F6U@kq55RiO?wLucBY00 z*4N*~|NnKpU(U9wNueXkX`R&0GB)=17j6tu+CLU9O#lA&_VE>mB#Tm>{IKAEdfDGz z_ixC`kX!x&F1m{0y)o8Bth{`@Csn`gW^okhmQl52(T`+jWAmG5V`*z^>-<9TxJzG; z%>0Gvvg{#W^pgdxvYS>YKe@&E{MCFpIXO9L>EHY;jv?GTgPv4Pyt#hi!i7#v({D2t z-k52e?#2;*V&cTd%I=&8ghGP(^YptQOQ6n^s)?(QtyF1$@KnmW{M{YHL-Iv6 zPc#%Onlg4hNOf_V?kiy08e?h{9v||-NU-;4u~Q#^lX^!OM_iih%k`X#mQ7f_jP2lQ zj;|UI`Q1LSG(O;DI;dRHq#$79s8GS;FTgQRp+k)G-4P9I3fJwriUH+Ns)8 z&ssnHpSei?(3!xHv)S!$%x-PCu$O%vvh6(sjb*94 z8JQ1jRe!8px$oVuZ;Y2Q{|QwhOuY zs?Dxn?q`0b@?TAsN@LA5?WFeTeP=%IHp-p{E>A#pRdsxru({c` z%d1}V7H(f1aaW*5p381S_UShfF4KC$7cAv-`=BfE=gE^N3oY{OIjk43Z|B!k?6fY| zU%~AavtxJi(xt9PpL)z&)1qP;y~`stujg~8 z1kL%U`7=XoUbHz&yvGOY^8DrJwACse*BzLu7u_abvumr+*57TbwuNPh-d_}=^|Muc zt#s4+R2KV}pXa-OIL5I12S=R0zt+Tf_SDGT`75%rmwHu-hH>dfnX}xlZz|t?;`t$y zs}bkKjNdO?7rwTBR|Tt3c^d!z)ncndO`~LYS;T)R+nN`$TU{fjzPe!^$emo* zy&$%S9qVaW|6x(7^9Q|y{ysiD#|1leBf6Ha+j=Btt=PvqWuHDCy1RS(<0}@1La#Oi zHf@eDHN2-bbJ2A!sXp~*U(a4Xy5?Ib*ZQ#S3QvA0{CLJ~=X?3t#@Ndb`?kO6&HSKL zy28qJ{S3?5Gp;|E{-pJ0_M-DErJJ5h*3>qcpVH8&h-bZ}^do2a%WoWY>si)Yn0Wih zU!2{?uR6!KcXp>=;WKW#yEAL{WvhqD*%ai?dsFoMV6*J*b6)2_&h-_nG1|U%Z_l)S z&(-ud{$yRhfAh4p=Y{4z()m^5PH9mXHcWo}=eN;` zeOLGWJ^k^d;2(yIR}DYjD@(1N`FO+gi~H|4hd;kzn(ZF^?scf!2RF`pn!lEKR3CV^ z#$nov-K$Tmz1sVwc6<3-7yreV#6Le-YrXs2x#dDXOPxQ&YW#>k=yK@yb3vPnO%c=h zQh)E|#9%l+nB`N9h8g9{ZQ#o#W_4~>u8nU34L?l_cQ&f+i7%WXGHPMKp-#fi}1<_8Py z=2bqMDIQnRIB%9hR`2t9)qd+_CA285V{I`_Y))7S6&)LzfQ zz`zjO*s*)U16A#ETLuP(yG{OgIOH%iGeE?YD;OBShC%oOHVh053LvqJy$`~}!tSYZ zG%0k5wZCAif4}m<(*^u*~S1)1(*?hmY>3gJ2Z0k!#1_rPh3@rC6o6PsDJM%E! zUO0v0*@wkb!u?f$u8;r!_=z&e_wP5Pf4J^%&HnC{Z^NdVUsoT@tc`HmabP760|Upt zY_|_p^KyR7>w7u#06PN%%YE)9^JR|&Z5S97e&mVoNp_M01!2>BuY>&acD<`P*{4|r z3gAC#)*uQTp!mFWpYP!MHEZ^G3$Qo}=<;3U{dX@IWF8_)AfX8L2tOzal`HnCxeKs3 zZuyv9iZ{wn>2_Tt`=T?}tO&GVDz!I+xF{t1{v={p%yN zd~(6RMba1V9XN2{A(0(Z3 zGQV1(0?+&hsTtazCjV}j2(~C#YWMXfdk=vY?I*KjWMrOL2)Ou}XjIJHXIK92&PF?q z%w;BG2ZdRh)H~_~_nb-i-uz(cOla!g_#nR}@G{5040#siiYA8-EEkV9iEpi!IhMVC zZ`%WF_Yd3ULdx#h%j?dsuU{TiS*M4;rXOcbdZyH|PpBrV{OU)J zeRG@a1>A3#pMB-ca`Clde9LbGo=Af*&*>^n=hyYKZ|9RKsIy9lcVW4xK9TF*hU!;8 zRyEmIe|s}g?daUIUa6n^>QgJ<22DINt;J;X-=_If5AI(5TB##$>+dj$ZI4Y4W{bBS zf6p=RMe@Pxe<#IWW~t9y8*}fD&hM7q2luyItymD>?NnuQ_urQ^m-RR9zO3;5@ap9J zAF=<=>+!vv6tJE*HFEbX4yJ?bP4j2Xvbxi=W5>45o68J;UElie?Aflp$7V)E@A>oT z^m=VY`MEcj%*++|^SN-($IKfaYknR3?B((3+;8KLNgGr+J^4~6D(uo<7q|CUuC|Kd zS%uh3|Nj2I+;9B;y^DBr>9gh2JNG{D>{+MQ^y1$OiG%8C<~;iH&RgHES(~a?u69jY z-EYp1d*AncKWvcVXjiuELHWIUXEzD2^Tw0;EP{S6pDP_Ja`AB@hn-=K)~_$?EM91= z;=WgCD#+4QuXT6N!W{+W>CfM>*1o*3@V3$EZx71mXkE{o@y;hlI@0WeaqR|Gv{jadN<8HLVkLdZbdw+5=+&FR7 zk)Q8E&_U;H*7_&U)EN?*A215oG_gB;VBnBDSU%$czkWRv1D}8mL(}`XgYvt+-dy7b_Wh|}dA_&X-}}4${=0wEuU~#@^8axEzM4<3=iB&va<8mm z-Sr{F^q)rdW~0em3|E@KKGqejSy{3tM5}i7^2H)YKALgV{pdZ(7V7`t$$%d7KkpRafn7 z+RU6EdViz#OI;R)_Cyx`3tk7iza6Pp_n$Xs-n@A)FHTtI$*g>SyYmP0cj`8OK6D?K z-&gzp!R>y#|Bo&@&58K;Gu-h}dEL(^pXKdCf~T~Wd{(#r@8SPH<9ofktLM!4w{_~b zr*GP=P`~9=_yXU!(8quOZJMJZ^_x|LrHMUb;{$Ic`=8#~%C@qX95T~Z>NeRIJgz%) zyZ_&D@&0GcPuuN(Jo?CgukX_7`mdo|=4=*FjJEx`x_{9Z_5a$Brl+nhNdI^De~t2T z2k!jP$$yWru4-kz!q&u|vGPG`MD@EnJCkb#F8O4>iR1qFKzhDy{o}eLclzc3zdFu; z`Dy*%RLdB>|8G_wzh7^C=JUn888en?tY(s{`_FCr_pST>Us>PJFWUNQlQP)lo?ln7 z?Kb9OU(wslA-CXY({#x1E=u3gZAHF)jst9|Lvr` zO^t-EdrZxbA0O{en_s>4&*l31Klk^qUVdD2)2ow@B~1Ibc~1C0UoN&M>~Dhk$^TE5 z+XsAp|L^5$OV+F>VOQ_j=*lcG0~^YEkeQ*0{YLV^`L@;HJiH$*{p`J7M|Dp9$++DX zmQ_zqym;cY<-(&0Y1`aC?EnAj@401vCfC=0Ixo4q{?bd)HaW(F%q5#26ragmfA;+S zxlQ&T+~?a?|FuJ8U4LI+**woZ7Q44t7)I6P*8OvHo^@01Ab;$Beg-oRxdqEv#o_z9_#_T_{&pbcB??!Ude{O~ijvpA-iq-6@+?-tV?AE2NGj4uVNmYxns!Mx# zYiq0V@x?C53sn`*<}^Rp|MTtIga3bsGbDWeb5^&ipkbZp9=$h@g+G55K7Mwqt?rM% z*X@Lk+y8f;&)9IvJU{R6J#G1m&CCiv@@JgSXqMOJ_P0 zR*LvuoPH&z>|a`&i7=??)0E%!;Bxv0@6Qu=`JYjfKYt_6-cUGgo}~K+Q2SI`bk85n ztIeRK3T`IuySSt3>nui43-*Tf!PBdl;WCg0G(;9R?Ort(~cAJ)-RPhIPpv}sf1#^6)g#V1#(ocjK3tM8;6F@dMz zZ+?1me^;^2a);(QT9#3T>8q1mB8v6|N3MSBktLDyBHwA^;i+%bR|eg3*sU0~_3dA= zb@O6HOlE#@@v2k$oc;7wItN43cg{G0w_lw_Hdeo8wJ%>EbMKbU>Qx+P0`*qM&d{p3 znz-`SlrINfblz@yYEpl}QcZTLRz-RvpMKS$U1#PL~*mv~I-RNk;^Z%{2Pi8*&_mfHChgMVjUf~*rHPxRl?w@5D*0f}&&B4`o z=RACwVQH|-?83!Qx22zbnQa;RY3m{Vid_A9vnoEwt+V{?a8>)qqN~mys@vwA{C3d& zL&F2X8h38Hmph-yybF2OW!rRKWL^J*#fxON`B{6--@c~0=@rC?QvI6+J3I70^Mzk# ziQiJiQFner-K<|a+zd_bALgq6@CkV(ar9cH;6e3?Wi`w4djEXoxECv2u3f}pKZ)<) zWX^)ekvq~0!k!jfwRO#Zw>{#kz@K}zo&M@MP4XMRI|_kJkyWlJU1cegzgup_@%)OP zEbEuAUi{6<{exfT(~y(byKD}suPUpys;|3Oy5o&?vzyxo*46C~zNZ!4`}%JAw<1ok z5$Y9hkLH}eU?3HA{R2!lHhPb?`-{Gp%=)KQ89h<| zN5#6UpV!UlZfaj`*`yz2%W^;I4f|Vd?Q)AB4G*M+AvMz1Z{<(C9A)yCKREk7I{osw zwCAFyj>+j&&o9&NU$pi8!PoIcoA-|?(wSQ={Ebx1D+v6*TwkOYh#)H=tD=yCa@&3ul$(Ju*Hnx?zWRjWiq_S?ZECa)r zPSo0i^PqUet-I6oWz3iI&AlMN(BLPyhbQ~|T#7AD8^?PHd~-tN-Q-%EK3A4lbX)U8isU%=lepxtVD;zbx#Eb041h zm{C|}7ZDT`B?igs9Q$5Qn?IvpMqV$*n{yJVGwLv%%TD5iK8qDUi@o)_wT_@}@maAy zM~)mRc>UQ#~D@mw{OTS zPmsY-W^vfAmb>q#Fo1g1*J#XcnuE!z%yrp~kvsUlv z&z?UMYx()Jp|$nsl%q#aTWaKfDU~{^S#k1uS<0-cEo&D^n!=CP z(}uHdJr20_;tmzHY%3b!_%*1V+iPqC`?;ht`@D88O`z0bD(`PTMJGkgA;($GvLkAydT zrG0m=Pv^eFa%20>v!XSdx}BQlUuBiI`j_D52k3<~u>-WB!V+vpWPf6hj`gXxq16rL+ca+n#(TeL1er(J&SnNxaQ zTy@uEj+kpyEbZMn_gK*#y|+rGYP<9*Q}_K`W;R*A$|FAd>jUZII~QG#_uk@ltxN0H zx2wFL7amTz^&xcYX0N&n=U!>;0{xGkOk z=;rO+i}tcl?l{F5m{;=VRi@E4v+b`Y-&wQbRQcNwv7W~{Q#LPel9!g2mY08@yW5+2 z>C9ZQJysW&_@ur*T={#phTgQn}L?Qhel{lb~_56Awl_-Zz-=uxY(*8F52%hZ`)jb7KX z-CyzG>+WeybKNGoJk3aHKl=6FoaD8IA6|>r+^c&V8vg+E()Tc~do}LL&$&wO1#1WUyqo@pXQ$NV;CI_!*#6CQ4&^#mH}8mZ zZT!Ja_ZNlVH@dj|^5Oj6Bk8mLrmlK&?|NOys~O#W#;nqombi~cQX2?>kJPfxyl`Qp>xX5uTQaaN}4TO_Eis8y_xyw&yRiT>K& zFC`w#OJ`oXu~!VqUO9W;3P%liYUmYXe{pBGkk zP4AbTSwz%g#j|fX4&J}HDr8&OlqplscFhfno9!K@8o1AVeeR?q&$@#Cotmcp|JvMS zOV+5Ar%&={goVzC*Oum8xqjQb(DH3sZcnbt@0$8S$E)r@@xIB%7H6*%=O6iXL*k>J zo7no8oohB!SoWU|j}u$hvggmIt20(#4_X%&?4fj8QlKS@(SLd1oI}%Va^078y5H7X zb#a^cy4!d5Zc<*p-!5&v#iN&7W|zyAwLduAy7h;PcTr5tZO>nS%-^<{Z@z34cUQV; zdhn_}TO-Y^mlZ{t&i@<}_?~&nmj`pa&uvSHyqsHPySk}dEMxw6&zZ&FuZ3}4by?@^ z|2;4}w>aGN_pe4iC5w+!xE1ZbzX8`NM}(E{9zF5s>1kFE7I~|GU57vJd{M^FIzRNl z<;*MT*8f%Gzo1queQ_JDS?1^6E4Wh^aC2w%!G9XuQ%^PDE{xiu!X4PP_w8Huhm!(9 z!JD)HLG$IW_iDbZFH2j);#vIjxmQ`6qdA|l<+u>=>?jM>Zq_#%n zb<(P9X6d3$?>}z*{miRzHp6eT?K{=owski(?VrOLSGdQ_L_g=d!v`-`o4Ia#cYTWe z#LBZ*UAGUK1?@0csiu+VBwzA?>4mtHQw<{R?VA!E#E>o zc6!aXGurct!tJH9SIgBrwg~_7E4wr7WK^K*?YjKaH7^XNoBf%0t6t4MBmL`?SZlNG zvvYids>){BCanE@&?}uQPG_x#WkH!$&UTjd8MY^;q<*`r_od;%=F3+y*UVv!UJb38 zX0gnVoi^|F%{89y4y-zOIb!S7oh%-!BO>%nE?oB9=hIoB1|OO{>m^3P2(D-Y~` zpdVjmdC$7<`;FKeA^9bH=DNA=3=ivhuuLlf(TdZ``^wRNj64i#scIL}vHh5(ZC^nQJz2R!l6~_2)s^ zrWs4JPCL4ov;JE4ZVqpo$>y_7;p(%dSmxF?tloRzQMJ|7C9nHiUr8N&e#)p?ZC3PT z(dWChu1$^Eu&w8TEq|)V}WUdEUX-=Bjeka~iw~EqtxS0(f>gQ5{y(yJQTg(P z52feL$)EP%ssBp3H_a2$wuOFpW-VnIzToq`sF_Jc`?sYpV}_H=u1C2qyCqUvwmHvdLdEy&H;V$=XWAcsm%01# zgB@n(uOGh=-D~}|e)WoI*7%PsP3867XKXFD%~PByoVxCM&?aripTBne+iU&%^_!oQ zUw!K~xSGAFY{$NR3mkGkhb#WL_kY=(Z?->{EWRGU|5JVDy?>iFMJ+2l`f}#l*fnSL zbt)o!B0UPN;(ki))hlhkyV#ejOzPq5s+2soh@Va)H~zj>wL$b&!T>xu-F$j zUpD=_gUw83!*8=|h28JEZsfcCadFAs_hye)#@%~X>FalN{`SiomR9D=zn}OZ^=hLX zN2c2TlY9%jBX8#HSidG&+?BXY(>%x{*VU zVV3@nO4kqE-KW-X|IGD|tEoMVyRM+X!%IR|*0%K3m6vk7nX^m+W?5R8v^-#BSfI}$ zZ&9aF@F&<-mi28PNTeK8w=ysY*fc?gR({8PVE)a{$iVOlGH>SaK|==AO>2TwcDq78 zEWPwGXyuo+^ZJ4Wj)QB)?gy^bkM>Vi_xJPnKmR4e5ac_R`0@pCV4GV)-?aGbvZ#cL7<#O%k_9e$bRkTZb&ja=F?c2?- zZNFNl_(BcT%~{>#U%cu&qgPeM{ta^?EzjD2y;ruXAoRmIrnO$nQvKHL+y3VD#TO44 z4i+ac9#sA@f%D_^jl=usUq!9JyXTJ^>qcF#(&V ze)p@1{RS^DRAyXVX>%~0>pG}+!56K*`!naged+;nj62jm2-<9!@}OmloQ>zA*Jf8{ zzth&;Ir-Xre@*_yn_h1G+WWR5DW|A3x-!gk!IGTy>x%w4Kj#LogqbC#KR3QARrBE= zZ+9#8B{ScO)jazeve$2}xZs|P+LGqHW&dWe%rEWx6~)58cI)of+cw1=?B4ZudhDWX zm)Z?at3Dpxb(PP|^PY95epjc%mpT70!8%{c2kJkA(d+{^Z^fw;s z&U!vyY|?N}^v{(mR~{}q+P&GkTX^xeBITzhAg7A%`Np=}=;iV<;foV?wWWVJPS=_A&Hb3q;@`Se-!G(BUj3?N z*VMjl)*|!tb1~t)-?+MeFS@+?h=^^;%mNdxHJm(tv#%*ZHr#eZTqq%h@sKf81@- z|F*WOVbS}g&(H0;-tup^Owqn-p?UjWP7j}Je&^KI2_mPx%PvfB;y+qbll1Ra&YKSj zmK*C-{u!j&iSC%Y@H?o5d4ao0JbQj*hv>RfahxX=toU=@ooIM)+c4+SK0cNUa~Ie9 zB|Cgr2_7q*Ew*rm_pu^_eEa!JRt0k9F?p@y$+A4lnW+XE^klie;{kJheD|JME93QN z4)D*P;j8u}-CregE6?G>>S>!&LAG)1OFMXaevs`AcEz(fE+78Oe-k(Um9f3rnt_3V N!PC{xWt~$(696wh!pi^v literal 15855 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 DHbz@s diff --git a/doc/qtcreator/images/qtcreator-android-sdk-manager-arguments.png b/doc/qtcreator/images/qtcreator-android-sdk-manager-arguments.png new file mode 100644 index 0000000000000000000000000000000000000000..9123fcffd4bfe92d1f71fac6e638730c00c75bcb GIT binary patch literal 9060 zcmeAS@N?(olHy`uVBq!ia0y~yV7$k`z-Z0E#K6Gtr?h-21B0@*r;B4q#jUq`pkx4Zj!_T_hO9Ew+r<}Um9+rCA>X{}&}8;9bB9swr~6Xg~G5Qk-! zAcT{}I!pf7`TqBRUNuTwUdW+n!f$fCSkgqf<$}$HKjrrSj#ub4r?m)ZmE6i)Zu|L+ z@w=j}0e>^KO!EKV+2_5l(KSOzu)x# z{E4soa9dt;HUF#mMzi{5?Q}0cOn$b1s-8`imv;D{*Hz*%sUiY>4_P)yR zzlz!I|6X1`@8{Le;r8{f@BjND@Avnaz1jY+ey&fpKIeP)^VV0US(A&+?05Rh+E$%$ z+Q4_GXlI-g`}RpYD|~*s9(LIJ@zCLR{T%+uOa84s{&dpuTcO8;*KT#%HvPGju~Y2A zVwLHOFZ{WrzODY>{x-+ZqpZ)Fs@0`zDUjKI2 zg_gF0V>7$G%F<7l&WO&w`6u`^pM2a8&AAhPzF7J3zjc4w!tdSFIDcRJsyMgknAw`HJt@iMu~g0)ypqG zb5|!Vp25b#KKD4E_zB^4QmPY6&0e>zezl#c%q~mxM4)A^N!L}W%Uw&(N~`ha>^0{O zaJZ22TCbu#(DMd$dxKR;K`+x6~_`ZoJd zfBpZyK0j~ggOjKKy=rBT`*GF$`n+BL_MDH~_ixQ}!vzIm;b%;%QW_MI^XNYBn+vyXjALj=z zjQly(|6SFS>iK`({jdA)zW;aUr`!8JJGu7fwymDO z_o}6H|EpxL^bbpucf{0rNm$)J9QQjd(!IQ)q{y)FkfM#No}TgZvvbX|zRp&D<6#o+ z^3=6BIM+eNLt=U*sTSH@8~`SjKoGOf=JJ+FPWN&nyZ z>Gq!|pWpxGIa$m#{D!PEfK z4KDxSg(1^f4n>w(7x#Rbwtdf2W{!o|yyvc3P}#bq?B~trIfo^--#NLGYnG$&F$ojp z3q6KxXE{ugd1eV_9Fu5HW0?iv_v~(Y7FR!I<$dG-YfWr6Et{(SZ);h~3~~1blF2s7 zCh9$B1$UP{@i^~P(Dm}o`=>>FSynCftl~3C-cyw!7Lll@b#t!n^~630<6}EIIeSxL zaxNV@Yv<%ehq{u|#Y-h;>zgfzwft3EJ@eu&b+LN!6CsjKWe9&CgD$H;ERX zy~JTI6nB*4>Urz!GsMsC3*7c&Lh!8@Jr`v<+}AAMlgR0Rw>hmR{Da{G!N0XTWcD6A zvfldQMm3(fs~?2wXovUdtNB^CEI)BJ^66M;#q7UsjD+DD73So zMtz|8k~+t^^C!Bm_#3obE5nUr;X6)@N)?i*1f9T17Q_K3*@c-Gb^bqykNC9SYNzP# zdafz%9EulW9K!w|Tz)Hx)uhjlR*~jsGrgaHYCe3Lr7o0B6G2WT7`KNc~t@W|i z_8+qRGft#d{an9%ntji!f45fJ&Q}UsdhFZH{oU~?y7h%u|0`dsWXL+3)U2BER^n1< z-u8T0<5`Y{GZ#nBKYqdOG;5tn%CzL;0*SV%U%WoI{_6j{ z^YJr>&|^=$*H>NH^UTRaz&X_R)>Q_@mRSy)%U0(xU7FXRw=q_yc!Q|c;_!#lrmvG| zT$R?7_I;MXy5)0NGvBY@tJGrElg4QwHT&w7b!O`WE%g^z;RMG89_Uy3?j>sm=bHnE3I|+KRL1j!uhFt1Vl8KBA+aajjxTLh-SJ z_-dXNcbUKZ-nckTk!@#0*mkW1+XXCVITl9xXOzS@MhdnFFrDR|SntQ8*y8Z{PW!2O z;?~fn5h$*}O(Rgz0pfrouJPG|b5PFu|d6*T%hXT_#-Tj?{-GM^lu6?NUd-3rjZApKHvHzrN{D}c;7QgHsi^6 zL%zRyab!+`!TrwH(e71w(%dprPG6mO{lmr^%oVewl&*{ZuIy4yJXp&&E4uU9y#?29 zXmvb`T%;Qinrdh|t7DIoj{L0Uo%Z|p-4b`*>~nHrPGyno+?zMnYG;&n`xdI`>^L9J zaaQ`MzjNyJYfI9Po2y0hJ^tdoXm9?n=0r2Tv)Kk}yl+}>`39WH^M1c@OZWej#Mz6V zJ>rAh|<4;!wYZgxqY^W5}&UYqac#x@OSCmy_ZV9(j>)rVIe%-mgR5&F$d!{c|w z>^~keLgzO>^LlcVJ*><^?YdQSp=3hqUIYN3n)i|SV=Bjb+ zNOE$P*||JgetOCB;5FI)HnUpSY3SSk3-;hSwtwA~hc{m({ZCn~KKFg6;~SstY=!5! zuJh!I|27b;IAHLVQODfC{!Et~-g zQp^zj^{`pnuA7oZma~p>AFI&){9=v6=N+X}V*{^fe%X9cG;ZJVITIFkzAw`D`}1j; zy5r_xXP#N-HPuYCpV`{>*FSH4=3w4drGNixv1{>H(~*B!9k_va={UdB4hy^SZtm%0C5wqE;D z+2lK-57l2D3OnOx96mq6>9Fqm{jKkFUruMQzICg@Qn83B>(S$dY_rbhnQY7USK@3B z{?p>-1NH0XjJU3yX|LDq3Afo%Fn{^d$JPtG@19=v`Ox|;2Dh)U_~)zh+?L!krM>QM zL+$$Lp6e1{+MhK${-1pK#q$TpoR@rBpBMh(y5;8l)y*H*YVSE^RhRdyHf-5m$ES8| zcfynz63_pdm&diLp_TUZXM--ka=YCR7OsnOaWtew# zb-sjgR^GqUOv)b>B|tS$T92dgF;MZ~Xq<6OBKbm(;jsmhCdoa98OJ7D&S@!6)2yn! zZ}29-Ev(1UIF2pEcm9gvdD)3PvmA{xK>D98El{Z3`15L=^2Bw2?*^;;=UH&(|5)EB zv)gcH@!!gstx`(Gyv=Dmvm8Iy?0nl;#eS+D*2*C*jTOSkr%WK>)BYid@8in2Dyf!i6+F5Ggu z+xfHQ(H*x>&ENtxBks<-z_BEDTAf+Ij=$^spH&G&~!B-Q?9Xsbdl*&Ciy_ zReZ2zTk~V9pl(k>lyt6uzbUEF;sza5=#lIla@_pnoSes` zj;SB~oaY=kwb+$^{hdXjpNr-SF0h<;`jDXUGS5x+ONDRS*l$hR*ZOl^(DdIa(LaUW zMr`Rn@p1l}xw|f8@GePPxK1^3)^y3&PgXi?mTtIljA7Q%ggap#wrXeIN-<12e+P;Td^EJPEFjqJ1`?iavpXU6&G)HhjYPd=OkAj zw@KvD71)t|lx4Es#AAm-zq99B@T_Y79=h)9H_JzB{cmb4e^NAGuxD0kf%}_Vn`XRv z%2}41AUxGr_tq}%zHOfzWY}YFZuz<3X1Ur8Ms<#YY9Bu3)Xj$F57&sw`dIDZ^2_k) ze5S^KE8)YwQ+K8Nq%z`O88ew2_sg)@y?lqZe*V@)a@YCW@%`IiyUlM%3O4sjt_PO^2XK$F>YTGX_ zMEkwAY26BvK6}tiZ2QvY#@!b_Kk=P$;RS!&v#l52Zgh~ye7Gd=Qk3DrjPpyXgncq} zz8QRA(|;$sar@d#uJ48kYd0^>PG`wDRx$DYfl!{mFLHTi8P2oTxl~>Cx~%cuu?3Qk zSr06#IbL>Tf}{y3?L$&Ka-rk@amPyL^^6mIB_8iwRJjJy++m$HyCU(LM@z{Pc2FOw z)8GE@7vpmlkI!&4KD*gJ{rBFyqaceWix!`^{eEXU>sR-c4xi7opP46~)>^XN?OoK? z0$u$il@+|AAHr{M%sKSw*`@aa-kO}P@27+EZZX4IBcmfF+r!>P>FW2-Td-|aLrm`R zO`NA^8|yKId8J+eW#M^cS9G3-@I2w?T7Ge&u~Jy*>+TJ_H(Q!#b3ZKy7b~65XIZyD zvrHG}%kK+u0Tncvxqs*Rers!+@vbb(Tl(ZvL$Zt zIk~3!?$a9M4SrI+1>t8{&d%ODZ~yc!J>kV?pW1$IOTKXDrDCxk@9*6wehEE1owM1s zIHk|Laa+`lsrR*dI&IX1W-8C~c(wdW2UmiWN&Bvl?4x&zE6?wEC}C25jjivku=Dc% zsUl9h6aB*{7OURYoO)E>ZF=*^#G`*Vb);!~=yJzi6ibetI`O!R65Hd>BS~`vdrsQf z>bKiB?AUVUX*JXd*VZ#izvr4s_ERWaer^T#U8X_jd zu=D4{z0HrbOkQ(;m5i%hs4l*_JR?%F)50*zRcTS=smF7^SI%qK*J_xt<;vq*m$p!-g4Y>nv@yXEU!; z3g2X$Hs$=!nLV@S_O=xpa!+hm=G<_&|5=iD(Bb2E^UC(wH=NjVWnzYz+nRUFw2Ldl zj|ymoZGI?WvVPjrB`5jXs-mqvy~$*>tSq$KB4YONnftu2F`FeiO^!Zvk?T?UGUt@} z^)*XZd^3wl6}vi1j8DN#cWb@V;_WxN_lBq654w?`;c_e>a81UJtw(B)vNk`vTDShD zto+RNGB^59Z~8i^{?y6t%j|aZUS?X`Z*sHE&w4z=+{EqNo0bi06P_&exORq<^F6oj zK93`9>Fe3@xWpM2YAan1dcA&i{@1^TEakg|3&eao1Bu(ZQ7yP!b zWBkS;)tuJzvBq}Z>x3RqQv|vHgIWW_@(Z-eCZYmHE|S3QAc^D)cLYsV%X6;#o;>AM z_+;hN$EVME`zknZ`<9=lzol(`mH+Dcl&AM*t2NZzz4d$P&2<@{^RgZfu{YK!z z9-hU|{1)#_o16S^n)>aG9a|0mJ&*dd`MdPIS?P_>ZkBkvU%XRt<89-EHGI-Mv%z3J)gg@F`w?j`C_i|>tEX-{Hzr1Co^ycqt)^15OkF0&VWu1A!ZjAz-^rJ0X7xkqq zU%GL5=)SL~4lnz3=b(1Ovp+k0`YwMu@%hfq?hHRIN%_UuFIgI5Hm{_f2{>O6RxG%|DCLr(f06lug#}T>gukWFQojx;q^*hU1;Uy zF40i#_M0)iCYhI;?y79_n{nH8UG62rIXdQ*QU5)*MN3si{d7C~=p5I4>m9o@wyoRs z&DEmg){+hH6FyDRf4MAt(Mj7WXV*?Kx#G7iXQAc8=#7gu#1<|QlW2K1<>dJThHFjI zLhm~7P+7a%dW~B9MHwxf_m?*%cW3+O|G7DHOXl6YNoI2kb)}cE^*vm8G`oE54CR~e zKAaHrdD`OkWoL7Es?%ak6L$B$tIzis9`JNGWMw+^d{6y^Ajzp_ch@9@^8I3qmfHMk zapk1D3r#H-Ir%?SnAI&go99&Xyp7tocg|koJN@Zr@9voTQ)$WX4n=DJ^0;QThttHk zpK(^}Vikjh3+J|<>`<vd*5-*%DpN$0%E^Jmm&v@yL%S{4lIPh6Ic zb(oiN0aQw4^w}H{pVM{Sc4bnLM!4!LQFGlrA-h-DT=c8{E7|f@ZN^-g`Nca~8MkP2 znzEgJ`~TR3q~MQi7i3N?l<~Wwoo8im*XF;?ML*$1pZ>AvCEtEDiBDgvVVmm0V+(d# ze-`TYJSuH*JNc5*adlr_A9H;L|1Il_tT%7&mRLMFd-<`r0EXOiqJ56VyD#oJ5weFd zC}fH2JfXAPr-k3Hj=9af@SgUvq*u!j%BE4fivpRfS>f+wcf9(2bLTGR@~ysaTVMEG-c!)#_}ObwW#h_<-4j@M?0kRAHEyzl zG22<~mS?QX9=#0{dyx89&W!CWq@Re06Hq582-bN$OEpsDp=w{B00kx#k zgblmTUC(*`{A>T$8rANns}3bjJ0E&*B^hFA#t^S;_|NLE7Rt!`Yh7^14%`U6ec?{)l9Lk27xoBc zybHUO(o@JgzwXyd{gb6(0iZB{Zk`o)e(SQ#{B^cFL4$qgMbC;av5LQ3xifAa7dR3? zU3XBwaz|^%zR%~Z?Vr7Xjrv(;ZF{k1$C(w9$vxus3j;4yo=F8|sI@b)_Zf>8pOr{H zlk5QQ^nZs_&-RAL z*Izzo`+NG0RgJ4=uG*N#zvAJNL(_hpy0dy(6hvr&g+Cvxo&M%lMAhoFrnCz^0qGb1 z>}uW~vnP9RV|t23ZvzSNT*seL?p7 zYODMwm%qpUK6Ufe+J2wdm04;TZY!)a_I;eztskF%;eA+)UFDZ)AMJ%%=2txE`%>KX ztmLP)oVJ)*>eVxB7w07XoVb13|2^;5E|63-VV$*p@5g7|dhyw3@B|x8N$1~Jn>c>HwUFJfPp&$CvY|@Y*)Iz#lan8d2EUy3yRTnv=WkKpSMS{2j=$fX zwn{6+*wNVOuH$E3^Z1gR_mv7}1KUMd%-O8`- zX{@e4pCteCj5b;ccATu!XJ6~GcbTWm)fYe8F3p|4`~Q)Xzw_@+Ui9KXrLUr+yEb6b5<`MmrL z9X4=uGltFHdqG^b{>Q_|j3&=B&Zp_mxh1!c+eCRwQO3SkyPVhWeA2b_duW}>>Xw<$ z*EWDd>aOGG*L?e)J&N_tzv^>=XO`eAo>}qLZx4pYZ^?eScGgSh&+}}n01qm4Z*8 vvg3e+9%zY3)?!lTT(1a%X3esu{*!OCD49L+?8%P|3=9mOu6{1-oD!M<34+ii literal 0 HcmV?d00001 diff --git a/doc/qtcreator/images/qtcreator-android-sdk-manager.png b/doc/qtcreator/images/qtcreator-android-sdk-manager.png index 8ff625d2236fce7d05c4a9a090d0d16ca6997b15..7f24683d7417b80536b7384696f0c7cb699d13d0 100644 GIT binary patch literal 10398 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 literal 8740 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 diff --git a/doc/qtcreator/images/qtcreator-options-android-main.png b/doc/qtcreator/images/qtcreator-options-android-main.png index 15afbe73b6b331accb34124dc1d194648c7f2a46..70d119b3206b41a848d24014c02917dc572148d4 100644 GIT binary patch literal 18155 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 L{an^LB{Ts5lcev& literal 15736 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 literal 15511 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 diff --git a/doc/qtcreator/src/android/androiddev.qdoc b/doc/qtcreator/src/android/androiddev.qdoc index cda10b5a287..e9f3e569fa5 100644 --- a/doc/qtcreator/src/android/androiddev.qdoc +++ b/doc/qtcreator/src/android/androiddev.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2022 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Creator documentation. @@ -113,8 +113,11 @@ The locked items were installed by the SDK Manager, and can only be modified from the \uicontrol {SDK Manager} tab. For more information, see \l{Managing Android NDK Packages}. - \li In the \uicontrol {Android OpenSSL} group, set the path to the - prebuilt OpenSSL libraries. + \li Select the \uicontrol {Automatically create kits for Android tool chains} + check box to allow \QC to create the kits for you. \QC displays a + warning if it cannot find a suitable Qt version. + \li Optionally, in the \uicontrol {Android OpenSSL Settings} group, set + the path to the prebuilt OpenSSL libraries. For Qt applications that require OpenSSL support, \QC allows to quickly add the \l {Android OpenSSL support} to your project. @@ -122,9 +125,6 @@ \li Select \uicontrol {Download OpenSSL} to download the OpenSSL repository to the selected path. If the automatic download fails, the download web page opens for manual download. - \li Select the \uicontrol {Automatically create kits for Android tool chains} - check box to allow \QC to create the kits for you. \QC displays a - warning if it cannot find a suitable Qt version. \endlist \section2 Manual Setup @@ -185,6 +185,9 @@ To manually download NDKs, select \inlineimage icons/online.png . + To use the selected NDK version for all Qt versions by default, select + \uicontrol {Make Default}. + To add custom NDK paths manually to the global list of NDKs, select \uicontrol Add. This creates custom tool chains and debuggers associated to that NDK. However, you have to manually create a kit that uses the @@ -206,8 +209,12 @@ \image qtcreator-android-sdk-manager.png "Android SDK Manager" - To filter the packages, select \uicontrol Available, \uicontrol Installed, - or \uicontrol All in \uicontrol {Show Packages}. + You can show packages for the release channel you select in + \uicontrol {Show Packages} > \uicontrol Channel. Common channel IDs include + \uicontrol Stable, \uicontrol Beta, \uicontrol Dev, and \uicontrol Canary. + To show and update also obsolete packages, select + \uicontrol {Include obsolete}. To filter packages, select + \uicontrol Available, \uicontrol Installed, or \uicontrol All. To update the installed Android SDK packages, select \uicontrol {Update Installed}. Select the packages to update, and then @@ -218,6 +225,8 @@ \uicontrol {SDK Manager arguments} field. The available arguments are listed and described in \uicontrol {Available arguments}. + \image qtcreator-android-sdk-manager-arguments.png "Android SDK Manager Arguments dialog" + \section1 Managing Android Virtual Devices (AVD) The available AVDs are listed in \uicontrol Tools > \uicontrol Options diff --git a/doc/qtcreator/src/android/deploying-android.qdoc b/doc/qtcreator/src/android/deploying-android.qdoc index 362abd7cf3e..4f361e44222 100644 --- a/doc/qtcreator/src/android/deploying-android.qdoc +++ b/doc/qtcreator/src/android/deploying-android.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2022 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Creator documentation. @@ -128,8 +128,8 @@ \section2 Specifying Settings for Packages To specify settings for the \c androiddeployqt tool, select - \uicontrol Projects > \uicontrol Build > \uicontrol {Build Android APK} > - \uicontrol Details. + \uicontrol Projects > \uicontrol {Build & Run} > \uicontrol Build > + \uicontrol {Build Android APK} > \uicontrol Details. \image qtcreator-android-build-apk-step.png "Build Android APK step" @@ -166,9 +166,9 @@ distribution to the Google Play store, create an AAB by selecting the \uicontrol {Build Android App Bundle (*.aab)} check box. - When building with CMake, you can view the selected ABIs in the - \uicontrol {Initial CMake parameters} field in the \uicontrol CMake section. - You can set additional ABIs as values of the ANDROID_ABI key: + When building with CMake, you can view the selected ABIs in + \uicontrol {Initial Configuration} in the \uicontrol CMake section. + You can set additional ABIs as values of the \c ANDROID_ABI key: \image qtcreator-android-cmake-settings.png "CMake settings for building AABs" From 68592ad59e4adeee6f56c1e95fb3cf9e13fc0b33 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Tue, 8 Feb 2022 14:01:21 +0100 Subject: [PATCH 23/94] Doc: Update info on clangd, which is now used by default Update the text and screenshot. Task-number: QTCREATORBUG-26610 Change-Id: Ie35f3b6885df49029ac0dbc54677e9e6f472d2c4 Reviewed-by: Christian Kandeler --- .../images/qtcreator-options-clangd.png | Bin 6895 -> 6133 bytes .../creator-only/creator-clang-codemodel.qdoc | 11 ++++------- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/doc/qtcreator/images/qtcreator-options-clangd.png b/doc/qtcreator/images/qtcreator-options-clangd.png index a277d076c96ae463a2750fa9169f01805fee828c..ef955f4563d816d11474e62211a5db8cc8ea7129 100644 GIT binary patch delta 5480 zcmaEF`c+@GGr-TCmrII^fq{Y7)59f*fq_Yafq~%?2Qvc$gZ(zon+yz0cP6STF{`So zP7GMgq@FeLljdYO#=A`I?UR2onoKris+qijDXu<$N6j||29YbCE{-7;x8Ba}t{1x* zd3>|xLMFw^>t%`(yPZ8E7KCkS-6Wnju_ZP`d1>v|Z3%|1&AZq6zFz8*z3^*L#PzTj zN2OltbzaL8DtSGrYX9DC+1vO0TBNsW_Ys$kfiD-Ch(445U~_)wnVF}n=PS;B_`T-A z+{*KFZdacxKUZ&QYOY{_Xzf zcao1re2Cq2V23x?^PQhsUhms;U2941n;qYm-YwlX^DMzW!v@DWR}6FLqbjXtnKs;c%>W(XntRR@bZ3vTa0HxNQmfc=*rL*)4HT zODBi%9NV>W^P|VtUoj_Ny|UuRkE2Sw`(7PA{AiJQkX+A-eHqf#i6&OLPtC(#R&DEz zwK|s@VJlI~^6!ACu)Ao;l5KbF?aOwg96kN_!i!Jc&w@O6|2z;;UH>a*$M@B&$xk~k z2JK%xH^1-K!5>SXf4|1=HnVD5Z>^pG)xWhV z{nIx+S(Gqko%%v`J)8g2Ha-qC^lG@cTuj}nPt)W2v}(Un`S`cRzS~y4dgWc$TJFCk zQuLvR=u~~-^)?g3ReFBS{<2cO)=TtS-O@vX$$MYdbBP@3{NaC~qMgf~$BwUO-6Utb zjqAi+lFmJ~>bClO@7{r}mz3K&H4i@W58t}#I?t<|(2Px;GKO7Og3}H>a677DpHz_$ zq0Dx@?5apVXXW~e_-+4;-rQfVwWvN<_37%e>Oj6G{U?8YwTk3p6}c~e)!cqepl6M3 zsIWxUB_5OK-SzFc%XVhf{@hpdA}Z6M#K+R+A7A^5n|q=RPFf%!qew_N=Xju2sOGM(8`ghU!UPlZT&iA?&e|!JCO>B!- zt!&|5?E1rE`bzc(g{)7?1Nu+R&b+$6#<6$8Pp*RohN-_+&OV;mRli4u*KOv?B|f&P zo1dQLkn0G1wKBzF&HC_pALeh+;M}8{>2l&Ogo@z`yC2mUZKMn(w%C{d4K!dZ$3E558y?O#;N(8lz5MXt*iji~2k?1yWN6YlKf zPGIQaFsMuTl`bM7``m9;{{|6Gy<*Ny1qUn6&X3aT zsg4F#=~t(pV=4|bINbE(&5SvvR?quNeEckK&Q`z5*gIRzVBhERfz1yb_OG zjxb1UKltc#TGZ`o_fCyN)Lj(J2{b}~Tdu^W>zdoLBdNhNjD09~Vi(56) zUB85v|Cs!I-u7cE)kos}8Qr`NWZc?S9GtVMI9vFD2d4xt|6WbE$`yh=z|$beEV1S2_3e9i$LTUmwTnz`TKw*7^P-hT>t;VTGgd#Vo8H!C zo@?(ud1C$VwdZ|a?Af{V`K#}?l^0HL_?oSCUyM&TG{U?0<*C?92{t<}s^9;d?)3S2 zzu7enelb?(l7z7QTUVm@uXb0NqLpY+RkUess`aeN4u{#Ic7A=X>Ebr+`9p!Zp{Gw= zefRI-ig}MNOxhcfy-VugkIVkKf9}=)eW`N5VD65B0}pQN8!Ol6y_r)RB*mk6+TJEb zsrz$5hu!<1Ytwf}?-!cN-ahTk(WuLz9LL`A+WlN-|5N4vdf&3?%*`fKGoxm{wfO!~ zbNd3dnUP`IGat-Ya`(?;r`H`KeGwOLW>}Wbsh;y#D>vQmzM|>e=Y1t=8{7Y^ka=4? ziSvDn)HmnnnR*$v@8jyvchtW=cY((+ng6reCaF(<6<_W7s=fAnnX#povy{)dKTN*H zUCWc#S^MlgadWkI$gAn+d9Kd#lb@CPwf;xMI?Lj%v;Fv|F+Se?KU(JBkLdUH%`evK z=l)o!U-&@!-_Nh}m#tU&5dD5VCy(XS32~BNKRwx6JGVH>e`?5?mU}Z7Z=G#Dud@Ef zOyy5kE*FJqhRRKj3ifsLX6sqFD4|2s;mqqRUuMqP^>@wg4ffAn-<@}DIZ=GElZj_y z^W4PKCwz+Cz6iGJ*-tZ;tezg_);7C359BoU>4Gj_=hyVlxnX1}%`<=fyLIcTkN8@C z@30Wrbs}^3hbQ~$wq^fa>J+|B!Ee`+*YBL_!v$aJZvCOcljED}zdTk;nAgw3ZTHUL zC^v!S^QLWPJN!g3XhYDJOYMHIR;nD z`qFZx&hJ~{)*DjEKQ|_>XFf7h=E&DYPHtx0Jq{f6|F50V9P>TPTvsBrEsQ;Q#mV?I zd4|QuO2i~&e49SrIe0)ynW<;%^7By%Yiz&%5WoNLwS8e>eRzHNHQUpTv0IxSUJluI z;K524p#!(h7HQ4=!js0qHpkD>Z-vbf*NIK)Q=86M3L2z5K27mDPY~6=l z@!#jZTKi^c)8xO**W9jWy{!NAjMrZ1jTUp;l@PJh$0J{#ObO7lyPC~6OY&dvfeBBK zs_Pnio}T%v|No<-uh(2FtDDty_0i?Iz5+Z_eeHXNO_OT+&S$bLYkl4m@wWCcC#M^K zFSDg&WW zT9l(_tBcmmVEqm(iB++Wz%{WW(fvmt{&Iucm4g{zqji!NoX=A zpL}GVe_wENPW|UcO9SLRx_=$GBACF?#CY4;jk*- z|GezPWhOn-HlGQME1%P0aQ?xu+fCO`y)<>JSkiuE|FId?PO&*XNi4cC1v-3_u5V53 zi5LBK=2&pC3(;0yE&)Dvdq8yy*^+@YJsv=-OiONFDA-OQjl=fjai{k89Uo`he@=&#Jq#OQ3p6G zm$a*}yKQOZc9%LX;P`3R#*HQs1#2=LCDS+Xq!sXe3wgx7nKzGR{nYthhvZ%=e%yat zV?|!)wt|CuPdT3IVv|1h;KiYs>DuD+=M}PL8XTTAM~}sgNA{WIor>uC4^gfOSDsIl z3zF)QP|2I@CHkb@evvMV0bBC6nZ`3(c;!y4Wo?ejJag0{;mBP16ghVujsp!0Ai{xx zjU~Y$&)VQa6L*3OS6L@B52$l=Oq-*pFWqZ@gWe`fC6PNX`q2FngQHAj;s}_)*Q9f$hMD=8yNjGx0P$WPjZ2#8>-mbNh=Q z0tYyn72i0Vwy%6$dsk=btNEcNFQ;;~J#d=DXrOf9MT+gjrdx|57tL<|UAUT6Ijl%T z;;-@4#TR~URg~`OmFEA;R)2b7ue3aiM4~~)>GE&i|6df`y1maE55LSU zoLM$C;meb%A_nD^N0$fO`tfMr_qig$T^E08Wu&Vp#u_i3woK$I)2d9rfb;cd-tTM? zI>L4A6F>h}yW3~?-Ya_c+%2Yj+0L(fUh{S5%UiwY`@Un{fo1V5+b@`QZTlk;n`U4Z zu}M0?rQxEb_KXu^n^^aYUEsFcYLczBaS98_)GbyM*Jg>m4pCYmkfUMH_QSx)C%bdn z#MO5t9bKROaeu@CL>$I6xQVWvq$HPeE)7g_mj2E#B&}>C1-2ydHz|Ixm}89 zmU~rNjzQFXVU;iZs|EheFT5))#j|hCfft*Wh$px-Z2V=S`Nijx(V=Ug!`k1hL7NOrEx zUKUz^*vbYRddJtNi+zYOlKA|{xOi*y8sk3R?)tMcrSFA&y5q>rBiQ+D+J_J&qnCdb z75CmzTA<{bZ})rW^rJCKY2EeWw)geL=bP`zY>6z`|B)qr@`D*imn)xqQOe+U>%fZl zXP@6y*str^^+4rJ8#2>1NnZqn2>rD5Zf(63D!4^P(Z z-Y9LMn~*Tw0$R|3OB*;5aYN`jx89yRUg8p^GaVZ^TfQ`1j&*3>f4`wo_|v4-XSGg7oSM3BChHbM z*|#&zFEunBeplZdSH60d*OOny8;)(rP3|~8?O}!i--+dum>Cv7spg53)VR!gsju;V zgJb*K+VDt|1zW7dc3%qJCNL$j#c}74DIXW{Xl$rI9;aQLTJM+^WGHdyNTW&hf*yI6 z108YwLR{>2%1;`YeZRBZuQ}JA?8D|PX?h}JzMX;5pIORMJW7unm<@tB-D+pOdtYa6 za+i_KN8t>!#AiibgGL5}MN0(L1Q^_=TuEhPR1>(w%?7HSU=l%GFYi>a1z+2o~63H4zi?_M%6h#&QIaSW-r z^>%J;jmYuJI3XV>+c?$3H2y|-t5?9a_<=Xd0u?c&<{Y@1}K;%CwAYhuNxU%U6IYi8lI@V7Oq zr+?h4J%7`h*D-+`tzHW`Khxc=*WthYo{{#oKda{Ee>K`y_Vj+0_uXZuPTrX!Q*U(r zSXI=uxb54t!Z$?y4AXy{9scjuu5;VErYDc7kQ5!scHodbTer#kbw9d9={UfNjwvuV;s9=Y9Wl*U#bd#J&G!r=9=(@ElWN zp!%+tE1p*>cb|J#8f+$O8~z}|E8-n%y-t+BX5zsn-SBU2OF6`3PgQVV{Sg!A7`XMR zRDatl!L^(<8xnqgbJ+js*_3I%&o*65{_^Rhrr)zg7a6O5&SeU(xyWs;d5K@sH%)}c z*L|LRhuyY6%a&Hy&hDFY^R#&3qm;bB`pUb{bEIMe8gCgX?BBFG>V4Qd1vm|zI%6aV&tNEzV3GRi&p)gIU0L3B=!@FJlvAA-_g-Ph z|JQkrC3lB#zLk~I-IMhzy)XUw6g_8$Qp%<5$+J&S+yWwWdCJIx4)ezpPYuE0o z`utP=U5NXN%cbj1h89qSXVJSGnnhGvSa=tyixx=cW3k?90?hQUsdU)y;ntYLoX<3Wy^Rs` zQ}z=!RnKBXX8uyn*Ss@3*g5mrv(x%H(Ph^rSZ=K<{l@pClZqa=DD?%}Ml3!eBW<<_UG^IblRZZ{8a{(M05>AgEOPjr=A-=|-a zaetS7srRhBP40=1*x#DzCrwnv_q+|?GjCPszrS;r)jbqZeV@LHdDqwFlbU7-ghuaM{QCa2+;3-= z9RK$0pR}dZ(M_uOT*bx9*1S4!C8vpqr9br&1sOB&7yt=5f`UY_ys zK=$f|Sx+HFWj45s3RMxFRW@tu!X$(6wf6DDbjR(uK1Y9GPgjUpB?bQ{}U4viyaVZF6p{kN*^^aHIFslc=^6zU3Q2 zD?7iX)nA>h{rj?z+WME%9^2|VTYA=}?(aP1srE%hI%rzo*_$!dn|Cy9^?J5?f6=pV z5hr4bs#f27Eo+i*BwjM3DtGUd#V2eE+nC!rd}P1=Nm%ek_5Z&ucjIdk?AImqPTHCL z=HRc06K7In-8lWew*C8^vdX;c%<>TH8^3JrUroFmeRq>_edMWAPp-~7EV{E@D zzkbc$_pf(qqS4e&Bh%`|w>)RwUuE(2fkjvSl-+k!Uv(D#KI;}`etZ4=lS@CJToO0$ zWX+EX{-t#{I$xc&N(plF=2_)qsh7BRV&(fA&7WV}TWnix=aaTt^7+;@$unzmB}6k# zbVB}qy0Cypv~uyH4s+9j`Vf=oGa>os5?`4f?-c1+wSE8dBXzPzJAS1Ib@M&die7Q- zM9tmj$I8~$JzKs0q;m1e6 zC!E|{yTS78&y-c`Y$h95CN7BV-urXa`rh8&y{GrjKPh6+A(?-{&i&XVPwOd*>UoT! z_5Zv%=y>}@J5J#yxit9^~IF^7mJIp-b4LVGG_9jzDmbuUA#_;b|W>@8_V_x;%9Wx}Uk<2`)lma=hM zd`XL(%=DE`pRaYRZGLuQPEK;zgM)aQorZC^n3P>ZN;ryYY(o8-~4l}VW#olB90WNj}t7j&$fkb%sf0RQbD+@{mic2 z_e2)ITg5yxz$YcIZ}OS53c_7$&(E-leo{@7{NmmNWYtta;sr#jgG-CmORzbLhJS20scS8Ln< zWA0f>1y5x|YmJ`IeY1S}{UDz&#xq`BD(`)Ld49d1Psb9y(v?cdyV`U)c8P30Y`QR( zvwp(goz-zl33tNHr>&kC-W9x)sdV+19XC$=nQb5Q)A;|#+2QRz-WNlZir>jq8$PS` z-fOdZR_{*vm)fps%hz?BId(p8%3KlCv$BWZ@pW@;XWWu6ZSninu_Dt?UWHoW3-YGQ zg&WSC9meuya{XWSKl_bxXIacV<<=eBeqwU&mD8{4>g|r7KFe;obkn_Gp_`lo{5akm zO4Z$Q!nXTzmbRYVKG&QbdSAE1-G~x3YISLP{KsvXf~sug_51SA?B?np+B13H^?b8C zT^IS5hb7*(`J(7|dSP$7-0mH7nN~hrdai8G#N;!L{e|^+CRDvN;Fq7Fr+5C{jAd8Y z4Ehp{?nXF%ztHYqAM}5n)NSYeYpbeO&RG{IAHLMl-E-=1E!%TBPd3N@X|+B4>dHy= zc^WhAzuIs4xmtejdtR2~)5HH9n{N4m_x~^9`X%>*9`xT67oK@(cJ}t3X$!fdqxB{E zl~eaQ_Q_->@4Z^|r|#|giC=YhtU2HILrQ|5-!shAX#d`e6K+me^!dJGeM1S)@7%P< z59>@tjAuL7GEMYad&o+!__tMgf7Vec{?Dz?Ja#@h_i{`;+J^AKMu?uHUEq}#$ zE9K??joVVw<)h|hN7t#{o_6vQ-_iN?6)SQpx2WM9tOKy6eo>dyU^{mO=9Ig32ewVJUH_vJ*FN#ohM&cCZ6Qpovd`htI}Pu-NdxoX8J@2T3h z=Va>dJ*YoZx7k|JsMF@qM00(+3)iky=iGdm`@Z(cm)ra{TXLp!#2gE^Da_U?H_n&F#otE8in&KexTKDDI_8Mp3CWE_Lx=YVBD;>@7 zo)o&;{JF8WanjYasF7~t6In4Z0Lz;=*OX{E_ z)7!qI+Z@%+Wou^CpGnXOPu_7bZQ1c-_djJn33)ooielgKyx3HKcZK$|j}`Gt zm)*_(6w(-Ax8^zToW~Zv%KQHBIC6veEYFW6=6O}8>*|l+^IiIrjs3-68>8lpch=Z0 zE8f(y^3+Tz&rqK!>xz~hKY6St>fdCIcMl{3R^HoV`-yGGws*-ES6p2Fmh0R~QYfBP z!=BRi@v~o?-s58(OXgj$osy+d^=@Ll)}5Z0_qJbpto55O+{Z+>$jjr#vb6d+kGazRF3x=5r#uHP{#ne{UB;4CqrFNp_ zk>cmJoB46u?bOy*e|}?md5+JTS9_~gS3N(|lOOv2Oy>So;vkQRd(I_R&O`Ak+A!-KV=g*jV60Mvp#0WV6NbhfADz>^BYt4}Jj=iD?p^3G`a6yFoU)2ohTU5+a7 z>=T;r=ic(OZO-?W$6k@=-mKeS{^sD%uktdtTX+5}kxP$z71$Gb`OF4pwdIc#I?a#G zoUgE1H+9#Porj)9-O9Q=LDTY8#pI3BVkS>`j!jkjTsmL+_SRoB*Y9IXsrUPC7Hl(x z%QE4WLZ|t+mh-FC-hBx>z9c|C%{NJtz0-gB=fg72=T>}KTJef7+_EyI3ywhx+rxc7<#%pQyV}Y%?aZY))9PDww3RPs z?w8OJJ{%h}xfw?HE08r#fGIUBF)xGrYxb&kBvb!nC7)@2vh zE&3AfePhYXE&Hd1vlplBn*N+sCM|ba+^WQ;tNo8QZ^|&*k#IS(_Mtq#QTE!iQ;sGs zzGU+1*r}KE@3!`3y@c4%F!NoL?*vYxTBFO7cP*b!)_jHuAIxfe%h3ESF03mgifgfg@fUK^XU)5 zHfK1Ah3s0v|59>-@EP|uv7B$WBqz+T7f87#Fw^tmk$2_~#bp(YXM$tJX{#@^(*f^k zfFf|tmS<;Hbo(0TF~}+y>lv*7zwzYCcWd`uyKwKmTau{g=fj zV|ErDpTD7OO-!Zw2_J=-S&Avo^#577nS9=m>2CGrz(bptbNcgpUrUBKr5!Ig zZg67GHe-dTGk=$^eSg<~@2;854xQs=R^H#0W)yC5i^ZsZvPW8W z--0tK#y1z(9{kLBm~Xjx`L%a#KGv5m+Oe*6S~;C}rp(%tImK5vjV9N7JbTo9Dl?&@ebPF4Hv2s`(G$*aT<$A5 z(Wv}o$>$x_#aG>{?;U;XdUA$uwu z&t`m_pC)Ja)`MNv!pYz2eQzb(6s!FckIkz7^)lZ1)u#Ki?RVc*oGi5Ro$Y?}-q@ZM?tF5|lIiUeetL5qy|SaoVp8}7OWu=L&NbbdapDK}Bu&MM$u?}8`yM73 zgdVtaqWtD2ySAVI+H&^gI`^(#cy5V}(bVS;3_j10s-GTSR=1h2b)R}-htH1#zOqIq z&-?zlUGv+#UH{j6X|Z41^4?in1xX*;n7{CGa>RlA6J&SzKD%apu6(L?KAVee#SEYO z3k^aKXiKN~tt?E_G&=n7VEL67Su2igzwq7ANBo1i%5r_{tQB*7jLc7E8`sM3n0)cB zwG7wt3wLTRl#7Mb|INP;AF%69j@(SOs{*qR{gU0dQCjYl+oa6H#*wpkZgig$kgqp+ z!3B%UU(YQ$SzT{3^ZUs=f9xjAeDiyzjn$QNO-aTQU&Kvn3(gtJgdCq0;{WlE=Nhi9 z`HAb#G^oT**{`^C-<8KH>)r~gPTq7=#A1`HBa8kAS z)2?0qOhqTI%xl(sZt9TMm0#{QdF6#Y`n*PtX{IOU%;CSY`#!I{#e|tIMh^ol-k#he zwyN1#@r2Kkv;zwTQq+Pb7iqRQE1p<04|_5Lr!wTxoe)=}|MJn>8wEvY-fwDRU|?YI MboFyt=akR{0AbNgA^-pY diff --git a/doc/qtcreator/src/editors/creator-only/creator-clang-codemodel.qdoc b/doc/qtcreator/src/editors/creator-only/creator-clang-codemodel.qdoc index 377f50394f4..3211d7d950a 100644 --- a/doc/qtcreator/src/editors/creator-only/creator-clang-codemodel.qdoc +++ b/doc/qtcreator/src/editors/creator-only/creator-clang-codemodel.qdoc @@ -149,11 +149,9 @@ \section1 Configuring clangd - You can use the experimental clangd support instead of libclang to receive - exact and complete results for services such as finding references, - following symbols under cursor, and using the locator, even for complex - constructs that the built-in code model cannot handle correctly. These - improvements are based on clangd's \e index. When you \l{Opening Projects} + The clangd \e index provides exact and complete results for services such + as finding references, following symbols under cursor, and using the + locator, even for complex constructs. When you \l{Opening Projects} {open a project}, clangd scans the source files to generate the index. For large projects, this can take a while, but the index is persistent and re-scanning is incremental, so nothing is lost by closing and re-starting @@ -171,8 +169,7 @@ {Outline} view is backed by clangd's document symbol support, which makes the results more reliable than before. - To use clangd for the current project instead of the built-in code model or - Clang: + To specify settings for clangd: \list 1 \li Select \uicontrol Tools > \uicontrol Options > \uicontrol C++ > From ade68514ff71a534d7578b2bfc65f4d70bd21d3a Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Mon, 24 Jan 2022 10:23:20 +0100 Subject: [PATCH 24/94] PE: Tweak clang detection Helps to detect clang on docker devices. Change-Id: I9340900e205e767d8b058f6e69c61abf41c25726 Reviewed-by: Christian Kandeler --- src/plugins/projectexplorer/gcctoolchain.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/projectexplorer/gcctoolchain.cpp b/src/plugins/projectexplorer/gcctoolchain.cpp index e4f4098c5ff..a194f3f8f3c 100644 --- a/src/plugins/projectexplorer/gcctoolchain.cpp +++ b/src/plugins/projectexplorer/gcctoolchain.cpp @@ -1187,8 +1187,8 @@ Toolchains GccToolChainFactory::autoDetectToolchains( bool existingTcMatches = false; const FilePath existingCommand = existingTc->compilerCommand(); if ((requiredTypeId == Constants::CLANG_TOOLCHAIN_TYPEID - && language == Constants::CXX_LANGUAGE_ID - && !existingCommand.fileName().contains("clang++")) + && ((language == Constants::CXX_LANGUAGE_ID && !existingCommand.fileName().contains("clang++")) + || (language == Constants::C_LANGUAGE_ID && !existingCommand.baseName().endsWith("clang")))) || compilerPath.toString().contains("icecc") || compilerPath.toString().contains("ccache")) { existingTcMatches = existingCommand == compilerPath; From d8bd4e8e0534469354d9a15ba3ef161c5b701482 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Mon, 7 Feb 2022 11:08:23 +0100 Subject: [PATCH 25/94] Tests: Fix pluginspec test on Windows Change-Id: Ie72131f2e85b999ef8aaefd773407b2c5ce23019 Reviewed-by: Eike Ziller --- tests/auto/extensionsystem/pluginspec/CMakeLists.txt | 2 +- tests/auto/extensionsystem/pluginspec/test.qbs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/auto/extensionsystem/pluginspec/CMakeLists.txt b/tests/auto/extensionsystem/pluginspec/CMakeLists.txt index 670412bfd84..ad91750f287 100644 --- a/tests/auto/extensionsystem/pluginspec/CMakeLists.txt +++ b/tests/auto/extensionsystem/pluginspec/CMakeLists.txt @@ -4,7 +4,7 @@ add_qtc_test(tst_pluginspec DEFINES PLUGIN_DIR="${CMAKE_CURRENT_BINARY_DIR}" PLUGINSPEC_DIR="${CMAKE_CURRENT_SOURCE_DIR}" - DLL_INFIX="d${PROJECT_VERSION_MAJOR}" + DLL_INFIX="$<$:d>" DEPENDS ExtensionSystem SOURCES tst_pluginspec.cpp diff --git a/tests/auto/extensionsystem/pluginspec/test.qbs b/tests/auto/extensionsystem/pluginspec/test.qbs index 88a009982f6..b8196f93e67 100644 --- a/tests/auto/extensionsystem/pluginspec/test.qbs +++ b/tests/auto/extensionsystem/pluginspec/test.qbs @@ -10,7 +10,7 @@ QtcAutotest { cpp.defines: outer.concat([ 'PLUGIN_DIR="' + destinationDirectory + '"', 'PLUGINSPEC_DIR="' + sourceDirectory + '"', - 'DLL_INFIX=""' + 'DLL_INFIX="' + (qbs.buildVariant === "debug" ? "d" : "") + '"' ]) } From 67e4e4f5a7b32037e3ef1b4bee873852976a3171 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Mon, 7 Feb 2022 12:05:55 +0100 Subject: [PATCH 26/94] Doc: Describe new option in Qt Quick Autotest project wizard The "Generate setup code" check box executes C++ code before any of the QML tests are run. Task-number: QTCREATORBUG-26741 Task-number: QTCREATORBUG-26610 Change-Id: Ica4d0391e3624196b3327267f5a3082ca57b58cd Reviewed-by: Reviewed-by: Christian Stenger --- .../qtcreator-autotests-project-qt-test.png | Bin 0 -> 9867 bytes .../qtcreator-autotests-project-qtquick-test.png | Bin 0 -> 9287 bytes .../external-resources/external-resources.qdoc | 4 ++++ .../src/howto/creator-only/creator-autotest.qdoc | 14 ++++++++++++-- 4 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 doc/qtcreator/images/qtcreator-autotests-project-qt-test.png create mode 100644 doc/qtcreator/images/qtcreator-autotests-project-qtquick-test.png diff --git a/doc/qtcreator/images/qtcreator-autotests-project-qt-test.png b/doc/qtcreator/images/qtcreator-autotests-project-qt-test.png new file mode 100644 index 0000000000000000000000000000000000000000..aa5bee758c641cdee31a196f19458ddfddfea18f GIT binary patch literal 9867 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 UdrtpkU|?YIboFyt=akR{0H3h>rvLx| literal 0 HcmV?d00001 diff --git a/doc/qtcreator/images/qtcreator-autotests-project-qtquick-test.png b/doc/qtcreator/images/qtcreator-autotests-project-qtquick-test.png new file mode 100644 index 0000000000000000000000000000000000000000..24d61b245aca3603ac8f7774911bcee1e783446e GIT binary patch literal 9287 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 Date: Thu, 3 Feb 2022 16:17:10 +0100 Subject: [PATCH 27/94] QmlDesigner: Improve finding node for cursor position MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using nodeLength(node) is very slow, while searching for the next closing bracket is nearly always sufficient. Task-number: QDS-6110 Change-Id: I22f710f4cf90302192285a8cadd6ea6fc698b2a6 Reviewed-by: Henning Gründl Reviewed-by: Reviewed-by: Qt CI Bot --- .../qmldesigner/designercore/model/rewriterview.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/designercore/model/rewriterview.cpp b/src/plugins/qmldesigner/designercore/model/rewriterview.cpp index 1fc05f10c04..1f730ce0f6d 100644 --- a/src/plugins/qmldesigner/designercore/model/rewriterview.cpp +++ b/src/plugins/qmldesigner/designercore/model/rewriterview.cpp @@ -861,11 +861,17 @@ ModelNode RewriterView::nodeAtTextCursorPositionHelper(const ModelNode &root, in ModelNode lastNode = root; + int i = 0; for (const myPair &pair : data) { ModelNode node = pair.first; + i++; + if (i >= data.size()) { + lastNode = node; + break; + } - const int nodeTextLength = nodeLength(node); const int nodeTextOffset = nodeOffset(node); + const int nodeTextLength = m_textModifier->text().indexOf("}", nodeTextOffset) - nodeTextOffset - 1; if (isInNodeDefinition(nodeTextOffset, nodeTextLength, cursorPosition)) lastNode = node; From 93f46595336ad406566472f17e28740337ff16a4 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Tue, 8 Feb 2022 14:58:01 +0100 Subject: [PATCH 28/94] CMakePM: Add "Close" button for Kit Configuration dialog This looks more in sync with other dialogs that we display. Change-Id: I445da900982b7bdcc12d810e69170b0a7695b30c Reviewed-by: Alessandro Portale --- .../cmakeprojectmanager/cmakebuildconfiguration.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index 2f4c082c70e..02279d1408e 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -639,6 +639,7 @@ void CMakeBuildSettingsWidget::kitCMakeConfiguration() dialog->setWindowTitle(tr("Kit CMake Configuration")); dialog->setAttribute(Qt::WA_DeleteOnClose); dialog->setModal(true); + dialog->setSizeGripEnabled(true); connect(dialog, &QDialog::finished, this, [=]{ m_buildConfiguration->kit()->unblockNotification(); }); @@ -658,6 +659,12 @@ void CMakeBuildSettingsWidget::kitCMakeConfiguration() layout->setColumnStretch(1, 1); + auto buttons = new QDialogButtonBox(QDialogButtonBox::Close); + connect(buttons, &QDialogButtonBox::clicked, dialog, &QDialog::close); + layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Maximum, QSizePolicy::MinimumExpanding), + 4, 0); + layout->addWidget(buttons, 5, 0, 1, -1); + dialog->setMinimumWidth(400); dialog->resize(800, 1); dialog->show(); From 9c5e6e2d8c6a6415c294004a14eb3650221d9329 Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Thu, 3 Feb 2022 19:49:27 +0200 Subject: [PATCH 29/94] QmlDesigner: Split components and assets libraries Fixes: QDS-6151 Change-Id: Id6f79a2d1fcff5fb55d3ba3f1b1394f1f55ca36b Reviewed-by: Reviewed-by: Samuel Ghinet Reviewed-by: Miikka Heikkinen Reviewed-by: Qt CI Bot Reviewed-by: Thomas Hartmann --- .../{AddImport.qml => AddModuleView.qml} | 34 +- .../itemLibraryQmlSources/Assets.qml | 444 ++++++++++-------- .../itemLibraryQmlSources/ItemsView.qml | 59 ++- .../itemLibraryQmlSources/LibraryHeader.qml | 266 ----------- .../itemLibraryQmlSources/PlusButton.qml | 79 ++++ .../itemLibraryQmlSources/SearchBox.qml | 168 +++++++ .../workspacePresets/3D_Preset.wrk | 5 +- .../workspacePresets/Essentials.wrk | 5 +- src/plugins/qmldesigner/CMakeLists.txt | 18 +- .../assetslibrary/assetslibrary.qrc | 16 + .../assetslibrarydir.cpp} | 36 +- .../assetslibrarydir.h} | 16 +- .../assetslibrarydirsmodel.cpp} | 22 +- .../assetslibrarydirsmodel.h} | 12 +- .../assetslibraryfilesmodel.cpp} | 12 +- .../assetslibraryfilesmodel.h} | 4 +- .../assetslibraryiconprovider.cpp} | 54 ++- .../assetslibraryiconprovider.h} | 17 +- .../assetslibrarymodel.cpp} | 77 +-- .../assetslibrarymodel.h} | 10 +- .../assetslibrary/assetslibraryview.cpp | 175 +++++++ .../assetslibrary/assetslibraryview.h | 67 +++ .../assetslibrary/assetslibrarywidget.cpp | 407 ++++++++++++++++ .../assetslibrary/assetslibrarywidget.h | 119 +++++ .../assetslibrary/images/asset_default.png | Bin 0 -> 312 bytes .../assetslibrary/images/asset_default@2x.png | Bin 0 -> 346 bytes .../images/asset_shader.png} | Bin .../images/asset_shader@2x.png} | Bin .../images/asset_shader_128.png | Bin .../images/asset_sound.png} | Bin .../images/asset_sound@2x.png} | Bin .../images/asset_sound_128.png | Bin .../images/asset_video.png} | Bin .../images/asset_video@2x.png} | Bin .../images/browse.png | Bin .../images/browse@2x.png | Bin .../formeditor/abstractformeditortool.cpp | 4 +- .../components/formeditor/dragtool.cpp | 6 +- .../components/formeditor/dragtool.h | 2 +- .../itemlibrary/images/asset_font_128.png | Bin 238 -> 0 bytes .../itemlibrary/images/asset_font_192.png | Bin 287 -> 0 bytes .../itemlibrary/images/asset_font_256.png | Bin 339 -> 0 bytes .../itemlibrary/images/asset_font_32.png | Bin 190 -> 0 bytes .../itemlibrary/images/asset_font_384.png | Bin 755 -> 0 bytes .../itemlibrary/images/asset_font_48.png | Bin 193 -> 0 bytes .../itemlibrary/images/asset_font_64.png | Bin 203 -> 0 bytes .../itemlibrary/images/asset_font_96.png | Bin 220 -> 0 bytes .../itemlibrary/images/asset_shader_192.png | Bin 3038 -> 0 bytes .../itemlibrary/images/asset_shader_256.png | Bin 4336 -> 0 bytes .../itemlibrary/images/asset_shader_32.png | Bin 499 -> 0 bytes .../itemlibrary/images/asset_shader_384.png | Bin 6744 -> 0 bytes .../itemlibrary/images/asset_shader_64.png | Bin 905 -> 0 bytes .../itemlibrary/images/asset_sound_192.png | Bin 2928 -> 0 bytes .../itemlibrary/images/asset_sound_256.png | Bin 3620 -> 0 bytes .../itemlibrary/images/asset_sound_32.png | Bin 640 -> 0 bytes .../itemlibrary/images/asset_sound_384.png | Bin 4964 -> 0 bytes .../itemlibrary/images/asset_sound_64.png | Bin 1192 -> 0 bytes .../components/itemlibrary/images/x.png | Bin 218 -> 0 bytes .../components/itemlibrary/images/x@2x.png | Bin 383 -> 0 bytes .../components/itemlibrary/itemlibrary.qrc | 32 +- .../itemlibrary/itemlibraryview.cpp | 15 +- .../components/itemlibrary/itemlibraryview.h | 2 - .../itemlibrary/itemlibrarywidget.cpp | 395 ++-------------- .../itemlibrary/itemlibrarywidget.h | 34 +- .../navigator/navigatortreemodel.cpp | 6 +- .../designercore/include/viewmanager.h | 2 - .../designercore/model/viewmanager.cpp | 14 +- src/plugins/qmldesigner/qmldesignerplugin.qbs | 28 +- 68 files changed, 1569 insertions(+), 1093 deletions(-) rename share/qtcreator/qmldesigner/itemLibraryQmlSources/{AddImport.qml => AddModuleView.qml} (90%) delete mode 100644 share/qtcreator/qmldesigner/itemLibraryQmlSources/LibraryHeader.qml create mode 100644 share/qtcreator/qmldesigner/itemLibraryQmlSources/PlusButton.qml create mode 100644 share/qtcreator/qmldesigner/itemLibraryQmlSources/SearchBox.qml create mode 100644 src/plugins/qmldesigner/components/assetslibrary/assetslibrary.qrc rename src/plugins/qmldesigner/components/{itemlibrary/itemlibraryassetsdir.cpp => assetslibrary/assetslibrarydir.cpp} (62%) rename src/plugins/qmldesigner/components/{itemlibrary/itemlibraryassetsdir.h => assetslibrary/assetslibrarydir.h} (85%) rename src/plugins/qmldesigner/components/{itemlibrary/itemlibraryassetsdirsmodel.cpp => assetslibrary/assetslibrarydirsmodel.cpp} (75%) rename src/plugins/qmldesigner/components/{itemlibrary/itemlibraryassetsdirsmodel.h => assetslibrary/assetslibrarydirsmodel.h} (84%) rename src/plugins/qmldesigner/components/{itemlibrary/itemlibraryassetsfilesmodel.cpp => assetslibrary/assetslibraryfilesmodel.cpp} (83%) rename src/plugins/qmldesigner/components/{itemlibrary/itemlibraryassetsfilesmodel.h => assetslibrary/assetslibraryfilesmodel.h} (93%) rename src/plugins/qmldesigner/components/{itemlibrary/itemlibraryassetsiconprovider.cpp => assetslibrary/assetslibraryiconprovider.cpp} (54%) rename src/plugins/qmldesigner/components/{itemlibrary/itemlibraryassetsiconprovider.h => assetslibrary/assetslibraryiconprovider.h} (72%) rename src/plugins/qmldesigner/components/{itemlibrary/itemlibraryassetsmodel.cpp => assetslibrary/assetslibrarymodel.cpp} (79%) rename src/plugins/qmldesigner/components/{itemlibrary/itemlibraryassetsmodel.h => assetslibrary/assetslibrarymodel.h} (93%) create mode 100644 src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.cpp create mode 100644 src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.h create mode 100644 src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp create mode 100644 src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h create mode 100644 src/plugins/qmldesigner/components/assetslibrary/images/asset_default.png create mode 100644 src/plugins/qmldesigner/components/assetslibrary/images/asset_default@2x.png rename src/plugins/qmldesigner/components/{itemlibrary/images/asset_shader_48.png => assetslibrary/images/asset_shader.png} (100%) rename src/plugins/qmldesigner/components/{itemlibrary/images/asset_shader_96.png => assetslibrary/images/asset_shader@2x.png} (100%) rename src/plugins/qmldesigner/components/{itemlibrary => assetslibrary}/images/asset_shader_128.png (100%) rename src/plugins/qmldesigner/components/{itemlibrary/images/asset_sound_48.png => assetslibrary/images/asset_sound.png} (100%) rename src/plugins/qmldesigner/components/{itemlibrary/images/asset_sound_96.png => assetslibrary/images/asset_sound@2x.png} (100%) rename src/plugins/qmldesigner/components/{itemlibrary => assetslibrary}/images/asset_sound_128.png (100%) rename src/plugins/qmldesigner/components/{itemlibrary/images/item-video-icon.png => assetslibrary/images/asset_video.png} (100%) rename src/plugins/qmldesigner/components/{itemlibrary/images/item-video-icon@2x.png => assetslibrary/images/asset_video@2x.png} (100%) rename src/plugins/qmldesigner/components/{itemlibrary => assetslibrary}/images/browse.png (100%) rename src/plugins/qmldesigner/components/{itemlibrary => assetslibrary}/images/browse@2x.png (100%) delete mode 100644 src/plugins/qmldesigner/components/itemlibrary/images/asset_font_128.png delete mode 100644 src/plugins/qmldesigner/components/itemlibrary/images/asset_font_192.png delete mode 100644 src/plugins/qmldesigner/components/itemlibrary/images/asset_font_256.png delete mode 100644 src/plugins/qmldesigner/components/itemlibrary/images/asset_font_32.png delete mode 100644 src/plugins/qmldesigner/components/itemlibrary/images/asset_font_384.png delete mode 100644 src/plugins/qmldesigner/components/itemlibrary/images/asset_font_48.png delete mode 100644 src/plugins/qmldesigner/components/itemlibrary/images/asset_font_64.png delete mode 100644 src/plugins/qmldesigner/components/itemlibrary/images/asset_font_96.png delete mode 100644 src/plugins/qmldesigner/components/itemlibrary/images/asset_shader_192.png delete mode 100644 src/plugins/qmldesigner/components/itemlibrary/images/asset_shader_256.png delete mode 100644 src/plugins/qmldesigner/components/itemlibrary/images/asset_shader_32.png delete mode 100644 src/plugins/qmldesigner/components/itemlibrary/images/asset_shader_384.png delete mode 100644 src/plugins/qmldesigner/components/itemlibrary/images/asset_shader_64.png delete mode 100644 src/plugins/qmldesigner/components/itemlibrary/images/asset_sound_192.png delete mode 100644 src/plugins/qmldesigner/components/itemlibrary/images/asset_sound_256.png delete mode 100644 src/plugins/qmldesigner/components/itemlibrary/images/asset_sound_32.png delete mode 100644 src/plugins/qmldesigner/components/itemlibrary/images/asset_sound_384.png delete mode 100644 src/plugins/qmldesigner/components/itemlibrary/images/asset_sound_64.png delete mode 100644 src/plugins/qmldesigner/components/itemlibrary/images/x.png delete mode 100644 src/plugins/qmldesigner/components/itemlibrary/images/x@2x.png diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/AddImport.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/AddModuleView.qml similarity index 90% rename from share/qtcreator/qmldesigner/itemLibraryQmlSources/AddImport.qml rename to share/qtcreator/qmldesigner/itemLibraryQmlSources/AddModuleView.qml index 71399afa011..492ef767a6e 100644 --- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/AddImport.qml +++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/AddModuleView.qml @@ -32,28 +32,40 @@ import StudioTheme 1.0 as StudioTheme Column { id: root - Text { - id: header - text: qsTr("Select a Module to Add") - color: StudioTheme.Values.themeTextColor - font.pixelSize: 16 - width: parent.width - height: 50 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter + spacing: 5 + + signal back() + + Row { + spacing: 5 + anchors.horizontalCenter: parent.horizontalCenter + + Button { + anchors.verticalCenter: parent.verticalCenter + text: "<" + width: 25 + height: 25 + onClicked: back() + } + + Text { + text: qsTr("Select a Module to Add") + color: StudioTheme.Values.themeTextColor + font.pixelSize: 16 + } } ScrollView { // ListView not used because of QTBUG-52941 id: listView width: parent.width - height: parent.height - header.height + height: parent.height - y clip: true Column { spacing: 2 Repeater { - model: addImportModel + model: addModuleModel delegate: Rectangle { id: itemBackground diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/Assets.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/Assets.qml index 115309c1277..2efe499f0f6 100644 --- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/Assets.qml +++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/Assets.qml @@ -40,6 +40,11 @@ Item { property var contextDir: undefined property bool isDirContextMenu: false + function clearSearchFilter() + { + searchBox.text = ""; + } + DropArea { id: dropArea @@ -90,6 +95,70 @@ Item { selectedAssetsChanged() } + StudioControls.Menu { + id: contextMenu + + StudioControls.MenuItem { + text: qsTr("Expand All") + enabled: allExpandedState !== 1 + visible: isDirContextMenu + height: visible ? implicitHeight : 0 + onTriggered: assetsModel.toggleExpandAll(true) + } + + StudioControls.MenuItem { + text: qsTr("Collapse All") + enabled: allExpandedState !== 2 + visible: isDirContextMenu + height: visible ? implicitHeight : 0 + onTriggered: assetsModel.toggleExpandAll(false) + } + + StudioControls.MenuSeparator { + visible: isDirContextMenu + height: visible ? StudioTheme.Values.border : 0 + } + + StudioControls.MenuItem { + text: qsTr("Delete File") + visible: contextFilePath + height: visible ? implicitHeight : 0 + onTriggered: assetsModel.deleteFile(contextFilePath) + } + + StudioControls.MenuSeparator { + visible: contextFilePath + height: visible ? StudioTheme.Values.border : 0 + } + + StudioControls.MenuItem { + text: qsTr("Rename Folder") + visible: isDirContextMenu + height: visible ? implicitHeight : 0 + onTriggered: renameFolderDialog.open() + } + + StudioControls.MenuItem { + text: qsTr("New Folder") + onTriggered: newFolderDialog.open() + } + + StudioControls.MenuItem { + text: qsTr("Delete Folder") + visible: isDirContextMenu + height: visible ? implicitHeight : 0 + onTriggered: { + var dirEmpty = !(contextDir.dirsModel && contextDir.dirsModel.rowCount() > 0) + && !(contextDir.filesModel && contextDir.filesModel.rowCount() > 0); + + if (dirEmpty) + assetsModel.deleteFolder(contextDir.dirPath) + else + confirmDeleteFolderDialog.open() + } + } + } + RegExpValidator { id: folderNameValidator regExp: /^(\w[^*/> 0) - && !(contextDir.filesModel && contextDir.filesModel.rowCount() > 0); - - if (dirEmpty) - assetsModel.deleteFolder(contextDir.dirPath) - else - confirmDeleteFolderDialog.open() - } - } + onClicked: rootView.handleAddAsset() } } - Column { - Repeater { - model: assetsModel // context property - delegate: dirSection - } + Text { + text: qsTr("No match found.") + leftPadding: 10 + color: StudioTheme.Values.themeTextColor + font.pixelSize: 12 + visible: assetsModel.isEmpty && !searchBox.isEmpty() + } - Component { - id: dirSection + ScrollView { // TODO: experiment using ListView instead of ScrollView + Column + id: assetsView + width: parent.width + height: parent.height - y + clip: true + interactive: assetsView.verticalScrollBarVisible - Section { - width: assetsView.width - - (assetsView.verticalScrollBarVisible ? assetsView.verticalThickness : 0) - 5 - caption: dirName - sectionHeight: 30 - sectionFontSize: 15 - leftPadding: 0 - topPadding: dirDepth > 0 ? 5 : 0 - bottomPadding: 0 - hideHeader: dirDepth === 0 - showLeftBorder: dirDepth > 0 - expanded: dirExpanded - visible: !assetsModel.isEmpty && dirVisible - expandOnClick: false - useDefaulContextMenu: false + Column { + Repeater { + model: assetsModel // context property + delegate: dirSection + } - onToggleExpand: { - dirExpanded = !dirExpanded - } + Component { + id: dirSection - onShowContextMenu: { - contextFilePath = "" - contextDir = model - isDirContextMenu = true - allExpandedState = assetsModel.getAllExpandedState() - contextMenu.popup() - } + Section { + width: assetsView.width - + (assetsView.verticalScrollBarVisible ? assetsView.verticalThickness : 0) - 5 + caption: dirName + sectionHeight: 30 + sectionFontSize: 15 + leftPadding: 0 + topPadding: dirDepth > 0 ? 5 : 0 + bottomPadding: 0 + hideHeader: dirDepth === 0 + showLeftBorder: dirDepth > 0 + expanded: dirExpanded + visible: !assetsModel.isEmpty && dirVisible + expandOnClick: false + useDefaulContextMenu: false - Column { - spacing: 5 - leftPadding: 5 - - Repeater { - model: dirsModel - delegate: dirSection + onToggleExpand: { + dirExpanded = !dirExpanded } - Repeater { - model: filesModel - delegate: fileSection + onShowContextMenu: { + contextFilePath = "" + contextDir = model + isDirContextMenu = true + allExpandedState = assetsModel.getAllExpandedState() + contextMenu.popup() } - Text { - text: qsTr("Empty folder") - color: StudioTheme.Values.themeTextColorDisabled - font.pixelSize: 12 - visible: !(dirsModel && dirsModel.rowCount() > 0) - && !(filesModel && filesModel.rowCount() > 0) + Column { + spacing: 5 + leftPadding: 5 - MouseArea { - anchors.fill: parent - acceptedButtons: Qt.RightButton - onClicked: { - contextFilePath = "" - contextDir = model - isDirContextMenu = true - contextMenu.popup() + Repeater { + model: dirsModel + delegate: dirSection + } + + Repeater { + model: filesModel + delegate: fileSection + } + + Text { + text: qsTr("Empty folder") + color: StudioTheme.Values.themeTextColorDisabled + font.pixelSize: 12 + visible: !(dirsModel && dirsModel.rowCount() > 0) + && !(filesModel && filesModel.rowCount() > 0) + + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.RightButton + onClicked: { + contextFilePath = "" + contextDir = model + isDirContextMenu = true + contextMenu.popup() + } } } } } } - } - Component { - id: fileSection + Component { + id: fileSection - Rectangle { - width: assetsView.width - - (assetsView.verticalScrollBarVisible ? assetsView.verticalThickness : 0) - height: img.height - color: selectedAssets[filePath] ? StudioTheme.Values.themeInteraction - : (mouseArea.containsMouse ? StudioTheme.Values.themeSectionHeadBackground - : "transparent") + Rectangle { + width: assetsView.width - + (assetsView.verticalScrollBarVisible ? assetsView.verticalThickness : 0) + height: img.height + color: selectedAssets[filePath] ? StudioTheme.Values.themeInteraction + : (mouseArea.containsMouse ? StudioTheme.Values.themeSectionHeadBackground + : "transparent") - Row { - spacing: 5 + Row { + spacing: 5 - Image { - id: img - asynchronous: true - width: 48 - height: 48 - source: "image://qmldesigner_assets/" + filePath + Image { + id: img + asynchronous: true + width: 48 + height: 48 + source: "image://qmldesigner_assets/" + filePath + } + + Text { + text: fileName + color: StudioTheme.Values.themeTextColor + font.pixelSize: 14 + anchors.verticalCenter: parent.verticalCenter + } } - Text { - text: fileName - color: StudioTheme.Values.themeTextColor - font.pixelSize: 14 - anchors.verticalCenter: parent.verticalCenter - } - } + readonly property string suffix: fileName.substr(-4) + readonly property bool isFont: suffix === ".ttf" || suffix === ".otf" + property bool currFileSelected: false - readonly property string suffix: fileName.substr(-4) - readonly property bool isFont: suffix === ".ttf" || suffix === ".otf" - property bool currFileSelected: false + MouseArea { + id: mouseArea - MouseArea { - id: mouseArea + anchors.fill: parent + hoverEnabled: true + acceptedButtons: Qt.LeftButton | Qt.RightButton - anchors.fill: parent - hoverEnabled: true - acceptedButtons: Qt.LeftButton | Qt.RightButton + onExited: tooltipBackend.hideTooltip() + onCanceled: tooltipBackend.hideTooltip() + onPositionChanged: tooltipBackend.reposition() + onPressed: (mouse)=> { + forceActiveFocus() + if (mouse.button === Qt.LeftButton) { + var ctrlDown = mouse.modifiers & Qt.ControlModifier + if (!selectedAssets[filePath] && !ctrlDown) + selectedAssets = {} + currFileSelected = ctrlDown ? !selectedAssets[filePath] : true + selectedAssets[filePath] = currFileSelected + selectedAssetsChanged() - onExited: tooltipBackend.hideTooltip() - onCanceled: tooltipBackend.hideTooltip() - onPositionChanged: tooltipBackend.reposition() - onPressed: (mouse)=> { - forceActiveFocus() - if (mouse.button === Qt.LeftButton) { - var ctrlDown = mouse.modifiers & Qt.ControlModifier - if (!selectedAssets[filePath] && !ctrlDown) - selectedAssets = {} - currFileSelected = ctrlDown ? !selectedAssets[filePath] : true - selectedAssets[filePath] = currFileSelected - selectedAssetsChanged() + var selectedAssetsArr = [] + for (var assetPath in selectedAssets) { + if (selectedAssets[assetPath]) + selectedAssetsArr.push(assetPath) + } - var selectedAssetsArr = [] - for (var assetPath in selectedAssets) { - if (selectedAssets[assetPath]) - selectedAssetsArr.push(assetPath) + if (currFileSelected) + rootView.startDragAsset(selectedAssetsArr, mapToGlobal(mouse.x, mouse.y)) + } else { + contextFilePath = filePath + contextDir = model.fileDir + + tooltipBackend.hideTooltip() + isDirContextMenu = false + contextMenu.popup() } - - if (currFileSelected) - rootView.startDragAsset(selectedAssetsArr, mapToGlobal(mouse.x, mouse.y)) - } else { - contextFilePath = filePath - contextDir = model.fileDir - - tooltipBackend.hideTooltip() - isDirContextMenu = false - contextMenu.popup() } - } - onReleased: (mouse)=> { - if (mouse.button === Qt.LeftButton) { - if (!(mouse.modifiers & Qt.ControlModifier)) - selectedAssets = {} - selectedAssets[filePath] = currFileSelected - selectedAssetsChanged() + onReleased: (mouse)=> { + if (mouse.button === Qt.LeftButton) { + if (!(mouse.modifiers & Qt.ControlModifier)) + selectedAssets = {} + selectedAssets[filePath] = currFileSelected + selectedAssetsChanged() + } } - } - ToolTip { - visible: !isFont && mouseArea.containsMouse && !contextMenu.visible - text: filePath - delay: 1000 - } + ToolTip { + visible: !isFont && mouseArea.containsMouse && !contextMenu.visible + text: filePath + delay: 1000 + } - Timer { - interval: 1000 - running: mouseArea.containsMouse - onTriggered: { - if (suffix === ".ttf" || suffix === ".otf") { - tooltipBackend.name = fileName - tooltipBackend.path = filePath - tooltipBackend.showTooltip() + Timer { + interval: 1000 + running: mouseArea.containsMouse + onTriggered: { + if (suffix === ".ttf" || suffix === ".otf") { + tooltipBackend.name = fileName + tooltipBackend.path = filePath + tooltipBackend.showTooltip() + } } } } @@ -568,7 +605,7 @@ Item { // Placeholder when the assets panel is empty Column { id: colNoAssets - visible: assetsModel.isEmpty && !rootView.searchActive + visible: assetsModel.isEmpty && searchBox.isEmpty() spacing: 20 x: 20 @@ -612,13 +649,4 @@ Item { wrapMode: Text.WordWrap } } - - Text { - text: qsTr("No match found.") - x: 20 - y: 10 - color: StudioTheme.Values.themeTextColor - font.pixelSize: 12 - visible: assetsModel.isEmpty && rootView.searchActive - } } diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml index 6f7fbc454f4..17d187c2418 100644 --- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml +++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml @@ -81,6 +81,7 @@ Item { property var currentCategory: null property var currentImport: null property bool isHorizontalView: false + property bool isAddModuleView: false // Called also from C++ to close context menu on focus out function closeContextMenu() @@ -89,6 +90,12 @@ Item { itemContextMenu.close() } + // Called also from C++ + function switchToComponentsView() + { + isAddModuleView = false + } + onWidthChanged: { itemsView.isHorizontalView = itemsView.width > widthLimit } @@ -188,9 +195,38 @@ Item { } } - Loader { - anchors.fill: parent - sourceComponent: itemsView.isHorizontalView ? horizontalView : verticalView + Column { + id: col + width: parent.width + height: parent.height + y: 5 + spacing: 5 + + Row { + width: parent.width + + SearchBox { + id: searchBox + + width: parent.width - addAssetButton.width - 5 + } + + PlusButton { + id: addAssetButton + tooltip: qsTr("Add a module.") + + onClicked: isAddModuleView = true + } + } + + Loader { + id: loader + + width: col.width + height: col.height - y - 5 + sourceComponent: isAddModuleView ? addModuleView + : itemsView.isHorizontalView ? horizontalView : verticalView + } } Component { @@ -198,8 +234,9 @@ Item { ScrollView { id: verticalScrollView - width: itemsView.width - height: itemsView.height + anchors.fill: parent + clip: true + onContentHeightChanged: { var maxPosition = Math.max(contentHeight - verticalScrollView.height, 0) if (contentY > maxPosition) @@ -312,7 +349,9 @@ Item { ScrollView { id: horizontalScrollView width: 270 - height: itemsView.height + height: parent.height + clip: true + onContentHeightChanged: { var maxPosition = Math.max(contentHeight - horizontalScrollView.height, 0) if (contentY > maxPosition) @@ -452,4 +491,12 @@ Item { } } } + + Component { + id: addModuleView + + AddModuleView { + onBack: isAddModuleView = false + } + } } diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/LibraryHeader.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/LibraryHeader.qml deleted file mode 100644 index c68891f3318..00000000000 --- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/LibraryHeader.qml +++ /dev/null @@ -1,266 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuickDesignerTheme 1.0 -import HelperWidgets 2.0 as HelperWidgets -import StudioControls 1.0 as StudioControls -import StudioTheme 1.0 as StudioTheme - -Item { - id: root - - function setTab(index) - { - tabBar.setCurrentIndex(index); - } - - function clearSearchFilter() - { - searchFilterText.text = ""; - } - - Column { - anchors.left: parent.left - anchors.right: parent.right - spacing: 9 - - TabBar { - id: tabBar - anchors.left: parent.left - anchors.right: parent.right - anchors.leftMargin: 5 - anchors.rightMargin: 5 - spacing: 40 - - background: Rectangle { - color: StudioTheme.Values.themePanelBackground - } - - Repeater { - model: [{title: qsTr("Components"), addToolTip: qsTr("Add Module")}, - {title: qsTr("Assets"), addToolTip: qsTr("Add new assets to project.")}] - - TabButton { - topPadding: 4 - bottomPadding: 4 - contentItem: Item { - implicitHeight: plusButton.height - - Text { // TabButton text - text: modelData.title - font.pixelSize: 13 - font.bold: false - color: tabBar.currentIndex === index ? StudioTheme.Values.themeInteraction - : StudioTheme.Values.themeTextColor - anchors.left: parent.left - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.right: plusButton.left - anchors.bottomMargin: 2 - horizontalAlignment: Text.AlignLeft - verticalAlignment: Text.AlignBottom - elide: Text.ElideRight - } - - Rectangle { // + button - id: plusButton - anchors.right: parent.right - anchors.top: parent.top - anchors.topMargin: 1 - width: 24 - height: 24 - color: mouseArea.containsMouse && enabled - ? StudioTheme.Values.themeControlBackgroundHover - : StudioTheme.Values.themeControlBackground - - Behavior on color { - ColorAnimation { - duration: StudioTheme.Values.hoverDuration - easing.type: StudioTheme.Values.hoverEasing - } - } - - enabled: index !== 0 || !rootView.subCompEditMode - - Label { // + sign - text: StudioTheme.Constants.plus - font.family: StudioTheme.Constants.iconFont.family - font.pixelSize: StudioTheme.Values.myIconFontSize - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter - anchors.centerIn: parent - color: !plusButton.enabled - ? StudioTheme.Values.themeIconColorDisabled - : tabBar.currentIndex === index - ? StudioTheme.Values.themeIconColorSelected - : StudioTheme.Values.themeIconColor - } - - HelperWidgets.ToolTipArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - onClicked: index === 0 ? rootView.handleAddModule() - : rootView.handleAddAsset() - tooltip: modelData.addToolTip - } - } - } - - background: Item { // TabButton background - Rectangle { // bottom strip - anchors.bottom: parent.bottom - width: parent.width - height: 2 - color: tabBar.currentIndex === index ? StudioTheme.Values.themeInteraction - : StudioTheme.Values.themeTextColor - } - } - - onClicked: rootView.handleTabChanged(index); - } - } - } - - TextField { // filter - id: searchFilterText - placeholderText: qsTr("Search") - placeholderTextColor: StudioTheme.Values.themePlaceholderTextColor - color: StudioTheme.Values.themeTextColor - selectionColor: StudioTheme.Values.themeTextSelectionColor - selectedTextColor: StudioTheme.Values.themeTextSelectedTextColor - background: Rectangle { - id: textFieldBackground - color: StudioTheme.Values.themeControlBackground - border.color: StudioTheme.Values.themeControlOutline - border.width: StudioTheme.Values.border - - Behavior on color { - ColorAnimation { - duration: StudioTheme.Values.hoverDuration - easing.type: StudioTheme.Values.hoverEasing - } - } - } - - height: StudioTheme.Values.defaultControlHeight - - leftPadding: 32 - rightPadding: 30 - topPadding: 6 - anchors.left: parent.left - anchors.right: parent.right - anchors.leftMargin: 5 - anchors.rightMargin: 5 - selectByMouse: true - hoverEnabled: true - - onTextChanged: rootView.handleSearchfilterChanged(text) - - Label { - text: StudioTheme.Constants.search - font.family: StudioTheme.Constants.iconFont.family - font.pixelSize: 16 - anchors.left: parent.left - anchors.leftMargin: 7 - anchors.verticalCenter: parent.verticalCenter - color: StudioTheme.Values.themeIconColor - } - - Rectangle { // x button - width: 16 - height: 15 - anchors.right: parent.right - anchors.rightMargin: 5 - anchors.verticalCenter: parent.verticalCenter - visible: searchFilterText.text !== "" - color: xMouseArea.containsMouse ? StudioTheme.Values.themePanelBackground - : "transparent" - - Label { - text: StudioTheme.Constants.closeCross - font.family: StudioTheme.Constants.iconFont.family - font.pixelSize: StudioTheme.Values.myIconFontSize - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter - anchors.centerIn: parent - color: StudioTheme.Values.themeIconColor - } - - MouseArea { - id: xMouseArea - hoverEnabled: true - anchors.fill: parent - onClicked: searchFilterText.text = "" - } - } - - states: [ - State { - name: "default" - when: !searchFilterText.hovered && !searchFilterText.activeFocus - PropertyChanges { - target: textFieldBackground - color: StudioTheme.Values.themeControlBackground - border.color: StudioTheme.Values.themeControlOutline - } - PropertyChanges { - target: searchFilterText - placeholderTextColor: StudioTheme.Values.themePlaceholderTextColor - } - }, - State { - name: "hover" - when: searchFilterText.hovered && !searchFilterText.activeFocus - PropertyChanges { - target: textFieldBackground - color: StudioTheme.Values.themeControlBackgroundHover - border.color: StudioTheme.Values.themeControlOutline - } - - PropertyChanges { - target: searchFilterText - placeholderTextColor: StudioTheme.Values.themePlaceholderTextColor - } - }, - State { - name: "edit" - when: searchFilterText.activeFocus - PropertyChanges { - target: textFieldBackground - color: StudioTheme.Values.themeControlBackgroundInteraction - border.color: StudioTheme.Values.themeControlOutlineInteraction - } - PropertyChanges { - target: searchFilterText - placeholderTextColor: StudioTheme.Values.themePlaceholderTextColorInteraction - } - } - ] - } - } -} diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/PlusButton.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/PlusButton.qml new file mode 100644 index 00000000000..31f69be9967 --- /dev/null +++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/PlusButton.qml @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuickDesignerTheme 1.0 +import HelperWidgets 2.0 as HelperWidgets +import StudioControls 1.0 as StudioControls +import StudioTheme 1.0 as StudioTheme + +Rectangle { + id: root + + property string tooltip: "" + + signal clicked() + + implicitWidth: 29 + implicitHeight: 29 + color: mouseArea.containsMouse && enabled + ? StudioTheme.Values.themeControlBackgroundHover + : StudioTheme.Values.themeControlBackground + + Behavior on color { + ColorAnimation { + duration: StudioTheme.Values.hoverDuration + easing.type: StudioTheme.Values.hoverEasing + } + } + + Label { // + sign + text: StudioTheme.Constants.plus + font.family: StudioTheme.Constants.iconFont.family + font.pixelSize: StudioTheme.Values.myIconFontSize + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + anchors.centerIn: parent + color: root.enabled ? StudioTheme.Values.themeIconColor + : StudioTheme.Values.themeIconColorDisabled + scale: mouseArea.containsMouse ? 1.4 : 1 + + Behavior on scale { + NumberAnimation { + duration: 300 + easing.type: Easing.OutExpo + } + } + } + + HelperWidgets.ToolTipArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + onClicked: root.clicked() + tooltip: root.tooltip + } +} diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/SearchBox.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/SearchBox.qml new file mode 100644 index 00000000000..81ed5c11e49 --- /dev/null +++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/SearchBox.qml @@ -0,0 +1,168 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuickDesignerTheme 1.0 +import HelperWidgets 2.0 as HelperWidgets +import StudioControls 1.0 as StudioControls +import StudioTheme 1.0 as StudioTheme + +Item { + id: root + + property alias text: searchFilterText.text + + function clearSearchFilter() + { + searchFilterText.text = ""; + } + + function isEmpty() + { + return searchFilterText.text === ""; + } + + implicitWidth: searchFilterText.width + implicitHeight: searchFilterText.height + + TextField { + id: searchFilterText + + placeholderText: qsTr("Search") + placeholderTextColor: StudioTheme.Values.themePlaceholderTextColor + color: StudioTheme.Values.themeTextColor + selectionColor: StudioTheme.Values.themeTextSelectionColor + selectedTextColor: StudioTheme.Values.themeTextSelectedTextColor + background: Rectangle { + id: textFieldBackground + color: StudioTheme.Values.themeControlBackground + border.color: StudioTheme.Values.themeControlOutline + border.width: StudioTheme.Values.border + + Behavior on color { + ColorAnimation { + duration: StudioTheme.Values.hoverDuration + easing.type: StudioTheme.Values.hoverEasing + } + } + } + + height: StudioTheme.Values.defaultControlHeight + + leftPadding: 32 + rightPadding: 30 + topPadding: 6 + anchors.left: parent.left + anchors.right: parent.right + anchors.leftMargin: 5 + anchors.rightMargin: 5 + selectByMouse: true + hoverEnabled: true + + onTextChanged: rootView.handleSearchfilterChanged(text) + + Label { + text: StudioTheme.Constants.search + font.family: StudioTheme.Constants.iconFont.family + font.pixelSize: 16 + anchors.left: parent.left + anchors.leftMargin: 7 + anchors.verticalCenter: parent.verticalCenter + color: StudioTheme.Values.themeIconColor + } + + Rectangle { // x button + width: 16 + height: 15 + anchors.right: parent.right + anchors.rightMargin: 5 + anchors.verticalCenter: parent.verticalCenter + visible: searchFilterText.text !== "" + color: xMouseArea.containsMouse ? StudioTheme.Values.themePanelBackground + : "transparent" + + Label { + text: StudioTheme.Constants.closeCross + font.family: StudioTheme.Constants.iconFont.family + font.pixelSize: StudioTheme.Values.myIconFontSize + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + anchors.centerIn: parent + color: StudioTheme.Values.themeIconColor + } + + MouseArea { + id: xMouseArea + hoverEnabled: true + anchors.fill: parent + onClicked: searchFilterText.text = "" + } + } + + states: [ + State { + name: "default" + when: !searchFilterText.hovered && !searchFilterText.activeFocus + PropertyChanges { + target: textFieldBackground + color: StudioTheme.Values.themeControlBackground + border.color: StudioTheme.Values.themeControlOutline + } + PropertyChanges { + target: searchFilterText + placeholderTextColor: StudioTheme.Values.themePlaceholderTextColor + } + }, + State { + name: "hover" + when: searchFilterText.hovered && !searchFilterText.activeFocus + PropertyChanges { + target: textFieldBackground + color: StudioTheme.Values.themeControlBackgroundHover + border.color: StudioTheme.Values.themeControlOutline + } + + PropertyChanges { + target: searchFilterText + placeholderTextColor: StudioTheme.Values.themePlaceholderTextColor + } + }, + State { + name: "edit" + when: searchFilterText.activeFocus + PropertyChanges { + target: textFieldBackground + color: StudioTheme.Values.themeControlBackgroundInteraction + border.color: StudioTheme.Values.themeControlOutlineInteraction + } + PropertyChanges { + target: searchFilterText + placeholderTextColor: StudioTheme.Values.themePlaceholderTextColorInteraction + } + } + ] + } +} diff --git a/share/qtcreator/qmldesigner/workspacePresets/3D_Preset.wrk b/share/qtcreator/qmldesigner/workspacePresets/3D_Preset.wrk index 62c823b1470..fba5f4a822f 100644 --- a/share/qtcreator/qmldesigner/workspacePresets/3D_Preset.wrk +++ b/share/qtcreator/qmldesigner/workspacePresets/3D_Preset.wrk @@ -3,8 +3,9 @@ - - + + + diff --git a/share/qtcreator/qmldesigner/workspacePresets/Essentials.wrk b/share/qtcreator/qmldesigner/workspacePresets/Essentials.wrk index 0b1a7c2d528..2bdbc74f22c 100644 --- a/share/qtcreator/qmldesigner/workspacePresets/Essentials.wrk +++ b/share/qtcreator/qmldesigner/workspacePresets/Essentials.wrk @@ -3,8 +3,9 @@ - - + + + diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index 68532c1a534..b501a98bdd1 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -251,11 +251,19 @@ extend_qtc_plugin(QmlDesigner itemlibraryimport.cpp itemlibraryimport.h itemlibrarycategoriesmodel.cpp itemlibrarycategoriesmodel.h itemlibraryaddimportmodel.cpp itemlibraryaddimportmodel.h - itemlibraryassetsmodel.cpp itemlibraryassetsmodel.h - itemlibraryassetsiconprovider.cpp itemlibraryassetsiconprovider.h - itemlibraryassetsdir.cpp itemlibraryassetsdir.h - itemlibraryassetsdirsmodel.cpp itemlibraryassetsdirsmodel.h - itemlibraryassetsfilesmodel.cpp itemlibraryassetsfilesmodel.h +) + +extend_qtc_plugin(QmlDesigner + SOURCES_PREFIX components/assetslibrary + SOURCES + assetslibrary.qrc + assetslibraryview.cpp assetslibraryview.h + assetslibrarywidget.cpp assetslibrarywidget.h + assetslibrarymodel.cpp assetslibrarymodel.h + assetslibraryiconprovider.cpp assetslibraryiconprovider.h + assetslibrarydir.cpp assetslibrarydir.h + assetslibrarydirsmodel.cpp assetslibrarydirsmodel.h + assetslibraryfilesmodel.cpp assetslibraryfilesmodel.h ) extend_qtc_plugin(QmlDesigner diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrary.qrc b/src/plugins/qmldesigner/components/assetslibrary/assetslibrary.qrc new file mode 100644 index 00000000000..f8cea612985 --- /dev/null +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrary.qrc @@ -0,0 +1,16 @@ + + + images/asset_default.png + images/asset_default@2x.png + images/asset_shader.png + images/asset_shader@2x.png + images/asset_shader_128.png + images/asset_sound.png + images/asset_sound@2x.png + images/asset_sound_128.png + images/asset_video.png + images/asset_video@2x.png + images/browse.png + images/browse@2x.png + + diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsdir.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarydir.cpp similarity index 62% rename from src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsdir.cpp rename to src/plugins/qmldesigner/components/assetslibrary/assetslibrarydir.cpp index e5bbaf792dd..2c965d702f6 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsdir.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarydir.cpp @@ -23,13 +23,13 @@ ** ****************************************************************************/ -#include "itemlibraryassetsdir.h" -#include "itemlibraryassetsdirsmodel.h" -#include "itemlibraryassetsfilesmodel.h" +#include "assetslibrarydir.h" +#include "assetslibrarydirsmodel.h" +#include "assetslibraryfilesmodel.h" namespace QmlDesigner { -ItemLibraryAssetsDir::ItemLibraryAssetsDir(const QString &path, int depth, bool expanded, QObject *parent) +AssetsLibraryDir::AssetsLibraryDir(const QString &path, int depth, bool expanded, QObject *parent) : QObject(parent) , m_dirPath(path) , m_dirDepth(depth) @@ -38,13 +38,13 @@ ItemLibraryAssetsDir::ItemLibraryAssetsDir(const QString &path, int depth, bool } -QString ItemLibraryAssetsDir::dirName() const { return m_dirPath.split('/').last(); } -QString ItemLibraryAssetsDir::dirPath() const { return m_dirPath; } -int ItemLibraryAssetsDir::dirDepth() const { return m_dirDepth; } -bool ItemLibraryAssetsDir::dirExpanded() const { return m_dirExpanded; } -bool ItemLibraryAssetsDir::dirVisible() const { return m_dirVisible; } +QString AssetsLibraryDir::dirName() const { return m_dirPath.split('/').last(); } +QString AssetsLibraryDir::dirPath() const { return m_dirPath; } +int AssetsLibraryDir::dirDepth() const { return m_dirDepth; } +bool AssetsLibraryDir::dirExpanded() const { return m_dirExpanded; } +bool AssetsLibraryDir::dirVisible() const { return m_dirVisible; } -void ItemLibraryAssetsDir::setDirExpanded(bool expand) +void AssetsLibraryDir::setDirExpanded(bool expand) { if (m_dirExpanded != expand) { m_dirExpanded = expand; @@ -52,7 +52,7 @@ void ItemLibraryAssetsDir::setDirExpanded(bool expand) } } -void ItemLibraryAssetsDir::setDirVisible(bool visible) +void AssetsLibraryDir::setDirVisible(bool visible) { if (m_dirVisible != visible) { m_dirVisible = visible; @@ -60,17 +60,17 @@ void ItemLibraryAssetsDir::setDirVisible(bool visible) } } -QObject *ItemLibraryAssetsDir::filesModel() const +QObject *AssetsLibraryDir::filesModel() const { return m_filesModel; } -QObject *ItemLibraryAssetsDir::dirsModel() const +QObject *AssetsLibraryDir::dirsModel() const { return m_dirsModel; } -QList ItemLibraryAssetsDir::childAssetsDirs() const +QList AssetsLibraryDir::childAssetsDirs() const { if (m_dirsModel) return m_dirsModel->assetsDirs(); @@ -78,18 +78,18 @@ QList ItemLibraryAssetsDir::childAssetsDirs() const return {}; } -void ItemLibraryAssetsDir::addDir(ItemLibraryAssetsDir *assetsDir) +void AssetsLibraryDir::addDir(AssetsLibraryDir *assetsDir) { if (!m_dirsModel) - m_dirsModel = new ItemLibraryAssetsDirsModel(this); + m_dirsModel = new AssetsLibraryDirsModel(this); m_dirsModel->addDir(assetsDir); } -void ItemLibraryAssetsDir::addFile(const QString &filePath) +void AssetsLibraryDir::addFile(const QString &filePath) { if (!m_filesModel) - m_filesModel = new ItemLibraryAssetsFilesModel(this); + m_filesModel = new AssetsLibraryFilesModel(this); m_filesModel->addFile(filePath); } diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsdir.h b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarydir.h similarity index 85% rename from src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsdir.h rename to src/plugins/qmldesigner/components/assetslibrary/assetslibrarydir.h index 66cc5509d7e..07e13389389 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsdir.h +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarydir.h @@ -29,10 +29,10 @@ namespace QmlDesigner { -class ItemLibraryAssetsDirsModel; -class ItemLibraryAssetsFilesModel; +class AssetsLibraryDirsModel; +class AssetsLibraryFilesModel; -class ItemLibraryAssetsDir : public QObject +class AssetsLibraryDir : public QObject { Q_OBJECT @@ -45,7 +45,7 @@ class ItemLibraryAssetsDir : public QObject Q_PROPERTY(QObject *dirsModel READ dirsModel NOTIFY dirsModelChanged) public: - ItemLibraryAssetsDir(const QString &path, int depth, bool expanded = true, QObject *parent = nullptr); + AssetsLibraryDir(const QString &path, int depth, bool expanded = true, QObject *parent = nullptr); QString dirName() const; QString dirPath() const; @@ -59,9 +59,9 @@ public: QObject *filesModel() const; QObject *dirsModel() const; - QList childAssetsDirs() const; + QList childAssetsDirs() const; - void addDir(ItemLibraryAssetsDir *assetsDir); + void addDir(AssetsLibraryDir *assetsDir); void addFile(const QString &filePath); signals: @@ -78,8 +78,8 @@ private: int m_dirDepth = 0; bool m_dirExpanded = true; bool m_dirVisible = true; - ItemLibraryAssetsDirsModel *m_dirsModel = nullptr; - ItemLibraryAssetsFilesModel *m_filesModel = nullptr; + AssetsLibraryDirsModel *m_dirsModel = nullptr; + AssetsLibraryFilesModel *m_filesModel = nullptr; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsdirsmodel.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarydirsmodel.cpp similarity index 75% rename from src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsdirsmodel.cpp rename to src/plugins/qmldesigner/components/assetslibrary/assetslibrarydirsmodel.cpp index 6af4049d872..563e0f111b1 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsdirsmodel.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarydirsmodel.cpp @@ -23,24 +23,24 @@ ** ****************************************************************************/ -#include "itemlibraryassetsdirsmodel.h" -#include "itemlibraryassetsmodel.h" +#include "assetslibrarydirsmodel.h" +#include "assetslibrarymodel.h" #include #include namespace QmlDesigner { -ItemLibraryAssetsDirsModel::ItemLibraryAssetsDirsModel(QObject *parent) +AssetsLibraryDirsModel::AssetsLibraryDirsModel(QObject *parent) : QAbstractListModel(parent) { // add roles - const QMetaObject meta = ItemLibraryAssetsDir::staticMetaObject; + const QMetaObject meta = AssetsLibraryDir::staticMetaObject; for (int i = meta.propertyOffset(); i < meta.propertyCount(); ++i) m_roleNames.insert(i, meta.property(i).name()); } -QVariant ItemLibraryAssetsDirsModel::data(const QModelIndex &index, int role) const +QVariant AssetsLibraryDirsModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { qWarning() << Q_FUNC_INFO << "Invalid index requested: " << QString::number(index.row()); @@ -54,7 +54,7 @@ QVariant ItemLibraryAssetsDirsModel::data(const QModelIndex &index, int role) co return {}; } -bool ItemLibraryAssetsDirsModel::setData(const QModelIndex &index, const QVariant &value, int role) +bool AssetsLibraryDirsModel::setData(const QModelIndex &index, const QVariant &value, int role) { // currently only dirExpanded property is updatable if (index.isValid() && m_roleNames.contains(role)) { @@ -62,7 +62,7 @@ bool ItemLibraryAssetsDirsModel::setData(const QModelIndex &index, const QVarian if (currValue != value) { m_dirs.at(index.row())->setProperty(m_roleNames.value(role), value); if (m_roleNames.value(role) == "dirExpanded") - ItemLibraryAssetsModel::saveExpandedState(value.toBool(), m_dirs.at(index.row())->dirPath()); + AssetsLibraryModel::saveExpandedState(value.toBool(), m_dirs.at(index.row())->dirPath()); emit dataChanged(index, index, {role}); return true; } @@ -70,24 +70,24 @@ bool ItemLibraryAssetsDirsModel::setData(const QModelIndex &index, const QVarian return false; } -int ItemLibraryAssetsDirsModel::rowCount(const QModelIndex &parent) const +int AssetsLibraryDirsModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent) return m_dirs.size(); } -QHash ItemLibraryAssetsDirsModel::roleNames() const +QHash AssetsLibraryDirsModel::roleNames() const { return m_roleNames; } -void ItemLibraryAssetsDirsModel::addDir(ItemLibraryAssetsDir *assetsDir) +void AssetsLibraryDirsModel::addDir(AssetsLibraryDir *assetsDir) { m_dirs.append(assetsDir); } -const QList ItemLibraryAssetsDirsModel::assetsDirs() const +const QList AssetsLibraryDirsModel::assetsDirs() const { return m_dirs; } diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsdirsmodel.h b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarydirsmodel.h similarity index 84% rename from src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsdirsmodel.h rename to src/plugins/qmldesigner/components/assetslibrary/assetslibrarydirsmodel.h index b139d2dd837..44e3f91ad8c 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsdirsmodel.h +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarydirsmodel.h @@ -26,28 +26,28 @@ #pragma once #include -#include "itemlibraryassetsdir.h" +#include "assetslibrarydir.h" namespace QmlDesigner { -class ItemLibraryAssetsDirsModel : public QAbstractListModel +class AssetsLibraryDirsModel : public QAbstractListModel { Q_OBJECT public: - ItemLibraryAssetsDirsModel(QObject *parent = nullptr); + AssetsLibraryDirsModel(QObject *parent = nullptr); QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const override; bool setData(const QModelIndex &index, const QVariant &value, int role) override; int rowCount(const QModelIndex & parent = QModelIndex()) const override; QHash roleNames() const override; - void addDir(ItemLibraryAssetsDir *assetsDir); + void addDir(AssetsLibraryDir *assetsDir); - const QList assetsDirs() const; + const QList assetsDirs() const; private: - QList m_dirs; + QList m_dirs; QHash m_roleNames; }; diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsfilesmodel.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryfilesmodel.cpp similarity index 83% rename from src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsfilesmodel.cpp rename to src/plugins/qmldesigner/components/assetslibrary/assetslibraryfilesmodel.cpp index 271f330fd23..ab9b6d9fcba 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsfilesmodel.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryfilesmodel.cpp @@ -22,13 +22,13 @@ ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ****************************************************************************/ -#include "itemlibraryassetsfilesmodel.h" +#include "assetslibraryfilesmodel.h" #include namespace QmlDesigner { -ItemLibraryAssetsFilesModel::ItemLibraryAssetsFilesModel(QObject *parent) +AssetsLibraryFilesModel::AssetsLibraryFilesModel(QObject *parent) : QAbstractListModel(parent) { // add roles @@ -37,7 +37,7 @@ ItemLibraryAssetsFilesModel::ItemLibraryAssetsFilesModel(QObject *parent) m_roleNames.insert(FileDirRole, "fileDir"); } -QVariant ItemLibraryAssetsFilesModel::data(const QModelIndex &index, int role) const +QVariant AssetsLibraryFilesModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { qWarning() << Q_FUNC_INFO << "Invalid index requested: " << QString::number(index.row()); @@ -57,19 +57,19 @@ QVariant ItemLibraryAssetsFilesModel::data(const QModelIndex &index, int role) c return {}; } -int ItemLibraryAssetsFilesModel::rowCount(const QModelIndex &parent) const +int AssetsLibraryFilesModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent) return m_files.size(); } -QHash ItemLibraryAssetsFilesModel::roleNames() const +QHash AssetsLibraryFilesModel::roleNames() const { return m_roleNames; } -void ItemLibraryAssetsFilesModel::addFile(const QString &filePath) +void AssetsLibraryFilesModel::addFile(const QString &filePath) { m_files.append(filePath); } diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsfilesmodel.h b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryfilesmodel.h similarity index 93% rename from src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsfilesmodel.h rename to src/plugins/qmldesigner/components/assetslibrary/assetslibraryfilesmodel.h index 5b44878eefc..ca010bae60c 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsfilesmodel.h +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryfilesmodel.h @@ -29,12 +29,12 @@ namespace QmlDesigner { -class ItemLibraryAssetsFilesModel : public QAbstractListModel +class AssetsLibraryFilesModel : public QAbstractListModel { Q_OBJECT public: - ItemLibraryAssetsFilesModel(QObject *parent = nullptr); + AssetsLibraryFilesModel(QObject *parent = nullptr); QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const override; int rowCount(const QModelIndex & parent = QModelIndex()) const override; diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsiconprovider.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.cpp similarity index 54% rename from src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsiconprovider.cpp rename to src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.cpp index ad6f3136837..9d11d264008 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsiconprovider.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.cpp @@ -23,8 +23,8 @@ ** ****************************************************************************/ -#include "itemlibraryassetsiconprovider.h" -#include "itemlibraryassetsmodel.h" +#include "assetslibraryiconprovider.h" +#include "assetslibrarymodel.h" #include #include @@ -32,40 +32,47 @@ namespace QmlDesigner { -ItemLibraryAssetsIconProvider::ItemLibraryAssetsIconProvider(SynchronousImageCache &fontImageCache) +AssetsLibraryIconProvider::AssetsLibraryIconProvider(SynchronousImageCache &fontImageCache) : QQuickImageProvider(QQuickImageProvider::Pixmap) , m_fontImageCache(fontImageCache) { } -QPixmap ItemLibraryAssetsIconProvider::requestPixmap(const QString &id, QSize *size, const QSize &requestedSize) +QPixmap AssetsLibraryIconProvider::requestPixmap(const QString &id, QSize *size, const QSize &requestedSize) { QPixmap pixmap; const QString suffix = "*." + id.split('.').last().toLower(); - if (id == "browse") - pixmap = Utils::StyleHelper::dpiSpecificImageFile(":/ItemLibrary/images/browse.png"); - else if (ItemLibraryAssetsModel::supportedFontSuffixes().contains(suffix)) - pixmap = generateFontIcons(id); - else if (ItemLibraryAssetsModel::supportedImageSuffixes().contains(suffix)) + if (id == "browse") { + pixmap = Utils::StyleHelper::dpiSpecificImageFile(":/AssetsLibrary/images/browse.png"); + } else if (AssetsLibraryModel::supportedFontSuffixes().contains(suffix)) { + pixmap = generateFontIcons(id, requestedSize); + } else if (AssetsLibraryModel::supportedImageSuffixes().contains(suffix)) { pixmap = Utils::StyleHelper::dpiSpecificImageFile(id); - else if (ItemLibraryAssetsModel::supportedTexture3DSuffixes().contains(suffix)) + } else if (AssetsLibraryModel::supportedTexture3DSuffixes().contains(suffix)) { pixmap = HdrImage{id}.toPixmap(); - else if (ItemLibraryAssetsModel::supportedShaderSuffixes().contains(suffix)) - pixmap = Utils::StyleHelper::dpiSpecificImageFile(":/ItemLibrary/images/asset_shader_48.png"); - else if (ItemLibraryAssetsModel::supportedAudioSuffixes().contains(suffix)) - pixmap = Utils::StyleHelper::dpiSpecificImageFile(":/ItemLibrary/images/asset_sound_48.png"); - else if (ItemLibraryAssetsModel::supportedVideoSuffixes().contains(suffix)) - pixmap = Utils::StyleHelper::dpiSpecificImageFile(":/ItemLibrary/images/item-video-icon.png"); + } else { + QString type; + if (AssetsLibraryModel::supportedShaderSuffixes().contains(suffix)) + type = "shader"; + else if (AssetsLibraryModel::supportedAudioSuffixes().contains(suffix)) + type = "sound"; + else if (AssetsLibraryModel::supportedVideoSuffixes().contains(suffix)) + type = "video"; + + QString pathTemplate = QString(":/AssetsLibrary/images/asset_%1%2.png").arg(type); + QString path = pathTemplate.arg('_' + QString::number(requestedSize.width())); + + pixmap = Utils::StyleHelper::dpiSpecificImageFile(QFileInfo::exists(path) ? path + : pathTemplate.arg("")); + } if (size) { size->setWidth(pixmap.width()); size->setHeight(pixmap.height()); } - if (pixmap.isNull()) { - pixmap = QPixmap(Utils::StyleHelper::dpiSpecificImageFile( - QStringLiteral(":/ItemLibrary/images/item-default-icon.png"))); - } + if (pixmap.isNull()) + pixmap = Utils::StyleHelper::dpiSpecificImageFile(":/AssetsLibrary/images/assets_default.png"); if (requestedSize.isValid()) return pixmap.scaled(requestedSize); @@ -73,12 +80,13 @@ QPixmap ItemLibraryAssetsIconProvider::requestPixmap(const QString &id, QSize *s return pixmap; } -QPixmap ItemLibraryAssetsIconProvider::generateFontIcons(const QString &filePath) const +QPixmap AssetsLibraryIconProvider::generateFontIcons(const QString &filePath, const QSize &requestedSize) const { - return m_fontImageCache.icon(filePath, {}, + QSize reqSize = requestedSize.isValid() ? requestedSize : QSize{48, 48}; + return m_fontImageCache.icon(filePath, {}, ImageCache::FontCollectorSizesAuxiliaryData{Utils::span{iconSizes}, Theme::getColor(Theme::DStextColor).name(), - "Abc"}).pixmap({48, 48}); + "Abc"}).pixmap(reqSize); } } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsiconprovider.h b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.h similarity index 72% rename from src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsiconprovider.h rename to src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.h index 3c5bc4081e3..83f4a63f96d 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsiconprovider.h +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.h @@ -31,28 +31,23 @@ namespace QmlDesigner { -class ItemLibraryAssetsIconProvider : public QQuickImageProvider +class AssetsLibraryIconProvider : public QQuickImageProvider { public: - ItemLibraryAssetsIconProvider(SynchronousImageCache &fontImageCache); + AssetsLibraryIconProvider(SynchronousImageCache &fontImageCache); QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize) override; private: - QPixmap generateFontIcons(const QString &filePath) const; + QPixmap generateFontIcons(const QString &filePath, const QSize &requestedSize) const; SynchronousImageCache &m_fontImageCache; // Generated icon sizes should contain all ItemLibraryResourceView needed icon sizes, and their // x2 versions for HDPI sceens - std::vector iconSizes = {{384, 384}, - {192, 192}, // Large - {256, 256}, - {128, 128}, // Drag - {96, 96}, // Medium - {48, 48}, // Small - {64, 64}, - {32, 32}}; // List + std::vector iconSizes = {{128, 128}, // Drag + {96, 96}, // list @2x + {48, 48}}; // list }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsmodel.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp similarity index 79% rename from src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsmodel.cpp rename to src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp index c7c8db45342..0470c81ee3a 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsmodel.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp @@ -23,9 +23,9 @@ ** ****************************************************************************/ -#include "itemlibraryassetsmodel.h" -#include "itemlibraryassetsdirsmodel.h" -#include "itemlibraryassetsfilesmodel.h" +#include "assetslibrarymodel.h" +#include "assetslibrarydirsmodel.h" +#include "assetslibraryfilesmodel.h" #include #include @@ -50,17 +50,17 @@ namespace QmlDesigner { -void ItemLibraryAssetsModel::saveExpandedState(bool expanded, const QString &assetPath) +void AssetsLibraryModel::saveExpandedState(bool expanded, const QString &assetPath) { m_expandedStateHash.insert(assetPath, expanded); } -bool ItemLibraryAssetsModel::loadExpandedState(const QString &assetPath) +bool AssetsLibraryModel::loadExpandedState(const QString &assetPath) { return m_expandedStateHash.value(assetPath, true); } -ItemLibraryAssetsModel::DirExpandState ItemLibraryAssetsModel::getAllExpandedState() const +AssetsLibraryModel::DirExpandState AssetsLibraryModel::getAllExpandedState() const { const auto keys = m_expandedStateHash.keys(); bool allExpanded = true; @@ -81,16 +81,16 @@ ItemLibraryAssetsModel::DirExpandState ItemLibraryAssetsModel::getAllExpandedSta : DirExpandState::SomeExpanded; } -void ItemLibraryAssetsModel::toggleExpandAll(bool expand) +void AssetsLibraryModel::toggleExpandAll(bool expand) { - std::function expandDirRecursive; - expandDirRecursive = [&](ItemLibraryAssetsDir *currAssetsDir) { + std::function expandDirRecursive; + expandDirRecursive = [&](AssetsLibraryDir *currAssetsDir) { if (currAssetsDir->dirDepth() > 0) { currAssetsDir->setDirExpanded(expand); saveExpandedState(expand, currAssetsDir->dirPath()); } - const QList childDirs = currAssetsDir->childAssetsDirs(); + const QList childDirs = currAssetsDir->childAssetsDirs(); for (const auto childDir : childDirs) expandDirRecursive(childDir); }; @@ -100,7 +100,7 @@ void ItemLibraryAssetsModel::toggleExpandAll(bool expand) endResetModel(); } -void ItemLibraryAssetsModel::deleteFile(const QString &filePath) +void AssetsLibraryModel::deleteFile(const QString &filePath) { bool askBeforeDelete = DesignerSettings::getValue( DesignerSettingsKey::ASK_BEFORE_DELETING_ASSET).toBool(); @@ -135,7 +135,7 @@ void ItemLibraryAssetsModel::deleteFile(const QString &filePath) } } -bool ItemLibraryAssetsModel::renameFolder(const QString &folderPath, const QString &newName) +bool AssetsLibraryModel::renameFolder(const QString &folderPath, const QString &newName) { QDir dir{folderPath}; QString oldName = dir.dirName(); @@ -147,7 +147,7 @@ bool ItemLibraryAssetsModel::renameFolder(const QString &folderPath, const QStri return dir.rename(oldName, newName); } -void ItemLibraryAssetsModel::addNewFolder(const QString &folderPath) +void AssetsLibraryModel::addNewFolder(const QString &folderPath) { QString iterPath = folderPath; QRegularExpression rgx("\\d+$"); // matches a number at the end of a string @@ -183,17 +183,17 @@ void ItemLibraryAssetsModel::addNewFolder(const QString &folderPath) dir.mkpath(iterPath); } -void ItemLibraryAssetsModel::deleteFolder(const QString &folderPath) +void AssetsLibraryModel::deleteFolder(const QString &folderPath) { QDir{folderPath}.removeRecursively(); } -QObject *ItemLibraryAssetsModel::rootDir() const +QObject *AssetsLibraryModel::rootDir() const { return m_assetsDir; } -const QStringList &ItemLibraryAssetsModel::supportedImageSuffixes() +const QStringList &AssetsLibraryModel::supportedImageSuffixes() { static QStringList retList; if (retList.isEmpty()) { @@ -204,13 +204,13 @@ const QStringList &ItemLibraryAssetsModel::supportedImageSuffixes() return retList; } -const QStringList &ItemLibraryAssetsModel::supportedFragmentShaderSuffixes() +const QStringList &AssetsLibraryModel::supportedFragmentShaderSuffixes() { static const QStringList retList {"*.frag", "*.glsl", "*.glslf", "*.fsh"}; return retList; } -const QStringList &ItemLibraryAssetsModel::supportedShaderSuffixes() +const QStringList &AssetsLibraryModel::supportedShaderSuffixes() { static const QStringList retList {"*.frag", "*.vert", "*.glsl", "*.glslv", "*.glslf", @@ -218,32 +218,32 @@ const QStringList &ItemLibraryAssetsModel::supportedShaderSuffixes() return retList; } -const QStringList &ItemLibraryAssetsModel::supportedFontSuffixes() +const QStringList &AssetsLibraryModel::supportedFontSuffixes() { static const QStringList retList {"*.ttf", "*.otf"}; return retList; } -const QStringList &ItemLibraryAssetsModel::supportedAudioSuffixes() +const QStringList &AssetsLibraryModel::supportedAudioSuffixes() { static const QStringList retList {"*.wav", "*.mp3"}; return retList; } -const QStringList &ItemLibraryAssetsModel::supportedVideoSuffixes() +const QStringList &AssetsLibraryModel::supportedVideoSuffixes() { static const QStringList retList {"*.mp4"}; return retList; } -const QStringList &ItemLibraryAssetsModel::supportedTexture3DSuffixes() +const QStringList &AssetsLibraryModel::supportedTexture3DSuffixes() { // These are file types only supported by 3D textures static QStringList retList {"*.hdr", "*.ktx"}; return retList; } -ItemLibraryAssetsModel::ItemLibraryAssetsModel(SynchronousImageCache &fontImageCache, +AssetsLibraryModel::AssetsLibraryModel(SynchronousImageCache &fontImageCache, Utils::FileSystemWatcher *fileSystemWatcher, QObject *parent) : QAbstractListModel(parent) @@ -252,12 +252,12 @@ ItemLibraryAssetsModel::ItemLibraryAssetsModel(SynchronousImageCache &fontImageC { // add role names int role = 0; - const QMetaObject meta = ItemLibraryAssetsDir::staticMetaObject; + const QMetaObject meta = AssetsLibraryDir::staticMetaObject; for (int i = meta.propertyOffset(); i < meta.propertyCount(); ++i) m_roleNames.insert(role++, meta.property(i).name()); } -QVariant ItemLibraryAssetsModel::data(const QModelIndex &index, int role) const +QVariant AssetsLibraryModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { qWarning() << Q_FUNC_INFO << "Invalid index requested: " << QString::number(index.row()); @@ -271,32 +271,32 @@ QVariant ItemLibraryAssetsModel::data(const QModelIndex &index, int role) const return {}; } -int ItemLibraryAssetsModel::rowCount(const QModelIndex &parent) const +int AssetsLibraryModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent) return 1; } -QHash ItemLibraryAssetsModel::roleNames() const +QHash AssetsLibraryModel::roleNames() const { return m_roleNames; } // called when a directory is changed to refresh the model for this directory -void ItemLibraryAssetsModel::refresh() +void AssetsLibraryModel::refresh() { setRootPath(m_assetsDir->dirPath()); } -void ItemLibraryAssetsModel::setRootPath(const QString &path) +void AssetsLibraryModel::setRootPath(const QString &path) { static const QStringList ignoredTopLevelDirs {"imports", "asset_imports"}; m_fileSystemWatcher->clear(); - std::function parseDirRecursive; - parseDirRecursive = [this, &parseDirRecursive](ItemLibraryAssetsDir *currAssetsDir, int currDepth) { + std::function parseDirRecursive; + parseDirRecursive = [this, &parseDirRecursive](AssetsLibraryDir *currAssetsDir, int currDepth) { m_fileSystemWatcher->addDirectory(currAssetsDir->dirPath(), Utils::FileSystemWatcher::WatchAllChanges); QDir dir(currAssetsDir->dirPath()); @@ -323,7 +323,8 @@ void ItemLibraryAssetsModel::setRootPath(const QString &path) if (currDepth == 1 && ignoredTopLevelDirs.contains(subDir.dirName())) continue; - ItemLibraryAssetsDir *assetsDir = new ItemLibraryAssetsDir(subDir.path(), currDepth, loadExpandedState(subDir.path()), currAssetsDir); + auto assetsDir = new AssetsLibraryDir(subDir.path(), currDepth, + loadExpandedState(subDir.path()), currAssetsDir); currAssetsDir->addDir(assetsDir); saveExpandedState(loadExpandedState(assetsDir->dirPath()), assetsDir->dirPath()); isEmpty &= parseDirRecursive(assetsDir, currDepth + 1); @@ -339,13 +340,13 @@ void ItemLibraryAssetsModel::setRootPath(const QString &path) delete m_assetsDir; beginResetModel(); - m_assetsDir = new ItemLibraryAssetsDir(path, 0, true, this); + m_assetsDir = new AssetsLibraryDir(path, 0, true, this); bool noAssets = parseDirRecursive(m_assetsDir, 1); setIsEmpty(noAssets); endResetModel(); } -void ItemLibraryAssetsModel::setSearchText(const QString &searchText) +void AssetsLibraryModel::setSearchText(const QString &searchText) { if (m_searchText != searchText) { m_searchText = searchText; @@ -353,7 +354,7 @@ void ItemLibraryAssetsModel::setSearchText(const QString &searchText) } } -const QSet &ItemLibraryAssetsModel::supportedSuffixes() const +const QSet &AssetsLibraryModel::supportedSuffixes() const { static QSet allSuffixes; if (allSuffixes.isEmpty()) { @@ -371,12 +372,12 @@ const QSet &ItemLibraryAssetsModel::supportedSuffixes() const return allSuffixes; } -bool ItemLibraryAssetsModel::isEmpty() const +bool AssetsLibraryModel::isEmpty() const { return m_isEmpty; }; -void ItemLibraryAssetsModel::setIsEmpty(bool empty) +void AssetsLibraryModel::setIsEmpty(bool empty) { if (m_isEmpty != empty) { m_isEmpty = empty; @@ -384,7 +385,7 @@ void ItemLibraryAssetsModel::setIsEmpty(bool empty) } }; -const QSet &ItemLibraryAssetsModel::previewableSuffixes() const +const QSet &AssetsLibraryModel::previewableSuffixes() const { static QSet previewableSuffixes; if (previewableSuffixes.isEmpty()) { diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsmodel.h b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.h similarity index 93% rename from src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsmodel.h rename to src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.h index 989f9f7226f..7651ae1a224 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsmodel.h +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.h @@ -32,24 +32,22 @@ #include #include #include -#include - -#include "itemlibraryassetsdir.h" namespace Utils { class FileSystemWatcher; } namespace QmlDesigner { class SynchronousImageCache; +class AssetsLibraryDir; -class ItemLibraryAssetsModel : public QAbstractListModel +class AssetsLibraryModel : public QAbstractListModel { Q_OBJECT Q_PROPERTY(bool isEmpty READ isEmpty WRITE setIsEmpty NOTIFY isEmptyChanged) public: - ItemLibraryAssetsModel(QmlDesigner::SynchronousImageCache &fontImageCache, + AssetsLibraryModel(QmlDesigner::SynchronousImageCache &fontImageCache, Utils::FileSystemWatcher *fileSystemWatcher, QObject *parent = nullptr); @@ -103,7 +101,7 @@ private: QString m_searchText; Utils::FileSystemWatcher *m_fileSystemWatcher = nullptr; - ItemLibraryAssetsDir *m_assetsDir = nullptr; + AssetsLibraryDir *m_assetsDir = nullptr; bool m_isEmpty = true; QHash m_roleNames; diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.cpp new file mode 100644 index 00000000000..937587d3c11 --- /dev/null +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.cpp @@ -0,0 +1,175 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "assetslibraryview.h" +#include "assetslibrarywidget.h" +#include "metainfo.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace QmlDesigner { + +namespace { +ProjectExplorer::Target *activeTarget(ProjectExplorer::Project *project) +{ + if (project) + return project->activeTarget(); + + return {}; +} +} // namespace + +class ImageCacheData +{ +public: + Sqlite::Database database{Utils::PathString{ + Core::ICore::cacheResourcePath("imagecache-v2.db").toString()}, + Sqlite::JournalMode::Wal, + Sqlite::LockingMode::Normal}; + ImageCacheStorage storage{database}; + ImageCacheConnectionManager connectionManager; + ImageCacheCollector collector{connectionManager}; + ImageCacheFontCollector fontCollector; + ImageCacheGenerator generator{collector, storage}; + ImageCacheGenerator fontGenerator{fontCollector, storage}; + TimeStampProvider timeStampProvider; + AsynchronousImageCache cache{storage, generator, timeStampProvider}; + AsynchronousImageCache asynchronousFontImageCache{storage, fontGenerator, timeStampProvider}; + SynchronousImageCache synchronousFontImageCache{storage, timeStampProvider, fontCollector}; +}; + +AssetsLibraryView::AssetsLibraryView(QObject *parent) + : AbstractView(parent) +{} + +AssetsLibraryView::~AssetsLibraryView() +{} + +bool AssetsLibraryView::hasWidget() const +{ + return true; +} + +WidgetInfo AssetsLibraryView::widgetInfo() +{ + if (m_widget.isNull()) { + m_widget = new AssetsLibraryWidget{imageCacheData()->cache, + imageCacheData()->asynchronousFontImageCache, + imageCacheData()->synchronousFontImageCache}; + } + + return createWidgetInfo(m_widget.data(), + new WidgetInfo::ToolBarWidgetDefaultFactory(m_widget.data()), + "Assets", + WidgetInfo::LeftPane, + 0, + tr("Assets")); +} + +void AssetsLibraryView::modelAttached(Model *model) +{ + AbstractView::modelAttached(model); + + m_widget->clearSearchFilter(); + m_widget->setModel(model); + + setResourcePath(DocumentManager::currentResourcePath().toFileInfo().absoluteFilePath()); +} + +void AssetsLibraryView::modelAboutToBeDetached(Model *model) +{ + AbstractView::modelAboutToBeDetached(model); + + m_widget->setModel(nullptr); +} + +void AssetsLibraryView::setResourcePath(const QString &resourcePath) +{ + if (m_widget.isNull()) { + m_widget = new AssetsLibraryWidget{m_imageCacheData->cache, + m_imageCacheData->asynchronousFontImageCache, + m_imageCacheData->synchronousFontImageCache}; + } + + m_widget->setResourcePath(resourcePath); +} + +ImageCacheData *AssetsLibraryView::imageCacheData() +{ + std::call_once(imageCacheFlag, [this]() { + m_imageCacheData = std::make_unique(); + auto setTargetInImageCache = + [imageCacheData = m_imageCacheData.get()](ProjectExplorer::Target *target) { + if (target == imageCacheData->collector.target()) + return; + + if (target) + imageCacheData->cache.clean(); + + imageCacheData->collector.setTarget(target); + }; + + if (auto project = ProjectExplorer::SessionManager::startupProject(); project) { + m_imageCacheData->collector.setTarget(project->activeTarget()); + connect(project, + &ProjectExplorer::Project::activeTargetChanged, + this, + setTargetInImageCache); + } + connect(ProjectExplorer::SessionManager::instance(), + &ProjectExplorer::SessionManager::startupProjectChanged, + this, + [=](ProjectExplorer::Project *project) { + setTargetInImageCache(activeTarget(project)); + }); + }); + return m_imageCacheData.get(); +} + +AsynchronousImageCache &AssetsLibraryView::imageCache() +{ + return imageCacheData()->cache; +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.h b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.h new file mode 100644 index 00000000000..79fbde852f9 --- /dev/null +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include + +#include + +#include + +namespace QmlDesigner { + +class AssetsLibraryWidget; +class ImageCacheData; +class AsynchronousImageCache; + +class AssetsLibraryView : public AbstractView +{ + Q_OBJECT + +public: + AssetsLibraryView(QObject* parent = nullptr); + ~AssetsLibraryView() override; + + bool hasWidget() const override; + WidgetInfo widgetInfo() override; + + // AbstractView + void modelAttached(Model *model) override; + void modelAboutToBeDetached(Model *model) override; + + void setResourcePath(const QString &resourcePath); + + AsynchronousImageCache &imageCache(); + +private: + ImageCacheData *imageCacheData(); + + std::once_flag imageCacheFlag; + std::unique_ptr m_imageCacheData; + QPointer m_widget; +}; + +} diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp new file mode 100644 index 00000000000..f51e070bf6a --- /dev/null +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp @@ -0,0 +1,407 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "assetslibrarywidget.h" + +#include "assetslibrarymodel.h" +#include "assetslibraryiconprovider.h" + +#include + +#include +#include "modelnodeoperations.h" +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace QmlDesigner { + +static QString propertyEditorResourcesPath() +{ +#ifdef SHARE_QML_PATH + if (qEnvironmentVariableIsSet("LOAD_QML_FROM_SOURCE")) + return QLatin1String(SHARE_QML_PATH) + "/propertyEditorQmlSources"; +#endif + return Core::ICore::resourcePath("qmldesigner/propertyEditorQmlSources").toString(); +} + +bool AssetsLibraryWidget::eventFilter(QObject *obj, QEvent *event) +{ + if (event->type() == QEvent::FocusOut) { + if (obj == m_assetsWidget.data()) + QMetaObject::invokeMethod(m_assetsWidget->rootObject(), "handleViewFocusOut"); + } else if (event->type() == QMouseEvent::MouseMove) { + if (!m_assetsToDrag.isEmpty()) { + QMouseEvent *me = static_cast(event); + if ((me->globalPos() - m_dragStartPoint).manhattanLength() > 10) { + 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()); + drag->setMimeData(mimeData); + drag->exec(); + drag->deleteLater(); + + m_assetsToDrag.clear(); + } + } + } else if (event->type() == QMouseEvent::MouseButtonRelease) { + m_assetsToDrag.clear(); + QWidget *view = QmlDesignerPlugin::instance()->viewManager().widget("Navigator"); + if (view) { + NavigatorWidget *navView = qobject_cast(view); + if (navView) { + navView->setDragType(""); + navView->update(); + } + } + } + + return QObject::eventFilter(obj, event); +} + +AssetsLibraryWidget::AssetsLibraryWidget(AsynchronousImageCache &imageCache, + AsynchronousImageCache &asynchronousFontImageCache, + SynchronousImageCache &synchronousFontImageCache) + : m_itemIconSize(24, 24) + , m_fontImageCache(synchronousFontImageCache) + , m_assetsIconProvider(new AssetsLibraryIconProvider(synchronousFontImageCache)) + , m_fileSystemWatcher(new Utils::FileSystemWatcher(this)) + , m_assetsModel(new AssetsLibraryModel(synchronousFontImageCache, m_fileSystemWatcher, this)) + , m_assetsWidget(new QQuickWidget(this)) + , m_imageCache{imageCache} +{ + m_assetCompressionTimer.setInterval(200); + m_assetCompressionTimer.setSingleShot(true); + + setWindowTitle(tr("Assets Library", "Title of assets library widget")); + setMinimumWidth(250); + + m_assetsWidget->installEventFilter(this); + + m_fontPreviewTooltipBackend = std::make_unique(asynchronousFontImageCache); + // Note: Though the text specified here appears in UI, it shouldn't be translated, as it's + // a commonly used sentence to preview the font glyphs in latin fonts. + // For fonts that do not have latin glyphs, the font family name will have to suffice for preview. + m_fontPreviewTooltipBackend->setAuxiliaryData( + ImageCache::FontCollectorSizeAuxiliaryData{QSize{300, 300}, + Theme::getColor(Theme::DStextColor).name(), + QStringLiteral("The quick brown fox jumps\n" + "over the lazy dog\n" + "1234567890")}); + // create assets widget + m_assetsWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); + Theme::setupTheme(m_assetsWidget->engine()); + m_assetsWidget->engine()->addImportPath(propertyEditorResourcesPath() + "/imports"); + m_assetsWidget->setClearColor(Theme::getColor(Theme::Color::QmlDesigner_BackgroundColorDarkAlternate)); + m_assetsWidget->engine()->addImageProvider("qmldesigner_assets", m_assetsIconProvider); + m_assetsWidget->rootContext()->setContextProperties(QVector{ + {{"assetsModel"}, QVariant::fromValue(m_assetsModel.data())}, + {{"rootView"}, QVariant::fromValue(this)}, + {{"tooltipBackend"}, QVariant::fromValue(m_fontPreviewTooltipBackend.get())} + }); + + // If project directory contents change, or one of the asset files is modified, we must + // reconstruct the model to update the icons + connect(m_fileSystemWatcher, &Utils::FileSystemWatcher::directoryChanged, [this](const QString & changedDirPath) { + Q_UNUSED(changedDirPath) + m_assetCompressionTimer.start(); + }); + + auto layout = new QVBoxLayout(this); + layout->setContentsMargins({}); + layout->setSpacing(0); + layout->addWidget(m_assetsWidget.data()); + + updateSearch(); + + setStyleSheet(Theme::replaceCssColors( + QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/stylesheet.css")))); + + m_qmlSourceUpdateShortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_F6), this); + connect(m_qmlSourceUpdateShortcut, &QShortcut::activated, this, &AssetsLibraryWidget::reloadQmlSource); + + connect(&m_assetCompressionTimer, &QTimer::timeout, this, [this]() { + // TODO: find a clever way to only refresh the changed directory part of the model + + // Don't bother with asset updates after model has detached, project is probably closing + if (!m_model.isNull()) { + if (QApplication::activeModalWidget()) { + // Retry later, as updating file system watchers can crash when there is an active + // modal widget + m_assetCompressionTimer.start(); + } else { + m_assetsModel->refresh(); + // reload assets qml so that an overridden file's image shows the new image + QTimer::singleShot(100, this, &AssetsLibraryWidget::reloadQmlSource); + } + } + }); + + // init the first load of the QML UI elements + reloadQmlSource(); +} + +AssetsLibraryWidget::~AssetsLibraryWidget() = default; + +QList AssetsLibraryWidget::createToolBarWidgets() +{ + return {}; +} + +void AssetsLibraryWidget::handleSearchfilterChanged(const QString &filterText) +{ + if (filterText != m_filterText) { + m_filterText = filterText; + updateSearch(); + } +} + +void AssetsLibraryWidget::handleAddAsset() +{ + addResources({}); +} + +void AssetsLibraryWidget::handleFilesDrop(const QStringList &filesPaths) +{ + addResources(filesPaths); +} + +QSet AssetsLibraryWidget::supportedDropSuffixes() +{ + const QList handlers = QmlDesignerPlugin::instance()->viewManager() + .designerActionManager().addResourceHandler(); + + QSet suffixes; + for (const AddResourceHandler &handler : handlers) + suffixes.insert(handler.filter); + + return suffixes; +} + +void AssetsLibraryWidget::setModel(Model *model) +{ + m_model = model; +} + +QString AssetsLibraryWidget::qmlSourcesPath() +{ +#ifdef SHARE_QML_PATH + if (qEnvironmentVariableIsSet("LOAD_QML_FROM_SOURCE")) + return QLatin1String(SHARE_QML_PATH) + "/itemLibraryQmlSources"; +#endif + return Core::ICore::resourcePath("qmldesigner/itemLibraryQmlSources").toString(); +} + +void AssetsLibraryWidget::clearSearchFilter() +{ + QMetaObject::invokeMethod(m_assetsWidget->rootObject(), "clearSearchFilter"); +} + +void AssetsLibraryWidget::reloadQmlSource() +{ + const QString assetsQmlPath = qmlSourcesPath() + "/Assets.qml"; + QTC_ASSERT(QFileInfo::exists(assetsQmlPath), return); + m_assetsWidget->engine()->clearComponentCache(); + m_assetsWidget->setSource(QUrl::fromLocalFile(assetsQmlPath)); +} + +void AssetsLibraryWidget::updateSearch() +{ + m_assetsModel->setSearchText(m_filterText); +} + +void AssetsLibraryWidget::setResourcePath(const QString &resourcePath) +{ + m_assetsModel->setRootPath(resourcePath); + updateSearch(); +} + +void AssetsLibraryWidget::startDragAsset(const QStringList &assetPaths, const QPointF &mousePos) +{ + // Actual drag is created after mouse has moved to avoid a QDrag bug that causes drag to stay + // active (and blocks mouse release) if mouse is released at the same spot of the drag start. + m_assetsToDrag = assetPaths; + m_dragStartPoint = mousePos.toPoint(); +} + +QPair AssetsLibraryWidget::getAssetTypeAndData(const QString &assetPath) +{ + QString suffix = "*." + assetPath.split('.').last().toLower(); + if (!suffix.isEmpty()) { + if (AssetsLibraryModel::supportedImageSuffixes().contains(suffix)) { + // Data: Image format (suffix) + return {"application/vnd.bauhaus.libraryresource.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()}; + } else if (AssetsLibraryModel::supportedShaderSuffixes().contains(suffix)) { + // Data: shader type, frament (f) or vertex (v) + return {"application/vnd.bauhaus.libraryresource.shader", + AssetsLibraryModel::supportedFragmentShaderSuffixes().contains(suffix) ? "f" : "v"}; + } else if (AssetsLibraryModel::supportedAudioSuffixes().contains(suffix)) { + // No extra data for sounds + return {"application/vnd.bauhaus.libraryresource.sound", {}}; + } else if (AssetsLibraryModel::supportedVideoSuffixes().contains(suffix)) { + // No extra data for videos + return {"application/vnd.bauhaus.libraryresource.video", {}}; + } else if (AssetsLibraryModel::supportedTexture3DSuffixes().contains(suffix)) { + // Data: Image format (suffix) + return {"application/vnd.bauhaus.libraryresource.texture3d", suffix.toUtf8()}; + } + } + return {}; +} + +static QHash allImageFormats() +{ + const QList mimeTypes = QImageReader::supportedMimeTypes(); + auto transformer = [](const QByteArray& format) -> QString { return QString("*.") + format; }; + QHash imageFormats; + for (const auto &mimeType : mimeTypes) + imageFormats.insert(mimeType, Utils::transform(QImageReader::imageFormatsForMimeType(mimeType), transformer)); + imageFormats.insert("image/vnd.radiance", {"*.hdr"}); + imageFormats.insert("image/ktx", {"*.ktx"}); + + return imageFormats; +} + +void AssetsLibraryWidget::addResources(const QStringList &files) +{ + DesignDocument *document = QmlDesignerPlugin::instance()->currentDesignDocument(); + + QTC_ASSERT(document, return); + + const QList handlers = QmlDesignerPlugin::instance()->viewManager() + .designerActionManager().addResourceHandler(); + + QStringList fileNames = files; + if (fileNames.isEmpty()) { // if no files, show the "add assets" dialog + QMultiMap map; + QHash priorities; + for (const AddResourceHandler &handler : handlers) { + map.insert(handler.category, handler.filter); + priorities.insert(handler.category, handler.piority); + } + + QStringList sortedKeys = map.uniqueKeys(); + Utils::sort(sortedKeys, [&priorities](const QString &first, const QString &second) { + return priorities.value(first) < priorities.value(second); + }); + + QStringList filters { tr("All Files (%1)").arg("*.*") }; + QString filterTemplate = "%1 (%2)"; + for (const QString &key : qAsConst(sortedKeys)) { + const QStringList values = map.values(key); + if (values.contains("*.png")) { // Avoid long filter for images by splitting + const QHash imageFormats = allImageFormats(); + QHash::const_iterator i = imageFormats.constBegin(); + while (i != imageFormats.constEnd()) { + filters.append(filterTemplate.arg(key + QString::fromLatin1(i.key()), i.value().join(' '))); + ++i; + } + } else { + filters.append(filterTemplate.arg(key, values.join(' '))); + } + } + + static QString lastDir; + const QString currentDir = lastDir.isEmpty() ? document->fileName().parentDir().toString() : lastDir; + + fileNames = QFileDialog::getOpenFileNames(Core::ICore::dialogParent(), + tr("Add Assets"), + currentDir, + filters.join(";;")); + + if (!fileNames.isEmpty()) + lastDir = QFileInfo(fileNames.first()).absolutePath(); + } + + QHash filterToCategory; + QHash categoryToOperation; + for (const AddResourceHandler &handler : handlers) { + filterToCategory.insert(handler.filter, handler.category); + categoryToOperation.insert(handler.category, handler.operation); + } + + QMultiMap categoryFileNames; // filenames grouped by category + + for (const QString &fileName : qAsConst(fileNames)) { + const QString suffix = "*." + QFileInfo(fileName).suffix().toLower(); + const QString category = filterToCategory.value(suffix); + categoryFileNames.insert(category, fileName); + } + + for (const QString &category : categoryFileNames.uniqueKeys()) { + QStringList fileNames = categoryFileNames.values(category); + AddResourceOperation operation = categoryToOperation.value(category); + QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_RESOURCE_IMPORTED + category); + if (operation) { + AddFilesResult result = operation(fileNames, + document->fileName().parentDir().toString()); + if (result == AddFilesResult::Failed) { + Core::AsynchronousMessageBox::warning(tr("Failed to Add Files"), + tr("Could not add %1 to project.") + .arg(fileNames.join(' '))); + } + } else { + Core::AsynchronousMessageBox::warning(tr("Failed to Add Files"), + tr("Could not add %1 to project. Unsupported file format.") + .arg(fileNames.join(' '))); + } + } +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h new file mode 100644 index 00000000000..6c27be54a61 --- /dev/null +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include +#include "assetslibrarymodel.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE +class QShortcut; +QT_END_NAMESPACE + +namespace Utils { class FileSystemWatcher; } + +namespace QmlDesigner { + +class MetaInfo; +class Model; + +class AssetsLibraryIconProvider; +class AssetsLibraryModel; +class SynchronousImageCache; +class AsynchronousImageCache; +class ImageCacheCollector; + +class AssetsLibraryWidget : public QFrame +{ + Q_OBJECT + +public: + AssetsLibraryWidget(AsynchronousImageCache &imageCache, + AsynchronousImageCache &asynchronousFontImageCache, + SynchronousImageCache &synchronousFontImageCache); + ~AssetsLibraryWidget(); + + QList createToolBarWidgets(); + + static QString qmlSourcesPath(); + void clearSearchFilter(); + + void delayedUpdateModel(); + void updateModel(); + + void setResourcePath(const QString &resourcePath); + void setModel(Model *model); + static QPair getAssetTypeAndData(const QString &assetPath); + + Q_INVOKABLE void startDragAsset(const QStringList &assetPaths, const QPointF &mousePos); + Q_INVOKABLE void handleAddAsset(); + Q_INVOKABLE void handleSearchfilterChanged(const QString &filterText); + Q_INVOKABLE void handleFilesDrop(const QStringList &filesPaths); + Q_INVOKABLE QSet supportedDropSuffixes(); + +signals: + void itemActivated(const QString &itemName); + +protected: + bool eventFilter(QObject *obj, QEvent *event) override; + +private: + void reloadQmlSource(); + + void addResources(const QStringList &files); + void updateSearch(); + + QTimer m_assetCompressionTimer; + QSize m_itemIconSize; + + SynchronousImageCache &m_fontImageCache; + + AssetsLibraryIconProvider *m_assetsIconProvider = nullptr; + Utils::FileSystemWatcher *m_fileSystemWatcher = nullptr; + QPointer m_assetsModel; + + QScopedPointer m_assetsWidget; + std::unique_ptr m_fontPreviewTooltipBackend; + + QShortcut *m_qmlSourceUpdateShortcut = nullptr; + AsynchronousImageCache &m_imageCache; + QPointer m_model; + QStringList m_assetsToDrag; + bool m_updateRetry = false; + QString m_filterText; + QPoint m_dragStartPoint; +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/assetslibrary/images/asset_default.png b/src/plugins/qmldesigner/components/assetslibrary/images/asset_default.png new file mode 100644 index 0000000000000000000000000000000000000000..ef59d892791f9a91d37b5cd1330b7d78be415cdd GIT binary patch literal 312 zcmeAS@N?(olHy`uVBq!ia0y~yV2}V|4rT@hhU+WOo?>8N@C)z>ab;j&SV29|be7SF zfq_A?B*-tAfss$Zz{J$ddcw2?%k~^Nbn5iuXCFR({`R|z(?pYjfuX_E#W6%<;@pY1 zg_;a_Se2h%b8}H-`u*SjmA9;(pG@lfOK*H;&Fh+@EWjM7BBbt97hq{EA*Sf5GXb#;Uo|hl>OSjhpYP9k}ch@-;Xnw768@VMK2K tJB{x}<#+S>OOy+pza-m#Z2td&$>_O|=w`;v=?n}E44$rjF6*2UngG||i@pE= literal 0 HcmV?d00001 diff --git a/src/plugins/qmldesigner/components/assetslibrary/images/asset_default@2x.png b/src/plugins/qmldesigner/components/assetslibrary/images/asset_default@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..6540cc859cd93fbc9e4cb2fab46f642d3d615ec5 GIT binary patch literal 346 zcmeAS@N?(olHy`uVBq!ia0y~yU@!n-4rT@hhJ-tuTNxM_Yyx~jTp1V`R*(yrN>jrb z7#M_0g8YIRxOsR51QpcuLgES_$qd(&r7#MbWx;Tb-9Df_?D0E1HXNj1W zi0G|9|JPe}S}ADG@IJk;I-zX>tI#CZmFo-{4}6h3{nFE+$8ODm1m3zQf1Y#9?kIj) z->miS=)VgG&Pz_ep>)KCkKgx4&j*Lwk9zbH?lg5PDhJrf&d+zh`FD?4lb@+g;)1K% zRjae(d>3=9mOu6{1-oD!M @@ -240,7 +240,7 @@ void AbstractFormEditorTool::dragEnterEvent(const QList &itemLis const QStringList assetPaths = QString::fromUtf8(event->mimeData() ->data("application/vnd.bauhaus.libraryresource")).split(","); for (const QString &assetPath : assetPaths) { - QString assetType = ItemLibraryWidget::getAssetTypeAndData(assetPath).first; + QString assetType = AssetsLibraryWidget::getAssetTypeAndData(assetPath).first; if (assetType == "application/vnd.bauhaus.libraryresource.image" || assetType == "application/vnd.bauhaus.libraryresource.font") { hasValidAssets = true; diff --git a/src/plugins/qmldesigner/components/formeditor/dragtool.cpp b/src/plugins/qmldesigner/components/formeditor/dragtool.cpp index f2eb5844066..b3650aaae0d 100644 --- a/src/plugins/qmldesigner/components/formeditor/dragtool.cpp +++ b/src/plugins/qmldesigner/components/formeditor/dragtool.cpp @@ -27,7 +27,7 @@ #include "formeditorscene.h" #include "formeditorview.h" -#include "itemlibrarywidget.h" +#include "assetslibrarywidget.h" #include #include #include @@ -142,7 +142,7 @@ void DragTool::createQmlItemNodeFromFont(const QString &fontPath, QPointF positonInItemSpace = parentItem->qmlItemNode().instanceSceneContentItemTransform() .inverted().map(scenePos); - const auto typeAndData = ItemLibraryWidget::getAssetTypeAndData(fontPath); + const auto typeAndData = AssetsLibraryWidget::getAssetTypeAndData(fontPath); QString fontFamily = QString::fromUtf8(typeAndData.second); m_dragNodes.append(QmlItemNode::createQmlItemNodeFromFont(view(), fontFamily, @@ -328,7 +328,7 @@ void DragTool::createDragNodes(const QMimeData *mimeData, const QPointF &scenePo const QStringList assetPaths = QString::fromUtf8(mimeData ->data("application/vnd.bauhaus.libraryresource")).split(","); for (const QString &assetPath : assetPaths) { - QString assetType = ItemLibraryWidget::getAssetTypeAndData(assetPath).first; + QString assetType = AssetsLibraryWidget::getAssetTypeAndData(assetPath).first; if (assetType == "application/vnd.bauhaus.libraryresource.image") createQmlItemNodeFromImage(assetPath, targetContainerQmlItemNode, scenePosition); else if (assetType == "application/vnd.bauhaus.libraryresource.font") diff --git a/src/plugins/qmldesigner/components/formeditor/dragtool.h b/src/plugins/qmldesigner/components/formeditor/dragtool.h index 7e1b4cb4812..63d3de6e8f7 100644 --- a/src/plugins/qmldesigner/components/formeditor/dragtool.h +++ b/src/plugins/qmldesigner/components/formeditor/dragtool.h @@ -99,7 +99,7 @@ private: QList m_dragNodes; bool m_blockMove; QPointF m_startPoint; - bool m_isAborted; + bool m_isAborted = false; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/asset_font_128.png b/src/plugins/qmldesigner/components/itemlibrary/images/asset_font_128.png deleted file mode 100644 index 44dd517b354bd86424697524ef667d6a7779e320..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 238 zcmeAS@N?(olHy`uVBq!ia0y~yU}ykg7G?$p219|G9}El(asfUet_%zeD{uqr=^w8% zFfeeI1o;IsXgIhPEVyvz-Ski2?=UbhlzF;1hGaCpz2V5&5Fp@sk-v*EX8~tV0;gm7 zHG>90mz>vSX3X*>mG8b8svns0Jeie&fq|icXUFslQqzs~+__>@uN+P7Kg|XbcHrt+ zxRCF~V_(nHji*2Y5d6S@!OH4mzM2>8LeGLlQVwwE=e$mMCN~Fcny0Iu%Q~loCICZZ BROSEx diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/asset_font_192.png b/src/plugins/qmldesigner/components/itemlibrary/images/asset_font_192.png deleted file mode 100644 index f6f394fdb0806446a45adf12e7d9c79071f23d8e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 287 zcmeAS@N?(olHy`uVBq!ia0y~yU^oE6EX)iH3=2LLnlLahs08?gxH2#>tRMuYS36`d zFfeeJ1o;Is7&y2^7j#cqu>L|qbjuM228Q{bE{-7;x8B~`$jRg=&~}k?OV{edcZ67W z9+1*GdP7Zbk4xh0%?*MwVSIewYCoRe!=`rY7%Kw;9AleT{AynK`aQcu8@-n-+Y|Nq z6$e7Lp_bYE-5qY3eKOrqrVsiN5~!>P;mhw$zmqLkvE|%7BpC_m9}J0$V+&_)+{XVVW$89 diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/asset_font_256.png b/src/plugins/qmldesigner/components/itemlibrary/images/asset_font_256.png deleted file mode 100644 index 2a830a216a5a4d3eb6184189f49e2b96c82db3f8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 339 zcmeAS@N?(olHy`uVBq!ia0y~yU}OMc7G?$phIKJpLm3ztqyv0HTp1V`R^R}Rt)eUp z3=AA4L4LsuGA0fM3wB&M!MUlBfq~(^r;B4q#jUq@c5@y!kZ28jsK#Bv@P2|??txbK z4;-4Co8>d!_!LMhb{u@3ee|il@QN$;;S9LIqtpL zXGZY*c@2j1GAn=;`-g!aMaG7#Nu1JzX3_DsH{K63BJPK*S|*b{FgZ zUH@BGO?0{IEa|c2`MQJ(_PCp-TZ%4TU|?WSU|?WjXkcIvU|?WkaA08IU|?XROpw8k z0byW0&xcy}?31asJKq@VI#jc)KACE|bB!-IVQUd)kmaa^ss^bw^B=Ew{ZhNvxcW2IA@dsjWX2on%o30x-L0pC8 i=)`9YX0j;RApgyxwsl9sj86;<3=E#GelF{r5}E)=ZHyrR diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/asset_font_48.png b/src/plugins/qmldesigner/components/itemlibrary/images/asset_font_48.png deleted file mode 100644 index e8691a2976198b1cc0efe3441ed8b4eeaec62402..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 193 zcmeAS@N?(olHy`uVBq!ia0y~yU@!n-7G?$phNU`BwlFX-$OZU>xH2#>tiTPdr+>W8 zz`(#+666=mpyA+Fu;9X-chf(8zr(=5;OXh&7-Hd{JfoA@fJeRaw_}X^R-zAF41i*z8HJ T*k#=PiUDM*tDnm{r-UW|0~`nSra;yc4m_JBd|Uz-SPC=y fNQFA2vog$nSbig9kI-}m1_lOCS3j3^P6Eaj?(fanPZ${(7#Ke2Ur6cClW*9j@|J;N0apdX>#K}RtOxYJfh0X${an^LB{Ts5*^N$i diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/asset_shader_192.png b/src/plugins/qmldesigner/components/itemlibrary/images/asset_shader_192.png deleted file mode 100644 index 5f8ee5151d8dbe9124253b1261b4209324f13940..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3038 zcmeAS@N?(olHy`uVBq!ia0y~yU^oE69Lx+145>_WOc@v$9|ZV>xH2#>tQZBuHv}#= zr=MkDV3=PLh9(3UO%`oT_?4 zDeFM<(P&3k7ojVx!h-!C0^(eR)6m@X*7dvhqQc`iHZE1TbjQ+W z{j3vzK78Fgv0=ig>DP`Q3%fccrF75c#LWSxo?kzb7Se4by!xcL^Y4HXhrr81sR~k` zqJJkO|L@9j4y()N`L&{MNp|2?-EMQ`e;NB1KArh$f{p$DgT-IXx2lG)t6to8GWhH1 zM_sQrXvC)8U*UwMvM`R3<}1VKAwAEpLMFl z`TyDGU$X1JCtO?3CC12b!m1*?-a(?|V1(_;-@lgYubG*Ajgf&PcE+{89O`q;ZsonS zO={K+sS*Q?bfOQPf%8e;!e$(PSA{#F0o@%F#T zTKmK_uhdpMIx{$26@DvhSMz+rFH6~5$Buu`etnaX;f?flyQRvrE|BtF$^xlwrl_fJn zqujj+%X!=W-FY4|%V)JU3qwcI`&?CDmiC=xaqnBq88$o?{r>FIukLR}|NjRVm7lj{ z(2#oc%Tda<(%Ssros-Sw3=_U+Me|DBqILO1TB&+q#+?>yFE zc)*_Lw=E^~$%b#|Pia>0Gc3R1_+g{y>AtP@(_cSiXSlNYa6&ul@AzlL-|9Lx@6b{(jPGMCkpA;o9=l?rphLE7yNw+FQUkT+tHaf!CaC*y!Neh+T zt3Q0UnaJ?uQpfc}=4=czPRvtdc%seVGULXwM)8$1u6-0|_*^FX_os#5(;yMgmao+q*< z+AW#5rB?6}lY@5V;=ujY+KLkyTTYbxw%+M;WaV^9_cAsU_FH&R>6ZM&+bMj0=MEdap%SPu8?*@Y!_V zWLfB2HW&5==~+=rmpqL6$arN^nw{nMuSc%)bn!1}@QLERRWKpuljaX&HT{M{291cR z;s>%C_-~z56J$7R#B9O6AUKWTIwQ|%o&<>ld(JRCYjg_D(sbE*he4|#CXb=CXa4`l zRn1jSVSl#22wU)4yy|HQtIKxAO-!G>wmWSNyB@YBTmPNl)fu-JU)?Huw}|QO*>k#_%efA)fIDt3s{%v^t5YbxM=(O_^|S z#^if*rrldO@!rxY_g1c-YP&|MHo^PXg+*Tu#{N9~`jUQu$NnQKf0gEcIlbnRe#zNRt%FqIsKfp-?fk4`V_xnv(B%HC41K}_yjeiePmGa zSeG=RVj`zNXeaA}u4z&`dwq&#h&!papG=-~SR&1CugC2P2Dbb~F1`~)7IIEf^Ubj8 zyWkeb=E^8g<9XW0(`trF;&vCt11g-m^OxCox%yl__GDkQh8gRDXC=bQf%p8hJ3qPj zg#MT%#-rvNCz*DwxBXhJrhsx}3Rj75&aQL2>z2RXb9lvMAxo~=d-k4-{TL zv2dGO=}$>}hB;~X|0{bhF=5oJ{A2l^al_y6xf?t@qYo{8pa0pa*50~qRlavZpq9n2 zb-Q2hVVQ9JT>PuwToGb7HFX-C_f710Q*+iX(z0dClNtUddcHQj-ny5jB->0pw|2pA zh9)Vcxm&)n^Zj&4{W7Wg$s@%Z6ZYCnU2r-js8Y&k<@aqTmNanj&b{8P^_?Lk^W`3` zgkUclm5|GMiE}j?b2&3K-=^JNxMlWLn->$6r+l*vFWts1S0Htu?z#snqsfbcPWzjW zRT}Q*U9w`j@k(!F+S1!cW?7l!u3EL~)d^1Z6~6v2f@XiSI2)hupjUlSZ|57={1d5+ zExa#k-``yL{jKSO@1?DIHp*Ep8)|fIo1SL3v7DAHaPK;+v939cfyGy2-FxxFww6Yj zD<(UuJf564sfYQ*#5vDo9Rhs{y=zs&SoD{u?0eJp>-0y1J(D)=cpUH8IsKrwW}dgj z%DP2sCE`y1n#Q^OO8vD>jQc#6WMAC(tvgomhx)-|bo_+fd96WOL*zpr5Pn|w<_T2dk7q8#AdF%F_yZ7!tc=Y(m(^qfbz5np> z%hzw;fBgLQ`_JEhA9Gmp7#MgvJY5_^DsH`<`_eh&y5zC>g>8-=iap+jy(%Xb1*Jx{ zTw0h6D9i|Uj&}ck;KSYH6IZBs2AO>N@$Q2|xqI~C zWfvYX#H{XlaEm#%Sf(u3ch7~pKq<6z5n;TlojtxZ~fdGa7}VLPxznPM%7jJYoA%4 zRH+R&K3n$gxB0z^K36`d?O%Jxf3@^PpKBg-YXyE}<$H_0C|i48?q7SGO81xA6KwCM zfAJJs_5QlpZu{R6KAS=|CU0K*=4)=RMz~>(QRR2PwyC-Ea<;B1k0^>Plqs+BwwtEP zpCI{Z`G`hPqd z!pOj}CO9MO@YA&KHM3Hy|MEw1)o;7X$k1?T8v7>YmS-l$fAuHvmVXITFS+!Ekzq;b z_Y*hcw2jXH|LUK5?2YWwmaTCN3{%QZ9FdxrXK?cG8^1bLx9I0V-&h*{l}Ua*&CKv@ zTi>Vse{bg)|A{~F{-<5`ypuZ`83MG!E7l4zB&2?yZxZxA^UY;s z*vUS>aQ*@QUb!D{pPL=7|1J7l?k*!ke$ByJ&bQ_z9TE?=9scY1&XjO3-7d2>Xy^@X%@TpZHG`K0muXU9)_)Aw$EN+BxNq7ONin5q~zbY90I2 z_r_cd0abG^%Y;imte35RBEL2~tF(uiA>Q`4d*{`c@BgdMnZG~cqaQOP!_n(EzW&;L z@1ObR`?b0+H;6I((S2i{w0YgTYCePgPwHA{&F*Do2>Ekh&7F7~t6%j~eu}22AK+sU zusFTuUf^Gj4fX%srf#%2%y{7Ti8?l(zyICug;($X$k6aznQa^MnQ#Bo7~ilku$uE$ zi(fHRuCv@A&amg+=~c`5{x)WX{eQk=+L0xe3=jTWuXdkOG{1mz_3EwO!N0SF7%Iv( zRvp#smp=L*d%yl}eKF&LNgsLEco_ZjJzk&edF4b3Lxk6M zX8*}u)6)5u-uoBH*l<;-?thig(~?(L*BePQm>Cqg-SUn+|Kk4vNrnS21T)V`i(UMA z{;}M0h7T9^K3XnSd_1${-|qaZ|Mtlft8%?{();JUo#%2pS889{D=Te#Tccgea^qBG znRd)H_!q5m)300TSetn;H{X=t#$z6je%yb@5a8hI@klD|qR)O;QU4?LIs6RoFE=xN zHC{RE#Si&8Yz!rHJ_K+5r@!Rc{<&YR_#38oiTbaY=96FBC;Egk{3<*3!e>$L^f|fVi{46F-nI*6 zFgkg&r2J2m&_eBnTnGHLnUt(U84qyrHrm>IzHU1HlfmZ6oJ)fLls8O#!(5!sV8y}E zl+s^ee7;C(=f9n@c?=Eu9NXI}v(IOrxbkWCJBANzH|5tnl!#M#!*@uQp24 zdTJPo?lLJ%KQm+6N-x&8tA9N+IP*6B#>2zjN)u(YN6zY^~=f%6{v zcUT#Y)U5X`ir*y5vM_5q;|evIJB~5x-|DL$luI{kVc)d(;PxrOjC|}4s+`YGy7_nC zVPD{2cB?it`NNGyh7%3{udclQOt9qIPQe3KGyfkbQ|gx~P;Ow@D1ZK&=Jj)`aaOG6 zObiAE87Qmw|fB^vI$R)v;>JaI8J2b zVe07MdB8bAnR6|J*k`@3*H3jsJi4Wt?#)xUf7)i%s-^8uaypM?_s`KSXTNmx3sd9# zEAN&ycvzo5EnwEkn_yh8qruj|wxyGILGLVE6^RDEIik`I=4?mU3Rn*(G5?T%*Twrl zPp+F+;gCFcC)0zOHyDm7cJew@u|5!GxX8$HpM&eaRE>%i!^7Q&4)M3O$n$Z_3kce& zlzDtvu;N2v;X`5NL(7k~`1kG8tE!6m!6~$U*$EDNPp==DMNa-xVt!|>TJvD?QsX$^ z>EhJ~k93B6r!hPzf5cR=G2@l^BK_HiO9L7I>?jbb_x%&GXX$2bVS72DypLaE9-TZ< zuFY`oQ)QxAz>P^2$4~Q$wA^%hT=GcPK7XO&3pK4!{q-EXde2Rn`}x1`o~w5_8}?6} zq!67c$e!VQ*US6I*()dBemS>Wu;ETwl~T@%2$vl*b}Ur7Df#D2EyD?2)BApV-u&_n z{rhS5s-WAiuI=D$xU_B8{*vFvP93q_a^={mkT#tcdJIc@=0q&|=MeGda4drr$M+X! zuio9ew@&UO|Ni3^HO1n}`7fjxQrIfYxhK7F&v_utJ6Ext@rL(~YbUq-(oKB2D7oxJ zsN$RCvLlumFBhFU7gVy&nqkk%Z!2`S%WZQzH)+pd>zrPze8Ydz<_rt^Za<#C!$WpQ z#YJ9ry*PzAlPn7arB8fW$lZ4*MssBy1A~0!i&wVaWp`Cs`ySRmU|V>`^7y-;%L=LU z9e$jU3^r_+-y@^KA161-zCuzyU^2&?+An6N!d6Q}Y~Crp|8e6a!-~V#t3^M%t3K&j zn6a^#QN;aZeMx5#-_PPrPhP+DW1Zl4w$5tV8~e0CZH;f1q70=Us#2zLG5qMz+I?sy zgVqVV4O>Ec|9|*5eb4)UJnBp{3g?^bd=tvbz^#75diUOQ%n#nG>8go2EtOh%Y4#lU z1)di<_g#7^`NexKTY_e4LH4dJ294#*`0X`I#2OB%Klxf=X|iJGv+0jj7%a_KzCIiE z$NiS*s)o$Q8o1zEieGP7bn;I`}8Tu+h7rY@qw@o!leR=*TA zaE?4FVlqFEElK`{`~jm||1bVL`FHBH%l(%=m%rtEF!y=M+Ud%khSx&-_h#oayzjYK zn&*41{zsL>`2*}_Y#Vw${{H@B5?jL@gV?y7t+k8>x9m0NG>e3Mn4o94@8UWJGowHC z5e-v9j{WfW?3J@-`e5+O{!)ZwP)Nttbzi*q|7G~mZ>%M?+U?Y>15#CU&u^4&m}3`a z`+7mMUE0)|)feIzxbin;{p2hOG+zBi-TN&|!b{;W+1U#xe=}4T@QvHe@WISbdq=$f z|A&^R{xrRl{KjCgcy{F8#d0s)8~*a#S-*j~q3idX`|F&A$(;Ux<~yVV&z@|1FaJK)8Hrm{u4&vxrpkVL6^CR)rHcIrG;@ zwXJxg`1^O#+L>VtCvxVdTz{S@$rI!_WAYS<$d`uF4e3ugmK!}}l2|rJE-vm_(uEj? zgWP*&eR*=g;pdLs{KsxTpT+**>^F<`a%=4*RzF?5XMJ6n!F3sio$Nc0C-vyHKb&QM zB|E^@T0q$|r|& zM)&5h6^E|dAe?@GS3?~G)9YVPc=M+oF7eHuGhzLeBP&gBRxzB2D-L=&d)BhUT)KPK zJUQ^=rS8v_j3@3FRmGfq^~oth<-NOBSsMR*FS!FJH*E4vSuK7o^V)N<_s1oz&A6|v zT5{a$f3clg^AxPNBlM?d`cHcI}DQvBVHoA3Is+&o^(@ZtJh!^?lIOY3g< zUS6d?>*>Fvvobd`hD%5%{<>i@2#sowyQqBT<(o-e(3cjf%p8&LMtCKJbkw# zrRDeZvNMgzQ^M;*0 zz`&qV666=mz{JeSD=aOet!H525SyG*IcfU*CCfML-GA!R?dKmqeg5|A&%bFrF;WZ+ zjQpN1jv*GOTZ3;lH97EfTPz59vMk0Z=I8(XJM8*pv2*sA8T;O5sW{kwI#1>Jx}Mq^ zr8Q}jPMheeJlFaYZ1&SDdW(wZw$`V!X6OFBb9outDU~iEEuXBL^Y4E>eZY!gfr!Hj zhNfAEpMI@Nc=phovAyT;WB$v=)?FPQhgYAN+S}0~WBjdL)-v1w2czYcGmHu`xeO0| zLv^LEwuOb}i?EdOGKTof?=_d2!n9-!L;be2{)9Jgl+zk*nYfN=+zWxc5CQq3 zUA}Vl+VvYZZ{5Cg_ul;n4<9{#^7PsB7cXDEe)IO-`wt&Keg5+G+xH(ofBpXR_n+b1 zwN4BSVkw?3jv*Dd-p+mPEb2b%*!|)@2L&O6s*biDSr>d=uCSDzsW_>%`C>z$+wt2e z>W_8XGTdBMlJCrIIcp?U;B;Y4M#%*gr!b!*6FNJMCpQQkT(DV7I^crb51)UYes^eM)9bD95H-sf8W za+-Q4PR3c*znYPu5V_j%WcRiwQ^U4qG-a**rIUYp(G$lfb254TBf|p=r&EVVbM9RPWt3Nf%=(_shxaYdJZ`ZHClC$uXd5neAhjVr} zmfm!WZ4cVBZd3hG&;s)-uy{x7JI`%R~1* zv$(pRZ|eDt=?5dvPPCf+j+6Dj`tgX5 zwm(-i7&v4Y7&@v9$Zv0i_-7K&gWHOVEAzM#9o!z-(MH@ZK`*e z_9T0cW_{ZF`w_=~R?znkgN4bN6;m>USF7d**_uuS$7OHY_V?f`K6+s`H1;%aq^etkXNnw0C{)c`kZ{ZNf~&H9nCH43EEeupKYon|C?#RmR1Y z?e7k;)OqGG2(50}_=$l*h|5(_X2a8L4bOsSYtzG<;sUc67*s^Qaj>mdxq1G7Ym@N# z_G7Q6FXdu5aHBbC?T&pH@|xGzi?9Ci+$r9mlz~C5Uhmo@`x{vSV$oV5FO5GR=?dm# zQ1I2MSbxP$`r~|&TM<>J&Lvjfx(poA)uBsluX2`stiP2yG5`JiKZjVg*ccw%*ZgF< z&*-k)KmGS2E8cL<>~%QB$e=P`VCKnRTV?sa5yUX{_Kf};}{cEnSy_4uXb+aHth0lN0XzQTf z|D56_i`Rrn&EBz9nBl{k3%yTwElBbBHf7!ascy-cIjjr{f#vT1TU}T;pWmf_e2)hQ zFN46(d3pZ&C(HiDMTxc*+i-P zXJ35(uH}j*j0Y~4S|vYPaK_8!<(dCeX4{t^U&oNJ!S7DCt3cYb8Y}0|O5ESJ+!SMI zd41;GRF=B3sPupTbF~*8d&A9O^MB!HJAsV<_n+APyS93o&5>ga3~_sx7WL*>*7uso zI>|HWJXqhzUNW~r>if;>>5bA12iCm46Q9VCtUB+>vH4s6@Z4c!SXS`3Z5>OFhfK8W zl9w90nJ>)jTEiD`X3lz(h|7)J*cUi2Ffo`LnD^%`tM>BbxBLvpik2V#C&2MvoGst# z4kJT?&Ubr(h8JI#e0!klZo$a#U$^A$r>`?J;?9(HAMGz@VeokLwKZ$ay`x8>`*!>@ zE>LEeaY&k9Wtm)fy>$iz|l3VKgVp1ID!uo3BdEHazXZZSzKv zq30rl+>ZS>JN|#nkT{b1FHB}TQ^WBK7M*3v<%SQx`@fvC|6vrvhe=bjjVE6`^o@bh zp=JF!kNX_Y9m5%=*o7H<`v0{&wb9#Mw1Z)7OP)YWH>1O@!rQ-ew=9fq>~3Tz_>!*k zy1%G=^E#*FS3j~Gxbfy}mgIlsi@)oyGci8M(w(;bU!wN4M%QOycX;geAB<|J6@?X{Q4Ac`di%LKZB$L!+|5^5g+tFaC~F85cXqm5ovp?mL=9b{ayp3 z$e#a)zA`9?78fkOpdca5T*JrWU|?Rx@4NTJsWaMX>R&h*?56&SZVXU(!&=6{(V)R_ zAn)+1k5YB@Uwc#;9x)tCTD;NZ?wVAObFmH#M;ILzUOd^u>2d5G3zGt~0^{!KLHcoj znN{Ky1sEh5Uc@^bKXFiY*?$I>hTq~ZK1fToyk%rkU}yLzy|IXSJAc>P6LS6xDU2$K z*^~Fody%6O%qhSS$xt9+Xngd*k3=iR3G4>GbuQBFb50gAaWvR4{NTQQcAbUEajTY_ zLQDxP2i6N%-*+fhsOHgY6J}6mI5eU8@2U+vCpipH&Yi~cVBH3W`ZrnkW6D1H*)tlj z9q8xD{(r*no%1_BT_&ak9)_|DL5CUAUWq*6H*RK-U^Vc~(%8^F_lJl8!(xU7U2k9J zh27$Ka%JjQmID?HOOo#&yYVieq&wT2?x3A0ctJs|P`(eXqz@ET% z`}+U4^Z7d4c05sKc*annzj5x|3;MD}?_%@>7>XG-NN)RQJm=}Oy^S0W@xJNSzfHVv}by;AWWlc+b`H^$t?flNYYmID%5PH}Lj)s(Wkqu4dX*Ckr!VGg5M`KmW&YE| z_{mZ1EC;w40*>pf`Bm3sp)zUL%?UTM1D1|}n?say;U z3z~WYmab=Dc)%sO(94&Bq4@-RsT2#t`3bzQrtmOypI|GE;<=+e+q3bSSPeU)ro<`s zhM-N3bM2VFbWGWIsz+43I>yj_5ldOXVUCYXZU)>L6IU?(=Ii6?6f$zHSXaC? z7)`j`o(VNDFlMynF)a{kV3T50U|?xr5MW?(VBlZ?aSoI+WGF0?VDNR-nAf%7q{Y$6 zg(k9VE39UTrHJUCxG-tSBUR6+DdAiTc>eh?gfLlnG)87IiUedViej)7nX_8#z-*Cu z>%_E+}MN7mE6mRkL*KIJ|;v1^lka26pS`i2B3xTYs`n47uwi0<|yx?)x z6fOQ22h^6{Vk$|Q8T6Oy#Ra>iUTjv|f>yFIUO2dxtCW@D#fzlYU9}~KviH{dZ0CQ! z?D6ZVFTZ{KTGH5Tba&r@#&rgP%O37I=^k|8YEk;5DeESMEZM#JcFDxqN>A@FI)qDV zUAnuP=cSRq>#pjV>appo-M+8e-1=Y9ION5>)^i`kW-fI4zTTvM;+cSjSE?D>HVBuP zNC$~;-XJZcs&H8BBh!Qc=}xUX31Syg&rIYiD}D6t_=XT;;W_Nii*_vdw<=jI?5_6F z>Kqqvau&Mr?%7wbO*7`E@G@>-I*_$(w|BK_XS%wkB10I1M&fSi`_^YA(-`r=d|PSCYsZuz*08=YGNjz+ ze#+AvpZ`t_XP6SEFOhveJ;&HOQjgJqTVeX!oUr{Vo^Mj7?_oJ0!|+~p+h*Zk>Ne;7 zzJqc-LnZUy$Biwwbzid!GBny<=wlZ;m!`f)%8}s=Lq|r^?^&N5P8q1AN--KREA+n2 z3ck_o$$it)UXdYDo6ux?S1Jl!CZT%$RML4r}BY~tH=)mhB9*KMD|Ai>yhWLC!O zkL6-UIX~JMBp5%K8g1!4ygA`|_IU+{PYlbH)8w8!nc4b8QFdG zX|t}bci1GS#PEn=!qSAdJq`*D}n3TLv5y+hbKl@y_H}TVEw?Fl(_f8 z9wRe}%W+B!Ni&~kwy`Can|?5wv{!8oLx;v6o}`50EjwFf-j*^cD1CX>uy)ba>9F`gtB9iiZsv zPTr7sv+9U`hBDiO==p&Rii(U3`-CH&`3lt^I8n7`3J=qP>rp!SwM)(vNmU(8ye-Vq zu>41u&U-D%|B7qaw4Wz49S|0~w&3b1*6@QhTZCS+FoavpDrNLoC8NEvkc07n$r8cS zk$SJ~RTgi(;m(jE{^;nh_kTlDzTAHj$MBsyGfbf0~jJ)^m_0EwuF4mOR!CLTAH-6FC^3=S`mN$+BSoq`U<;>loR-3Pz=b ziZH$~uMTc~b}Ro%y+l|1w>ka{zqI(zUa>l3z!1@TJynwN#ah*hWv0jevg_BKj;mH; zd?DI#weQ)_Q`t-mHdhg(rAf1JUA5jffd*^k2Ih)sI>rAEH{^fV zw3+ijZt7!8KRyFahGUQQ7tY(s!oZN=$N!IM7RR!!g6sXWl^7W$y34O^?S1x_{k?d_ z&*u@1PVePRwZD};<@(5UWA1jn%c9lOMcG2ye;1!gXJnAL*=7Imbh`q>CdZfw8GV9I*wd9hZL=Bo95Z~D zv!(QW8^b8B1Qv3@umy+eQQ$%9IFXFdvJ*lgYWJ?%%w=M}Hd?-V|8<+V)kx9C3` zUdUVUXICEUWl$?(OSm;NWA*>M$G0r|vwe!>8+|H{h3aAeLip^9U+3~EJx?Pa+cFReJe z=lM39=VA=Om4D^me$wEWQFl(dGUIyi9mWK+_5atG`ZY6TNtW+jRJ>4{;m@Ss+E=DI zJ8W(J{ULgNt6jtOyh7a*Z4BD|`!l}xsc&Jdxc6+kz5a!N&F_Wlc)!_-oMKS=_9^=R zO8o~63ajSCx9k61$bF!G&i!wX0|i)){+S!!UEH~lD-2Uqj2gfX-5{`_c7Zz>yOu|#@S{b$s*Hws~Jd6v2DbNmDA z1)-{~Yz<4a_D+kFU`}vnG7qnu!+&7&r?#}!@AKE+%UGLdQ+_gFIkQC6qT45K2`=z( z{+b7Ru zP58vw=vJ!79{u9^bXKj~!4Jy$82ECIsBjz0vUZVuJtP zYnojN_gN|#W=bA9HHF<^pU0Jd=Xf@(ooBncb5%*34#VX~3^U@CVou#m*|2fZ_m1C% zNuE1w8Cvu$72`YtO>RW*&lAl*b5v)46~n(Z-H%+i?B&^Z{Y0|Rypnfw7m6L|S>)F# z)Yr?xeq#GZ=VQ}?^N*}#64?H4iqF5kUb})ewHoDApX*-ydQ-BA z!fNMpvzN_1U){`kz}k4fr(Uu9HHLyo^VUt+`aI~}=Y0Zm2M zSvO`%iDobauKdY+$ujzS#lcFcUlSQ8=S^E9DQm&7IDGmYg9#rG7!)iE%Hoj>y)G!h z03Q7M!z8o%gYR{d_SLn)EEbXd;+D7nFFJnk<*bl*F~3i%J8NXrtu=nTK9)go(T1sC z&u!jc7i!Vcr(_;iI_+<`xvNu#W?A;;;y3yCq_`I@zp-}u$-1plKX!ZbReaCyXuA;l zBfoCL_P^vTeQ<1-z5D)00@DuHX7d|)Ib~&s6AC8p+00jV z^Z4I&&71c=u=;sD^w!~jr@j_G2vU9iZ^^B{ZFf=%HrH$}-@2lBe`$CZf6V%hox5j+ z?6|+BI*(;%eflnw)ZafJ?5eMG_mcQ|&;7Ca^m6v&f8KpMD|{kHi1_n=8KbLh* G2~7Y_7|{9v diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/asset_shader_64.png b/src/plugins/qmldesigner/components/itemlibrary/images/asset_shader_64.png deleted file mode 100644 index 16023491cf5620c529404de67655bdedc64b5fae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 905 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4rT@hhPm4t-!L#RY!C1Wab;j&STO{F_2k-Y z1_lP3k|4ie21XWEHZEQf2}yZHO)VW=`+%6(gv6A*g8KH3p593_=FFSFaM_Ag>v!+l zfAH|B^H;Ckx&PqB`;T9~|M>fFTT@FV0|S$*r;B4q#NoBmZ-%{c5ODPuade!paN>j1 z37%~Fiyb7s{ja}X%V8AT#F@J{K)dAaRKL>js}q@YA}e0^J(sKaT=;$MgbpQ&0D|P`?(A`ZX0Sv%)L?DE?Wu<;(PS>dO~S-ui#H&fVDVddZ)s*^ch8 zWSy}?^2fawsuurBSvR~)QITBmcGtSsyK)bBoGLM6Sbe?WLj-d}UDPeco^yAe+cEUs zSo)(~?tqd$EAx^+ObfmjDE<>pm~pAJA;`I5|9`nO^J`3{_tplEVabXUpF9zr3n=W{{+jl|PkLR9#+!3;K+jk2Z^mtl2 zMfmNKXIgxCrVeBGltau@q8OI`{TsB^|Vud_ctjP=E9=?{55hR14T?vy`x{NS02 zXYGPbyZ_7OT&ix^IgNEQyG{Oq&##>&UubAK$S%&ACsmO}qCldiMR8xwmJpuC3lKXRxT>V&i7P<5ed% z$$x&sewJf#-kVP=qziBStKpFQK3Dqq-+(6NTHk^C diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/asset_sound_192.png b/src/plugins/qmldesigner/components/itemlibrary/images/asset_sound_192.png deleted file mode 100644 index 8dd93eb33d587e9b60805073ee68fa89e7c000bb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2928 zcmeAS@N?(olHy`uVBq!ia0y~yU^oE69Lx+145>_WOc@xMo(A}YxH2#>tQZBOAuy~% z;L4Wz5C#T@ZzVx~!3>N{%q*;I>>Qk2+&sK|`~reP!Xlz#;u4Zl(lWC03W`d~DynMg z8k*WVx_bHshDOFFre@|AmR8m_ws!W8PR=f_Ztfml-afv5{sDnO!6Bhx;SrHh(J`@c z@d=4Z$tkI6=^2^XIk|cH1%*Y$C8cHM6_r)hHMMp14UJ9BEv;=Gon75My?y-?CQh0> zb=ve9GiT44J8%Aig^Lz1S-Ncbij}KYuUWfp{f3R3HgDOwZTpU$yLRu{yKn!2gNF_u zIePrW$y2A#oIQ8`!o^FMuUx%${l?8(x9{A&cmKh|M~|O8efIpt%U7@8ynXln!^cmb zzkL1n{m0K=zyJLGm-C3Xf`NhE#nZ(xq~g}wyY(@>;WF$Wig&-8y6DMuACtAqlGd3e zYxL^eT*Rw5+4NcX=fyhR5Br>!9c|f>lWW#;Vpfjo;yA0P^HEUB>$d|`|_RhNQ zv%YHH?>WWqD&JLpvzq_E_Wbj?w=Y-b-Tln4U_-`l|CpWMpKE)qzAK~s{lHds?pKM$ zd0MM?y}eMrcyhkUq5q2{9KKI1PVyHy92Us1VEcFWLdnzs1s!G`nd7Z*PwioMJ*>81 zZukFBEpM_k6xT57u(Q4R{`|V*$wc-Gg&%rWEXn2-Fw|k##WR1a=2DJFNB1<$TYvWU zq%bDWB(;W92h%@(yZm&5%_in6=jt9-p9_6xzV5XD75}Se4VfKYU)%F@)zS5Fb0=>& zbU*a-`3(w@jA8FC&&%1jp-8_t{Dy^l_j0#WtQogzax-@Rbn?lpis{&1`}*J)#n2-X6hsJd<~x{`7d3)Ka@fk#QOFfGmn2HK7;v}rj@s5 z_DqQjTYh#;*zr?n$AJ`eo$uurJ>oAeY3Tde|6z4_+B=@lxrL1rk< ztY@quvi&pP-fYeAHD;7rr@oe3Dkr(gG?o3z)A!feJ$4`1z_w!F41tI5FP%GLpOeBE zlJbt{>)UL`j25E@e!re8E`Gy!G=N#8R^GV#1Cz31*sch#2ANZ5L-~@$a_jh$eq;+n*?KltwYVym|I6+@Veqxzf8j^)r94du z<}V*O`uuh^eK@CN%#d6Ezn>@F;GTw&{etP&=lCAyl2%AN!?EF#@2?-Hxmn5=q%p6M zanrvsr;2-)$|okPy&^k)&7PB$acG9b1ie3(Gag>sl9cf)fc*yVT)~+$z6)I9vTb{xW0S+uBWrS7_K~#y<<>4#rgL4D?ZF}PvkndzP(y36g}DZz~48u z+39^#zN9fEH=N?Gwx9X%qHv;b7{k-&LSg>$*JNvbH#5IWtJ_#~Yr?u4*|Ycqs;a(s zH5@Ekl0AztpeQT+h)a2N!YmucJInYr>?Gy?O^1*-ZjxZ~QHmJHKZm&(wyaxm9Oh>STx3{&f59Tg zZ#&Yb8#8S81hp7K1@*-pO>>FQ=-AOr6F(8qZlNcAd>@$)0Ysg@==wIle`-fh=U!cQKu5`fY z;lcS%l?;D9e#ML0ab|E$;Y{$pu>YcS#qWSd^CI(KsbBQ$5_&&ec|1e;{9@+5gzx_0 z+8xx|_q zu1){=uP_)FFO_*!uN!b`^4xza3@XfTETr}}o}H=oc4m~y`URB@3XhFk)xxFQyyiMz z*uPI)q3im)ZT|xnWyLcbnz)^%LB&Dp^~c%zTWf@}GEWupZ&5!fX!H4i_zb0KyBbs{ z-sWlhQJVO^B1y)#R&ICwG_DO3_TFHSSNqlcbI0HQjThy=9Dfu4_5=q*%t7We=}YaO z<$iNa`_-IYFwgW$x2!dTKRA{)UDmey!!9#N2zc06<_n7 z$*I5P*WTf^@oe-S;oDzlU(TI*;j;K=C#%iz`z^EP=dS&CZKav=nMldE^6pQKY`C#Y&3Kj7#J8lUHx3vIVCg!0JJIfK>z>% diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/asset_sound_256.png b/src/plugins/qmldesigner/components/itemlibrary/images/asset_sound_256.png deleted file mode 100644 index e73588220fffb0dad6d48d25ea18218db907e3a9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3620 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 diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/asset_sound_384.png b/src/plugins/qmldesigner/components/itemlibrary/images/asset_sound_384.png deleted file mode 100644 index 571de696e31adc2fb0d524c03d765fbc9ce20173..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4964 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 diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/x@2x.png b/src/plugins/qmldesigner/components/itemlibrary/images/x@2x.png deleted file mode 100644 index 18fa9a35f786d21f80aa372431cce86f60ea7472..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 383 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANNfZk{fVArY-_ryk60F%WRw zf0yB~YKC_VOlq<7VkPUG9*0beQDj%Q3V@YpImp|Nx+A95(Z5Z79 za#AGPuJ2#*w7A=)WY+Ual||Xwb2`=qy`FNr+|r^!xvKh@Z21t&*xSMyry8J~*c#3~Mde9W(`ptjq0Eqitq1yAr1)}r9tE)&q-}H4l`$w$ z_35qn#ZBq z6Gby-zK!af%3!?z^l7yUPp4OREOY|v6re(tMo!OG7QlC78;ir2*->Q-FDZCoDp n!RX8#!HY|`o}2i8w!G^pfvTSZlY$u-7#KWV{an^LB{Ts5!%m@c diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrary.qrc b/src/plugins/qmldesigner/components/itemlibrary/itemlibrary.qrc index c6d60413d07..eb927c2aa95 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrary.qrc +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrary.qrc @@ -1,39 +1,9 @@ - images/item-default-icon.png images/item-invalid-icon.png + images/item-default-icon.png images/item-default-icon@2x.png images/item-3D_model-icon.png images/item-3D_model-icon@2x.png - images/asset_font_32.png - images/asset_font_48.png - images/asset_font_64.png - images/asset_font_96.png - images/asset_font_128.png - images/asset_font_192.png - images/asset_font_256.png - images/asset_font_384.png - images/asset_shader_32.png - images/asset_shader_48.png - images/asset_shader_64.png - images/asset_shader_96.png - images/asset_shader_128.png - images/asset_shader_192.png - images/asset_shader_256.png - images/asset_shader_384.png - images/asset_sound_32.png - images/asset_sound_48.png - images/asset_sound_64.png - images/asset_sound_96.png - images/asset_sound_128.png - images/asset_sound_192.png - images/asset_sound_256.png - images/asset_sound_384.png - images/x.png - images/x@2x.png - images/browse.png - images/browse@2x.png - images/item-video-icon.png - images/item-video-icon@2x.png diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp index 151be411ad1..6596a10b4a4 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp @@ -105,10 +105,10 @@ WidgetInfo ItemLibraryView::widgetInfo() return createWidgetInfo(m_widget.data(), new WidgetInfo::ToolBarWidgetDefaultFactory(m_widget.data()), - QStringLiteral("Library"), + "Components", WidgetInfo::LeftPane, 0, - tr("Library")); + tr("Components")); } void ItemLibraryView::modelAttached(Model *model) @@ -122,7 +122,6 @@ void ItemLibraryView::modelAttached(Model *model) m_widget->updatePossibleImports(model->possibleImports()); m_hasErrors = !rewriterView()->errors().isEmpty(); m_widget->setFlowMode(QmlItemNode(rootModelNode()).isFlowView()); - setResourcePath(DocumentManager::currentResourcePath().toFileInfo().absoluteFilePath()); } void ItemLibraryView::modelAboutToBeDetached(Model *model) @@ -183,16 +182,6 @@ void ItemLibraryView::usedImportsChanged(const QList &usedImports) m_widget->updateUsedImports(usedImports); } -void ItemLibraryView::setResourcePath(const QString &resourcePath) -{ - if (m_widget.isNull()) - m_widget = new ItemLibraryWidget{m_imageCacheData->cache, - m_imageCacheData->asynchronousFontImageCache, - m_imageCacheData->synchronousFontImageCache}; - - m_widget->setResourcePath(resourcePath); -} - ImageCacheData *ItemLibraryView::imageCacheData() { std::call_once(imageCacheFlag, [this]() { diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.h index 3741df65c39..8d85383d5dc 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.h @@ -59,8 +59,6 @@ public: void customNotification(const AbstractView *view, const QString &identifier, const QList &nodeList, const QList &data) override; - void setResourcePath(const QString &resourcePath); - AsynchronousImageCache &imageCache(); protected: diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp index f71c629a43b..edca09720fd 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp @@ -25,7 +25,6 @@ #include "itemlibrarywidget.h" -#include "itemlibraryassetsmodel.h" #include "itemlibraryiconimageprovider.h" #include "itemlibraryimport.h" @@ -37,7 +36,6 @@ #include #include #include -#include "itemlibraryassetsiconprovider.h" #include "modelnodeoperations.h" #include #include @@ -91,10 +89,8 @@ static QString propertyEditorResourcesPath() bool ItemLibraryWidget::eventFilter(QObject *obj, QEvent *event) { if (event->type() == QEvent::FocusOut) { - if (obj == m_itemViewQuickWidget.data()) - QMetaObject::invokeMethod(m_itemViewQuickWidget->rootObject(), "closeContextMenu"); - else if (obj == m_assetsWidget.data()) - QMetaObject::invokeMethod(m_assetsWidget->rootObject(), "handleViewFocusOut"); + if (obj == m_itemsWidget.data()) + QMetaObject::invokeMethod(m_itemsWidget->rootObject(), "closeContextMenu"); } else if (event->type() == QMouseEvent::MouseMove) { if (m_itemToDrag.isValid()) { QMouseEvent *me = static_cast(event); @@ -134,23 +130,9 @@ bool ItemLibraryWidget::eventFilter(QObject *obj, QEvent *event) m_itemToDrag = {}; } - } else if (!m_assetsToDrag.isEmpty()) { - QMouseEvent *me = static_cast(event); - if ((me->globalPos() - m_dragStartPoint).manhattanLength() > 10) { - 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()); - drag->setMimeData(mimeData); - drag->exec(); - drag->deleteLater(); - - m_assetsToDrag.clear(); - } } } else if (event->type() == QMouseEvent::MouseButtonRelease) { m_itemToDrag = {}; - m_assetsToDrag.clear(); QWidget *view = QmlDesignerPlugin::instance()->viewManager().widget("Navigator"); if (view) { NavigatorWidget *navView = qobject_cast(view); @@ -175,113 +157,47 @@ ItemLibraryWidget::ItemLibraryWidget(AsynchronousImageCache &imageCache, : m_itemIconSize(24, 24) , m_fontImageCache(synchronousFontImageCache) , m_itemLibraryModel(new ItemLibraryModel(this)) - , m_itemLibraryAddImportModel(new ItemLibraryAddImportModel(this)) - , m_assetsIconProvider(new ItemLibraryAssetsIconProvider(synchronousFontImageCache)) - , m_fileSystemWatcher(new Utils::FileSystemWatcher(this)) - , m_assetsModel(new ItemLibraryAssetsModel(synchronousFontImageCache, m_fileSystemWatcher, this)) - , m_headerWidget(new QQuickWidget(this)) - , m_addImportWidget(new QQuickWidget(this)) - , m_itemViewQuickWidget(new QQuickWidget(this)) - , m_assetsWidget(new QQuickWidget(this)) + , m_addModuleModel(new ItemLibraryAddImportModel(this)) + , m_itemsWidget(new QQuickWidget(this)) , m_imageCache{imageCache} { m_compressionTimer.setInterval(200); m_compressionTimer.setSingleShot(true); - m_assetCompressionTimer.setInterval(200); - m_assetCompressionTimer.setSingleShot(true); ItemLibraryModel::registerQmlTypes(); - setWindowTitle(tr("Library", "Title of library view")); + setWindowTitle(tr("Components Library", "Title of library view")); setMinimumWidth(100); - // create header widget - m_headerWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); - m_headerWidget->setMinimumHeight(75); - m_headerWidget->setMinimumWidth(100); - Theme::setupTheme(m_headerWidget->engine()); - m_headerWidget->engine()->addImportPath(propertyEditorResourcesPath() + "/imports"); - m_headerWidget->setClearColor(Theme::getColor(Theme::Color::DSpanelBackground)); - m_headerWidget->rootContext()->setContextProperty("rootView", QVariant::fromValue(this)); + // set up Component Library view and model + m_itemsWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); + m_itemsWidget->engine()->addImportPath(propertyEditorResourcesPath() + "/imports"); - // create add imports widget - m_addImportWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); - Theme::setupTheme(m_addImportWidget->engine()); - m_addImportWidget->engine()->addImportPath(propertyEditorResourcesPath() + "/imports"); - m_addImportWidget->setClearColor(Theme::getColor(Theme::Color::DSpanelBackground)); - m_addImportWidget->rootContext()->setContextProperties({ - {"addImportModel", QVariant::fromValue(m_itemLibraryAddImportModel.data())}, + m_itemsWidget->rootContext()->setContextProperties({ + {"itemLibraryModel", QVariant::fromValue(m_itemLibraryModel.data())}, + {"addModuleModel", QVariant::fromValue(m_addModuleModel.data())}, + {"itemLibraryIconWidth", m_itemIconSize.width()}, + {"itemLibraryIconHeight", m_itemIconSize.height()}, {"rootView", QVariant::fromValue(this)}, - }); - - // set up Item Library view and model - m_itemViewQuickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); - m_itemViewQuickWidget->engine()->addImportPath(propertyEditorResourcesPath() + "/imports"); - - m_itemViewQuickWidget->rootContext()->setContextProperties(QVector{ - {{"itemLibraryModel"}, QVariant::fromValue(m_itemLibraryModel.data())}, - {{"itemLibraryIconWidth"}, m_itemIconSize.width()}, - {{"itemLibraryIconHeight"}, m_itemIconSize.height()}, - {{"rootView"}, QVariant::fromValue(this)}, - {{"widthLimit"}, HORIZONTAL_LAYOUT_WIDTH_LIMIT}, - {{"highlightColor"}, Utils::StyleHelper::notTooBrightHighlightColor()}, + {"widthLimit", HORIZONTAL_LAYOUT_WIDTH_LIMIT}, + {"highlightColor", Utils::StyleHelper::notTooBrightHighlightColor()}, }); m_previewTooltipBackend = std::make_unique(m_imageCache); - m_itemViewQuickWidget->rootContext()->setContextProperty("tooltipBackend", - m_previewTooltipBackend.get()); + m_itemsWidget->rootContext()->setContextProperty("tooltipBackend", m_previewTooltipBackend.get()); - m_itemViewQuickWidget->setClearColor(Theme::getColor(Theme::Color::DSpanelBackground)); - m_itemViewQuickWidget->engine()->addImageProvider(QStringLiteral("qmldesigner_itemlibrary"), + m_itemsWidget->setClearColor(Theme::getColor(Theme::Color::DSpanelBackground)); + m_itemsWidget->engine()->addImageProvider(QStringLiteral("qmldesigner_itemlibrary"), new Internal::ItemLibraryImageProvider); - Theme::setupTheme(m_itemViewQuickWidget->engine()); - m_itemViewQuickWidget->installEventFilter(this); - m_assetsWidget->installEventFilter(this); - - m_fontPreviewTooltipBackend = std::make_unique(asynchronousFontImageCache); - // Note: Though the text specified here appears in UI, it shouldn't be translated, as it's - // a commonly used sentence to preview the font glyphs in latin fonts. - // For fonts that do not have latin glyphs, the font family name will have to suffice for preview. - m_fontPreviewTooltipBackend->setAuxiliaryData( - ImageCache::FontCollectorSizeAuxiliaryData{QSize{300, 300}, - Theme::getColor(Theme::DStextColor).name(), - QStringLiteral("The quick brown fox jumps\n" - "over the lazy dog\n" - "1234567890")}); - // create assets widget - m_assetsWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); - Theme::setupTheme(m_assetsWidget->engine()); - m_assetsWidget->engine()->addImportPath(propertyEditorResourcesPath() + "/imports"); - m_assetsWidget->setClearColor(Theme::getColor(Theme::Color::QmlDesigner_BackgroundColorDarkAlternate)); - m_assetsWidget->engine()->addImageProvider("qmldesigner_assets", m_assetsIconProvider); - m_assetsWidget->rootContext()->setContextProperties(QVector{ - {{"assetsModel"}, QVariant::fromValue(m_assetsModel.data())}, - {{"rootView"}, QVariant::fromValue(this)}, - {{"tooltipBackend"}, QVariant::fromValue(m_fontPreviewTooltipBackend.get())} - }); - - // If project directory contents change, or one of the asset files is modified, we must - // reconstruct the model to update the icons - connect(m_fileSystemWatcher, &Utils::FileSystemWatcher::directoryChanged, [this](const QString & changedDirPath) { - Q_UNUSED(changedDirPath) - m_assetCompressionTimer.start(); - }); - - m_stackedWidget = new QStackedWidget(this); - m_stackedWidget->addWidget(m_itemViewQuickWidget.data()); - m_stackedWidget->addWidget(m_assetsWidget.data()); - m_stackedWidget->addWidget(m_addImportWidget.data()); - m_stackedWidget->setMinimumHeight(30); - m_stackedWidget->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); + Theme::setupTheme(m_itemsWidget->engine()); + m_itemsWidget->installEventFilter(this); auto layout = new QVBoxLayout(this); layout->setContentsMargins({}); layout->setSpacing(0); - layout->addWidget(m_headerWidget.data()); - layout->addWidget(m_stackedWidget.data()); + layout->addWidget(m_itemsWidget.data()); updateSearch(); - /* style sheets */ setStyleSheet(Theme::replaceCssColors( QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/stylesheet.css")))); @@ -289,28 +205,8 @@ ItemLibraryWidget::ItemLibraryWidget(AsynchronousImageCache &imageCache, connect(m_qmlSourceUpdateShortcut, &QShortcut::activated, this, &ItemLibraryWidget::reloadQmlSource); connect(&m_compressionTimer, &QTimer::timeout, this, &ItemLibraryWidget::updateModel); - connect(&m_assetCompressionTimer, &QTimer::timeout, this, [this]() { - // TODO: find a clever way to only refresh the changed directory part of the model - // Don't bother with asset updates after model has detached, project is probably closing - if (!m_model.isNull()) { - if (QApplication::activeModalWidget()) { - // Retry later, as updating file system watchers can crash when there is an active - // modal widget - m_assetCompressionTimer.start(); - } else { - m_assetsModel->refresh(); - // reload assets qml so that an overridden file's image shows the new image - QTimer::singleShot(100, this, [this] { - const QString assetsQmlPath = qmlSourcesPath() + "/Assets.qml"; - m_assetsWidget->engine()->clearComponentCache(); - m_assetsWidget->setSource(QUrl::fromLocalFile(assetsQmlPath)); - }); - } - } - }); - - m_itemViewQuickWidget->engine()->addImageProvider("itemlibrary_preview", + m_itemsWidget->engine()->addImageProvider("itemlibrary_preview", new ItemLibraryIconImageProvider{m_imageCache}); // init the first load of the QML UI elements @@ -336,42 +232,28 @@ void ItemLibraryWidget::setItemLibraryInfo(ItemLibraryInfo *itemLibraryInfo) this, &ItemLibraryWidget::delayedUpdateModel); connect(m_itemLibraryInfo.data(), &ItemLibraryInfo::priorityImportsChanged, this, &ItemLibraryWidget::handlePriorityImportsChanged); - m_itemLibraryAddImportModel->setPriorityImports(m_itemLibraryInfo->priorityImports()); + m_addModuleModel->setPriorityImports(m_itemLibraryInfo->priorityImports()); } delayedUpdateModel(); } QList ItemLibraryWidget::createToolBarWidgets() { -// TODO: implement - QList buttons; - return buttons; + return {}; } + void ItemLibraryWidget::handleSearchfilterChanged(const QString &filterText) { if (filterText != m_filterText) { m_filterText = filterText; - emit searchActiveChanged(); + updateSearch(); } - - updateSearch(); -} - -void ItemLibraryWidget::handleAddModule() -{ - QMetaObject::invokeMethod(m_headerWidget->rootObject(), "setTab", Q_ARG(QVariant, 0)); - handleTabChanged(2); -} - -void ItemLibraryWidget::handleAddAsset() -{ - addResources({}); } void ItemLibraryWidget::handleAddImport(int index) { - Import import = m_itemLibraryAddImportModel->getImportAt(index); + Import import = m_addModuleModel->getImportAt(index); if (import.isLibraryImport() && (import.url().startsWith("QtQuick") || import.url().startsWith("SimulinkConnector"))) { QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_IMPORT_ADDED @@ -381,27 +263,10 @@ void ItemLibraryWidget::handleAddImport(int index) auto document = QmlDesignerPlugin::instance()->currentDesignDocument(); document->documentModel()->changeImports({import}, {}); - m_stackedWidget->setCurrentIndex(0); // switch to the Components view after import is added + QMetaObject::invokeMethod(m_itemsWidget->rootObject(), "switchToComponentsView"); updateSearch(); } -void ItemLibraryWidget::handleFilesDrop(const QStringList &filesPaths) -{ - addResources(filesPaths); -} - -QSet ItemLibraryWidget::supportedDropSuffixes() -{ - const QList handlers = QmlDesignerPlugin::instance()->viewManager() - .designerActionManager().addResourceHandler(); - - QSet suffixes; - for (const AddResourceHandler &handler : handlers) - suffixes.insert(handler.filter); - - return suffixes; -} - void ItemLibraryWidget::delayedUpdateModel() { static bool disableTimer = DesignerSettings::getValue(DesignerSettingsKey::DISABLE_ITEM_LIBRARY_UPDATE_TIMER).toBool(); @@ -423,20 +288,14 @@ void ItemLibraryWidget::setModel(Model *model) const bool subCompEditMode = document->inFileComponentModelActive(); if (m_subCompEditMode != subCompEditMode) { m_subCompEditMode = subCompEditMode; - // Switch out of module add panel if it's active - if (m_subCompEditMode && m_stackedWidget->currentIndex() == 2) - m_stackedWidget->setCurrentIndex(0); + // Switch out of add module view if it's active + if (m_subCompEditMode) + QMetaObject::invokeMethod(m_itemsWidget->rootObject(), "switchToComponentsView"); emit subCompEditModeChanged(); } } } -void ItemLibraryWidget::handleTabChanged(int index) -{ - m_stackedWidget->setCurrentIndex(index); - updateSearch(); -} - QString ItemLibraryWidget::qmlSourcesPath() { #ifdef SHARE_QML_PATH @@ -448,30 +307,15 @@ QString ItemLibraryWidget::qmlSourcesPath() void ItemLibraryWidget::clearSearchFilter() { - QMetaObject::invokeMethod(m_headerWidget->rootObject(), "clearSearchFilter"); + QMetaObject::invokeMethod(m_itemsWidget->rootObject(), "clearSearchFilter"); } void ItemLibraryWidget::reloadQmlSource() { - const QString libraryHeaderQmlPath = qmlSourcesPath() + "/LibraryHeader.qml"; - QTC_ASSERT(QFileInfo::exists(libraryHeaderQmlPath), return); - m_headerWidget->engine()->clearComponentCache(); - m_headerWidget->setSource(QUrl::fromLocalFile(libraryHeaderQmlPath)); - - const QString addImportQmlPath = qmlSourcesPath() + "/AddImport.qml"; - QTC_ASSERT(QFileInfo::exists(addImportQmlPath), return); - m_addImportWidget->engine()->clearComponentCache(); - m_addImportWidget->setSource(QUrl::fromLocalFile(addImportQmlPath)); - const QString itemLibraryQmlPath = qmlSourcesPath() + "/ItemsView.qml"; QTC_ASSERT(QFileInfo::exists(itemLibraryQmlPath), return); - m_itemViewQuickWidget->engine()->clearComponentCache(); - m_itemViewQuickWidget->setSource(QUrl::fromLocalFile(itemLibraryQmlPath)); - - const QString assetsQmlPath = qmlSourcesPath() + "/Assets.qml"; - QTC_ASSERT(QFileInfo::exists(assetsQmlPath), return); - m_assetsWidget->engine()->clearComponentCache(); - m_assetsWidget->setSource(QUrl::fromLocalFile(assetsQmlPath)); + m_itemsWidget->engine()->clearComponentCache(); + m_itemsWidget->setSource(QUrl::fromLocalFile(itemLibraryQmlPath)); } void ItemLibraryWidget::updateModel() @@ -496,7 +340,7 @@ void ItemLibraryWidget::updateModel() void ItemLibraryWidget::updatePossibleImports(const QList &possibleImports) { - m_itemLibraryAddImportModel->update(possibleImports); + m_addModuleModel->update(possibleImports); delayedUpdateModel(); } @@ -507,30 +351,19 @@ void ItemLibraryWidget::updateUsedImports(const QList &usedImports) void ItemLibraryWidget::updateSearch() { - if (m_stackedWidget->currentIndex() == 0) { // Item Library tab selected - m_itemLibraryModel->setSearchText(m_filterText); - m_itemViewQuickWidget->update(); - } else if (m_stackedWidget->currentIndex() == 1) { // Assets tab selected - m_assetsModel->setSearchText(m_filterText); - } else if (m_stackedWidget->currentIndex() == 2) { // QML imports tab selected - m_itemLibraryAddImportModel->setSearchText(m_filterText); - } + m_itemLibraryModel->setSearchText(m_filterText); + m_itemsWidget->update(); + m_addModuleModel->setSearchText(m_filterText); } void ItemLibraryWidget::handlePriorityImportsChanged() { if (!m_itemLibraryInfo.isNull()) { - m_itemLibraryAddImportModel->setPriorityImports(m_itemLibraryInfo->priorityImports()); - m_itemLibraryAddImportModel->update(m_model->possibleImports()); + m_addModuleModel->setPriorityImports(m_itemLibraryInfo->priorityImports()); + m_addModuleModel->update(m_model->possibleImports()); } } -void ItemLibraryWidget::setResourcePath(const QString &resourcePath) -{ - m_assetsModel->setRootPath(resourcePath); - updateSearch(); -} - void ItemLibraryWidget::startDragAndDrop(const QVariant &itemLibEntry, const QPointF &mousePos) { // Actual drag is created after mouse has moved to avoid a QDrag bug that causes drag to stay @@ -539,54 +372,11 @@ void ItemLibraryWidget::startDragAndDrop(const QVariant &itemLibEntry, const QPo m_dragStartPoint = mousePos.toPoint(); } -void ItemLibraryWidget::startDragAsset(const QStringList &assetPaths, const QPointF &mousePos) -{ - // Actual drag is created after mouse has moved to avoid a QDrag bug that causes drag to stay - // active (and blocks mouse release) if mouse is released at the same spot of the drag start. - m_assetsToDrag = assetPaths; - m_dragStartPoint = mousePos.toPoint(); -} - -QPair ItemLibraryWidget::getAssetTypeAndData(const QString &assetPath) -{ - QString suffix = "*." + assetPath.split('.').last().toLower(); - if (!suffix.isEmpty()) { - if (ItemLibraryAssetsModel::supportedImageSuffixes().contains(suffix)) { - // Data: Image format (suffix) - return {"application/vnd.bauhaus.libraryresource.image", suffix.toUtf8()}; - } else if (ItemLibraryAssetsModel::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()}; - } else if (ItemLibraryAssetsModel::supportedShaderSuffixes().contains(suffix)) { - // Data: shader type, frament (f) or vertex (v) - return {"application/vnd.bauhaus.libraryresource.shader", - ItemLibraryAssetsModel::supportedFragmentShaderSuffixes().contains(suffix) ? "f" : "v"}; - } else if (ItemLibraryAssetsModel::supportedAudioSuffixes().contains(suffix)) { - // No extra data for sounds - return {"application/vnd.bauhaus.libraryresource.sound", {}}; - } else if (ItemLibraryAssetsModel::supportedVideoSuffixes().contains(suffix)) { - // No extra data for videos - return {"application/vnd.bauhaus.libraryresource.video", {}}; - } else if (ItemLibraryAssetsModel::supportedTexture3DSuffixes().contains(suffix)) { - // Data: Image format (suffix) - return {"application/vnd.bauhaus.libraryresource.texture3d", suffix.toUtf8()}; - } - } - return {}; -} - bool ItemLibraryWidget::subCompEditMode() const { return m_subCompEditMode; } -bool ItemLibraryWidget::searchActive() const -{ - return !m_filterText.isEmpty(); -} - void ItemLibraryWidget::setFlowMode(bool b) { m_itemLibraryModel->setFlowMode(b); @@ -608,111 +398,8 @@ void ItemLibraryWidget::addImportForItem(const QString &importUrl) QTC_ASSERT(m_itemLibraryModel, return); QTC_ASSERT(m_model, return); - Import import = m_itemLibraryAddImportModel->getImport(importUrl); + Import import = m_addModuleModel->getImport(importUrl); m_model->changeImports({import}, {}); } -static QHash allImageFormats() -{ - const QList mimeTypes = QImageReader::supportedMimeTypes(); - auto transformer = [](const QByteArray& format) -> QString { return QString("*.") + format; }; - QHash imageFormats; - for (const auto &mimeType : mimeTypes) - imageFormats.insert(mimeType, Utils::transform(QImageReader::imageFormatsForMimeType(mimeType), transformer)); - imageFormats.insert("image/vnd.radiance", {"*.hdr"}); - imageFormats.insert("image/ktx", {"*.ktx"}); - - return imageFormats; -} - -void ItemLibraryWidget::addResources(const QStringList &files) -{ - DesignDocument *document = QmlDesignerPlugin::instance()->currentDesignDocument(); - - QTC_ASSERT(document, return); - - const QList handlers = QmlDesignerPlugin::instance()->viewManager() - .designerActionManager().addResourceHandler(); - - QStringList fileNames = files; - if (fileNames.isEmpty()) { // if no files, show the "add assets" dialog - QMultiMap map; - QHash priorities; - for (const AddResourceHandler &handler : handlers) { - map.insert(handler.category, handler.filter); - priorities.insert(handler.category, handler.piority); - } - - QStringList sortedKeys = map.uniqueKeys(); - Utils::sort(sortedKeys, [&priorities](const QString &first, const QString &second) { - return priorities.value(first) < priorities.value(second); - }); - - QStringList filters { tr("All Files (%1)").arg("*.*") }; - QString filterTemplate = "%1 (%2)"; - for (const QString &key : qAsConst(sortedKeys)) { - const QStringList values = map.values(key); - if (values.contains("*.png")) { // Avoid long filter for images by splitting - const QHash imageFormats = allImageFormats(); - QHash::const_iterator i = imageFormats.constBegin(); - while (i != imageFormats.constEnd()) { - filters.append(filterTemplate.arg(key + QString::fromLatin1(i.key()), i.value().join(' '))); - ++i; - } - } else { - filters.append(filterTemplate.arg(key, values.join(' '))); - } - } - - static QString lastDir; - const QString currentDir = lastDir.isEmpty() ? document->fileName().parentDir().toString() : lastDir; - - fileNames = QFileDialog::getOpenFileNames(Core::ICore::dialogParent(), - tr("Add Assets"), - currentDir, - filters.join(";;")); - - if (!fileNames.isEmpty()) { - lastDir = QFileInfo(fileNames.first()).absolutePath(); - // switch to assets view after an asset is added - m_stackedWidget->setCurrentIndex(1); - QMetaObject::invokeMethod(m_headerWidget->rootObject(), "setTab", Q_ARG(QVariant, 1)); - } - } - - QHash filterToCategory; - QHash categoryToOperation; - for (const AddResourceHandler &handler : handlers) { - filterToCategory.insert(handler.filter, handler.category); - categoryToOperation.insert(handler.category, handler.operation); - } - - QMultiMap categoryFileNames; // filenames grouped by category - - for (const QString &fileName : qAsConst(fileNames)) { - const QString suffix = "*." + QFileInfo(fileName).suffix().toLower(); - const QString category = filterToCategory.value(suffix); - categoryFileNames.insert(category, fileName); - } - - for (const QString &category : categoryFileNames.uniqueKeys()) { - QStringList fileNames = categoryFileNames.values(category); - AddResourceOperation operation = categoryToOperation.value(category); - QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_RESOURCE_IMPORTED + category); - if (operation) { - AddFilesResult result = operation(fileNames, - document->fileName().parentDir().toString()); - if (result == AddFilesResult::Failed) { - Core::AsynchronousMessageBox::warning(tr("Failed to Add Files"), - tr("Could not add %1 to project.") - .arg(fileNames.join(' '))); - } - } else { - Core::AsynchronousMessageBox::warning(tr("Failed to Add Files"), - tr("Could not add %1 to project. Unsupported file format.") - .arg(fileNames.join(' '))); - } - } -} - } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h index d67c3df71db..85b95ce23f4 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h @@ -31,7 +31,6 @@ #include #include #include -#include "itemlibraryassetsmodel.h" #include #include @@ -48,18 +47,13 @@ class QStackedWidget; class QShortcut; QT_END_NAMESPACE -namespace Utils { class FileSystemWatcher; } - namespace QmlDesigner { class MetaInfo; class ItemLibraryEntry; class Model; -class CustomFileSystemModel; class ItemLibraryModel; -class ItemLibraryAssetsIconProvider; -class ItemLibraryAssetsModel; class ItemLibraryAddImportModel; class ItemLibraryResourceView; class SynchronousImageCache; @@ -72,7 +66,6 @@ class ItemLibraryWidget : public QFrame public: Q_PROPERTY(bool subCompEditMode READ subCompEditMode NOTIFY subCompEditModeChanged) - Q_PROPERTY(bool searchActive READ searchActive NOTIFY searchActiveChanged) ItemLibraryWidget(AsynchronousImageCache &imageCache, AsynchronousImageCache &asynchronousFontImageCache, @@ -90,32 +83,22 @@ public: void updatePossibleImports(const QList &possibleImports); void updateUsedImports(const QList &usedImports); - void setResourcePath(const QString &resourcePath); void setModel(Model *model); void setFlowMode(bool b); - static QPair getAssetTypeAndData(const QString &assetPath); inline static bool isHorizontalLayout = false; bool subCompEditMode() const; - bool searchActive() const; Q_INVOKABLE void startDragAndDrop(const QVariant &itemLibEntry, const QPointF &mousePos); - Q_INVOKABLE void startDragAsset(const QStringList &assetPaths, const QPointF &mousePos); Q_INVOKABLE void removeImport(const QString &importUrl); Q_INVOKABLE void addImportForItem(const QString &importUrl); - Q_INVOKABLE void handleTabChanged(int index); - Q_INVOKABLE void handleAddModule(); - Q_INVOKABLE void handleAddAsset(); Q_INVOKABLE void handleSearchfilterChanged(const QString &filterText); Q_INVOKABLE void handleAddImport(int index); - Q_INVOKABLE void handleFilesDrop(const QStringList &filesPaths); - Q_INVOKABLE QSet supportedDropSuffixes(); signals: void itemActivated(const QString &itemName); void subCompEditModeChanged(); - void searchActiveChanged(); protected: bool eventFilter(QObject *obj, QEvent *event) override; @@ -124,38 +107,25 @@ protected: private: void reloadQmlSource(); - void addResources(const QStringList &files); void updateSearch(); void handlePriorityImportsChanged(); QTimer m_compressionTimer; - QTimer m_assetCompressionTimer; QSize m_itemIconSize; SynchronousImageCache &m_fontImageCache; QPointer m_itemLibraryInfo; QPointer m_itemLibraryModel; - QPointer m_itemLibraryAddImportModel; - ItemLibraryAssetsIconProvider *m_assetsIconProvider = nullptr; - Utils::FileSystemWatcher *m_fileSystemWatcher = nullptr; - QPointer m_assetsModel; + QPointer m_addModuleModel; - QPointer m_stackedWidget; - - QScopedPointer m_headerWidget; - QScopedPointer m_addImportWidget; - QScopedPointer m_itemViewQuickWidget; - QScopedPointer m_assetsWidget; + QScopedPointer m_itemsWidget; std::unique_ptr m_previewTooltipBackend; - std::unique_ptr m_fontPreviewTooltipBackend; QShortcut *m_qmlSourceUpdateShortcut; AsynchronousImageCache &m_imageCache; QPointer m_model; QVariant m_itemToDrag; - QStringList m_assetsToDrag; - QPair m_assetToDragTypeAndData; bool m_updateRetry = false; QString m_filterText; QPoint m_dragStartPoint; diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp index 8a8547a84a4..5e22fcec425 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp @@ -28,7 +28,7 @@ #include "navigatorwidget.h" #include "choosefrompropertylistdialog.h" #include "qmldesignerplugin.h" -#include "itemlibrarywidget.h" +#include "assetslibrarywidget.h" #include #include @@ -568,7 +568,7 @@ bool NavigatorTreeModel::dropMimeData(const QMimeData *mimeData, if (document && !document->inFileComponentModelActive()) { QSet neededImports; for (const QString &assetPath : assetsPaths) { - QString assetType = ItemLibraryWidget::getAssetTypeAndData(assetPath).first; + QString assetType = AssetsLibraryWidget::getAssetTypeAndData(assetPath).first; if (assetType == "application/vnd.bauhaus.libraryresource.shader") neededImports.insert("QtQuick3D"); else if (assetType == "application/vnd.bauhaus.libraryresource.sound") @@ -584,7 +584,7 @@ bool NavigatorTreeModel::dropMimeData(const QMimeData *mimeData, m_view->executeInTransaction("NavigatorTreeModel::dropMimeData", [&] { for (const QString &assetPath : assetsPaths) { - auto assetTypeAndData = ItemLibraryWidget::getAssetTypeAndData(assetPath); + auto assetTypeAndData = AssetsLibraryWidget::getAssetTypeAndData(assetPath); QString assetType = assetTypeAndData.first; QString assetData = QString::fromUtf8(assetTypeAndData.second); if (assetType == "application/vnd.bauhaus.libraryresource.image") diff --git a/src/plugins/qmldesigner/designercore/include/viewmanager.h b/src/plugins/qmldesigner/designercore/include/viewmanager.h index ecfec36860b..04f25b84f81 100644 --- a/src/plugins/qmldesigner/designercore/include/viewmanager.h +++ b/src/plugins/qmldesigner/designercore/include/viewmanager.h @@ -64,7 +64,6 @@ public: void attachViewsExceptRewriterAndComponetView(); void detachViewsExceptRewriterAndComponetView(); - void setItemLibraryViewResourcePath(const QString &resourcePath); void setComponentNode(const ModelNode &componentNode); void setComponentViewToMaster(); void setNodeInstanceViewTarget(ProjectExplorer::Target *target); @@ -116,7 +115,6 @@ private: // functions void addView(std::unique_ptr &&view); void attachNodeInstanceView(); - void attachItemLibraryView(); void attachAdditionalViews(); void detachAdditionalViews(); void detachStandardViews(); diff --git a/src/plugins/qmldesigner/designercore/model/viewmanager.cpp b/src/plugins/qmldesigner/designercore/model/viewmanager.cpp index 127925df1b3..a2565d0c415 100644 --- a/src/plugins/qmldesigner/designercore/model/viewmanager.cpp +++ b/src/plugins/qmldesigner/designercore/model/viewmanager.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -71,6 +72,7 @@ public: Edit3DView edit3DView; FormEditorView formEditorView; TextEditorView textEditorView; + AssetsLibraryView assetsLibraryView; ItemLibraryView itemLibraryView; NavigatorView navigatorView; PropertyEditorView propertyEditorView; @@ -177,6 +179,7 @@ QList ViewManager::standardViews() const QList list = {&d->edit3DView, &d->formEditorView, &d->textEditorView, + &d->assetsLibraryView, &d->itemLibraryView, &d->navigatorView, &d->propertyEditorView, @@ -210,11 +213,6 @@ void ViewManager::detachViewsExceptRewriterAndComponetView() currentModel()->setNodeInstanceView(nullptr); } -void ViewManager::attachItemLibraryView() -{ - currentModel()->attachView(&d->itemLibraryView); -} - void ViewManager::attachAdditionalViews() { for (auto &view : d->additionalViews) @@ -292,11 +290,6 @@ void ViewManager::attachViewsExceptRewriterAndComponetView() switchStateEditorViewToSavedState(); } -void ViewManager::setItemLibraryViewResourcePath(const QString &resourcePath) -{ - d->itemLibraryView.setResourcePath(resourcePath); -} - void ViewManager::setComponentNode(const ModelNode &componentNode) { d->componentView.setComponentNode(componentNode); @@ -319,6 +312,7 @@ QList ViewManager::widgetInfos() const widgetInfoList.append(d->edit3DView.widgetInfo()); widgetInfoList.append(d->formEditorView.widgetInfo()); widgetInfoList.append(d->textEditorView.widgetInfo()); + widgetInfoList.append(d->assetsLibraryView.widgetInfo()); widgetInfoList.append(d->itemLibraryView.widgetInfo()); widgetInfoList.append(d->navigatorView.widgetInfo()); widgetInfoList.append(d->propertyEditorView.widgetInfo()); diff --git a/src/plugins/qmldesigner/qmldesignerplugin.qbs b/src/plugins/qmldesigner/qmldesignerplugin.qbs index e8bd9e68a04..a3f5649680c 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.qbs +++ b/src/plugins/qmldesigner/qmldesignerplugin.qbs @@ -45,6 +45,7 @@ Project { "../../../share/qtcreator/qml/qmlpuppet/types", "components", "components/annotationeditor", + "components/assetslibrary", "components/componentcore", "components/curveeditor", "components/connectioneditor", @@ -449,6 +450,21 @@ Project { Group { prefix: "components/" files: [ + "assetslibrary/assetslibrary.qrc", + "assetslibrary/assetslibraryview.cpp", + "assetslibrary/assetslibraryview.h", + "assetslibrary/assetslibrarywidget.cpp", + "assetslibrary/assetslibrarywidget.h", + "assetslibrary/assetslibrarymodel.cpp", + "assetslibrary/assetslibrarymodel.h", + "assetslibrary/assetslibraryiconprovider.cpp", + "assetslibrary/assetslibraryiconprovider.h", + "assetslibrary/assetslibrarydir.cpp", + "assetslibrary/assetslibrarydir.h", + "assetslibrary/assetslibrarydirsmodel.cpp", + "assetslibrary/assetslibrarydirsmodel.h", + "assetslibrary/assetslibraryfilesmodel.cpp", + "assetslibrary/assetslibraryfilesmodel.h", "componentcore/addimagesdialog.cpp", "componentcore/addimagesdialog.h", "componentcore/abstractaction.cpp", @@ -472,7 +488,7 @@ Project { "componentcore/formatoperation.h", "componentcore/layoutingridlayout.cpp", "componentcore/layoutingridlayout.h", - "componentcore/theme.cpp", + "componentcore/theme.cpp", "componentcore/theme.h", "componentcore/modelnodecontextmenu.cpp", "componentcore/modelnodecontextmenu.h", @@ -639,16 +655,6 @@ Project { "itemlibrary/itemlibraryassetimportdialog.ui", "itemlibrary/itemlibraryassetimporter.cpp", "itemlibrary/itemlibraryassetimporter.h", - "itemlibrary/itemlibraryassetsdir.cpp", - "itemlibrary/itemlibraryassetsdir.h", - "itemlibrary/itemlibraryassetsdirsmodel.cpp", - "itemlibrary/itemlibraryassetsdirsmodel.h", - "itemlibrary/itemlibraryassetsfilesmodel.cpp", - "itemlibrary/itemlibraryassetsfilesmodel.h", - "itemlibrary/itemlibraryassetsiconprovider.cpp", - "itemlibrary/itemlibraryassetsiconprovider.h", - "itemlibrary/itemlibraryassetsmodel.cpp", - "itemlibrary/itemlibraryassetsmodel.h", "itemlibrary/itemlibrarycategoriesmodel.cpp", "itemlibrary/itemlibrarycategoriesmodel.h", "itemlibrary/itemlibrarycategory.cpp", From 2962da2255a1c0528e9b0d55d2cc8bf192991f52 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 21 Jan 2022 08:23:13 +0100 Subject: [PATCH 30/94] CMake: Prevent crash if kit has no toolchain Amends beb167a963. (cherry picked from commit b3375cfd560b7fb9449ac127cc0aeb6530a3dd1d) Fixes: QTCREATORBUG-26777 Change-Id: I65feee771a21bdfbb2a102419a0d778af97a22eb Reviewed-by: Christiaan Janssen Reviewed-by: Eike Ziller --- src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index 6f74bc9126e..c34c6660570 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -807,7 +807,9 @@ static bool isDocker(const Kit *k) static bool isWindowsARM64(const Kit *k) { - const auto targetAbi = ToolChainKitAspect::cxxToolChain(k)->targetAbi(); + ToolChain *toolchain = ToolChainKitAspect::cxxToolChain(k); + QTC_ASSERT(toolchain, return false); + const Abi targetAbi = toolchain->targetAbi(); return targetAbi.os() == Abi::WindowsOS && targetAbi.architecture() == Abi::ArmArchitecture && targetAbi.wordWidth() == 64; } From 9e1c2232a4988ba32aa6974c56d278f6e4fb5aa8 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Tue, 8 Feb 2022 19:09:26 +0100 Subject: [PATCH 31/94] QmlDesigner: Remove Studio3D item from metainfo Change-Id: I682e655e4369bb4d59a8a7b2c74be2427dbf14a0 Reviewed-by: Thomas Hartmann --- .../qmldesigner/studioplugin/studioplugin.metainfo | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/plugins/qmldesigner/studioplugin/studioplugin.metainfo b/src/plugins/qmldesigner/studioplugin/studioplugin.metainfo index 5468269e83c..aca27866ac4 100644 --- a/src/plugins/qmldesigner/studioplugin/studioplugin.metainfo +++ b/src/plugins/qmldesigner/studioplugin/studioplugin.metainfo @@ -1,18 +1,4 @@ MetaInfo { - Type { - name: "QtStudio3D.Studio3D" - icon: ":/qtquickplugin/images/item-icon16.png" - - ItemLibraryEntry { - name: "Studio 3D" - category: "Qt 3D Studio" - libraryIcon: ":/qtquickplugin/images/item-icon.png" - version: "2.0" - requiredImport: "QtStudio3D" - - QmlSource { source: ":/studioplugin/data/qt3ditem.qml" } - } - } Imports { blacklistImports: [ From 46e2683f0df51fdd16fefe624f54e23481a508bc Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Tue, 8 Feb 2022 16:47:08 +0100 Subject: [PATCH 32/94] QmlDesigner: Collect usage statistics for contex help Change-Id: Ie1a1250abc6e55c13d71d8545a50d539f4360392 Reviewed-by: Qt CI Bot Reviewed-by: Thomas Hartmann --- .../qmldesigner/designercore/model/abstractview.cpp | 8 ++++++++ src/plugins/qmldesigner/qmldesignerconstants.h | 1 + src/plugins/qmldesigner/qmldesignerplugin.cpp | 5 +++++ src/plugins/qmldesigner/qmldesignerplugin.h | 1 + 4 files changed, 15 insertions(+) diff --git a/src/plugins/qmldesigner/designercore/model/abstractview.cpp b/src/plugins/qmldesigner/designercore/model/abstractview.cpp index 6ef3c6d5d61..78014142e3b 100644 --- a/src/plugins/qmldesigner/designercore/model/abstractview.cpp +++ b/src/plugins/qmldesigner/designercore/model/abstractview.cpp @@ -633,7 +633,15 @@ void AbstractView::enableWidget() void AbstractView::contextHelp(const Core::IContext::HelpCallback &callback) const { #ifndef QMLDESIGNER_TEST + + const QString id = const_cast(this)->widgetInfo().uniqueId; + + QString nodeId; + if (!selectedModelNodes().isEmpty()) + nodeId = selectedModelNodes().first().simplifiedTypeName(); + QmlDesignerPlugin::instance()->emitUsageStatisticsHelpRequested(id + " " + nodeId); QmlDesignerPlugin::instance()->viewManager().qmlJSEditorContextHelp(callback); + #else callback(QString()); #endif diff --git a/src/plugins/qmldesigner/qmldesignerconstants.h b/src/plugins/qmldesigner/qmldesignerconstants.h index 3830c9e8da8..1bfdbb8ddbf 100644 --- a/src/plugins/qmldesigner/qmldesignerconstants.h +++ b/src/plugins/qmldesigner/qmldesignerconstants.h @@ -97,6 +97,7 @@ const char EVENT_PROPERTY_ADDED[] = "Property Added"; const char EVENT_ANNOTATION_ADDED[] = "Annotation Added"; const char EVENT_RESOURCE_IMPORTED[] = "Resource Imported "; const char EVENT_ACTION_EXECUTED[] = "Action Executed "; +const char EVENT_HELP_REQUESTED[] = "Help Requested "; const char EVENT_IMPORT_ADDED[] = "Import Added "; const char EVENT_BINDINGEDITOR_OPENED[] = "Binding Editor Opened"; const char EVENT_RICHTEXT_OPENED[] = "Richtext Editor Opened"; diff --git a/src/plugins/qmldesigner/qmldesignerplugin.cpp b/src/plugins/qmldesigner/qmldesignerplugin.cpp index ec4957bcc9d..2114a56d3d7 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.cpp +++ b/src/plugins/qmldesigner/qmldesignerplugin.cpp @@ -617,6 +617,11 @@ void QmlDesignerPlugin::emitUsageStatisticsContextAction(const QString &identifi emitUsageStatistics(Constants::EVENT_ACTION_EXECUTED + identifier); } +void QmlDesignerPlugin::emitUsageStatisticsHelpRequested(const QString &identifier) +{ + emitUsageStatistics(Constants::EVENT_HELP_REQUESTED + identifier); +} + AsynchronousImageCache &QmlDesignerPlugin::imageCache() { return m_instance->d->viewManager.imageCache(); diff --git a/src/plugins/qmldesigner/qmldesignerplugin.h b/src/plugins/qmldesigner/qmldesignerplugin.h index a773368c4d8..22800aa0454 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.h +++ b/src/plugins/qmldesigner/qmldesignerplugin.h @@ -87,6 +87,7 @@ public: static void emitUsageStatistics(const QString &identifier); static void emitUsageStatisticsContextAction(const QString &identifier); + static void emitUsageStatisticsHelpRequested(const QString &identifier); static void emitUsageStatisticsTime(const QString &identifier, int elapsed); static AsynchronousImageCache &imageCache(); From 2f29b9886a912ec27ee2a86202c889db5e733fa0 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Tue, 8 Feb 2022 19:08:50 +0100 Subject: [PATCH 33/94] QmlDesigner: Extend DebugView Change-Id: I7a0d52b215762794511ecf60993bca1cebc185bb Reviewed-by: Qt CI Bot Reviewed-by: Thomas Hartmann --- src/plugins/qmldesigner/components/debugview/debugview.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/plugins/qmldesigner/components/debugview/debugview.cpp b/src/plugins/qmldesigner/components/debugview/debugview.cpp index 62626b89cd7..be09b3864a4 100644 --- a/src/plugins/qmldesigner/components/debugview/debugview.cpp +++ b/src/plugins/qmldesigner/components/debugview/debugview.cpp @@ -110,6 +110,11 @@ void DebugView::nodeCreated(const ModelNode &createdNode) QString string; message.setString(&string); message << createdNode; + message << createdNode.nodeSource(); + message << "MetaInfo " << createdNode.metaInfo().isValid(); + if (createdNode.metaInfo().isValid()) { + message << createdNode.metaInfo().componentFileName(); + } log("::nodeCreated:", message.readAll()); } } From fa7a60eed70e6cb9e30c0c8a36bbfe6b946833d8 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 8 Feb 2022 12:10:31 +0100 Subject: [PATCH 34/94] Docker: Update manual/docker/README.md Change-Id: I2c8f713bc1d32191fd52765d3e82733a460b2fbf Reviewed-by: Christian Stenger --- tests/manual/docker/README.md | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/tests/manual/docker/README.md b/tests/manual/docker/README.md index 42833b0aecc..68be58f2e49 100644 --- a/tests/manual/docker/README.md +++ b/tests/manual/docker/README.md @@ -1,13 +1,11 @@ Limitations: -- Only Linux development hosts supported, as the docker container - contents is accessed via the local file system. - -- It currently unconditionally mounts /data and /opt, - source code has to live in either. - -- Kit items are auto-detected, but Kits themselves need to be - fixed up manually. +- Linux, Mac, Windows hosts are supported in principle, + Linux is recommended. +- Only Kit items in selected directories are auto-detected. +- Kits themselves need to be fixed up manually. +- Shared mounts are restricted to locations on the host system + that can end up on the same absolute location in the container What works: @@ -40,6 +38,11 @@ For testing: but using the Run container gives a more restricted setup closer to a real world scenario. +- MAKE SURE there's something sensible in "Paths to Mount". + These paths are shared between your host system and the docker device. + These should contain at the very least your sources, otherwise a build + in the container can't access it. + - Try to auto-detect kit items by pressing "Auto Detect Kit Items" for the Build container (only Build, not Run) From 035b8aa5f76b65a105bf4b311339fd43d35a7537 Mon Sep 17 00:00:00 2001 From: Aaron Barany Date: Tue, 8 Feb 2022 11:56:52 -0800 Subject: [PATCH 35/94] Debugger: Read remaining data before shutting down output collector Make sure any last data is read before shutting down the output collector. Prevents situations where output can be truncated when many lines of output are written before the program terminates. Task-number: QTCREATORBUG-27010 Change-Id: I33fd84281c371a68cccb195fa21b76a9e94482f0 Reviewed-by: hjk --- src/plugins/debugger/outputcollector.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/debugger/outputcollector.cpp b/src/plugins/debugger/outputcollector.cpp index e40fb3541c2..831a9f1276d 100644 --- a/src/plugins/debugger/outputcollector.cpp +++ b/src/plugins/debugger/outputcollector.cpp @@ -109,6 +109,8 @@ bool OutputCollector::listen() void OutputCollector::shutdown() { + // Make sure any last data is read first. + bytesAvailable(); #ifdef Q_OS_WIN delete m_server; // Deletes socket as well (QObject parent) m_server = nullptr; From 3c1a87290e55a343c3193d24da0b9740b96cfdc2 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 7 Feb 2022 09:53:19 +0100 Subject: [PATCH 36/94] Register some more windows So they get an entry in the Window menu, and window related shortcuts are registered correctly. Change-Id: Ie7e882a009f928f1268fdd312e7fb5362f6a837f Reviewed-by: Christian Stenger --- src/plugins/coreplugin/loggingviewer.cpp | 1 + src/plugins/cppeditor/cppeditorplugin.cpp | 1 + src/plugins/git/gerrit/gerritplugin.cpp | 1 + src/plugins/git/gitplugin.cpp | 2 ++ src/plugins/languageclient/languageclientmanager.cpp | 1 + 5 files changed, 6 insertions(+) diff --git a/src/plugins/coreplugin/loggingviewer.cpp b/src/plugins/coreplugin/loggingviewer.cpp index 25e015e1ac3..89046e39b2e 100644 --- a/src/plugins/coreplugin/loggingviewer.cpp +++ b/src/plugins/coreplugin/loggingviewer.cpp @@ -737,6 +737,7 @@ void LoggingViewer::showLoggingView() // explicitly disable manager again widget->deleteLater(); }); + ICore::registerWindow(widget, Context("Qtc.LogViewer")); widget->show(); } diff --git a/src/plugins/cppeditor/cppeditorplugin.cpp b/src/plugins/cppeditor/cppeditorplugin.cpp index 2a8557b2981..0bc90d1f1f1 100644 --- a/src/plugins/cppeditor/cppeditorplugin.cpp +++ b/src/plugins/cppeditor/cppeditorplugin.cpp @@ -516,6 +516,7 @@ void CppEditorPluginPrivate::inspectCppCodeModel() ICore::raiseWindow(m_cppCodeModelInspectorDialog); } else { m_cppCodeModelInspectorDialog = new CppCodeModelInspectorDialog(ICore::dialogParent()); + ICore::registerWindow(m_cppCodeModelInspectorDialog, Context("CppEditor.Inspector")); m_cppCodeModelInspectorDialog->show(); } } diff --git a/src/plugins/git/gerrit/gerritplugin.cpp b/src/plugins/git/gerrit/gerritplugin.cpp index 71ac8da38ea..d0904f96d6d 100644 --- a/src/plugins/git/gerrit/gerritplugin.cpp +++ b/src/plugins/git/gerrit/gerritplugin.cpp @@ -348,6 +348,7 @@ void GerritPlugin::openView() } GerritDialog *gd = new GerritDialog(m_parameters, m_server, currentRepository(), ICore::dialogParent()); gd->setModal(false); + ICore::registerWindow(gd, Context("Git.Gerrit")); connect(gd, &GerritDialog::fetchDisplay, this, [this](const QSharedPointer &change) { fetch(change, FetchDisplay); }); connect(gd, &GerritDialog::fetchCherryPick, this, diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp index 77a948e7773..2dbcfeb56ff 100644 --- a/src/plugins/git/gitplugin.cpp +++ b/src/plugins/git/gitplugin.cpp @@ -1715,6 +1715,7 @@ void GitPluginPrivate::branchList() void GitPluginPrivate::manageRemotes() { showNonModalDialog(currentState().topLevel(), m_remoteDialog); + ICore::registerWindow(m_remoteDialog, Context("Git.Remotes")); } void GitPluginPrivate::initRepository() @@ -1725,6 +1726,7 @@ void GitPluginPrivate::initRepository() void GitPluginPrivate::stashList() { showNonModalDialog(currentState().topLevel(), m_stashDialog); + ICore::registerWindow(m_stashDialog, Context("Git.Stashes")); } void GitPluginPrivate::updateActions(VcsBasePluginPrivate::ActionState as) diff --git a/src/plugins/languageclient/languageclientmanager.cpp b/src/plugins/languageclient/languageclientmanager.cpp index 37d502a945b..e76d3ff31b3 100644 --- a/src/plugins/languageclient/languageclientmanager.cpp +++ b/src/plugins/languageclient/languageclientmanager.cpp @@ -453,6 +453,7 @@ void LanguageClientManager::showInspector() clientName = client->name(); QWidget *inspectorWidget = instance()->m_inspector.createWidget(clientName); inspectorWidget->setAttribute(Qt::WA_DeleteOnClose); + Core::ICore::registerWindow(inspectorWidget, Core::Context("LanguageClient.Inspector")); inspectorWidget->show(); } From 4075b793c0d92de565f7a68cd2f9cfe6d26b2830 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Mon, 7 Feb 2022 13:09:21 +0100 Subject: [PATCH 37/94] CMakePM: Use the right type for the few kit CMake variables Use FILEPATH for CMAKE_C|CXX_COMPILER variables, and PATH for directory variables like CMAKE_PREFIX_PATH. Task-number: QTCREATORBUG-27005 Change-Id: I906de43ab97d2dbad0374469c4576d901d2f6339 Reviewed-by: Eike Ziller --- .../cmakeprojectmanager/cmakebuildconfiguration.cpp | 6 +++--- src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp | 4 ++++ src/plugins/cmakeprojectmanager/cmakeconfigitem.h | 1 + src/plugins/cmakeprojectmanager/cmakekitinformation.cpp | 8 ++++---- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index 02279d1408e..7760ad63089 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -102,7 +102,7 @@ const char DEVELOPMENT_TEAM_FLAG[] = "Ios:DevelopmentTeam:Flag"; const char PROVISIONING_PROFILE_FLAG[] = "Ios:ProvisioningProfile:Flag"; const char CMAKE_OSX_ARCHITECTURES_FLAG[] = "CMAKE_OSX_ARCHITECTURES:DefaultFlag"; const char CMAKE_QT6_TOOLCHAIN_FILE_ARG[] = - "-DCMAKE_TOOLCHAIN_FILE:PATH=%{Qt:QT_INSTALL_PREFIX}/lib/cmake/Qt6/qt.toolchain.cmake"; + "-DCMAKE_TOOLCHAIN_FILE:FILEPATH=%{Qt:QT_INSTALL_PREFIX}/lib/cmake/Qt6/qt.toolchain.cmake"; namespace Internal { @@ -1087,7 +1087,7 @@ static CommandLine defaultInitialCMakeCommand(const Kit *k, const QString buildT // Package manager if (!isDocker(k) && settings->packageManagerAutoSetup.value()) { - cmd.addArg("-DCMAKE_PROJECT_INCLUDE_BEFORE:PATH=" + cmd.addArg("-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=" "%{IDE:ResourcePath}/package-manager/auto-setup.cmake"); } @@ -1204,7 +1204,7 @@ CMakeBuildConfiguration::CMakeBuildConfiguration(Target *target, Id id) auto ndkLocation = bs->data(Android::Constants::NdkLocation).value(); cmd.addArg("-DANDROID_NDK:PATH=" + ndkLocation.path()); - cmd.addArg("-DCMAKE_TOOLCHAIN_FILE:PATH=" + cmd.addArg("-DCMAKE_TOOLCHAIN_FILE:FILEPATH=" + ndkLocation.pathAppended("build/cmake/android.toolchain.cmake").path()); auto androidAbis = bs->data(Android::Constants::AndroidMkSpecAbis).toStringList(); diff --git a/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp b/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp index 9347d84eccb..ad9c2277928 100644 --- a/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp @@ -51,6 +51,10 @@ CMakeConfigItem::CMakeConfigItem(const QByteArray &k, Type t, key(k), type(t), value(v), documentation(d), values(s) { } +CMakeConfigItem::CMakeConfigItem(const QByteArray &k, Type t, const QByteArray &v) : + key(k), type(t), value(v) +{ } + CMakeConfigItem::CMakeConfigItem(const QByteArray &k, const QByteArray &v) : key(k), value(v) { } diff --git a/src/plugins/cmakeprojectmanager/cmakeconfigitem.h b/src/plugins/cmakeprojectmanager/cmakeconfigitem.h index 10a8d8b7174..e7490562e3d 100644 --- a/src/plugins/cmakeprojectmanager/cmakeconfigitem.h +++ b/src/plugins/cmakeprojectmanager/cmakeconfigitem.h @@ -50,6 +50,7 @@ public: enum Type { FILEPATH, PATH, BOOL, STRING, INTERNAL, STATIC, UNINITIALIZED }; CMakeConfigItem(); CMakeConfigItem(const QByteArray &k, Type t, const QByteArray &d, const QByteArray &v, const QStringList &s = {}); + CMakeConfigItem(const QByteArray &k, Type t, const QByteArray &v); CMakeConfigItem(const QByteArray &k, const QByteArray &v); static QStringList cmakeSplitValue(const QString &in, bool keepEmpty = false); diff --git a/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp b/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp index 33224d439d1..f97575be5ac 100644 --- a/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp +++ b/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp @@ -1109,12 +1109,12 @@ CMakeConfig CMakeConfigurationKitAspect::defaultConfiguration(const Kit *k) Q_UNUSED(k) CMakeConfig config; // Qt4: - config << CMakeConfigItem(CMAKE_QMAKE_KEY, "%{Qt:qmakeExecutable}"); + config << CMakeConfigItem(CMAKE_QMAKE_KEY, CMakeConfigItem::FILEPATH, "%{Qt:qmakeExecutable}"); // Qt5: - config << CMakeConfigItem(CMAKE_PREFIX_PATH_KEY, "%{Qt:QT_INSTALL_PREFIX}"); + config << CMakeConfigItem(CMAKE_PREFIX_PATH_KEY, CMakeConfigItem::PATH, "%{Qt:QT_INSTALL_PREFIX}"); - config << CMakeConfigItem(CMAKE_C_TOOLCHAIN_KEY, "%{Compiler:Executable:C}"); - config << CMakeConfigItem(CMAKE_CXX_TOOLCHAIN_KEY, "%{Compiler:Executable:Cxx}"); + config << CMakeConfigItem(CMAKE_C_TOOLCHAIN_KEY, CMakeConfigItem::FILEPATH, "%{Compiler:Executable:C}"); + config << CMakeConfigItem(CMAKE_CXX_TOOLCHAIN_KEY, CMakeConfigItem::FILEPATH, "%{Compiler:Executable:Cxx}"); return config; } From 2f08f2bc11ccfaae08f66424857e44a168334991 Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Tue, 8 Feb 2022 23:03:00 +0200 Subject: [PATCH 38/94] QmlDesigner: Fix image drop to a navigator material issue When dropping an image from the assets library to a material in the navigator, and then cancelling the texture property dialog, don't create an image. Also some styling fixes. Change-Id: I49a3e7f154110de7b8a99e2a334b6c1753a98840 Reviewed-by: Reviewed-by: Qt CI Bot Reviewed-by: Thomas Hartmann --- .../navigator/navigatortreemodel.cpp | 51 +++++++++---------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp index 5e22fcec425..c92e2a20fe8 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp @@ -343,8 +343,7 @@ QList NavigatorTreeModel::filteredList(const NodeListProperty &proper return list; } -QModelIndex NavigatorTreeModel::index(int row, int column, - const QModelIndex &parent) const +QModelIndex NavigatorTreeModel::index(int row, int column, const QModelIndex &parent) const { if (!m_view->model()) return {}; @@ -391,21 +390,20 @@ QModelIndex NavigatorTreeModel::parent(const QModelIndex &index) const int row = 0; - if (!parentModelNode.isRootNode() && parentModelNode.parentProperty().isNodeListProperty()) + if (!parentModelNode.isRootNode() && parentModelNode.parentProperty().isNodeListProperty()) { row = filteredList(parentModelNode.parentProperty().toNodeListProperty(), m_showOnlyVisibleItems, m_reverseItemOrder).indexOf(parentModelNode); + } return createIndexFromModelNode(row, 0, parentModelNode); } int NavigatorTreeModel::rowCount(const QModelIndex &parent) const { - if (!m_view->isAttached()) + if (!m_view->isAttached() || parent.column() > 0) return 0; - if (parent.column() > 0) - return 0; const ModelNode modelNode = modelNodeForIndex(parent); if (!modelNode.isValid()) @@ -413,10 +411,11 @@ int NavigatorTreeModel::rowCount(const QModelIndex &parent) const int rows = 0; - if (modelNode.defaultNodeListProperty().isValid()) + if (modelNode.defaultNodeListProperty().isValid()) { rows = filteredList(modelNode.defaultNodeListProperty(), m_showOnlyVisibleItems, m_reverseItemOrder).count(); + } return rows; } @@ -456,8 +455,8 @@ 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"}); + "application/vnd.bauhaus.itemlibraryinfo", + "application/vnd.bauhaus.libraryresource"}); return types; } @@ -790,8 +789,7 @@ ModelNode NavigatorTreeModel::handleItemLibraryImageDrop(const QString &imagePat ModelNode newModelNode; if (!dropAsImage3dTexture(targetNode, targetProperty, imagePathRelative, newModelNode)) { - if (targetNode.isSubclassOf("QtQuick.Image") - || targetNode.isSubclassOf("QtQuick.BorderImage")) { + if (targetNode.isSubclassOf("QtQuick.Image") || targetNode.isSubclassOf("QtQuick.BorderImage")) { // if dropping an image on an existing image, set the source targetNode.variantProperty("source").setValue(imagePathRelative); } else { @@ -966,28 +964,27 @@ bool NavigatorTreeModel::dropAsImage3dTexture(const ModelNode &targetNode, const QString &imagePath, ModelNode &newNode) { - if (targetNode.isSubclassOf("QtQuick3D.Material")) { - // if dropping an image on a default material, create a texture instead of image - ChooseFromPropertyListDialog *dialog = nullptr; - if (targetNode.isSubclassOf("QtQuick3D.DefaultMaterial") - || targetNode.isSubclassOf("QtQuick3D.PrincipledMaterial")) { - // Show texture property selection dialog - dialog = ChooseFromPropertyListDialog::createIfNeeded(targetNode, "QtQuick3D.Texture", - Core::ICore::dialogParent()); - if (dialog) - dialog->exec(); - } - if (!dialog || dialog->result() == QDialog::Accepted) { + if (targetNode.isSubclassOf("QtQuick3D.DefaultMaterial") + || targetNode.isSubclassOf("QtQuick3D.PrincipledMaterial")) { + // if dropping an image on a material, create a texture instead of image + // Show texture property selection dialog + auto dialog = ChooseFromPropertyListDialog::createIfNeeded(targetNode, "QtQuick3D.Texture", + Core::ICore::dialogParent()); + if (!dialog) + return false; + + dialog->exec(); + + if (dialog->result() == QDialog::Accepted) { m_view->executeInTransaction("NavigatorTreeModel::dropAsImage3dTexture", [&] { newNode = createTextureNode(targetProp, imagePath); - if (newNode.isValid() && dialog) { - // Automatically set the texture to selected property + if (newNode.isValid()) // Automatically set the texture to selected property targetNode.bindingProperty(dialog->selectedProperty()).setExpression(newNode.validId()); - } }); } + delete dialog; - return newNode.isValid(); + return true; } else if (targetNode.isSubclassOf("QtQuick3D.TextureInput")) { // If dropping an image on a TextureInput, create a texture on the same level as // TextureInput, as the TextureInput doesn't support Texture children (QTBUG-86219) From eb7aad198f8e2f1845b712a553834199d6a5c953 Mon Sep 17 00:00:00 2001 From: Andre Hartmann Date: Wed, 9 Feb 2022 08:38:55 +0100 Subject: [PATCH 39/94] VcsOutputLineParser: Allow copying links to clipboard Change-Id: I193225ed42db61966db9cc9cdf3db7e9dca26672 Reviewed-by: Orgad Shaneh Reviewed-by: --- src/plugins/vcsbase/vcsoutputformatter.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/plugins/vcsbase/vcsoutputformatter.cpp b/src/plugins/vcsbase/vcsoutputformatter.cpp index 60d929e50a0..dc6ac9f708b 100644 --- a/src/plugins/vcsbase/vcsoutputformatter.cpp +++ b/src/plugins/vcsbase/vcsoutputformatter.cpp @@ -28,6 +28,8 @@ #include +#include +#include #include #include #include @@ -88,6 +90,8 @@ void VcsOutputLineParser::fillLinkContextMenu( tr("&Open \"%1\"").arg(href), [href] { QDesktopServices::openUrl(QUrl(href)); }); menu->setDefaultAction(action); + menu->addAction(tr("&Copy to clipboard: \"%1\"").arg(href), + [href] { QApplication::clipboard()->setText(href); }); return; } if (Core::IVersionControl *vcs = Core::VcsManager::findVersionControlForDirectory(workingDirectory)) From 76eb84e72d5a84d9c1d086c3483a5493745345cf Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 9 Feb 2022 09:04:09 +0100 Subject: [PATCH 40/94] Docker: Also mention the logging category used for debugging/testing Change-Id: I3f3c34e6102a6225539f3ad3b32d2e1e0026bc3a Reviewed-by: Reviewed-by: Christian Stenger --- tests/manual/docker/README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/manual/docker/README.md b/tests/manual/docker/README.md index 68be58f2e49..d9ef944d46f 100644 --- a/tests/manual/docker/README.md +++ b/tests/manual/docker/README.md @@ -23,7 +23,10 @@ What works: For testing: -- build docker containers from this directory (tests/manual/docker) by +- Optional: Set QT_LOGGING_RULES=qtc.docker.device=true + This will show a large part of the communication with the docker CLI client. + +- Build docker containers from this directory (tests/manual/docker) by running ./build.sh. This builds a docker image containing a Desktop Qt build setup (including compiler etc) and second docker image container containing a run environment without the build tools, but e.g. with gdb From 3bb4483288f0b122e042048d3c20ce9873edb746 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 9 Feb 2022 11:01:31 +0100 Subject: [PATCH 41/94] Remove unneeded declaration of Connection class There is no such a class in ProjectExplorer namespace. Change-Id: Ib82c154795bd120b4d3ec696b6553863a0bf7566 Reviewed-by: Qt CI Bot Reviewed-by: hjk --- src/plugins/projectexplorer/devicesupport/idevice.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/plugins/projectexplorer/devicesupport/idevice.h b/src/plugins/projectexplorer/devicesupport/idevice.h index 8e395368a8c..9090500f493 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.h +++ b/src/plugins/projectexplorer/devicesupport/idevice.h @@ -59,7 +59,6 @@ class QtcProcess; namespace ProjectExplorer { -class Connection; class DeviceProcess; class DeviceProcessList; class Kit; From 4e781e79151a29c9dd50e0391f66b8a5fb3203b6 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Wed, 9 Feb 2022 11:16:18 +0100 Subject: [PATCH 42/94] Doc: Describe new Clang compiler options The target triple can be viewed and overridden if Clang does not understand the target architecture. Task-number: QTCREATORBUG-26610 Change-Id: I3420f09ae5227c3aa4be3baf9cb2383e9bdac135 Reviewed-by: Christian Kandeler --- .../qtcreator-compilers-target-triple.png | Bin 0 -> 8998 bytes doc/qtcreator/images/qtcreator-toolchains.png | Bin 26001 -> 22497 bytes .../creator-projects-compilers.qdoc | 9 ++++++++- 3 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 doc/qtcreator/images/qtcreator-compilers-target-triple.png diff --git a/doc/qtcreator/images/qtcreator-compilers-target-triple.png b/doc/qtcreator/images/qtcreator-compilers-target-triple.png new file mode 100644 index 0000000000000000000000000000000000000000..7157cae001ef72871928e6beb01963eababb1127 GIT binary patch literal 8998 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 Bqa*+T literal 0 HcmV?d00001 diff --git a/doc/qtcreator/images/qtcreator-toolchains.png b/doc/qtcreator/images/qtcreator-toolchains.png index 1e54fe33330bce65351d56be69a01908e8ce99fd..c82b677b5db0b7a95b9bb7871f8d940576662abd 100644 GIT binary patch literal 22497 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 literal 26001 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 Q5zry^p00i_>zopr04_Xo4FCWD diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-compilers.qdoc b/doc/qtcreator/src/projects/creator-only/creator-projects-compilers.qdoc index e03e367aba0..79280560dca 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-projects-compilers.qdoc +++ b/doc/qtcreator/src/projects/creator-only/creator-projects-compilers.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2020 The Qt Company Ltd. +** Copyright (C) 2022 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Creator documentation. @@ -181,6 +181,13 @@ target architecture. This is used to warn about ABI mismatches within the kits. + \li In the \uicontrol {Target triple} field, specify the GCC target + architecture. If services provided by the code model fail because + Clang does not understand the target architecture, select + \uicontrol {Override for code model}. + + \image qtcreator-compilers-target-triple.png "Target triple field" + \endlist \section1 Adding Nim Compilers From cfbf083089cf12c461980294f6e0df0bb856f10a Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 9 Feb 2022 11:57:41 +0100 Subject: [PATCH 43/94] Docker: Allow use of local access only as compile time switch That's sufficient for testing/working on the feature and removes accidental use by users. Change-Id: Ic0fb3076f769ab9ab7ff74973f0129402db7f142 Reviewed-by: Christian Stenger --- src/plugins/docker/dockerdevice.cpp | 33 +++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index 99c795ae22a..daba1b235a2 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -87,6 +87,8 @@ #include #endif +//#define ALLOW_LOCAL_ACCESS 1 + using namespace Core; using namespace ProjectExplorer; using namespace QtSupport; @@ -249,6 +251,7 @@ class DockerDevicePrivate : public QObject public: DockerDevicePrivate(DockerDevice *parent) : q(parent) { +#ifdef ALLOW_LOCAL_ACCESS connect(&m_mergedDirWatcher, &QFileSystemWatcher::fileChanged, this, [this](const QString &path) { Q_UNUSED(path) LOG("Container watcher change, file: " << path); @@ -257,6 +260,7 @@ public: Q_UNUSED(path) LOG("Container watcher change, directory: " << path); }); +#endif } ~DockerDevicePrivate() { stopCurrentContainer(); } @@ -279,8 +283,11 @@ public: QPointer m_shell; mutable QMutex m_shellMutex; QString m_container; + +#ifdef ALLOW_LOCAL_ACCESS QString m_mergedDir; QFileSystemWatcher m_mergedDirWatcher; +#endif Environment m_cachedEnviroment; @@ -333,6 +340,7 @@ public: data.useLocalUidGid = on; }); +#ifdef ALLOW_LOCAL_ACCESS // This tries to find the directory in the host file system that corresponds to the // docker container root file system, which is a merge of the layers from the // container image and the volumes mapped using -v on container startup. @@ -348,6 +356,7 @@ public: data.useFilePathMapping = on; dockerDevice->updateContainerAccess(); }); +#endif m_pathsListEdit = new PathListEditor; m_pathsListEdit->setToolTip(tr("Maps paths in this list one-to-one to the " @@ -420,7 +429,9 @@ public: repoLabel, m_repoLineEdit, Break(), daemonStateLabel, m_daemonReset, m_daemonState, Break(), m_runAsOutsideUser, Break(), +#ifdef ALLOW_LOCAL_ACCESS m_usePathMapping, Break(), +#endif Column { new QLabel(tr("Paths to mount:")), m_pathsListEdit, @@ -459,7 +470,9 @@ private: QToolButton *m_daemonReset; QLabel *m_daemonState; QCheckBox *m_runAsOutsideUser; +#ifdef ALLOW_LOCAL_ACCESS QCheckBox *m_usePathMapping; +#endif Utils::PathListEditor *m_pathsListEdit; KitDetector m_kitItemDetector; @@ -791,7 +804,9 @@ void DockerDevicePrivate::stopCurrentContainer() if (m_shell->state() == QProcess::NotRunning) { LOG("Clean exit via shell"); m_container.clear(); +#ifdef ALLOW_LOCAL_ACCESS m_mergedDir.clear(); +#endif delete m_shell; m_shell = nullptr; return; @@ -802,7 +817,9 @@ void DockerDevicePrivate::stopCurrentContainer() proc.setCommand({"docker", {"container", "stop", m_container}}); m_container.clear(); +#ifdef ALLOW_LOCAL_ACCESS m_mergedDir.clear(); +#endif proc.runBlocking(); } @@ -917,6 +934,7 @@ void DockerDevicePrivate::updateContainerAccess() void DockerDevicePrivate::updateFileSystemAccess() { +#ifdef ALLOW_LOCAL_ACCESS if (!m_data.useFilePathMapping) { // Direct access was used previously, but is not wanted anymore. if (!m_mergedDir.isEmpty()) { @@ -958,14 +976,19 @@ void DockerDevicePrivate::updateFileSystemAccess() } m_mergedDirWatcher.addPath(m_mergedDir); +#endif } bool DockerDevice::hasLocalFileAccess() const { +#ifdef ALLOW_LOCAL_ACCESS static const bool denyLocalAccess = qEnvironmentVariableIsSet("QTC_DOCKER_DENY_LOCAL_ACCESS"); if (denyLocalAccess) return false; return !d->m_mergedDir.isEmpty(); +#else + return false; +#endif } void DockerDevice::setMounts(const QStringList &mounts) const @@ -976,6 +999,7 @@ void DockerDevice::setMounts(const QStringList &mounts) const FilePath DockerDevice::mapToLocalAccess(const FilePath &filePath) const { +#ifdef ALLOW_LOCAL_ACCESS QTC_ASSERT(!d->m_mergedDir.isEmpty(), return {}); QString path = filePath.path(); for (const QString &mount : qAsConst(d->m_data.mounts)) { @@ -985,6 +1009,10 @@ FilePath DockerDevice::mapToLocalAccess(const FilePath &filePath) const if (path.startsWith('/')) return FilePath::fromString(d->m_mergedDir + path); return FilePath::fromString(d->m_mergedDir + '/' + path); +#else + QTC_CHECK(false); + return {}; +#endif } FilePath DockerDevice::mapFromLocalAccess(const FilePath &filePath) const @@ -995,9 +1023,14 @@ FilePath DockerDevice::mapFromLocalAccess(const FilePath &filePath) const FilePath DockerDevice::mapFromLocalAccess(const QString &filePath) const { +#ifdef ALLOW_LOCAL_FILE_ACCESS QTC_ASSERT(!d->m_mergedDir.isEmpty(), return {}); QTC_ASSERT(filePath.startsWith(d->m_mergedDir), return FilePath::fromString(filePath)); return mapToGlobalPath(FilePath::fromString(filePath.mid(d->m_mergedDir.size()))); +#else + QTC_CHECK(false); + return {}; +#endif } const char DockerDeviceDataImageIdKey[] = "DockerDeviceDataImageId"; From ff68923846e30b8b23947c3a107d0e0aec3df4dc Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 8 Feb 2022 11:35:35 +0100 Subject: [PATCH 44/94] Fix stopping the remote app run in terminal It amends 9ec997b37654894b027cf4bbd98ca8bba47171b5 were in case of runInTerminal() we were not connected to self started() signal anymore, so we were missing a call to setState(SshDeviceProcessPrivate::ProcessRunning) after start. Amends 9ec997b37654894b027cf4bbd98ca8bba47171b5 Fixes: QTCREATORBUG-27014 Change-Id: I48bd2c223f36cd12b0b66bdc62f735b12cf7bdeb Reviewed-by: Reviewed-by: hjk --- .../devicesupport/sshdeviceprocess.cpp | 41 ++++++++----------- .../devicesupport/sshdeviceprocess.h | 4 +- 2 files changed, 19 insertions(+), 26 deletions(-) diff --git a/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp b/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp index 5d7d285e668..bf265b0258f 100644 --- a/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp +++ b/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp @@ -51,7 +51,7 @@ public: SshDeviceProcessPrivate(SshDeviceProcess *q) : q(q) {} SshDeviceProcess * const q; - bool ignoreFinished = true; + bool ignoreSelfSignals = true; QSsh::SshConnection *connection = nullptr; QSsh::SshRemoteProcessPtr remoteProcess; Runnable runnable; @@ -74,7 +74,17 @@ SshDeviceProcess::SshDeviceProcess(const IDevice::ConstPtr &device, QObject *par : DeviceProcess(device, QtcProcess::TerminalOn, parent), d(std::make_unique(this)) { - connect(this, &QtcProcess::finished, this, &SshDeviceProcess::handleThisProcessFinished); + // Hack: we rely on fact that below slots were called before any other external slots connected + // to this instance signals. That's why we don't re-emit them from inside our handlers since + // these signal will reach all other external slots anyway after our handlers are done. + connect(this, &QtcProcess::started, this, [this] { + if (!d->ignoreSelfSignals) + handleProcessStarted(); + }); + connect(this, &QtcProcess::finished, this, [this] { + if (!d->ignoreSelfSignals) + handleProcessFinished(QtcProcess::errorString()); + }); connect(&d->killTimer, &QTimer::timeout, this, &SshDeviceProcess::handleKillOperationTimeout); } @@ -185,8 +195,8 @@ void SshDeviceProcess::handleConnected() const QString display = d->displayName(); if (!display.isEmpty()) d->remoteProcess->requestX11Forwarding(display); + d->ignoreSelfSignals = !runInTerminal(); if (runInTerminal()) { - d->ignoreFinished = false; setAbortOnMetaChars(false); setCommand(d->remoteProcess->fullLocalCommandLine(true)); QtcProcess::start(); @@ -194,7 +204,7 @@ void SshDeviceProcess::handleConnected() connect(d->remoteProcess.get(), &QSsh::SshRemoteProcess::started, this, &SshDeviceProcess::handleProcessStarted); connect(d->remoteProcess.get(), &QSsh::SshRemoteProcess::done, - this, &SshDeviceProcess::handleRemoteProcessFinished); + this, &SshDeviceProcess::handleProcessFinished); connect(d->remoteProcess.get(), &QSsh::SshRemoteProcess::readyReadStandardOutput, this, &QtcProcess::readyReadStandardOutput); connect(d->remoteProcess.get(), &QSsh::SshRemoteProcess::readyReadStandardError, @@ -234,31 +244,17 @@ void SshDeviceProcess::handleProcessStarted() QTC_ASSERT(d->state == SshDeviceProcessPrivate::Connected, return); d->setState(SshDeviceProcessPrivate::ProcessRunning); - emit started(); + if (d->ignoreSelfSignals) + emit started(); } -void SshDeviceProcess::handleThisProcessFinished() -{ - if (d->ignoreFinished) - return; - // Hack: we rely on fact that this slot was called before any other external slot connected - // to finished() signal. That's why we don't emit finished() signal from inside - // handleProcessFinished() since this signal will reach all other external slots anyway. - handleProcessFinished(QtcProcess::errorString(), false); -} - -void SshDeviceProcess::handleRemoteProcessFinished(const QString &error) -{ - handleProcessFinished(error, true); -} - -void SshDeviceProcess::handleProcessFinished(const QString &error, bool emitFinished) +void SshDeviceProcess::handleProcessFinished(const QString &error) { d->errorMessage = error; if (d->killOperation && error.isEmpty()) d->errorMessage = tr("The process was ended forcefully."); d->setState(SshDeviceProcessPrivate::Inactive); - if (emitFinished) + if (d->ignoreSelfSignals) emit finished(); } @@ -345,7 +341,6 @@ void SshDeviceProcess::SshDeviceProcessPrivate::setState(SshDeviceProcess::SshDe QMetaObject::invokeMethod(q, &QtcProcess::stopProcess, Qt::QueuedConnection); } killTimer.stop(); - ignoreFinished = true; if (remoteProcess) remoteProcess->disconnect(q); if (connection) { diff --git a/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.h b/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.h index 11b5a92bc12..0980d530bcf 100644 --- a/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.h +++ b/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.h @@ -60,9 +60,7 @@ private: void handleConnectionError(); void handleDisconnected(); void handleProcessStarted(); - void handleThisProcessFinished(); - void handleRemoteProcessFinished(const QString &error); - void handleProcessFinished(const QString &error, bool emitFinished); + void handleProcessFinished(const QString &error); void handleKillOperationFinished(const QString &errorMessage); void handleKillOperationTimeout(); From 072750a284516d141933595b9e2652c370b64c47 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 8 Feb 2022 16:17:48 +0100 Subject: [PATCH 45/94] Fix crash reporting in output pane when remote run in terminal Fixes: QTCREATORBUG-27007 Change-Id: I6e409eb6489530dc6c48c90d20e28ff019eff187 Reviewed-by: Reviewed-by: hjk --- src/libs/ssh/sshremoteprocess.cpp | 2 - .../projectexplorer/applicationlauncher.cpp | 3 - src/plugins/projectexplorer/runcontrol.cpp | 76 ++++++++----------- src/plugins/projectexplorer/runcontrol.h | 1 + 4 files changed, 31 insertions(+), 51 deletions(-) diff --git a/src/libs/ssh/sshremoteprocess.cpp b/src/libs/ssh/sshremoteprocess.cpp index bbfec939eba..0cb916acf13 100644 --- a/src/libs/ssh/sshremoteprocess.cpp +++ b/src/libs/ssh/sshremoteprocess.cpp @@ -60,8 +60,6 @@ SshRemoteProcess::SshRemoteProcess(const QString &command, const QStringList &co QString error; if (exitStatus() == QProcess::CrashExit) error = tr("The ssh process crashed: %1").arg(errorString()); - else if (exitCode() == 255) - error = tr("Remote process crashed."); emit done(error); }); connect(this, &QtcProcess::errorOccurred, [this](QProcess::ProcessError error) { diff --git a/src/plugins/projectexplorer/applicationlauncher.cpp b/src/plugins/projectexplorer/applicationlauncher.cpp index ea9dbd4a059..2d5b5ce5fd5 100644 --- a/src/plugins/projectexplorer/applicationlauncher.cpp +++ b/src/plugins/projectexplorer/applicationlauncher.cpp @@ -458,9 +458,6 @@ void ApplicationLauncherPrivate::handleApplicationFinished() if (exitCode != 0) { doReportError(ApplicationLauncher::tr("Application finished with exit code %1.") .arg(exitCode), QProcess::UnknownError); - } else { - emit q->appendMessage(ApplicationLauncher::tr("Application finished with exit code 0."), - Utils::NormalMessageFormat); } } setFinished(); diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp index f0824ead6e0..883760dfda0 100644 --- a/src/plugins/projectexplorer/runcontrol.cpp +++ b/src/plugins/projectexplorer/runcontrol.cpp @@ -1196,6 +1196,7 @@ void SimpleTargetRunner::start() void SimpleTargetRunner::doStart(const Runnable &runnable, const IDevice::ConstPtr &device) { + m_stopForced = false; m_stopReported = false; m_launcher.disconnect(this); m_launcher.setUseTerminal(m_useTerminal); @@ -1205,11 +1206,34 @@ void SimpleTargetRunner::doStart(const Runnable &runnable, const IDevice::ConstP const QString msg = RunControl::tr("Starting %1...").arg(runnable.command.toUserOutput()); appendMessage(msg, Utils::NormalMessageFormat); + connect(&m_launcher, &ApplicationLauncher::processExited, + this, [this, runnable](int exitCode, QProcess::ExitStatus status) { + if (m_stopReported) + return; + const QString msg = (status == QProcess::CrashExit) + ? tr("%1 crashed.") : tr("%2 exited with code %1").arg(exitCode); + const QString displayName = runnable.command.executable().toUserOutput(); + appendMessage(msg.arg(displayName), Utils::NormalMessageFormat); + m_stopReported = true; + reportStopped(); + }); + + connect(&m_launcher, &ApplicationLauncher::error, + this, [this, runnable](QProcess::ProcessError error) { + if (m_stopReported) + return; + if (error == QProcess::Timedout) + return; // No actual change on the process side. + const QString msg = m_stopForced ? tr("The process was ended forcefully.") + : userMessageForProcessError(error, runnable.command.executable()); + appendMessage(msg, Utils::NormalMessageFormat); + m_stopReported = true; + reportStopped(); + }); + + connect(&m_launcher, &ApplicationLauncher::appendMessage, this, &RunWorker::appendMessage); + if (isDesktop) { - - connect(&m_launcher, &ApplicationLauncher::appendMessage, - this, &SimpleTargetRunner::appendMessage); - connect(&m_launcher, &ApplicationLauncher::processStarted, this, [this] { // Console processes only know their pid after being started ProcessHandle pid = m_launcher.applicationPID(); @@ -1218,33 +1242,6 @@ void SimpleTargetRunner::doStart(const Runnable &runnable, const IDevice::ConstP reportStarted(); }); - connect(&m_launcher, &ApplicationLauncher::processExited, - this, [this, runnable](int exitCode, QProcess::ExitStatus status) { - if (m_stopReported) - return; - const QString msg = (status == QProcess::CrashExit) - ? tr("%1 crashed.") : tr("%2 exited with code %1").arg(exitCode); - const QString displayName = runnable.command.executable().toUserOutput(); - appendMessage(msg.arg(displayName), Utils::NormalMessageFormat); - m_stopReported = true; - reportStopped(); - }); - - connect(&m_launcher, &ApplicationLauncher::error, - this, [this, runnable](QProcess::ProcessError error) { - if (error == QProcess::Timedout) - return; // No actual change on the process side. - if (error != QProcess::Crashed) { - const QString msg = userMessageForProcessError( - error, runnable.command.executable()); - appendMessage(msg, Utils::NormalMessageFormat); - } - if (!m_stopReported) { - m_stopReported = true; - reportStopped(); - } - }); - if (runnable.command.isEmpty()) { reportFailure(RunControl::tr("No executable specified.")); } else { @@ -1252,27 +1249,14 @@ void SimpleTargetRunner::doStart(const Runnable &runnable, const IDevice::ConstP } } else { - - connect(&m_launcher, &ApplicationLauncher::error, this, [this] { - reportFailure(m_launcher.errorString()); - }); - connect(&m_launcher, &ApplicationLauncher::processStarted, this, &RunWorker::reportStarted); - - connect(&m_launcher, &ApplicationLauncher::processExited, - this, [this] { - m_launcher.disconnect(this); - reportStopped(); - }); - - connect(&m_launcher, &ApplicationLauncher::appendMessage, this, &RunWorker::appendMessage); - m_launcher.start(runnable, device); } } void SimpleTargetRunner::stop() { + m_stopForced = true; m_launcher.stop(); } @@ -1559,7 +1543,7 @@ QString RunWorker::userMessageForProcessError(QProcess::ProcessError error, cons "permissions to invoke the program.").arg(program.toUserOutput()); break; case QProcess::Crashed: - msg = tr("The process was ended forcefully."); + msg = tr("The process crashed."); break; case QProcess::Timedout: // "The last waitFor...() function timed out. " diff --git a/src/plugins/projectexplorer/runcontrol.h b/src/plugins/projectexplorer/runcontrol.h index 6f00b57e97d..c1ab5d67813 100644 --- a/src/plugins/projectexplorer/runcontrol.h +++ b/src/plugins/projectexplorer/runcontrol.h @@ -308,6 +308,7 @@ private: bool m_stopReported = false; bool m_useTerminal = false; bool m_runAsRoot = false; + bool m_stopForced = false; }; class PROJECTEXPLORER_EXPORT OutputFormatterFactory From cdeb3ae13f1f06a9cb19b977f8c4bc96adf65126 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Thu, 20 Jan 2022 14:23:38 +0200 Subject: [PATCH 46/94] Add quick3d memory consumption to profiler Change-Id: I300ef808793fafc7328118dcc694ab67e90f9f52 Reviewed-by: Qt CI Bot Reviewed-by: Janne Koskinen Reviewed-by: Miikka Heikkinen Reviewed-by: Thomas Hartmann --- src/plugins/qmlprofiler/quick3dmodel.cpp | 159 +++++++++++++++++++---- src/plugins/qmlprofiler/quick3dmodel.h | 25 +++- 2 files changed, 154 insertions(+), 30 deletions(-) diff --git a/src/plugins/qmlprofiler/quick3dmodel.cpp b/src/plugins/qmlprofiler/quick3dmodel.cpp index fd2b5959dfe..ac8f42d5338 100644 --- a/src/plugins/qmlprofiler/quick3dmodel.cpp +++ b/src/plugins/qmlprofiler/quick3dmodel.cpp @@ -38,11 +38,6 @@ Quick3DModel::Quick3DModel(QmlProfilerModelManager *manager, { } -int Quick3DModel::typeId(int index) const -{ - return m_data[index].typeId; -} - QRgb Quick3DModel::color(int index) const { return colorBySelectionId(index); @@ -58,6 +53,15 @@ static const char *messageTypes[] = { QT_TRANSLATE_NOOP("Quick3DModel", "Generate Shader"), QT_TRANSLATE_NOOP("Quick3DModel", "Load Shader"), QT_TRANSLATE_NOOP("Quick3DModel", "Particle Update"), + + QT_TRANSLATE_NOOP("Quick3DModel", "Mesh Memory consumption"), + QT_TRANSLATE_NOOP("Quick3DModel", "Texture Memory consumption"), +}; + +static const char *unloadMessageTypes[] = { + QT_TRANSLATE_NOOP("Quick3DModel", "Mesh Unload"), + QT_TRANSLATE_NOOP("Quick3DModel", "Custom Mesh Unload"), + QT_TRANSLATE_NOOP("Quick3DModel", "Texture Unload"), }; QString Quick3DModel::messageType(uint i) @@ -66,12 +70,26 @@ QString Quick3DModel::messageType(uint i) tr("Unknown Message %1").arg(i); } +QString Quick3DModel::unloadMessageType(uint i) +{ + switch (i) { + case MeshLoad: + return tr(unloadMessageTypes[0]); + case CustomMeshLoad: + return tr(unloadMessageTypes[1]); + case TextureLoad: + return tr(unloadMessageTypes[2]); + } + return tr("Unknown Unload Message %1").arg(i); +} + QVariantList Quick3DModel::labels() const { QVariantList result; for (int i = 0; i <= m_maximumMsgType; ++i) { QVariantMap element; - element.insert(QLatin1String("displayName"), i < ParticleUpdate ? tr("Render Thread") : tr("GUI Thread")); + element.insert(QLatin1String("displayName"), + i != ParticleUpdate ? tr("Render Thread") : tr("GUI Thread")); element.insert(QLatin1String("description"), messageType(i)); element.insert(QLatin1String("id"), i); result << element; @@ -79,17 +97,49 @@ QVariantList Quick3DModel::labels() const return result; } +float Quick3DModel::relativeHeight(int index) const +{ + auto detailType = m_data[index].additionalType; + if (detailType == TextureMemoryConsumption) + return qMin(1.0f, (float)m_data[index].data / (float)m_maxTextureSize); + if (detailType == MeshMemoryConsumption) + return qMin(1.0f, (float)m_data[index].data / (float)m_maxMeshSize); + return 1.0f; +} + +qint64 Quick3DModel::rowMaxValue(int rowNumber) const +{ + int index = rowNumber - 1; + if (index == TextureMemoryConsumption) + return m_maxTextureSize; + if (index == MeshMemoryConsumption) + return m_maxMeshSize; + return 0; +} + QVariantMap Quick3DModel::details(int index) const { - const QmlProfilerModelManager *manager = modelManager(); - const QmlEventType &type = manager->eventType(m_data[index].typeId); - + auto detailType = m_data[index].additionalType; + bool unload = m_data[index].unload; QVariantMap result; - result.insert(QLatin1String("displayName"), type.detailType() < ParticleUpdate ? tr("Render Thread") : tr("GUI Thread")); - result.insert(tr("Description"), messageType(type.detailType())); - result.insert(tr("Duration"), Timeline::formatTime(duration(index))); - if (type.detailType() == ParticleUpdate) + result.insert(QLatin1String("displayName"), + detailType != ParticleUpdate ? tr("Render Thread") : tr("GUI Thread")); + result.insert(tr("Description"), + !unload ? messageType(detailType) : unloadMessageType(detailType)); + if (detailType < MeshMemoryConsumption) + result.insert(tr("Duration"), Timeline::formatTime(duration(index))); + if (detailType == ParticleUpdate) result.insert(tr("Count"), m_data[index].data); + if (detailType == RenderFrame) { + quint32 calls = m_data[index].data & 0xffffffff; + quint32 passes = m_data[index].data >> 32; + result.insert(tr("Draw Calls"), calls); + result.insert(tr("Render Passes"), passes); + } + if ((detailType >= MeshLoad && detailType <= TextureLoad) + || (detailType >= MeshMemoryConsumption && detailType <= TextureMemoryConsumption)) { + result.insert(tr("Total Memory Usage"), m_data[index].data); + } return result; } @@ -106,23 +156,80 @@ int Quick3DModel::collapsedRow(int index) const void Quick3DModel::loadEvent(const QmlEvent &event, const QmlEventType &type) { + auto detailType = type.detailType(); qint64 eventDuration = event.number(0); - qint64 startTime = event.timestamp() - eventDuration; - if (type.detailType() == MessageType::ParticleUpdate) { - quint64 particleCount = event.number(1); - m_data.insert(insert(startTime, eventDuration, type.detailType()), - Item(event.typeIndex(), particleCount)); - } else { - m_data.insert(insert(startTime, eventDuration, type.detailType()), - Item(event.typeIndex(), 0)); - } + qint64 eventTime = event.timestamp() - eventDuration; + QVector numbers = event.numbers>(); + quint64 data = numbers.size() > 1 ? event.number(1) : 0; - if (type.detailType() > m_maximumMsgType) - m_maximumMsgType = type.detailType(); + int typeCount = detailType; + if (detailType == MeshLoad || detailType == CustomMeshLoad) { + bool updatePrevValues = true; + if (m_prevMeshStartTime != -1) { + bool unload = m_prevMeshData > data; + m_data.insert(insert(eventTime, eventDuration, detailType), + Item(detailType, data, unload)); + if (m_prevMeshData != data) { + m_data.insert(insert(m_prevMeshStartTime, + eventTime - m_prevMeshStartTime, MeshMemoryConsumption), + Item(MeshMemoryConsumption, m_prevMeshData)); + } else { + updatePrevValues = false; + } + } else { + m_data.insert(insert(eventTime, eventDuration, detailType), + Item(detailType, data)); + } + m_maxMeshSize = qMax(m_maxMeshSize, data); + if (updatePrevValues) { + m_prevMeshStartTime = eventTime; + m_prevMeshData = data; + } + typeCount = MeshMemoryConsumption; + } else if (detailType == TextureLoad) { + bool updatePrevValues = true; + if (m_prevTexStartTime != -1) { + bool unload = m_prevTexData > data; + m_data.insert(insert(eventTime, eventDuration, detailType), + Item(detailType, data, unload)); + if (m_prevTexData != data) { + m_data.insert(insert(m_prevTexStartTime, + eventTime - m_prevTexStartTime, TextureMemoryConsumption), + Item(TextureMemoryConsumption, m_prevTexData)); + } else { + updatePrevValues = false; + } + } else { + m_data.insert(insert(eventTime, eventDuration, detailType), + Item(detailType, data)); + } + m_maxTextureSize = qMax(m_maxTextureSize, data); + if (updatePrevValues) { + m_prevTexData = data; + m_prevTexStartTime = eventTime; + } + typeCount = TextureMemoryConsumption; + } else { + m_data.insert(insert(eventTime, eventDuration, detailType), + Item(detailType, data)); + } + if (typeCount > m_maximumMsgType) + m_maximumMsgType = typeCount; } void Quick3DModel::finalize() { + if (m_prevMeshStartTime != -1) { + m_data.insert(insert(m_prevMeshStartTime, modelManager()->traceEnd() - m_prevMeshStartTime, + MeshMemoryConsumption), + Item(MeshMemoryConsumption, m_prevMeshData)); + } + if (m_prevTexStartTime != -1) { + m_data.insert(insert(m_prevTexStartTime, modelManager()->traceEnd() - m_prevTexStartTime, + TextureMemoryConsumption), + Item(TextureMemoryConsumption, m_prevTexData)); + } + computeNesting(); setCollapsedRowCount(Constants::QML_MIN_LEVEL + 1); setExpandedRowCount(m_maximumMsgType + 2); QmlProfilerTimelineModel::finalize(); @@ -132,6 +239,10 @@ void Quick3DModel::clear() { m_data.clear(); m_maximumMsgType = -1; + m_prevTexStartTime = -1; + m_prevMeshStartTime = -1; + m_maxMeshSize = 0; + m_maxTextureSize = 0; QmlProfilerTimelineModel::clear(); } diff --git a/src/plugins/qmlprofiler/quick3dmodel.h b/src/plugins/qmlprofiler/quick3dmodel.h index 50bcebcb732..c82a2056ae3 100644 --- a/src/plugins/qmlprofiler/quick3dmodel.h +++ b/src/plugins/qmlprofiler/quick3dmodel.h @@ -36,10 +36,11 @@ class Quick3DModel : public QmlProfilerTimelineModel public: struct Item { - Item(int typeId, int data) : - typeId(typeId), data(data) {} - int typeId; - int data; + Item(int additionalType, quint64 data, bool unload = false) : + additionalType(additionalType), data(data), unload(unload) {} + int additionalType = 0; + quint64 data = 0; + bool unload = false; }; enum MessageType @@ -53,16 +54,21 @@ public: GenerateShader, LoadShader, ParticleUpdate, + + // additional types + MeshMemoryConsumption, + TextureMemoryConsumption }; Quick3DModel(QmlProfilerModelManager *manager, Timeline::TimelineModelAggregator *parent); - int typeId(int index) const override; QRgb color(int index) const override; QVariantList labels() const override; QVariantMap details(int index) const override; int expandedRow(int index) const override; int collapsedRow(int index) const override; + qint64 rowMaxValue(int rowNumber) const override; + float relativeHeight(int index) const override; void loadEvent(const QmlEvent &event, const QmlEventType &type) override; void finalize() override; void clear() override; @@ -70,8 +76,15 @@ public: private: static QString messageType(uint i); + static QString unloadMessageType(uint i); - int m_maximumMsgType; + int m_maximumMsgType = 0; + qint64 m_prevTexStartTime = -1; + qint64 m_prevMeshStartTime = -1; + quint64 m_prevMeshData = 0; + quint64 m_prevTexData = 0; + quint64 m_maxMeshSize = 0; + quint64 m_maxTextureSize = 0; QVector m_data; }; From aac0e8ef6ecca8979cd753b2aaa86301ef2d4bbb Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Wed, 9 Feb 2022 14:14:01 +0100 Subject: [PATCH 47/94] Fix finding python development package for cdb extension Amends e9f3f8cc641a773078ca17c5110587d5c3b717f7 We switched to find_package(Python3 ...) and that doesn't use PYTHON_LIBRARY and PYTHON_INCLUDE_DIR. Simply provide the root path for find_package(Python3 ...). Change-Id: If862151c095af358be5f35d3d8002d77dcd17aa6 Reviewed-by: Christian Stenger --- scripts/build.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/scripts/build.py b/scripts/build.py index 9b1a46c1c4e..2f33b95ff56 100755 --- a/scripts/build.py +++ b/scripts/build.py @@ -126,8 +126,9 @@ def common_cmake_arguments(args): '-G', 'Ninja'] if args.python3: - cmake_args += ['-DPYTHON_EXECUTABLE=' + args.python3] cmake_args += ['-DPython3_EXECUTABLE=' + args.python3] + if args.python_path: + cmake_args += ['-DPython3_ROOT_DIR=' + args.python_path] if args.module_paths: module_paths = [common.to_posix_path(os.path.abspath(fp)) for fp in args.module_paths] @@ -140,11 +141,6 @@ def common_cmake_arguments(args): if not os.environ.get('CC') and not os.environ.get('CXX'): cmake_args += ['-DCMAKE_C_COMPILER=cl', '-DCMAKE_CXX_COMPILER=cl'] - if args.python_path: - python_library = glob.glob(os.path.join(args.python_path, 'libs', 'python??.lib')) - if python_library: - cmake_args += ['-DPYTHON_LIBRARY=' + python_library[0], - '-DPYTHON_INCLUDE_DIR=' + os.path.join(args.python_path, 'include')] pch_option = 'ON' if args.with_pch else 'OFF' cmake_args += ['-DBUILD_WITH_PCH=' + pch_option] From a6fcb4b3ce4e9c323168cb94696f3037d839330d Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Tue, 8 Feb 2022 18:22:14 +0100 Subject: [PATCH 48/94] Tests: Fix crashing of tst_flamegraphview on Windows ...by setting the RHI backend to "opengl". That is preliminary. QQuickWidget will work with other backends such as "d3d11", soon (likely with Qt 6.4). Change-Id: I57e1869e837794fa887894cae0905a548f9e436c Reviewed-by: Christian Stenger --- .../tracing/flamegraphview/tst_flamegraphview.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/auto/tracing/flamegraphview/tst_flamegraphview.cpp b/tests/auto/tracing/flamegraphview/tst_flamegraphview.cpp index cf384e5691e..9e217216870 100644 --- a/tests/auto/tracing/flamegraphview/tst_flamegraphview.cpp +++ b/tests/auto/tracing/flamegraphview/tst_flamegraphview.cpp @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -55,6 +56,8 @@ class tst_FlameGraphView : public QObject public: tst_FlameGraphView() { Utils::setCreatorTheme(&theme); } + static void initMain(); + private slots: void initTestCase(); void testZoom(); @@ -67,6 +70,15 @@ private: DummyTheme theme; }; +void tst_FlameGraphView::initMain() +{ + if (Utils::HostOsInfo::isWindowsHost()) { +#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0) + qputenv("QSG_RHI_BACKEND", "opengl"); +#endif // Qt >= 6.2 + } +} + void tst_FlameGraphView::initTestCase() { model.fill(); From 0b131fae72e98a0630e4a8a739374023224430d5 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 8 Feb 2022 09:41:46 +0100 Subject: [PATCH 49/94] Docker: Use repo + tag for image identification Makes configurations a bit better exchangable (sdktool...). Change-Id: Ia566a516afea2205c973527e02ce5664634ebbdc Reviewed-by: Christian Stenger --- src/plugins/docker/dockerbuildstep.cpp | 12 ++++- src/plugins/docker/dockerdevice.cpp | 70 +++++++++++++++++--------- src/plugins/docker/dockerdevice.h | 5 +- 3 files changed, 60 insertions(+), 27 deletions(-) diff --git a/src/plugins/docker/dockerbuildstep.cpp b/src/plugins/docker/dockerbuildstep.cpp index 52c6c6cf45f..1970147569a 100644 --- a/src/plugins/docker/dockerbuildstep.cpp +++ b/src/plugins/docker/dockerbuildstep.cpp @@ -94,10 +94,20 @@ private: { MacroExpander *expander = target()->kit()->macroExpander(); expander->registerVariable("BuildDevice:DockerImage", - "Build Host Docker Image ID", [=]() -> QString { + "Build Host Docker Image ID", [this] { const DockerDevice *dockerDevice = dockerBuildDevice(); return dockerDevice ? dockerDevice->data().imageId : QString(); }, true); + expander->registerVariable("BuildDevice:DockerRepo", + "Build Host Docker Repo", [this] { + const DockerDevice *dockerDevice = dockerBuildDevice(); + return dockerDevice ? dockerDevice->data().repo : QString(); + }, true); + expander->registerVariable("BuildDevice:DockerTag", + "Build Host Docker Tag", [this] { + const DockerDevice *dockerDevice = dockerBuildDevice(); + return dockerDevice ? dockerDevice->data().tag : QString(); + }, true); return expander; } diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index daba1b235a2..22428aea254 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -307,16 +307,21 @@ public: DockerDeviceData &data = dockerDevice->data(); - auto idLabel = new QLabel(tr("Image ID:")); - m_idLineEdit = new QLineEdit; - m_idLineEdit->setText(data.imageId); - m_idLineEdit->setEnabled(false); - auto repoLabel = new QLabel(tr("Repository:")); m_repoLineEdit = new QLineEdit; m_repoLineEdit->setText(data.repo); m_repoLineEdit->setEnabled(false); + auto tagLabel = new QLabel(tr("Tag:")); + m_tagLineEdit = new QLineEdit; + m_tagLineEdit->setText(data.tag); + m_tagLineEdit->setEnabled(false); + + auto idLabel = new QLabel(tr("Image ID:")); + m_idLineEdit = new QLineEdit; + m_idLineEdit->setText(data.imageId); + m_idLineEdit->setEnabled(false); + auto daemonStateLabel = new QLabel(tr("Daemon state:")); m_daemonReset = new QToolButton; m_daemonReset->setToolTip(tr("Clears detected daemon state. " @@ -399,11 +404,11 @@ public: }; connect(autoDetectButton, &QPushButton::clicked, this, - [this, logView, id = data.id(), dockerDevice, searchPaths] { + [this, logView, data, dockerDevice, searchPaths] { logView->clear(); dockerDevice->updateContainerAccess(); - m_kitItemDetector.autoDetect(id, searchPaths()); + m_kitItemDetector.autoDetect(data.autodetectId(), searchPaths()); if (DockerPlugin::isDaemonRunning().value_or(false) == false) logView->append(tr("Docker daemon appears to be not running.")); @@ -412,21 +417,22 @@ public: updateDaemonStateTexts(); }); - connect(undoAutoDetectButton, &QPushButton::clicked, this, [this, logView, id = data.id()] { + connect(undoAutoDetectButton, &QPushButton::clicked, this, [this, logView, data] { logView->clear(); - m_kitItemDetector.undoAutoDetect(id); + m_kitItemDetector.undoAutoDetect(data.autodetectId()); }); - connect(listAutoDetectedButton, &QPushButton::clicked, this, [this, logView, id = data.id()] { + connect(listAutoDetectedButton, &QPushButton::clicked, this, [this, logView, data] { logView->clear(); - m_kitItemDetector.listAutoDetected(id); + m_kitItemDetector.listAutoDetected(data.autodetectId()); }); using namespace Layouting; Form { - idLabel, m_idLineEdit, Break(), repoLabel, m_repoLineEdit, Break(), + tagLabel, m_tagLineEdit, Break(), + idLabel, m_idLineEdit, Break(), daemonStateLabel, m_daemonReset, m_daemonState, Break(), m_runAsOutsideUser, Break(), #ifdef ALLOW_LOCAL_ACCESS @@ -465,8 +471,9 @@ public: void updateDaemonStateTexts(); private: - QLineEdit *m_idLineEdit; QLineEdit *m_repoLineEdit; + QLineEdit *m_tagLineEdit; + QLineEdit *m_idLineEdit; QToolButton *m_daemonReset; QLabel *m_daemonState; QCheckBox *m_runAsOutsideUser; @@ -496,6 +503,19 @@ Tasks DockerDevice::validate() const } +// DockerDeviceData + +QString DockerDeviceData::dockerId() const +{ + if (repo == "") + return imageId; + + if (tag == "") + return repo; + + return repo + ':' + tag; +} + // DockerDevice DockerDevice::DockerDevice(const DockerDeviceData &data) @@ -506,7 +526,7 @@ DockerDevice::DockerDevice(const DockerDeviceData &data) setDisplayType(tr("Docker")); setOsType(OsTypeOtherUnix); setDefaultDisplayName(tr("Docker Image"));; - setDisplayName(tr("Docker Image \"%1\" (%2)").arg(data.repo).arg(data.imageId)); + setDisplayName(tr("Docker Image \"%1\" (%2)").arg(data.dockerId()).arg(data.imageId)); setAllowEmptyCommand(true); setOpenTerminal([this](const Environment &env, const FilePath &workingDir) { @@ -865,7 +885,7 @@ void DockerDevicePrivate::startContainer() dockerCreate.addArgs({"-v", q->debugDumperPath().toUserOutput() + ':' + dumperPath.path()}); q->setDebugDumperPath(dumperPath); - dockerCreate.addArgs({"--entrypoint", "/bin/sh", m_data.imageId}); + dockerCreate.addArgs({"--entrypoint", "/bin/sh", m_data.dockerId()}); LOG("RUNNING: " << dockerCreate.toUserOutput()); QtcProcess createProcess; @@ -1044,9 +1064,9 @@ const char DockerDeviceMappedPaths[] = "DockerDeviceMappedPaths"; void DockerDevice::fromMap(const QVariantMap &map) { ProjectExplorer::IDevice::fromMap(map); - d->m_data.imageId = map.value(DockerDeviceDataImageIdKey).toString(); d->m_data.repo = map.value(DockerDeviceDataRepoKey).toString(); d->m_data.tag = map.value(DockerDeviceDataTagKey).toString(); + d->m_data.imageId = map.value(DockerDeviceDataImageIdKey).toString(); d->m_data.size = map.value(DockerDeviceDataSizeKey).toString(); d->m_data.useLocalUidGid = map.value(DockerDeviceUseOutsideUser, HostOsInfo::isLinuxHost()).toBool(); @@ -1058,9 +1078,9 @@ void DockerDevice::fromMap(const QVariantMap &map) QVariantMap DockerDevice::toMap() const { QVariantMap map = ProjectExplorer::IDevice::toMap(); - map.insert(DockerDeviceDataImageIdKey, d->m_data.imageId); map.insert(DockerDeviceDataRepoKey, d->m_data.repo); map.insert(DockerDeviceDataTagKey, d->m_data.tag); + map.insert(DockerDeviceDataImageIdKey, d->m_data.imageId); map.insert(DockerDeviceDataSizeKey, d->m_data.size); map.insert(DockerDeviceUseOutsideUser, d->m_data.useLocalUidGid); map.insert(DockerDeviceUseFilePathMapping, d->m_data.useFilePathMapping); @@ -1112,7 +1132,7 @@ FilePath DockerDevice::mapToGlobalPath(const FilePath &pathOnDevice) const } FilePath result; result.setScheme("docker"); - result.setHost(d->m_data.imageId); + result.setHost(d->m_data.dockerId()); result.setPath(pathOnDevice.path()); return result; } @@ -1132,7 +1152,7 @@ QString DockerDevice::mapToDevicePath(const Utils::FilePath &globalPath) const bool DockerDevice::handlesFile(const FilePath &filePath) const { - return filePath.scheme() == "docker" && filePath.host() == d->m_data.imageId; + return filePath.scheme() == "docker" && filePath.host() == d->m_data.dockerId(); } bool DockerDevice::isExecutableFile(const FilePath &filePath) const @@ -1682,7 +1702,7 @@ Environment DockerDevice::systemEnvironment() const void DockerDevice::aboutToBeRemoved() const { KitDetector detector(sharedFromThis()); - detector.undoAutoDetect(d->m_data.id()); + detector.undoAutoDetect(d->m_data.autodetectId()); } void DockerDevicePrivate::fetchSystemEnviroment() @@ -1785,15 +1805,15 @@ public: switch (column) { case 0: if (role == Qt::DisplayRole) - return imageId; + return repo; break; case 1: if (role == Qt::DisplayRole) - return repo; + return tag; break; case 2: if (role == Qt::DisplayRole) - return tag; + return imageId; break; case 3: if (role == Qt::DisplayRole) @@ -1814,7 +1834,7 @@ public: setWindowTitle(DockerDevice::tr("Docker Image Selection")); resize(800, 600); - m_model.setHeader({"Image", "Repository", "Tag", "Size"}); + m_model.setHeader({"Repository", "Tag", "Image", "Size"}); m_view = new TreeView; m_view->setModel(&m_model); @@ -1886,7 +1906,7 @@ public: QTC_ASSERT(item, return {}); auto device = DockerDevice::create(*item); - device->setupId(IDevice::ManuallyAdded, Id::fromString(item->id())); + device->setupId(IDevice::ManuallyAdded, Id::fromString(item->autodetectId())); device->setType(Constants::DOCKER_DEVICE_TYPE); device->setMachineType(IDevice::Hardware); diff --git a/src/plugins/docker/dockerdevice.h b/src/plugins/docker/dockerdevice.h index 9ead0c5c102..6b2cca21a68 100644 --- a/src/plugins/docker/dockerdevice.h +++ b/src/plugins/docker/dockerdevice.h @@ -37,7 +37,10 @@ namespace Internal { class DockerDeviceData { public: - QString id() const { return "docker:" + imageId; } + // Used for "docker run" and for host parts of FilePaths + QString dockerId() const; + // Used as autodetection source string + QString autodetectId() const { return "docker:" + dockerId(); } QString imageId; QString repo; From 3bd96e7e739a3a8decc2f0b1fc9832b7acf5d64d Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Tue, 8 Feb 2022 16:48:02 +0100 Subject: [PATCH 50/94] Doc: Move creating files into a separate topic "New File" is now a separate menu item in the "File" menu. This way the topics are a bit shorter. Task-number: QTCREATORBUG-26610 Change-Id: Iedfc79f196fc9c3b28f8613f7d8a5ed057770b9a Reviewed-by: Reviewed-by: Eike Ziller --- .../creator-only/creator-files-creating.qdoc | 230 ++++++++++++++++++ .../creator-projects-creating.qdoc | 210 +--------------- .../creator-projects-opening.qdoc | 4 +- doc/qtcreator/src/qtcreator-toc.qdoc | 1 + .../creator-file-system-view.qdoc | 6 +- .../user-interface/creator-projects-view.qdoc | 6 +- 6 files changed, 249 insertions(+), 208 deletions(-) create mode 100644 doc/qtcreator/src/projects/creator-only/creator-files-creating.qdoc diff --git a/doc/qtcreator/src/projects/creator-only/creator-files-creating.qdoc b/doc/qtcreator/src/projects/creator-only/creator-files-creating.qdoc new file mode 100644 index 00000000000..72b4ed80305 --- /dev/null +++ b/doc/qtcreator/src/projects/creator-only/creator-files-creating.qdoc @@ -0,0 +1,230 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Creator documentation. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** +****************************************************************************/ + +/*! + \previouspage creator-project-creating.html + \page creator-file-creating.html + \nextpage creator-project-opening.html + + \title Creating Files + + You can use wizard templates to add individual files to your + \l{Creating Projects}{projects}. + The following table lists the wizard templates for creating files. + + \table + \header + \li Category + \li Wizard Template + \li Purpose + \row + \li {1,3} C/C++ + \li C++ Class + \li C++ header and source file for a new class that you can add to + a C++ project. + \row + \li C/C++ Source File + \li C++ source file that you can add to a C++ project. + \row + \li C/C++ Header File + \li C++ header file that you can add to a C++ project. + \row + \li {1,3} Modeling + \li State Chart + \li State Chart XML (SCXML) file that contains boilerplate + code for state machines. You can use the classes in the + \l {Qt SCXML} module to embed state machines created from + the files in Qt applications. + \row + \li Model + \li Universal Modeling Language (UML) style model with a structured + diagram. However, the model editor uses a variant of UML and + provides only a subset of properties for specifying the + appearance of model elements. For more information, see + \l {Modeling}. + \row + \li Scratch Model + \li Scratch model using a temporary file. + \row + \li {1,7} Qt + \li Qt Item Model + \li Source and header files that you can use to create classes + derived from QAbstractItemModel, QAbstractTableModel, or + QAbstractListModel. + \row + \li \QD Form Class + \li \QD form and a matching class for implementing a UI based + on Qt widgets. + \row + \li \QD Form + \li \QD form for Qt widget based projects. This is useful + if you already have an existing class for the UI logic. + \row + \li Qt Resource File + \li Resource file for storing binary files in the application + executable. + \row + \li QML File (Qt Quick 2) + \li QML file that imports Qt Quick 2.0 for use in Qt Quick projects. + \row + \li Qt Quick UI File + \li \l{UI Files}{UI file} (\e .ui.qml) and the corresponding + implementation file (\e .qml) for use in Qt Quick projects. + \row + \li JS File + \li JavaScript file that you can use to write the application logic + in Qt Quick projects. + \row + \li {1,4} GLSL + \li Fragment Shader (OpenGL/ES 2.0) + \li Fragment shader that generates the final pixel colors for + triangles, points, and lines rendered with OpenGL. You can use + it in both Qt Quick projects and Qt widget based projects. + \row + \li Vertex Shader (OpenGL/ES 2.0) + \li Vertex shader that transforms the positions, normals, and + texture coordinates of triangles, points, and lines rendered + with OpenGL. You can use it in both Qt Quick projects and Qt + widget based projects. + \row + \li Fragment Shader (Desktop OpenGL) + \li Fragment shader for use in both Qt Quick projects and Qt + widget based projects. + \row + \li Vertex Shader (Desktop OpenGL) + \li Vertex shader for use in both Qt Quick projects and Qt + widget based projects. + \row + \li {1,2} General + \li Empty File + \li Empty file that you can save with any filename extensio. + \row + \li Scratch Buffer + \li Scratch buffer that uses temporary files. You can + create this type of files for temporarily storing information + that you do not intend to save + \row + \li Java + \li Java File + \li Java class files that you can use to create Java classes. + \row + \li {1,2} Python + \li Python Class + \li Python class file. + \row + \li Python File + \li Python script file using UTF-8 encoding. + \row + \li {1,2} Nim (experimental) + \li Nim Script File + \li Empty Nim script file using UTF-8 encoding. + \row + \li Nim File + \li Empty Nim source file using UTF-8 encoding. + \endtable + + \section1 Creating C++ Classes + + The \uicontrol {C++ Class Wizard} allows you to create a C++ header and source + file for a new class that you can add to a C++ project. Specify the class + name, base class, and header and source files for the class. + + The wizard supports namespaces. To use a namespace, enter a qualified + class name in the \uicontrol {Class name} field. For example: + \c MyNamespace::MySubNamespace::MyClass. The wizard suggests + existing namespaces and class names as you type. + + \image qtcreator-cpp-class-wizard.png "Enter Class Name dialog" + + The names of the header and source file are based on the class name. To + change the default suffix of a file, select \uicontrol Tools > \uicontrol Options > + \uicontrol {C++} > \uicontrol {File Naming}. + + \image qtcreator-options-cpp-files.png "File Naming tab in Options" + + In the \uicontrol {License template} field, you can use + \l{Using Variables in Wizards}{predefined wizard variables} to specify the + path and filename of the license to use in the source and header files. + + You can create your own project and class wizards. For more information, + see \l{Adding New Custom Wizards}. + + \section1 Creating Resource Files + + \QC supports the \l{The Qt Resource System}{Qt Resource System}, which is a + platform-independent mechanism for storing files in the application's + executable. + + \image qtcreator-add-resource-wizard.png "New File dialog" + + The wizard creates a resource collection file (.qrc) that you can manage in + the resource editor. + + \image qtcreator-add-resource.png "Editing resource files" + + Select \uicontrol {Add Files} to locate and add individual + files. + + To list the folders and files in ascending alphabetic order in the source + tree, select \uicontrol {Sort Alphabetically} in the context menu. + + By default, resources are accessible in the application under the same file + name as they have in the source tree, with a \c{:/} prefix, or by a URL with + a \c qrc scheme. To specify a path prefix for all files in the \c .qrc file, + select \uicontrol {Add Prefix} and enter the prefix in the \uicontrol Prefix + field. + + Some resources need to change based on the user's locale, such as + translation files or icons. You can specify a locale in the + \uicontrol Language field. + + Select \uicontrol Remove to remove the selected file from the resource + collection. In the \uicontrol {Remove File} dialog, select the + \uicontrol {Delete file permanently} check box to remove the file from + the file system. To remove files that cannot be found in the file system, + select \uicontrol {Remove Missing Files}. + + The above functions are also available in the context menu in the + \uicontrol Projects view. + + \section1 Creating OpenGL Fragment and Vertex Shaders + + Qt provides support for integration with OpenGL implementations on all + platforms, which allows you to display hardware accelerated 3D graphics + alongside a more conventional user interface. For more information, see + \l{Qt GUI}. + + You can use the QOpenGLShader class to compile OpenGL shaders written in the + OpenGL Shading Language (GLSL) and in the OpenGL/ES Shading Language + (GLSL/ES). QOpenGLShader and QOpenGLShaderProgram shelter you from the + details of + compiling and linking vertex and fragment shaders. + + You can use \QC code editor to write fragment and vertex shaders + in GLSL or GLSL/ES. The code editor provides syntax highlighting and code + completion for the files. + + \image qtcreator-new-opengl-file.png "New OpenGL file wizard" +*/ diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-creating.qdoc b/doc/qtcreator/src/projects/creator-only/creator-projects-creating.qdoc index a7c9f9a6d61..24b30b4a4c8 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-projects-creating.qdoc +++ b/doc/qtcreator/src/projects/creator-only/creator-projects-creating.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2022 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Creator documentation. @@ -32,7 +32,7 @@ /*! \previouspage creator-project-managing.html \page creator-project-creating.html - \nextpage creator-project-opening.html + \nextpage creator-file-creating.html \title Creating Projects @@ -239,206 +239,7 @@ \include creator-python-project.qdocinc python project wizards - \section1 Adding Files to Projects - - You can use wizards also to add individual files to your projects. - The following table lists the wizard templates for creating files. - - \table - \header - \li Category - \li Wizard Template - \li Purpose - \row - \li {1,3} C/C++ - \li C++ Class - \li C++ header and source file for a new class that you can add to - a C++ project. - \row - \li C/C++ Source File - \li C++ source file that you can add to a C++ project. - \row - \li C/C++ Header File - \li C++ header file that you can add to a C++ project. - \row - \li {1,3} Modeling - \li State Chart - \li State Chart XML (SCXML) file that contains boilerplate - code for state machines. You can use the classes in the - \l {Qt SCXML} module to embed state machines created from - the files in Qt applications. - \row - \li Model - \li Universal Modeling Language (UML) style model with a structured - diagram. However, the model editor uses a variant of UML and - provides only a subset of properties for specifying the - appearance of model elements. For more information, see - \l {Modeling}. - \row - \li Scratch Model - \li Scratch model using a temporary file. - \row - \li {1,7} Qt - \li Qt Item Model - \li Source and header files that you can use to create classes - derived from QAbstractItemModel, QAbstractTableModel, or - QAbstractListModel. - \row - \li \QD Form Class - \li \QD form and a matching class for implementing a UI based - on Qt widgets. - \row - \li \QD Form - \li \QD form for Qt widget based projects. This is useful - if you already have an existing class for the UI logic. - \row - \li Qt Resource File - \li Resource file for storing binary files in the application - executable. - \row - \li QML File (Qt Quick 2) - \li QML file that imports Qt Quick 2.0 for use in Qt Quick projects. - \row - \li Qt Quick UI File - \li \l{UI Files}{UI file} (\e .ui.qml) and the corresponding - implementation file (\e .qml) for use in Qt Quick projects. - \row - \li JS File - \li JavaScript file that you can use to write the application logic - in Qt Quick projects. - \row - \li {1,4} GLSL - \li Fragment Shader (OpenGL/ES 2.0) - \li Fragment shader that generates the final pixel colors for - triangles, points, and lines rendered with OpenGL. You can use - it in both Qt Quick projects and Qt widget based projects. - \row - \li Vertex Shader (OpenGL/ES 2.0) - \li Vertex shader that transforms the positions, normals, and - texture coordinates of triangles, points, and lines rendered - with OpenGL. You can use it in both Qt Quick projects and Qt - widget based projects. - \row - \li Fragment Shader (Desktop OpenGL) - \li Fragment shader for use in both Qt Quick projects and Qt - widget based projects. - \row - \li Vertex Shader (Desktop OpenGL) - \li Vertex shader for use in both Qt Quick projects and Qt - widget based projects. - \row - \li {1,2} General - \li Empty File - \li Empty file that you can save with any filename extensio. - \row - \li Scratch Buffer - \li Scratch buffer that uses temporary files. You can - create this type of files for temporarily storing information - that you do not intend to save - \row - \li Java - \li Java File - \li Java class files that you can use to create Java classes. - \row - \li {1,2} Python - \li Python Class - \li Python class file. - \row - \li Python File - \li Python script file using UTF-8 encoding. - \row - \li {1,2} Nim (experimental) - \li Nim Script File - \li Empty Nim script file using UTF-8 encoding. - \row - \li Nim File - \li Empty Nim source file using UTF-8 encoding. - \endtable - - \section2 Creating C++ Classes - - The \uicontrol {C++ Class Wizard} allows you to create a C++ header and source - file for a new class that you can add to a C++ project. Specify the class - name, base class, and header and source files for the class. - - The wizard supports namespaces. To use a namespace, enter a qualified - class name in the \uicontrol {Class name} field. For example: - \c MyNamespace::MySubNamespace::MyClass. The wizard suggests - existing namespaces and class names as you type. - - \image qtcreator-cpp-class-wizard.png "Enter Class Name dialog" - - The names of the header and source file are based on the class name. To - change the default suffix of a file, select \uicontrol Tools > \uicontrol Options > - \uicontrol {C++} > \uicontrol {File Naming}. - - \image qtcreator-options-cpp-files.png "File Naming tab in Options" - - In the \uicontrol {License template} field, you can use - \l{Using Variables in Wizards}{predefined wizard variables} to specify the - path and filename of the license to use in the source and header files. - - You can create your own project and class wizards. For more information, - see \l{Adding New Custom Wizards}. - - \section2 Creating Resource Files - - \QC supports the \l{The Qt Resource System}{Qt Resource System}, which is a - platform-independent mechanism for storing files in the application's - executable. - - \image qtcreator-add-resource-wizard.png "New File dialog" - - The wizard creates a resource collection file (.qrc) that you can manage in - the resource editor. - - \image qtcreator-add-resource.png "Editing resource files" - - Select \uicontrol {Add Files} to locate and add individual - files. - - To list the folders and files in ascending alphabetic order in the source - tree, select \uicontrol {Sort Alphabetically} in the context menu. - - By default, resources are accessible in the application under the same file - name as they have in the source tree, with a \c{:/} prefix, or by a URL with - a \c qrc scheme. To specify a path prefix for all files in the \c .qrc file, - select \uicontrol {Add Prefix} and enter the prefix in the \uicontrol Prefix - field. - - Some resources need to change based on the user's locale, such as - translation files or icons. You can specify a locale in the - \uicontrol Language field. - - Select \uicontrol Remove to remove the selected file from the resource - collection. In the \uicontrol {Remove File} dialog, select the - \uicontrol {Delete file permanently} check box to remove the file from - the file system. To remove files that cannot be found in the file system, - select \uicontrol {Remove Missing Files}. - - The above functions are also available in the context menu in the - \uicontrol Projects view. - - \section2 Creating OpenGL Fragment and Vertex Shaders - - Qt provides support for integration with OpenGL implementations on all - platforms, which allows you to display hardware accelerated 3D graphics - alongside a more conventional user interface. For more information, see - \l{Qt GUI}. - - You can use the QOpenGLShader class to compile OpenGL shaders written in the - OpenGL Shading Language (GLSL) and in the OpenGL/ES Shading Language - (GLSL/ES). QOpenGLShader and QOpenGLShaderProgram shelter you from the - details of - compiling and linking vertex and fragment shaders. - - You can use \QC code editor to write fragment and vertex shaders - in GLSL or GLSL/ES. The code editor provides syntax highlighting and code - completion for the files. - - \image qtcreator-new-opengl-file.png "New OpenGL file wizard" - - \section2 Displaying Additional File Types in Projects View + \section1 Displaying Additional File Types in Projects View \QC displays all files that are declared to be part of the project by the project files in the \l Projects view. The files are sorted into categories @@ -448,7 +249,7 @@ Alternatively, you can see all the files in a project in the \l {File System} view. - \section3 CMake Projects + \section2 CMake Projects When using CMake, you can specify additional files to display in the \uicontrol Projects view by either adding them as sources or installing @@ -470,7 +271,7 @@ Alternatively, to install the files, use the \l {CMake: install command} {install} command with the \c FILES or \c DIRECTORY property. - \section3 qmake Projects + \section2 qmake Projects When using qmake, add filenames as values of the \c {DISTFILES} variable in the .pro file. You can also use wildcards. @@ -550,6 +351,7 @@ \section1 Related Topics \list + \li \l{Creating Files} \li \l{Opening Projects} \li \l{Adding Libraries to Projects} \li \l{Adding New Custom Wizards} diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-opening.qdoc b/doc/qtcreator/src/projects/creator-only/creator-projects-opening.qdoc index 1b54b8d8ac0..e6280066895 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-projects-opening.qdoc +++ b/doc/qtcreator/src/projects/creator-only/creator-projects-opening.qdoc @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2020 The Qt Company Ltd. +** Copyright (C) 2022 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Creator documentation. @@ -31,7 +31,7 @@ // ********************************************************************** /*! - \previouspage creator-project-creating.html + \previouspage creator-file-creating.html \page creator-project-opening.html \nextpage creator-project-qmake-libraries.html diff --git a/doc/qtcreator/src/qtcreator-toc.qdoc b/doc/qtcreator/src/qtcreator-toc.qdoc index ed38c906cf1..23bc02bec20 100644 --- a/doc/qtcreator/src/qtcreator-toc.qdoc +++ b/doc/qtcreator/src/qtcreator-toc.qdoc @@ -58,6 +58,7 @@ \list \li \l{Creating Projects} \list + \li \l{Creating Files} \li \l{Opening Projects} \li \l{Adding Libraries to Projects} \li \l{Adding New Custom Wizards} diff --git a/doc/qtcreator/src/user-interface/creator-file-system-view.qdoc b/doc/qtcreator/src/user-interface/creator-file-system-view.qdoc index 60db096f2c8..22babb5026e 100644 --- a/doc/qtcreator/src/user-interface/creator-file-system-view.qdoc +++ b/doc/qtcreator/src/user-interface/creator-file-system-view.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2022 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Creator documentation. @@ -83,7 +83,11 @@ line endings, indentation, owner, size, last read and modified dates, and permissions. \li Create new files. For more information, see + \if defined(qtdesignstudio) \l{Adding Files to Projects}. + \else + \l{Creating Files}. + \endif \li Rename or remove existing files. \li Create new folders. \li Compare the selected file with the currently open file in the diff diff --git a/doc/qtcreator/src/user-interface/creator-projects-view.qdoc b/doc/qtcreator/src/user-interface/creator-projects-view.qdoc index 87021c3aa8c..94acded57c3 100644 --- a/doc/qtcreator/src/user-interface/creator-projects-view.qdoc +++ b/doc/qtcreator/src/user-interface/creator-projects-view.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2022 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Creator documentation. @@ -79,7 +79,11 @@ \li Set a project as the active project. \li Execute the \uicontrol Build menu commands. \li Create new files. For more information, see + \if defined(qtdesignstudio) \l{Adding Files to Projects}. + \else + \l{Creating Files}. + \endif \li Rename or remove existing files. If you change the base name of a file, \QC displays a list of other files with the same base name and offers to rename them as well. From cea31a2c4f16a8cdba279b2834cc3f795b22cf13 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Wed, 9 Feb 2022 13:37:05 +0100 Subject: [PATCH 51/94] QmlDesigner: Add cache for instances When detaching the NodeInstanceView from a model we insert all instances for this model into a cache. The cache currently takes a maximum of 20 models. If the model is reattached we use the existing instances, instead of creating new ones. We also recycle the state previews. Outdated data will be overridden by new data once the puppet is sending the respective commands. Task-number: QDS-6121 Change-Id: I15b5628afc5579ba8a03dca23ba5809e55022f3d Reviewed-by: Marco Bubke Reviewed-by: --- .../designercore/include/modelcache.h | 81 +++++++++++++++++++ .../designercore/include/nodeinstanceview.h | 19 +++++ .../instances/nodeinstanceview.cpp | 45 ++++++++++- 3 files changed, 141 insertions(+), 4 deletions(-) create mode 100644 src/plugins/qmldesigner/designercore/include/modelcache.h diff --git a/src/plugins/qmldesigner/designercore/include/modelcache.h b/src/plugins/qmldesigner/designercore/include/modelcache.h new file mode 100644 index 00000000000..bd4704294dd --- /dev/null +++ b/src/plugins/qmldesigner/designercore/include/modelcache.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include + +#include + +#include + +#include +#include + +namespace QmlDesigner { + +template +class ModelCache +{ +public: + ModelCache(int max = 20) + : m_maxEntries(max) + {} + + void insert(Model *model, const DataType &data) + { + QObject::connect(model, &Model::destroyed, [this](QObject *o) { + QObject *deletedModel = o; + + if (deletedModel) { + m_content.remove(deletedModel); + m_queue.removeAll(deletedModel); + } + }); + + m_content.insert(model, data); + if (!m_queue.contains(model)) + m_queue.append(model); + if (m_queue.length() > m_maxEntries) { + QObject *first = m_queue.takeFirst(); + m_content.remove(first); + } + } + + Utils::optional take(Model *model) + { + if (!m_content.contains(model)) + return {}; + m_queue.removeOne(model); + return m_content.take(model); + } + +private: + QHash m_content; + QQueue m_queue; + int m_maxEntries = 20; +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h b/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h index e29498e1438..48ecd4119f6 100644 --- a/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h +++ b/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h @@ -27,6 +27,7 @@ #include "qmldesignercorelib_global.h" #include "abstractview.h" +#include "modelcache.h" #include #include @@ -232,11 +233,29 @@ private: // functions PropertyChangeFlags flags); private: + struct NodeInstanceCacheData + { + NodeInstanceCacheData(const QHash &i, + const QHash &p) + : instances(i) + , previewImages(p) + {} + + NodeInstanceCacheData() = default; + + QHash instances; + QHash previewImages; + }; + + QList loadInstancesFromCache(const QList &nodeList, + const NodeInstanceCacheData &cache); + QHash m_imageDataMap; NodeInstance m_rootNodeInstance; NodeInstance m_activeStateInstance; QHash m_nodeInstanceHash; + ModelCache m_nodeInstanceCache; QHash m_statePreviewImage; ConnectionManagerInterface &m_connectionManager; std::unique_ptr m_nodeInstanceServer; diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp index 5b83b637953..48391fe4b9c 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp @@ -265,6 +265,9 @@ void NodeInstanceView::modelAboutToBeDetached(Model * model) { m_connectionManager.setCrashCallback({}); + m_nodeInstanceCache.insert(model, + NodeInstanceCacheData(m_nodeInstanceHash, m_statePreviewImage)); + removeAllInstanceNodeRelationships(); if (m_nodeInstanceServer) { m_nodeInstanceServer->clearScene(createClearSceneCommand()); @@ -935,10 +938,16 @@ CreateSceneCommand NodeInstanceView::createCreateSceneCommand() QList nodeList = allModelNodes(); QList instanceList; - for (const ModelNode &node : std::as_const(nodeList)) { - NodeInstance instance = loadNode(node); - if (!isSkippedNode(node)) - instanceList.append(instance); + Utils::optional oldNodeInstanceHash = m_nodeInstanceCache.take(model()); + if (oldNodeInstanceHash + && oldNodeInstanceHash->instances.value(rootModelNode()).isValid()) { + instanceList = loadInstancesFromCache(nodeList, oldNodeInstanceHash.value()); + } else { + for (const ModelNode &node : std::as_const(nodeList)) { + NodeInstance instance = loadNode(node); + if (!isSkippedNode(node)) + instanceList.append(instance); + } } nodeList = filterNodesForSkipItems(nodeList); @@ -1942,4 +1951,32 @@ void NodeInstanceView::maybeResetOnPropertyChange(const PropertyName &name, cons resetPuppet(); } +QList NodeInstanceView::loadInstancesFromCache(const QList &nodeList, + const NodeInstanceCacheData &cache) +{ + QList instanceList; + + auto previews = cache.previewImages; + auto iterator = previews.begin(); + while (iterator != previews.end()) { + if (iterator.key().isValid()) + m_statePreviewImage.insert(iterator.key(), iterator.value()); + iterator++; + } + + for (const ModelNode &node : std::as_const(nodeList)) { + NodeInstance instance = cache.instances.value(node); + if (instance.isValid()) + insertInstanceRelationships(instance); + else + instance = loadNode(node); + + if (node.isRootNode()) + m_rootNodeInstance = instance; + if (!isSkippedNode(node)) + instanceList.append(instanceForModelNode(node)); + } + + return instanceList; } +} // namespace QmlDesigner From b36bba03ba260afc2d117f3a9ae84067f250a2ee Mon Sep 17 00:00:00 2001 From: Knud Dollereder Date: Tue, 8 Feb 2022 12:59:50 +0100 Subject: [PATCH 52/94] QmlDesigner: Improve performance of ConnectionManager This is a pertial cherry-pick from master. See commit: b9d59edeb16675c3c1442b36c63c156cd8236d04 I removed the changes to the process deletion. This requires an extra cleanup patch in master. Change-Id: If845ea44f483c5d3c646595ff9298bcdd3dfd59a Reviewed-by: Qt CI Bot Reviewed-by: Thomas Hartmann --- .../instances/connectionmanager.cpp | 30 ++++++++----------- .../instances/connectionmanager.h | 2 -- .../instances/connectionmanagerinterface.cpp | 2 ++ .../instances/connectionmanagerinterface.h | 2 ++ 4 files changed, 17 insertions(+), 19 deletions(-) diff --git a/src/plugins/qmldesigner/designercore/instances/connectionmanager.cpp b/src/plugins/qmldesigner/designercore/instances/connectionmanager.cpp index 7db7913c569..eb994376ea0 100644 --- a/src/plugins/qmldesigner/designercore/instances/connectionmanager.cpp +++ b/src/plugins/qmldesigner/designercore/instances/connectionmanager.cpp @@ -53,17 +53,18 @@ void ConnectionManager::setUp(NodeInstanceServerInterface *nodeInstanceServerPro { BaseConnectionManager::setUp(nodeInstanceServerProxy, qrcMappingString, target, view); - m_localServer = std::make_unique(); - QString socketToken(QUuid::createUuid().toString()); - m_localServer->listen(socketToken); - m_localServer->setMaxPendingConnections(3); - PuppetCreator puppetCreator(target, view->model()); puppetCreator.setQrcMappingString(qrcMappingString); puppetCreator.createQml2PuppetExecutableIfMissing(); for (Connection &connection : m_connections) { + + QString socketToken(QUuid::createUuid().toString()); + connection.localServer = std::make_unique(); + connection.localServer->listen(socketToken); + connection.localServer->setMaxPendingConnections(1); + connection.qmlPuppetProcess = puppetCreator.createPuppetProcess( connection.mode, socketToken, @@ -71,10 +72,11 @@ void ConnectionManager::setUp(NodeInstanceServerInterface *nodeInstanceServerPro [&](int exitCode, QProcess::ExitStatus exitStatus) { processFinished(exitCode, exitStatus, connection.name); }); + } - const int second = 1000; + const int second = 1000; + for (Connection &connection : m_connections) { int waitConstant = 8 * second; - if (!connection.qmlPuppetProcess->waitForStarted(waitConstant)) { closeSocketsAndKillProcesses(); showCannotConnectToPuppetWarningAndSwitchToEditMode(); @@ -84,11 +86,11 @@ void ConnectionManager::setUp(NodeInstanceServerInterface *nodeInstanceServerPro waitConstant /= 2; bool connectedToPuppet = true; - if (!m_localServer->hasPendingConnections()) - connectedToPuppet = m_localServer->waitForNewConnection(waitConstant); + if (!connection.localServer->hasPendingConnections()) + connectedToPuppet = connection.localServer->waitForNewConnection(waitConstant); if (connectedToPuppet) { - connection.socket.reset(m_localServer->nextPendingConnection()); + connection.socket.reset(connection.localServer->nextPendingConnection()); QObject::connect(connection.socket.get(), &QIODevice::readyRead, this, [&] { readDataStream(connection); }); @@ -97,9 +99,8 @@ void ConnectionManager::setUp(NodeInstanceServerInterface *nodeInstanceServerPro showCannotConnectToPuppetWarningAndSwitchToEditMode(); return; } + connection.localServer->close(); } - - m_localServer->close(); } void ConnectionManager::shutDown() @@ -107,11 +108,6 @@ void ConnectionManager::shutDown() BaseConnectionManager::shutDown(); closeSocketsAndKillProcesses(); - - m_localServer.reset(); - - for (Connection &connection : m_connections) - connection.clear(); } void ConnectionManager::writeCommand(const QVariant &command) diff --git a/src/plugins/qmldesigner/designercore/instances/connectionmanager.h b/src/plugins/qmldesigner/designercore/instances/connectionmanager.h index 4f25724adba..604f787ede2 100644 --- a/src/plugins/qmldesigner/designercore/instances/connectionmanager.h +++ b/src/plugins/qmldesigner/designercore/instances/connectionmanager.h @@ -70,8 +70,6 @@ private: void closeSocketsAndKillProcesses(); private: - std::unique_ptr m_localServer; - std::vector m_connections; quint32 m_writeCommandCounter = 0; }; diff --git a/src/plugins/qmldesigner/designercore/instances/connectionmanagerinterface.cpp b/src/plugins/qmldesigner/designercore/instances/connectionmanagerinterface.cpp index 43ff7f48a28..a0d578aa4de 100644 --- a/src/plugins/qmldesigner/designercore/instances/connectionmanagerinterface.cpp +++ b/src/plugins/qmldesigner/designercore/instances/connectionmanagerinterface.cpp @@ -26,6 +26,7 @@ #include "connectionmanagerinterface.h" #include +#include #include namespace QmlDesigner { @@ -45,6 +46,7 @@ void ConnectionManagerInterface::Connection::clear() { qmlPuppetProcess.reset(); socket.reset(); + localServer.reset(); blockSize = 0; lastReadCommandCounter = 0; timer.reset(); diff --git a/src/plugins/qmldesigner/designercore/instances/connectionmanagerinterface.h b/src/plugins/qmldesigner/designercore/instances/connectionmanagerinterface.h index ce4206ca981..1edaf7f7306 100644 --- a/src/plugins/qmldesigner/designercore/instances/connectionmanagerinterface.h +++ b/src/plugins/qmldesigner/designercore/instances/connectionmanagerinterface.h @@ -30,6 +30,7 @@ QT_BEGIN_NAMESPACE class QLocalSocket; +class QLocalServer; QT_END_NAMESPACE namespace ProjectExplorer { @@ -59,6 +60,7 @@ public: QString mode; QProcessUniquePointer qmlPuppetProcess; std::unique_ptr socket; + std::unique_ptr localServer; quint32 blockSize = 0; quint32 lastReadCommandCounter = 0; std::unique_ptr timer; From d40872602336511c0aff0d9ec4a8a43b203e184a Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 9 Feb 2022 15:06:42 +0100 Subject: [PATCH 53/94] Tests: Include flamegraphview test Change-Id: Id30d171d43c7b5adf5bb7b45fda99364662c93be Reviewed-by: Alessandro Portale --- tests/auto/tracing/flamegraphview/flamegraphview.qbs | 1 + tests/auto/tracing/tracing.qbs | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/auto/tracing/flamegraphview/flamegraphview.qbs b/tests/auto/tracing/flamegraphview/flamegraphview.qbs index 0be52f5d7ab..711e955014f 100644 --- a/tests/auto/tracing/flamegraphview/flamegraphview.qbs +++ b/tests/auto/tracing/flamegraphview/flamegraphview.qbs @@ -4,6 +4,7 @@ import "../tracingautotest.qbs" as TracingAutotest TracingAutotest { name: "FlameGraphView autotest" + Depends { name: "Utils" } Depends { name: "Qt.quickwidgets" } Group { diff --git a/tests/auto/tracing/tracing.qbs b/tests/auto/tracing/tracing.qbs index 643d25f31ab..84000d731fe 100644 --- a/tests/auto/tracing/tracing.qbs +++ b/tests/auto/tracing/tracing.qbs @@ -5,6 +5,7 @@ Project { references: [ "flamegraph/flamegraph.qbs", + "flamegraphview/flamegraphview.qbs", "timelinemodel/timelinemodel.qbs", "timelinemodelaggregator/timelinemodelaggregator.qbs", "timelinenotesmodel/timelinenotesmodel.qbs", From bafea94402431ff07f2f511056851a1e1d83072b Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 9 Feb 2022 09:58:48 +0100 Subject: [PATCH 54/94] Clangd: Fix possible crash in inspector When fast switching between clients listed inside the inspector the message response for memory usage may arrive after the model has been destroyed. Change-Id: I0503bb334cf21b0919316f0ac2e731472f3433bd Reviewed-by: David Schulz --- src/plugins/clangcodemodel/clangdclient.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index 78d3793b502..97d0799b862 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -1074,6 +1074,7 @@ class MemoryUsageWidget : public QWidget Q_DECLARE_TR_FUNCTIONS(MemoryUsageWidget) public: MemoryUsageWidget(ClangdClient *client); + ~MemoryUsageWidget(); private: void setupUi(); @@ -1082,6 +1083,7 @@ private: ClangdClient * const m_client; MemoryTreeModel * const m_model; Utils::TreeView m_view; + Utils::optional m_currentRequest; }; class ClangdClient::Private @@ -3959,6 +3961,12 @@ MemoryUsageWidget::MemoryUsageWidget(ClangdClient *client) getMemoryTree(); } +MemoryUsageWidget::~MemoryUsageWidget() +{ + if (m_currentRequest.has_value()) + m_client->cancelRequest(m_currentRequest.value()); +} + void MemoryUsageWidget::setupUi() { const auto layout = new QVBoxLayout(this); @@ -3978,11 +3986,13 @@ void MemoryUsageWidget::getMemoryTree() { Request request("$/memoryUsage", {}); request.setResponseCallback([this](decltype(request)::Response response) { + m_currentRequest.reset(); qCDebug(clangdLog) << "received memory usage response"; if (const auto result = response.result()) m_model->update(*result); }); qCDebug(clangdLog) << "sending memory usage request"; + m_currentRequest = request.id(); m_client->sendContent(request, ClangdClient::SendDocUpdates::Ignore); } From 08c25aef25a2582ac3c9a9e36ccb7cf3f3256da3 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Wed, 9 Feb 2022 09:52:07 +0100 Subject: [PATCH 55/94] TextEditor: Fix High-DPI+Qt6 drawing of the refactor marker icon Subtle devicePixelRatio-related changes in Qt require to restrict one division by a Qt 5 specific #ifdef. Fixes: QTCREATORBUG-26905 Change-Id: Ic5eecef5c7cb355abc8a5391708c5cd1050af282 Reviewed-by: Reviewed-by: David Schulz --- src/plugins/texteditor/refactoroverlay.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/plugins/texteditor/refactoroverlay.cpp b/src/plugins/texteditor/refactoroverlay.cpp index 2906ef045cc..5c1c56ad7e6 100644 --- a/src/plugins/texteditor/refactoroverlay.cpp +++ b/src/plugins/texteditor/refactoroverlay.cpp @@ -87,7 +87,10 @@ void RefactorOverlay::paintMarker(const RefactorMarker& marker, QPainter *painte const QSize proposedIconSize = QSize(m_editor->fontMetrics().horizontalAdvance(QLatin1Char(' ')) + 3, cursorRect.height()) * devicePixelRatio; - const QSize actualIconSize = icon.actualSize(proposedIconSize) / devicePixelRatio; + QSize actualIconSize = icon.actualSize(proposedIconSize); +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + actualIconSize /= devicePixelRatio; +#endif // Qt < 6.0 const int y = cursorRect.top() + ((cursorRect.height() - actualIconSize.height()) / 2); const int x = cursorRect.right(); From d61069b90f791e312a1398fb953ad5a940039f60 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Wed, 9 Feb 2022 14:48:28 +0100 Subject: [PATCH 56/94] LanguageClient: Prevent extra frame border around outline view For consistency with other views. Change-Id: I3d495a3bd037fe917c99bf5e9916651ca48c03fd Reviewed-by: Reviewed-by: David Schulz --- src/plugins/languageclient/languageclientoutline.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/languageclient/languageclientoutline.cpp b/src/plugins/languageclient/languageclientoutline.cpp index 8cffbe9b4df..27f4ac263cf 100644 --- a/src/plugins/languageclient/languageclientoutline.cpp +++ b/src/plugins/languageclient/languageclientoutline.cpp @@ -170,6 +170,7 @@ LanguageClientOutlineWidget::LanguageClientOutlineWidget(Client *client, m_view.setModel(&m_model); m_view.setHeaderHidden(true); m_view.setExpandsOnDoubleClick(false); + m_view.setFrameStyle(QFrame::NoFrame); connect(&m_view, &QAbstractItemView::activated, this, &LanguageClientOutlineWidget::onItemActivated); connect(m_editor->editorWidget(), &TextEditor::TextEditorWidget::cursorPositionChanged, From 385367cfd7f83c74b70e50dc36af53d39cb9554b Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 10 Feb 2022 07:53:33 +0100 Subject: [PATCH 57/94] QmlJS: Fix compiulation with namespaces Amends 125d7c0cced77. Change-Id: I75f2c562aca2e3a00bb0284f39c3951664e2c956 Reviewed-by: Christian Stenger --- src/libs/qmljs/parser/qmljsast_p.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libs/qmljs/parser/qmljsast_p.h b/src/libs/qmljs/parser/qmljsast_p.h index 78b9f4b0800..50ab370922a 100644 --- a/src/libs/qmljs/parser/qmljsast_p.h +++ b/src/libs/qmljs/parser/qmljsast_p.h @@ -43,9 +43,11 @@ #include -QT_QML_BEGIN_NAMESPACE - +QT_BEGIN_NAMESPACE class QString; +QT_END_NAMESPACE + +QT_QML_BEGIN_NAMESPACE namespace QmlJS { class Parser; From d59047a4c282503dafdc45d9af15ef9584f04969 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 8 Feb 2022 15:08:26 +0100 Subject: [PATCH 58/94] LanguageClient: do not disconnect client from manager The previously connected signals should be safe to stay connected while the server restarts. This fixes restarting crashed clients more than once. Change-Id: I161d41418e10b7e3bd3e17141720f4a5f399841c Reviewed-by: Christian Stenger --- src/plugins/languageclient/languageclientmanager.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/plugins/languageclient/languageclientmanager.cpp b/src/plugins/languageclient/languageclientmanager.cpp index e76d3ff31b3..cc8b03ea6dc 100644 --- a/src/plugins/languageclient/languageclientmanager.cpp +++ b/src/plugins/languageclient/languageclientmanager.cpp @@ -159,7 +159,6 @@ void LanguageClientManager::clientFinished(Client *client) = managerInstance->m_clientForDocument.keys(client); if (client->reset()) { qCDebug(Log) << "restart unexpectedly finished client: " << client->name() << client; - client->disconnect(managerInstance); client->log( tr("Unexpectedly finished. Restarting in %1 seconds.").arg(restartTimeoutS)); QTimer::singleShot(restartTimeoutS * 1000, client, [client]() { client->start(); }); From a1cc9b4e5c65415242211a7ea62a5bb17fef5676 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 10 Feb 2022 08:26:19 +0100 Subject: [PATCH 59/94] Editor: fix internal cursor position after backspace Fixes: QTCREATORBUG-27035 Change-Id: Id39d8832c5e3327cd42ce10447da98ca78fe476d Reviewed-by: Christian Stenger --- src/plugins/texteditor/texteditor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 731c5ba779e..fd814163a72 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -5889,7 +5889,7 @@ void TextEditorWidgetPrivate::handleBackspaceKey() QTC_ASSERT(!q->multiTextCursor().hasSelection(), return); MultiTextCursor cursor = m_cursors; cursor.beginEditBlock(); - for (QTextCursor c : cursor) { + for (QTextCursor &c : cursor) { const int pos = c.position(); if (!pos) continue; From 105e5910601f6e5bafa6e92fe795075f7b24de71 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 9 Feb 2022 16:25:41 +0100 Subject: [PATCH 60/94] ProjectExplorer: Delay project parsing until it's part of the session E.g. code model logic relies on the session manager knowing about the project currently being parsed. Fixes: QTCREATORBUG-26987 Change-Id: I4d9a1c21ab8474f7ac21edaeebe667fc4f3a6c4e Reviewed-by: hjk Reviewed-by: --- src/plugins/projectexplorer/buildsystem.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/plugins/projectexplorer/buildsystem.cpp b/src/plugins/projectexplorer/buildsystem.cpp index 8382d2d0600..424b49d802c 100644 --- a/src/plugins/projectexplorer/buildsystem.cpp +++ b/src/plugins/projectexplorer/buildsystem.cpp @@ -29,6 +29,7 @@ #include "projectexplorer.h" #include "runconfiguration.h" #include "runcontrol.h" +#include "session.h" #include "target.h" #include @@ -77,7 +78,13 @@ BuildSystem::BuildSystem(Target *target) // Timer: d->m_delayedParsingTimer.setSingleShot(true); - connect(&d->m_delayedParsingTimer, &QTimer::timeout, this, &BuildSystem::triggerParsing); + connect(&d->m_delayedParsingTimer, &QTimer::timeout, this, + [this] { + if (SessionManager::hasProject(project())) + triggerParsing(); + else + requestDelayedParse(); + }); } BuildSystem::~BuildSystem() From 64fee150ef66a67320b05884efbee658454e9a0d Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 9 Feb 2022 12:08:04 +0100 Subject: [PATCH 61/94] ClangCodeModel: Consider whitespace in preprocessor directives ... when highlighting with clangd. That is, treat "# ifdef" the same as "#ifdef". Fixes: QTCREATORBUG-27021 Change-Id: Ic57ed42e09f95611dd85ca3c112e23b52a3f91fc Reviewed-by: Reviewed-by: Qt CI Bot Reviewed-by: David Schulz --- src/plugins/clangcodemodel/clangdclient.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index 97d0799b862..07e8956f0a0 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -2532,7 +2532,7 @@ private: // clangd reports also the #ifs, #elses and #endifs around the disabled code as disabled, // and not even in a consistent manner. We don't want this, so we have to clean up here. // But note that we require this behavior, as otherwise we would not be able to grey out -// e.g. empty lines after an #fdef, due to the lack of symbols. +// e.g. empty lines after an #ifdef, due to the lack of symbols. static QList cleanupDisabledCode(HighlightingResults &results, const QTextDocument *doc, const QString &docContent) { @@ -2558,8 +2558,13 @@ static QList cleanupDisabledCode(HighlightingResults &results, const && !content.startsWith(QLatin1String("#elif")) && !content.startsWith(QLatin1String("#else")) && !content.startsWith(QLatin1String("#endif"))) { - ++it; - continue; + static const QStringList ppSuffixes{"if", "ifdef", "elif", "else", "endif"}; + const QList contentList = content.split(' ', Qt::SkipEmptyParts); + if (contentList.size() < 2 || contentList.first() != QLatin1String("#") + || !ppSuffixes.contains(contentList.at(1))) { + ++it; + continue; + } } if (!wasIfdefedOut) { From d84c5da4e9274858196b984134250009daed2b78 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Thu, 10 Feb 2022 09:22:17 +0100 Subject: [PATCH 62/94] Core: Limit rendering of tag rows in ListItemDelegate Unlimited rows make the tags flow over the lower edge. Two rows should be enough for proper tagging. All tags are still used for searching, even if some are omitted in the rendering. Change-Id: Ia731031f362165c75ef5fa34a80200c85d2f93aa Reviewed-by: Christian Stenger --- src/plugins/coreplugin/welcomepagehelper.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/plugins/coreplugin/welcomepagehelper.cpp b/src/plugins/coreplugin/welcomepagehelper.cpp index d363fdf6656..3519cb9ab58 100644 --- a/src/plugins/coreplugin/welcomepagehelper.cpp +++ b/src/plugins/coreplugin/welcomepagehelper.cpp @@ -522,11 +522,14 @@ void ListItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &opti painter->setPen(themeColor(Theme::Welcome_LinkColor)); m_currentTagRects.clear(); + int emptyTagRowsLeft = 2; int xx = 0; int yy = 0; for (const QString &tag : item->tags) { const int ww = fm.horizontalAdvance(tag) + tagsHorSpacing; if (xx + ww > textArea.width() - tagsLabelRect.width()) { + if (--emptyTagRowsLeft == 0) + break; yy += fm.lineSpacing(); xx = 0; } From a3596e65277fe96d35d0581c06ebf16fac2b6971 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Mon, 7 Feb 2022 16:59:51 +0200 Subject: [PATCH 63/94] QmlDesigner: Fix 3D import crash and import statement insertion Sometimes importing 3D models would crash because null process output callback, so just make an empty dummy callback. Import statement insertion to the qml document for the asset also failed, because new import creation is no longer automatically detected by qmljs, probably due to some optimization. Fixed by explicitly scanning the import target directory for new content. This also allows us to know when scan is completed, so we can reduce mandatory waiting time. Also added check to see when the new imports are available in the model to reduce mandatory waiting for that step, too. Change-Id: I8d8757efea5481e0d3f15add2b93e6f0f5b155cb Reviewed-by: Thomas Hartmann Reviewed-by: Reviewed-by: Mahmoud Badri Reviewed-by: Samuel Ghinet --- .../itemlibrary/itemlibraryassetimporter.cpp | 53 ++++++++++++++----- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp index c65d5256c8d..9c70baa7997 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp @@ -33,7 +33,10 @@ #include "rewritertransaction.h" #include "rewritingexception.h" +#include + #include +#include #include #include @@ -568,7 +571,7 @@ bool ItemLibraryAssetImporter::startImportProcess(const ParseData &pd) QProcessUniquePointer process = puppetCreator.createPuppetProcess( "custom", {}, - std::function(), + [&] {}, [&](int exitCode, QProcess::ExitStatus exitStatus) { importProcessFinished(exitCode, exitStatus); }, @@ -598,7 +601,7 @@ bool ItemLibraryAssetImporter::startIconProcess(int size, const QString &iconFil QProcessUniquePointer process = puppetCreator.createPuppetProcess( "custom", {}, - std::function(), + [&] {}, [&](int exitCode, QProcess::ExitStatus exitStatus) { iconProcessFinished(exitCode, exitStatus); }, @@ -653,6 +656,16 @@ void ItemLibraryAssetImporter::finalizeQuick3DImport() addInfo(progressTitle); notifyProgress(0, progressTitle); + auto modelManager = QmlJS::ModelManagerInterface::instance(); + QFuture result; + if (modelManager) { + QmlJS::PathsAndLanguages pathToScan; + pathToScan.maybeInsert(Utils::FilePath::fromString(m_importPath)); + result = Utils::runAsync(&QmlJS::ModelManagerInterface::importScan, + modelManager->workingCopy(), pathToScan, + modelManager, true, true, true); + } + // First we have to wait a while to ensure qmljs detects new files and updates its // internal model. Then we make a non-change to the document to trigger qmljs snapshot // update. There is an inbuilt delay before rewriter change actually updates the data @@ -661,24 +674,37 @@ void ItemLibraryAssetImporter::finalizeQuick3DImport() QTimer *timer = new QTimer(parent()); static int counter; counter = 0; - timer->callOnTimeout([this, timer, progressTitle, model]() { + timer->callOnTimeout([this, timer, progressTitle, model, result]() { if (!isCancelled()) { - notifyProgress(++counter * 5, progressTitle); - if (counter < 10) { - // Do not proceed while application isn't active as the filesystem - // watcher qmljs uses won't trigger unless application is active - if (QApplication::applicationState() != Qt::ApplicationActive) - --counter; - } else if (counter == 10) { + notifyProgress(++counter, progressTitle); + if (counter < 50) { + if (result.isCanceled() || result.isFinished()) + counter = 49; // skip to next step + } else if (counter == 50) { model->rewriterView()->textModifier()->replace(0, 0, {}); - } else if (counter == 19) { + } else if (counter < 100) { try { + const QList posImports = model->possibleImports(); const QList currentImports = model->imports(); QList newImportsToAdd; + for (auto &imp : qAsConst(m_requiredImports)) { + const bool isPos = Utils::contains(posImports, [imp](const Import &posImp) { + return posImp.url() == imp.url(); + }); + const bool isCur = Utils::contains(currentImports, [imp](const Import &curImp) { + return curImp.url() == imp.url(); + }); + if (!(isPos || isCur)) + return; + // Check again with 'contains' to ensure we insert latest version if (!currentImports.contains(imp)) newImportsToAdd.append(imp); } + if (counter == 99) + addError(tr("Failed to insert import statement into qml document.")); + else + counter = 99; if (!newImportsToAdd.isEmpty()) { RewriterTransaction transaction = model->rewriterView()->beginRewriterTransaction( @@ -689,8 +715,9 @@ void ItemLibraryAssetImporter::finalizeQuick3DImport() } } catch (const RewritingException &e) { addError(tr("Failed to update imports: %1").arg(e.description())); + counter = 99; } - } else if (counter >= 20) { + } else if (counter >= 100) { if (!m_overwrittenImports.isEmpty()) model->rewriterView()->emitCustomNotification("asset_import_update"); timer->stop(); @@ -700,7 +727,7 @@ void ItemLibraryAssetImporter::finalizeQuick3DImport() timer->stop(); } }); - timer->start(100); + timer->start(50); } else { notifyFinished(); } From 6b6b35f59e00fe902daf55ef0dd9d61e38e130ee Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Tue, 1 Feb 2022 14:30:35 +0100 Subject: [PATCH 64/94] Move MCUPackage and MCUToolChain package to separate files Also move `packagePathFromSettings` so it can be used from multiple places. This function will probably move into a separate utility file in future changes. Change-Id: I208a5a7bc8aa689829178809a1f4053a961d93be Reviewed-by: Alessandro Portale Reviewed-by: Reviewed-by: --- src/plugins/mcusupport/CMakeLists.txt | 1 + src/plugins/mcusupport/mcupackage.cpp | 316 ++++++++++++++++++ src/plugins/mcusupport/mcupackage.h | 157 +++++++++ src/plugins/mcusupport/mcusupport.qbs | 2 + src/plugins/mcusupport/mcusupportoptions.cpp | 286 +--------------- src/plugins/mcusupport/mcusupportoptions.h | 112 +------ .../mcusupport/mcusupportoptionspage.cpp | 1 + src/plugins/mcusupport/mcusupportsdk.cpp | 11 + src/plugins/mcusupport/mcusupportsdk.h | 4 + 9 files changed, 498 insertions(+), 392 deletions(-) create mode 100644 src/plugins/mcusupport/mcupackage.cpp create mode 100644 src/plugins/mcusupport/mcupackage.h diff --git a/src/plugins/mcusupport/CMakeLists.txt b/src/plugins/mcusupport/CMakeLists.txt index a85b35b5f9b..bb2b98738de 100644 --- a/src/plugins/mcusupport/CMakeLists.txt +++ b/src/plugins/mcusupport/CMakeLists.txt @@ -8,6 +8,7 @@ add_qtc_plugin(McuSupport mcusupportdevice.cpp mcusupportdevice.h mcusupportoptions.cpp mcusupportoptions.h mcusupportoptionspage.cpp mcusupportoptionspage.h + mcupackage.cpp mcupackage.h mcusupportplugin.cpp mcusupportplugin.h mcusupportsdk.cpp mcusupportsdk.h mcusupportrunconfiguration.cpp mcusupportrunconfiguration.h diff --git a/src/plugins/mcusupport/mcupackage.cpp b/src/plugins/mcusupport/mcupackage.cpp new file mode 100644 index 00000000000..d8f5a2aeb00 --- /dev/null +++ b/src/plugins/mcusupport/mcupackage.cpp @@ -0,0 +1,316 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "mcupackage.h" +#include "mcusupportconstants.h" +#include "mcusupportsdk.h" + +#include +#include +#include +#include + +#include +#include +#include + +using namespace Utils; + +namespace McuSupport { +namespace Internal { + +static bool automaticKitCreationFromSettings(QSettings::Scope scope = QSettings::UserScope) +{ + QSettings *settings = Core::ICore::settings(scope); + const QString key = QLatin1String(Constants::SETTINGS_GROUP) + '/' + + QLatin1String(Constants::SETTINGS_KEY_AUTOMATIC_KIT_CREATION); + bool automaticKitCreation = settings->value(key, true).toBool(); + return automaticKitCreation; +} + +McuPackage::McuPackage(const QString &label, const FilePath &defaultPath, + const QString &detectionPath, const QString &settingsKey, + const McuPackageVersionDetector *versionDetector) + : m_label(label) + , m_defaultPath(Sdk::packagePathFromSettings(settingsKey, QSettings::SystemScope, defaultPath)) + , m_detectionPath(detectionPath) + , m_settingsKey(settingsKey) + , m_versionDetector(versionDetector) +{ + m_path = Sdk::packagePathFromSettings(settingsKey, QSettings::UserScope, m_defaultPath); + m_automaticKitCreation = automaticKitCreationFromSettings(QSettings::UserScope); +} + +FilePath McuPackage::basePath() const +{ + return m_fileChooser != nullptr ? m_fileChooser->filePath() : m_path; +} + +FilePath McuPackage::path() const +{ + return basePath().resolvePath(m_relativePathModifier).absoluteFilePath(); +} + +QString McuPackage::label() const +{ + return m_label; +} + +FilePath McuPackage::defaultPath() const +{ + return m_defaultPath; +} + +QString McuPackage::detectionPath() const +{ + return m_detectionPath; +} + +QWidget *McuPackage::widget() +{ + if (m_widget) + return m_widget; + + m_widget = new QWidget; + m_fileChooser = new PathChooser; + m_fileChooser->lineEdit()->setButtonIcon(FancyLineEdit::Right, + Icons::RESET.icon()); + m_fileChooser->lineEdit()->setButtonVisible(FancyLineEdit::Right, true); + connect(m_fileChooser->lineEdit(), &FancyLineEdit::rightButtonClicked, this, [&] { + m_fileChooser->setFilePath(m_defaultPath); + }); + + auto layout = new QGridLayout(m_widget); + layout->setContentsMargins(0, 0, 0, 0); + m_infoLabel = new InfoLabel(); + + if (!m_downloadUrl.isEmpty()) { + auto downLoadButton = new QToolButton; + downLoadButton->setIcon(Icons::ONLINE.icon()); + downLoadButton->setToolTip(tr("Download from \"%1\"").arg(m_downloadUrl)); + QObject::connect(downLoadButton, &QToolButton::pressed, this, [this] { + QDesktopServices::openUrl(m_downloadUrl); + }); + layout->addWidget(downLoadButton, 0, 2); + } + + layout->addWidget(m_fileChooser, 0, 0, 1, 2); + layout->addWidget(m_infoLabel, 1, 0, 1, -1); + + m_fileChooser->setFilePath(m_path); + + QObject::connect(this, &McuPackage::statusChanged, this, [this] { + updateStatusUi(); + }); + + QObject::connect(m_fileChooser, &PathChooser::pathChanged, this, [this] { + updatePath(); + emit changed(); + }); + + updateStatus(); + return m_widget; +} + +McuPackage::Status McuPackage::status() const +{ + return m_status; +} + +bool McuPackage::validStatus() const +{ + return m_status == McuPackage::ValidPackage || m_status == McuPackage::ValidPackageMismatchedVersion; +} + +void McuPackage::setDownloadUrl(const QString &url) +{ + m_downloadUrl = url; +} + +void McuPackage::setEnvironmentVariableName(const QString &name) +{ + m_environmentVariableName = name; +} + +QString McuPackage::environmentVariableName() const +{ + return m_environmentVariableName; +} + +void McuPackage::setAddToPath(bool addToPath) +{ + m_addToPath = addToPath; +} + +bool McuPackage::addToPath() const +{ + return m_addToPath; +} + +void McuPackage::writeGeneralSettings() const +{ + const QString key = QLatin1String(Constants::SETTINGS_GROUP) + '/' + + QLatin1String(Constants::SETTINGS_KEY_AUTOMATIC_KIT_CREATION); + QSettings *settings = Core::ICore::settings(); + settings->setValue(key, m_automaticKitCreation); +} + +bool McuPackage::writeToSettings() const +{ + const FilePath savedPath = Sdk::packagePathFromSettings(m_settingsKey, QSettings::UserScope, m_defaultPath); + const QString key = QLatin1String(Constants::SETTINGS_GROUP) + '/' + + QLatin1String(Constants::SETTINGS_KEY_PACKAGE_PREFIX) + m_settingsKey; + Core::ICore::settings()->setValueWithDefault(key, m_path.toString(), m_defaultPath.toString()); + + return savedPath != m_path; +} + +void McuPackage::setRelativePathModifier(const QString &path) +{ + m_relativePathModifier = path; +} + +void McuPackage::setVersions(const QStringList &versions) +{ + m_versions = versions; +} + +bool McuPackage::automaticKitCreationEnabled() const +{ + return m_automaticKitCreation; +} + +void McuPackage::setAutomaticKitCreationEnabled(const bool enabled) +{ + m_automaticKitCreation = enabled; +} + +void McuPackage::updatePath() +{ + m_path = m_fileChooser->rawFilePath(); + m_fileChooser->lineEdit()->button(FancyLineEdit::Right)->setEnabled(m_path != m_defaultPath); + updateStatus(); +} + +void McuPackage::updateStatus() +{ + bool validPath = !m_path.isEmpty() && m_path.exists(); + const FilePath detectionPath = basePath() / m_detectionPath; + const bool validPackage = m_detectionPath.isEmpty() || detectionPath.exists(); + m_detectedVersion = validPath && validPackage && m_versionDetector + ? m_versionDetector->parseVersion(basePath().toString()) : QString(); + const bool validVersion = m_detectedVersion.isEmpty() || + m_versions.isEmpty() || m_versions.contains(m_detectedVersion); + + m_status = validPath ? + ( validPackage ? + (validVersion ? ValidPackage : ValidPackageMismatchedVersion) + : ValidPathInvalidPackage ) + : m_path.isEmpty() ? EmptyPath : InvalidPath; + + emit statusChanged(); +} + +void McuPackage::updateStatusUi() +{ + switch (m_status) { + case ValidPackage: m_infoLabel->setType(InfoLabel::Ok); break; + case ValidPackageMismatchedVersion: m_infoLabel->setType(InfoLabel::Warning); break; + default: m_infoLabel->setType(InfoLabel::NotOk); break; + } + m_infoLabel->setText(statusText()); +} + +QString McuPackage::statusText() const +{ + const QString displayPackagePath = m_path.toUserOutput(); + const QString displayVersions = m_versions.join(" or "); + const QString outDetectionPath = FilePath::fromString(m_detectionPath).toUserOutput(); + const QString displayRequiredPath = m_versions.empty() ? + outDetectionPath : + QString("%1 %2").arg(outDetectionPath, displayVersions); + const QString displayDetectedPath = m_versions.empty() ? + outDetectionPath : + QString("%1 %2").arg(outDetectionPath, m_detectedVersion); + + QString response; + switch (m_status) { + case ValidPackage: + response = m_detectionPath.isEmpty() + ? ( m_detectedVersion.isEmpty() + ? tr("Path %1 exists.").arg(displayPackagePath) + : tr("Path %1 exists. Version %2 was found.") + .arg(displayPackagePath, m_detectedVersion) ) + : tr("Path %1 is valid, %2 was found.") + .arg(displayPackagePath, displayDetectedPath); + break; + case ValidPackageMismatchedVersion: { + const QString versionWarning = m_versions.size() == 1 ? + tr("but only version %1 is supported").arg(m_versions.first()) : + tr("but only versions %1 are supported").arg(displayVersions); + response = tr("Path %1 is valid, %2 was found, %3.") + .arg(displayPackagePath, displayDetectedPath, versionWarning); + break; + } + case ValidPathInvalidPackage: + response = tr("Path %1 exists, but does not contain %2.") + .arg(displayPackagePath, displayRequiredPath); + break; + case InvalidPath: + response = tr("Path %1 does not exist.").arg(displayPackagePath); + break; + case EmptyPath: + response = m_detectionPath.isEmpty() + ? tr("Path is empty.") + : tr("Path is empty, %1 not found.") + .arg(displayRequiredPath); + break; + } + return response; +} + +McuToolChainPackage::McuToolChainPackage(const QString &label, + const FilePath &defaultPath, + const QString &detectionPath, + const QString &settingsKey, + McuToolChainPackage::Type type, + const McuPackageVersionDetector *versionDetector) + : McuPackage(label, defaultPath, detectionPath, settingsKey, versionDetector) + , m_type(type) +{ +} + +McuToolChainPackage::Type McuToolChainPackage::type() const +{ + return m_type; +} + +bool McuToolChainPackage::isDesktopToolchain() const +{ + return m_type == TypeMSVC || m_type == TypeGCC; +} + +} // namespace Internal +} // namespace McuSupport diff --git a/src/plugins/mcusupport/mcupackage.h b/src/plugins/mcusupport/mcupackage.h new file mode 100644 index 00000000000..b14236f8e5e --- /dev/null +++ b/src/plugins/mcusupport/mcupackage.h @@ -0,0 +1,157 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "mcusupportversiondetection.h" + +#include +#include + +#include + +QT_FORWARD_DECLARE_CLASS(QWidget) + +namespace ProjectExplorer { +class ToolChain; +} + +namespace Utils { +class PathChooser; +class InfoLabel; +} // namespace Utils + +namespace McuSupport { +namespace Internal { + +class McuPackage : public QObject +{ + Q_OBJECT + +public: + enum Status { + EmptyPath, + InvalidPath, + ValidPathInvalidPackage, + ValidPackageMismatchedVersion, + ValidPackage + }; + + McuPackage(const QString &label, const Utils::FilePath &defaultPath, + const QString &detectionPath, const QString &settingsKey, + const McuPackageVersionDetector *versionDetector = nullptr); + virtual ~McuPackage() = default; + + Utils::FilePath basePath() const; + Utils::FilePath path() const; + QString label() const; + Utils::FilePath defaultPath() const; + QString detectionPath() const; + QString statusText() const; + void updateStatus(); + + Status status() const; + bool validStatus() const; + void setDownloadUrl(const QString &url); + void setEnvironmentVariableName(const QString &name); + void setAddToPath(bool addToPath); + bool addToPath() const; + void writeGeneralSettings() const; + bool writeToSettings() const; + void setRelativePathModifier(const QString &path); + void setVersions(const QStringList &versions); + + bool automaticKitCreationEnabled() const; + void setAutomaticKitCreationEnabled(const bool enabled); + + QWidget *widget(); + + QString environmentVariableName() const; + +signals: + void changed(); + void statusChanged(); + +private: + void updatePath(); + void updateStatusUi(); + + QWidget *m_widget = nullptr; + Utils::PathChooser *m_fileChooser = nullptr; + Utils::InfoLabel *m_infoLabel = nullptr; + + const QString m_label; + const Utils::FilePath m_defaultPath; + const QString m_detectionPath; + const QString m_settingsKey; + const McuPackageVersionDetector *m_versionDetector; + + Utils::FilePath m_path; + QString m_relativePathModifier; // relative path to m_path to be returned by path() + QString m_detectedVersion; + QStringList m_versions; + QString m_downloadUrl; + QString m_environmentVariableName; + bool m_addToPath = false; + bool m_automaticKitCreation = true; + + Status m_status = InvalidPath; +}; + +class McuToolChainPackage : public McuPackage +{ +public: + enum Type { + TypeArmGcc, + TypeIAR, + TypeKEIL, + TypeGHS, + TypeMSVC, + TypeGCC, + TypeGHSArm, + TypeUnsupported + }; + + McuToolChainPackage(const QString &label, + const Utils::FilePath &defaultPath, + const QString &detectionPath, + const QString &settingsKey, + Type type, + const McuPackageVersionDetector *versionDetector = nullptr + ); + + Type type() const; + bool isDesktopToolchain() const; + ProjectExplorer::ToolChain *toolChain(Utils::Id language) const; + QString toolChainName() const; + QString cmakeToolChainFileName() const; + QVariant debuggerId() const; + +private: + const Type m_type; +}; + +} // namespace Internal +} // namespace McuSupport diff --git a/src/plugins/mcusupport/mcusupport.qbs b/src/plugins/mcusupport/mcusupport.qbs index 2f775a01549..f18f13a52ea 100644 --- a/src/plugins/mcusupport/mcusupport.qbs +++ b/src/plugins/mcusupport/mcusupport.qbs @@ -15,6 +15,8 @@ QtcPlugin { Depends { name: "QtSupport" } files: [ + "mcupackage.cpp", + "mcupackage.h", "mcusupport.qrc", "mcusupport_global.h", "mcusupportconstants.h", diff --git a/src/plugins/mcusupport/mcusupportoptions.cpp b/src/plugins/mcusupport/mcusupportoptions.cpp index 8ee5f1f9179..cda32cac65b 100644 --- a/src/plugins/mcusupport/mcusupportoptions.cpp +++ b/src/plugins/mcusupport/mcusupportoptions.cpp @@ -23,6 +23,7 @@ ** ****************************************************************************/ +#include "mcupackage.h" #include "mcusupportconstants.h" #include "mcusupportoptions.h" #include "mcusupportsdk.h" @@ -73,26 +74,6 @@ namespace Internal { static const int KIT_VERSION = 9; // Bumps up whenever details in Kit creation change -static FilePath packagePathFromSettings(const QString &settingsKey, - QSettings::Scope scope = QSettings::UserScope, - const FilePath &defaultPath = {}) -{ - QSettings *settings = Core::ICore::settings(scope); - const QString key = QLatin1String(Constants::SETTINGS_GROUP) + '/' + - QLatin1String(Constants::SETTINGS_KEY_PACKAGE_PREFIX) + settingsKey; - const QString path = settings->value(key, defaultPath.toString()).toString(); - return FilePath::fromUserInput(path); -} - -static bool automaticKitCreationFromSettings(QSettings::Scope scope = QSettings::UserScope) -{ - QSettings *settings = Core::ICore::settings(scope); - const QString key = QLatin1String(Constants::SETTINGS_GROUP) + '/' + - QLatin1String(Constants::SETTINGS_KEY_AUTOMATIC_KIT_CREATION); - bool automaticKitCreation = settings->value(key, true).toBool(); - return automaticKitCreation; -} - static bool kitNeedsQtVersion() { // Only on Windows, Qt is linked into the distributed qul Desktop libs. Also, the host tools @@ -116,267 +97,6 @@ static void remapQul2xCmakeVars(Kit *kit, const EnvironmentItems &envItems) CMakeConfigurationKitAspect::setConfiguration(kit, config); } -McuPackage::McuPackage(const QString &label, const FilePath &defaultPath, - const QString &detectionPath, const QString &settingsKey, - const McuPackageVersionDetector *versionDetector) - : m_label(label) - , m_defaultPath(packagePathFromSettings(settingsKey, QSettings::SystemScope, defaultPath)) - , m_detectionPath(detectionPath) - , m_settingsKey(settingsKey) - , m_versionDetector(versionDetector) -{ - m_path = packagePathFromSettings(settingsKey, QSettings::UserScope, m_defaultPath); - m_automaticKitCreation = automaticKitCreationFromSettings(QSettings::UserScope); -} - -FilePath McuPackage::basePath() const -{ - return m_fileChooser != nullptr ? m_fileChooser->filePath() : m_path; -} - -FilePath McuPackage::path() const -{ - return basePath().resolvePath(m_relativePathModifier).absoluteFilePath(); -} - -QString McuPackage::label() const -{ - return m_label; -} - -FilePath McuPackage::defaultPath() const -{ - return m_defaultPath; -} - -QString McuPackage::detectionPath() const -{ - return m_detectionPath; -} - -QWidget *McuPackage::widget() -{ - if (m_widget) - return m_widget; - - m_widget = new QWidget; - m_fileChooser = new PathChooser; - m_fileChooser->lineEdit()->setButtonIcon(FancyLineEdit::Right, - Icons::RESET.icon()); - m_fileChooser->lineEdit()->setButtonVisible(FancyLineEdit::Right, true); - connect(m_fileChooser->lineEdit(), &FancyLineEdit::rightButtonClicked, this, [&] { - m_fileChooser->setFilePath(m_defaultPath); - }); - - auto layout = new QGridLayout(m_widget); - layout->setContentsMargins(0, 0, 0, 0); - m_infoLabel = new InfoLabel(); - - if (!m_downloadUrl.isEmpty()) { - auto downLoadButton = new QToolButton; - downLoadButton->setIcon(Icons::ONLINE.icon()); - downLoadButton->setToolTip(tr("Download from \"%1\"").arg(m_downloadUrl)); - QObject::connect(downLoadButton, &QToolButton::pressed, this, [this] { - QDesktopServices::openUrl(m_downloadUrl); - }); - layout->addWidget(downLoadButton, 0, 2); - } - - layout->addWidget(m_fileChooser, 0, 0, 1, 2); - layout->addWidget(m_infoLabel, 1, 0, 1, -1); - - m_fileChooser->setFilePath(m_path); - - QObject::connect(this, &McuPackage::statusChanged, this, [this] { - updateStatusUi(); - }); - - QObject::connect(m_fileChooser, &PathChooser::pathChanged, this, [this] { - updatePath(); - emit changed(); - }); - - updateStatus(); - return m_widget; -} - -McuPackage::Status McuPackage::status() const -{ - return m_status; -} - -bool McuPackage::validStatus() const -{ - return m_status == McuPackage::ValidPackage || m_status == McuPackage::ValidPackageMismatchedVersion; -} - -void McuPackage::setDownloadUrl(const QString &url) -{ - m_downloadUrl = url; -} - -void McuPackage::setEnvironmentVariableName(const QString &name) -{ - m_environmentVariableName = name; -} - -QString McuPackage::environmentVariableName() const -{ - return m_environmentVariableName; -} - -void McuPackage::setAddToPath(bool addToPath) -{ - m_addToPath = addToPath; -} - -bool McuPackage::addToPath() const -{ - return m_addToPath; -} - -void McuPackage::writeGeneralSettings() const -{ - const QString key = QLatin1String(Constants::SETTINGS_GROUP) + '/' + - QLatin1String(Constants::SETTINGS_KEY_AUTOMATIC_KIT_CREATION); - QSettings *settings = Core::ICore::settings(); - settings->setValue(key, m_automaticKitCreation); -} - -bool McuPackage::writeToSettings() const -{ - const FilePath savedPath = packagePathFromSettings(m_settingsKey, QSettings::UserScope, m_defaultPath); - const QString key = QLatin1String(Constants::SETTINGS_GROUP) + '/' + - QLatin1String(Constants::SETTINGS_KEY_PACKAGE_PREFIX) + m_settingsKey; - Core::ICore::settings()->setValueWithDefault(key, m_path.toString(), m_defaultPath.toString()); - - return savedPath != m_path; -} - -void McuPackage::setRelativePathModifier(const QString &path) -{ - m_relativePathModifier = path; -} - -void McuPackage::setVersions(const QStringList &versions) -{ - m_versions = versions; -} - -bool McuPackage::automaticKitCreationEnabled() const -{ - return m_automaticKitCreation; -} - -void McuPackage::setAutomaticKitCreationEnabled(const bool enabled) -{ - m_automaticKitCreation = enabled; -} - -void McuPackage::updatePath() -{ - m_path = m_fileChooser->rawFilePath(); - m_fileChooser->lineEdit()->button(FancyLineEdit::Right)->setEnabled(m_path != m_defaultPath); - updateStatus(); -} - -void McuPackage::updateStatus() -{ - bool validPath = !m_path.isEmpty() && m_path.exists(); - const FilePath detectionPath = basePath() / m_detectionPath; - const bool validPackage = m_detectionPath.isEmpty() || detectionPath.exists(); - m_detectedVersion = validPath && validPackage && m_versionDetector - ? m_versionDetector->parseVersion(basePath().toString()) : QString(); - const bool validVersion = m_detectedVersion.isEmpty() || - m_versions.isEmpty() || m_versions.contains(m_detectedVersion); - - m_status = validPath ? - ( validPackage ? - (validVersion ? ValidPackage : ValidPackageMismatchedVersion) - : ValidPathInvalidPackage ) - : m_path.isEmpty() ? EmptyPath : InvalidPath; - - emit statusChanged(); -} - -void McuPackage::updateStatusUi() -{ - switch (m_status) { - case ValidPackage: m_infoLabel->setType(InfoLabel::Ok); break; - case ValidPackageMismatchedVersion: m_infoLabel->setType(InfoLabel::Warning); break; - default: m_infoLabel->setType(InfoLabel::NotOk); break; - } - m_infoLabel->setText(statusText()); -} - -QString McuPackage::statusText() const -{ - const QString displayPackagePath = m_path.toUserOutput(); - const QString displayVersions = m_versions.join(" or "); - const QString outDetectionPath = FilePath::fromString(m_detectionPath).toUserOutput(); - const QString displayRequiredPath = m_versions.empty() ? - outDetectionPath : - QString("%1 %2").arg(outDetectionPath, displayVersions); - const QString displayDetectedPath = m_versions.empty() ? - outDetectionPath : - QString("%1 %2").arg(outDetectionPath, m_detectedVersion); - - QString response; - switch (m_status) { - case ValidPackage: - response = m_detectionPath.isEmpty() - ? ( m_detectedVersion.isEmpty() - ? tr("Path %1 exists.").arg(displayPackagePath) - : tr("Path %1 exists. Version %2 was found.") - .arg(displayPackagePath, m_detectedVersion) ) - : tr("Path %1 is valid, %2 was found.") - .arg(displayPackagePath, displayDetectedPath); - break; - case ValidPackageMismatchedVersion: { - const QString versionWarning = m_versions.size() == 1 ? - tr("but only version %1 is supported").arg(m_versions.first()) : - tr("but only versions %1 are supported").arg(displayVersions); - response = tr("Path %1 is valid, %2 was found, %3.") - .arg(displayPackagePath, displayDetectedPath, versionWarning); - break; - } - case ValidPathInvalidPackage: - response = tr("Path %1 exists, but does not contain %2.") - .arg(displayPackagePath, displayRequiredPath); - break; - case InvalidPath: - response = tr("Path %1 does not exist.").arg(displayPackagePath); - break; - case EmptyPath: - response = m_detectionPath.isEmpty() - ? tr("Path is empty.") - : tr("Path is empty, %1 not found.") - .arg(displayRequiredPath); - break; - } - return response; -} - -McuToolChainPackage::McuToolChainPackage(const QString &label, - const FilePath &defaultPath, - const QString &detectionPath, - const QString &settingsKey, - McuToolChainPackage::Type type, - const McuPackageVersionDetector *versionDetector) - : McuPackage(label, defaultPath, detectionPath, settingsKey, versionDetector) - , m_type(type) -{ -} - -McuToolChainPackage::Type McuToolChainPackage::type() const -{ - return m_type; -} - -bool McuToolChainPackage::isDesktopToolchain() const -{ - return m_type == TypeMSVC || m_type == TypeGCC; -} static ToolChain *msvcToolChain(Id language) { @@ -701,8 +421,8 @@ void McuSupportOptions::setQulDir(const FilePath &dir) FilePath McuSupportOptions::qulDirFromSettings() { - return packagePathFromSettings(Constants::SETTINGS_KEY_PACKAGE_QT_FOR_MCUS_SDK, - QSettings::UserScope); + return Sdk::packagePathFromSettings(Constants::SETTINGS_KEY_PACKAGE_QT_FOR_MCUS_SDK, + QSettings::UserScope); } static void setKitProperties(const QString &kitName, Kit *k, const McuTarget *mcuTarget, diff --git a/src/plugins/mcusupport/mcusupportoptions.h b/src/plugins/mcusupport/mcusupportoptions.h index 807683167f2..baefd8aaa3d 100644 --- a/src/plugins/mcusupport/mcusupportoptions.h +++ b/src/plugins/mcusupport/mcusupportoptions.h @@ -25,10 +25,8 @@ #pragma once -#include "mcusupportversiondetection.h" #include "mcusupport_global.h" -#include #include #include @@ -51,115 +49,11 @@ class ToolChain; namespace McuSupport { namespace Internal { +class McuPackage; +class McuToolChainPackage; + void printMessage(const QString &message, bool important); -class McuPackage : public QObject -{ - Q_OBJECT - -public: - enum Status { - EmptyPath, - InvalidPath, - ValidPathInvalidPackage, - ValidPackageMismatchedVersion, - ValidPackage - }; - - McuPackage(const QString &label, const Utils::FilePath &defaultPath, - const QString &detectionPath, const QString &settingsKey, - const McuPackageVersionDetector *versionDetector = nullptr); - virtual ~McuPackage() = default; - - Utils::FilePath basePath() const; - Utils::FilePath path() const; - QString label() const; - Utils::FilePath defaultPath() const; - QString detectionPath() const; - QString statusText() const; - void updateStatus(); - - Status status() const; - bool validStatus() const; - void setDownloadUrl(const QString &url); - void setEnvironmentVariableName(const QString &name); - void setAddToPath(bool addToPath); - bool addToPath() const; - void writeGeneralSettings() const; - bool writeToSettings() const; - void setRelativePathModifier(const QString &path); - void setVersions(const QStringList &versions); - - bool automaticKitCreationEnabled() const; - void setAutomaticKitCreationEnabled(const bool enabled); - - QWidget *widget(); - - QString environmentVariableName() const; - -signals: - void changed(); - void statusChanged(); - -private: - void updatePath(); - void updateStatusUi(); - - QWidget *m_widget = nullptr; - Utils::PathChooser *m_fileChooser = nullptr; - Utils::InfoLabel *m_infoLabel = nullptr; - - const QString m_label; - const Utils::FilePath m_defaultPath; - const QString m_detectionPath; - const QString m_settingsKey; - const McuPackageVersionDetector *m_versionDetector; - - Utils::FilePath m_path; - QString m_relativePathModifier; // relative path to m_path to be returned by path() - QString m_detectedVersion; - QStringList m_versions; - QString m_downloadUrl; - QString m_environmentVariableName; - bool m_addToPath = false; - bool m_automaticKitCreation = true; - - Status m_status = InvalidPath; -}; - -class McuToolChainPackage : public McuPackage -{ -public: - enum Type { - TypeArmGcc, - TypeIAR, - TypeKEIL, - TypeGHS, - TypeMSVC, - TypeGCC, - TypeGHSArm, - TypeUnsupported - }; - - McuToolChainPackage(const QString &label, - const Utils::FilePath &defaultPath, - const QString &detectionPath, - const QString &settingsKey, - Type type, - const McuPackageVersionDetector *versionDetector = nullptr - ); - - Type type() const; - bool isDesktopToolchain() const; - ProjectExplorer::ToolChain *toolChain(Utils::Id language) const; - QString toolChainName() const; - QString cmakeToolChainFileName() const; - QVariant debuggerId() const; - -private: - const Type m_type; -}; - class McuTarget : public QObject { Q_OBJECT diff --git a/src/plugins/mcusupport/mcusupportoptionspage.cpp b/src/plugins/mcusupport/mcusupportoptionspage.cpp index f4b79ec0f2e..eb83d48f30a 100644 --- a/src/plugins/mcusupport/mcusupportoptionspage.cpp +++ b/src/plugins/mcusupport/mcusupportoptionspage.cpp @@ -23,6 +23,7 @@ ** ****************************************************************************/ +#include "mcupackage.h" #include "mcusupportconstants.h" #include "mcusupportoptionspage.h" #include "mcusupportoptions.h" diff --git a/src/plugins/mcusupport/mcusupportsdk.cpp b/src/plugins/mcusupport/mcusupportsdk.cpp index 44ad3c2356e..353944a907d 100644 --- a/src/plugins/mcusupport/mcusupportsdk.cpp +++ b/src/plugins/mcusupport/mcusupportsdk.cpp @@ -23,12 +23,14 @@ ** ****************************************************************************/ +#include "mcupackage.h" #include "mcusupportconstants.h" #include "mcusupportoptions.h" #include "mcusupportsdk.h" #include "mcusupportversiondetection.h" #include +#include #include #include #include @@ -883,6 +885,15 @@ void targetsAndPackages(const Utils::FilePath &dir, McuSdkRepository *repo) }); } +FilePath packagePathFromSettings(const QString &settingsKey, QSettings::Scope scope, const FilePath &defaultPath) +{ + QSettings *settings = Core::ICore::settings(scope); + const QString key = QLatin1String(Constants::SETTINGS_GROUP) + '/' + + QLatin1String(Constants::SETTINGS_KEY_PACKAGE_PREFIX) + settingsKey; + const QString path = settings->value(key, defaultPath.toString()).toString(); + return FilePath::fromUserInput(path); +} + } // namespace Sdk } // namespace Internal } // namespace McuSupport diff --git a/src/plugins/mcusupport/mcusupportsdk.h b/src/plugins/mcusupport/mcusupportsdk.h index 2f687555d68..8429462880d 100644 --- a/src/plugins/mcusupport/mcusupportsdk.h +++ b/src/plugins/mcusupport/mcusupportsdk.h @@ -25,6 +25,7 @@ #pragma once +#include #include namespace Utils { @@ -48,6 +49,9 @@ void targetsAndPackages(const Utils::FilePath &qulDir, McuSdkRepository *repo); Utils::FilePath kitsPath(const Utils::FilePath &dir); +Utils::FilePath packagePathFromSettings(const QString &settingsKey, + QSettings::Scope scope = QSettings::UserScope, + const Utils::FilePath &defaultPath = {}); } // namespace Sdk } // namespace Internal } // namespace McuSupport From 32f8ed7b669e3d9ffe5c37eb6c66e73dd26f6d17 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Tue, 1 Feb 2022 16:07:50 +0100 Subject: [PATCH 65/94] Make (and return) more properties as const-ref in McuPackage This implies that those properties are now passed into the constructor, and their setters are removed. Change-Id: I34b4d9d7450897e6a7a72b8edaffdc05961546d1 Reviewed-by: Alessandro Portale Reviewed-by: --- src/plugins/mcusupport/mcupackage.cpp | 19 +-- src/plugins/mcusupport/mcupackage.h | 10 +- src/plugins/mcusupport/mcusupportoptions.cpp | 6 +- src/plugins/mcusupport/mcusupportoptions.h | 6 +- src/plugins/mcusupport/mcusupportsdk.cpp | 158 +++++++++---------- 5 files changed, 89 insertions(+), 110 deletions(-) diff --git a/src/plugins/mcusupport/mcupackage.cpp b/src/plugins/mcusupport/mcupackage.cpp index d8f5a2aeb00..31d70b34b5e 100644 --- a/src/plugins/mcusupport/mcupackage.cpp +++ b/src/plugins/mcusupport/mcupackage.cpp @@ -52,12 +52,15 @@ static bool automaticKitCreationFromSettings(QSettings::Scope scope = QSettings: McuPackage::McuPackage(const QString &label, const FilePath &defaultPath, const QString &detectionPath, const QString &settingsKey, + const QString &envVarName, const QString &downloadUrl, const McuPackageVersionDetector *versionDetector) : m_label(label) , m_defaultPath(Sdk::packagePathFromSettings(settingsKey, QSettings::SystemScope, defaultPath)) , m_detectionPath(detectionPath) , m_settingsKey(settingsKey) , m_versionDetector(versionDetector) + , m_environmentVariableName(envVarName) + , m_downloadUrl(downloadUrl) { m_path = Sdk::packagePathFromSettings(settingsKey, QSettings::UserScope, m_defaultPath); m_automaticKitCreation = automaticKitCreationFromSettings(QSettings::UserScope); @@ -144,17 +147,7 @@ bool McuPackage::validStatus() const return m_status == McuPackage::ValidPackage || m_status == McuPackage::ValidPackageMismatchedVersion; } -void McuPackage::setDownloadUrl(const QString &url) -{ - m_downloadUrl = url; -} - -void McuPackage::setEnvironmentVariableName(const QString &name) -{ - m_environmentVariableName = name; -} - -QString McuPackage::environmentVariableName() const +const QString &McuPackage::environmentVariableName() const { return m_environmentVariableName; } @@ -295,9 +288,9 @@ McuToolChainPackage::McuToolChainPackage(const QString &label, const FilePath &defaultPath, const QString &detectionPath, const QString &settingsKey, - McuToolChainPackage::Type type, + McuToolChainPackage::Type type, const QString &envVarName, const McuPackageVersionDetector *versionDetector) - : McuPackage(label, defaultPath, detectionPath, settingsKey, versionDetector) + : McuPackage(label, defaultPath, detectionPath, settingsKey, envVarName, {}, versionDetector) , m_type(type) { } diff --git a/src/plugins/mcusupport/mcupackage.h b/src/plugins/mcusupport/mcupackage.h index b14236f8e5e..ced8ff1d0ce 100644 --- a/src/plugins/mcusupport/mcupackage.h +++ b/src/plugins/mcusupport/mcupackage.h @@ -61,6 +61,7 @@ public: McuPackage(const QString &label, const Utils::FilePath &defaultPath, const QString &detectionPath, const QString &settingsKey, + const QString &envVarName = {}, const QString &downloadUrl = {}, const McuPackageVersionDetector *versionDetector = nullptr); virtual ~McuPackage() = default; @@ -74,8 +75,6 @@ public: Status status() const; bool validStatus() const; - void setDownloadUrl(const QString &url); - void setEnvironmentVariableName(const QString &name); void setAddToPath(bool addToPath); bool addToPath() const; void writeGeneralSettings() const; @@ -88,7 +87,7 @@ public: QWidget *widget(); - QString environmentVariableName() const; + const QString &environmentVariableName() const; signals: void changed(); @@ -112,8 +111,8 @@ private: QString m_relativePathModifier; // relative path to m_path to be returned by path() QString m_detectedVersion; QStringList m_versions; - QString m_downloadUrl; - QString m_environmentVariableName; + const QString m_environmentVariableName; + const QString m_downloadUrl; bool m_addToPath = false; bool m_automaticKitCreation = true; @@ -139,6 +138,7 @@ public: const QString &detectionPath, const QString &settingsKey, Type type, + const QString &envVarName = {}, const McuPackageVersionDetector *versionDetector = nullptr ); diff --git a/src/plugins/mcusupport/mcusupportoptions.cpp b/src/plugins/mcusupport/mcusupportoptions.cpp index cda32cac65b..fb874a0d153 100644 --- a/src/plugins/mcusupport/mcusupportoptions.cpp +++ b/src/plugins/mcusupport/mcusupportoptions.cpp @@ -269,7 +269,7 @@ McuTarget::McuTarget(const QVersionNumber &qulVersion, { } -QVector McuTarget::packages() const +const QVector &McuTarget::packages() const { return m_packages; } @@ -284,7 +284,7 @@ McuTarget::OS McuTarget::os() const return m_os; } -McuTarget::Platform McuTarget::platform() const +const McuTarget::Platform &McuTarget::platform() const { return m_platform; } @@ -316,7 +316,7 @@ void McuTarget::printPackageProblems() const } } -QVersionNumber McuTarget::qulVersion() const +const QVersionNumber &McuTarget::qulVersion() const { return m_qulVersion; } diff --git a/src/plugins/mcusupport/mcusupportoptions.h b/src/plugins/mcusupport/mcusupportoptions.h index baefd8aaa3d..1b957d4e169 100644 --- a/src/plugins/mcusupport/mcusupportoptions.h +++ b/src/plugins/mcusupport/mcusupportoptions.h @@ -75,10 +75,10 @@ public: const QVector &packages, const McuToolChainPackage *toolChainPackage); - QVersionNumber qulVersion() const; - QVector packages() const; + const QVersionNumber &qulVersion() const; + const QVector &packages() const; const McuToolChainPackage *toolChainPackage() const; - Platform platform() const; + const Platform &platform() const; OS os() const; void setColorDepth(int colorDepth); int colorDepth() const; diff --git a/src/plugins/mcusupport/mcusupportsdk.cpp b/src/plugins/mcusupport/mcusupportsdk.cpp index 353944a907d..88b410f974d 100644 --- a/src/plugins/mcusupport/mcusupportsdk.cpp +++ b/src/plugins/mcusupport/mcusupportsdk.cpp @@ -65,13 +65,11 @@ static FilePath findInProgramFiles(const QString &folder) McuPackage *createQtForMCUsPackage() { - auto result = new McuPackage( - McuPackage::tr("Qt for MCUs SDK"), - FileUtils::homePath(), - FilePath("bin/qmltocpp").withExecutableSuffix().toString(), - Constants::SETTINGS_KEY_PACKAGE_QT_FOR_MCUS_SDK); - result->setEnvironmentVariableName("Qul_DIR"); - return result; + return new McuPackage(McuPackage::tr("Qt for MCUs SDK"), + FileUtils::homePath(), // defaultPath + FilePath("bin/qmltocpp").withExecutableSuffix().toString(), // detectionPath + Constants::SETTINGS_KEY_PACKAGE_QT_FOR_MCUS_SDK, // settingsKey + QStringLiteral("Qul_DIR")); // envVarName } static McuToolChainPackage *createMsvcToolChainPackage() @@ -114,15 +112,13 @@ static McuToolChainPackage *createArmGccPackage() "\\b(\\d+\\.\\d+\\.\\d+)\\b" ); - auto result = new McuToolChainPackage( - McuPackage::tr("GNU Arm Embedded Toolchain"), - defaultPath, - detectionPath, - "GNUArmEmbeddedToolchain", - McuToolChainPackage::TypeArmGcc, - versionDetector); - result->setEnvironmentVariableName(envVar); - return result; + return new McuToolChainPackage(McuPackage::tr("GNU Arm Embedded Toolchain"), + defaultPath, + detectionPath, + "GNUArmEmbeddedToolchain", // settingsKey + McuToolChainPackage::TypeArmGcc, + envVar, + versionDetector); } static McuToolChainPackage *createGhsToolchainPackage() @@ -137,15 +133,14 @@ static McuToolChainPackage *createGhsToolchainPackage() "\\bv(\\d+\\.\\d+\\.\\d+)\\b" ); - auto result = new McuToolChainPackage( - "Green Hills Compiler", - defaultPath, - Utils::HostOsInfo::withExecutableSuffix("ccv850"), - "GHSToolchain", - McuToolChainPackage::TypeGHS, - versionDetector); - result->setEnvironmentVariableName(envVar); - return result; + return new McuToolChainPackage("Green Hills Compiler", + defaultPath, + Utils::HostOsInfo::withExecutableSuffix( + "ccv850"), // detectionPath + "GHSToolchain", // settingsKey + McuToolChainPackage::TypeGHS, + envVar, + versionDetector); } static McuToolChainPackage *createGhsArmToolchainPackage() @@ -160,15 +155,13 @@ static McuToolChainPackage *createGhsArmToolchainPackage() "\\bv(\\d+\\.\\d+\\.\\d+)\\b" ); - auto result = new McuToolChainPackage( - "Green Hills Compiler for ARM", - defaultPath, - Utils::HostOsInfo::withExecutableSuffix("cxarm"), - "GHSArmToolchain", - McuToolChainPackage::TypeGHSArm, - versionDetector); - result->setEnvironmentVariableName(envVar); - return result; + return new McuToolChainPackage("Green Hills Compiler for ARM", + defaultPath, + Utils::HostOsInfo::withExecutableSuffix("cxarm"), // detectionPath + "GHSArmToolchain", // settingsKey + McuToolChainPackage::TypeGHSArm, + envVar, + versionDetector); } static McuToolChainPackage *createIarToolChainPackage() @@ -196,15 +189,13 @@ static McuToolChainPackage *createIarToolChainPackage() "\\bV(\\d+\\.\\d+\\.\\d+)\\.\\d+\\b" ); - auto result = new McuToolChainPackage( - "IAR ARM Compiler", - defaultPath, - detectionPath, - "IARToolchain", - McuToolChainPackage::TypeIAR, - versionDetector); - result->setEnvironmentVariableName(envVar); - return result; + return new McuToolChainPackage("IAR ARM Compiler", + defaultPath, + detectionPath, + "IARToolchain", // settings key + McuToolChainPackage::TypeIAR, + envVar, + versionDetector); } static McuPackage *createRGLPackage() @@ -225,13 +216,11 @@ static McuPackage *createRGLPackage() } } - auto result = new McuPackage( - "Renesas Graphics Library", - defaultPath, - {}, - "RGL"); - result->setEnvironmentVariableName(envVar); - return result; + return new McuPackage("Renesas Graphics Library", + defaultPath, + {}, // detection path + "RGL", + envVar); } static McuPackage *createStm32CubeProgrammerPackage() @@ -247,15 +236,16 @@ static McuPackage *createStm32CubeProgrammerPackage() if (programPath.exists()) defaultPath = programPath; } - auto result = new McuPackage( - McuPackage::tr("STM32CubeProgrammer"), - defaultPath, - QLatin1String(Utils::HostOsInfo::isWindowsHost() ? "/bin/STM32_Programmer_CLI.exe" - : "/bin/STM32_Programmer.sh"), - "Stm32CubeProgrammer"); + auto result + = new McuPackage(McuPackage::tr("STM32CubeProgrammer"), + defaultPath, + QLatin1String(Utils::HostOsInfo::isWindowsHost() + ? "/bin/STM32_Programmer_CLI.exe" + : "/bin/STM32_Programmer.sh"), // detection path + "Stm32CubeProgrammer", + {}, // env var + "https://www.st.com/en/development-tools/stm32cubeprog.html"); // download url result->setRelativePathModifier("/bin"); - result->setDownloadUrl( - "https://www.st.com/en/development-tools/stm32cubeprog.html"); result->setAddToPath(true); return result; } @@ -283,14 +273,13 @@ static McuPackage *createMcuXpressoIdePackage() defaultPath = programPath; } - auto result = new McuPackage( - "MCUXpresso IDE", - defaultPath, - Utils::HostOsInfo::withExecutableSuffix("ide/binaries/crt_emu_cm_redlink"), - "MCUXpressoIDE"); - result->setDownloadUrl("https://www.nxp.com/mcuxpresso/ide"); - result->setEnvironmentVariableName(envVar); - return result; + return new McuPackage("MCUXpresso IDE", + defaultPath, + Utils::HostOsInfo::withExecutableSuffix( + "ide/binaries/crt_emu_cm_redlink"), // detection path + "MCUXpressoIDE", // settings key + envVar, + "https://www.nxp.com/mcuxpresso/ide"); // download url } static McuPackage *createCypressProgrammerPackage() @@ -315,8 +304,8 @@ static McuPackage *createCypressProgrammerPackage() "Cypress Auto Flash Utility", defaultPath, Utils::HostOsInfo::withExecutableSuffix("/bin/openocd"), - "CypressAutoFlashUtil"); - result->setEnvironmentVariableName(envVar); + "CypressAutoFlashUtil", + envVar); return result; } @@ -342,8 +331,8 @@ static McuPackage *createRenesasProgrammerPackage() "Renesas Flash Programmer", defaultPath, Utils::HostOsInfo::withExecutableSuffix("rfp-cli"), - "RenesasFlashProgrammer"); - result->setEnvironmentVariableName(envVar); + "RenesasFlashProgrammer", + envVar); return result; } @@ -422,14 +411,13 @@ static McuPackage *createBoardSdkPackage(const McuTargetDescription& desc) const auto versionDetector = generatePackageVersionDetector(desc.boardSdk.envVar); - auto result = new McuPackage( - sdkName, - defaultPath, - {}, - desc.boardSdk.envVar, - versionDetector); - result->setEnvironmentVariableName(desc.boardSdk.envVar); - return result; + return new McuPackage(sdkName, + defaultPath, + {}, // detection path + desc.boardSdk.envVar, // settings key + desc.boardSdk.envVar, // env var + {}, // download URL + versionDetector); } static McuPackage *createFreeRTOSSourcesPackage(const QString &envVar, const FilePath &boardSdkDir, @@ -443,14 +431,12 @@ static McuPackage *createFreeRTOSSourcesPackage(const QString &envVar, const Fil else if (!boardSdkDir.isEmpty() && !freeRTOSBoardSdkSubDir.isEmpty()) defaultPath = boardSdkDir / freeRTOSBoardSdkSubDir; - auto result = new McuPackage( - QString::fromLatin1("FreeRTOS Sources (%1)").arg(envVarPrefix), - defaultPath, - {}, - QString::fromLatin1("FreeRTOSSourcePackage_%1").arg(envVarPrefix)); - result->setDownloadUrl("https://freertos.org"); - result->setEnvironmentVariableName(envVar); - return result; + return new McuPackage(QString::fromLatin1("FreeRTOS Sources (%1)").arg(envVarPrefix), + defaultPath, + {}, + QString::fromLatin1("FreeRTOSSourcePackage_%1").arg(envVarPrefix), + envVar, + "https://freertos.org"); } struct McuTargetFactory From 34345f8b7edfed0db5a964e08f813c3c78080286 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Tue, 1 Feb 2022 16:29:11 +0100 Subject: [PATCH 66/94] Make McuToolChainPackage::Type an enum class And make more use of switch statements without a default case, so each type is handled explicitly. (Ok, there is a default, but that is Q_UNREACHABLE). Change-Id: I30ccc447e55a5aeebebe1a9879ea3136545f5e68 Reviewed-by: Alessandro Portale Reviewed-by: --- src/plugins/mcusupport/mcupackage.cpp | 2 +- src/plugins/mcusupport/mcupackage.h | 18 +-- src/plugins/mcusupport/mcusupportoptions.cpp | 151 ++++++++++++------- src/plugins/mcusupport/mcusupportsdk.cpp | 16 +- 4 files changed, 111 insertions(+), 76 deletions(-) diff --git a/src/plugins/mcusupport/mcupackage.cpp b/src/plugins/mcusupport/mcupackage.cpp index 31d70b34b5e..7a98738ffa5 100644 --- a/src/plugins/mcusupport/mcupackage.cpp +++ b/src/plugins/mcusupport/mcupackage.cpp @@ -302,7 +302,7 @@ McuToolChainPackage::Type McuToolChainPackage::type() const bool McuToolChainPackage::isDesktopToolchain() const { - return m_type == TypeMSVC || m_type == TypeGCC; + return m_type == Type::MSVC || m_type == Type::GCC; } } // namespace Internal diff --git a/src/plugins/mcusupport/mcupackage.h b/src/plugins/mcusupport/mcupackage.h index ced8ff1d0ce..8729a40a335 100644 --- a/src/plugins/mcusupport/mcupackage.h +++ b/src/plugins/mcusupport/mcupackage.h @@ -122,15 +122,15 @@ private: class McuToolChainPackage : public McuPackage { public: - enum Type { - TypeArmGcc, - TypeIAR, - TypeKEIL, - TypeGHS, - TypeMSVC, - TypeGCC, - TypeGHSArm, - TypeUnsupported + enum class Type { + IAR, + KEIL, + MSVC, + GCC, + ArmGcc, + GHS, + GHSArm, + Unsupported }; McuToolChainPackage(const QString &label, diff --git a/src/plugins/mcusupport/mcusupportoptions.cpp b/src/plugins/mcusupport/mcusupportoptions.cpp index fb874a0d153..ec23b7ad084 100644 --- a/src/plugins/mcusupport/mcusupportoptions.cpp +++ b/src/plugins/mcusupport/mcusupportoptions.cpp @@ -178,35 +178,42 @@ static ToolChain *iarToolChain(const FilePath &path, Id language) ToolChain *McuToolChainPackage::toolChain(Id language) const { - ToolChain *tc = nullptr; - if (m_type == TypeMSVC) - tc = msvcToolChain(language); - else if (m_type == TypeGCC) - tc = gccToolChain(language); - else if (m_type == TypeIAR) { + switch (m_type) { + case Type::MSVC: + return msvcToolChain(language); + case Type::GCC: + return gccToolChain(language); + case Type::IAR: { const FilePath compiler = path().pathAppended("/bin/iccarm").withExecutableSuffix(); - tc = iarToolChain(compiler, language); + return iarToolChain(compiler, language); } - else { + case Type::ArmGcc: + case Type::KEIL: + case Type::GHS: + case Type::GHSArm: + case Type::Unsupported: { const QLatin1String compilerName( - language == ProjectExplorer::Constants::C_LANGUAGE_ID ? "gcc" : "g++"); - const QString comp = QLatin1String(m_type == TypeArmGcc ? "/bin/arm-none-eabi-%1" : "/bar/foo-keil-%1") - .arg(compilerName); + language == ProjectExplorer::Constants::C_LANGUAGE_ID ? "gcc" : "g++"); + const QString comp = QLatin1String(m_type == Type::ArmGcc ? "/bin/arm-none-eabi-%1" + : "/bar/foo-keil-%1") + .arg(compilerName); const FilePath compiler = path().pathAppended(comp).withExecutableSuffix(); - tc = armGccToolChain(compiler, language); + return armGccToolChain(compiler, language); + } + default: + Q_UNREACHABLE(); } - return tc; } QString McuToolChainPackage::toolChainName() const { switch (m_type) { - case TypeArmGcc: return QLatin1String("armgcc"); - case TypeIAR: return QLatin1String("iar"); - case TypeKEIL: return QLatin1String("keil"); - case TypeGHS: return QLatin1String("ghs"); - case TypeGHSArm: return QLatin1String("ghs-arm"); + case Type::ArmGcc: return QLatin1String("armgcc"); + case Type::IAR: return QLatin1String("iar"); + case Type::KEIL: return QLatin1String("keil"); + case Type::GHS: return QLatin1String("ghs"); + case Type::GHSArm: return QLatin1String("ghs-arm"); default: return QLatin1String("unsupported"); } } @@ -224,37 +231,38 @@ QVariant McuToolChainPackage::debuggerId() const DebuggerEngineType engineType; switch (m_type) { - case TypeArmGcc: { + case Type::ArmGcc: { sub = QString::fromLatin1("bin/arm-none-eabi-gdb-py"); displayName = McuPackage::tr("Arm GDB at %1"); engineType = Debugger::GdbEngineType; - break; } - case TypeIAR: { + break; + } + case Type::IAR: { sub = QString::fromLatin1("../common/bin/CSpyBat"); displayName = QLatin1String("CSpy"); engineType = Debugger::NoEngineType; // support for IAR missing - break; } - case TypeKEIL: { + break; + } + case Type::KEIL: { sub = QString::fromLatin1("UV4/UV4"); displayName = QLatin1String("KEIL uVision Debugger"); engineType = Debugger::UvscEngineType; - break; } - default: return QVariant(); + break; + } + default: + return QVariant(); } const FilePath command = path().pathAppended(sub).withExecutableSuffix(); - const DebuggerItem *debugger = DebuggerItemManager::findByCommand(command); - QVariant debuggerId; - if (!debugger) { - DebuggerItem newDebugger; - newDebugger.setCommand(command); - newDebugger.setUnexpandedDisplayName(displayName.arg(command.toUserOutput())); - newDebugger.setEngineType(engineType); - debuggerId = DebuggerItemManager::registerDebugger(newDebugger); - } else { - debuggerId = debugger->id(); + if (const DebuggerItem *debugger = DebuggerItemManager::findByCommand(command)) { + return debugger->id(); } - return debuggerId; + + DebuggerItem newDebugger; + newDebugger.setCommand(command); + newDebugger.setUnexpandedDisplayName(displayName.arg(command.toUserOutput())); + newDebugger.setEngineType(engineType); + return DebuggerItemManager::registerDebugger(newDebugger); } McuTarget::McuTarget(const QVersionNumber &qulVersion, @@ -458,33 +466,60 @@ static void setKitProperties(const QString &kitName, Kit *k, const McuTarget *mc static void setKitToolchains(Kit *k, const McuToolChainPackage *tcPackage) { - // No Green Hills toolchain, because support for it is missing. - if (tcPackage->type() == McuToolChainPackage::TypeUnsupported - || tcPackage->type() == McuToolChainPackage::TypeGHS - || tcPackage->type() == McuToolChainPackage::TypeGHSArm) + switch (tcPackage->type()) { + case McuToolChainPackage::Type::Unsupported: return; - ToolChainKitAspect::setToolChain(k, tcPackage->toolChain( - ProjectExplorer::Constants::C_LANGUAGE_ID)); - ToolChainKitAspect::setToolChain(k, tcPackage->toolChain( - ProjectExplorer::Constants::CXX_LANGUAGE_ID)); + case McuToolChainPackage::Type::GHS: + case McuToolChainPackage::Type::GHSArm: + return; // No Green Hills toolchain, because support for it is missing. + + case McuToolChainPackage::Type::IAR: + case McuToolChainPackage::Type::KEIL: + case McuToolChainPackage::Type::MSVC: + case McuToolChainPackage::Type::GCC: + case McuToolChainPackage::Type::ArmGcc: + ToolChainKitAspect::setToolChain(k, + tcPackage->toolChain( + ProjectExplorer::Constants::C_LANGUAGE_ID)); + ToolChainKitAspect::setToolChain(k, + tcPackage->toolChain( + ProjectExplorer::Constants::CXX_LANGUAGE_ID)); + return; + + default: + Q_UNREACHABLE(); + } } static void setKitDebugger(Kit *k, const McuToolChainPackage *tcPackage) { - // Qt Creator seems to be smart enough to deduce the right Kit debugger from the ToolChain - // We rely on that at least in the Desktop case. - if (tcPackage->isDesktopToolchain() - // No Green Hills and IAR debugger, because support for it is missing. - || tcPackage->type() == McuToolChainPackage::TypeUnsupported - || tcPackage->type() == McuToolChainPackage::TypeGHS - || tcPackage->type() == McuToolChainPackage::TypeGHSArm - || tcPackage->type() == McuToolChainPackage::TypeIAR) + if (tcPackage->isDesktopToolchain()) { + // Qt Creator seems to be smart enough to deduce the right Kit debugger from the ToolChain return; + } - const QVariant debuggerId = tcPackage->debuggerId(); - if (debuggerId.isValid()) - Debugger::DebuggerKitAspect::setDebugger(k, debuggerId); + switch (tcPackage->type()) { + case McuToolChainPackage::Type::Unsupported: + case McuToolChainPackage::Type::GHS: + case McuToolChainPackage::Type::GHSArm: + case McuToolChainPackage::Type::IAR: + return; // No Green Hills and IAR debugger, because support for it is missing. + + case McuToolChainPackage::Type::KEIL: + case McuToolChainPackage::Type::MSVC: + case McuToolChainPackage::Type::GCC: + case McuToolChainPackage::Type::ArmGcc: { + const QVariant debuggerId = tcPackage->debuggerId(); + if (debuggerId.isValid()) { + Debugger::DebuggerKitAspect::setDebugger(k, debuggerId); + } + return; + } + + default: + Q_UNREACHABLE(); + } } static void setKitDevice(Kit *k, const McuTarget* mcuTarget) @@ -596,8 +631,8 @@ static void setKitCMakeOptions(Kit *k, const McuTarget* mcuTarget, const FilePat CMakeConfig config = CMakeConfigurationKitAspect::configuration(k); // CMake ToolChain file for ghs handles CMAKE_*_COMPILER autonomously - if (mcuTarget->toolChainPackage()->type() != McuToolChainPackage::TypeGHS && - mcuTarget->toolChainPackage()->type() != McuToolChainPackage::TypeGHSArm) { + if (mcuTarget->toolChainPackage()->type() != McuToolChainPackage::Type::GHS && + mcuTarget->toolChainPackage()->type() != McuToolChainPackage::Type::GHSArm) { config.append(CMakeConfigItem("CMAKE_CXX_COMPILER", "%{Compiler:Executable:Cxx}")); config.append(CMakeConfigItem("CMAKE_C_COMPILER", "%{Compiler:Executable:C}")); } @@ -638,7 +673,7 @@ static void setKitCMakeOptions(Kit *k, const McuTarget* mcuTarget, const FilePat if (HostOsInfo::isWindowsHost()) { auto type = mcuTarget->toolChainPackage()->type(); - if (type == McuToolChainPackage::TypeGHS || type == McuToolChainPackage::TypeGHSArm) { + if (type == McuToolChainPackage::Type::GHS || type == McuToolChainPackage::Type::GHSArm) { // See https://bugreports.qt.io/browse/UL-4247?focusedCommentId=565802&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-565802 // and https://bugreports.qt.io/browse/UL-4247?focusedCommentId=565803&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-565803 CMakeGeneratorKitAspect::setGenerator(k, "NMake Makefiles JOM"); diff --git a/src/plugins/mcusupport/mcusupportsdk.cpp b/src/plugins/mcusupport/mcusupportsdk.cpp index 88b410f974d..2287ad61d7e 100644 --- a/src/plugins/mcusupport/mcusupportsdk.cpp +++ b/src/plugins/mcusupport/mcusupportsdk.cpp @@ -74,17 +74,17 @@ McuPackage *createQtForMCUsPackage() static McuToolChainPackage *createMsvcToolChainPackage() { - return new McuToolChainPackage({}, {}, {}, {}, McuToolChainPackage::TypeMSVC); + return new McuToolChainPackage({}, {}, {}, {}, McuToolChainPackage::Type::MSVC); } static McuToolChainPackage *createGccToolChainPackage() { - return new McuToolChainPackage({}, {}, {}, {}, McuToolChainPackage::TypeGCC); + return new McuToolChainPackage({}, {}, {}, {}, McuToolChainPackage::Type::GCC); } static McuToolChainPackage *createUnsupportedToolChainPackage() { - return new McuToolChainPackage({}, {}, {}, {}, McuToolChainPackage::TypeUnsupported); + return new McuToolChainPackage({}, {}, {}, {}, McuToolChainPackage::Type::Unsupported); } static McuToolChainPackage *createArmGccPackage() @@ -116,7 +116,7 @@ static McuToolChainPackage *createArmGccPackage() defaultPath, detectionPath, "GNUArmEmbeddedToolchain", // settingsKey - McuToolChainPackage::TypeArmGcc, + McuToolChainPackage::Type::ArmGcc, envVar, versionDetector); } @@ -138,7 +138,7 @@ static McuToolChainPackage *createGhsToolchainPackage() Utils::HostOsInfo::withExecutableSuffix( "ccv850"), // detectionPath "GHSToolchain", // settingsKey - McuToolChainPackage::TypeGHS, + McuToolChainPackage::Type::GHS, envVar, versionDetector); } @@ -159,7 +159,7 @@ static McuToolChainPackage *createGhsArmToolchainPackage() defaultPath, Utils::HostOsInfo::withExecutableSuffix("cxarm"), // detectionPath "GHSArmToolchain", // settingsKey - McuToolChainPackage::TypeGHSArm, + McuToolChainPackage::Type::GHSArm, envVar, versionDetector); } @@ -193,7 +193,7 @@ static McuToolChainPackage *createIarToolChainPackage() defaultPath, detectionPath, "IARToolchain", // settings key - McuToolChainPackage::TypeIAR, + McuToolChainPackage::Type::IAR, envVar, versionDetector); } @@ -555,7 +555,7 @@ protected: // Desktop toolchains don't need any additional settings if (tcPkg && !tcPkg->isDesktopToolchain() - && tcPkg->type() != McuToolChainPackage::TypeUnsupported) + && tcPkg->type() != McuToolChainPackage::Type::Unsupported) required3rdPartyPkgs.append(tcPkg); // Add setting specific to platform IDE From 7e00d5f662e9ccfb2b3b8e8a5e9d781db537891d Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Wed, 9 Feb 2022 17:18:28 +0100 Subject: [PATCH 67/94] Doc: Describe applying context menu actions to multiple issues ...in the Issues pane. Task-number: QTCREATORBUG-26610 Change-Id: I5ad148b7f8e1696aa0f3b494f05b068df9d2210d Reviewed-by: Christian Kandeler --- doc/qtcreator/src/user-interface/creator-ui.qdoc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/qtcreator/src/user-interface/creator-ui.qdoc b/doc/qtcreator/src/user-interface/creator-ui.qdoc index 8c013c13d38..43645074980 100644 --- a/doc/qtcreator/src/user-interface/creator-ui.qdoc +++ b/doc/qtcreator/src/user-interface/creator-ui.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2022 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Creator documentation. @@ -508,10 +508,10 @@ \image qtcreator-issues.png "Issues output pane" - Right-clicking on a line brings up a context menu with actions that you can - apply to the contents of the line. You can remove a line, copy its contents - to the clipboard, or search the Internet for a solution using the contents - of the line as search criteria. In addition, you can show a version control + Select one or several lines to apply context-menu actions to their contents. + You can remove the selected lines or copy their contents to the clipboard. + For single lines, you can search the Internet for a solution using the + contents of the line as search criteria or open a version control annotation view of the line that causes the error message. To navigate to the corresponding source code, click an issue or From 3bdab2f05eae5133b9fcd1f1df71d8999efa1eb2 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 9 Feb 2022 12:29:40 +0100 Subject: [PATCH 68/94] Docker: Simplify and fix "Open Shell in Container" Change-Id: Icce72712a006f524b8a8328904d89f2b0e2b8a3d Reviewed-by: Reviewed-by: Christian Stenger --- src/plugins/docker/dockerdevice.cpp | 33 +++++++++++++---------------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index 22428aea254..7652ef935f8 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -530,32 +530,29 @@ DockerDevice::DockerDevice(const DockerDeviceData &data) setAllowEmptyCommand(true); setOpenTerminal([this](const Environment &env, const FilePath &workingDir) { - DeviceProcess * const proc = createProcess(nullptr); - QObject::connect(proc, &DeviceProcess::finished, [proc] { - if (!proc->errorString().isEmpty()) { - MessageManager::writeDisrupting( - tr("Error running remote shell: %1").arg(proc->errorString())); - } - proc->deleteLater(); - }); + Q_UNUSED(env); // TODO: That's the runnable's environment in general. Use it via -e below. + updateContainerAccess(); + if (d->m_container.isEmpty()) { + MessageManager::writeDisrupting(tr("Error starting remote shell. No container")); + return; + } + + QtcProcess *proc = new QtcProcess(QtcProcess::TerminalOn); + QObject::connect(proc, &QtcProcess::finished, proc, &QObject::deleteLater); + QObject::connect(proc, &DeviceProcess::errorOccurred, [proc] { MessageManager::writeDisrupting(tr("Error starting remote shell.")); proc->deleteLater(); }); - Runnable runnable; - runnable.command = {"/bin/sh", {}}; - runnable.device = sharedFromThis(); - runnable.environment = env; - runnable.workingDirectory = workingDir; - runnable.extraData[Constants::DOCKER_RUN_FLAGS] = QStringList({"--interactive", "--tty"}); - - proc->setRunInTerminal(true); - proc->start(runnable); + const QString wd = workingDir.isEmpty() ? "/" : workingDir.path(); + proc->setCommand({"docker", {"exec", "-it", "-w", wd, d->m_container, "/bin/sh"}}); + proc->setEnvironment(Environment::systemEnvironment()); // The host system env. Intentional. + proc->start(); }); if (HostOsInfo::isAnyUnixHost()) { - addDeviceAction({tr("Open Shell in Container"), [](const IDevice::Ptr &device, QWidget *) { + addDeviceAction({tr("Open Shell in Container"), [this](const IDevice::Ptr &device, QWidget *) { device->openTerminal(Environment(), FilePath()); }}); } From 14ee4654c1140a76c03af1d2350fd2c548efc43b Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 10 Feb 2022 10:15:54 +0100 Subject: [PATCH 69/94] ClangCodeModel: Fix detection of #ifdef'ed out blocks with clangd We were erroneously merging adjacent disabled blocks. Change-Id: I9f8f588c0362d488a24c044910474815b94efd59 Reviewed-by: David Schulz Reviewed-by: --- src/plugins/clangcodemodel/clangdclient.cpp | 3 ++- src/plugins/clangcodemodel/test/clangdtests.cpp | 13 +++++++++++++ src/plugins/clangcodemodel/test/clangdtests.h | 3 +++ .../test/data/highlighting/highlighting.cpp | 11 +++++++++++ src/plugins/texteditor/textdocument.cpp | 4 ++++ src/plugins/texteditor/textdocument.h | 4 ++++ 6 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index 07e8956f0a0..48cb1bf13bd 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -2576,7 +2576,8 @@ static QList cleanupDisabledCode(HighlightingResults &results, const } if (wasIfdefedOut && (it + 1 == results.end() - || (it + 1)->textStyles.mainStyle != C_DISABLED_CODE)) { + || (it + 1)->textStyles.mainStyle != C_DISABLED_CODE + || (it + 1)->line != it->line + 1)) { // The #else or #endif that ends disabled code should not be disabled. const QTextBlock block = doc->findBlockByNumber(it->line - 1); ifdefedOutRanges << BlockRange(rangeStartPos, block.position()); diff --git a/src/plugins/clangcodemodel/test/clangdtests.cpp b/src/plugins/clangcodemodel/test/clangdtests.cpp index 36217ad8d76..6ed6163a6bd 100644 --- a/src/plugins/clangcodemodel/test/clangdtests.cpp +++ b/src/plugins/clangcodemodel/test/clangdtests.cpp @@ -675,6 +675,8 @@ void ClangdTestHighlighting::initTestCase() { ClangdTest::initTestCase(); + connect(document("highlighting.cpp"), &TextDocument::ifdefedOutBlocksChanged, this, + [this](const QList &ranges) { m_ifdefedOutBlocks = ranges; }); QTimer timer; timer.setSingleShot(true); QEventLoop loop; @@ -1380,6 +1382,17 @@ void ClangdTestHighlighting::test() QCOMPARE(result.kind, expectedKind); } +void ClangdTestHighlighting::testIfdefedOutBlocks() +{ + QCOMPARE(m_ifdefedOutBlocks.size(), 3); + QCOMPARE(m_ifdefedOutBlocks.at(0).first(), 12033); + QCOMPARE(m_ifdefedOutBlocks.at(0).last(), 12050); + QCOMPARE(m_ifdefedOutBlocks.at(1).first(), 13351); + QCOMPARE(m_ifdefedOutBlocks.at(1).last(), 13364); + QCOMPARE(m_ifdefedOutBlocks.at(2).first(), 13390); + QCOMPARE(m_ifdefedOutBlocks.at(2).last(), 13402); +} + class Manipulator : public TextDocumentManipulatorInterface { diff --git a/src/plugins/clangcodemodel/test/clangdtests.h b/src/plugins/clangcodemodel/test/clangdtests.h index b6399a9c59f..66f41cfa156 100644 --- a/src/plugins/clangcodemodel/test/clangdtests.h +++ b/src/plugins/clangcodemodel/test/clangdtests.h @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -141,9 +142,11 @@ private slots: void initTestCase() override; void test_data(); void test(); + void testIfdefedOutBlocks(); private: TextEditor::HighlightingResults m_results; + QList m_ifdefedOutBlocks; }; class ClangdTestCompletion : public ClangdTest diff --git a/src/plugins/clangcodemodel/test/data/highlighting/highlighting.cpp b/src/plugins/clangcodemodel/test/data/highlighting/highlighting.cpp index 46112c2f136..7ebc39d433f 100644 --- a/src/plugins/clangcodemodel/test/data/highlighting/highlighting.cpp +++ b/src/plugins/clangcodemodel/test/data/highlighting/highlighting.cpp @@ -869,3 +869,14 @@ void constMemberAsFunctionArg() const Foo &constMember; }; } + +# if 0 +#define FOO + +#endif + +// comment + +#if 0 +#define BAR +# endif diff --git a/src/plugins/texteditor/textdocument.cpp b/src/plugins/texteditor/textdocument.cpp index 4376cc17398..696e4caf0a2 100644 --- a/src/plugins/texteditor/textdocument.cpp +++ b/src/plugins/texteditor/textdocument.cpp @@ -532,6 +532,10 @@ void TextDocument::setIfdefedOutBlocks(const QList &blocks) if (needUpdate) documentLayout->requestUpdate(); + +#ifdef WITH_TESTS + emit ifdefedOutBlocksChanged(blocks); +#endif } const ExtraEncodingSettings &TextDocument::extraEncodingSettings() const diff --git a/src/plugins/texteditor/textdocument.h b/src/plugins/texteditor/textdocument.h index 71a9a120a6c..0385bb2463f 100644 --- a/src/plugins/texteditor/textdocument.h +++ b/src/plugins/texteditor/textdocument.h @@ -172,6 +172,10 @@ signals: void fontSettingsChanged(); void markRemoved(TextMark *mark); +#ifdef WITH_TESTS + void ifdefedOutBlocksChanged(const QList &blocks); +#endif + protected: virtual void applyFontSettings(); From a204ad3236396e82ad62ce9a2efbbd1f982f6480 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Wed, 9 Feb 2022 11:07:15 +0100 Subject: [PATCH 70/94] CMakePM: Do not reconfigure project on KitUpdated Initial Configuration will get the updated kit values and it's up to the user to react. The reconfiguration doesn't help at all, since none of the variables / options ends up in the Current Configuration. Change-Id: I5ee75fce1a33ce30a011ce6f1b6399fd79727ca6 Reviewed-by: Reviewed-by: Eike Ziller --- src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index 5817ace058a..c4d2127573b 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -805,17 +805,6 @@ void CMakeBuildSystem::wireUpConnections() // At this point the entire project will be fully configured, so let's connect everything and // trigger an initial parser run - // Kit changed: - connect(KitManager::instance(), &KitManager::kitUpdated, this, [this](Kit *k) { - if (k != kit()) - return; // not for us... - // FIXME: This is no longer correct: QtC now needs to update the initial parameters - // FIXME: and then ask to reconfigure. - qCDebug(cmakeBuildSystemLog) << "Requesting parse due to kit being updated"; - setParametersAndRequestParse(BuildDirParameters(cmakeBuildConfiguration()), - CMakeBuildSystem::REPARSE_FORCE_CMAKE_RUN); - }); - // Became active/inactive: connect(target(), &Target::activeBuildConfigurationChanged, this, [this]() { // Build configuration has changed: From 2eef90e86f0f66b6e81c5bab53ea2d3a08f0321a Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Tue, 8 Feb 2022 20:40:22 +0100 Subject: [PATCH 71/94] CMakePM: Update generator kit value after Kit Configuration dialog The CMAKE_GENERATOR variable in "Initial Configuration" didn't get the Kit value after a change in the "Kit Configuration" dialog. Change-Id: Ieb9d634e2e9b1a5522b189e16bb66f8cea4c63b1 Reviewed-by: Reviewed-by: Eike Ziller --- .../cmakebuildconfiguration.cpp | 4 +++- .../cmakekitinformation.cpp | 23 +++++++++++++++++++ .../cmakeprojectmanager/cmakekitinformation.h | 1 + 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index 7760ad63089..fda6987e5e2 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -770,7 +770,9 @@ void CMakeBuildSettingsWidget::updateAdvancedCheckBox() void CMakeBuildSettingsWidget::updateFromKit() { const Kit *k = m_buildConfiguration->kit(); - const CMakeConfig config = CMakeConfigurationKitAspect::configuration(k); + CMakeConfig config = CMakeConfigurationKitAspect::configuration(k); + + config.append(CMakeGeneratorKitAspect::generatorCMakeConfig(k)); // First the key value parameters ConfigModel::KitConfiguration configHash; diff --git a/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp b/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp index f97575be5ac..bc43f8be3ca 100644 --- a/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp +++ b/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp @@ -660,6 +660,29 @@ QStringList CMakeGeneratorKitAspect::generatorArguments(const Kit *k) return result; } +CMakeConfig CMakeGeneratorKitAspect::generatorCMakeConfig(const ProjectExplorer::Kit *k) +{ + CMakeConfig config; + + GeneratorInfo info = generatorInfo(k); + if (info.generator.isEmpty()) + return config; + + if (info.extraGenerator.isEmpty()) + config << CMakeConfigItem("CMAKE_GENERATOR", info.generator.toUtf8()); + else + config << CMakeConfigItem("CMAKE_GENERATOR", + (info.extraGenerator + " - " + info.generator).toUtf8()); + + if (!info.platform.isEmpty()) + config << CMakeConfigItem("CMAKE_GENERATOR_PLATFORM", info.platform.toUtf8()); + + if (!info.toolset.isEmpty()) + config << CMakeConfigItem("CMAKE_GENERATOR_TOOLSET", info.toolset.toUtf8()); + + return config; +} + bool CMakeGeneratorKitAspect::isMultiConfigGenerator(const Kit *k) { const QString generator = CMakeGeneratorKitAspect::generator(k); diff --git a/src/plugins/cmakeprojectmanager/cmakekitinformation.h b/src/plugins/cmakeprojectmanager/cmakekitinformation.h index 65c3a24dccd..9129f0704cb 100644 --- a/src/plugins/cmakeprojectmanager/cmakekitinformation.h +++ b/src/plugins/cmakeprojectmanager/cmakekitinformation.h @@ -77,6 +77,7 @@ public: static void set(ProjectExplorer::Kit *k, const QString &generator, const QString &extraGenerator, const QString &platform, const QString &toolset); static QStringList generatorArguments(const ProjectExplorer::Kit *k); + static CMakeConfig generatorCMakeConfig(const ProjectExplorer::Kit *k); static bool isMultiConfigGenerator(const ProjectExplorer::Kit *k); // KitAspect interface From 5d675ff53343aed139e70ad00bb3c15b7a7dbf0c Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Tue, 8 Feb 2022 11:16:21 +0100 Subject: [PATCH 72/94] Remove QTC_ASSERT because unset toolchain is a valid condition Change-Id: I2ba710cf4e0af31138787bb7859302ad3a3f3d03 Reviewed-by: Reviewed-by: Cristian Adam --- src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index c34c6660570..b81b52358b6 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -808,7 +808,8 @@ static bool isDocker(const Kit *k) static bool isWindowsARM64(const Kit *k) { ToolChain *toolchain = ToolChainKitAspect::cxxToolChain(k); - QTC_ASSERT(toolchain, return false); + if (!toolchain) + return false; const Abi targetAbi = toolchain->targetAbi(); return targetAbi.os() == Abi::WindowsOS && targetAbi.architecture() == Abi::ArmArchitecture && targetAbi.wordWidth() == 64; From 400ada2daae9051c7479e7e4818d6b866ad5ed13 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 9 Feb 2022 18:00:59 +0100 Subject: [PATCH 73/94] ProjectExplorer: Dis-ambiguate issues pane's "show output" action Amends 08a86169db. Fixes: QTCREATORBUG-27031 Change-Id: Ie6d214673f6c1c52aab1a035c84a7381f9965588 Reviewed-by: Qt CI Bot Reviewed-by: Reviewed-by: hjk --- src/plugins/projectexplorer/appoutputpane.cpp | 5 ++++- .../projectexplorer/compileoutputwindow.cpp | 5 ++++- .../projectexplorer/showoutputtaskhandler.cpp | 16 +++++++++++----- .../projectexplorer/showoutputtaskhandler.h | 6 +++++- 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/plugins/projectexplorer/appoutputpane.cpp b/src/plugins/projectexplorer/appoutputpane.cpp index 4920f771571..076fb1c8953 100644 --- a/src/plugins/projectexplorer/appoutputpane.cpp +++ b/src/plugins/projectexplorer/appoutputpane.cpp @@ -172,7 +172,10 @@ AppOutputPane::AppOutputPane() : m_attachButton(new QToolButton), m_settingsButton(new QToolButton), m_formatterWidget(new QWidget), - m_handler(new ShowOutputTaskHandler(this)) + m_handler(new ShowOutputTaskHandler(this, + tr("Show &App Output"), + tr("Show the output that generated this issue in the application output window"), + tr("A"))) { ExtensionSystem::PluginManager::addObject(m_handler); diff --git a/src/plugins/projectexplorer/compileoutputwindow.cpp b/src/plugins/projectexplorer/compileoutputwindow.cpp index 839a1d25469..a51397bd256 100644 --- a/src/plugins/projectexplorer/compileoutputwindow.cpp +++ b/src/plugins/projectexplorer/compileoutputwindow.cpp @@ -116,7 +116,10 @@ CompileOutputWindow::CompileOutputWindow(QAction *cancelBuildAction) : qRegisterMetaType("QTextCharFormat"); - m_handler = new ShowOutputTaskHandler(this); + m_handler = new ShowOutputTaskHandler(this, + tr("Show Compile &Output"), + tr("Show the output that generated this issue in the compile output window"), + tr("O")); ExtensionSystem::PluginManager::addObject(m_handler); setupContext(C_COMPILE_OUTPUT, m_outputWindow); loadSettings(); diff --git a/src/plugins/projectexplorer/showoutputtaskhandler.cpp b/src/plugins/projectexplorer/showoutputtaskhandler.cpp index 8190cd7431b..592ab6e8dab 100644 --- a/src/plugins/projectexplorer/showoutputtaskhandler.cpp +++ b/src/plugins/projectexplorer/showoutputtaskhandler.cpp @@ -30,15 +30,19 @@ #include #include #include +#include #include namespace ProjectExplorer { namespace Internal { -ShowOutputTaskHandler::ShowOutputTaskHandler(Core::IOutputPane *window) : m_window(window) +ShowOutputTaskHandler::ShowOutputTaskHandler(Core::IOutputPane *window, const QString &text, + const QString &tooltip, const QString &shortcut) + : m_window(window), m_text(text), m_tooltip(tooltip), m_shortcut(shortcut) { - Q_ASSERT(m_window); + QTC_CHECK(m_window); + QTC_CHECK(!m_text.isEmpty()); } bool ShowOutputTaskHandler::canHandle(const Task &task) const @@ -64,9 +68,11 @@ void ShowOutputTaskHandler::handle(const Task &task) QAction *ShowOutputTaskHandler::createAction(QObject *parent) const { - QAction *outputAction = new QAction(tr("Show &Output"), parent); - outputAction->setToolTip(tr("Show output generating this issue.")); - outputAction->setShortcut(QKeySequence(tr("O"))); + QAction * const outputAction = new QAction(m_text, parent); + if (!m_tooltip.isEmpty()) + outputAction->setToolTip(m_tooltip); + if (!m_shortcut.isEmpty()) + outputAction->setShortcut(QKeySequence(m_shortcut)); outputAction->setShortcutContext(Qt::WidgetWithChildrenShortcut); return outputAction; } diff --git a/src/plugins/projectexplorer/showoutputtaskhandler.h b/src/plugins/projectexplorer/showoutputtaskhandler.h index 0dd70f7f10d..b30f63388d7 100644 --- a/src/plugins/projectexplorer/showoutputtaskhandler.h +++ b/src/plugins/projectexplorer/showoutputtaskhandler.h @@ -37,7 +37,8 @@ class ShowOutputTaskHandler : public ITaskHandler Q_OBJECT public: - explicit ShowOutputTaskHandler(Core::IOutputPane *window); + explicit ShowOutputTaskHandler(Core::IOutputPane *window, const QString &text, + const QString &tooltip, const QString &shortcut); bool canHandle(const Task &) const override; void handle(const Task &task) override; @@ -45,6 +46,9 @@ public: private: Core::IOutputPane * const m_window; + const QString m_text; + const QString m_tooltip; + const QString m_shortcut; }; } // namespace Internal From 959e2b0124d5629f8a0703eb0f633e86fe89ebaf Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 8 Feb 2022 17:41:35 +0100 Subject: [PATCH 74/94] Fix showing non-zero exit code in output pane for remote app Change-Id: Ifc1b26c439ad6e78669b4ba9ac38e7d7e6a8c614 Reviewed-by: hjk --- src/plugins/projectexplorer/applicationlauncher.cpp | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/plugins/projectexplorer/applicationlauncher.cpp b/src/plugins/projectexplorer/applicationlauncher.cpp index 2d5b5ce5fd5..ab685ae8cbd 100644 --- a/src/plugins/projectexplorer/applicationlauncher.cpp +++ b/src/plugins/projectexplorer/applicationlauncher.cpp @@ -451,15 +451,8 @@ void ApplicationLauncherPrivate::handleApplicationFinished() { QTC_ASSERT(m_state == Run, return); - if (m_deviceProcess->exitStatus() == QProcess::CrashExit) { + if (m_deviceProcess->exitStatus() == QProcess::CrashExit) doReportError(m_deviceProcess->errorString(), QProcess::Crashed); - } else { - const int exitCode = m_deviceProcess->exitCode(); - if (exitCode != 0) { - doReportError(ApplicationLauncher::tr("Application finished with exit code %1.") - .arg(exitCode), QProcess::UnknownError); - } - } setFinished(); } From 6ede8b3bc0e96453e7c5725718b200cb8ac9b30f Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 8 Feb 2022 11:49:37 +0100 Subject: [PATCH 75/94] ClangCodeModel: Support parse contexts with clangd Fixes: QTCREATORBUG-27009 Change-Id: I177db0658d545211b940623cae071db91e82ddb4 Reviewed-by: Reviewed-by: David Schulz --- src/plugins/clangcodemodel/clangdclient.cpp | 35 +++++++++++++++++ src/plugins/clangcodemodel/clangdclient.h | 4 ++ .../clangeditordocumentprocessor.cpp | 6 +++ .../clangeditordocumentprocessor.h | 3 ++ .../clangmodelmanagersupport.cpp | 38 +++++++++++++++++-- .../cppeditor/baseeditordocumentparser.h | 7 ++++ 6 files changed, 90 insertions(+), 3 deletions(-) diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index 48cb1bf13bd..5988d04d40d 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -1142,6 +1142,7 @@ public: std::unordered_map highlighters; QHash, int>> previousTokens; + QHash parserConfigs; // The ranges of symbols referring to virtual functions, with document version, // as extracted by the highlighting procedure. @@ -1468,6 +1469,7 @@ void ClangdClient::handleDocumentClosed(TextDocument *doc) d->astCache.remove(doc); d->previousTokens.remove(doc); d->virtualRanges.remove(doc); + d->parserConfigs.remove(doc->filePath()); } QTextCursor ClangdClient::adjustedCursorForHighlighting(const QTextCursor &cursor, @@ -1625,6 +1627,39 @@ void ClangdClient::handleUiHeaderChange(const QString &fileName) } } +void ClangdClient::updateParserConfig(const Utils::FilePath &filePath, + const CppEditor::BaseEditorDocumentParser::Configuration &config) +{ + if (config.preferredProjectPartId.isEmpty()) + return; + + CppEditor::BaseEditorDocumentParser::Configuration &cachedConfig = d->parserConfigs[filePath]; + if (cachedConfig == config) + return; + cachedConfig = config; + + // TODO: Also handle editorDefines (and usePrecompiledHeaders?) + const auto projectPart = CppEditor::CppModelManager::instance() + ->projectPartForId(config.preferredProjectPartId); + if (!projectPart) + return; + const CppEditor::ClangDiagnosticConfig projectWarnings = warningsConfigForProject(project()); + const QStringList projectOptions = optionsForProject(project()); + QJsonObject cdbChanges; + QStringList args = createClangOptions(*projectPart, filePath.toString(), projectWarnings, + projectOptions); + args.prepend("clang"); + args.append(filePath.toString()); + QJsonObject value; + value.insert("workingDirectory", filePath.parentDir().toString()); + value.insert("compilationCommand", QJsonArray::fromStringList(args)); + cdbChanges.insert(filePath.toUserOutput(), value); + const QJsonObject settings({qMakePair(QString("compilationDatabaseChanges"), cdbChanges)}); + DidChangeConfigurationParams configChangeParams; + configChangeParams.setSettings(settings); + sendContent(DidChangeConfigurationNotification(configChangeParams)); +} + void ClangdClient::Private::handleFindUsagesResult(quint64 key, const QList &locations) { const auto refData = runningFindUsages.find(key); diff --git a/src/plugins/clangcodemodel/clangdclient.h b/src/plugins/clangcodemodel/clangdclient.h index 92ca40d0ffa..cc4b6aa71e9 100644 --- a/src/plugins/clangcodemodel/clangdclient.h +++ b/src/plugins/clangcodemodel/clangdclient.h @@ -25,6 +25,7 @@ #pragma once +#include #include #include #include @@ -88,6 +89,9 @@ public: static void handleUiHeaderChange(const QString &fileName); + void updateParserConfig(const Utils::FilePath &filePath, + const CppEditor::BaseEditorDocumentParser::Configuration &config); + signals: void indexingFinished(); void foundReferences(const QList &items); diff --git a/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp b/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp index 2461120d9af..1b2027139f1 100644 --- a/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp +++ b/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp @@ -328,6 +328,12 @@ void ClangEditorDocumentProcessor::setParserConfig( { m_parser->setConfiguration(config); m_builtinProcessor.parser()->setConfiguration(config); + emit parserConfigChanged(Utils::FilePath::fromString(filePath()), config); +} + +CppEditor::BaseEditorDocumentParser::Configuration ClangEditorDocumentProcessor::parserConfig() const +{ + return m_parser->configuration(); } static bool isCursorOnIdentifier(const QTextCursor &textCursor) diff --git a/src/plugins/clangcodemodel/clangeditordocumentprocessor.h b/src/plugins/clangcodemodel/clangeditordocumentprocessor.h index 532c134b40b..7111eee4c80 100644 --- a/src/plugins/clangcodemodel/clangeditordocumentprocessor.h +++ b/src/plugins/clangcodemodel/clangeditordocumentprocessor.h @@ -91,6 +91,7 @@ public: void editorDocumentTimerRestarted() override; void setParserConfig(const CppEditor::BaseEditorDocumentParser::Configuration &config) override; + CppEditor::BaseEditorDocumentParser::Configuration parserConfig() const; QFuture cursorInfo(const CppEditor::CursorInfoParams ¶ms) override; QFuture requestLocalReferences(const QTextCursor &cursor) override; @@ -115,6 +116,8 @@ public: signals: void tokenInfosUpdated(); + void parserConfigChanged(const Utils::FilePath &filePath, + const CppEditor::BaseEditorDocumentParser::Configuration &config); private: void onParserFinished(); diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp index 1d8a3f8af2e..7ceb40011f8 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp @@ -217,7 +217,15 @@ bool ClangModelManagerSupport::supportsLocalUses(const TextEditor::TextDocument CppEditor::BaseEditorDocumentProcessor *ClangModelManagerSupport::createEditorDocumentProcessor( TextEditor::TextDocument *baseTextDocument) { - return new ClangEditorDocumentProcessor(m_communicator, baseTextDocument); + const auto processor = new ClangEditorDocumentProcessor(m_communicator, baseTextDocument); + const auto handleConfigChange = [this](const Utils::FilePath &fp, + const BaseEditorDocumentParser::Configuration &config) { + if (const auto client = clientForFile(fp)) + client->updateParserConfig(fp, config); + }; + connect(processor, &ClangEditorDocumentProcessor::parserConfigChanged, + this, handleConfigChange); + return processor; } void ClangModelManagerSupport::onCurrentEditorChanged(Core::IEditor *editor) @@ -233,6 +241,8 @@ void ClangModelManagerSupport::onCurrentEditorChanged(Core::IEditor *editor) if (auto processor = ClangEditorDocumentProcessor::get(filePath.toString())) { processor->semanticRehighlight(); processor->generateTaskHubIssues(); + if (const auto client = clientForFile(filePath)) + client->updateParserConfig(filePath, processor->parserConfig()); } } @@ -342,16 +352,38 @@ void ClangModelManagerSupport::updateLanguageClient( if (!newProjectInfo || *newProjectInfo != *projectInfo) return; + const auto updateParserConfig = [client] { + if (const auto editor = TextEditor::BaseTextEditor::currentTextEditor()) { + if (!client->documentOpen(editor->textDocument())) + return; + const Utils::FilePath filePath = editor->textDocument()->filePath(); + if (const auto processor = ClangEditorDocumentProcessor::get( + filePath.toString())) { + const CppEditor::BaseEditorDocumentParser::Configuration config + = processor->parserConfig(); + client->updateParserConfig(filePath, config); + } + } + }; + // Acquaint the client with all open C++ documents for this project. bool hasDocuments = false; for (TextEditor::BaseTextEditor * const editor : allCppEditors()) { - if (!project->isKnownFile(editor->textDocument()->filePath())) + const Utils::FilePath filePath = editor->textDocument()->filePath(); + if (!project->isKnownFile(filePath)) continue; LanguageClientManager::openDocumentWithClient(editor->textDocument(), client); - ClangEditorDocumentProcessor::clearTextMarks(editor->textDocument()->filePath()); + ClangEditorDocumentProcessor::clearTextMarks(filePath); hasDocuments = true; } + if (client->state() == Client::Initialized) + updateParserConfig(); + else + connect(client, &Client::initialized, client, updateParserConfig); + connect(CppModelManager::instance(), &CppModelManager::projectPartsUpdated, + client, updateParserConfig); + if (hasDocuments) return; diff --git a/src/plugins/cppeditor/baseeditordocumentparser.h b/src/plugins/cppeditor/baseeditordocumentparser.h index 2e10d561787..2f48058b8b6 100644 --- a/src/plugins/cppeditor/baseeditordocumentparser.h +++ b/src/plugins/cppeditor/baseeditordocumentparser.h @@ -50,6 +50,13 @@ public: bool usePrecompiledHeaders = false; QByteArray editorDefines; QString preferredProjectPartId; + + bool operator==(const Configuration &other) + { + return usePrecompiledHeaders == other.usePrecompiledHeaders + && editorDefines == other.editorDefines + && preferredProjectPartId == other.preferredProjectPartId; + } }; struct UpdateParams { From 8a29a78ebfcfa4c4c825e2763900d8c4c33bc58f Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 9 Feb 2022 12:30:36 +0100 Subject: [PATCH 76/94] CdbExt: Fix Python-C API handling From 3.10 onwards we need an additional macro when parsing and building values. Change-Id: Ia0bcdde467d87a1c7d22ec8657e050cdf5f1e52e Reviewed-by: David Schulz --- src/libs/qtcreatorcdbext/CMakeLists.txt | 2 +- src/libs/qtcreatorcdbext/qtcreatorcdbext.qbs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/qtcreatorcdbext/CMakeLists.txt b/src/libs/qtcreatorcdbext/CMakeLists.txt index 03ca0eda6d8..bf3d1c0989d 100644 --- a/src/libs/qtcreatorcdbext/CMakeLists.txt +++ b/src/libs/qtcreatorcdbext/CMakeLists.txt @@ -90,7 +90,7 @@ if (_library_enabled) extend_qtc_library(qtcreatorcdbext DEPENDS "${Python3_LIBRARIES}" INCLUDES "${Python3_INCLUDE_DIRS}" - DEFINES WITH_PYTHON=1 + DEFINES WITH_PYTHON=1 PY_SSIZE_T_CLEAN SOURCES pycdbextmodule.cpp pycdbextmodule.h pyfield.cpp pyfield.h diff --git a/src/libs/qtcreatorcdbext/qtcreatorcdbext.qbs b/src/libs/qtcreatorcdbext/qtcreatorcdbext.qbs index fac2f7a25b7..91e91bc8514 100644 --- a/src/libs/qtcreatorcdbext/qtcreatorcdbext.qbs +++ b/src/libs/qtcreatorcdbext/qtcreatorcdbext.qbs @@ -87,7 +87,7 @@ QtcLibrary { Properties { condition: pythonDllProbe.found - cpp.defines: ["WITH_PYTHON=1"] + cpp.defines: ["WITH_PYTHON=1", "PY_SSIZE_T_CLEAN"] } cpp.includePaths: { if (pythonDllProbe.found) From ab5fdd94f334a2517510c6b51e89dbac49d561d4 Mon Sep 17 00:00:00 2001 From: Artem Sokolovskii Date: Tue, 11 Jan 2022 13:18:29 +0100 Subject: [PATCH 77/94] [ClangFormat] Add test checkking indentation after Q_OBJECT Added test checking behavior when after Q_OBJECT all class structure have correct indenting and redundent tabs doesn't appear before key words such as public:, private: , etc. Made automatic addition Qt defines to StatementMacro to .clang-format files. Fixes: QTCREATORBUG-26776 Change-Id: I3490421a9caf2831b593939597940358f7ce8f01 Reviewed-by: Christian Kandeler --- .../clangformat/clangformatbaseindenter.cpp | 7 ++-- src/plugins/clangformat/clangformatutils.cpp | 33 +++++++++++++++---- src/plugins/clangformat/clangformatutils.h | 2 ++ .../clangformat/tests/clangformat-test.cpp | 8 +++++ .../clangformat/tests/clangformat-test.h | 1 + 5 files changed, 43 insertions(+), 8 deletions(-) diff --git a/src/plugins/clangformat/clangformatbaseindenter.cpp b/src/plugins/clangformat/clangformatbaseindenter.cpp index fa95514ca32..d9e36e3717a 100644 --- a/src/plugins/clangformat/clangformatbaseindenter.cpp +++ b/src/plugins/clangformat/clangformatbaseindenter.cpp @@ -24,6 +24,7 @@ ****************************************************************************/ #include "clangformatbaseindenter.h" +#include "clangformatutils.h" #include @@ -728,14 +729,16 @@ clang::format::FormatStyle ClangFormatBaseIndenter::styleForFile() const { llvm::Expected style = clang::format::getStyle("file", m_fileName.toString().toStdString(), "none"); - if (style) + if (style) { + addQtcStatementMacros(*style); return *style; + } handleAllErrors(style.takeError(), [](const llvm::ErrorInfoBase &) { // do nothing }); - return clang::format::getLLVMStyle(); + return qtcStyle(); } } // namespace ClangFormat diff --git a/src/plugins/clangformat/clangformatutils.cpp b/src/plugins/clangformat/clangformatutils.cpp index ff184ea737c..e59a151f0b2 100644 --- a/src/plugins/clangformat/clangformatutils.cpp +++ b/src/plugins/clangformat/clangformatutils.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include @@ -46,7 +47,7 @@ using namespace Utils; namespace ClangFormat { -static clang::format::FormatStyle qtcStyle() +clang::format::FormatStyle qtcStyle() { clang::format::FormatStyle style = getLLVMStyle(); style.Language = FormatStyle::LK_Cpp; @@ -355,18 +356,38 @@ clang::format::FormatStyle styleForFile(Utils::FilePath fileName) return styleForFile(fileName, true); } +void addQtcStatementMacros(clang::format::FormatStyle &style) +{ + static const std::vector macros = {"Q_OBJECT", + "QT_BEGIN_NAMESPACE", + "QT_END_NAMESPACE"}; + for (const std::string ¯o : macros) { + if (std::find(style.StatementMacros.begin(), style.StatementMacros.end(), macro) + == style.StatementMacros.end()) + style.StatementMacros.emplace_back(macro); + } +} + static std::string readFile(const QString &path) { + const std::string defaultStyle = clang::format::configurationAsText(qtcStyle()); + QFile file(path); - if (!file.open(QFile::ReadOnly)) { - clang::format::FormatStyle defaultStyle = qtcStyle(); - return clang::format::configurationAsText(defaultStyle); - } + if (!file.open(QFile::ReadOnly)) + return defaultStyle; const QByteArray content = file.readAll(); file.close(); - return content.toStdString(); + clang::format::FormatStyle style; + style.Language = clang::format::FormatStyle::LK_Cpp; + const std::error_code error = clang::format::parseConfiguration(content.toStdString(), &style); + + QTC_ASSERT(error.value() == static_cast(ParseError::Success), return defaultStyle); + + addQtcStatementMacros(style); + + return clang::format::configurationAsText(style); } std::string currentProjectConfigText() diff --git a/src/plugins/clangformat/clangformatutils.h b/src/plugins/clangformat/clangformatutils.h index 74fd84c9c6b..3caf6c9d6fc 100644 --- a/src/plugins/clangformat/clangformatutils.h +++ b/src/plugins/clangformat/clangformatutils.h @@ -51,4 +51,6 @@ clang::format::FormatStyle currentGlobalStyle(); QString configForFile(Utils::FilePath fileName); clang::format::FormatStyle styleForFile(Utils::FilePath fileName); +void addQtcStatementMacros(clang::format::FormatStyle &style); +clang::format::FormatStyle qtcStyle(); } diff --git a/src/plugins/clangformat/tests/clangformat-test.cpp b/src/plugins/clangformat/tests/clangformat-test.cpp index 3bef6506795..bc5e07328df 100644 --- a/src/plugins/clangformat/tests/clangformat-test.cpp +++ b/src/plugins/clangformat/tests/clangformat-test.cpp @@ -646,4 +646,12 @@ void ClangFormatTest::testCommentBlock() "****************************************************************************/"})); } +void ClangFormatTest::testClassIndentStructure() +{ + insertLines({"class test {", " Q_OBJECT", " public:", "};"}); + m_indenter->indent(*m_cursor, QChar::Null, TextEditor::TabSettings()); + QCOMPARE(documentLines(), + (std::vector{"class test {", " Q_OBJECT", "public:", "};"})); +} + } // namespace ClangFormat::Internal diff --git a/src/plugins/clangformat/tests/clangformat-test.h b/src/plugins/clangformat/tests/clangformat-test.h index e34a1491168..094657d1b01 100644 --- a/src/plugins/clangformat/tests/clangformat-test.h +++ b/src/plugins/clangformat/tests/clangformat-test.h @@ -109,6 +109,7 @@ private slots: void testSortIncludes(); void testChainedMemberFunctionCalls(); void testCommentBlock(); + void testClassIndentStructure(); private: void insertLines(const std::vector &lines); From f146b846cd4f7d6175ff1bc9cd4c6ac46438c8a3 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Wed, 2 Feb 2022 17:56:16 +0200 Subject: [PATCH 78/94] QmlDesigner: Implement proper preview for pure 3D scenes Refactored the existing 3D node preview generation to be done synchronously, which enables their use also for creating state and item library previews for 3D nodes with ease. Fixes: QDS-5785 Change-Id: Ib493eccbc239f33bcad3301673a865494616a901 Reviewed-by: Reviewed-by: Thomas Hartmann --- .../mockfiles/qt5/MaterialNodeView.qml | 5 + .../mockfiles/qt5/ModelNode3DImageView.qml | 19 +-- .../qmlpuppet/mockfiles/qt5/ModelNodeView.qml | 29 +--- .../qmlpuppet/mockfiles/qt5/NodeNodeView.qml | 39 +---- .../mockfiles/qt6/MaterialNodeView.qml | 5 + .../mockfiles/qt6/ModelNode3DImageView.qml | 19 +-- .../qmlpuppet/mockfiles/qt6/ModelNodeView.qml | 30 +--- .../qmlpuppet/mockfiles/qt6/NodeNodeView.qml | 39 +---- .../qml2puppet/editor3d/generalhelper.cpp | 159 ++++++++++++++++++ .../qml2puppet/editor3d/generalhelper.h | 5 + .../instances/nodeinstanceserver.cpp | 5 + .../qml2puppet/instances/nodeinstanceserver.h | 2 + .../instances/objectnodeinstance.cpp | 5 + .../qml2puppet/instances/objectnodeinstance.h | 1 + .../qt5captureimagenodeinstanceserver.cpp | 9 +- .../qt5informationnodeinstanceserver.cpp | 108 +++++------- .../qt5informationnodeinstanceserver.h | 22 --- .../instances/qt5nodeinstanceserver.h | 2 +- .../qt5previewnodeinstanceserver.cpp | 5 + .../instances/qt5previewnodeinstanceserver.h | 1 + .../instances/quick3dnodeinstance.cpp | 119 +++++++++++++ .../instances/quick3dnodeinstance.h | 10 ++ .../instances/quickitemnodeinstance.cpp | 5 + .../instances/quickitemnodeinstance.h | 1 + .../instances/servernodeinstance.cpp | 2 +- .../itemlibrary/itemlibraryitem.cpp | 3 +- .../previewtooltip/previewimagetooltip.ui | 10 +- .../imagecache/imagecachecollector.cpp | 3 +- .../metainfo/subcomponentmanager.cpp | 1 + 29 files changed, 420 insertions(+), 243 deletions(-) diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/MaterialNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/MaterialNodeView.qml index f52bcf4bee9..48ed09cba70 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/MaterialNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/MaterialNodeView.qml @@ -32,6 +32,11 @@ View3D { property Material previewMaterial + function fitToViewPort() + { + // No need to zoom this view, this is here just to avoid runtime warnings + } + SceneEnvironment { id: sceneEnv antialiasingMode: SceneEnvironment.MSAA diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNode3DImageView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNode3DImageView.qml index 324a020d6fa..de3e3ee431c 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNode3DImageView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNode3DImageView.qml @@ -41,8 +41,6 @@ Item { property var modelViewComponent property var nodeViewComponent - property bool ready: false - function destroyView() { previewObject = null; @@ -58,8 +56,6 @@ Item { createViewForModel(obj); else if (obj instanceof Node) createViewForNode(obj); - - previewObject = obj; } function createViewForMaterial(material) @@ -70,6 +66,8 @@ Item { // Always recreate the view to ensure material is up to date if (materialViewComponent.status === Component.Ready) view = materialViewComponent.createObject(viewRect, {"previewMaterial": material}); + + previewObject = material; } function createViewForModel(model) @@ -80,6 +78,8 @@ Item { // Always recreate the view to ensure model is up to date if (modelViewComponent.status === Component.Ready) view = modelViewComponent.createObject(viewRect, {"sourceModel": model}); + + previewObject = model; } function createViewForNode(node) @@ -90,16 +90,13 @@ Item { // Always recreate the view to ensure node is up to date if (nodeViewComponent.status === Component.Ready) view = nodeViewComponent.createObject(viewRect, {"importScene": node}); + + previewObject = node; } - function afterRender() + function fitToViewPort() { - if (previewObject instanceof Node) { - view.fitToViewPort(); - ready = view.ready; - } else { - ready = true; - } + view.fitToViewPort(); } View3D { diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNodeView.qml index dc10f441e1c..e61a9a8fb25 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNodeView.qml @@ -32,24 +32,13 @@ View3D { environment: sceneEnv camera: theCamera - property bool ready: false - property real prevZoomFactor: -1 property Model sourceModel function fitToViewPort() { - cameraControl.focusObject(model, theCamera.eulerRotation, true, false); - - if (cameraControl._zoomFactor < 0.1) { - model.scale = model.scale.times(10); - } else if (cameraControl._zoomFactor > 10) { - model.scale = model.scale.times(0.1); - } else { - // We need one more render after zoom factor change, so only set ready when zoom factor - // or scaling hasn't changed from the previous frame - ready = _generalHelper.fuzzyCompare(cameraControl._zoomFactor, prevZoomFactor); - prevZoomFactor = cameraControl._zoomFactor; - } + // The magic number is the distance from camera default pos to origin + _generalHelper.calculateNodeBoundsAndFocusCamera(theCamera, importScene, root, + 1040); } SceneEnvironment { @@ -58,14 +47,6 @@ View3D { antialiasingQuality: SceneEnvironment.High } - EditCameraController { - id: cameraControl - camera: theCamera - anchors.fill: parent - view3d: root - ignoreToolState: true - } - DirectionalLight { eulerRotation.x: -30 eulerRotation.y: -30 @@ -75,15 +56,15 @@ View3D { id: theCamera z: 600 y: 600 + x: 600 eulerRotation.x: -45 + eulerRotation.y: -45 clipFar: 10000 clipNear: 1 } Model { id: model - eulerRotation.y: 45 - source: sourceModel.source geometry: sourceModel.geometry diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/NodeNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/NodeNodeView.qml index b41c74af54e..91008abb251 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/NodeNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/NodeNodeView.qml @@ -32,30 +32,11 @@ View3D { environment: sceneEnv camera: theCamera - property bool ready: false - property bool first: true - property real prevZoomFactor: -1 - function fitToViewPort() { - if (first) { - first = false; - selectionBox.targetNode = root.importScene; - } else { - cameraControl.focusObject(selectionBox.model, theCamera.eulerRotation, true, false); - - if (cameraControl._zoomFactor < 0.1) { - root.importScene.scale = root.importScene.scale.times(10); - } else if (cameraControl._zoomFactor > 10) { - root.importScene.scale = root.importScene.scale.times(0.1); - } else { - // We need one more render after zoom factor change, so only set ready when zoom factor - // or scaling hasn't changed from the previous frame - ready = _generalHelper.fuzzyCompare(cameraControl._zoomFactor, prevZoomFactor); - prevZoomFactor = cameraControl._zoomFactor; - selectionBox.visible = false; - } - } + // The magic number is the distance from camera default pos to origin + _generalHelper.calculateNodeBoundsAndFocusCamera(theCamera, importScene, root, + 1040); } SceneEnvironment { @@ -64,20 +45,6 @@ View3D { antialiasingQuality: SceneEnvironment.High } - SelectionBox { - id: selectionBox - view3D: root - geometryName: "NodeNodeViewSB" - } - - EditCameraController { - id: cameraControl - camera: theCamera - anchors.fill: parent - view3d: root - ignoreToolState: true - } - DirectionalLight { eulerRotation.x: -30 eulerRotation.y: -30 diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/MaterialNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/MaterialNodeView.qml index 6103df98c2b..0b6c7bd2144 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/MaterialNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/MaterialNodeView.qml @@ -32,6 +32,11 @@ View3D { property Material previewMaterial + function fitToViewPort() + { + // No need to zoom this view, this is here just to avoid runtime warnings + } + SceneEnvironment { id: sceneEnv antialiasingMode: SceneEnvironment.MSAA diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNode3DImageView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNode3DImageView.qml index 36d4cea8553..4bd07e57d12 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNode3DImageView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNode3DImageView.qml @@ -41,8 +41,6 @@ Item { property var modelViewComponent property var nodeViewComponent - property bool ready: false - function destroyView() { previewObject = null; @@ -58,8 +56,6 @@ Item { createViewForModel(obj); else if (obj instanceof Node) createViewForNode(obj); - - previewObject = obj; } function createViewForMaterial(material) @@ -70,6 +66,8 @@ Item { // Always recreate the view to ensure material is up to date if (materialViewComponent.status === Component.Ready) view = materialViewComponent.createObject(viewRect, {"previewMaterial": material}); + + previewObject = material; } function createViewForModel(model) @@ -80,6 +78,8 @@ Item { // Always recreate the view to ensure model is up to date if (modelViewComponent.status === Component.Ready) view = modelViewComponent.createObject(viewRect, {"sourceModel": model}); + + previewObject = model; } function createViewForNode(node) @@ -90,16 +90,13 @@ Item { // Always recreate the view to ensure node is up to date if (nodeViewComponent.status === Component.Ready) view = nodeViewComponent.createObject(viewRect, {"importScene": node}); + + previewObject = node; } - function afterRender() + function fitToViewPort() { - if (previewObject instanceof Node) { - view.fitToViewPort(); - ready = view.ready; - } else { - ready = true; - } + view.fitToViewPort(); } Item { diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml index 7fe6a114163..d6574f660ca 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml @@ -32,24 +32,13 @@ View3D { environment: sceneEnv camera: theCamera - property bool ready: false - property real prevZoomFactor: -1 property Model sourceModel function fitToViewPort() { - cameraControl.focusObject(model, theCamera.eulerRotation, true, false); - - if (cameraControl._zoomFactor < 0.1) { - model.scale = model.scale.times(10); - } else if (cameraControl._zoomFactor > 10) { - model.scale = model.scale.times(0.1); - } else { - // We need one more render after zoom factor change, so only set ready when zoom factor - // or scaling hasn't changed from the previous frame - ready = _generalHelper.fuzzyCompare(cameraControl._zoomFactor, prevZoomFactor); - prevZoomFactor = cameraControl._zoomFactor; - } + // The magic number is the distance from camera default pos to origin + _generalHelper.calculateNodeBoundsAndFocusCamera(theCamera, importScene, root, + 1040); } SceneEnvironment { @@ -58,14 +47,6 @@ View3D { antialiasingQuality: SceneEnvironment.High } - EditCameraController { - id: cameraControl - camera: theCamera - anchors.fill: parent - view3d: root - ignoreToolState: true - } - DirectionalLight { eulerRotation.x: -30 eulerRotation.y: -30 @@ -75,16 +56,15 @@ View3D { id: theCamera z: 600 y: 600 + x: 600 eulerRotation.x: -45 + eulerRotation.y: -45 clipFar: 10000 clipNear: 1 } Model { id: model - readonly property bool _edit3dLocked: true // Make this non-pickable - eulerRotation.y: 45 - source: sourceModel.source geometry: sourceModel.geometry diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/NodeNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/NodeNodeView.qml index 49d88d4c8a9..a48eb665191 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/NodeNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/NodeNodeView.qml @@ -32,30 +32,11 @@ View3D { environment: sceneEnv camera: theCamera - property bool ready: false - property bool first: true - property real prevZoomFactor: -1 - function fitToViewPort() { - if (first) { - first = false; - selectionBox.targetNode = root.importScene; - } else { - cameraControl.focusObject(selectionBox.model, theCamera.eulerRotation, true, false); - - if (cameraControl._zoomFactor < 0.1) { - root.importScene.scale = root.importScene.scale.times(10); - } else if (cameraControl._zoomFactor > 10) { - root.importScene.scale = root.importScene.scale.times(0.1); - } else { - // We need one more render after zoom factor change, so only set ready when zoom factor - // or scaling hasn't changed from the previous frame - ready = _generalHelper.fuzzyCompare(cameraControl._zoomFactor, prevZoomFactor); - prevZoomFactor = cameraControl._zoomFactor; - selectionBox.visible = false; - } - } + // The magic number is the distance from camera default pos to origin + _generalHelper.calculateNodeBoundsAndFocusCamera(theCamera, importScene, root, + 1040); } SceneEnvironment { @@ -64,20 +45,6 @@ View3D { antialiasingQuality: SceneEnvironment.High } - SelectionBox { - id: selectionBox - view3D: root - geometryName: "NodeNodeViewSB" - } - - EditCameraController { - id: cameraControl - camera: theCamera - anchors.fill: parent - view3d: root - ignoreToolState: true - } - DirectionalLight { eulerRotation.x: -30 eulerRotation.y: -30 diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp index f0131c80895..9d7d4b05ce9 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp @@ -55,6 +55,11 @@ const QString _globalStateId = QStringLiteral("@GTS"); // global tool state const QString _lastSceneIdKey = QStringLiteral("lastSceneId"); const QString _rootSizeKey = QStringLiteral("rootSize"); +static const float floatMin = std::numeric_limits::lowest(); +static const float floatMax = std::numeric_limits::max(); +static const QVector3D maxVec = QVector3D(floatMax, floatMax, floatMax); +static const QVector3D minVec = QVector3D(floatMin, floatMin, floatMin); + GeneralHelper::GeneralHelper() : QObject() { @@ -269,6 +274,37 @@ QVector4D GeneralHelper::focusNodesToCamera(QQuick3DCamera *camera, float defaul return QVector4D(lookAt, cameraZoomFactor); } +// This function can be used to synchronously focus camera on a node, which doesn't have to be +// a selection box for bound calculations to work. This is used to focus the view for +// various preview image generations, where doing things asynchronously is not good +// and recalculating bounds for every frame is not a problem. +void GeneralHelper::calculateNodeBoundsAndFocusCamera( + QQuick3DCamera *camera, QQuick3DNode *node, QQuick3DViewport *viewPort, + float defaultLookAtDistance) +{ + QVector3D minBounds; + QVector3D maxBounds; + + getBounds(viewPort, node, minBounds, maxBounds); + + QVector3D extents = maxBounds - minBounds; + QVector3D lookAt = minBounds + (extents / 2.f); + float maxExtent = qMax(extents.x(), qMax(extents.y(), extents.z())); + + // Reset camera position to default zoom + QMatrix4x4 m = camera->sceneTransform(); + const float *dataPtr(m.data()); + QVector3D newLookVector(dataPtr[8], dataPtr[9], dataPtr[10]); + newLookVector.normalize(); + newLookVector *= defaultLookAtDistance; + + camera->setPosition(lookAt + newLookVector); + + float newZoomFactor = maxExtent / 725.f; // Divisor taken from focusNodesToCamera function + + zoomCamera(viewPort, camera, 0, defaultLookAtDistance, lookAt, newZoomFactor, false); +} + // Aligns any cameras found in nodes list to a camera. // Only position and rotation are copied, rest of the camera properties stay the same. void GeneralHelper::alignCameras(QQuick3DCamera *camera, const QVariant &nodes) @@ -727,6 +763,129 @@ QVector3D GeneralHelper::pivotScenePosition(QQuick3DNode *node) const return mat44::getPosition(sceneTransform); } +// Calculate bounds for given node, including all child nodes. +// Returns true if the tree contains at least one Model node. +bool GeneralHelper::getBounds(QQuick3DViewport *view3D, QQuick3DNode *node, QVector3D &minBounds, + QVector3D &maxBounds, bool recursive) +{ + if (!node) { + const float halfExtent = 100.f; + minBounds = {-halfExtent, -halfExtent, -halfExtent}; + maxBounds = {halfExtent, halfExtent, halfExtent}; + return false; + } + + QMatrix4x4 localTransform; + auto nodePriv = QQuick3DObjectPrivate::get(node); + auto renderNode = static_cast(nodePriv->spatialNode); + + if (recursive && renderNode) { + if (renderNode->flags.testFlag(QSSGRenderNode::Flag::TransformDirty)) + renderNode->calculateLocalTransform(); + localTransform = renderNode->localTransform; + } + + QVector3D localMinBounds = maxVec; + QVector3D localMaxBounds = minVec; + + // Find bounds for children + QVector minBoundsVec; + QVector maxBoundsVec; + const auto children = node->childItems(); + bool hasModel = false; + for (const auto child : children) { + if (auto childNode = qobject_cast(child)) { + QVector3D newMinBounds = minBounds; + QVector3D newMaxBounds = maxBounds; + hasModel = getBounds(view3D, childNode, newMinBounds, newMaxBounds, true); + // Ignore any subtrees that do not have Model in them as we don't need those + // for visual bounds calculations + if (hasModel) { + minBoundsVec << newMinBounds; + maxBoundsVec << newMaxBounds; + } + } + } + + auto combineMinBounds = [](QVector3D &target, const QVector3D &source) { + target.setX(qMin(source.x(), target.x())); + target.setY(qMin(source.y(), target.y())); + target.setZ(qMin(source.z(), target.z())); + }; + auto combineMaxBounds = [](QVector3D &target, const QVector3D &source) { + target.setX(qMax(source.x(), target.x())); + target.setY(qMax(source.y(), target.y())); + target.setZ(qMax(source.z(), target.z())); + }; + auto transformCorner = [&](const QMatrix4x4 &m, QVector3D &minTarget, QVector3D &maxTarget, + const QVector3D &corner) { + QVector3D mappedCorner = m.map(corner); + combineMinBounds(minTarget, mappedCorner); + combineMaxBounds(maxTarget, mappedCorner); + }; + auto transformCorners = [&](const QMatrix4x4 &m, QVector3D &minTarget, QVector3D &maxTarget, + const QVector3D &minCorner, const QVector3D &maxCorner) { + transformCorner(m, minTarget, maxTarget, minCorner); + transformCorner(m, minTarget, maxTarget, maxCorner); + transformCorner(m, minTarget, maxTarget, QVector3D(minCorner.x(), minCorner.y(), maxCorner.z())); + transformCorner(m, minTarget, maxTarget, QVector3D(minCorner.x(), maxCorner.y(), minCorner.z())); + transformCorner(m, minTarget, maxTarget, QVector3D(maxCorner.x(), minCorner.y(), minCorner.z())); + transformCorner(m, minTarget, maxTarget, QVector3D(minCorner.x(), maxCorner.y(), maxCorner.z())); + transformCorner(m, minTarget, maxTarget, QVector3D(maxCorner.x(), maxCorner.y(), minCorner.z())); + transformCorner(m, minTarget, maxTarget, QVector3D(maxCorner.x(), minCorner.y(), maxCorner.z())); + }; + + // Combine all child bounds + for (const auto &newBounds : qAsConst(minBoundsVec)) + combineMinBounds(localMinBounds, newBounds); + for (const auto &newBounds : qAsConst(maxBoundsVec)) + combineMaxBounds(localMaxBounds, newBounds); + + if (qobject_cast(node)) { + if (auto renderModel = static_cast(renderNode)) { + QWindow *window = static_cast(view3D->window()); + if (window) { + QSSGRef context; +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + context = QSSGRenderContextInterface::getRenderContextInterface(quintptr(window)); +#else + context = QQuick3DObjectPrivate::get(node)->sceneManager->rci; +#endif + if (!context.isNull()) { + auto bufferManager = context->bufferManager(); +#if QT_VERSION < QT_VERSION_CHECK(6, 3, 0) + QSSGBounds3 bounds = renderModel->getModelBounds(bufferManager); +#else + QSSGBounds3 bounds = bufferManager->getModelBounds(renderModel); +#endif + QVector3D center = bounds.center(); + QVector3D extents = bounds.extents(); + QVector3D localMin = center - extents; + QVector3D localMax = center + extents; + + combineMinBounds(localMinBounds, localMin); + combineMaxBounds(localMaxBounds, localMax); + + hasModel = true; + } + } + } + } else { + combineMinBounds(localMinBounds, {}); + combineMaxBounds(localMaxBounds, {}); + } + + if (localMaxBounds == minVec) { + localMinBounds = {}; + localMaxBounds = {}; + } + + // Transform local space bounding box to parent space + transformCorners(localTransform, minBounds, maxBounds, localMinBounds, localMaxBounds); + + return hasModel; +} + } } diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h index 06068601537..46e6019dd58 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h @@ -72,6 +72,9 @@ public: const QVariant &nodes, QQuick3DViewport *viewPort, float oldZoom, bool updateZoom = true, bool closeUp = false); + Q_INVOKABLE void calculateNodeBoundsAndFocusCamera(QQuick3DCamera *camera, QQuick3DNode *node, + QQuick3DViewport *viewPort, + float defaultLookAtDistance); Q_INVOKABLE void alignCameras(QQuick3DCamera *camera, const QVariant &nodes); Q_INVOKABLE QVector3D alignView(QQuick3DCamera *camera, const QVariant &nodes, const QVector3D &lookAtPoint); @@ -126,6 +129,8 @@ protected: private: void handlePendingToolStateUpdate(); QVector3D pivotScenePosition(QQuick3DNode *node) const; + bool getBounds(QQuick3DViewport *view3D, QQuick3DNode *node, QVector3D &minBounds, + QVector3D &maxBounds, bool recursive = false); QTimer m_overlayUpdateTimer; QTimer m_toolStateUpdateTimer; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp index b37486f0481..d496aff3889 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp @@ -1588,6 +1588,11 @@ bool NodeInstanceServer::isInformationServer() const return false; } +bool NodeInstanceServer::isPreviewServer() const +{ + return false; +} + static QString baseProperty(const QString &property) { int index = property.indexOf('.'); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h index f2255bd891d..ba51f5e5888 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h @@ -229,8 +229,10 @@ public: virtual QImage grabWindow() = 0; virtual QImage grabItem(QQuickItem *item) = 0; + virtual bool renderWindow() = 0; virtual bool isInformationServer() const; + virtual bool isPreviewServer() const; void addAnimation(QQuickAbstractAnimation *animation); QVector animations() const; QVariant animationDefaultValue(int index) const; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp index 4eb8cdd65f4..9f3a1d6b3bc 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp @@ -180,6 +180,11 @@ bool ObjectNodeInstance::isLayoutable() const return false; } +bool ObjectNodeInstance::isRenderable() const +{ + return false; +} + bool ObjectNodeInstance::equalGraphicsItem(QGraphicsItem * /*item*/) const { return false; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.h index 67e1663496c..88e2ca26770 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.h @@ -103,6 +103,7 @@ public: virtual bool isQuickItem() const; virtual bool isQuickWindow() const; virtual bool isLayoutable() const; + virtual bool isRenderable() const; virtual bool equalGraphicsItem(QGraphicsItem *item) const; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5captureimagenodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5captureimagenodeinstanceserver.cpp index c0d763c906b..cff435bdd49 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5captureimagenodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5captureimagenodeinstanceserver.cpp @@ -44,10 +44,10 @@ QImage renderImage(ServerNodeInstance rootNodeInstance) QSize previewImageSize = rootNodeInstance.boundingRect().size().toSize(); if (previewImageSize.isEmpty()) - previewImageSize = {300, 300}; + previewImageSize = {150, 150}; - if (previewImageSize.width() > 300 || previewImageSize.height() > 300) - previewImageSize.scale({300, 300}, Qt::KeepAspectRatio); + if (previewImageSize.width() > 150 || previewImageSize.height() > 150) + previewImageSize.scale({150, 150}, Qt::KeepAspectRatio); QImage previewImage = rootNodeInstance.renderPreviewImage(previewImageSize); @@ -68,7 +68,8 @@ void Qt5CaptureImageNodeInstanceServer::collectItemChangesAndSendChangeCommands( inFunction = true; auto rooNodeInstance = rootNodeInstance(); - rooNodeInstance.rootQuickItem()->setClip(true); + if (QQuickItem *qitem = rooNodeInstance.rootQuickItem()) + qitem->setClip(true); DesignerSupport::polishItems(quickWindow()); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp index afde832afcb..e2bd56562d5 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp @@ -1007,17 +1007,17 @@ void Qt5InformationNodeInstanceServer::doRenderModelNodeImageView() void Qt5InformationNodeInstanceServer::doRenderModelNode3DImageView() { #ifdef QUICK3D_MODULE - m_modelNode3DImageViewAsyncData.cleanup(); if (m_modelNode3DImageViewData.rootItem) { QMetaObject::invokeMethod(m_modelNode3DImageViewData.rootItem, "destroyView"); if (!m_modelNode3DImageViewData.contentItem) m_modelNode3DImageViewData.contentItem = getContentItemForRendering(m_modelNode3DImageViewData.rootItem); + QImage renderImage; if (m_modelNodePreviewImageCache.contains(m_modelNodePreviewImageCommand.componentPath())) { - m_modelNode3DImageViewAsyncData.renderImage - = m_modelNodePreviewImageCache[m_modelNodePreviewImageCommand.componentPath()]; - modelNode3DImageViewSendImageToCreator(); + renderImage = m_modelNodePreviewImageCache[m_modelNodePreviewImageCommand.componentPath()]; } else { + bool createdFromComponent = false; + QObject *instanceObj = nullptr; ServerNodeInstance instance = instanceForId(m_modelNodePreviewImageCommand.instanceId()); if (!m_modelNodePreviewImageCommand.componentPath().isEmpty() && instance.isSubclassOf("QQuick3DNode")) { @@ -1026,15 +1026,14 @@ void Qt5InformationNodeInstanceServer::doRenderModelNode3DImageView() // wouldn't want the children of the Node to appear in the preview. QQmlComponent component(engine()); component.loadUrl(QUrl::fromLocalFile(m_modelNodePreviewImageCommand.componentPath())); - m_modelNode3DImageViewAsyncData.instanceObj = qobject_cast(component.create()); - if (!m_modelNode3DImageViewAsyncData.instanceObj) { + instanceObj = qobject_cast(component.create()); + if (!instanceObj) { qWarning() << "Could not create preview component: " << component.errors(); - m_modelNode3DImageViewAsyncData.cleanup(); return; } - m_modelNode3DImageViewAsyncData.createdFromComponent = true; + createdFromComponent = true; } else { - m_modelNode3DImageViewAsyncData.instanceObj = instance.internalObject(); + instanceObj = instance.internalObject(); } QSize renderSize = m_modelNodePreviewImageCommand.size(); if (Internal::QuickItemNodeInstance::unifiedRenderPathOrQt6()) { @@ -1055,69 +1054,53 @@ void Qt5InformationNodeInstanceServer::doRenderModelNode3DImageView() QMetaObject::invokeMethod( m_modelNode3DImageViewData.rootItem, "createViewForObject", - Q_ARG(QVariant, objectToVariant(m_modelNode3DImageViewAsyncData.instanceObj))); + Q_ARG(QVariant, objectToVariant(instanceObj))); - // Selection box geometry updates have an asynchronous step, so we need to do rendering - // in asynchronous steps as well, since we are adjusting the selection box geometry - // while finding correct zoom level. - m_modelNode3DImageViewAsyncData.timer.start(); - } - } + // Need to render twice, first render updates spatial nodes + for (int i = 0; i < 2; ++i) { + if (i == 1) + QMetaObject::invokeMethod(m_modelNode3DImageViewData.rootItem, "fitToViewPort" + , Qt::DirectConnection); + + updateNodesRecursive(m_modelNode3DImageViewData.contentItem); +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + if (Internal::QuickItemNodeInstance::unifiedRenderPath()) { + renderImage = m_modelNode3DImageViewData.window->grabWindow(); + } else { + // Fake render loop signaling to update things like QML items as 3D textures + m_modelNode3DImageViewData.window->beforeSynchronizing(); + m_modelNode3DImageViewData.window->beforeRendering(); + + QSizeF size = qobject_cast(m_modelNode3DImageViewData.contentItem)->size(); + QRectF renderRect(QPointF(0., 0.), size); + renderImage = designerSupport()->renderImageForItem(m_modelNode3DImageViewData.contentItem, + renderRect, size.toSize()); + m_modelNode3DImageViewData.window->afterRendering(); + } +#else + renderImage = grabRenderControl(m_modelNode3DImageViewData); #endif -} + } -void Qt5InformationNodeInstanceServer::modelNode3DImageViewSendImageToCreator() -{ - if (!m_modelNode3DImageViewAsyncData.renderImage.isNull()) { + QMetaObject::invokeMethod(m_modelNode3DImageViewData.rootItem, "destroyView"); + + if (createdFromComponent) { + // If component changes, puppet will need a reset anyway, so we can cache the image + m_modelNodePreviewImageCache.insert(m_modelNodePreviewImageCommand.componentPath(), + renderImage); + delete instanceObj; + } + } // Key number is selected so that it is unlikely to conflict other ImageContainer use. ImageContainer imgContainer(m_modelNodePreviewImageCommand.instanceId(), {}, 2100000001); - imgContainer.setImage(m_modelNode3DImageViewAsyncData.renderImage); + imgContainer.setImage(renderImage); // send the rendered image to creator process nodeInstanceClient()->handlePuppetToCreatorCommand( {PuppetToCreatorCommand::RenderModelNodePreviewImage, QVariant::fromValue(imgContainer)}); - - m_modelNode3DImageViewAsyncData.cleanup(); } -} - -void Qt5InformationNodeInstanceServer::modelNode3DImageViewRenderStep() -{ - ++m_modelNode3DImageViewAsyncData.count; - - updateNodesRecursive(m_modelNode3DImageViewData.contentItem); -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - if (Internal::QuickItemNodeInstance::unifiedRenderPath()) { - m_modelNode3DImageViewAsyncData.renderImage = m_modelNode3DImageViewData.window->grabWindow(); - } else { - // Fake render loop signaling to update things like QML items as 3D textures - m_modelNode3DImageViewData.window->beforeSynchronizing(); - m_modelNode3DImageViewData.window->beforeRendering(); - - QSizeF size = qobject_cast(m_modelNode3DImageViewData.contentItem)->size(); - QRectF renderRect(QPointF(0., 0.), size); - m_modelNode3DImageViewAsyncData.renderImage - = designerSupport()->renderImageForItem(m_modelNode3DImageViewData.contentItem, - renderRect, size.toSize()); - m_modelNode3DImageViewData.window->afterRendering(); - } -#else - m_modelNode3DImageViewAsyncData.renderImage = grabRenderControl(m_modelNode3DImageViewData); #endif - QMetaObject::invokeMethod(m_modelNode3DImageViewData.rootItem, "afterRender"); - const bool ready = QQmlProperty::read(m_modelNode3DImageViewData.rootItem, "ready").value(); - if (ready || m_modelNode3DImageViewAsyncData.count >= 10) { - QMetaObject::invokeMethod(m_modelNode3DImageViewData.rootItem, "destroyView"); - if (m_modelNode3DImageViewAsyncData.createdFromComponent) { - // If component changes, puppet will need a reset anyway, so we can cache the image - m_modelNodePreviewImageCache.insert(m_modelNodePreviewImageCommand.componentPath(), - m_modelNode3DImageViewAsyncData.renderImage); - } - modelNode3DImageViewSendImageToCreator(); - } else { - m_modelNode3DImageViewAsyncData.timer.start(); - } } static QRectF itemBoundingRect(QQuickItem *item) @@ -1234,7 +1217,6 @@ Qt5InformationNodeInstanceServer::Qt5InformationNodeInstanceServer(NodeInstanceC m_render3DEditViewTimer.setSingleShot(true); m_inputEventTimer.setSingleShot(true); m_renderModelNodeImageViewTimer.setSingleShot(true); - m_modelNode3DImageViewAsyncData.timer.setSingleShot(true); m_dynamicAddObjectTimer.setSingleShot(true); #ifdef FPS_COUNTER @@ -1260,7 +1242,6 @@ Qt5InformationNodeInstanceServer::~Qt5InformationNodeInstanceServer() m_render3DEditViewTimer.stop(); m_inputEventTimer.stop(); m_renderModelNodeImageViewTimer.stop(); - m_modelNode3DImageViewAsyncData.timer.stop(); m_dynamicAddObjectTimer.stop(); if (m_editView3DData.rootItem) @@ -1677,8 +1658,6 @@ void Qt5InformationNodeInstanceServer::setup3DEditView(const QList &instances); void handleInputEvents(); @@ -190,26 +188,6 @@ private: QObject *m_3dHelper = nullptr; int m_need3DEditViewRender = 0; QSet m_dynamicObjectConstructors; - - struct ModelNode3DImageViewAsyncData { - QTimer timer; - QImage renderImage; - int count = 0; - bool createdFromComponent = false; - QObject *instanceObj = nullptr; - - void cleanup() - { - timer.stop(); - count = 0; - renderImage = {}; - if (createdFromComponent) - delete instanceObj; - instanceObj = nullptr; - createdFromComponent = false; - } - }; - ModelNode3DImageViewAsyncData m_modelNode3DImageViewAsyncData; }; } // namespace QmlDesigner diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.h index 4af451b61ae..a0c79296033 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.h @@ -70,6 +70,7 @@ public: QImage grabWindow() override; QImage grabItem(QQuickItem *item) override; + bool renderWindow() override; static QQuickItem *parentEffectItem(QQuickItem *item); @@ -97,7 +98,6 @@ protected: virtual bool initRhi(RenderViewData &viewData); virtual QImage grabRenderControl(RenderViewData &viewData); - virtual bool renderWindow(); private: RenderViewData m_viewData; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5previewnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5previewnodeinstanceserver.cpp index fb3113bdcd1..f61ba1a3421 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5previewnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5previewnodeinstanceserver.cpp @@ -133,4 +133,9 @@ void Qt5PreviewNodeInstanceServer::changePreviewImageSize( collectItemChangesAndSendChangeCommands(); } +bool Qt5PreviewNodeInstanceServer::isPreviewServer() const +{ + return true; +} + } // namespace QmlDesigner diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5previewnodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5previewnodeinstanceserver.h index 182db45d405..6c97658466f 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5previewnodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5previewnodeinstanceserver.h @@ -39,6 +39,7 @@ public: void changeState(const ChangeStateCommand &command) override; void removeSharedMemory(const RemoveSharedMemoryCommand &command) override; void changePreviewImageSize(const ChangePreviewImageSizeCommand &command) override; + bool isPreviewServer() const override; QImage renderPreviewImage(); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp index 980da0da791..65bda831a6e 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp @@ -26,6 +26,8 @@ #include "quick3dnodeinstance.h" #include "qt5nodeinstanceserver.h" #include "qt5informationnodeinstanceserver.h" +#include "quickitemnodeinstance.h" +#include "../editor3d/generalhelper.h" #include @@ -37,6 +39,7 @@ #include #ifdef QUICK3D_MODULE +#include #include #include #include @@ -45,8 +48,10 @@ #if defined(QUICK3D_ASSET_UTILS_MODULE) && QT_VERSION > QT_VERSION_CHECK(6, 2, 0) #include #endif +#include #endif + namespace QmlDesigner { namespace Internal { @@ -57,6 +62,7 @@ Quick3DNodeInstance::Quick3DNodeInstance(QObject *node) Quick3DNodeInstance::~Quick3DNodeInstance() { + delete m_dummyRootView; } void Quick3DNodeInstance::initialize(const ObjectNodeInstance::Pointer &objectNodeInstance, @@ -87,10 +93,123 @@ void Quick3DNodeInstance::initialize(const ObjectNodeInstance::Pointer &objectNo } } } + +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + // In case this is the scene root, we need to create a dummy View3D for the scene + // in preview puppets + if (instanceId() == 0 && nodeInstanceServer()->isPreviewServer()) { + auto helper = new QmlDesigner::Internal::GeneralHelper(); + engine()->rootContext()->setContextProperty("_generalHelper", helper); + + QQmlComponent component(engine()); + component.loadUrl(QUrl("qrc:/qtquickplugin/mockfiles/qt6/ModelNode3DImageView.qml")); + m_dummyRootView = qobject_cast(component.create()); + + QMetaObject::invokeMethod( + m_dummyRootView, "createViewForNode", + Q_ARG(QVariant, QVariant::fromValue(object()))); + + nodeInstanceServer()->setRootItem(m_dummyRootView); + } +#endif #endif ObjectNodeInstance::initialize(objectNodeInstance, flags); } +QImage Quick3DNodeInstance::renderImage() const +{ +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + if (!isRootNodeInstance() || !m_dummyRootView) + return {}; + + QSize size(640, 480); + nodeInstanceServer()->quickWindow()->resize(size); + m_dummyRootView->setSize(size); + + // Just render the window once to update spatial nodes + nodeInstanceServer()->renderWindow(); + + QMetaObject::invokeMethod(m_dummyRootView, "fitToViewPort", Qt::DirectConnection); + + QRectF renderBoundingRect = m_dummyRootView->boundingRect(); + QImage renderImage; + + if (QuickItemNodeInstance::unifiedRenderPath()) { + renderImage = nodeInstanceServer()->grabWindow(); + renderImage = renderImage.copy(renderBoundingRect.toRect()); + } else { + renderImage = nodeInstanceServer()->grabItem(m_dummyRootView); + } + + // When grabbing an offscreen window the device pixel ratio is 1 + renderImage.setDevicePixelRatio(1); + + return renderImage; +#endif + return {}; +} + +QImage Quick3DNodeInstance::renderPreviewImage(const QSize &previewImageSize) const +{ +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + if (!isRootNodeInstance() || !m_dummyRootView) + return {}; + + nodeInstanceServer()->quickWindow()->resize(previewImageSize); + m_dummyRootView->setSize(previewImageSize); + + // Just render the window once to update spatial nodes + nodeInstanceServer()->renderWindow(); + + QMetaObject::invokeMethod(m_dummyRootView, "fitToViewPort", Qt::DirectConnection); + + QRectF previewItemBoundingRect = boundingRect(); + + if (previewItemBoundingRect.isValid()) { + const QSize size = previewImageSize; + if (m_dummyRootView->isVisible()) { + QImage image; + image = nodeInstanceServer()->grabWindow(); + image = image.copy(previewItemBoundingRect.toRect()); + image = image.scaledToWidth(size.width()); + return image; + } else { + QImage transparentImage(size, QImage::Format_ARGB32_Premultiplied); + transparentImage.fill(Qt::transparent); + return transparentImage; + } + } +#endif + return {}; +} + +bool Quick3DNodeInstance::isRenderable() const +{ + return m_dummyRootView; +} + +QRectF Quick3DNodeInstance::boundingRect() const +{ + if (m_dummyRootView) + return m_dummyRootView->boundingRect(); + return ObjectNodeInstance::boundingRect(); +} + +QList Quick3DNodeInstance::stateInstances() const +{ + QList instanceList; +#ifdef QUICK3D_MODULE + if (auto obj3D = quick3DNode()) { + const QList stateList = QQuick3DObjectPrivate::get(obj3D)->_states()->states(); + for (QQuickState *state : stateList) { + if (state && nodeInstanceServer()->hasInstanceForObject(state)) + instanceList.append(nodeInstanceServer()->instanceForObject(state)); + } + } +#endif + return instanceList; +} + Qt5NodeInstanceServer *Quick3DNodeInstance::qt5NodeInstanceServer() const { return qobject_cast(nodeInstanceServer()); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.h index 892946ee1f6..322762af26a 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.h @@ -47,12 +47,22 @@ public: void initialize(const ObjectNodeInstance::Pointer &objectNodeInstance, InstanceContainer::NodeFlags flags) override; + QImage renderImage() const override; + QImage renderPreviewImage(const QSize &previewImageSize) const override; + + bool isRenderable() const override; + QRectF boundingRect() const override; + + QList stateInstances() const override; + protected: explicit Quick3DNodeInstance(QObject *node); private: Qt5NodeInstanceServer *qt5NodeInstanceServer() const; QQuick3DNode *quick3DNode() const; + + QQuickItem *m_dummyRootView = nullptr; }; } // namespace Internal diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.cpp index b78bf6328e7..41d0015ce56 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.cpp @@ -571,6 +571,11 @@ bool QuickItemNodeInstance::isQuickItem() const return true; } +bool QuickItemNodeInstance::isRenderable() const +{ + return quickItem() && (!s_unifiedRenderPath || isRootNodeInstance()); +} + QList QuickItemNodeInstance::stateInstances() const { QList instanceList; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.h index 46b22b8c9a8..50cf494e8e2 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.h @@ -94,6 +94,7 @@ public: bool isResizable() const override; bool isMovable() const override; bool isQuickItem() const override; + bool isRenderable() const override; QList stateInstances() const override; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp index 6b2ba783402..9803f6d79e6 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp @@ -154,7 +154,7 @@ void ServerNodeInstance::setNodeSource(const QString &source) bool ServerNodeInstance::holdsGraphical() const { - return m_nodeInstance->isQuickItem(); + return m_nodeInstance->isRenderable(); } bool ServerNodeInstance::isComponentWrap() const diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitem.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitem.cpp index 78e06f0b56b..c86e5360d1c 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitem.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitem.cpp @@ -48,7 +48,8 @@ QString ItemLibraryItem::typeName() const QString ItemLibraryItem::itemLibraryIconPath() const { - if (m_itemLibraryEntry.customComponentSource().isEmpty()) { + if (m_itemLibraryEntry.customComponentSource().isEmpty() + || !m_itemLibraryEntry.libraryEntryIconPath().isEmpty()) { return QStringLiteral("image://qmldesigner_itemlibrary/") + m_itemLibraryEntry.libraryEntryIconPath(); } else { diff --git a/src/plugins/qmldesigner/components/previewtooltip/previewimagetooltip.ui b/src/plugins/qmldesigner/components/previewtooltip/previewimagetooltip.ui index fec0ba8f384..6839c1b107d 100644 --- a/src/plugins/qmldesigner/components/previewtooltip/previewimagetooltip.ui +++ b/src/plugins/qmldesigner/components/previewtooltip/previewimagetooltip.ui @@ -6,8 +6,8 @@ 0 0 - 651 - 318 + 517 + 166 @@ -90,8 +90,8 @@ - 300 - 300 + 150 + 150 @@ -163,7 +163,7 @@ 0 - 1 + 3 diff --git a/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp b/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp index b4f50848b9a..f5164a97213 100644 --- a/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp +++ b/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp @@ -90,7 +90,8 @@ void ImageCacheCollector::start(Utils::SmallStringView name, model->setRewriterView(&rewriterView); - if (rewriterView.inErrorState() || !rewriterView.rootModelNode().metaInfo().isGraphicalItem()) { + if (rewriterView.inErrorState() || (!rewriterView.rootModelNode().metaInfo().isGraphicalItem() + && !rewriterView.rootModelNode().isSubclassOf("Quick3D.Node") )) { if (abortCallback) abortCallback(ImageCache::AbortReason::Failed); return; diff --git a/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp b/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp index cede56f299d..a001a8b0c29 100644 --- a/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp +++ b/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp @@ -420,6 +420,7 @@ void SubComponentManager::parseQuick3DAssetsItem(const QString &importUrl, const itemLibraryEntry.setType(type.toUtf8(), 1, 0); itemLibraryEntry.setName(name); itemLibraryEntry.setCategory(::QmlDesigner::SubComponentManager::tr("My 3D Components")); + itemLibraryEntry.setCustomComponentSource(qmlIt.fileInfo().absoluteFilePath()); itemLibraryEntry.setRequiredImport(importUrl); QString iconPath = qmlIt.fileInfo().absolutePath() + '/' + Constants::QUICK_3D_ASSET_ICON_DIR + '/' + name From 44493857c2b1bf154dd1c74cedca6f651b2802a9 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 18 Nov 2021 16:56:35 +0100 Subject: [PATCH 79/94] SdkTool: Use slightly less repetitive approach for operation interface Change-Id: I4d1d205c610df39be6a810dfda3049ae14a06806 Reviewed-by: Reviewed-by: Eike Ziller --- src/tools/sdktool/addabiflavor.cpp | 24 +- src/tools/sdktool/addabiflavor.h | 36 +-- src/tools/sdktool/addcmakeoperation.cpp | 37 ++- src/tools/sdktool/addcmakeoperation.h | 38 +-- src/tools/sdktool/adddebuggeroperation.cpp | 28 +- src/tools/sdktool/adddebuggeroperation.h | 38 ++- src/tools/sdktool/adddeviceoperation.cpp | 103 +++---- src/tools/sdktool/adddeviceoperation.h | 54 ++-- src/tools/sdktool/addkeysoperation.cpp | 14 +- src/tools/sdktool/addkeysoperation.h | 38 +-- src/tools/sdktool/addkitoperation.cpp | 284 +++++++++----------- src/tools/sdktool/addkitoperation.h | 57 ++-- src/tools/sdktool/addqtoperation.cpp | 60 ++--- src/tools/sdktool/addqtoperation.h | 36 ++- src/tools/sdktool/addtoolchainoperation.cpp | 55 ++-- src/tools/sdktool/addtoolchainoperation.h | 40 ++- src/tools/sdktool/addvalueoperation.cpp | 31 +-- src/tools/sdktool/addvalueoperation.h | 37 +-- src/tools/sdktool/findkeyoperation.h | 13 +- src/tools/sdktool/findvalueoperation.cpp | 2 +- src/tools/sdktool/findvalueoperation.h | 12 +- src/tools/sdktool/getoperation.h | 12 +- src/tools/sdktool/operation.cpp | 10 +- src/tools/sdktool/operation.h | 30 ++- src/tools/sdktool/rmcmakeoperation.cpp | 22 +- src/tools/sdktool/rmcmakeoperation.h | 35 +-- src/tools/sdktool/rmdebuggeroperation.cpp | 21 +- src/tools/sdktool/rmkitoperation.cpp | 54 ++-- src/tools/sdktool/rmqtoperation.cpp | 16 +- src/tools/sdktool/rmtoolchainoperation.cpp | 12 +- src/tools/sdktool/rmtoolchainoperation.h | 12 +- 31 files changed, 578 insertions(+), 683 deletions(-) diff --git a/src/tools/sdktool/addabiflavor.cpp b/src/tools/sdktool/addabiflavor.cpp index 01faa7b4183..c7fde38a62a 100644 --- a/src/tools/sdktool/addabiflavor.cpp +++ b/src/tools/sdktool/addabiflavor.cpp @@ -97,7 +97,7 @@ int AddAbiFlavor::execute() const if (map.isEmpty()) map = initializeAbiFlavors(); - QVariantMap result = addAbiFlavor(map, m_oses, m_flavor); + QVariantMap result = addAbiFlavor(map); if (result.isEmpty() || result == map) return 2; @@ -113,7 +113,7 @@ bool AddAbiFlavor::test() const || !map.contains(QLatin1String(VERSION))) return false; - map = addAbiFlavor(map, {"linux", "windows"}, "foo"); + map = AddAbiFlavorData{{"linux", "windows"}, "foo"}.addAbiFlavor(map); if (map.count() != 2 || !map.contains(QLatin1String(VERSION)) @@ -126,7 +126,7 @@ bool AddAbiFlavor::test() const return false; // Ignore known flavors: - const QVariantMap result = addAbiFlavor(map, {"linux"}, "foo"); + const QVariantMap result = AddAbiFlavorData({{"linux"}, "foo"}).addAbiFlavor(map);; if (map != result) return false; @@ -135,37 +135,35 @@ bool AddAbiFlavor::test() const } #endif -QVariantMap AddAbiFlavor::addAbiFlavor(const QVariantMap &map, - const QStringList &oses, - const QString &flavor) +QVariantMap AddAbiFlavorData::addAbiFlavor(const QVariantMap &map) const { // Sanity check: Is flavor already set in abi file? - if (exists(map, flavor)) { - std::cerr << "Error: flavor " << qPrintable(flavor) << " already defined as extra ABI flavor." << std::endl; + if (exists(map, m_flavor)) { + std::cerr << "Error: flavor " << qPrintable(m_flavor) << " already defined as extra ABI flavor." << std::endl; return map; } QVariantMap result = map; QVariantMap flavorMap = map.value(QLatin1String(FLAVORS)).toMap(); - flavorMap.insert(flavor, oses); + flavorMap.insert(m_flavor, m_oses); result.insert(QLatin1String(FLAVORS), flavorMap); return result; } -QVariantMap AddAbiFlavor::initializeAbiFlavors() +QVariantMap AddAbiFlavorData::initializeAbiFlavors() { QVariantMap map; map.insert(QLatin1String(VERSION), 1); return map; } -bool AddAbiFlavor::exists(const QString &flavor) +bool AddAbiFlavorData::exists(const QString &flavor) { - QVariantMap map = load(QLatin1String(ABI_FILE_ID)); + QVariantMap map = Operation::load(QLatin1String(ABI_FILE_ID)); return exists(map, flavor); } -bool AddAbiFlavor::exists(const QVariantMap &map, const QString &flavor) +bool AddAbiFlavorData::exists(const QVariantMap &map, const QString &flavor) { const QVariantMap flavorMap = map.value(QLatin1String(FLAVORS)).toMap(); return flavorMap.contains(flavor); diff --git a/src/tools/sdktool/addabiflavor.h b/src/tools/sdktool/addabiflavor.h index 61c817b8797..fabd9d001a9 100644 --- a/src/tools/sdktool/addabiflavor.h +++ b/src/tools/sdktool/addabiflavor.h @@ -27,32 +27,32 @@ #include "operation.h" -#include - -class AddAbiFlavor : public Operation +class AddAbiFlavorData { public: - QString name() const; - QString helpText() const; - QString argumentsHelpText() const; - - bool setArguments(const QStringList &args); - - int execute() const; - -#ifdef WITH_TESTS - bool test() const; -#endif - - static QVariantMap addAbiFlavor(const QVariantMap &map, - const QStringList &oses, const QString &flavor); + QVariantMap addAbiFlavor(const QVariantMap &map) const; static QVariantMap initializeAbiFlavors(); static bool exists(const QString &flavor); static bool exists(const QVariantMap &map, const QString &flavor); -private: QStringList m_oses; QString m_flavor; }; + +class AddAbiFlavor : public Operation, public AddAbiFlavorData +{ +public: + QString name() const final; + QString helpText() const final; + QString argumentsHelpText() const final; + + bool setArguments(const QStringList &args) final; + + int execute() const final; + +#ifdef WITH_TESTS + bool test() const final; +#endif +}; diff --git a/src/tools/sdktool/addcmakeoperation.cpp b/src/tools/sdktool/addcmakeoperation.cpp index a5c087e8466..9bbec46ac68 100644 --- a/src/tools/sdktool/addcmakeoperation.cpp +++ b/src/tools/sdktool/addcmakeoperation.cpp @@ -122,7 +122,7 @@ int AddCMakeOperation::execute() const if (map.isEmpty()) map = initializeCMake(); - QVariantMap result = addCMake(map, m_id, m_displayName, m_path, m_extra); + QVariantMap result = addCMake(map); if (result.isEmpty() || map == result) return 2; @@ -135,8 +135,7 @@ bool AddCMakeOperation::test() const QVariantMap map = initializeCMake(); // Add toolchain: - map = addCMake(map, "testId", "name", "/tmp/test", - KeyValuePairList() << KeyValuePair("ExtraKey", QVariant("ExtraValue"))); + map = AddCMakeData{"testId", "name", "/tmp/test", {{"ExtraKey", QVariant("ExtraValue")}}}.addCMake(map); if (map.value(COUNT).toInt() != 1 || !map.contains(QString::fromLatin1(PREFIX) + '0')) return false; @@ -150,14 +149,14 @@ bool AddCMakeOperation::test() const return false; // Ignore same Id: - QVariantMap unchanged = addCMake(map, "testId", "name2", "/tmp/test2", - KeyValuePairList() << KeyValuePair("ExtraKey", QVariant("ExtraValue2"))); + QVariantMap unchanged = AddCMakeData{"testId", "name2", "/tmp/test2", {{"ExtraKey", QVariant("ExtraValue2")}}} + .addCMake(map); if (!unchanged.isEmpty()) return false; // add 2nd cmake - map = addCMake(map, "{some-cm-id}", "name", "/tmp/test", - KeyValuePairList() << KeyValuePair("ExtraKey", QVariant("ExtraValue"))); + map = AddCMakeData{"{some-cm-id}", "name", "/tmp/test", {{"ExtraKey", QVariant("ExtraValue")}}} + .addCMake(map); if (map.value(COUNT).toInt() != 2 || !map.contains(QString::fromLatin1(PREFIX) + '0') || !map.contains(QString::fromLatin1(PREFIX) + '1')) @@ -183,13 +182,11 @@ bool AddCMakeOperation::test() const } #endif -QVariantMap AddCMakeOperation::addCMake(const QVariantMap &map, const QString &id, - const QString &displayName, const QString &path, - const KeyValuePairList &extra) +QVariantMap AddCMakeData::addCMake(const QVariantMap &map) const { // Sanity check: Does the Id already exist? - if (exists(map, id)) { - std::cerr << "Error: Id " << qPrintable(id) << " already defined for tool chains." << std::endl; + if (exists(map, m_id)) { + std::cerr << "Error: Id " << qPrintable(m_id) << " already defined for tool chains." << std::endl; return QVariantMap(); } @@ -206,20 +203,20 @@ QVariantMap AddCMakeOperation::addCMake(const QVariantMap &map, const QString &i const QString cm = QString::fromLatin1(PREFIX) + QString::number(count); KeyValuePairList data; - data << KeyValuePair({cm, ID_KEY}, QVariant(id)); - data << KeyValuePair({cm, DISPLAYNAME_KEY}, QVariant(displayName)); + data << KeyValuePair({cm, ID_KEY}, QVariant(m_id)); + data << KeyValuePair({cm, DISPLAYNAME_KEY}, QVariant(m_displayName)); data << KeyValuePair({cm, AUTODETECTED_KEY}, QVariant(true)); - data << KeyValuePair({cm, PATH_KEY}, Utils::FilePath::fromUserInput(path).toVariant()); + data << KeyValuePair({cm, PATH_KEY}, Utils::FilePath::fromUserInput(m_path).toVariant()); KeyValuePairList extraList; - foreach (const KeyValuePair &pair, extra) + foreach (const KeyValuePair &pair, m_extra) extraList << KeyValuePair(QStringList({cm}) << pair.key, pair.value); data.append(extraList); data << KeyValuePair(COUNT, QVariant(count + 1)); - return AddKeysOperation::addKeys(result, data); + return AddKeysData{data}.addKeys(result); } -QVariantMap AddCMakeOperation::initializeCMake() +QVariantMap AddCMakeData::initializeCMake() { QVariantMap map; map.insert(COUNT, 0); @@ -227,7 +224,7 @@ QVariantMap AddCMakeOperation::initializeCMake() return map; } -bool AddCMakeOperation::exists(const QVariantMap &map, const QString &id) +bool AddCMakeData::exists(const QVariantMap &map, const QString &id) { QStringList valueKeys = FindValueOperation::findValue(map, id); // support old settings using QByteArray for id's @@ -241,7 +238,7 @@ bool AddCMakeOperation::exists(const QVariantMap &map, const QString &id) return false; } -bool AddCMakeOperation::exists(const QString &id) +bool AddCMakeData::exists(const QString &id) { QVariantMap map = Operation::load("cmaketools"); return exists(map, id); diff --git a/src/tools/sdktool/addcmakeoperation.h b/src/tools/sdktool/addcmakeoperation.h index 51212154526..13045290178 100644 --- a/src/tools/sdktool/addcmakeoperation.h +++ b/src/tools/sdktool/addcmakeoperation.h @@ -27,34 +27,34 @@ #include "operation.h" -#include - -class AddCMakeOperation : public Operation +class AddCMakeData { public: - QString name() const; - QString helpText() const; - QString argumentsHelpText() const; - - bool setArguments(const QStringList &args); - - int execute() const; - -#ifdef WITH_TESTS - bool test() const; -#endif - - static QVariantMap addCMake(const QVariantMap &map, const QString &id, - const QString &displayName, const QString &path, - const KeyValuePairList &extra); + QVariantMap addCMake(const QVariantMap &map) const; static QVariantMap initializeCMake(); + static bool exists(const QString &id); static bool exists(const QVariantMap &map, const QString &id); -private: QString m_id; QString m_displayName; QString m_path; KeyValuePairList m_extra; }; + +class AddCMakeOperation : public Operation, public AddCMakeData +{ +public: + QString name() const final; + QString helpText() const final; + QString argumentsHelpText() const final; + + bool setArguments(const QStringList &args) final; + + int execute() const final; + +#ifdef WITH_TESTS + bool test() const final; +#endif +}; diff --git a/src/tools/sdktool/adddebuggeroperation.cpp b/src/tools/sdktool/adddebuggeroperation.cpp index eb7b9c66004..e3797525786 100644 --- a/src/tools/sdktool/adddebuggeroperation.cpp +++ b/src/tools/sdktool/adddebuggeroperation.cpp @@ -144,8 +144,7 @@ int AddDebuggerOperation::execute() const if (map.isEmpty()) map = initializeDebuggers(); - QVariantMap result = addDebugger(map, m_id, m_displayName, m_engine, m_binary, m_abis, - m_extra); + QVariantMap result = addDebugger(map); if (result.isEmpty() || map == result) return 2; @@ -169,13 +168,10 @@ bool AddDebuggerOperation::test() const } #endif -QVariantMap AddDebuggerOperation::addDebugger(const QVariantMap &map, - const QString &id, const QString &displayName, - int engine, const QString &binary, - const QStringList &abis, const KeyValuePairList &extra) +QVariantMap AddDebuggerData::addDebugger(const QVariantMap &map) const { // Sanity check: Make sure autodetection source is not in use already: - QStringList valueKeys = FindValueOperation::findValue(map, QVariant(id)); + QStringList valueKeys = FindValueOperation::findValue(map, QVariant(m_id)); bool hasId = false; foreach (const QString &k, valueKeys) { if (k.endsWith(QString(QLatin1Char('/')) + QLatin1String(ID))) { @@ -184,7 +180,7 @@ QVariantMap AddDebuggerOperation::addDebugger(const QVariantMap &map, } } if (hasId) { - std::cerr << "Error: Id " << qPrintable(id) << " already defined as debugger." << std::endl; + std::cerr << "Error: Id " << qPrintable(m_id) << " already defined as debugger." << std::endl; return QVariantMap(); } @@ -204,27 +200,27 @@ QVariantMap AddDebuggerOperation::addDebugger(const QVariantMap &map, // insert data: KeyValuePairList data; - data << KeyValuePair(QStringList() << debugger << QLatin1String(ID), QVariant(id)); + data << KeyValuePair(QStringList() << debugger << QLatin1String(ID), QVariant(m_id)); data << KeyValuePair(QStringList() << debugger << QLatin1String(DISPLAYNAME), - QVariant(displayName)); + QVariant(m_displayName)); data << KeyValuePair(QStringList() << debugger << QLatin1String(AUTODETECTED), QVariant(true)); - data << KeyValuePair(QStringList() << debugger << QLatin1String(ABIS), QVariant(abis)); - data << KeyValuePair(QStringList() << debugger << QLatin1String(ENGINE_TYPE), QVariant(engine)); + data << KeyValuePair(QStringList() << debugger << QLatin1String(ABIS), QVariant(m_abis)); + data << KeyValuePair(QStringList() << debugger << QLatin1String(ENGINE_TYPE), QVariant(m_engine)); data << KeyValuePair(QStringList() << debugger << QLatin1String(BINARY), - Utils::FilePath::fromUserInput(binary).toVariant()); + Utils::FilePath::fromUserInput(m_binary).toVariant()); data << KeyValuePair(QStringList() << QLatin1String(COUNT), QVariant(count + 1)); KeyValuePairList qtExtraList; - foreach (const KeyValuePair &pair, extra) + foreach (const KeyValuePair &pair, m_extra) qtExtraList << KeyValuePair(QStringList() << debugger << pair.key, pair.value); data.append(qtExtraList); - return AddKeysOperation::addKeys(cleaned, data); + return AddKeysData{data}.addKeys(cleaned); } -QVariantMap AddDebuggerOperation::initializeDebuggers() +QVariantMap AddDebuggerData::initializeDebuggers() { QVariantMap map; map.insert(QLatin1String(VERSION), 1); diff --git a/src/tools/sdktool/adddebuggeroperation.h b/src/tools/sdktool/adddebuggeroperation.h index 5c7731d780a..788900ee2c6 100644 --- a/src/tools/sdktool/adddebuggeroperation.h +++ b/src/tools/sdktool/adddebuggeroperation.h @@ -27,31 +27,13 @@ #include "operation.h" -#include - -class AddDebuggerOperation : public Operation +class AddDebuggerData { public: - QString name() const; - QString helpText() const; - QString argumentsHelpText() const; - - bool setArguments(const QStringList &args); - - int execute() const; - -#ifdef WITH_TESTS - bool test() const; -#endif - - static QVariantMap addDebugger(const QVariantMap &map, - const QString &id, const QString &displayName, - int engine, const QString &binary, - const QStringList &abis, const KeyValuePairList &extra); + QVariantMap addDebugger(const QVariantMap &map) const; static QVariantMap initializeDebuggers(); -private: QString m_id; QString m_displayName; int m_engine = 0; @@ -59,3 +41,19 @@ private: QStringList m_abis; KeyValuePairList m_extra; }; + +class AddDebuggerOperation : public Operation, public AddDebuggerData +{ +public: + QString name() const final; + QString helpText() const final; + QString argumentsHelpText() const final; + + bool setArguments(const QStringList &args) final; + + int execute() const final; + +#ifdef WITH_TESTS + bool test() const final; +#endif +}; diff --git a/src/tools/sdktool/adddeviceoperation.cpp b/src/tools/sdktool/adddeviceoperation.cpp index 91eff774cfe..4484e699225 100644 --- a/src/tools/sdktool/adddeviceoperation.cpp +++ b/src/tools/sdktool/adddeviceoperation.cpp @@ -247,10 +247,7 @@ int AddDeviceOperation::execute() const if (map.isEmpty()) map = initializeDevices(); - QVariantMap result = addDevice(map, m_id, m_displayName, m_type, m_authentication, - m_b2q_platformHardware, m_b2q_platformSoftware, m_debugServer, - m_freePortsSpec, m_host, m_keyFile, m_origin, m_osType, - m_password, m_sshPort, m_timeout, m_uname, m_version, m_extra); + QVariantMap result = addDevice(map); if (result.isEmpty() || map == result) return 2; @@ -263,13 +260,15 @@ bool AddDeviceOperation::test() const { QVariantMap map = initializeDevices(); - QVariantMap result = addDevice(map, QLatin1String("test id"), QLatin1String("test name"), - 1, 2, QLatin1String("HW"), QLatin1String("SW"), - QLatin1String("debugServer"), QLatin1String("ports"), - QLatin1String("host"), QLatin1String("keyfile"), 3, - QLatin1String("ostype"), QLatin1String("passwd"), 4, 5, - QLatin1String("uname"), 6, KeyValuePairList()); - + AddDeviceData devData = { + QLatin1String("test id"), QLatin1String("test name"), + 1, 2, QLatin1String("HW"), QLatin1String("SW"), + QLatin1String("debugServer"), QLatin1String("ports"), + QLatin1String("host"), QLatin1String("keyfile"), 3, + QLatin1String("ostype"), QLatin1String("passwd"), 4, 5, + QLatin1String("uname"), 6, KeyValuePairList() + }; + QVariantMap result = devData.addDevice(map); QVariantMap data = result.value(QLatin1String(DEVICEMANAGER_ID)).toMap(); QVariantList devList = data.value(QLatin1String(DEVICE_LIST_ID)).toList(); if (devList.count() != 1) @@ -312,30 +311,38 @@ bool AddDeviceOperation::test() const } #endif -QVariantMap AddDeviceOperation::addDevice(const QVariantMap &map, - const QString &id, const QString &displayName, int type, - int auth, const QString &hwPlatform, const QString &swPlatform, - const QString &debugServer, const QString &freePorts, - const QString &host, const QString &keyFile, - int origin, const QString &osType, const QString &passwd, - int sshPort, int timeout, const QString &uname, int version, - const KeyValuePairList &extra) +QVariantMap AddDeviceData::addDevice(const QVariantMap &map) const { QVariantMap result = map; - if (exists(map, id)) { - std::cerr << "Device " << qPrintable(id) << " already exists!" << std::endl; + if (exists(map, m_id)) { + std::cerr << "Device " << qPrintable(m_id) << " already exists!" << std::endl; return result; } QVariantMap dmMap = map.value(QLatin1String(DEVICEMANAGER_ID)).toMap(); QVariantList devList = dmMap.value(QLatin1String(DEVICE_LIST_ID)).toList(); - QVariantMap devMap - = AddKeysOperation::addKeys(QVariantMap(), - createDevice(id, displayName, type, auth, hwPlatform, - swPlatform, debugServer, freePorts, host, - keyFile, origin, osType, passwd, sshPort, - timeout, uname, version, extra)); + KeyValuePairList dev; + dev.append(KeyValuePair(QLatin1String(DEVICE_ID_ID), QVariant(m_id))); + dev.append(KeyValuePair(QLatin1String("Name"), QVariant(m_displayName))); + dev.append(KeyValuePair(QLatin1String("Type"), QVariant(m_type))); + dev.append(KeyValuePair(QLatin1String("Authentication"), QVariant(m_authentication))); + dev.append(KeyValuePair(QLatin1String("Boot2Qt.PlatformInfoHardware"), QVariant(m_b2q_platformHardware))); + dev.append(KeyValuePair(QLatin1String("Boot2Qt.PlatformInfoSoftware"), QVariant(m_b2q_platformSoftware))); + dev.append(KeyValuePair(QLatin1String("DebugServerKey"), QVariant(m_debugServer))); + dev.append(KeyValuePair(QLatin1String("FreePortsSpec"), QVariant(m_freePortsSpec))); + dev.append(KeyValuePair(QLatin1String("Host"), QVariant(m_host))); + dev.append(KeyValuePair(QLatin1String("KeyFile"), QVariant(m_keyFile))); + dev.append(KeyValuePair(QLatin1String("Origin"), QVariant(m_origin))); + dev.append(KeyValuePair(QLatin1String("OsType"), QVariant(m_osType))); + dev.append(KeyValuePair(QLatin1String("Password"), QVariant(m_password))); + dev.append(KeyValuePair(QLatin1String("SshPort"), QVariant(m_sshPort))); + dev.append(KeyValuePair(QLatin1String("Timeout"), QVariant(m_timeout))); + dev.append(KeyValuePair(QLatin1String("Uname"), QVariant(m_uname))); + dev.append(KeyValuePair(QLatin1String("Version"), QVariant(m_version))); + dev.append(m_extra); + + QVariantMap devMap = AddKeysData{dev}.addKeys(QVariantMap()); devList.append(devMap); @@ -346,7 +353,7 @@ QVariantMap AddDeviceOperation::addDevice(const QVariantMap &map, return result; } -QVariantMap AddDeviceOperation::initializeDevices() +QVariantMap AddDeviceData::initializeDevices() { QVariantMap dmData; dmData.insert(QLatin1String(DEFAULT_DEVICES_ID), QVariantMap()); @@ -357,13 +364,13 @@ QVariantMap AddDeviceOperation::initializeDevices() return data; } -bool AddDeviceOperation::exists(const QString &id) +bool AddDeviceData::exists(const QString &id) { - QVariantMap map = load(QLatin1String("Devices")); + QVariantMap map = Operation::load(QLatin1String("Devices")); return exists(map, id); } -bool AddDeviceOperation::exists(const QVariantMap &map, const QString &id) +bool AddDeviceData::exists(const QVariantMap &map, const QString &id) { if (id == QLatin1String(INTERNAL_DSEKTOP_DEVICE_ID)) return true; @@ -377,37 +384,3 @@ bool AddDeviceOperation::exists(const QVariantMap &map, const QString &id) } return false; } - -Operation::KeyValuePairList AddDeviceOperation::createDevice(const QString &id, const QString &displayName, - int type, int auth, const QString &hwPlatform, - const QString &swPlatform, const QString &debugServer, - const QString &freePorts, const QString &host, - const QString &keyFile, int origin, - const QString &osType, const QString &passwd, - int sshPort, int timeout, const QString &uname, - int version, const Operation::KeyValuePairList &extra) -{ - Operation::KeyValuePairList dev; - dev.append(KeyValuePair(QLatin1String(DEVICE_ID_ID), QVariant(id))); - dev.append(KeyValuePair(QLatin1String("Name"), QVariant(displayName))); - dev.append(KeyValuePair(QLatin1String("Type"), QVariant(type))); - - dev.append(KeyValuePair(QLatin1String("Authentication"), QVariant(auth))); - dev.append(KeyValuePair(QLatin1String("Boot2Qt.PlatformInfoHardware"), QVariant(hwPlatform))); - dev.append(KeyValuePair(QLatin1String("Boot2Qt.PlatformInfoSoftware"), QVariant(swPlatform))); - dev.append(KeyValuePair(QLatin1String("DebugServerKey"), QVariant(debugServer))); - dev.append(KeyValuePair(QLatin1String("FreePortsSpec"), QVariant(freePorts))); - dev.append(KeyValuePair(QLatin1String("Host"), QVariant(host))); - dev.append(KeyValuePair(QLatin1String("KeyFile"), QVariant(keyFile))); - dev.append(KeyValuePair(QLatin1String("Origin"), QVariant(origin))); - dev.append(KeyValuePair(QLatin1String("OsType"), QVariant(osType))); - dev.append(KeyValuePair(QLatin1String("Password"), QVariant(passwd))); - dev.append(KeyValuePair(QLatin1String("SshPort"), QVariant(sshPort))); - dev.append(KeyValuePair(QLatin1String("Timeout"), QVariant(timeout))); - dev.append(KeyValuePair(QLatin1String("Uname"), QVariant(uname))); - dev.append(KeyValuePair(QLatin1String("Version"), QVariant(version))); - - dev.append(extra); - - return dev; -} diff --git a/src/tools/sdktool/adddeviceoperation.h b/src/tools/sdktool/adddeviceoperation.h index 843d78f6f6c..2e0c9cfb615 100644 --- a/src/tools/sdktool/adddeviceoperation.h +++ b/src/tools/sdktool/adddeviceoperation.h @@ -35,60 +35,48 @@ extern const char DEVICE_LIST_ID[]; extern const char DEVICE_ID_ID[]; -class AddDeviceOperation : public Operation +class AddDeviceData { public: - QString name() const; - QString helpText() const; - QString argumentsHelpText() const; - - bool setArguments(const QStringList &args); - - int execute() const; - -#ifdef WITH_TESTS - bool test() const; -#endif - - static QVariantMap addDevice(const QVariantMap &map, - const QString &id, const QString &displayName, int type, - int auth, const QString &hwPlatform, const QString &swPlatform, - const QString &debugServer, const QString &freePorts, - const QString &host, const QString &keyFile, - int origin, const QString &osType, const QString &passwd, - int sshPort, int timeout, const QString &uname, int version, - const KeyValuePairList &extra); + QVariantMap addDevice(const QVariantMap &map) const; static QVariantMap initializeDevices(); static bool exists(const QString &id); static bool exists(const QVariantMap &map, const QString &id); -private: - static KeyValuePairList createDevice(const QString &id, const QString &displayName, int type, - int auth, const QString &hwPlatform, const QString &swPlatform, - const QString &debugServer, const QString &freePorts, - const QString &host, const QString &keyFile, - int origin, const QString &osType, const QString &passwd, - int sshPort, int timeout, const QString &uname, int version, - const KeyValuePairList &extra); - + QString m_id; + QString m_displayName; + int m_type = -1; int m_authentication = -1; QString m_b2q_platformHardware; QString m_b2q_platformSoftware; QString m_debugServer; QString m_freePortsSpec; QString m_host; - QString m_id; QString m_keyFile; - QString m_displayName; int m_origin = 1; QString m_osType; QString m_password; int m_sshPort = 0; int m_timeout = 5; - int m_type = -1; QString m_uname; int m_version = 0; KeyValuePairList m_extra; }; + +class AddDeviceOperation : public Operation, public AddDeviceData +{ +public: + QString name() const final; + QString helpText() const final; + QString argumentsHelpText() const final; + + bool setArguments(const QStringList &args) final; + + int execute() const final; + +#ifdef WITH_TESTS + bool test() const final; +#endif +}; diff --git a/src/tools/sdktool/addkeysoperation.cpp b/src/tools/sdktool/addkeysoperation.cpp index 95535a7e976..cc26b536f58 100644 --- a/src/tools/sdktool/addkeysoperation.cpp +++ b/src/tools/sdktool/addkeysoperation.cpp @@ -76,7 +76,7 @@ int AddKeysOperation::execute() const QVariantMap map = load(m_file); - QVariantMap result = addKeys(map, m_data); + QVariantMap result = addKeys(map); if (result.isEmpty() || map == result) return 4; @@ -108,7 +108,7 @@ bool AddKeysOperation::test() const data.append(KeyValuePair(QLatin1String("newsub/1/2/3/qbytearray"), QString::fromLatin1("QByteArray:test array."))); data.append(KeyValuePair(QLatin1String("newsub/1/2.1/3/qbytearray"), QString::fromLatin1("QByteArray:test array."))); - QVariantMap result = addKeys(testMap, data); + QVariantMap result = AddKeysData{data}.addKeys(testMap); if (result.count() != 9) return false; @@ -194,13 +194,13 @@ bool AddKeysOperation::test() const // preexisting: data.clear(); data.append(KeyValuePair(QLatin1String("testint"), QString::fromLatin1("int:4"))); - result = addKeys(testMap, data); + result = AddKeysData{data}.addKeys(testMap); if (!result.isEmpty()) return false; data.clear(); data.append(KeyValuePair(QLatin1String("subkeys/testbool"), QString::fromLatin1("int:24"))); - result = addKeys(testMap, data); + result = AddKeysData{data}.addKeys(testMap); if (!result.isEmpty()) return false; @@ -208,7 +208,7 @@ bool AddKeysOperation::test() const data.clear(); data.append(KeyValuePair(QLatin1String("bool-true"), QString::fromLatin1("bool:trUe"))); data.append(KeyValuePair(QLatin1String("bool-true"), QString::fromLatin1("bool:trUe"))); - result = addKeys(testMap, data); + result = AddKeysData{data}.addKeys(testMap); if (!result.isEmpty()) return false; @@ -216,12 +216,12 @@ bool AddKeysOperation::test() const } #endif -QVariantMap AddKeysOperation::addKeys(const QVariantMap &map, const KeyValuePairList &additions) +QVariantMap AddKeysData::addKeys(const QVariantMap &map) const { // Insert data: QVariantMap result = map; - foreach (const KeyValuePair &p, additions) { + foreach (const KeyValuePair &p, m_data) { QList stack; // Set up a stack of QVariantMaps along the path we take: diff --git a/src/tools/sdktool/addkeysoperation.h b/src/tools/sdktool/addkeysoperation.h index 40483befd10..9623d715045 100644 --- a/src/tools/sdktool/addkeysoperation.h +++ b/src/tools/sdktool/addkeysoperation.h @@ -27,25 +27,29 @@ #include "operation.h" -class AddKeysOperation : public Operation +class AddKeysData { public: - QString name() const; - QString helpText() const; - QString argumentsHelpText() const; - - bool setArguments(const QStringList &args); - - int execute() const; - -#ifdef WITH_TESTS - bool test() const; -#endif - - static QVariantMap addKeys(const QVariantMap &map, const KeyValuePairList &additions); - -private: - QString m_file; + QVariantMap addKeys(const QVariantMap &map) const; QList m_data; }; + +class AddKeysOperation : public Operation, public AddKeysData +{ +public: + QString name() const final; + QString helpText() const final; + QString argumentsHelpText() const final; + + bool setArguments(const QStringList &args) final; + + int execute() const final; + +#ifdef WITH_TESTS + bool test() const final; +#endif + +private: + QString m_file; +}; diff --git a/src/tools/sdktool/addkitoperation.cpp b/src/tools/sdktool/addkitoperation.cpp index d5de0562bfa..d6b3442a701 100644 --- a/src/tools/sdktool/addkitoperation.cpp +++ b/src/tools/sdktool/addkitoperation.cpp @@ -293,12 +293,7 @@ int AddKitOperation::execute() const if (map.isEmpty()) map = initializeKits(); - QVariantMap result = addKit(map, m_id, m_displayName, m_icon, m_debuggerId, m_debuggerEngine, - m_debugger, m_deviceType, m_device, m_sysRoot, m_tcs, m_qt, - m_mkspec, m_cmakeId, m_cmakeGenerator, m_cmakeExtraGenerator, - m_cmakeGeneratorToolset, m_cmakeGeneratorPlatform, m_cmakeConfiguration, - m_env, m_extra); - + const QVariantMap result = addKit(map); if (result.isEmpty() || map == result) return 2; @@ -308,26 +303,26 @@ int AddKitOperation::execute() const #ifdef WITH_TESTS bool AddKitOperation::test() const { + AddKitData kitData; QVariantMap map = initializeKits(); - QVariantMap tcMap = AddToolChainOperation::initializeToolChains(); - tcMap = AddToolChainOperation::addToolChain(tcMap, "{tc-id}", "langId", "TC", "/usr/bin/gcc", - "x86-linux-generic-elf-32bit", - "x86-linux-generic-elf-32bit", - KeyValuePairList()); + QVariantMap tcMap = AddToolChainData::initializeToolChains(); + tcMap = AddToolChainData{"{tc-id}", "langId", "TC", "/usr/bin/gcc", + "x86-linux-generic-elf-32bit", "x86-linux-generic-elf-32bit", {}} + .addToolChain(tcMap); - QVariantMap qtMap = AddQtOperation::initializeQtVersions(); - qtMap = AddQtOperation::addQt(qtMap, "{qt-id}", "Qt", "desktop-qt", "/usr/bin/qmake", - KeyValuePairList(), {}); + QVariantMap qtMap = AddQtData::initializeQtVersions(); + qtMap = AddQtData{"{qt-id}", "Qt", "desktop-qt", "/usr/bin/qmake", {}, {}}.addQt(qtMap); QVariantMap devMap = AddDeviceOperation::initializeDevices(); - devMap = AddDeviceOperation::addDevice(devMap, "{dev-id}", "Dev", 0, 0, - "HWplatform", "SWplatform", - "localhost", "10000-11000", - "localhost", "", 42, - "desktop", "", 22, 10000, - "uname", 1, - KeyValuePairList()); + devMap = AddDeviceData{"{dev-id}", "Dev", 0, 0, + "HWplatform", "SWplatform", + "localhost", "10000-11000", + "localhost", "", 42, + "desktop", "", 22, 10000, + "uname", 1, + KeyValuePairList()} + .addDevice(devMap); const QStringList env = {"TEST=1", "PATH"}; @@ -341,34 +336,35 @@ bool AddKitOperation::test() const tcs.insert("Cxx", "{tcXX-id}"); // Fail if TC is not there: - QVariantMap empty = addKit(map, tcMap, qtMap, devMap, QVariantMap(), - "testId", "Test Kit", "/tmp/icon.png", QString(), 1, - "/usr/bin/gdb-test", "Desktop", "{dev-id}", QString(), - tcs, "{qt-id}", "unsupported/mkspec", - QString(), QString(), QString(), QString(), QString(), QStringList(), - QStringList(), - KeyValuePairList({KeyValuePair("PE.Profile.Data/extraData", QVariant("extraValue"))})); + kitData = {"testId", "Test Kit", "/tmp/icon.png", QString(), 1, + "/usr/bin/gdb-test", "Desktop", "{dev-id}", QString(), + tcs, "{qt-id}", "unsupported/mkspec", + QString(), QString(), QString(), QString(), QString(), QStringList(), + QStringList(), + {{{"PE.Profile.Data/extraData", QVariant("extraValue")}}}}; + QVariantMap empty = kitData.addKit(map, tcMap, qtMap, devMap, {}); + if (!empty.isEmpty()) return false; // Do not fail if TC is an ABI: tcs.clear(); tcs.insert("C", "x86-linux-generic-elf-64bit"); - empty = addKit(map, tcMap, qtMap, devMap, QVariantMap(), - "testId", "Test Kit", "/tmp/icon.png", QString(), 1, - "/usr/bin/gdb-test", "Desktop", "{dev-id}", QString(), - tcs, "{qt-id}", "unsupported/mkspec", - QString(), QString(), QString(), QString(), QString(), QStringList(), env, - KeyValuePairList({KeyValuePair("PE.Profile.Data/extraData", QVariant("extraValue"))})); + kitData = {"testId", "Test Kit", "/tmp/icon.png", QString(), 1, + "/usr/bin/gdb-test", "Desktop", "{dev-id}", QString(), + tcs, "{qt-id}", "unsupported/mkspec", + QString(), QString(), QString(), QString(), QString(), QStringList(), env, + {KeyValuePair("PE.Profile.Data/extraData", QVariant("extraValue"))}}; + empty = kitData.addKit(map, tcMap, qtMap, devMap, {}); if (empty.isEmpty()) return false; // QTCREATORBUG-11983, mach_o was not covered by the first attempt to fix this. tcs.insert("D", "x86-macos-generic-mach_o-64bit"); - empty = addKit(map, tcMap, qtMap, devMap, QVariantMap(), - "testId", "Test Kit", "/tmp/icon.png", QString(), 1, - "/usr/bin/gdb-test", "Desktop", "{dev-id}", QString(), - tcs, "{qt-id}", "unsupported/mkspec", - QString(), QString(), QString(), QString(), QString(), QStringList(), env, - KeyValuePairList({KeyValuePair("PE.Profile.Data/extraData", QVariant("extraValue"))})); + kitData = {"testId", "Test Kit", "/tmp/icon.png", QString(), 1, + "/usr/bin/gdb-test", "Desktop", "{dev-id}", QString(), + tcs, "{qt-id}", "unsupported/mkspec", + QString(), QString(), QString(), QString(), QString(), QStringList(), env, + {{KeyValuePair("PE.Profile.Data/extraData", QVariant("extraValue"))}}}; + empty = kitData.addKit(map, tcMap, qtMap, devMap, {}); if (empty.isEmpty()) return false; @@ -376,31 +372,31 @@ bool AddKitOperation::test() const tcs.insert("Cxx", "{tc-id}"); // Fail if Qt is not there: - empty = addKit(map, tcMap, qtMap, devMap, QVariantMap(), - "testId", "Test Kit", "/tmp/icon.png", QString(), 1, - "/usr/bin/gdb-test", "Desktop", "{dev-id}", QString(), tcs, "{qtXX-id}", - "unsupported/mkspec", - QString(), QString(), QString(), QString(), QString(), QStringList(), env, - KeyValuePairList({KeyValuePair("PE.Profile.Data/extraData", QVariant("extraValue"))})); + kitData = {"testId", "Test Kit", "/tmp/icon.png", QString(), 1, + "/usr/bin/gdb-test", "Desktop", "{dev-id}", QString(), tcs, "{qtXX-id}", + "unsupported/mkspec", + QString(), QString(), QString(), QString(), QString(), QStringList(), env, + {{KeyValuePair("PE.Profile.Data/extraData", QVariant("extraValue"))}}}; + empty = kitData.addKit(map, tcMap, qtMap, devMap, {}); if (!empty.isEmpty()) return false; // Fail if dev is not there: - empty = addKit(map, tcMap, qtMap, devMap, QVariantMap(), - "testId", "Test Kit", "/tmp/icon.png", QString(), 1, - "/usr/bin/gdb-test", "Desktop", "{devXX-id}", QString(), tcs, "{qt-id}", - "unsupported/mkspec", - QString(), QString(), QString(), QString(), QString(), QStringList(), env, - KeyValuePairList({KeyValuePair("PE.Profile.Data/extraData", QVariant("extraValue"))})); + kitData = {"testId", "Test Kit", "/tmp/icon.png", QString(), 1, + "/usr/bin/gdb-test", "Desktop", "{devXX-id}", QString(), tcs, "{qt-id}", + "unsupported/mkspec", + QString(), QString(), QString(), QString(), QString(), QStringList(), env, + {KeyValuePair("PE.Profile.Data/extraData", QVariant("extraValue"))}}; + empty = kitData.addKit(map, tcMap, qtMap, devMap, {}); if (!empty.isEmpty()) return false; // Profile 0: - map = addKit(map, tcMap, qtMap, devMap, QVariantMap(), - "testId", "Test Kit", "/tmp/icon.png", QString(), 1, - "/usr/bin/gdb-test", "Desktop", QString(), QString(), tcs, "{qt-id}", - "unsupported/mkspec", - QString(), QString(), QString(), QString(), QString(), QStringList(), env, - KeyValuePairList({KeyValuePair("PE.Profile.Data/extraData", QVariant("extraValue"))})); + kitData = {"testId", "Test Kit", "/tmp/icon.png", QString(), 1, + "/usr/bin/gdb-test", "Desktop", QString(), QString(), tcs, "{qt-id}", + "unsupported/mkspec", + QString(), QString(), QString(), QString(), QString(), QStringList(), env, + {{KeyValuePair("PE.Profile.Data/extraData", QVariant("extraValue"))}}}; + map = kitData.addKit(map, tcMap, qtMap, devMap, {}); if (map.count() != 4 || !map.contains(VERSION) || map.value(VERSION).toInt() != 1 @@ -434,22 +430,23 @@ bool AddKitOperation::test() const return false; // Ignore existing ids: - QVariantMap result = addKit(map, tcMap, qtMap, devMap, QVariantMap(), - "testId", "Test Qt Version X", - "/tmp/icon3.png", QString(), 1, "/usr/bin/gdb-test3", "Desktop", - QString(), QString(), tcs, "{qt-id}", "unsupported/mkspec", - QString(), QString(), QString(), QString(), QString(), QStringList(), env, - KeyValuePairList({KeyValuePair("PE.Profile.Data/extraData", QVariant("extraValue"))})); + kitData = {"testId", "Test Qt Version X", + "/tmp/icon3.png", QString(), 1, "/usr/bin/gdb-test3", "Desktop", + QString(), QString(), tcs, "{qt-id}", "unsupported/mkspec", + QString(), QString(), QString(), QString(), QString(), QStringList(), env, + {{KeyValuePair("PE.Profile.Data/extraData", QVariant("extraValue"))}}}; + QVariantMap result = kitData.addKit(map, tcMap, qtMap, devMap, {}); if (!result.isEmpty()) return false; // Profile 1: Make sure name is unique: - map = addKit(map, tcMap, qtMap, devMap, QVariantMap(), - "testId2", "Test Kit2", "/tmp/icon2.png", QString(), 1, - "/usr/bin/gdb-test2", "Desktop", "{dev-id}", "/sys/root//", tcs, - "{qt-id}", "unsupported/mkspec", - QString(), QString(), QString(), QString(), QString(), QStringList(), env, - KeyValuePairList({KeyValuePair("PE.Profile.Data/extraData", QVariant("extraValue"))})); + kitData = {"testId2", "Test Kit2", "/tmp/icon2.png", QString(), 1, + "/usr/bin/gdb-test2", "Desktop", "{dev-id}", "/sys/root//", tcs, + "{qt-id}", "unsupported/mkspec", + QString(), QString(), QString(), QString(), QString(), QStringList(), env, + {{KeyValuePair("PE.Profile.Data/extraData", QVariant("extraValue"))}}}; + map = kitData.addKit(map, tcMap, qtMap, devMap, {}); + if (map.count() != 5 || !map.contains(VERSION) || map.value(VERSION).toInt() != 1 || !map.contains(COUNT) || map.value(COUNT).toInt() != 2 @@ -489,12 +486,12 @@ bool AddKitOperation::test() const return false; // Profile 2: Test debugger id: - map = addKit(map, tcMap, qtMap, devMap, QVariantMap(), - "test with debugger Id", "Test debugger Id", - "/tmp/icon2.png", "debugger Id", 0, QString(), "Desktop", QString(), QString(), - tcs, "{qt-id}", "unsupported/mkspec", - QString(), QString(), QString(), QString(), QString(), QStringList(), env, - KeyValuePairList({KeyValuePair("PE.Profile.Data/extraData", QVariant("extraValue"))})); + kitData = {"test with debugger Id", "Test debugger Id", + "/tmp/icon2.png", "debugger Id", 0, QString(), "Desktop", QString(), QString(), + tcs, "{qt-id}", "unsupported/mkspec", + QString(), QString(), QString(), QString(), QString(), QStringList(), env, + {KeyValuePair("PE.Profile.Data/extraData", QVariant("extraValue"))}}; + map = kitData.addKit(map, tcMap, qtMap, devMap, {}); if (map.count() != 6 || !map.contains(VERSION) || map.value(VERSION).toInt() != 1 || !map.contains(COUNT) || map.value(COUNT).toInt() != 3 @@ -528,61 +525,35 @@ bool AddKitOperation::test() const } #endif -QVariantMap AddKitOperation::addKit(const QVariantMap &map, - const QString &id, const QString &displayName, - const QString &icon, const QString &debuggerId, - const quint32 &debuggerType, const QString &debugger, - const QString &deviceType, const QString &device, - const QString &sysRoot, const QHash &tcs, const QString &qt, - const QString &mkspec, const QString &cmakeId, - const QString &cmakeGenerator, const QString &cmakeExtraGenerator, - const QString &cmakeGeneratorToolset, - const QString &cmakeGeneratorPlatform, - const QStringList &cmakeConfiguration, const QStringList &env, - const KeyValuePairList &extra) +QVariantMap AddKitData::addKit(const QVariantMap &map) const { - QVariantMap tcMap = load("ToolChains"); - QVariantMap qtMap = load("QtVersions"); - QVariantMap devMap = load("Devices"); - QVariantMap cmakeMap = load("cmaketools"); + QVariantMap tcMap = Operation::load("ToolChains"); + QVariantMap qtMap = Operation::load("QtVersions"); + QVariantMap devMap = Operation::load("Devices"); + QVariantMap cmakeMap = Operation::load("cmaketools"); - return addKit(map, tcMap, qtMap, devMap, cmakeMap, id, displayName, icon, debuggerId, debuggerType, - debugger, deviceType, device, sysRoot, tcs, qt, mkspec, - cmakeId, cmakeGenerator, cmakeExtraGenerator, cmakeGeneratorToolset, - cmakeGeneratorPlatform, cmakeConfiguration, - env, extra); + return AddKitData::addKit(map, tcMap, qtMap, devMap, cmakeMap); } -QVariantMap AddKitOperation::addKit(const QVariantMap &map, const QVariantMap &tcMap, +QVariantMap AddKitData::addKit(const QVariantMap &map, const QVariantMap &tcMap, const QVariantMap &qtMap, const QVariantMap &devMap, - const QVariantMap &cmakeMap, - const QString &id, const QString &displayName, - const QString &icon, const QString &debuggerId, - const quint32 &debuggerType, const QString &debugger, - const QString &deviceType, const QString &device, - const QString &sysRoot, const QHash &tcs, const QString &qt, - const QString &mkspec, const QString &cmakeId, - const QString &cmakeGenerator, const QString &cmakeExtraGenerator, - const QString &cmakeGeneratorToolset, - const QString &cmakeGeneratorPlatform, - const QStringList &cmakeConfiguration, const QStringList &env, - const KeyValuePairList &extra) + const QVariantMap &cmakeMap) const { // Sanity check: Make sure autodetection source is not in use already: - QStringList valueKeys = FindValueOperation::findValue(map, QVariant(id)); + const QStringList valueKeys = FindValueOperation::findValue(map, QVariant(m_id)); bool hasId = false; - foreach (const QString &k, valueKeys) { + for (const QString &k : valueKeys) { if (k.endsWith(QString('/') + ID)) { hasId = true; break; } } if (hasId) { - std::cerr << "Error: Id " << qPrintable(id) << " already defined as kit." << std::endl; + std::cerr << "Error: Id " << qPrintable(m_id) << " already defined as kit." << std::endl; return QVariantMap(); } - for (auto i = tcs.constBegin(); i != tcs.constEnd(); ++i) { + for (auto i = m_tcs.constBegin(); i != m_tcs.constEnd(); ++i) { if (!i.value().isEmpty() && !AddToolChainOperation::exists(tcMap, i.value())) { const QRegularExpression abiRegExp("^[a-z0-9_]+-[a-z0-9_]+-[a-z0-9_]+-[a-z0-9_]+-(8|16|32|64|128)bit$"); if (!abiRegExp.match(i.value()).hasMatch()) { @@ -593,15 +564,15 @@ QVariantMap AddKitOperation::addKit(const QVariantMap &map, const QVariantMap &t } } - QString qtId = qt; + QString qtId = m_qt; if (!qtId.isEmpty() && !qtId.startsWith("SDK.")) - qtId = QString::fromLatin1("SDK.") + qt; - if (!qtId.isEmpty() && !AddQtOperation::exists(qtMap, qtId)) { + qtId = QString::fromLatin1("SDK.") + m_qt; + if (!qtId.isEmpty() && !AddQtData::exists(qtMap, qtId)) { std::cerr << "Error: Qt " << qPrintable(qtId) << " does not exist." << std::endl; return QVariantMap(); } - if (!device.isEmpty() && !AddDeviceOperation::exists(devMap, device)) { - std::cerr << "Error: Device " << qPrintable(device) << " does not exist." << std::endl; + if (!m_device.isEmpty() && !AddDeviceOperation::exists(devMap, m_device)) { + std::cerr << "Error: Device " << qPrintable(m_device) << " does not exist." << std::endl; return QVariantMap(); } @@ -609,8 +580,8 @@ QVariantMap AddKitOperation::addKit(const QVariantMap &map, const QVariantMap &t if (!qtId.isNull() && qtId.isEmpty()) qtId = "-1"; - if (!cmakeId.isEmpty() && !AddCMakeOperation::exists(cmakeMap, cmakeId)) { - std::cerr << "Error: CMake tool " << qPrintable(cmakeId) << " does not exist." << std::endl; + if (!m_cmakeId.isEmpty() && !AddCMakeData::exists(cmakeMap, m_cmakeId)) { + std::cerr << "Error: CMake tool " << qPrintable(m_cmakeId) << " does not exist." << std::endl; return QVariantMap(); } @@ -625,68 +596,69 @@ QVariantMap AddKitOperation::addKit(const QVariantMap &map, const QVariantMap &t QString defaultKit = GetOperation::get(map, DEFAULT).toString(); if (defaultKit.isEmpty()) - defaultKit = id; + defaultKit = m_id; // remove data: QVariantMap cleaned = RmKeysOperation::rmKeys(map, {COUNT, DEFAULT}); // insert data: - KeyValuePairList data = {KeyValuePair({kit, ID}, QVariant(id)), - KeyValuePair({kit, DISPLAYNAME}, QVariant(displayName)), - KeyValuePair({kit, ICON}, QVariant(icon)), + KeyValuePairList data = {KeyValuePair({kit, ID}, QVariant(m_id)), + KeyValuePair({kit, DISPLAYNAME}, QVariant(m_displayName)), + KeyValuePair({kit, ICON}, QVariant(m_icon)), KeyValuePair({kit, AUTODETECTED}, QVariant(true)), KeyValuePair({kit, SDK}, QVariant(true))}; - if (!debuggerId.isEmpty() || !debugger.isEmpty()) { - if (debuggerId.isEmpty()) { - data << KeyValuePair({kit, DATA, DEBUGGER, DEBUGGER_ENGINE}, QVariant(debuggerType)); - data << KeyValuePair({kit, DATA, DEBUGGER, DEBUGGER_BINARY}, QVariant(debugger)); + if (!m_debuggerId.isEmpty() || !m_debugger.isEmpty()) { + if (m_debuggerId.isEmpty()) { + data << KeyValuePair({kit, DATA, DEBUGGER, DEBUGGER_ENGINE}, QVariant(m_debuggerEngine)); + data << KeyValuePair({kit, DATA, DEBUGGER, DEBUGGER_BINARY}, QVariant(m_debugger)); } else { - data << KeyValuePair({kit, DATA, DEBUGGER }, QVariant(debuggerId)); + data << KeyValuePair({kit, DATA, DEBUGGER }, QVariant(m_debuggerId)); } } - if (!deviceType.isNull()) - data << KeyValuePair({kit, DATA, DEVICE_TYPE}, QVariant(deviceType)); - if (!device.isNull()) - data << KeyValuePair({kit, DATA, DEVICE_ID}, QVariant(device)); - if (!sysRoot.isNull()) - data << KeyValuePair({kit, DATA, SYSROOT}, Utils::FilePath::fromUserInput(sysRoot).toVariant()); - for (auto i = tcs.constBegin(); i != tcs.constEnd(); ++i) + + if (!m_deviceType.isNull()) + data << KeyValuePair({kit, DATA, DEVICE_TYPE}, QVariant(m_deviceType)); + if (!m_device.isNull()) + data << KeyValuePair({kit, DATA, DEVICE_ID}, QVariant(m_device)); + if (!m_sysRoot.isNull()) + data << KeyValuePair({kit, DATA, SYSROOT}, Utils::FilePath::fromUserInput(m_sysRoot).toVariant()); + for (auto i = m_tcs.constBegin(); i != m_tcs.constEnd(); ++i) data << KeyValuePair({kit, DATA, TOOLCHAIN, i.key()}, QVariant(i.value())); if (!qtId.isNull()) data << KeyValuePair({kit, DATA, QT}, QVariant(qtId)); - if (!mkspec.isNull()) - data << KeyValuePair({kit, DATA, MKSPEC}, QVariant(mkspec)); - if (!cmakeId.isNull()) - data << KeyValuePair({kit, DATA, CMAKE_ID}, QVariant(cmakeId)); - if (!cmakeGenerator.isNull()) { + if (!m_mkspec.isNull()) + data << KeyValuePair({kit, DATA, MKSPEC}, QVariant(m_mkspec)); + if (!m_cmakeId.isNull()) + data << KeyValuePair({kit, DATA, CMAKE_ID}, QVariant(m_cmakeId)); + if (!m_cmakeGenerator.isNull()) { QVariantMap generatorMap; - generatorMap.insert("Generator", cmakeGenerator); - if (!cmakeExtraGenerator.isNull()) - generatorMap.insert("ExtraGenerator", cmakeExtraGenerator); - if (!cmakeGeneratorToolset.isNull()) - generatorMap.insert("Toolset", cmakeGeneratorToolset); - if (!cmakeGeneratorPlatform.isNull()) - generatorMap.insert("Platform", cmakeGeneratorPlatform); + generatorMap.insert("Generator", m_cmakeGenerator); + if (!m_cmakeExtraGenerator.isNull()) + generatorMap.insert("ExtraGenerator", m_cmakeExtraGenerator); + if (!m_cmakeGeneratorToolset.isNull()) + generatorMap.insert("Toolset", m_cmakeGeneratorToolset); + if (!m_cmakeGeneratorPlatform.isNull()) + generatorMap.insert("Platform", m_cmakeGeneratorPlatform); data << KeyValuePair({kit, DATA, CMAKE_GENERATOR}, generatorMap); } - if (!cmakeConfiguration.isEmpty()) - data << KeyValuePair({kit, DATA, CMAKE_CONFIGURATION}, QVariant(cmakeConfiguration)); - if (!env.isEmpty()) - data << KeyValuePair({kit, DATA, ENV}, QVariant(env)); + if (!m_cmakeConfiguration.isEmpty()) + data << KeyValuePair({kit, DATA, CMAKE_CONFIGURATION}, QVariant(m_cmakeConfiguration)); + if (!m_env.isEmpty()) + data << KeyValuePair({kit, DATA, ENV}, QVariant(m_env)); data << KeyValuePair(DEFAULT, QVariant(defaultKit)); data << KeyValuePair(COUNT, QVariant(count + 1)); KeyValuePairList qtExtraList; - foreach (const KeyValuePair &pair, extra) + foreach (const KeyValuePair &pair, m_extra) qtExtraList << KeyValuePair(QStringList() << kit << pair.key, pair.value); data.append(qtExtraList); - return AddKeysOperation::addKeys(cleaned, data); + return AddKeysData{data}.addKeys(cleaned); } -QVariantMap AddKitOperation::initializeKits() +QVariantMap AddKitData::initializeKits() { QVariantMap map; map.insert(VERSION, 1); diff --git a/src/tools/sdktool/addkitoperation.h b/src/tools/sdktool/addkitoperation.h index 037144353a0..89b588e7944 100644 --- a/src/tools/sdktool/addkitoperation.h +++ b/src/tools/sdktool/addkitoperation.h @@ -28,49 +28,17 @@ #include "operation.h" #include -#include -class AddKitOperation : public Operation +class AddKitData { public: - QString name() const; - QString helpText() const; - QString argumentsHelpText() const; - - bool setArguments(const QStringList &args); - - int execute() const; - -#ifdef WITH_TESTS - bool test() const; -#endif - - static QVariantMap addKit(const QVariantMap &map, const QString &id, const QString &displayName, - const QString &icon, const QString &debuggerId, - const quint32 &debuggerType, const QString &debugger, - const QString &deviceType, const QString &device, - const QString &sysRoot, const QHash &tcs, - const QString &qt, const QString &mkspec, - const QString &cmakeId, const QString &cmakeGenerator, - const QString &cmakeExtraGenerator, const QString &cmakeGeneratorToolset, - const QString &cmakeGeneratorPlatform, - const QStringList &cmakeConfiguration, const QStringList &env, - const KeyValuePairList &extra); + QVariantMap addKit(const QVariantMap &map) const; + QVariantMap addKit(const QVariantMap &map, const QVariantMap &tcMap, + const QVariantMap &qtMap, const QVariantMap &devMap, + const QVariantMap &cmakeMap) const; static QVariantMap initializeKits(); - // internal: - static QVariantMap addKit(const QVariantMap &map, const QVariantMap &tcMap, - const QVariantMap &qtMap, const QVariantMap &devMap, const QVariantMap &cmakeMap, - const QString &id, const QString &displayName, - const QString &icon, const QString &debuggerId, - const quint32 &debuggerType, const QString &debugger, - const QString &deviceType, const QString &device, - const QString &sysRoot, const QHash &tcs, - const QString &qt, const QString &mkspec, const QString &cmakeId, const QString &cmakeGenerator, const QString &cmakeExtraGenerator, const QString &cmakeGeneratorToolset, const QString &cmakeGeneratorPlatform, const QStringList &cmakeConfiguration, const QStringList &env, - const KeyValuePairList &extra); - -private: QString m_id; QString m_displayName; QString m_icon; @@ -92,3 +60,18 @@ private: QStringList m_env; KeyValuePairList m_extra; }; + +class AddKitOperation : public Operation, public AddKitData +{ +public: + QString name() const final; + QString helpText() const final; + QString argumentsHelpText() const final; + + bool setArguments(const QStringList &args) final; + int execute() const final; + +#ifdef WITH_TESTS + bool test() const final; +#endif +}; diff --git a/src/tools/sdktool/addqtoperation.cpp b/src/tools/sdktool/addqtoperation.cpp index 7a94480d4a8..99eb3c78c0d 100644 --- a/src/tools/sdktool/addqtoperation.cpp +++ b/src/tools/sdktool/addqtoperation.cpp @@ -169,7 +169,7 @@ int AddQtOperation::execute() const if (map.isEmpty()) map = initializeQtVersions(); - QVariantMap result = addQt(map, m_id, m_displayName, m_type, m_qmake, m_extra, m_abis); + QVariantMap result = addQt(map); if (result.isEmpty() || result == map) return 2; @@ -180,6 +180,7 @@ int AddQtOperation::execute() const #ifdef WITH_TESTS bool AddQtOperation::test() const { + AddQtData qtData; QVariantMap map = initializeQtVersions(); if (map.count() != 1 @@ -188,16 +189,13 @@ bool AddQtOperation::test() const return false; #if defined Q_OS_WIN - map = addQt(map, QLatin1String("{some-qt-id}"), QLatin1String("Test Qt Version"), QLatin1String("testType"), - QLatin1String("/tmp//../tmp/test\\qmake"), - KeyValuePairList() << KeyValuePair(QLatin1String("extraData"), QVariant(QLatin1String("extraValue"))), - QStringList()); + qtData = {"{some-qt-id}", "Test Qt Version", "testType", "/tmp//../tmp/test\\qmake", {}, + {{QLatin1String("extraData"), QVariant(QLatin1String("extraValue"))}}}; #else - map = addQt(map, QLatin1String("{some-qt-id}"), QLatin1String("Test Qt Version"), QLatin1String("testType"), - QLatin1String("/tmp//../tmp/test/qmake"), - KeyValuePairList() << KeyValuePair(QLatin1String("extraData"), QVariant(QLatin1String("extraValue"))), - QStringList()); + qtData = {"{some-qt-id}", "Test Qt Version", "testType", "/tmp//../tmp/test/qmake", {}, + {{QLatin1String("extraData"), QVariant(QLatin1String("extraValue"))}}}; #endif + map = qtData.addQt(map); if (map.count() != 2 || !map.contains(QLatin1String(VERSION)) @@ -226,18 +224,16 @@ bool AddQtOperation::test() const return false; // Ignore existing ids: - QVariantMap result = addQt(map, QLatin1String("{some-qt-id}"), QLatin1String("Test Qt Version2"), QLatin1String("testType2"), - QLatin1String("/tmp/test/qmake2"), - KeyValuePairList() << KeyValuePair(QLatin1String("extraData"), QVariant(QLatin1String("extraValue"))), - QStringList()); + qtData = {"{some-qt-id}", "Test Qt Version2", "testType2", "/tmp/test/qmake2", {}, + {{QLatin1String("extraData"), QVariant(QLatin1String("extraValue"))}}}; + QVariantMap result = qtData.addQt(map); if (!result.isEmpty()) return false; // add 2nd Qt version: - map = addQt(map, QLatin1String("testId2"), QLatin1String("Test Qt Version"), QLatin1String("testType3"), - QLatin1String("/tmp/test/qmake2"), - KeyValuePairList() << KeyValuePair(QLatin1String("extraData"), QVariant(QLatin1String("extraValue"))), - QStringList()); + qtData = {"testId2", "Test Qt Version", "testType3", "/tmp/test/qmake2", {}, + {{QLatin1String("extraData"), QVariant(QLatin1String("extraValue"))}}}; + map = qtData.addQt(map); if (map.count() != 3 || !map.contains(QLatin1String(VERSION)) || map.value(QLatin1String(VERSION)).toInt() != 1 @@ -272,16 +268,13 @@ bool AddQtOperation::test() const } #endif -QVariantMap AddQtOperation::addQt(const QVariantMap &map, - const QString &id, const QString &displayName, const QString &type, - const QString &qmake, const KeyValuePairList &extra, - const QStringList &abis) +QVariantMap AddQtData::addQt(const QVariantMap &map) const { - QString sdkId = extendId(id); + QString sdkId = extendId(m_id); // Sanity check: Make sure autodetection source is not in use already: if (exists(map, sdkId)) { - std::cerr << "Error: Id " << qPrintable(id) << " already defined as Qt versions." << std::endl; + std::cerr << "Error: Id " << qPrintable(m_id) << " already defined as Qt versions." << std::endl; return QVariantMap(); } @@ -299,40 +292,41 @@ QVariantMap AddQtOperation::addQt(const QVariantMap &map, const QString qt = QString::fromLatin1(PREFIX) + QString::number(versionCount); // Sanitize qmake path: - FilePath saneQmake = FilePath::fromUserInput(qmake).cleanPath(); + FilePath saneQmake = FilePath::fromUserInput(m_qmake).cleanPath(); // insert data: KeyValuePairList data; data << KeyValuePair(QStringList() << qt << QLatin1String(ID), QVariant(-1)); - data << KeyValuePair(QStringList() << qt << QLatin1String(DISPLAYNAME), QVariant(displayName)); + data << KeyValuePair(QStringList() << qt << QLatin1String(DISPLAYNAME), QVariant(m_displayName)); data << KeyValuePair(QStringList() << qt << QLatin1String(AUTODETECTED), QVariant(true)); data << KeyValuePair(QStringList() << qt << QLatin1String(AUTODETECTION_SOURCE), QVariant(sdkId)); + data << KeyValuePair(QStringList() << qt << QLatin1String(QMAKE), saneQmake.toVariant()); - data << KeyValuePair(QStringList() << qt << QLatin1String(TYPE), QVariant(type)); - data << KeyValuePair(QStringList() << qt << ABIS, QVariant(abis)); + data << KeyValuePair(QStringList() << qt << QLatin1String(TYPE), QVariant(m_type)); + data << KeyValuePair(QStringList() << qt << ABIS, QVariant(m_abis)); KeyValuePairList qtExtraList; - foreach (const KeyValuePair &pair, extra) + foreach (const KeyValuePair &pair, m_extra) qtExtraList << KeyValuePair(QStringList() << qt << pair.key, pair.value); data.append(qtExtraList); - return AddKeysOperation::addKeys(map, data); + return AddKeysData{data}.addKeys(map); } -QVariantMap AddQtOperation::initializeQtVersions() +QVariantMap AddQtData::initializeQtVersions() { QVariantMap map; map.insert(QLatin1String(VERSION), 1); return map; } -bool AddQtOperation::exists(const QString &id) +bool AddQtData::exists(const QString &id) { - QVariantMap map = load(QLatin1String("QtVersions")); + QVariantMap map = Operation::load(QLatin1String("QtVersions")); return exists(map, id); } -bool AddQtOperation::exists(const QVariantMap &map, const QString &id) +bool AddQtData::exists(const QVariantMap &map, const QString &id) { QString sdkId = extendId(id); diff --git a/src/tools/sdktool/addqtoperation.h b/src/tools/sdktool/addqtoperation.h index 65e31ff8353..d7269e32454 100644 --- a/src/tools/sdktool/addqtoperation.h +++ b/src/tools/sdktool/addqtoperation.h @@ -27,34 +27,16 @@ #include "operation.h" -#include - -class AddQtOperation : public Operation +class AddQtData { public: - QString name() const; - QString helpText() const; - QString argumentsHelpText() const; - - bool setArguments(const QStringList &args); - - int execute() const; - -#ifdef WITH_TESTS - bool test() const; -#endif - - static QVariantMap addQt(const QVariantMap &map, - const QString &id, const QString &displayName, const QString &type, - const QString &qmake, const KeyValuePairList &extra, - const QStringList &abis); + QVariantMap addQt(const QVariantMap &map) const; static QVariantMap initializeQtVersions(); static bool exists(const QString &id); static bool exists(const QVariantMap &map, const QString &id); -private: QString m_id; // actually this is the autodetectionSource QString m_displayName; QString m_type; @@ -62,3 +44,17 @@ private: QStringList m_abis; KeyValuePairList m_extra; }; + +class AddQtOperation : public Operation, public AddQtData +{ +private: + QString name() const final; + QString helpText() const final; + QString argumentsHelpText() const final; + bool setArguments(const QStringList &args) final; + int execute() const final; + +#ifdef WITH_TESTS + bool test() const final; +#endif +}; diff --git a/src/tools/sdktool/addtoolchainoperation.cpp b/src/tools/sdktool/addtoolchainoperation.cpp index 6bd8380a15d..aec304b647e 100644 --- a/src/tools/sdktool/addtoolchainoperation.cpp +++ b/src/tools/sdktool/addtoolchainoperation.cpp @@ -158,8 +158,7 @@ int AddToolChainOperation::execute() const if (map.isEmpty()) map = initializeToolChains(); - QVariantMap result = addToolChain(map, m_id, m_languageId, m_displayName, m_path, - m_targetAbi, m_supportedAbis, m_extra); + QVariantMap result = addToolChain(map); if (result.isEmpty() || map == result) return 2; @@ -172,8 +171,8 @@ bool AddToolChainOperation::test() const QVariantMap map = initializeToolChains(); // Add toolchain: - map = addToolChain(map, "testId", "langId", "name", "/tmp/test", "test-abi", "test-abi,test-abi2", - KeyValuePairList() << KeyValuePair("ExtraKey", QVariant("ExtraValue"))); + map = AddToolChainData{"testId", "langId", "name", "/tmp/test", "test-abi", "test-abi,test-abi2", + {{"ExtraKey", QVariant("ExtraValue")}}}.addToolChain(map); if (map.value(COUNT).toInt() != 1 || !map.contains(QString::fromLatin1(PREFIX) + '0')) return false; @@ -190,15 +189,15 @@ bool AddToolChainOperation::test() const return false; // Ignore same Id: - QVariantMap unchanged = addToolChain(map, "testId", "langId", "name2", "/tmp/test2", "test-abi2", + QVariantMap unchanged = AddToolChainData{"testId", "langId", "name2", "/tmp/test2", "test-abi2", "test-abi2,test-abi3", - KeyValuePairList() << KeyValuePair("ExtraKey", QVariant("ExtraValue2"))); + {{"ExtraKey", QVariant("ExtraValue2")}}}.addToolChain(map); if (!unchanged.isEmpty()) return false; // add 2nd tool chain: - map = addToolChain(map, "{some-tc-id}", "langId2", "name", "/tmp/test", "test-abi", "test-abi,test-abi2", - KeyValuePairList() << KeyValuePair("ExtraKey", QVariant("ExtraValue"))); + map = AddToolChainData{"{some-tc-id}", "langId2", "name", "/tmp/test", "test-abi", "test-abi,test-abi2", + {{"ExtraKey", QVariant("ExtraValue")}}}.addToolChain(map); if (map.value(COUNT).toInt() != 2 || !map.contains(QString::fromLatin1(PREFIX) + '0') || !map.contains(QString::fromLatin1(PREFIX) + '1')) @@ -230,15 +229,11 @@ bool AddToolChainOperation::test() const } #endif -QVariantMap AddToolChainOperation::addToolChain(const QVariantMap &map, const QString &id, - const QString &lang, const QString &displayName, - const QString &path, const QString &abi, - const QString &supportedAbis, - const KeyValuePairList &extra) +QVariantMap AddToolChainData::addToolChain(const QVariantMap &map) const { // Sanity check: Does the Id already exist? - if (exists(map, id)) { - std::cerr << "Error: Id " << qPrintable(id) << " already defined for tool chains." << std::endl; + if (exists(map, m_id)) { + std::cerr << "Error: Id " << qPrintable(m_id) << " already defined for tool chains." << std::endl; return QVariantMap(); } @@ -255,44 +250,44 @@ QVariantMap AddToolChainOperation::addToolChain(const QVariantMap &map, const QS const QString tc = QString::fromLatin1(PREFIX) + QString::number(count); KeyValuePairList data; - data << KeyValuePair({tc, ID}, QVariant(id)); + data << KeyValuePair({tc, ID}, QVariant(m_id)); // Language compatibility hack for old Qt components that use the language spec from 4.2. // Some Qt 5.15 components were actually still using this. QString newLang; // QtC 4.3 and later - lang.toInt(&ok); - if (lang == "2" || lang == "Cxx") { + m_languageId.toInt(&ok); + if (m_languageId == "2" || m_languageId == "Cxx") { newLang = "Cxx"; - } else if (lang == "1" || lang == "C") { + } else if (m_languageId == "1" || m_languageId == "C") { newLang = "C"; } else if (ok) { std::cerr << "Error: Language ID must be 1 for C, 2 for Cxx " << "or a string like \"C\", \"Cxx\", \"Nim\" (was \"" - << qPrintable(lang) << "\")" << std::endl; + << qPrintable(m_languageId) << "\")" << std::endl; return {}; } else if (!ok) { - newLang = lang; + newLang = m_languageId; } data << KeyValuePair({tc, LANGUAGE_KEY_V2}, QVariant(newLang)); - data << KeyValuePair({tc, DISPLAYNAME}, QVariant(displayName)); + data << KeyValuePair({tc, DISPLAYNAME}, QVariant(m_displayName)); data << KeyValuePair({tc, AUTODETECTED}, QVariant(true)); - data << KeyValuePair({tc, PATH}, Utils::FilePath::fromUserInput(path).toVariant()); - data << KeyValuePair({tc, TARGET_ABI}, QVariant(abi)); + data << KeyValuePair({tc, PATH}, Utils::FilePath::fromUserInput(m_path).toVariant()); + data << KeyValuePair({tc, TARGET_ABI}, QVariant(m_targetAbi)); QVariantList abis; - QStringList abiStrings = supportedAbis.split(','); + QStringList abiStrings = m_supportedAbis.split(','); foreach (const QString &s, abiStrings) abis << QVariant(s); data << KeyValuePair({tc, SUPPORTED_ABIS}, QVariant(abis)); KeyValuePairList tcExtraList; - foreach (const KeyValuePair &pair, extra) + foreach (const KeyValuePair &pair, m_extra) tcExtraList << KeyValuePair(QStringList({tc}) << pair.key, pair.value); data.append(tcExtraList); data << KeyValuePair(COUNT, QVariant(count + 1)); - return AddKeysOperation::addKeys(result, data); + return AddKeysData{data}.addKeys(result); } -QVariantMap AddToolChainOperation::initializeToolChains() +QVariantMap AddToolChainData::initializeToolChains() { QVariantMap map; map.insert(COUNT, 0); @@ -300,7 +295,7 @@ QVariantMap AddToolChainOperation::initializeToolChains() return map; } -bool AddToolChainOperation::exists(const QVariantMap &map, const QString &id) +bool AddToolChainData::exists(const QVariantMap &map, const QString &id) { QStringList valueKeys = FindValueOperation::findValue(map, id); // support old settings using QByteArray for id's @@ -314,7 +309,7 @@ bool AddToolChainOperation::exists(const QVariantMap &map, const QString &id) return false; } -bool AddToolChainOperation::exists(const QString &id) +bool AddToolChainData::exists(const QString &id) { QVariantMap map = Operation::load("ToolChains"); return exists(map, id); diff --git a/src/tools/sdktool/addtoolchainoperation.h b/src/tools/sdktool/addtoolchainoperation.h index 5f743eba483..5e6ac39a7c2 100644 --- a/src/tools/sdktool/addtoolchainoperation.h +++ b/src/tools/sdktool/addtoolchainoperation.h @@ -27,34 +27,16 @@ #include "operation.h" -#include - -class AddToolChainOperation : public Operation +class AddToolChainData { public: - QString name() const; - QString helpText() const; - QString argumentsHelpText() const; - - bool setArguments(const QStringList &args); - - int execute() const; - -#ifdef WITH_TESTS - bool test() const; -#endif - - static QVariantMap addToolChain(const QVariantMap &map, - const QString &id, const QString &lang, - const QString &displayName, const QString &path, - const QString &abi, const QString &supportedAbis, - const KeyValuePairList &extra); + QVariantMap addToolChain(const QVariantMap &map) const; static QVariantMap initializeToolChains(); + static bool exists(const QString &id); static bool exists(const QVariantMap &map, const QString &id); -private: QString m_id; QString m_languageId; QString m_displayName; @@ -63,3 +45,19 @@ private: QString m_supportedAbis; KeyValuePairList m_extra; }; + +class AddToolChainOperation : public Operation, public AddToolChainData +{ +public: + QString name() const final; + QString helpText() const final; + QString argumentsHelpText() const final; + + bool setArguments(const QStringList &args) final; + + int execute() const final; + +#ifdef WITH_TESTS + bool test() const final; +#endif +}; diff --git a/src/tools/sdktool/addvalueoperation.cpp b/src/tools/sdktool/addvalueoperation.cpp index ef434d3b3f5..a604409f611 100644 --- a/src/tools/sdktool/addvalueoperation.cpp +++ b/src/tools/sdktool/addvalueoperation.cpp @@ -79,7 +79,7 @@ bool AddValueOperation::setArguments(const QStringList &args) m_file = tempArgs.takeFirst(); m_key = tempArgs.takeFirst(); for (const auto &arg : tempArgs) { - const auto val = Operation::valueFromString(arg); + const auto val = valueFromString(arg); if (!val.isValid() || val.isNull()) { std::cerr << "Error: " << std::quoted(arg.toStdString()) << " is not a valid QVariant like string Type:Value.\n" @@ -101,7 +101,7 @@ int AddValueOperation::execute() const return FAILURE; } - auto status = appendListToMap(map, m_key, m_values); + bool status = appendListToMap(map); if (status) { status = save(map, m_file); @@ -122,13 +122,12 @@ bool AddValueOperation::test() const testKvpList.append(KeyValuePair(QLatin1String("test/foobar"), QString::fromLatin1("int:42"))); testKvpList.append(KeyValuePair(QLatin1String("test/bar"), testDataList)); - const auto valueList = QVariantList( - {Operation::valueFromString("QString:ELIL"), Operation::valueFromString("int:-1")}); + const QVariantList valueList = {valueFromString("QString:ELIL"), valueFromString("int:-1")}; QVariantMap testMap; // add to empty map - auto result = appendListToMap(testMap, "some key", valueList); + bool result = AddValueData{"some key", valueList}.appendListToMap(testMap); if (result) return false; @@ -137,19 +136,19 @@ bool AddValueOperation::test() const testMap.insert(QLatin1String("aKey"), "withAString"); // append to a value - result = appendListToMap(testMap, "aKey", valueList); + result = AddValueData{"aKey", valueList}.appendListToMap(testMap); if (result) return false; - testMap = AddKeysOperation::addKeys(testMap, testKvpList); + testMap = AddKeysData{testKvpList}.addKeys(testMap); // quick sanity check if (testMap.count() != 3 && testDataList.count() != 2 && testKvpList.count() != 3) return false; // successful adding of values - result = appendListToMap(testMap, "test/bar", valueList); + result = AddValueData{"test/bar", valueList}.appendListToMap(testMap); if (!result) return false; @@ -165,30 +164,28 @@ bool AddValueOperation::test() const } #endif -bool AddValueOperation::appendListToMap(QVariantMap &map, - const QString &key, - const QVariantList &values) +bool AddValueData::appendListToMap(QVariantMap &map) const { - const auto data = GetOperation::get(map, key); + const QVariant data = GetOperation::get(map, m_key); if (!data.isValid() || data.isNull()) { - std::cerr << "Error: Could not retrieve value for key " << std::quoted(key.toStdString()) + std::cerr << "Error: Could not retrieve value for key " << std::quoted(m_key.toStdString()) << std::endl; return false; } if (data.type() != QVariant::List) { - std::cerr << "Error: Data stored in " << std::quoted(key.toStdString()) + std::cerr << "Error: Data stored in " << std::quoted(m_key.toStdString()) << " is not a QVariantList." << std::endl; return false; } auto newList = qvariant_cast(data); - newList.append(values); + newList.append(m_values); - map = RmKeysOperation::rmKeys(map, {key}); - map = AddKeysOperation::addKeys(map, {Operation::KeyValuePair(key, newList)}); + map = RmKeysOperation::rmKeys(map, {m_key}); + map = AddKeysData{{{m_key, newList}}}.addKeys(map); return true; } diff --git a/src/tools/sdktool/addvalueoperation.h b/src/tools/sdktool/addvalueoperation.h index fe1910a2272..df19f1f2357 100644 --- a/src/tools/sdktool/addvalueoperation.h +++ b/src/tools/sdktool/addvalueoperation.h @@ -28,25 +28,30 @@ #include "operation.h" -class AddValueOperation : public Operation +class AddValueData { public: - QString name() const override; - QString helpText() const override; - QString argumentsHelpText() const override; + bool appendListToMap(QVariantMap &map) const; - bool setArguments(const QStringList &args) override; - - int execute() const override; - -#ifdef WITH_TESTS - bool test() const override; -#endif - - static bool appendListToMap(QVariantMap &map, const QString &key, const QVariantList &values); - -private: - QString m_file; QString m_key; QVariantList m_values; }; + +class AddValueOperation : public Operation, public AddValueData +{ +public: + QString name() const final; + QString helpText() const final; + QString argumentsHelpText() const final; + + bool setArguments(const QStringList &args) final; + + int execute() const final; + +#ifdef WITH_TESTS + bool test() const final; +#endif + +private: + QString m_file; +}; diff --git a/src/tools/sdktool/findkeyoperation.h b/src/tools/sdktool/findkeyoperation.h index f6365c7ebd8..e8138fa7865 100644 --- a/src/tools/sdktool/findkeyoperation.h +++ b/src/tools/sdktool/findkeyoperation.h @@ -30,18 +30,17 @@ class FindKeyOperation : public Operation { public: - QString name() const; - QString helpText() const; - QString argumentsHelpText() const; + QString name() const final; + QString helpText() const final; + QString argumentsHelpText() const final; - bool setArguments(const QStringList &args); + bool setArguments(const QStringList &args) final; - int execute() const; + int execute() const final; #ifdef WITH_TESTS - bool test() const; + bool test() const final; #endif - static QStringList findKey(const QVariant &in, const QString &key, const QString &prefix = QString()); diff --git a/src/tools/sdktool/findvalueoperation.cpp b/src/tools/sdktool/findvalueoperation.cpp index e59a0fa115e..2ed856c608b 100644 --- a/src/tools/sdktool/findvalueoperation.cpp +++ b/src/tools/sdktool/findvalueoperation.cpp @@ -53,7 +53,7 @@ bool FindValueOperation::setArguments(const QStringList &args) continue; } - QVariant v = Operation::valueFromString(current); + QVariant v = valueFromString(current); if (!v.isValid()) { std::cerr << "Value for key '" << qPrintable(current) << "' is not valid." << std::endl << std::endl; return false; diff --git a/src/tools/sdktool/findvalueoperation.h b/src/tools/sdktool/findvalueoperation.h index 2d49678b666..f53dae125b0 100644 --- a/src/tools/sdktool/findvalueoperation.h +++ b/src/tools/sdktool/findvalueoperation.h @@ -30,16 +30,16 @@ class FindValueOperation : public Operation { public: - QString name() const; - QString helpText() const; - QString argumentsHelpText() const; + QString name() const final; + QString helpText() const final; + QString argumentsHelpText() const final; - bool setArguments(const QStringList &args); + bool setArguments(const QStringList &args) final; - int execute() const; + int execute() const final; #ifdef WITH_TESTS - bool test() const; + bool test() const final; #endif static QStringList findValue(const QVariant &in, const QVariant &value, diff --git a/src/tools/sdktool/getoperation.h b/src/tools/sdktool/getoperation.h index 6d9b018ad04..56b7970ca35 100644 --- a/src/tools/sdktool/getoperation.h +++ b/src/tools/sdktool/getoperation.h @@ -30,16 +30,16 @@ class GetOperation : public Operation { public: - QString name() const; - QString helpText() const; - QString argumentsHelpText() const; + QString name() const final; + QString helpText() const final; + QString argumentsHelpText() const final; - bool setArguments(const QStringList &args); + bool setArguments(const QStringList &args) final; - int execute() const; + int execute() const final; #ifdef WITH_TESTS - bool test() const; + bool test() const final; #endif static QVariant get(const QVariantMap &map, const QString &key); diff --git a/src/tools/sdktool/operation.cpp b/src/tools/sdktool/operation.cpp index 44af491b867..4c1eec03d96 100644 --- a/src/tools/sdktool/operation.cpp +++ b/src/tools/sdktool/operation.cpp @@ -34,7 +34,7 @@ #include -QVariant Operation::valueFromString(const QString &v) +QVariant valueFromString(const QString &v) { int pos = v.indexOf(QLatin1Char(':')); if (pos <= 0) @@ -62,23 +62,23 @@ QVariant Operation::valueFromString(const QString &v) return QVariant(); } -Operation::KeyValuePair::KeyValuePair(const QString &k, const QString &v) : +KeyValuePair::KeyValuePair(const QString &k, const QString &v) : value(valueFromString(v)) { key = k.split(QLatin1Char('/')); } -Operation::KeyValuePair::KeyValuePair(const QString &k, const QVariant &v) : +KeyValuePair::KeyValuePair(const QString &k, const QVariant &v) : value(v) { key = k.split(QLatin1Char('/')); } -Operation::KeyValuePair::KeyValuePair(const QStringList &k, const QString &v) : +KeyValuePair::KeyValuePair(const QStringList &k, const QString &v) : key(k), value(valueFromString(v)) { } -Operation::KeyValuePair::KeyValuePair(const QStringList &k, const QVariant &v) : +KeyValuePair::KeyValuePair(const QStringList &k, const QVariant &v) : key(k), value(v) { } diff --git a/src/tools/sdktool/operation.h b/src/tools/sdktool/operation.h index 99077fb2160..cc489ce0757 100644 --- a/src/tools/sdktool/operation.h +++ b/src/tools/sdktool/operation.h @@ -30,21 +30,25 @@ #include #include +class KeyValuePair +{ +public: + KeyValuePair(const QString &k, const QString &v); + KeyValuePair(const QString &k, const QVariant &v); + KeyValuePair(const QStringList &k, const QString &v); + KeyValuePair(const QStringList &k, const QVariant &v); + + QStringList key; + QVariant value; +}; + +using KeyValuePairList = QList; + +QVariant valueFromString(const QString &v); + class Operation { public: - class KeyValuePair { - public: - KeyValuePair(const QString &k, const QString &v); - KeyValuePair(const QString &k, const QVariant &v); - KeyValuePair(const QStringList &k, const QString &v); - KeyValuePair(const QStringList &k, const QVariant &v); - - QStringList key; - QVariant value; - }; - typedef QList KeyValuePairList; - virtual ~Operation() { } virtual QString name() const = 0; @@ -61,6 +65,4 @@ public: static QVariantMap load(const QString &file); bool save(const QVariantMap &map, const QString &file) const; - - static QVariant valueFromString(const QString &v); }; diff --git a/src/tools/sdktool/rmcmakeoperation.cpp b/src/tools/sdktool/rmcmakeoperation.cpp index a5583c3f843..423abdbc695 100644 --- a/src/tools/sdktool/rmcmakeoperation.cpp +++ b/src/tools/sdktool/rmcmakeoperation.cpp @@ -85,7 +85,7 @@ int RmCMakeOperation::execute() const if (map.isEmpty()) return 0; - QVariantMap result = rmCMake(map, m_id); + QVariantMap result = RmCMakeData{m_id}.rmCMake(map); if (result == map) return 2; @@ -98,20 +98,20 @@ bool RmCMakeOperation::test() const // Add cmakes: QVariantMap map = AddCMakeOperation::initializeCMake(); const QVariantMap emptyMap = map; - map = AddCMakeOperation::addCMake(map, "testId", "name", "/tmp/test", - KeyValuePairList({KeyValuePair("ExtraKey", QVariant("ExtraValue"))})); - map = AddCMakeOperation::addCMake(map, "testId2", "other name", "/tmp/test2", KeyValuePairList()); + map = AddCMakeData{"testId", "name", "/tmp/test", + {{"ExtraKey", QVariant("ExtraValue")}}}.addCMake(map); + map = AddCMakeData{"testId2", "other name", "/tmp/test2", {}}.addCMake(map); - QVariantMap result = rmCMake(QVariantMap(), "nonexistent"); + QVariantMap result = RmCMakeData{"nonexistent"}.rmCMake(QVariantMap()); if (!result.isEmpty()) return false; - result = rmCMake(map, "nonexistent"); + result = RmCMakeData{"nonexistent"}.rmCMake(map); if (result != map) return false; // Remove from map with both testId and testId2: - result = rmCMake(map, "testId2"); + result = RmCMakeData{"testId2"}.rmCMake(map); if (result == map || result.value(COUNT, 0).toInt() != 1 || !result.contains(QString::fromLatin1(PREFIX) + "0") @@ -119,7 +119,7 @@ bool RmCMakeOperation::test() const return false; // Remove from map with both testId and testId2: - result = rmCMake(map, "testId"); + result = RmCMakeData{"testId"}.rmCMake(map); if (result == map || result.value(COUNT, 0).toInt() != 1 || !result.contains(QString::fromLatin1(PREFIX) + "0") @@ -127,7 +127,7 @@ bool RmCMakeOperation::test() const return false; // Remove from map without testId! - result = rmCMake(result, "testId2"); + result = RmCMakeData{"testId2"}.rmCMake(result); if (result != emptyMap) return false; @@ -135,7 +135,7 @@ bool RmCMakeOperation::test() const } #endif -QVariantMap RmCMakeOperation::rmCMake(const QVariantMap &map, const QString &id) +QVariantMap RmCMakeData::rmCMake(const QVariantMap &map) const { // Find count of cmakes: bool ok; @@ -148,7 +148,7 @@ QVariantMap RmCMakeOperation::rmCMake(const QVariantMap &map, const QString &id) QVariantList cmList; for (int i = 0; i < count; ++i) { QVariantMap cmData = GetOperation::get(map, QString::fromLatin1(PREFIX) + QString::number(i)).toMap(); - if (cmData.value(ID).toString() != id) + if (cmData.value(ID).toString() != m_id) cmList.append(cmData); } diff --git a/src/tools/sdktool/rmcmakeoperation.h b/src/tools/sdktool/rmcmakeoperation.h index 1a292a3fd6e..98d9f7847a0 100644 --- a/src/tools/sdktool/rmcmakeoperation.h +++ b/src/tools/sdktool/rmcmakeoperation.h @@ -27,25 +27,26 @@ #include "operation.h" -#include - -class RmCMakeOperation : public Operation +class RmCMakeData { public: - QString name() const; - QString helpText() const; - QString argumentsHelpText() const; + QVariantMap rmCMake(const QVariantMap &map) const; - bool setArguments(const QStringList &args); - - int execute() const; - -#ifdef WITH_TESTS - bool test() const; -#endif - - static QVariantMap rmCMake(const QVariantMap &map, const QString &id); - -private: QString m_id; }; + +class RmCMakeOperation : public Operation, public RmCMakeData +{ +public: + QString name() const final; + QString helpText() const final; + QString argumentsHelpText() const final; + + bool setArguments(const QStringList &args) final; + + int execute() const final; + +#ifdef WITH_TESTS + bool test() const final; +#endif +}; diff --git a/src/tools/sdktool/rmdebuggeroperation.cpp b/src/tools/sdktool/rmdebuggeroperation.cpp index 8c2a6bea0d9..5ed3ec6a86e 100644 --- a/src/tools/sdktool/rmdebuggeroperation.cpp +++ b/src/tools/sdktool/rmdebuggeroperation.cpp @@ -95,16 +95,15 @@ bool RmDebuggerOperation::test() const { QVariantMap map = - AddDebuggerOperation::addDebugger(AddDebuggerOperation::initializeDebuggers(), - QLatin1String("id1"), QLatin1String("Name1"), - 2, QLatin1String("/tmp/debugger1"), - QStringList() << QLatin1String("test11") << QLatin1String("test12"), - KeyValuePairList()); - map = - AddDebuggerOperation::addDebugger(map, QLatin1String("id2"), QLatin1String("Name2"), - 2, QLatin1String("/tmp/debugger2"), - QStringList() << QLatin1String("test21") << QLatin1String("test22"), - KeyValuePairList()); + AddDebuggerData{QLatin1String("id1"), QLatin1String("Name1"), + 2, QLatin1String("/tmp/debugger1"), + {"test11", "test12"}, {}} + .addDebugger(AddDebuggerOperation::initializeDebuggers()); + + map = AddDebuggerData{QLatin1String("id2"), QLatin1String("Name2"), + 2, QLatin1String("/tmp/debugger2"), + {"test21", "test22"}, {}} + .addDebugger(map); QVariantMap result = rmDebugger(map, QLatin1String("id2")); if (result.count() != 3 @@ -178,6 +177,6 @@ QVariantMap RmDebuggerOperation::rmDebugger(const QVariantMap &map, const QStrin debuggerList.at(i)); } - return AddKeysOperation::addKeys(result, data); + return AddKeysData{data}.addKeys(result); } diff --git a/src/tools/sdktool/rmkitoperation.cpp b/src/tools/sdktool/rmkitoperation.cpp index 4e7487f40b0..306cfc3bd75 100644 --- a/src/tools/sdktool/rmkitoperation.cpp +++ b/src/tools/sdktool/rmkitoperation.cpp @@ -98,40 +98,40 @@ int RmKitOperation::execute() const bool RmKitOperation::test() const { QVariantMap tcMap = AddToolChainOperation::initializeToolChains(); - tcMap = AddToolChainOperation::addToolChain(tcMap, "{tc-id}", "langId", "TC", "/usr/bin/gcc", - "x86-linux-generic-elf-32bit", - "x86-linux-generic-elf-32bit", - KeyValuePairList()); + tcMap = AddToolChainData{"{tc-id}", "langId", "TC", "/usr/bin/gcc", + "x86-linux-generic-elf-32bit", "x86-linux-generic-elf-32bit", {}} + .addToolChain(tcMap); - QVariantMap qtMap = AddQtOperation::initializeQtVersions(); - qtMap = AddQtOperation::addQt(qtMap, "{qt-id}", "Qt", "desktop-qt", "/usr/bin/qmake", - KeyValuePairList(), QStringList()); + QVariantMap qtMap = AddQtData::initializeQtVersions(); + qtMap = AddQtData{"{qt-id}", "Qt", "desktop-qt", "/usr/bin/qmake", {}, {}}.addQt(qtMap); QVariantMap devMap = AddDeviceOperation::initializeDevices(); - devMap = AddDeviceOperation::addDevice(devMap, "{dev-id}", "Dev", 0, 0, - "HWplatform", "SWplatform", - "localhost", "10000-11000", "localhost", "", 42, - "desktop", "", 22, 10000, "uname", 1, - KeyValuePairList()); + devMap = AddDeviceData{"{dev-id}", "Dev", 0, 0, + "HWplatform", "SWplatform", + "localhost", "10000-11000", "localhost", "", 42, + "desktop", "", 22, 10000, "uname", 1, + KeyValuePairList()} + .addDevice(devMap); QHash tcs; tcs.insert("Cxx", "{tc-id}"); QVariantMap map = - AddKitOperation::addKit(AddKitOperation::initializeKits(), tcMap, qtMap, devMap, - QVariantMap(), - "testId", "Test Qt Version", "/tmp/icon.png", QString(), 1, - "/usr/bin/gdb-test", "Desktop", QString(), QString(), tcs, - "{qt-id}", "unsupported/mkspec", - QString(), QString(), QString(), QString(), QString(), QStringList(), QStringList(), - KeyValuePairList() << KeyValuePair("PE.Profile.Data/extraData", QVariant("extraValue"))); - map = - AddKitOperation::addKit(map, tcMap, qtMap, devMap, QVariantMap(), "testId2", "Test Qt Version", - "/tmp/icon2.png", QString(), 1, "/usr/bin/gdb-test2", - "Desktop", QString(), QString(), tcs, "{qt-id}", - "unsupported/mkspec2", - QString(), QString(), QString(), QString(), QString(), QStringList(), QStringList(), - KeyValuePairList() << KeyValuePair("PE.Profile.Data/extraData", QVariant("extraValue2"))); + AddKitData{"testId", "Test Qt Version", "/tmp/icon.png", QString(), 1, + "/usr/bin/gdb-test", "Desktop", QString(), QString(), tcs, + "{qt-id}", "unsupported/mkspec", + QString(), QString(), QString(), QString(), QString(), QStringList(), QStringList(), + {{"PE.Profile.Data/extraData", QVariant("extraValue")}}} + .addKit(AddKitData::initializeKits(), tcMap, qtMap, devMap, {}); + + + map = AddKitData{"testId2", "Test Qt Version", + "/tmp/icon2.png", QString(), 1, "/usr/bin/gdb-test2", + "Desktop", QString(), QString(), tcs, "{qt-id}", + "unsupported/mkspec2", + QString(), QString(), QString(), QString(), QString(), QStringList(), QStringList(), + {{"PE.Profile.Data/extraData", QVariant("extraValue2")}}} + .addKit(map, tcMap, qtMap, devMap, {}); QVariantMap result = rmKit(map, "testId"); if (result.count() != 4 @@ -212,5 +212,5 @@ QVariantMap RmKitOperation::rmKit(const QVariantMap &map, const QString &id) data << KeyValuePair(QString::fromLatin1(PREFIX) + QString::number(i), profileList.at(i)); - return AddKeysOperation::addKeys(result, data); + return AddKeysData{data}.addKeys(result); } diff --git a/src/tools/sdktool/rmqtoperation.cpp b/src/tools/sdktool/rmqtoperation.cpp index 53f3b760015..bad6c923060 100644 --- a/src/tools/sdktool/rmqtoperation.cpp +++ b/src/tools/sdktool/rmqtoperation.cpp @@ -95,19 +95,17 @@ int RmQtOperation::execute() const bool RmQtOperation::test() const { // Add toolchain: - QVariantMap map = AddQtOperation::initializeQtVersions(); + QVariantMap map = AddQtData::initializeQtVersions(); QVariantMap result = rmQt(QVariantMap(), QLatin1String("nonexistant")); if (result != map) return false; - map = AddQtOperation::addQt(map, QLatin1String("testId"), QLatin1String("name"), QLatin1String("type"), - QLatin1String("/tmp/test"), - KeyValuePairList() << KeyValuePair(QLatin1String("ExtraKey"), QVariant(QLatin1String("ExtraValue"))), - QStringList()); - map = AddQtOperation::addQt(map, QLatin1String("testId2"), QLatin1String("other name"), QLatin1String("type"), - QLatin1String("/tmp/test2"), - KeyValuePairList(), QStringList()); + map = AddQtData{"testId", "name", "type", "/tmp/test", {}, + {{QLatin1String("ExtraKey"), QVariant(QLatin1String("ExtraValue"))}}} + .addQt(map); + + map = AddQtData{"testId2", "other name", "type", "/tmp/test2", {}, {}}.addQt(map); result = rmQt(map, QLatin1String("nonexistant")); if (result != map) @@ -149,7 +147,7 @@ QVariantMap RmQtOperation::rmQt(const QVariantMap &map, const QString &id) qtList.append(qtData); } - QVariantMap newMap = AddQtOperation::initializeQtVersions(); + QVariantMap newMap = AddQtData::initializeQtVersions(); for (int i = 0; i < qtList.count(); ++i) newMap.insert(QString::fromLatin1(PREFIX) + QString::number(i), qtList.at(i)); diff --git a/src/tools/sdktool/rmtoolchainoperation.cpp b/src/tools/sdktool/rmtoolchainoperation.cpp index 1cefe020609..bf71ec5cfe9 100644 --- a/src/tools/sdktool/rmtoolchainoperation.cpp +++ b/src/tools/sdktool/rmtoolchainoperation.cpp @@ -97,11 +97,13 @@ bool RmToolChainOperation::test() const { // Add toolchain: QVariantMap map = AddToolChainOperation::initializeToolChains(); - map = AddToolChainOperation::addToolChain(map, "testId", "langId", "name", "/tmp/test", "test-abi", - "test-abi,test-abi2", - KeyValuePairList({KeyValuePair("ExtraKey", QVariant("ExtraValue"))})); - map = AddToolChainOperation::addToolChain(map, "testId2", "langId", "other name", "/tmp/test2", "test-abi", - "test-abi,test-abi2", KeyValuePairList()); + map = AddToolChainData{"testId", "langId", "name", "/tmp/test", "test-abi", + "test-abi,test-abi2", {{"ExtraKey", QVariant("ExtraValue")}}} + .addToolChain(map); + + map = AddToolChainData{"testId2", "langId", "other name", "/tmp/test2", "test-abi", + "test-abi,test-abi2", {}} + .addToolChain(map); QVariantMap result = rmToolChain(QVariantMap(), "nonexistent"); if (!result.isEmpty()) diff --git a/src/tools/sdktool/rmtoolchainoperation.h b/src/tools/sdktool/rmtoolchainoperation.h index 3755320710b..cf4d12d1e5e 100644 --- a/src/tools/sdktool/rmtoolchainoperation.h +++ b/src/tools/sdktool/rmtoolchainoperation.h @@ -32,16 +32,16 @@ class RmToolChainOperation : public Operation { public: - QString name() const; - QString helpText() const; - QString argumentsHelpText() const; + QString name() const final; + QString helpText() const final; + QString argumentsHelpText() const final; - bool setArguments(const QStringList &args); + bool setArguments(const QStringList &args) final; - int execute() const; + int execute() const final; #ifdef WITH_TESTS - bool test() const; + bool test() const final; #endif static QVariantMap rmToolChain(const QVariantMap &map, const QString &id); From 652639327f35003c0f46a93a8e576d5f4e3fdf89 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 4 Feb 2022 15:59:01 -0800 Subject: [PATCH 80/94] CMake: install the cmake files inside CMAKE_INSTALL_LIBDIR Change-Id: I54f205f6b7314351b078fffd16d0bab2ccd81cd4 Reviewed-by: Eike Ziller --- cmake/QtCreatorAPIInternal.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/QtCreatorAPIInternal.cmake b/cmake/QtCreatorAPIInternal.cmake index 86fe1c0d939..d7bef93491f 100644 --- a/cmake/QtCreatorAPIInternal.cmake +++ b/cmake/QtCreatorAPIInternal.cmake @@ -80,7 +80,7 @@ else () set(_IDE_LIBRARY_ARCHIVE_PATH "${_IDE_LIBRARY_PATH}") set(_IDE_HEADER_INSTALL_PATH "include/qtcreator") - set(_IDE_CMAKE_INSTALL_PATH "lib/cmake") + set(_IDE_CMAKE_INSTALL_PATH "${_IDE_LIBRARY_BASE_PATH}/cmake") endif () file(RELATIVE_PATH _PLUGIN_TO_LIB "/${_IDE_PLUGIN_PATH}" "/${_IDE_LIBRARY_PATH}") From 3ba00ac39f84dbc2509bebca4276b1b23fd73823 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 10 Feb 2022 08:52:32 +0100 Subject: [PATCH 81/94] CMake build: Allow adding RPATHs via CMAKE_(BUILD|INSTALL)_RPATH Prepend our own relative RPATHs to CMAKE_INSTALL_RPATH (or CMAKE_BUILD_RPATH respectively) instead of overriding them completely. That allows adding an RPATH to e.g. a self-compiled and separately installed Qt to the installed Qt Creator. Fixes: QTCREATORBUG-27008 Change-Id: I8cd9167fdf5ba9838850fcfab8135da9b79e6695 Reviewed-by: Alexandru Croitor --- cmake/QtCreatorAPI.cmake | 14 ++++++++------ src/libs/CMakeLists.txt | 4 ++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/cmake/QtCreatorAPI.cmake b/cmake/QtCreatorAPI.cmake index 194852d6b7f..1f36ac0af35 100644 --- a/cmake/QtCreatorAPI.cmake +++ b/cmake/QtCreatorAPI.cmake @@ -228,8 +228,8 @@ function(add_qtc_library name) CXX_EXTENSIONS OFF CXX_VISIBILITY_PRESET hidden VISIBILITY_INLINES_HIDDEN ON - BUILD_RPATH "${_LIB_RPATH}" - INSTALL_RPATH "${_LIB_RPATH}" + BUILD_RPATH "${_LIB_RPATH};${CMAKE_BUILD_RPATH}" + INSTALL_RPATH "${_LIB_RPATH};${CMAKE_INSTALL_RPATH}" RUNTIME_OUTPUT_DIRECTORY "${_output_binary_dir}/${_DESTINATION}" LIBRARY_OUTPUT_DIRECTORY "${_output_binary_dir}/${IDE_LIBRARY_PATH}" ARCHIVE_OUTPUT_DIRECTORY "${_output_binary_dir}/${IDE_LIBRARY_ARCHIVE_PATH}" @@ -478,8 +478,8 @@ function(add_qtc_plugin target_name) VISIBILITY_INLINES_HIDDEN ON _arg_DEPENDS "${_arg_PLUGIN_DEPENDS}" _arg_VERSION "${_arg_VERSION}" - BUILD_RPATH "${_PLUGIN_RPATH}" - INSTALL_RPATH "${_PLUGIN_RPATH}" + BUILD_RPATH "${_PLUGIN_RPATH};${CMAKE_BUILD_RPATH}" + INSTALL_RPATH "${_PLUGIN_RPATH};${CMAKE_INSTALL_RPATH}" LIBRARY_OUTPUT_DIRECTORY "${_output_binary_dir}/${plugin_dir}" ARCHIVE_OUTPUT_DIRECTORY "${_output_binary_dir}/${plugin_dir}" RUNTIME_OUTPUT_DIRECTORY "${_output_binary_dir}/${plugin_dir}" @@ -654,6 +654,8 @@ function(add_qtc_executable name) file(RELATIVE_PATH relative_plugins_path "/${_EXECUTABLE_PATH}" "/${IDE_PLUGIN_PATH}") set(install_rpath "${install_rpath};${_RPATH_BASE}/${relative_qt_path};${_RPATH_BASE}/${relative_plugins_path}") endif() + set(build_rpath "${build_rpath};${CMAKE_BUILD_RPATH}") + set(install_rpath "${install_rpath};${CMAKE_INSTALL_RPATH}") qtc_output_binary_dir(_output_binary_dir) set_target_properties("${name}" PROPERTIES @@ -811,8 +813,8 @@ function(add_qtc_test name) LINK_DEPENDS_NO_SHARED ON CXX_VISIBILITY_PRESET hidden VISIBILITY_INLINES_HIDDEN ON - BUILD_RPATH "${_RPATH_BASE}/${_RPATH}" - INSTALL_RPATH "${_RPATH_BASE}/${_RPATH}" + BUILD_RPATH "${_RPATH_BASE}/${_RPATH};${CMAKE_BUILD_RPATH}" + INSTALL_RPATH "${_RPATH_BASE}/${_RPATH};${CMAKE_INSTALL_RPATH}" ) if (NOT _arg_SKIP_PCH) enable_pch(${name}) diff --git a/src/libs/CMakeLists.txt b/src/libs/CMakeLists.txt index aee880b4ddb..b4ef8af90cd 100644 --- a/src/libs/CMakeLists.txt +++ b/src/libs/CMakeLists.txt @@ -42,8 +42,8 @@ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/qlitehtml/src/CMakeLists.txt) #qtc_enable_separate_debug_info(qlitehtml "${IDE_LIBRARY_PATH}") qtc_output_binary_dir(_output_binary_dir) set_target_properties(qlitehtml PROPERTIES - BUILD_RPATH "${_LIB_RPATH}" - INSTALL_RPATH "${_LIB_RPATH}" + BUILD_RPATH "${_LIB_RPATH};${CMAKE_BUILD_RPATH}" + INSTALL_RPATH "${_LIB_RPATH};${CMAKE_INSTALL_RPATH}" RUNTIME_OUTPUT_DIRECTORY "${_output_binary_dir}/${IDE_BIN_PATH}" LIBRARY_OUTPUT_DIRECTORY "${_output_binary_dir}/${IDE_LIBRARY_PATH}" ARCHIVE_OUTPUT_DIRECTORY "${_output_binary_dir}/${IDE_LIBRARY_ARCHIVE_PATH}" From 6472e8c5bb1bf3d49ca44b9cdebf2a6f8b7c83f1 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Thu, 10 Feb 2022 16:12:08 +0100 Subject: [PATCH 82/94] QmlDesigner: Set proper version when duplicating states When duplicating a state we did not set the correct version. This stopped the rewriter from syncing the property with the QML code. I added a regression test. Task-number: QDS-6185 Change-Id: I11552a9f880eb83f4df1341fb0b94c9a3a6e5035 Reviewed-by: Miikka Heikkinen Reviewed-by: Mahmoud Badri Reviewed-by: Qt CI Bot --- .../designercore/model/qmlstate.cpp | 17 ++- .../qmldesigner/coretests/tst_testcore.cpp | 109 ++++++++++++++++++ .../qml/qmldesigner/coretests/tst_testcore.h | 1 + 3 files changed, 125 insertions(+), 2 deletions(-) diff --git a/src/plugins/qmldesigner/designercore/model/qmlstate.cpp b/src/plugins/qmldesigner/designercore/model/qmlstate.cpp index bddbe63b33c..70bb2719383 100644 --- a/src/plugins/qmldesigner/designercore/model/qmlstate.cpp +++ b/src/plugins/qmldesigner/designercore/model/qmlstate.cpp @@ -157,7 +157,13 @@ void QmlModelState::addChangeSetIfNotExists(const ModelNode &node) if (!hasPropertyChanges(node)) { ModelNode newChangeSet; - newChangeSet = modelNode().view()->createModelNode("QtQuick.PropertyChanges", view()->majorQtQuickVersion(), 0); + const QByteArray typeName = "QtQuick.PropertyChanges"; + NodeMetaInfo metaInfo = modelNode().model()->metaInfo(typeName); + + int major = metaInfo.majorVersion(); + int minor = metaInfo.minorVersion(); + + newChangeSet = modelNode().view()->createModelNode(typeName, major, minor); modelNode().nodeListProperty("changes").reparentHere(newChangeSet); @@ -287,9 +293,16 @@ QmlModelStateGroup QmlModelState::stateGroup() const ModelNode QmlModelState::createQmlState(AbstractView *view, const PropertyListType &propertyList) { + QTC_ASSERT(view, return {}); QTC_CHECK(view->majorQtQuickVersion() < 3); - return view->createModelNode("QtQuick.State", 2, 0, propertyList); + const QByteArray typeName = "QtQuick.State"; + NodeMetaInfo metaInfo = view->model()->metaInfo(typeName); + + int major = metaInfo.majorVersion(); + int minor = metaInfo.minorVersion(); + + return view->createModelNode(typeName, major, minor, propertyList); } void QmlModelState::setAsDefault() diff --git a/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp b/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp index c8c81453197..26b8ddcf8e3 100644 --- a/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp +++ b/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp @@ -1234,6 +1234,115 @@ void tst_TestCore::testRewriterForGradientMagic() transaction.commit(); } +void tst_TestCore::testStatesVersionFailing() +{ + char qmlString[] = "import QtQuick\n" + "Rectangle {\n" + "id: root;\n" + "Rectangle {\n" + "id: rect1;\n" + "}\n" + "Rectangle {\n" + "id: rect2;\n" + "}\n" + "states: [\n" + "State {\n" + "name: \"state1\"\n" + "PropertyChanges {\n" + "target: rect1\n" + "}\n" + "}\n" + "]\n" + "}\n"; + + Exception::setShouldAssert(true); + + QPlainTextEdit textEdit; + textEdit.setPlainText(QLatin1String(qmlString)); + NotIndentingTextEditModifier textModifier(&textEdit); + + QScopedPointer model(Model::create("QtQuick.Item")); + QVERIFY(model.data()); + + QScopedPointer view(new TestView(model.data())); + QVERIFY(view.data()); + model->attachView(view.data()); + + ModelNode rootModelNode(view->rootModelNode()); + QVERIFY(rootModelNode.isValid()); + QCOMPARE(rootModelNode.type(), QmlDesigner::TypeName("QtQuick.Item")); + QScopedPointer testRewriterView(new TestRewriterView()); + testRewriterView->setTextModifier(&textModifier); + + model->attachView(testRewriterView.data()); + QVERIFY(rootModelNode.isValid()); + QCOMPARE(rootModelNode.type(), QmlDesigner::TypeName("QtQuick.Rectangle")); + + QCOMPARE(QmlItemNode(rootModelNode).states().allStates().count(), 1); + QCOMPARE(QmlItemNode(rootModelNode).states().names().count(), 1); + QCOMPARE(QmlItemNode(rootModelNode).states().names().first(), QString("state1")); + + QmlModelState state = QmlItemNode(rootModelNode).states().state("state1"); + ModelNode stateNode = QmlItemNode(rootModelNode).states().state("state1").modelNode(); + QVERIFY(stateNode.isValid()); + + NodeMetaInfo stateInfo = stateNode.metaInfo(); + + QVERIFY(stateInfo.isValid()); + QmlModelState newState = state.duplicate("state2"); + + QCOMPARE(QmlItemNode(rootModelNode).states().allStates().count(), 2); + QCOMPARE(QmlItemNode(rootModelNode).states().names().count(), 2); + QCOMPARE(QmlItemNode(rootModelNode).states().names().last(), QString("state2")); + + QCOMPARE(QmlItemNode(rootModelNode).states().state("state2"), newState); + + QCOMPARE(stateInfo.majorVersion(), newState.modelNode().majorVersion()); + QCOMPARE(stateInfo.minorVersion(), newState.modelNode().minorVersion()); + + ModelNode rect1Node = view->modelNodeForId("rect1"); + QVERIFY(rect1Node.isValid()); + QmlObjectNode rect1(rect1Node); + QmlPropertyChanges changes = newState.propertyChanges(rect1Node); + QVERIFY(changes.isValid()); + + NodeMetaInfo changeInfo = changes.modelNode().metaInfo(); + QVERIFY(changeInfo.isValid()); + + QVERIFY(!changes.modelNode().hasProperty("x")); + + view->setCurrentState(newState); + + QVERIFY(view->currentState() == newState); + + QString oldText = textEdit.toPlainText(); + + rect1.setVariantProperty("x", 100); + QVERIFY(changes.modelNode().hasProperty("x")); + QVERIFY(oldText != textEdit.toPlainText()); + + ModelNode rect2Node = view->modelNodeForId("rect2"); + QVERIFY(rect2Node.isValid()); + QmlObjectNode rect2(rect2Node); + QVERIFY(!newState.hasPropertyChanges(rect2Node)); + QmlPropertyChanges changes2 = newState.propertyChanges(rect2Node); + + QVERIFY(changes2.isValid()); + + QVERIFY(view->currentState() == newState); + + oldText = textEdit.toPlainText(); + + rect2.setVariantProperty("x", 100); + changes2 = newState.propertyChanges(rect2Node); + QVERIFY(changes2.isValid()); + QVERIFY(changes2.modelNode().hasProperty("x")); + QVERIFY(oldText != textEdit.toPlainText()); + + QCOMPARE(changeInfo.majorVersion(), changes2.modelNode().majorVersion()); + QCOMPARE(changeInfo.minorVersion(), changes2.modelNode().minorVersion()); +} + void tst_TestCore::loadSubItems() { QFile file(QString(TESTSRCDIR) + "/../data/fx/topitem.qml"); diff --git a/tests/auto/qml/qmldesigner/coretests/tst_testcore.h b/tests/auto/qml/qmldesigner/coretests/tst_testcore.h index d052bf950e5..9a8aeb6450b 100644 --- a/tests/auto/qml/qmldesigner/coretests/tst_testcore.h +++ b/tests/auto/qml/qmldesigner/coretests/tst_testcore.h @@ -199,6 +199,7 @@ private slots: void reparentingNodeLikeDragAndDrop(); void testRewriterForGradientMagic(); + void testStatesVersionFailing(); // // old tests From 250f4fb72f9706a0af29e78e4ab2142f22c65b57 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Tue, 1 Feb 2022 16:51:27 +0100 Subject: [PATCH 83/94] McuSupport: Move McuDependenciesKitAspectWidget into its own file Change-Id: I41a2a6ec48c5c02ca655cb09ad08080d73d336fe Reviewed-by: Alessandro Portale Reviewed-by: --- src/plugins/mcusupport/CMakeLists.txt | 1 + src/plugins/mcusupport/mcukitinformation.cpp | 133 +++++++++++++++++++ src/plugins/mcusupport/mcukitinformation.h | 53 ++++++++ src/plugins/mcusupport/mcusupport.qbs | 4 +- src/plugins/mcusupport/mcusupportoptions.cpp | 96 +------------ src/plugins/mcusupport/mcusupportoptions.h | 24 +--- src/plugins/mcusupport/mcusupportplugin.cpp | 1 + 7 files changed, 193 insertions(+), 119 deletions(-) create mode 100644 src/plugins/mcusupport/mcukitinformation.cpp create mode 100644 src/plugins/mcusupport/mcukitinformation.h diff --git a/src/plugins/mcusupport/CMakeLists.txt b/src/plugins/mcusupport/CMakeLists.txt index bb2b98738de..261dd6e0b52 100644 --- a/src/plugins/mcusupport/CMakeLists.txt +++ b/src/plugins/mcusupport/CMakeLists.txt @@ -2,6 +2,7 @@ add_qtc_plugin(McuSupport DEPENDS Qt5::Core PLUGIN_DEPENDS Core BareMetal ProjectExplorer Debugger CMakeProjectManager QtSupport SOURCES + mcukitinformation.cpp mcukitinformation.h mcusupport.qrc mcusupport_global.h mcusupportconstants.h diff --git a/src/plugins/mcusupport/mcukitinformation.cpp b/src/plugins/mcusupport/mcukitinformation.cpp new file mode 100644 index 00000000000..f72fef1f2e7 --- /dev/null +++ b/src/plugins/mcusupport/mcukitinformation.cpp @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "mcukitinformation.h" + +#include + +using namespace ProjectExplorer; + +namespace { + +class McuDependenciesKitAspectWidget final : public KitAspectWidget +{ +public: + McuDependenciesKitAspectWidget(Kit *workingCopy, const KitAspect *ki) + : KitAspectWidget(workingCopy, ki) + {} + + void makeReadOnly() override {} + void refresh() override {} + void addToLayout(Utils::LayoutBuilder &) override {} +}; + +} // anonymous namespace + +namespace McuSupport { +namespace Internal { + +McuDependenciesKitAspect::McuDependenciesKitAspect() +{ + setObjectName(QLatin1String("McuDependenciesKitAspect")); + setId(McuDependenciesKitAspect::id()); + setDisplayName(tr("MCU Dependencies")); + setDescription(tr("Paths to 3rd party dependencies")); + setPriority(28500); +} + +Tasks McuDependenciesKitAspect::validate(const Kit *k) const +{ + Tasks result; + QTC_ASSERT(k, return result); + + const QVariant checkFormat = k->value(McuDependenciesKitAspect::id()); + if (!checkFormat.isNull() && !checkFormat.canConvert(QVariant::List)) + return { BuildSystemTask(Task::Error, tr("The MCU dependencies setting value is invalid.")) }; + + const QVariant envStringList = k->value(EnvironmentKitAspect::id()); + if (!envStringList.isNull() && !envStringList.canConvert(QVariant::List)) + return { BuildSystemTask(Task::Error, tr("The environment setting value is invalid.")) }; + + const auto environment = Utils::NameValueDictionary(envStringList.toStringList()); + for (const auto &dependency: dependencies(k)) { + if (!environment.hasKey(dependency.name)) { + result << BuildSystemTask(Task::Warning, tr("Environment variable %1 not defined.").arg(dependency.name)); + } else { + const auto path = Utils::FilePath::fromUserInput( + environment.value(dependency.name) + "/" + dependency.value); + if (!path.exists()) { + result << BuildSystemTask(Task::Warning, tr("%1 not found.").arg(path.toUserOutput())); + } + } + } + + return result; +} + +void McuDependenciesKitAspect::fix(Kit *k) +{ + QTC_ASSERT(k, return); + + const QVariant variant = k->value(McuDependenciesKitAspect::id()); + if (!variant.isNull() && !variant.canConvert(QVariant::List)) { + qWarning("Kit \"%s\" has a wrong mcu dependencies value set.", qPrintable(k->displayName())); + setDependencies(k, Utils::NameValueItems()); + } +} + +KitAspectWidget *McuDependenciesKitAspect::createConfigWidget(Kit *k) const +{ + QTC_ASSERT(k, return nullptr); + return new McuDependenciesKitAspectWidget(k, this); +} + +KitAspect::ItemList McuDependenciesKitAspect::toUserOutput(const Kit *k) const +{ + Q_UNUSED(k) + + return {}; +} + +Utils::Id McuDependenciesKitAspect::id() +{ + return "PE.Profile.McuDependencies"; +} + + +Utils::NameValueItems McuDependenciesKitAspect::dependencies(const Kit *k) +{ + if (k) + return Utils::NameValueItem::fromStringList(k->value(McuDependenciesKitAspect::id()).toStringList()); + return Utils::NameValueItems(); +} + +void McuDependenciesKitAspect::setDependencies(Kit *k, const Utils::NameValueItems &dependencies) +{ + if (k) + k->setValue(McuDependenciesKitAspect::id(), Utils::NameValueItem::toStringList(dependencies)); +} + +} // namespace Internal +} // namespace McuSupport diff --git a/src/plugins/mcusupport/mcukitinformation.h b/src/plugins/mcusupport/mcukitinformation.h new file mode 100644 index 00000000000..85c811ad668 --- /dev/null +++ b/src/plugins/mcusupport/mcukitinformation.h @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include + +namespace McuSupport { +namespace Internal { + +class McuDependenciesKitAspect final : public ProjectExplorer::KitAspect +{ + Q_OBJECT + +public: + McuDependenciesKitAspect(); + + ProjectExplorer::Tasks validate(const ProjectExplorer::Kit *k) const override; + void fix(ProjectExplorer::Kit *k) override; + + ProjectExplorer::KitAspectWidget *createConfigWidget(ProjectExplorer::Kit *k) const override; + + ItemList toUserOutput(const ProjectExplorer::Kit *k) const override; + + static Utils::Id id(); + static Utils::NameValueItems dependencies(const ProjectExplorer::Kit *k); + static void setDependencies(ProjectExplorer::Kit *k, const Utils::NameValueItems &dependencies); +}; + +} // namespace Internal +} // namespace McuSupport diff --git a/src/plugins/mcusupport/mcusupport.qbs b/src/plugins/mcusupport/mcusupport.qbs index f18f13a52ea..e8529e24649 100644 --- a/src/plugins/mcusupport/mcusupport.qbs +++ b/src/plugins/mcusupport/mcusupport.qbs @@ -35,6 +35,8 @@ QtcPlugin { "mcusupportversiondetection.cpp", "mcusupportversiondetection.h", "mcusupportcmakemapper.h", - "mcusupportcmakemapper.cpp" + "mcusupportcmakemapper.cpp", + "mcukitinformation.cpp", + "mcukitinformation.h" ] } diff --git a/src/plugins/mcusupport/mcusupportoptions.cpp b/src/plugins/mcusupport/mcusupportoptions.cpp index ec23b7ad084..d7ef38fdd1d 100644 --- a/src/plugins/mcusupport/mcusupportoptions.cpp +++ b/src/plugins/mcusupport/mcusupportoptions.cpp @@ -23,6 +23,7 @@ ** ****************************************************************************/ +#include "mcukitinformation.h" #include "mcupackage.h" #include "mcusupportconstants.h" #include "mcusupportoptions.h" @@ -1065,100 +1066,5 @@ void McuSupportOptions::fixExistingKits() delete qtForMCUsPackage; } -class McuDependenciesKitAspectWidget final : public KitAspectWidget -{ - Q_DECLARE_TR_FUNCTIONS(McuSupport::McuDependenciesKitAspect) - -public: - McuDependenciesKitAspectWidget(Kit *workingCopy, const KitAspect *ki) - : KitAspectWidget(workingCopy, ki) - {} - - void makeReadOnly() override {} - void refresh() override {} - void addToLayout(Utils::LayoutBuilder &) override {} -}; - } // Internal - -McuDependenciesKitAspect::McuDependenciesKitAspect() -{ - setObjectName(QLatin1String("McuDependenciesKitAspect")); - setId(McuDependenciesKitAspect::id()); - setDisplayName(tr("MCU Dependencies")); - setDescription(tr("Paths to 3rd party dependencies")); - setPriority(28500); -} - -Tasks McuDependenciesKitAspect::validate(const Kit *k) const -{ - Tasks result; - QTC_ASSERT(k, return result); - - const QVariant checkFormat = k->value(McuDependenciesKitAspect::id()); - if (!checkFormat.isNull() && !checkFormat.canConvert(QVariant::List)) - return { BuildSystemTask(Task::Error, tr("The MCU dependencies setting value is invalid.")) }; - - const QVariant envStringList = k->value(EnvironmentKitAspect::id()); - if (!envStringList.isNull() && !envStringList.canConvert(QVariant::List)) - return { BuildSystemTask(Task::Error, tr("The environment setting value is invalid.")) }; - - const auto environment = Utils::NameValueDictionary(envStringList.toStringList()); - for (const auto &dependency: dependencies(k)) { - if (!environment.hasKey(dependency.name)) { - result << BuildSystemTask(Task::Warning, tr("Environment variable %1 not defined.").arg(dependency.name)); - } else { - const auto path = Utils::FilePath::fromUserInput( - environment.value(dependency.name) + "/" + dependency.value); - if (!path.exists()) { - result << BuildSystemTask(Task::Warning, tr("%1 not found.").arg(path.toUserOutput())); - } - } - } - - return result; -} - -void McuDependenciesKitAspect::fix(Kit *k) -{ - QTC_ASSERT(k, return); - - const QVariant variant = k->value(McuDependenciesKitAspect::id()); - if (!variant.isNull() && !variant.canConvert(QVariant::List)) { - qWarning("Kit \"%s\" has a wrong mcu dependencies value set.", qPrintable(k->displayName())); - setDependencies(k, Utils::NameValueItems()); - } -} - -KitAspectWidget *McuDependenciesKitAspect::createConfigWidget(Kit *k) const -{ - QTC_ASSERT(k, return nullptr); - return new Internal::McuDependenciesKitAspectWidget(k, this); -} - -KitAspect::ItemList McuDependenciesKitAspect::toUserOutput(const Kit *k) const -{ - Q_UNUSED(k); - return {}; -} - -Utils::Id McuDependenciesKitAspect::id() -{ - return "PE.Profile.McuDependencies"; -} - - -Utils::NameValueItems McuDependenciesKitAspect::dependencies(const Kit *k) -{ - if (k) - return Utils::NameValueItem::fromStringList(k->value(McuDependenciesKitAspect::id()).toStringList()); - return Utils::NameValueItems(); -} - -void McuDependenciesKitAspect::setDependencies(Kit *k, const Utils::NameValueItems &dependencies) -{ - if (k) - k->setValue(McuDependenciesKitAspect::id(), Utils::NameValueItem::toStringList(dependencies)); -} - } // McuSupport diff --git a/src/plugins/mcusupport/mcusupportoptions.h b/src/plugins/mcusupport/mcusupportoptions.h index 1b957d4e169..faec8b3ccb6 100644 --- a/src/plugins/mcusupport/mcusupportoptions.h +++ b/src/plugins/mcusupport/mcusupportoptions.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2020 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. @@ -27,8 +27,6 @@ #include "mcusupport_global.h" -#include - #include #include #include @@ -155,24 +153,4 @@ signals: }; } // namespace Internal - -class MCUSUPPORTSHARED_EXPORT McuDependenciesKitAspect : public ProjectExplorer::KitAspect -{ - Q_OBJECT - -public: - McuDependenciesKitAspect(); - - ProjectExplorer::Tasks validate(const ProjectExplorer::Kit *k) const override; - void fix(ProjectExplorer::Kit *k) override; - - ProjectExplorer::KitAspectWidget *createConfigWidget(ProjectExplorer::Kit *k) const override; - - ItemList toUserOutput(const ProjectExplorer::Kit *k) const override; - - static Utils::Id id(); - static Utils::NameValueItems dependencies(const ProjectExplorer::Kit *k); - static void setDependencies(ProjectExplorer::Kit *k, const Utils::NameValueItems &dependencies); -}; - } // namespace McuSupport diff --git a/src/plugins/mcusupport/mcusupportplugin.cpp b/src/plugins/mcusupport/mcusupportplugin.cpp index 3e7db5e0ad7..21d8878645b 100644 --- a/src/plugins/mcusupport/mcusupportplugin.cpp +++ b/src/plugins/mcusupport/mcusupportplugin.cpp @@ -23,6 +23,7 @@ ** ****************************************************************************/ +#include "mcukitinformation.h" #include "mcusupportplugin.h" #include "mcusupportconstants.h" #include "mcusupportdevice.h" From 52e3f2cd5f782f77d4bdb08380672a24b5c488a2 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Wed, 9 Feb 2022 18:49:40 +0100 Subject: [PATCH 84/94] QmlDesigner: Cache last image in 3D view and add busy indicator This patch caches the last image from a document/model. The result ist that when reopening a file in the 3D editor the user sees immediately something. Since the view is not interactive, yet, we show a busy indicator until the view is fully initialized. Change-Id: I26c8b0ea69f98ceb41580624c51d48d1e633ab80 Reviewed-by: Mahmoud Badri Reviewed-by: Miikka Heikkinen Reviewed-by: Qt CI Bot --- .../qmldesigner/misc/BusyIndicator.qml | 86 +++++++++++++++++++ .../components/edit3d/edit3dcanvas.cpp | 54 +++++++++++- .../components/edit3d/edit3dcanvas.h | 8 +- .../components/edit3d/edit3dview.cpp | 14 ++- .../components/edit3d/edit3dview.h | 3 + 5 files changed, 159 insertions(+), 6 deletions(-) create mode 100644 share/qtcreator/qmldesigner/misc/BusyIndicator.qml diff --git a/share/qtcreator/qmldesigner/misc/BusyIndicator.qml b/share/qtcreator/qmldesigner/misc/BusyIndicator.qml new file mode 100644 index 00000000000..93cf639bca7 --- /dev/null +++ b/share/qtcreator/qmldesigner/misc/BusyIndicator.qml @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +import QtQuick +import QtQuick.Controls + +BusyIndicator { + id: control + + contentItem: Item { + implicitWidth: 64 + implicitHeight: 64 + + Item { + id: item + anchors.centerIn: parent + width: 64 + height: 64 + opacity: control.running ? 1 : 0 + + Behavior on opacity { + OpacityAnimator { + duration: 250 + } + } + + RotationAnimator { + target: item + running: control.visible && control.running + from: 0 + to: 360 + loops: Animation.Infinite + duration: 2000 + } + + Repeater { + id: repeater + model: 6 + + Rectangle { + id: delegate + anchors.centerIn: parent + implicitWidth: 10 + implicitHeight: 10 + radius: 5 + color: "#2aafd3" + + required property int index + + transform: [ + Translate { + y: -Math.min(item.width, item.height) * 0.5 + 5 + }, + Rotation { + angle: delegate.index / repeater.count * 360 + origin.x: 5 + origin.y: 5 + } + ] + } + } + } + } +} diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp index 7ea74f6cbee..65e1b763e59 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp @@ -30,21 +30,43 @@ #include "nodehints.h" #include "qmlvisualnode.h" +#include + +#include + #include #include -#include +#include #include +#include +#include namespace QmlDesigner { +static QQuickWidget *createBusyIndicator(QWidget *p) +{ + auto widget = new QQuickWidget(p); + + const QString source = Core::ICore::resourcePath("qmldesigner/misc/BusyIndicator.qml").toString(); + QTC_ASSERT(QFileInfo::exists(source), return widget); + widget->setSource(QUrl::fromLocalFile(source)); + widget->setFixedSize(64, 64); + widget->setAttribute(Qt::WA_AlwaysStackOnTop); + widget->setClearColor(Qt::transparent); + widget->setResizeMode(QQuickWidget::SizeRootObjectToView); + return widget; +} + Edit3DCanvas::Edit3DCanvas(Edit3DWidget *parent) - : QWidget(parent), - m_parent(parent) + : QWidget(parent) + , m_parent(parent) + , m_busyIndicator(createBusyIndicator(this)) { setMouseTracking(true); setAcceptDrops(true); setFocusPolicy(Qt::ClickFocus); + m_busyIndicator->show(); } void Edit3DCanvas::updateRenderImage(const QImage &img) @@ -58,6 +80,21 @@ void Edit3DCanvas::updateActiveScene(qint32 activeScene) m_activeScene = activeScene; } +QImage QmlDesigner::Edit3DCanvas::renderImage() const +{ + return m_image; +} + +void Edit3DCanvas::setOpacity(qreal opacity) +{ + m_opacity = opacity; +} + +QWidget *Edit3DCanvas::busyIndicator() const +{ + return m_busyIndicator; +} + void Edit3DCanvas::mousePressEvent(QMouseEvent *e) { m_parent->view()->sendInputEvent(e); @@ -108,11 +145,17 @@ void Edit3DCanvas::paintEvent(QPaintEvent *e) QPainter painter(this); + if (m_opacity < 1.0) { + painter.fillRect(rect(), Qt::black); + painter.setOpacity(m_opacity); + } + painter.drawImage(rect(), m_image, QRect(0, 0, m_image.width(), m_image.height())); } void Edit3DCanvas::resizeEvent(QResizeEvent *e) { + positionBusyInidicator(); m_parent->view()->edit3DViewResized(e->size()); } @@ -161,4 +204,9 @@ void Edit3DCanvas::focusInEvent(QFocusEvent *focusEvent) QWidget::focusInEvent(focusEvent); } +void Edit3DCanvas::positionBusyInidicator() +{ + m_busyIndicator->move(width() / 2 - 32, height() / 2 - 32); +} + } diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.h b/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.h index b6f07683d7e..faa164bfe9c 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.h +++ b/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.h @@ -45,8 +45,10 @@ public: void updateRenderImage(const QImage &img); void updateActiveScene(qint32 activeScene); - qint32 activeScene() const { return m_activeScene; } + QImage renderImage() const; + void setOpacity(qreal opacity); + QWidget *busyIndicator() const; protected: void mousePressEvent(QMouseEvent *e) override; @@ -64,11 +66,15 @@ protected: void focusInEvent(QFocusEvent *focusEvent) override; private: + void positionBusyInidicator(); + QPointer m_parent; QImage m_image; qint32 m_activeScene = -1; ItemLibraryEntry m_itemLibraryEntry; QElapsedTimer m_usageTimer; + qreal m_opacity = 1.0; + QWidget *m_busyIndicator = nullptr; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp index 8e6d75efc37..8a8007ec2ea 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp @@ -110,6 +110,10 @@ void Edit3DView::renderImage3DChanged(const QImage &img) // Notify puppet to resize if received image wasn't correct size if (img.size() != canvasSize()) edit3DViewResized(canvasSize()); + if (edit3DWidget()->canvas()->busyIndicator()->isVisible()) { + edit3DWidget()->canvas()->setOpacity(1.0); + edit3DWidget()->canvas()->busyIndicator()->hide(); + } } void Edit3DView::updateActiveScene3D(const QVariantMap &sceneState) @@ -195,13 +199,19 @@ void Edit3DView::modelAttached(Model *model) AbstractView::modelAttached(model); checkImports(); + auto cachedImage = m_canvasCache.take(model); + if (cachedImage) { + edit3DWidget()->canvas()->updateRenderImage(*cachedImage); + edit3DWidget()->canvas()->setOpacity(0.5); + } + + edit3DWidget()->canvas()->busyIndicator()->show(); } void Edit3DView::modelAboutToBeDetached(Model *model) { - Q_UNUSED(model) - // Hide the canvas when model is detached (i.e. changing documents) + m_canvasCache.insert(model, edit3DWidget()->canvas()->renderImage()); edit3DWidget()->showCanvas(false); AbstractView::modelAboutToBeDetached(model); diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.h b/src/plugins/qmldesigner/components/edit3d/edit3dview.h index 721a69bfa2e..daddb84d6c8 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dview.h +++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.h @@ -27,6 +27,8 @@ #include "view3dactioncommand.h" #include "seekerslider.h" +#include + #include #include #include @@ -107,6 +109,7 @@ private: Edit3DAction *m_visibilityTogglesAction = nullptr; SeekerSlider *m_seeker = nullptr; int particlemode; + ModelCache m_canvasCache; }; } // namespace QmlDesigner From 93fc6b5c3c6caa92ff9a091c73748f320d40d4ee Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Mon, 7 Feb 2022 16:17:35 +0100 Subject: [PATCH 85/94] McuSupport: Make all member fields of McuTarget const In proactive, the color depth was never changed after setCMakeOptions was called. This change makes it clear that it is also not intended to be changed: a board does not suddenly change color depth, and for a new board configuration a new target is created. Change-Id: Ie5b99726d833efcdf129655b8e70120a033914e6 Reviewed-by: Alessandro Portale Reviewed-by: --- src/plugins/mcusupport/mcusupportoptions.cpp | 16 +++++++--------- src/plugins/mcusupport/mcusupportoptions.h | 17 +++++++++++------ src/plugins/mcusupport/mcusupportsdk.cpp | 19 +++++++++++++------ 3 files changed, 31 insertions(+), 21 deletions(-) diff --git a/src/plugins/mcusupport/mcusupportoptions.cpp b/src/plugins/mcusupport/mcusupportoptions.cpp index d7ef38fdd1d..36811c5a13a 100644 --- a/src/plugins/mcusupport/mcusupportoptions.cpp +++ b/src/plugins/mcusupport/mcusupportoptions.cpp @@ -267,14 +267,17 @@ QVariant McuToolChainPackage::debuggerId() const } McuTarget::McuTarget(const QVersionNumber &qulVersion, - const Platform &platform, OS os, + const Platform &platform, + OS os, const QVector &packages, - const McuToolChainPackage *toolChainPackage) + const McuToolChainPackage *toolChainPackage, + int colorDepth) : m_qulVersion(qulVersion) , m_platform(platform) , m_os(os) , m_packages(packages) , m_toolChainPackage(toolChainPackage) + , m_colorDepth(colorDepth) { } @@ -335,11 +338,6 @@ int McuTarget::colorDepth() const return m_colorDepth; } -void McuTarget::setColorDepth(int colorDepth) -{ - m_colorDepth = colorDepth; -} - void McuSdkRepository::deletePackagesAndTargets() { qDeleteAll(packages); @@ -665,7 +663,7 @@ static void setKitCMakeOptions(Kit *k, const McuTarget* mcuTarget, const FilePat if (mcuTarget->qulVersion() <= QVersionNumber{1,3} // OS variable was removed in Qul 1.4 && mcuTarget->os() == McuTarget::OS::FreeRTOS) config.append(CMakeConfigItem("OS", "FreeRTOS")); - if (mcuTarget->colorDepth() >= 0) + if (mcuTarget->colorDepth() != McuTarget::UnspecifiedColorDepth) config.append(CMakeConfigItem("QUL_COLOR_DEPTH", QString::number(mcuTarget->colorDepth()).toLatin1())); if (kitNeedsQtVersion()) @@ -700,7 +698,7 @@ QString McuSupportOptions::kitName(const McuTarget *mcuTarget) const QString compilerName = tcPkg && !tcPkg->isDesktopToolchain() ? QString::fromLatin1(" (%1)").arg(tcPkg->toolChainName().toUpper()) : ""; - const QString colorDepth = mcuTarget->colorDepth() > 0 + const QString colorDepth = mcuTarget->colorDepth() != McuTarget::UnspecifiedColorDepth ? QString::fromLatin1(" %1bpp").arg(mcuTarget->colorDepth()) : ""; const QString targetName = mcuTarget->platform().displayName.isEmpty() diff --git a/src/plugins/mcusupport/mcusupportoptions.h b/src/plugins/mcusupport/mcusupportoptions.h index faec8b3ccb6..e7b0f66015a 100644 --- a/src/plugins/mcusupport/mcusupportoptions.h +++ b/src/plugins/mcusupport/mcusupportoptions.h @@ -1,6 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2021 +** The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. @@ -69,16 +70,20 @@ public: QString vendor; }; - McuTarget(const QVersionNumber &qulVersion, const Platform &platform, OS os, + enum { UnspecifiedColorDepth = -1 }; + + McuTarget(const QVersionNumber &qulVersion, + const Platform &platform, + OS os, const QVector &packages, - const McuToolChainPackage *toolChainPackage); + const McuToolChainPackage *toolChainPackage, + int colorDepth = UnspecifiedColorDepth); const QVersionNumber &qulVersion() const; const QVector &packages() const; const McuToolChainPackage *toolChainPackage() const; const Platform &platform() const; OS os() const; - void setColorDepth(int colorDepth); int colorDepth() const; bool isValid() const; void printPackageProblems() const; @@ -86,10 +91,10 @@ public: private: const QVersionNumber m_qulVersion; const Platform m_platform; - const OS m_os = OS::BareMetal; + const OS m_os; const QVector m_packages; const McuToolChainPackage *m_toolChainPackage; - int m_colorDepth = -1; + const int m_colorDepth; }; class McuSdkRepository diff --git a/src/plugins/mcusupport/mcusupportsdk.cpp b/src/plugins/mcusupport/mcusupportsdk.cpp index 2287ad61d7e..a966d10870d 100644 --- a/src/plugins/mcusupport/mcusupportsdk.cpp +++ b/src/plugins/mcusupport/mcusupportsdk.cpp @@ -512,9 +512,13 @@ protected: const auto platform = McuTarget::Platform{ desc.platform.id, desc.platform.name, desc.platform.vendor }; auto mcuTarget = new McuTarget(QVersionNumber::fromString(desc.qulVersion), - platform, os, required3rdPartyPkgs, tcPkg); - if (desc.platform.colorDepths.count() > 1) - mcuTarget->setColorDepth(colorDepth); + platform, + os, + required3rdPartyPkgs, + tcPkg, + desc.platform.colorDepths.count() > 1 + ? colorDepth + : McuTarget::UnspecifiedColorDepth); mcuTargets.append(mcuTarget); } } @@ -586,10 +590,13 @@ protected: required3rdPartyPkgs.append(freeRTOSPkgs.value(desc.freeRTOS.envVar)); } - const auto platform = McuTarget::Platform{ desc.platform.id, desc.platform.name, desc.platform.vendor }; + const McuTarget::Platform platform({ desc.platform.id, desc.platform.name, desc.platform.vendor }); auto mcuTarget = new McuTarget(QVersionNumber::fromString(desc.qulVersion), - platform, os, required3rdPartyPkgs, tcPkg); - mcuTarget->setColorDepth(colorDepth); + platform, + os, + required3rdPartyPkgs, + tcPkg, + colorDepth); mcuTargets.append(mcuTarget); } return mcuTargets; From 26bf18e1fefed78a5a4f87df7c02c5d90e9d4686 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Thu, 10 Feb 2022 17:16:04 +0100 Subject: [PATCH 86/94] Core: Turn LocatorFilterEntry ofn ILocatorFilter::accept to const & In ILocatorFilter::accept and all the overrides. Change-Id: I27cd6babb66d91aad57e85572a1cdc77aef4fd79 Reviewed-by: Reviewed-by: Qt CI Bot Reviewed-by: Eike Ziller --- src/plugins/bookmarks/bookmarkfilter.cpp | 2 +- src/plugins/bookmarks/bookmarkfilter.h | 2 +- src/plugins/clangcodemodel/clangcurrentdocumentfilter.cpp | 2 +- src/plugins/clangcodemodel/clangcurrentdocumentfilter.h | 2 +- src/plugins/clangcodemodel/clangdlocatorfilters.cpp | 4 ++-- src/plugins/clangcodemodel/clangdlocatorfilters.h | 4 ++-- src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp | 4 ++-- src/plugins/cmakeprojectmanager/cmakelocatorfilter.h | 4 ++-- src/plugins/coreplugin/locator/basefilefilter.cpp | 2 +- src/plugins/coreplugin/locator/basefilefilter.h | 2 +- src/plugins/coreplugin/locator/commandlocator.cpp | 2 +- src/plugins/coreplugin/locator/commandlocator.h | 2 +- src/plugins/coreplugin/locator/executefilter.cpp | 2 +- src/plugins/coreplugin/locator/executefilter.h | 2 +- src/plugins/coreplugin/locator/externaltoolsfilter.cpp | 2 +- src/plugins/coreplugin/locator/externaltoolsfilter.h | 2 +- src/plugins/coreplugin/locator/filesystemfilter.cpp | 2 +- src/plugins/coreplugin/locator/filesystemfilter.h | 2 +- src/plugins/coreplugin/locator/ilocatorfilter.cpp | 2 +- src/plugins/coreplugin/locator/ilocatorfilter.h | 2 +- src/plugins/coreplugin/locator/javascriptfilter.cpp | 2 +- src/plugins/coreplugin/locator/javascriptfilter.h | 2 +- src/plugins/coreplugin/locator/locatorfiltersfilter.cpp | 2 +- src/plugins/coreplugin/locator/locatorfiltersfilter.h | 2 +- src/plugins/coreplugin/locator/opendocumentsfilter.cpp | 2 +- src/plugins/coreplugin/locator/opendocumentsfilter.h | 2 +- src/plugins/coreplugin/locator/urllocatorfilter.cpp | 2 +- src/plugins/coreplugin/locator/urllocatorfilter.h | 2 +- src/plugins/coreplugin/menubarfilter.cpp | 2 +- src/plugins/coreplugin/menubarfilter.h | 2 +- src/plugins/cppeditor/cppcurrentdocumentfilter.cpp | 2 +- src/plugins/cppeditor/cppcurrentdocumentfilter.h | 2 +- src/plugins/cppeditor/cpplocatorfilter.cpp | 2 +- src/plugins/cppeditor/cpplocatorfilter.h | 2 +- src/plugins/help/helpindexfilter.cpp | 2 +- src/plugins/help/helpindexfilter.h | 2 +- src/plugins/languageclient/locatorfilter.cpp | 4 ++-- src/plugins/languageclient/locatorfilter.h | 4 ++-- src/plugins/macros/macrolocatorfilter.cpp | 2 +- src/plugins/macros/macrolocatorfilter.h | 2 +- src/plugins/qmljstools/qmljsfunctionfilter.cpp | 2 +- src/plugins/qmljstools/qmljsfunctionfilter.h | 2 +- src/plugins/texteditor/linenumberfilter.cpp | 2 +- src/plugins/texteditor/linenumberfilter.h | 2 +- 44 files changed, 50 insertions(+), 50 deletions(-) diff --git a/src/plugins/bookmarks/bookmarkfilter.cpp b/src/plugins/bookmarks/bookmarkfilter.cpp index 28173ffe5d1..594b18e11c9 100644 --- a/src/plugins/bookmarks/bookmarkfilter.cpp +++ b/src/plugins/bookmarks/bookmarkfilter.cpp @@ -124,7 +124,7 @@ QList BookmarkFilter::matchesFor(QFutureInterface matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(Core::LocatorFilterEntry selection, QString *newText, + void accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; private: diff --git a/src/plugins/clangcodemodel/clangcurrentdocumentfilter.cpp b/src/plugins/clangcodemodel/clangcurrentdocumentfilter.cpp index ced0fafa76e..47b4803f894 100644 --- a/src/plugins/clangcodemodel/clangcurrentdocumentfilter.cpp +++ b/src/plugins/clangcodemodel/clangcurrentdocumentfilter.cpp @@ -135,7 +135,7 @@ QList ClangCurrentDocumentFilter::matchesFor( return goodEntries; } -void ClangCurrentDocumentFilter::accept(Core::LocatorFilterEntry selection, +void ClangCurrentDocumentFilter::accept(const Core::LocatorFilterEntry &selection, QString *, int *, int *) const { if (!m_currentEditor) diff --git a/src/plugins/clangcodemodel/clangcurrentdocumentfilter.h b/src/plugins/clangcodemodel/clangcurrentdocumentfilter.h index 599bbd2d59b..c60d20630f8 100644 --- a/src/plugins/clangcodemodel/clangcurrentdocumentfilter.h +++ b/src/plugins/clangcodemodel/clangcurrentdocumentfilter.h @@ -42,7 +42,7 @@ public: void prepareSearch(const QString &entry) override; QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(Core::LocatorFilterEntry selection, + void accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; private: diff --git a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp index cafd7633d7d..6aa5d1e9703 100644 --- a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp +++ b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp @@ -198,7 +198,7 @@ QList ClangGlobalSymbolFilter::matchesFor( return matches; } -void ClangGlobalSymbolFilter::accept(Core::LocatorFilterEntry selection, QString *newText, +void ClangGlobalSymbolFilter::accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const { if (qvariant_cast(selection.internalData)) @@ -318,7 +318,7 @@ QList ClangdCurrentDocumentFilter::matchesFor( return d->activeFilter->matchesFor(future, entry); } -void ClangdCurrentDocumentFilter::accept(Core::LocatorFilterEntry selection, QString *newText, +void ClangdCurrentDocumentFilter::accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const { QTC_ASSERT(d->activeFilter, return); diff --git a/src/plugins/clangcodemodel/clangdlocatorfilters.h b/src/plugins/clangcodemodel/clangdlocatorfilters.h index 28341a6a573..bf3f6792820 100644 --- a/src/plugins/clangcodemodel/clangdlocatorfilters.h +++ b/src/plugins/clangcodemodel/clangdlocatorfilters.h @@ -41,7 +41,7 @@ private: void prepareSearch(const QString &entry) override; QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(Core::LocatorFilterEntry selection, QString *newText, + void accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; Core::ILocatorFilter * const m_cppFilter; @@ -70,7 +70,7 @@ private: void prepareSearch(const QString &entry) override; QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(Core::LocatorFilterEntry selection, QString *newText, + void accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; class Private; diff --git a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp index 9364b155952..ec6d14b9b5e 100644 --- a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp +++ b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp @@ -121,7 +121,7 @@ BuildCMakeTargetLocatorFilter::BuildCMakeTargetLocatorFilter() setPriority(High); } -void BuildCMakeTargetLocatorFilter::accept(Core::LocatorFilterEntry selection, +void BuildCMakeTargetLocatorFilter::accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const @@ -171,7 +171,7 @@ OpenCMakeTargetLocatorFilter::OpenCMakeTargetLocatorFilter() setPriority(Medium); } -void OpenCMakeTargetLocatorFilter::accept(Core::LocatorFilterEntry selection, +void OpenCMakeTargetLocatorFilter::accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const diff --git a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.h b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.h index 0749e2bb858..99cc87eca68 100644 --- a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.h +++ b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.h @@ -54,7 +54,7 @@ class BuildCMakeTargetLocatorFilter : CMakeTargetLocatorFilter public: BuildCMakeTargetLocatorFilter(); - void accept(Core::LocatorFilterEntry selection, + void accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const final; @@ -67,7 +67,7 @@ class OpenCMakeTargetLocatorFilter : CMakeTargetLocatorFilter public: OpenCMakeTargetLocatorFilter(); - void accept(Core::LocatorFilterEntry selection, + void accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const final; diff --git a/src/plugins/coreplugin/locator/basefilefilter.cpp b/src/plugins/coreplugin/locator/basefilefilter.cpp index 8c34e305aac..888db29ac58 100644 --- a/src/plugins/coreplugin/locator/basefilefilter.cpp +++ b/src/plugins/coreplugin/locator/basefilefilter.cpp @@ -218,7 +218,7 @@ QList BaseFileFilter::matchesFor(QFutureInterface matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(LocatorFilterEntry selection, + void accept(const LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; static void openEditorAt(const LocatorFilterEntry &selection); diff --git a/src/plugins/coreplugin/locator/commandlocator.cpp b/src/plugins/coreplugin/locator/commandlocator.cpp index bb8029ce25a..7a803ac1c98 100644 --- a/src/plugins/coreplugin/locator/commandlocator.cpp +++ b/src/plugins/coreplugin/locator/commandlocator.cpp @@ -112,7 +112,7 @@ QList CommandLocator::matchesFor(QFutureInterface matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(LocatorFilterEntry selection, + void accept(const LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; private: diff --git a/src/plugins/coreplugin/locator/executefilter.cpp b/src/plugins/coreplugin/locator/executefilter.cpp index 7924b8a0053..327731f1e26 100644 --- a/src/plugins/coreplugin/locator/executefilter.cpp +++ b/src/plugins/coreplugin/locator/executefilter.cpp @@ -80,7 +80,7 @@ QList ExecuteFilter::matchesFor(QFutureInterface matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(LocatorFilterEntry selection, + void accept(const LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; private: diff --git a/src/plugins/coreplugin/locator/externaltoolsfilter.cpp b/src/plugins/coreplugin/locator/externaltoolsfilter.cpp index 159af87cafc..719f52e59d4 100644 --- a/src/plugins/coreplugin/locator/externaltoolsfilter.cpp +++ b/src/plugins/coreplugin/locator/externaltoolsfilter.cpp @@ -49,7 +49,7 @@ QList ExternalToolsFilter::matchesFor(QFutureInterface matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(LocatorFilterEntry selection, + void accept(const LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; void prepareSearch(const QString &entry) override; diff --git a/src/plugins/coreplugin/locator/filesystemfilter.cpp b/src/plugins/coreplugin/locator/filesystemfilter.cpp index 9e0751e570f..08ecb68418a 100644 --- a/src/plugins/coreplugin/locator/filesystemfilter.cpp +++ b/src/plugins/coreplugin/locator/filesystemfilter.cpp @@ -169,7 +169,7 @@ QList FileSystemFilter::matchesFor(QFutureInterface matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(LocatorFilterEntry selection, + void accept(const LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; void restoreState(const QByteArray &state) override; bool openConfigDialog(QWidget *parent, bool &needsRefresh) override; diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.cpp b/src/plugins/coreplugin/locator/ilocatorfilter.cpp index aee4fe49065..3d15253ef31 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/ilocatorfilter.cpp @@ -595,7 +595,7 @@ bool ILocatorFilter::isOldSetting(const QByteArray &state) */ /*! - \fn void Core::ILocatorFilter::accept(Core::LocatorFilterEntry selection, QString *newText, int *selectionStart, int *selectionLength) const + \fn void Core::ILocatorFilter::accept(Core::const LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const Called with the entry specified by \a selection when the user activates it in the result list. diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.h b/src/plugins/coreplugin/locator/ilocatorfilter.h index 48679878691..dfcbfc4e67f 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.h +++ b/src/plugins/coreplugin/locator/ilocatorfilter.h @@ -143,7 +143,7 @@ public: virtual QList matchesFor(QFutureInterface &future, const QString &entry) = 0; - virtual void accept(LocatorFilterEntry selection, + virtual void accept(const LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const = 0; virtual void refresh(QFutureInterface &future) { Q_UNUSED(future) }; diff --git a/src/plugins/coreplugin/locator/javascriptfilter.cpp b/src/plugins/coreplugin/locator/javascriptfilter.cpp index 257f133dda8..b15c69f5337 100644 --- a/src/plugins/coreplugin/locator/javascriptfilter.cpp +++ b/src/plugins/coreplugin/locator/javascriptfilter.cpp @@ -89,7 +89,7 @@ QList JavaScriptFilter::matchesFor( return entries; } -void JavaScriptFilter::accept(Core::LocatorFilterEntry selection, QString *newText, +void JavaScriptFilter::accept(const LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const { Q_UNUSED(newText) diff --git a/src/plugins/coreplugin/locator/javascriptfilter.h b/src/plugins/coreplugin/locator/javascriptfilter.h index ccded299900..fffe0ad1b07 100644 --- a/src/plugins/coreplugin/locator/javascriptfilter.h +++ b/src/plugins/coreplugin/locator/javascriptfilter.h @@ -49,7 +49,7 @@ public: void prepareSearch(const QString &entry) override; QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(Core::LocatorFilterEntry selection, QString *newText, + void accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; private: diff --git a/src/plugins/coreplugin/locator/locatorfiltersfilter.cpp b/src/plugins/coreplugin/locator/locatorfiltersfilter.cpp index 7b62ff1bf1e..6eed862a5cb 100644 --- a/src/plugins/coreplugin/locator/locatorfiltersfilter.cpp +++ b/src/plugins/coreplugin/locator/locatorfiltersfilter.cpp @@ -89,7 +89,7 @@ QList LocatorFiltersFilter::matchesFor(QFutureInterface matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(LocatorFilterEntry selection, + void accept(const LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; private: diff --git a/src/plugins/coreplugin/locator/opendocumentsfilter.cpp b/src/plugins/coreplugin/locator/opendocumentsfilter.cpp index e6aced8d00a..2570c7ea650 100644 --- a/src/plugins/coreplugin/locator/opendocumentsfilter.cpp +++ b/src/plugins/coreplugin/locator/opendocumentsfilter.cpp @@ -120,7 +120,7 @@ void OpenDocumentsFilter::refresh(QFutureInterface &future) QMetaObject::invokeMethod(this, &OpenDocumentsFilter::refreshInternally, Qt::QueuedConnection); } -void OpenDocumentsFilter::accept(LocatorFilterEntry selection, +void OpenDocumentsFilter::accept(const LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const { Q_UNUSED(newText) diff --git a/src/plugins/coreplugin/locator/opendocumentsfilter.h b/src/plugins/coreplugin/locator/opendocumentsfilter.h index 956dea22d2e..eb9315d1916 100644 --- a/src/plugins/coreplugin/locator/opendocumentsfilter.h +++ b/src/plugins/coreplugin/locator/opendocumentsfilter.h @@ -45,7 +45,7 @@ public: OpenDocumentsFilter(); QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(LocatorFilterEntry selection, + void accept(const LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; void refresh(QFutureInterface &future) override; diff --git a/src/plugins/coreplugin/locator/urllocatorfilter.cpp b/src/plugins/coreplugin/locator/urllocatorfilter.cpp index 2e58cde291e..061c5c49bac 100644 --- a/src/plugins/coreplugin/locator/urllocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/urllocatorfilter.cpp @@ -162,7 +162,7 @@ QList UrlLocatorFilter::matchesFor( return entries; } -void UrlLocatorFilter::accept(Core::LocatorFilterEntry selection, +void UrlLocatorFilter::accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const diff --git a/src/plugins/coreplugin/locator/urllocatorfilter.h b/src/plugins/coreplugin/locator/urllocatorfilter.h index fdfe8096d3a..8a011a42f41 100644 --- a/src/plugins/coreplugin/locator/urllocatorfilter.h +++ b/src/plugins/coreplugin/locator/urllocatorfilter.h @@ -46,7 +46,7 @@ public: // ILocatorFilter QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(Core::LocatorFilterEntry selection, + void accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; void restoreState(const QByteArray &state) override; bool openConfigDialog(QWidget *parent, bool &needsRefresh) override; diff --git a/src/plugins/coreplugin/menubarfilter.cpp b/src/plugins/coreplugin/menubarfilter.cpp index 207959f2d74..4d30763eebf 100644 --- a/src/plugins/coreplugin/menubarfilter.cpp +++ b/src/plugins/coreplugin/menubarfilter.cpp @@ -79,7 +79,7 @@ QList MenuBarFilter::matchesFor(QFutureInterface matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(LocatorFilterEntry selection, QString *newText, + void accept(const LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; void prepareSearch(const QString &entry) override; diff --git a/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp b/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp index a35eb9c6f14..7c83ceaec61 100644 --- a/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp +++ b/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp @@ -117,7 +117,7 @@ QList CppCurrentDocumentFilter::matchesFor( return betterEntries; } -void CppCurrentDocumentFilter::accept(Core::LocatorFilterEntry selection, +void CppCurrentDocumentFilter::accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const { diff --git a/src/plugins/cppeditor/cppcurrentdocumentfilter.h b/src/plugins/cppeditor/cppcurrentdocumentfilter.h index 073f601d374..b6c715c70db 100644 --- a/src/plugins/cppeditor/cppcurrentdocumentfilter.h +++ b/src/plugins/cppeditor/cppcurrentdocumentfilter.h @@ -47,7 +47,7 @@ public: QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(Core::LocatorFilterEntry selection, + void accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; private: diff --git a/src/plugins/cppeditor/cpplocatorfilter.cpp b/src/plugins/cppeditor/cpplocatorfilter.cpp index 1def7351788..08421e6cb9d 100644 --- a/src/plugins/cppeditor/cpplocatorfilter.cpp +++ b/src/plugins/cppeditor/cpplocatorfilter.cpp @@ -136,7 +136,7 @@ QList CppLocatorFilter::matchesFor( return std::accumulate(std::begin(entries), std::end(entries), QList()); } -void CppLocatorFilter::accept(Core::LocatorFilterEntry selection, +void CppLocatorFilter::accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const { Q_UNUSED(newText) diff --git a/src/plugins/cppeditor/cpplocatorfilter.h b/src/plugins/cppeditor/cpplocatorfilter.h index fa579f1067a..fd74f1a9f6a 100644 --- a/src/plugins/cppeditor/cpplocatorfilter.h +++ b/src/plugins/cppeditor/cpplocatorfilter.h @@ -43,7 +43,7 @@ public: QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(Core::LocatorFilterEntry selection, + void accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; protected: diff --git a/src/plugins/help/helpindexfilter.cpp b/src/plugins/help/helpindexfilter.cpp index ee810c866e7..5e422c3a59d 100644 --- a/src/plugins/help/helpindexfilter.cpp +++ b/src/plugins/help/helpindexfilter.cpp @@ -197,7 +197,7 @@ QList HelpIndexFilter::matchesFor(QFutureInterface matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(Core::LocatorFilterEntry selection, + void accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; void refresh(QFutureInterface &future) override; diff --git a/src/plugins/languageclient/locatorfilter.cpp b/src/plugins/languageclient/locatorfilter.cpp index 28d01d2c82d..5ccc4d175a0 100644 --- a/src/plugins/languageclient/locatorfilter.cpp +++ b/src/plugins/languageclient/locatorfilter.cpp @@ -218,7 +218,7 @@ QList DocumentLocatorFilter::matchesFor( return {}; } -void DocumentLocatorFilter::accept(Core::LocatorFilterEntry selection, +void DocumentLocatorFilter::accept(const Core::LocatorFilterEntry &selection, QString * /*newText*/, int * /*selectionStart*/, int * /*selectionLength*/) const @@ -325,7 +325,7 @@ QList WorkspaceLocatorFilter::matchesFor( .toList(); } -void WorkspaceLocatorFilter::accept(Core::LocatorFilterEntry selection, +void WorkspaceLocatorFilter::accept(const Core::LocatorFilterEntry &selection, QString * /*newText*/, int * /*selectionStart*/, int * /*selectionLength*/) const diff --git a/src/plugins/languageclient/locatorfilter.h b/src/plugins/languageclient/locatorfilter.h index ebc35de57a7..c149fadcad0 100644 --- a/src/plugins/languageclient/locatorfilter.h +++ b/src/plugins/languageclient/locatorfilter.h @@ -49,7 +49,7 @@ public: void prepareSearch(const QString &entry) override; QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(Core::LocatorFilterEntry selection, + void accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; @@ -103,7 +103,7 @@ public: void prepareSearch(const QString &entry, const QVector &clients); QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(Core::LocatorFilterEntry selection, + void accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; diff --git a/src/plugins/macros/macrolocatorfilter.cpp b/src/plugins/macros/macrolocatorfilter.cpp index 35b238454b7..533f2461907 100644 --- a/src/plugins/macros/macrolocatorfilter.cpp +++ b/src/plugins/macros/macrolocatorfilter.cpp @@ -85,7 +85,7 @@ QList MacroLocatorFilter::matchesFor(QFutureInterface< return betterEntries; } -void MacroLocatorFilter::accept(Core::LocatorFilterEntry selection, +void MacroLocatorFilter::accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const { Q_UNUSED(newText) diff --git a/src/plugins/macros/macrolocatorfilter.h b/src/plugins/macros/macrolocatorfilter.h index b12a8a30ff4..f81831c3f8b 100644 --- a/src/plugins/macros/macrolocatorfilter.h +++ b/src/plugins/macros/macrolocatorfilter.h @@ -42,7 +42,7 @@ public: QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(Core::LocatorFilterEntry selection, + void accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; private: diff --git a/src/plugins/qmljstools/qmljsfunctionfilter.cpp b/src/plugins/qmljstools/qmljsfunctionfilter.cpp index 60b0cedc8c7..6525cff633a 100644 --- a/src/plugins/qmljstools/qmljsfunctionfilter.cpp +++ b/src/plugins/qmljstools/qmljsfunctionfilter.cpp @@ -95,7 +95,7 @@ QList FunctionFilter::matchesFor( return std::accumulate(std::begin(entries), std::end(entries), QList()); } -void FunctionFilter::accept(Core::LocatorFilterEntry selection, +void FunctionFilter::accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const { Q_UNUSED(newText) diff --git a/src/plugins/qmljstools/qmljsfunctionfilter.h b/src/plugins/qmljstools/qmljsfunctionfilter.h index ee96834a5c1..d0997f54b96 100644 --- a/src/plugins/qmljstools/qmljsfunctionfilter.h +++ b/src/plugins/qmljstools/qmljsfunctionfilter.h @@ -42,7 +42,7 @@ public: QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(Core::LocatorFilterEntry selection, + void accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; private: diff --git a/src/plugins/texteditor/linenumberfilter.cpp b/src/plugins/texteditor/linenumberfilter.cpp index 7695bbd39d7..7b772023986 100644 --- a/src/plugins/texteditor/linenumberfilter.cpp +++ b/src/plugins/texteditor/linenumberfilter.cpp @@ -90,7 +90,7 @@ QList LineNumberFilter::matchesFor(QFutureInterface matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(Core::LocatorFilterEntry selection, + void accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; private: From a9c5d6b99fe7feb42ebd2f20ae246208174ea01a Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 10 Feb 2022 15:41:23 +0100 Subject: [PATCH 87/94] Fix accelerator/mnemonic conflicts in advanced search Fixes: QTCREATORBUG-26914 Change-Id: I260e2dac92a2e2cac8d7a0cda111fe38d9265d19 Reviewed-by: Reviewed-by: hjk --- src/plugins/coreplugin/find/finddialog.ui | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/coreplugin/find/finddialog.ui b/src/plugins/coreplugin/find/finddialog.ui index 4ccc2c99202..bcd64728b4e 100644 --- a/src/plugins/coreplugin/find/finddialog.ui +++ b/src/plugins/coreplugin/find/finddialog.ui @@ -57,7 +57,7 @@ - Sear&ch for: + Search f&or: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -132,7 +132,7 @@ - Case &sensitive + &Case sensitive From 12c63bbce9f829ef9c165cfc651c0ea1c25a23e1 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 10 Feb 2022 16:39:48 +0100 Subject: [PATCH 88/94] Tests: Fix manual plugin view test Amends b822b3f9e207. Change-Id: Ibbed286a8626396319738194f417cedc84332011 Reviewed-by: Christian Kandeler --- qbs/imports/QtcManualtest.qbs | 2 ++ tests/manual/pluginview/plugindialog.cpp | 2 +- tests/manual/pluginview/plugins/plugin1/plugin1.qbs | 3 +++ tests/manual/pluginview/plugins/plugin2/plugin2.qbs | 3 +++ tests/manual/pluginview/plugins/plugin3/plugin3.qbs | 3 +++ 5 files changed, 12 insertions(+), 1 deletion(-) diff --git a/qbs/imports/QtcManualtest.qbs b/qbs/imports/QtcManualtest.qbs index cc21c8e3fa6..cfa1abc1d8f 100644 --- a/qbs/imports/QtcManualtest.qbs +++ b/qbs/imports/QtcManualtest.qbs @@ -17,5 +17,7 @@ QtcProduct { return defines; } + destinationDirectory: project.buildDirectory + '/' + + FileInfo.relativePath(project.ide_source_tree, sourceDirectory) install: false } diff --git a/tests/manual/pluginview/plugindialog.cpp b/tests/manual/pluginview/plugindialog.cpp index 9a0af5d449e..05e9bede88e 100644 --- a/tests/manual/pluginview/plugindialog.cpp +++ b/tests/manual/pluginview/plugindialog.cpp @@ -136,7 +136,7 @@ int main(int argc, char *argv[]) QObject::connect(&app, &QCoreApplication::aboutToQuit, &manager, &ExtensionSystem::PluginManager::shutdown); PluginDialog dialog; - manager.setPluginPaths(QStringList() << "plugins"); + manager.setPluginPaths(QStringList() << app.applicationDirPath() + "/plugins"); manager.loadPlugins(); dialog.show(); app.exec(); diff --git a/tests/manual/pluginview/plugins/plugin1/plugin1.qbs b/tests/manual/pluginview/plugins/plugin1/plugin1.qbs index 631d08088d3..e709f0208ae 100644 --- a/tests/manual/pluginview/plugins/plugin1/plugin1.qbs +++ b/tests/manual/pluginview/plugins/plugin1/plugin1.qbs @@ -1,7 +1,10 @@ +import qbs.FileInfo + QtcManualtest { name: "Manual test plugin1" targetName: "plugin1" type: [ "dynamiclibrary" ] + destinationDirectory: FileInfo.cleanPath(FileInfo.joinPaths(base , "..")) Depends { name: "ExtensionSystem" } Depends { name: "Manual test plugin2"} diff --git a/tests/manual/pluginview/plugins/plugin2/plugin2.qbs b/tests/manual/pluginview/plugins/plugin2/plugin2.qbs index f2cb5036f1b..4c97412990c 100644 --- a/tests/manual/pluginview/plugins/plugin2/plugin2.qbs +++ b/tests/manual/pluginview/plugins/plugin2/plugin2.qbs @@ -1,7 +1,10 @@ +import qbs.FileInfo + QtcManualtest { name: "Manual test plugin2" targetName: "plugin2" type: [ "dynamiclibrary" ] + destinationDirectory: FileInfo.cleanPath(FileInfo.joinPaths(base , "..")) Depends { name: "ExtensionSystem" } diff --git a/tests/manual/pluginview/plugins/plugin3/plugin3.qbs b/tests/manual/pluginview/plugins/plugin3/plugin3.qbs index 884b850c6f9..659fcda5063 100644 --- a/tests/manual/pluginview/plugins/plugin3/plugin3.qbs +++ b/tests/manual/pluginview/plugins/plugin3/plugin3.qbs @@ -1,7 +1,10 @@ +import qbs.FileInfo + QtcManualtest { name: "Manual test plugin3" targetName: "plugin3" type: [ "dynamiclibrary" ] + destinationDirectory: FileInfo.cleanPath(FileInfo.joinPaths(base , "..")) Depends { name: "ExtensionSystem" } Depends { name: "Manual test plugin2" } From 37f8fcd79113c4093f6984e94f507d05dde54090 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Wed, 9 Feb 2022 09:13:05 +0100 Subject: [PATCH 89/94] Editor: update ksyntaxhighlighting engine to v5.90.0 Task-number: QTCREATORBUG-22558 Change-Id: I7314c146a6de359ea8d60750d8a2c8e972b33fc9 Reviewed-by: Qt CI Bot Reviewed-by: Eike Ziller --- .../syntax-highlighting/CMakeLists.txt | 1 + .../ksyntaxhighlighting_version.h | 6 +- .../src/lib/ksyntaxhighlighting_export.h | 8 +- .../syntax-highlighting/data/CMakeLists.txt | 4 +- .../data/generators/cmake.xml.tpl | 145 +- .../data/generators/cmake.yaml | 1822 ++++++++- .../data/generators/generate-cmake-syntax.py | 37 +- .../data/generators/spdx-comments.xml.tpl | 11 +- .../data/schema/language.xsd | 4 +- .../syntax-highlighting/data/syntax/bash.xml | 50 +- .../syntax-highlighting/data/syntax/cmake.xml | 3615 ++++++++++++++++- .../data/syntax/markdown.xml | 41 +- .../data/syntax/spdx-comments.xml | 971 ++--- .../data/themes/oblivion.theme | 4 +- .../syntax-highlighting/src/CMakeLists.txt | 5 +- .../src/indexer/CMakeLists.txt | 3 +- .../src/indexer/katehighlightingindexer.cpp | 155 +- .../src/lib/CMakeLists.txt | 11 +- .../src/lib/abstracthighlighter.cpp | 8 +- .../src/lib/ansihighlighter.cpp | 26 +- .../syntax-highlighting/src/lib/context.cpp | 176 +- .../syntax-highlighting/src/lib/context_p.h | 51 +- .../src/lib/contextswitch.cpp | 72 +- .../src/lib/contextswitch_p.h | 24 +- .../src/lib/definition.cpp | 176 +- .../src/lib/definition_p.h | 18 +- .../src/lib/definitiondownloader.cpp | 3 +- .../src/lib/definitiondownloader.h | 2 +- .../src/lib/definitionref_p.h | 4 + .../src/lib/highlightingdata.cpp | 402 ++ .../src/lib/highlightingdata_p.hpp | 215 + .../src/lib/keywordlist_p.h | 10 +- .../syntax-highlighting/src/lib/rule.cpp | 466 +-- .../syntax-highlighting/src/lib/rule_p.h | 164 +- .../src/lib/wildcardmatcher.cpp | 1 - .../src/lib/worddelimiters.cpp | 9 +- .../src/lib/worddelimiters_p.h | 4 +- 37 files changed, 7284 insertions(+), 1440 deletions(-) create mode 100644 src/libs/3rdparty/syntax-highlighting/src/lib/highlightingdata.cpp create mode 100644 src/libs/3rdparty/syntax-highlighting/src/lib/highlightingdata_p.hpp diff --git a/src/libs/3rdparty/syntax-highlighting/CMakeLists.txt b/src/libs/3rdparty/syntax-highlighting/CMakeLists.txt index a8f5980862e..4d352af3d65 100644 --- a/src/libs/3rdparty/syntax-highlighting/CMakeLists.txt +++ b/src/libs/3rdparty/syntax-highlighting/CMakeLists.txt @@ -29,6 +29,7 @@ add_qtc_library(KSyntaxHighlighting SHARED src/lib/foldingregion.cpp src/lib/foldingregion.h src/lib/format.cpp src/lib/format.h src/lib/format_p.h src/lib/htmlhighlighter.cpp src/lib/htmlhighlighter.h + src/lib/highlightingdata.cpp src/lib/highlightingdata_p.hpp src/lib/keywordlist.cpp src/lib/keywordlist_p.h src/lib/matchresult_p.h src/lib/repository.cpp src/lib/repository.h src/lib/repository_p.h diff --git a/src/libs/3rdparty/syntax-highlighting/autogenerated/ksyntaxhighlighting_version.h b/src/libs/3rdparty/syntax-highlighting/autogenerated/ksyntaxhighlighting_version.h index a8c5d74235a..4336b19ce5d 100644 --- a/src/libs/3rdparty/syntax-highlighting/autogenerated/ksyntaxhighlighting_version.h +++ b/src/libs/3rdparty/syntax-highlighting/autogenerated/ksyntaxhighlighting_version.h @@ -3,10 +3,10 @@ #ifndef SyntaxHighlighting_VERSION_H #define SyntaxHighlighting_VERSION_H -#define SyntaxHighlighting_VERSION_STRING "5.87.0" +#define SyntaxHighlighting_VERSION_STRING "5.90.0" #define SyntaxHighlighting_VERSION_MAJOR 5 -#define SyntaxHighlighting_VERSION_MINOR 87 +#define SyntaxHighlighting_VERSION_MINOR 90 #define SyntaxHighlighting_VERSION_PATCH 0 -#define SyntaxHighlighting_VERSION ((5<<16)|(87<<8)|(0)) +#define SyntaxHighlighting_VERSION ((5<<16)|(90<<8)|(0)) #endif diff --git a/src/libs/3rdparty/syntax-highlighting/autogenerated/src/lib/ksyntaxhighlighting_export.h b/src/libs/3rdparty/syntax-highlighting/autogenerated/src/lib/ksyntaxhighlighting_export.h index 1213499635c..25fb987a978 100644 --- a/src/libs/3rdparty/syntax-highlighting/autogenerated/src/lib/ksyntaxhighlighting_export.h +++ b/src/libs/3rdparty/syntax-highlighting/autogenerated/src/lib/ksyntaxhighlighting_export.h @@ -88,7 +88,7 @@ #define KSYNTAXHIGHLIGHTING_BUILD_DEPRECATED_SINCE(major, minor) 1 #ifdef KSYNTAXHIGHLIGHTING_NO_DEPRECATED -# define KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT 0x55700 +# define KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT 0x55a00 #endif #ifdef KSYNTAXHIGHLIGHTING_NO_DEPRECATED_WARNINGS # define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE 0 @@ -98,7 +98,7 @@ # ifdef KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT # define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT # else -# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE 0x55700 +# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE 0x55a00 # endif #endif @@ -178,7 +178,7 @@ #define KSYNTAXHIGHLIGHTING_BUILD_DEPRECATED_SINCE(major, minor) 1 #ifdef KSYNTAXHIGHLIGHTING_NO_DEPRECATED -# define KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT 0x55700 +# define KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT 0x55a00 #endif #ifdef KSYNTAXHIGHLIGHTING_NO_DEPRECATED_WARNINGS # define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE 0 @@ -188,7 +188,7 @@ # ifdef KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT # define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT # else -# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE 0x55700 +# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE 0x55a00 # endif #endif diff --git a/src/libs/3rdparty/syntax-highlighting/data/CMakeLists.txt b/src/libs/3rdparty/syntax-highlighting/data/CMakeLists.txt index acc2429ec84..6e86a05e9e3 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/CMakeLists.txt +++ b/src/libs/3rdparty/syntax-highlighting/data/CMakeLists.txt @@ -64,7 +64,7 @@ if (QRC_SYNTAX) # generate the qrc file manually, to make dependencies on generated files work... add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/qrc_syntax-data.cpp" - COMMAND ${Qt5Core_RCC_EXECUTABLE} --name syntax_data -o "${CMAKE_CURRENT_BINARY_DIR}/qrc_syntax-data.cpp" "${CMAKE_CURRENT_BINARY_DIR}/syntax-data.qrc" + COMMAND Qt${QT_MAJOR_VERSION}::rcc --name syntax_data -o "${CMAKE_CURRENT_BINARY_DIR}/qrc_syntax-data.cpp" "${CMAKE_CURRENT_BINARY_DIR}/syntax-data.qrc" DEPENDS ${defs} ${CMAKE_CURRENT_BINARY_DIR}/index.katesyntax ) set_source_files_properties("${CMAKE_CURRENT_BINARY_DIR}/qrc_syntax-data.cpp" PROPERTIES SKIP_AUTOMOC ON) @@ -79,5 +79,5 @@ endif() # this needs some more recent CMake than generally required set_property(TARGET SyntaxHighlightingData PROPERTY POSITION_INDEPENDENT_CODE 1) if(NOT ${CMAKE_VERSION} VERSION_LESS "3.13.0") - target_link_libraries(SyntaxHighlightingData PRIVATE Qt5::Core) + target_link_libraries(SyntaxHighlightingData PRIVATE Qt${QT_MAJOR_VERSION}::Core) endif() diff --git a/src/libs/3rdparty/syntax-highlighting/data/generators/cmake.xml.tpl b/src/libs/3rdparty/syntax-highlighting/data/generators/cmake.xml.tpl index 1c1a3da4ba2..45057a8a054 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/generators/cmake.xml.tpl +++ b/src/libs/3rdparty/syntax-highlighting/data/generators/cmake.xml.tpl @@ -1,7 +1,10 @@ + + + + ]> - + + + @@ -54,6 +59,9 @@ + + + @@ -87,6 +95,24 @@ + + + + + + + + + + + + + + + + + + @@ -94,25 +120,68 @@ beginRegion="" endRegion="" /> + + + - - - + + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + @@ -132,9 +201,21 @@ + + + + + + + + + + + + - + @@ -153,33 +234,27 @@ - + + + - + + - - - - - - - - - - + - + @@ -198,7 +273,7 @@ - + @@ -229,6 +304,15 @@ + + + + + + + + + @@ -261,12 +345,12 @@ - - + + - + @@ -330,9 +414,12 @@ + + + @@ -351,8 +438,10 @@ - + + + @@ -360,7 +449,7 @@ - + diff --git a/src/libs/3rdparty/syntax-highlighting/data/generators/cmake.yaml b/src/libs/3rdparty/syntax-highlighting/data/generators/cmake.yaml index ab26c2153b3..f5437900627 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/generators/cmake.yaml +++ b/src/libs/3rdparty/syntax-highlighting/data/generators/cmake.yaml @@ -1,4 +1,4 @@ -version: 34 +version: 37 global-properties: - ALLOW_DUPLICATE_CUSTOM_TARGETS @@ -415,6 +415,7 @@ test-properties: - DEPENDS - DISABLED - ENVIRONMENT + - ENVIRONMENT_MODIFICATION # Since 3.22 - FAIL_REGULAR_EXPRESSION - FIXTURES_CLEANUP - FIXTURES_REQUIRED @@ -790,6 +791,7 @@ variables: - CMAKE_PROJECT_INCLUDE # Since 3.15 - CMAKE_PROJECT_INCLUDE_BEFORE # Since 3.15 - CMAKE_PROJECT__INCLUDE + - CMAKE_REQUIRE_FIND_PACKAGE_ # Since 3.22 - CMAKE_SKIP_INSTALL_ALL_DEPENDENCY - CMAKE_STAGING_PREFIX - CMAKE_SUBLIME_TEXT_2_ENV_SETTINGS @@ -967,6 +969,7 @@ variables: - CMAKE__LINKER_LAUNCHER # Sine 3.21 - CMAKE__LINK_LIBRARY_FILE_FLAG # Sine 3.16 - CMAKE__LINK_LIBRARY_FLAG # Sine 3.16 + - CMAKE__LINK_WHAT_YOU_USE_FLAG # Since 3.22 - CMAKE__VISIBILITY_PRESET - CMAKE_LIBRARY_OUTPUT_DIRECTORY - CMAKE_LIBRARY_OUTPUT_DIRECTORY_ @@ -977,6 +980,7 @@ variables: - CMAKE_LINK_LIBRARY_FILE_FLAG - CMAKE_LINK_LIBRARY_FLAG - CMAKE_LINK_WHAT_YOU_USE + - CMAKE_LINK_WHAT_YOU_USE_CHECK # Since 3.22 - CMAKE_MACOSX_BUNDLE - CMAKE_MACOSX_RPATH - CMAKE_MAP_IMPORTED_CONFIG_ @@ -1055,6 +1059,10 @@ variables: - CMAKE_Fortran_MODDIR_DEFAULT - CMAKE_Fortran_MODDIR_FLAG - CMAKE_Fortran_MODOUT_FLAG + - CMAKE_HIP_ARCHITECTURES # Since 3.21 + - CMAKE_HIP_EXTENSIONS # Since 3.21 + - CMAKE_HIP_STANDARD # Since 3.21 + - CMAKE_HIP_STANDARD_REQUIRED # Since 3.21 - CMAKE_ISPC_HEADER_DIRECTORY # Since 3.19 - CMAKE_ISPC_HEADER_SUFFIX # Since 3.19.2 - CMAKE_ISPC_INSTRUCTION_SETS # Since 3.19 @@ -1075,6 +1083,8 @@ variables: - CMAKE__CREATE_SHARED_LIBRARY - CMAKE__CREATE_SHARED_MODULE - CMAKE__CREATE_STATIC_LIBRARY + - CMAKE__EXTENSIONS + - CMAKE__EXTENSIONS_DEFAULT # Since 3.22 - CMAKE__FLAGS - CMAKE__FLAGS_DEBUG - CMAKE__FLAGS_DEBUG_INIT @@ -1269,7 +1279,14 @@ variables: - CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM - CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL - CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND + # Fallback Interface Variables for `cmake_host_system_information` + # Since CMake 3.22 + - CMAKE_GET_OS_RELEASE_FALLBACK_SCRIPTS + - CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_ + - CMAKE_GET_OS_RELEASE_FALLBACK_RESULT # Well known CMake's official module's variables + # - BundleUtilities + - BU_CHMOD_BUNDLE_ITEMS # - CheckCompilerFlag # - CheckCCompilerFlag # - CheckSourceCompiles @@ -1289,6 +1306,13 @@ variables: # - CheckIncludeFile # - CheckIncludeFiles # - CheckLibraryExists + # - CheckPIESupported + - CMAKE_C_LINK_PIE_SUPPORTED + - CMAKE_CXX_LINK_PIE_SUPPORTED + - CMAKE_Fortran_LINK_PIE_SUPPORTED + - CMAKE_C_LINK_NO_PIE_SUPPORTED + - CMAKE_CXX_LINK_NO_PIE_SUPPORTED + - CMAKE_Fortran_LINK_NO_PIE_SUPPORTED # - CheckPrototypeDefinition # - CheckStructHasMember # - CheckSymbolExists @@ -1498,6 +1522,7 @@ variables: - CPACK_NSIS_BRANDING_TEXT # Since 3.20 - CPACK_NSIS_BRANDING_TEXT_TRIM_POSITION # Since 3.20 - CPACK_NSIS_EXECUTABLE # Since 3.21 + - CPACK_NSIS_IGNORE_LICENSE_PAGE # Since 3.22 # - CPackNuGet (since 3.12) - CPACK_NUGET_COMPONENT_INSTALL - CPACK_NUGET_PACKAGE_NAME @@ -1655,6 +1680,7 @@ variables: - CPACK_RPM_SOURCE_PKG_BUILD_PARAMS - CPACK_RPM_SOURCE_PKG_PACKAGING_INSTALL_PREFIX - CPACK_RPM_BUILDREQUIRES + - CPACK_RPM_REQUIRES_EXCLUDE_FROM # Since 3.22 # - CPack - CPACK_PACKAGE_NAME - CPACK_PACKAGE_VENDOR @@ -1746,18 +1772,552 @@ variables: - ExternalData_CUSTOM_LOCATION - ExternalData_CUSTOM_FILE - ExternalData_CUSTOM_ERROR + # - FetchContent + - FETCHCONTENT_QUIET + - FETCHCONTENT_FULLY_DISCONNECTED + - FETCHCONTENT_UPDATES_DISCONNECTED + - FETCHCONTENT_SOURCE_DIR_ + - FETCHCONTENT_UPDATES_DISCONNECTED_ # - FindXXX module "standard" variables - _INCLUDE_DIRS - _LIBRARIES - _LIBRARY_DIRS - _VERSION_STRING + # NOTE For the other stanfard finders below variables matched + # the regular expressions above gonna be omitted. + # - FindALSA + - ALSA_LIBRARY + # - FindArmadillo + - ALSA_LIBRARY + # - FindASPELL + - ASPELL_EXECUTABLE + - ASPELL_DEFINITIONS + # - FindAVIFile + - AVIFILE_DEFINITIONS + # - FindBacktrace + - Backtrace_HEADER + - Backtrace_LIBRARY + # - FindBISON + - BISON_EXECUTABLE + - BISON__DEFINED + - BISON__INPUT + - BISON__OUTPUT_SOURCE + - BISON__OUTPUT_HEADER + - BISON__OUTPUTS + - BISON__COMPILE_FLAGS + # - FindBLAS + - BLA_STATIC + - BLA_VENDOR + - BLA_F95 + - BLA_PREFER_PKGCONFIG + - BLAS_LINKER_FLAGS + - BLA_SIZEOF_INTEGER # Since 3.22 + # - FindBoost + - Boost__LIBRARY + - Boost_VERSION_MACRO + - Boost_VERSION_COUNT + - Boost_INCLUDE_DIR + - Boost_LIBRARY_DIR_DEBUG + - Boost_LIBRARY_DIR_RELEASE + - Boost__LIBRARY_DEBUG + - Boost__LIBRARY_RELEASE + - BOOSTROOT + - BOOST_INCLUDEDIR + - BOOST_LIBRARYDIR + - Boost_NO_SYSTEM_PATHS + - Boost_ADDITIONAL_VERSIONS + - Boost_USE_DEBUG_LIBS + - Boost_USE_RELEASE_LIBS + - Boost_USE_MULTITHREADED + - Boost_USE_STATIC_LIBS + - Boost_USE_DEBUG_RUNTIME + - Boost_USE_DEBUG_PYTHON + - Boost_USE_STLPORT + - Boost_USE_STLPORT_DEPRECATED_NATIVE_IOSTREAMS + - Boost_COMPILER + - Boost_LIB_PREFIX + - Boost_ARCHITECTURE + - Boost_THREADAPI + - Boost_NAMESPACE + - Boost_DEBUG + - Boost_REALPATH + - Boost_NO_WARN_NEW_VERSIONS + # - FindBullet + # - FindBZip2 + - BZIP2_NEED_PREFIX + - BZIP2_INCLUDE_DIR + # - FindCABLE + - CABLE + - CABLE_TCL_LIBRARY + - CABLE_INCLUDE_DIR + # - FindCoin3D + # - FindCUDAToolkit + - CUDAToolkit_NVCC_EXECUTABLE + # - FindCups + - CUPS_INCLUDE_DIR + # - FindCURL + - CURL_NO_CURL_CMAKE + # - FindCurses + - CURSES_CFLAGS + - CURSES_HAVE_CURSES_H + - CURSES_HAVE_NCURSES_H + - CURSES_HAVE_NCURSES_NCURSES_H + - CURSES_HAVE_NCURSES_CURSES_H + - CURSES_NEED_NCURSES + - CURSES_NEED_WIDE + # - CURSES_LIBRARY deprecated + # - FindCVS + - CVS_EXECUTABLE + # - FindCxxTest + - CXXTEST_USE_PYTHON + - CXXTEST_TESTGEN_ARGS + - CXXTEST_PERL_TESTGEN_EXECUTABLE + - CXXTEST_PYTHON_TESTGEN_EXECUTABLE + - CXXTEST_TESTGEN_EXECUTABLE + - CXXTEST_TESTGEN_INTERPRETER + # - FindCygwin + # - FindDart + # - FindDCMTK + # - FindDevIL # - FindDoxygen - DOXYGEN_ + # - FindEnvModules + - EnvModules_COMMAND + # - FindEXPAT + # - FindFLEX + - FLEX_EXECUTABLE + # - FindFLTK + - FLTK_SKIP_OPENGL + - FLTK_SKIP_FORMS + - FLTK_SKIP_IMAGES + - FLTK_SKIP_FLUID + - FLTK_FLUID_EXECUTABLE + - FLTK_WRAP_UI + - FLTK_BASE_LIBRARY_RELEASE + - FLTK_BASE_LIBRARY_DEBUG + - FLTK_GL_LIBRARY_RELEASE + - FLTK_GL_LIBRARY_DEBUG + - FLTK_FORMS_LIBRARY_RELEASE + - FLTK_FORMS_LIBRARY_DEBUG + - FLTK_IMAGES_LIBRARY_RELEASE + - FLTK_IMAGES_LIBRARY_DEBUG + # - FindFLTK2 + - FLTK2_FLUID_EXECUTABLE + - FLTK2_WRAP_UI + - FLTK2_BASE_LIBRARY + - FLTK2_GL_LIBRARY + - FLTK2_IMAGES_LIBRARY + # - FindFontconfig + - Fontconfig_COMPILE_OPTIONS + # - FindFreetype + - FREETYPE_INCLUDE_DIR_ft2build + - FREETYPE_INCLUDE_DIR_freetype2 + # - FindGCCXML + - GCCXML + # - FindGDAL + - GDAL_LIBRARY + - FindGDAL_SKIP_GDAL_CONFIG + - GDAL_ADDITIONAL_LIBRARY_VERSIONS + # - FindGettext + - GETTEXT_MSGMERGE_EXECUTABLE + - GETTEXT_MSGFMT_EXECUTABLE + # - FindGIF + - GIF_LIBRARY + # - FindGit + - GIT_EXECUTABLE + # - FindGLEW + - GLEW_USE_STATIC_LIBS + - GLEW_VERBOSE + # - FindGLUT + - GLUT_glut_LIBRARY + - GLUT_Xmu_LIBRARY + - GLUT_Xi_LIBRARY + # - FindGnuplot + - GNUPLOT_EXECUTABLE + # - FindGnuTLS + - GNUTLS_DEFINITIONS + # - FindGSL + - GSL_CBLAS_LIBRARY + - GSL_CBLAS_LIBRARY_DEBUG + - GSL_CONFIG_EXECUTABLE + - GSL_LIBRARY + - GSL_LIBRARY_DEBUG + # - FindGTest + - GTEST_MSVC_SEARCH + # - FindGTK + # - FindGTK2 + - GTK2_TARGETS + - GTK2_DEFINITIONS + - GTK2_USE_IMPORTED_TARGETS + - GTK2_DEBUG + - GTK2_ADDITIONAL_SUFFIXES + # - FindHDF5 + - HDF5_DEFINITIONS + - HDF5_C_DEFINITIONS + - HDF5_CXX_DEFINITIONS + - HDF5_Fortran_DEFINITIONS + - HDF5_IS_PARALLEL + - HDF5_C_COMPILER_EXECUTABLE + - HDF5_CXX_COMPILER_EXECUTABLE + - HDF5_Fortran_COMPILER_EXECUTABLE + - HDF5_C_COMPILER_EXECUTABLE_NO_INTERROGATE + - HDF5_CXX_COMPILER_EXECUTABLE_NO_INTERROGATE + - HDF5_Fortran_COMPILER_EXECUTABLE_NO_INTERROGATE + - HDF5_DIFF_EXECUTABLE + - HDF5_PREFER_PARALLEL + - HDF5_FIND_DEBUG + - HDF5_NO_FIND_PACKAGE_CONFIG_FILE + # - FindHg + - HG_EXECUTABLE + #- _WC_CHANGESET + #- _WC_REVISION + # - FindHSPELL + # - FindHTMLHelp + - HTML_HELP_COMPILER + - HTML_HELP_LIBRARY + # - FindIce + # - FindIconv + - Iconv_IS_BUILT_IN + - Iconv_LIBRARY + # - FindIcotool + - ICOTOOL_EXECUTABLE + # - FindICU + - ICU_MAKEFILE_INC + - ICU_PKGDATA_INC + - ICU_

_EXECUTABLE + - ICU__LIBRARY + - ICU_DEBUG + # - FindImageMagick + # - FindIntl + - Intl_LIBRARY + - Intl_IS_BUILT_IN + # - FindITK + # - FindJasper + - JASPER_LIBRARY_RELEASE + - JASPER_LIBARRY_DEBUG + # - FindJava + - Java_JAVA_EXECUTABLE + - Java_JAVAC_EXECUTABLE + - Java_JAVAH_EXECUTABLE + - Java_JAVADOC_EXECUTABLE + - Java_IDLJ_EXECUTABLE + - Java_JAR_EXECUTABLE + - Java_JARSIGNER_EXECUTABLE + # - FindJNI + - JAVA_AWT_LIBRARY + - JAVA_JVM_LIBRARY + - JAVA_INCLUDE_PATH + - JAVA_INCLUDE_PATH2 + - JAVA_AWT_INCLUDE_PATH + # - FindJPEG + - JPEG_LIBRARY_RELEASE + - JPEG_LIBRARY_DEBUG + - JPEG_LIBRARY + # - FindKDE3 + # - FindKDE4 + # - FindLAPACK + - LAPACK_LINKER_FLAGS + # - FindLATEX + - LATEX_COMPILER + - PDFLATEX_COMPILER + - XELATEX_COMPILER + - LUALATEX_COMPILER + - BIBTEX_COMPILER + - BIBER_COMPILER + - MAKEINDEX_COMPILER + - XINDY_COMPILER + - DVIPS_CONVERTER + - DVIPDF_CONVERTER + - PS2PDF_CONVERTER + - PDFTOPS_CONVERTER + - LATEX2HTML_CONVERTER + - HTLATEX_COMPILER + # - FindLibArchive + # - FindLibinput + - Libinput_COMPILE_OPTIONS + # - FindLibLZMA + - LIBLZMA_HAS_AUTO_DECODER + - LIBLZMA_HAS_EASY_ENCODER + - LIBLZMA_HAS_LZMA_PRESET + # - FindLibXml2 + - LIBXML2_DEFINITIONS + - LIBXML2_XMLLINT_EXECUTABLE + - LIBXML2_LIBRARY + # - FindLibXslt + - LIBXSLT_DEFINITIONS + - LIBXSLT_XSLTPROC_EXECUTABLE + # - FindLTTngUST + - LTTNGUST_HAS_TRACEF + - LTTNGUST_HAS_TRACELOG + # - FindLua + # - FindLua50 + # - FindLua51 + # - FindMatlab + - MATLAB_FIND_DEBUG + - MATLAB_ADDITIONAL_VERSIONS + - Matlab_MAIN_PROGRAM + - Matlab_MEX_LIBRARY + - Matlab_MX_LIBRARY + - Matlab_ENG_LIBRARY + - Matlab_MAT_LIBRARY + - Matlab_ENGINE_LIBRARY + - Matlab_DATAARRAY_LIBRARY + - Matlab_MEX_COMPILER + - Matlab_MCC_COMPILER + - Matlab_MEX_EXTENSION + # - FindMFC + # - FindMotif + # - FindMPEG + - MPEG_mpeg2_LIBRARY + - MPEG_vo_LIBRARY + # - FindMPEG2 + - MPEG2_mpeg2_LIBRARY + - MPEG2_vo_LIBRARY + # - FindMPI + - MPI__COMPILER + - MPI__COMPILE_OPTIONS + - MPI__COMPILE_DEFINITIONS + - MPI_Fortran_HAVE_F77_HEADER + - MPI_Fortran_HAVE_F90_MODULE + - MPI_Fortran_HAVE_F08_MODULE + - MPIEXEC_EXECUTABLE + - MPIEXEC_NUMPROC_FLAG + - MPIEXEC_MAX_NUMPROCS + - MPIEXEC_PREFLAGS + - MPIEXEC_POSTFLAGS + - MPIEXEC_EXECUTABLE + - MPI_HOME + - MPI_COMPILER_FLAGS + - MPI_EXECUTABLE_SUFFIX + - MPI_GUESS_LIBRARY_NAME + - MPI_ASSUME_NO_BUILTIN_MPI + - MPI_SKIP_COMPILER_WRAPPER + - MPI_SKIP_GUESSING + - MPI_CXX_SKIP_MPICXX + - MPI__ADDITIONAL_INCLUDE_VARS + - MPI__LIBRARY + - MPI__LIB_NAMES + - MPI_DETERMINE_Fortran_CAPABILITIES + - MPI_SUBARRAYS_SUPPORTED + - MPI_ASYNC_PROTECTS_NONBLOCKING + - MPI_Fortran_F77_HEADER_SUBARRAYS + - MPI_Fortran_F77_HEADER_ASYNCPROT + - MPI_Fortran_F90_MODULE_SUBARRAYS + - MPI_Fortran_F90_MODULE_ASYNCPROT + - MPI_Fortran_F08_MODULE_SUBARRAYS + - MPI_Fortran_F08_MODULE_ASYNCPROT + # - FindMsys + # - FindODBC + - ODBC_CONFIG + - ODBC_LIBRARY + # - FindOpenACC + - OpenACC__FLAGS + - OpenACC__OPTIONS + - OpenACC__SPEC_DATE + - OpenACC_ACCEL_TARGET + # - FindOpenAL + - OPENAL_LIBRARY + # - FindOpenCL + - OpenCL_LIBRARY + # - FindOpenGL + - OPENGL_egl_LIBRARY + - OPENGL_glu_LIBRARY + - OPENGL_glx_LIBRARY + - OPENGL_opengl_LIBRARY + - OPENGL_gl_LIBRARY + - OpenGL_GL_PREFERENCE + # - FindOpenMP + - OpenMP__FLAGS + - OpenMP__LIB_NAMES + - OpenMP__LIBRARY + - OpenMP_Fortran_HAVE_OMPLIB_HEADER + - OpenMP_Fortran_HAVE_OMPLIB_MODULE + - OpenMP__SPEC_DATE + # - FindOpenSceneGraph + # - FindOpenSSL + - OPENSSL_CRYPTO_LIBRARY + - OPENSSL_SSL_LIBRARY + - OPENSSL_APPLINK_SOURCE + - OPENSSL_USE_STATIC_LIBS + - OPENSSL_MSVC_STATIC_RT + # - FindOpenThreads + # - Findosg + # - Findosg_functions + # - FindosgAnimation + # - FindosgDB + # - FindosgFX + # - FindosgGA + # - FindosgIntrospection + # - FindosgManipulator + # - FindosgParticle + # - FindosgPresentation + # - FindosgProducer + # - FindosgQt + # - FindosgShadow + # - FindosgSim + # - FindosgTerrain + # - FindosgText + # - FindosgUtil + # - FindosgViewer + # - FindosgVolume + # - FindosgWidget + # - FindPatch + - Patch_EXECUTABLE + # - FindPerl + - PERL_EXECUTABLE + # - FindPerlLibs + - PERL_SITESEARCH + - PERL_SITEARCH + - PERL_SITELIB + - PERL_VENDORARCH + - PERL_VENDORLIB + - PERL_ARCHLIB + - PERL_PRIVLIB + - PERL_UPDATE_ARCHLIB + - PERL_UPDATE_PRIVLIB + - PERL_EXTRA_C_FLAGS + # - FindPHP4 + - PHP4_INCLUDE_PATH + - PHP4_EXECUTABLE + # - FindPhysFS + - PHYSFS_LIBRARY + # - FindPike + - PIKE_INCLUDE_PATH + - PIKE_EXECUTABLE # - FindPkgConfig - PKG_CONFIG_EXECUTABLE - PKG_CONFIG_VERSION_STRING - PKG_CONFIG_USE_CMAKE_PREFIX_PATH - _MODULE_NAME # Since 3.16 + # - FindPNG + - PNG_DEFINITIONS + - PNG_LIBRARY + # - FindPostgreSQL + # - FindProducer + # - FindProtobuf + - Protobuf_SRC_ROOT_FOLDER + - Protobuf_IMPORT_DIRS + - Protobuf_DEBUG + - Protobuf_USE_STATIC_LIBS + - Protobuf_LIBRARY + - Protobuf_PROTOC_LIBRARY + - Protobuf_PROTOC_EXECUTABLE + - Protobuf_LIBRARY_DEBUG + - Protobuf_PROTOC_LIBRARY_DEBUG + - Protobuf_LITE_LIBRARY + - Protobuf_LITE_LIBRARY_DEBUG + # - FindPython + - Python_EXECUTABLE + - Python_INTERPRETER_ID + - Python_STDLIB + - Python_STDARCH + - Python_SITELIB + - Python_SITEARCH + - Python_SOABI + - Python_COMPILER + - Python_COMPILER_ID + - Python_DOTNET_LAUNCHER + - Python_LINK_OPTIONS + - Python_USE_STATIC_LIBS + - Python_FIND_ABI + - Python_FIND_STRATEGY + - Python_FIND_REGISTRY + - Python_FIND_FRAMEWORK + - Python_FIND_VIRTUALENV + - Python_FIND_IMPLEMENTATIONS + - Python_FIND_UNVERSIONED_NAMES + - Python_ARTIFACTS_INTERACTIVE + # - FindPython2 + - Python2_EXECUTABLE + - Python2_INTERPRETER_ID + - Python2_STDLIB + - Python2_STDARCH + - Python2_SITELIB + - Python2_SITEARCH + - Python2_SOABI + - Python2_COMPILER + - Python2_COMPILER_ID + - Python2_DOTNET_LAUNCHER + - Python2_LINK_OPTIONS + - Python2_USE_STATIC_LIBS + - Python2_FIND_ABI + - Python2_FIND_STRATEGY + - Python2_FIND_REGISTRY + - Python2_FIND_FRAMEWORK + - Python2_FIND_VIRTUALENV + - Python2_FIND_IMPLEMENTATIONS + - Python2_FIND_UNVERSIONED_NAMES + - Python2_ARTIFACTS_INTERACTIVE + # - FindPython3 + - Python3_EXECUTABLE + - Python3_INTERPRETER_ID + - Python3_STDLIB + - Python3_STDARCH + - Python3_SITELIB + - Python3_SITEARCH + - Python3_SOABI + - Python3_COMPILER + - Python3_COMPILER_ID + - Python3_DOTNET_LAUNCHER + - Python3_LINK_OPTIONS + - Python3_USE_STATIC_LIBS + - Python3_FIND_ABI + - Python3_FIND_STRATEGY + - Python3_FIND_REGISTRY + - Python3_FIND_FRAMEWORK + - Python3_FIND_VIRTUALENV + - Python3_FIND_IMPLEMENTATIONS + - Python3_FIND_UNVERSIONED_NAMES + - Python3_ARTIFACTS_INTERACTIVE + # - FindQt3 + # - FindQt4 + # - FindQuickTime + # - FindRTI + - RTI_DEFINITIONS + # - FindRuby + - Ruby_EXECUTABLE + - Ruby_FIND_VIRTUALENV + # - FindSDL + - SDL_LIBRARY + - SDL_BUILDING_LIBRARY + # - FindSDL_image + - SDLIMAGE_LIBRARY + # - FindSDL_mixer + - SDLMIXER_LIBRARY + # - FindSDL_net + - SDLNET_LIBRARY + # - FindSDL_sound + - SDL_SOUND_LIBRARY + # - FindSDL_ttf + - SDLTTF_LIBRARY + # - FindSelfPackers + # - FindSquish + - SQUISH_SERVER_EXECUTABLE + - SQUISH_CLIENT_EXECUTABLE + # - FindSQLite3 + # - FindSubversion + - Subversion_SVN_EXECUTABLE + - Subversion_VERSION_SVN + # _WC_URL + # _WC_ROOT + # _WC_REVISION + # _WC_LAST_CHANGED_AUTHOR + # _WC_LAST_CHANGED_DATE + # _WC_LAST_CHANGED_REV + # _WC_INFO + # - FindSWIG + - SWIG_EXECUTABLE + # - FindTCL + - TCL_INCLUDE_PATH + - TCL_TCLSH + - TK_LIBRARY + - TK_INCLUDE_PATH + - TK_WISH + # - FindTclsh + # - FindTclStub + - TCL_STUB_LIBRARY + - TK_STUB_LIBRARY + - TTK_STUB_LIBRARY # - FindThreads - CMAKE_THREAD_LIBS_INIT - CMAKE_USE_SPROC_INIT @@ -1766,6 +2326,62 @@ variables: - CMAKE_HP_PTHREADS_INIT - CMAKE_THREAD_PREFER_PTHREAD - THREADS_PREFER_PTHREAD_FLAG + # - FindTIFF + - TIFF_LIBRARY_RELEASE + - TIFF_LIBRARY_DEBUG + - TIFFXX_LIBRARY_RELEASE + - TIFFXX_LIBRARY_DEBUG + # - FindUnixCommands + # - FindVTK + # - FindVulkan + - Vulkan_LIBRARY + - Vulkan_GLSLC_EXECUTABLE + - Vulkan_GLSLANG_VALIDATOR_EXECUTABLE + # - FindWget + - WGET_EXECUTABLE + # - FindWish + # - FindwxWidgets + - wxWidgets_CONFIGURATION + - wxWidgets_EXCLUDE_COMMON_LIBRARIES + - wxWidgets_USE_DEBUG + - wxWidgets_USE_UNICODE + - wxWidgets_USE_UNIVERSAL + - wxWidgets_USE_STATIC + - wxWidgets_DEFINITIONS + - wxWidgets_DEFINITIONS_DEBUG + - wxWidgets_CXX_FLAGS + - wxWidgets_USE_FILE + # - FindX11 + # - FindXalanC + - XalanC_LIBRARY + # - FindXCTest + - XCTest_EXECUTABLE + # - FindXercesC + - XercesC_LIBRARY + # - FindXMLRPC + # - FindZLIB + # - FortranCInterface + # The following vars gonna match by regex + # - FortranCInterface_GLOBAL_FOUND + # - FortranCInterface_MODULE_FOUND + - FortranCInterface_GLOBAL_PREFIX + - FortranCInterface_GLOBAL_SUFFIX + - FortranCInterface_GLOBAL_CASE + - FortranCInterface_GLOBAL__PREFIX + - FortranCInterface_GLOBAL__SUFFIX + - FortranCInterface_GLOBAL__CASE + - FortranCInterface_MODULE_PREFIX + - FortranCInterface_MODULE_MIDDLE + - FortranCInterface_MODULE_SUFFIX + - FortranCInterface_MODULE_CASE + - FortranCInterface_MODULE__PREFIX + - FortranCInterface_MODULE__MIDDLE + - FortranCInterface_MODULE__SUFFIX + - FortranCInterface_MODULE__CASE + - FortranCInterface_VERIFIED_C + - FortranCInterface_VERIFIED_CXX + - FortranCInterface_GLOBAL_SYMBOLS + - FortranCInterface_MODULE_SYMBOLS # - GNUInstallDirs - CMAKE_INSTALL_BINDIR - CMAKE_INSTALL_FULL_BINDIR @@ -1799,6 +2415,8 @@ variables: - CMAKE_INSTALL_FULL_MANDIR - CMAKE_INSTALL_DOCDIR - CMAKE_INSTALL_FULL_DOCDIR + # - GoogleTest + - CMAKE_GTEST_DISCOVER_TESTS_DISCOVERY_MODE # - InstallRequiredSystemLibraries - CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS - CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP @@ -1866,12 +2484,15 @@ environment-variables: # Environment Variables that Control the Build - CMAKE_APPLE_SILICON_PROCESSOR # Since 3.19.2 - CMAKE_BUILD_PARALLEL_LEVEL + - CMAKE_BUILD_TYPE # Since 3.22 + - CMAKE_CONFIGURATION_TYPES # Since 3.22 - CMAKE_CONFIG_TYPE - CMAKE_EXPORT_COMPILE_COMMANDS # Since 3.17 - CMAKE_GENERATOR - CMAKE_GENERATOR_INSTANCE - CMAKE_GENERATOR_PLATFORM - CMAKE_GENERATOR_TOOLSET + - CMAKE_INSTALL_MODE # Since 3.22 - CMAKE__COMPILER_LAUNCHER # Since 3.17 - CMAKE_MSVCIDE_RUN_PATH - CMAKE_NO_VERBOSE @@ -1951,6 +2572,9 @@ scripting-commands: , OS_RELEASE , OS_VERSION , OS_PLATFORM + # Since 3.22 + , DISTRIB_INFO + , DISTRIB_ ] - name: cmake_language @@ -2075,6 +2699,7 @@ scripting-commands: , IN_LIST , DEFINED ] + has-target-name-after-kw: TARGET nested-parentheses?: true - name: else @@ -2460,6 +3085,7 @@ scripting-commands: - name: if named-args: *if + has-target-name-after-kw: TARGET nested-parentheses?: true start-region: if - @@ -2671,6 +3297,7 @@ scripting-commands: - name: while named-args: *if + has-target-name-after-kw: TARGET nested-parentheses?: true start-region: while @@ -2703,6 +3330,7 @@ project-commands: , POST_BUILD ] nested-parentheses?: true + has-target-name-after-kw: TARGET - name: add_custom_target named-args: [ @@ -2721,17 +3349,22 @@ project-commands: , COMMAND_EXPAND_LISTS , SOURCES ] + first-arg-is-target?: true nested-parentheses?: true - name: add_definitions - name: add_dependencies + first-args-are-targets?: true - name: add_executable named-args: [WIN32, MACOSX_BUNDLE, EXCLUDE_FROM_ALL, IMPORTED, GLOBAL, ALIAS] + first-arg-is-target?: true - name: add_library named-args: [STATIC, SHARED, MODULE, OBJECT, EXCLUDE_FROM_ALL, IMPORTED, UNKNOWN, GLOBAL, ALIAS, INTERFACE] + first-arg-is-target?: true + has-target-name-after-kw: ALIAS - name: add_link_options - @@ -2750,6 +3383,7 @@ project-commands: , PARALLEL_LEVEL # Since 3.21 , TARGET ] + has-target-name-after-kw: TARGET - name: create_test_sourcelist named-args: [EXTRA_INCLUDE, FUNCTION] @@ -2760,7 +3394,7 @@ project-commands: - name: enable_language named-args: [OPTIONAL] - special-args: [ + special-args: &langs [ ASM , ASM-ATT , ASM_NASM @@ -2783,6 +3417,7 @@ project-commands: - name: export named-args: [EXPORT, NAMESPACE, FILE, TARGETS, APPEND, EXPORT_LINK_INTERFACE_LIBRARIES, ANDROID_MK] + has-target-names-after-kw: TARGETS - name: fltk_wrap_ui - @@ -2795,6 +3430,7 @@ project-commands: property-args: &get_source_file_property [source-properties] - name: get_target_property + second-arg-is-target?: true property-args: &get_target_property [target-properties] - name: get_test_property @@ -2882,6 +3518,7 @@ project-commands: , SETUID , SETGID ] + has-target-names-after-kw: TARGETS - name: link_directories named-args: [AFTER, BEFORE] @@ -2936,6 +3573,7 @@ project-commands: name: set_target_properties named-args: [PROPERTIES] property-args: *get_target_property + first-args-are-targets?: true # NOTE Multiple target args - name: set_tests_properties named-args: [PROPERTIES] @@ -2946,6 +3584,7 @@ project-commands: - name: target_compile_definitions named-args: &target_compile_definitions [INTERFACE, PUBLIC, PRIVATE] + first-arg-is-target?: true - name: target_compile_features named-args: *target_compile_definitions @@ -3032,9 +3671,11 @@ project-commands: , cuda_std_20 , cuda_std_23 # Since 3.21 ] + first-arg-is-target?: true - name: target_compile_options named-args: &target_compile_options [BEFORE, INTERFACE, PUBLIC, PRIVATE] + first-arg-is-target?: true - name: target_include_directories named-args: [ @@ -3045,23 +3686,29 @@ project-commands: , PUBLIC , PRIVATE ] + first-arg-is-target?: true - # Since 3.13 name: target_link_directories named-args: *target_compile_options + first-arg-is-target?: true - name: target_link_libraries named-args: *target_compile_definitions + first-arg-is-target?: true - name: target_link_options named-args: *target_compile_definitions + first-arg-is-target?: true - # Since 3.16 name: target_precompile_headers named-args: [INTERFACE, PUBLIC, PRIVATE, REUSE_FROM] + first-arg-is-target?: true - name: target_sources named-args: *target_compile_definitions + first-arg-is-target?: true - name: try_compile named-args: [ @@ -3191,3 +3838,1174 @@ ctest-commands: - name: ctest_upload named-args: [FILES, CAPTURE_CMAKE_ERROR, QUIET] + +modules: + # The modules listed here are part of the CMake distribution: + # https://cmake.org/cmake/help/latest/manual/cmake-modules.7.html + utility: + - AndroidTestUtilities + - BundleUtilities + - CheckCCompilerFlag + - CheckCompilerFlag + - CheckCSourceCompiles + - CheckCSourceRuns + - CheckCXXCompilerFlag + - CheckCXXSourceCompiles + - CheckCXXSourceRuns + - CheckCXXSymbolExists + - CheckFortranCompilerFlag + - CheckFortranFunctionExists + - CheckFortranSourceCompiles + - CheckFortranSourceRuns + - CheckFunctionExists + - CheckIncludeFileCXX + - CheckIncludeFile + - CheckIncludeFiles + - CheckIPOSupported + - CheckLanguage + - CheckLibraryExists + - CheckLinkerFlag + - CheckOBJCCompilerFlag + - CheckOBJCSourceCompiles + - CheckOBJCSourceRuns + - CheckOBJCXXCompilerFlag + - CheckOBJCXXSourceCompiles + - CheckOBJCXXSourceRuns + - CheckPIESupported + - CheckPrototypeDefinition + - CheckSourceCompiles + - CheckSourceRuns + - CheckStructHasMember + - CheckSymbolExists + - CheckTypeSize + - CheckVariableExists + - CMakeAddFortranSubdirectory + - CMakeBackwardCompatibilityCXX + - CMakeDependentOption + - CMakeFindDependencyMacro + - CMakeFindFrameworks + # NOTE The commented modules below are not for `include()` + # - CMakeFindPackageMode + # - CMakeGraphVizOptions + - CMakePackageConfigHelpers + - CMakePrintHelpers + - CMakePrintSystemInformation + - CMakePushCheckState + # NOTE The commented module below is not for `include()` + # - CMakeVerifyManifest + - CPack + - CPackComponent + - CPackIFW + - CPackIFWConfigureFile + - CSharpUtilities + - CTest + - CTestCoverageCollectGCOV + - CTestScriptMode + - CTestUseLaunchers + - Dart + - DeployQt4 + - ExternalData + - ExternalProject + - FeatureSummary + - FetchContent + - FindPackageHandleStandardArgs + - FindPackageMessage + - FortranCInterface + - GenerateExportHeader + - GNUInstallDirs + - GoogleTest + - InstallRequiredSystemLibraries + - ProcessorCount + - SelectLibraryConfigurations + # NOTE The commented module below is not for `include()` + # - SquishTestScript + - TestForANSIForScope + - TestForANSIStreamHeaders + - TestForSSTREAM + - TestForSTDNamespace + - UseEcos + - UseJava + - UseSWIG + - UsewxWidgets + + finder: + - FindALSA + - FindArmadillo + - FindASPELL + - FindAVIFile + - FindBacktrace + - FindBISON + - FindBLAS + - FindBoost + - FindBullet + - FindBZip2 + - FindCABLE + - FindCoin3D + - FindCUDAToolkit + - FindCups + - FindCURL + - FindCurses + - FindCVS + - FindCxxTest + - FindCygwin + - FindDart + - FindDCMTK + - FindDevIL + - FindDoxygen + - FindEnvModules + - FindEXPAT + - FindFLEX + - FindFLTK + - FindFLTK2 + - FindFontconfig + - FindFreetype + - FindGCCXML + - FindGDAL + - FindGettext + - FindGIF + - FindGit + - FindGLEW + - FindGLUT + - FindGnuplot + - FindGnuTLS + - FindGSL + - FindGTest + - FindGTK + - FindGTK2 + - FindHDF5 + - FindHg + - FindHSPELL + - FindHTMLHelp + - FindIce + - FindIconv + - FindIcotool + - FindICU + - FindImageMagick + - FindIntl + - FindITK + - FindJasper + - FindJava + - FindJNI + - FindJPEG + - FindKDE3 + - FindKDE4 + - FindLAPACK + - FindLATEX + - FindLibArchive + - FindLibinput + - FindLibLZMA + - FindLibXml2 + - FindLibXslt + - FindLTTngUST + - FindLua + - FindLua50 + - FindLua51 + - FindMatlab + - FindMFC + - FindMotif + - FindMPEG + - FindMPEG2 + - FindMPI + - FindMsys + - FindODBC + - FindOpenACC + - FindOpenAL + - FindOpenCL + - FindOpenGL + - FindOpenMP + - FindOpenSceneGraph + - FindOpenSSL + - FindOpenThreads + - Findosg + - Findosg_functions + - FindosgAnimation + - FindosgDB + - FindosgFX + - FindosgGA + - FindosgIntrospection + - FindosgManipulator + - FindosgParticle + - FindosgPresentation + - FindosgProducer + - FindosgQt + - FindosgShadow + - FindosgSim + - FindosgTerrain + - FindosgText + - FindosgUtil + - FindosgViewer + - FindosgVolume + - FindosgWidget + - FindPatch + - FindPerl + - FindPerlLibs + - FindPHP4 + - FindPhysFS + - FindPike + - FindPkgConfig + - FindPNG + - FindPostgreSQL + - FindProducer + - FindProtobuf + - FindPython + - FindPython2 + - FindPython3 + - FindQt3 + - FindQt4 + - FindQuickTime + - FindRTI + - FindRuby + - FindSDL + - FindSDL_image + - FindSDL_mixer + - FindSDL_net + - FindSDL_sound + - FindSDL_ttf + - FindSelfPackers + - FindSquish + - FindSQLite3 + - FindSubversion + - FindSWIG + - FindTCL + - FindTclsh + - FindTclStub + - FindThreads + - FindTIFF + - FindUnixCommands + - FindVTK + - FindVulkan + - FindWget + - FindWish + - FindwxWidgets + - FindX11 + - FindXalanC + - FindXCTest + - FindXercesC + - FindXMLRPC + - FindZLIB + + deprecated: + # Deprecated Utility Modules + - AddFileDependencies + - CMakeDetermineVSServicePack + - CMakeExpandImportedTargets + - CMakeForceCompiler + - CMakeParseArguments + - Documentation + - MacroAddFileDependencies + - TestCXXAcceptsFlag + - UseJavaClassFilelist + - UseJavaSymlinks + - UsePkgConfig + - Use_wxWindows + - WriteBasicConfigVersionFile + - WriteCompilerDetectionHeader + # Deprecated Find Modules + - FindCUDA + - FindPythonInterp + - FindPythonLibs + - FindQt + - FindwxWindows + # Legacy CPack Modules + - CPackArchive + - CPackBundle + - CPackCygwin + - CPackDeb + - CPackDMG + - CPackFreeBSD + - CPackNSIS + - CPackNuGet + - CPackPackageMaker + - CPackProductBuild + - CPackRPM + - CPackWIX + # ATTENTION The following modules still in the list of the standard modules + # however, the docs claims that they have been deprecated + - GetPrerequisites + - TestBigEndian + +standard-module-commands: + # AndroidTestUtilities + - + name: android_add_test_data + named-args: + - FILES + - FILES_DEST + - LIBS + - LIBS_DEST + - DEVICE_OBJECT_STORE + - DEVICE_TEST_DIR + - NO_LINK_REGEX + # BundleUtilities + - name: fixup_bundle + - name: copy_and_fixup_bundle + - name: verify_app + - name: get_bundle_main_executable + - name: get_dotapp_dir + - name: get_bundle_and_executable + - name: get_bundle_all_executables + - name: get_item_key + - name: get_item_rpaths + - name: clear_bundle_keys + - name: set_bundle_key_values + - name: get_bundle_keys + - name: copy_resolved_item_into_bundle + - name: copy_resolved_framework_into_bundle + - name: fixup_bundle_item + - name: verify_bundle_prerequisites + - name: verify_bundle_symlinks + # CheckCCompilerFlag + - name: check_c_compiler_flag + # CheckCompilerFlag + - name: check_compiler_flag + # CheckCSourceCompiles + - + name: check_c_source_compiles + named-args: &ccsc [FAIL_REGEX] + # CheckCSourceRuns + - name: check_c_source_runs + # CheckCXXCompilerFlag + - name: check_cxx_compiler_flag + # CheckCXXSourceCompiles + - + name: check_cxx_source_compiles + named-args: *ccsc + # CheckCXXSourceRuns + - name: check_cxx_source_runs + # CheckCXXSymbolExists + - name: check_cxx_symbol_exists + # CheckFortranCompilerFlag + - name: check_fortran_compiler_flag + # CheckFortranFunctionExists + - name: check_fortran_function_exists + # CheckFortranSourceCompiles + - + name: check_fortran_source_compiles + named-args: &frse [FAIL_REGEX, SRC_EXT] + # CheckFortranSourceRuns + - + name: check_fortran_source_runs + named-args: &se [SRC_EXT] + # CheckFunctionExists + - name: check_function_exists + # CheckIncludeFileCXX + - name: check_include_file_cxx + # CheckIncludeFile + - name: check_include_file + # CheckIncludeFiles + - + name: check_include_files + named-args: &l [LANGUAGE] + special-args: &ccxx [C, CXX] + # CheckIPOSupported + - + name: check_ipo_supported + named-args: [RESULT, OUTPUT, LANGUAGES] + special-args: &ccxxf [C, CXX, Fortran] + # CheckLanguage + - + name: check_language + special-args: *langs + # CheckLibraryExists + - name: check_library_exists + # CheckLinkerFlag + - name: check_linker_flag + # CheckOBJCCompilerFlag + - name: check_objc_compiler_flag + # CheckOBJCSourceCompiles + - + name: check_objc_source_compiles + named-args: *ccsc + # CheckOBJCSourceRuns + - name: check_objc_source_runs + # CheckOBJCXXCompilerFlag + - name: check_objcxx_compiler_flag + # CheckOBJCXXSourceCompiles + - + name: check_objcxx_source_compiles + named-args: *ccsc + # CheckOBJCXXSourceRuns + - name: check_objcxx_source_runs + # CheckPIESupported + - + name: check_pie_supported + named-args: [OUTPUT_VARIABLE, LANGUAGES] + special-args: *ccxxf + # CheckPrototypeDefinition + - name: check_prototype_definition + # CheckSourceCompiles + - + name: check_source_compiles + named-args: *frse + # CheckSourceRuns + - + name: check_source_runs + named-args: *se + # CheckStructHasMember + - + name: check_struct_has_member + named-args: *l + special-args: *ccxx + # CheckSymbolExists + - name: check_symbol_exists + # CheckTypeSize + - + name: check_type_size + named-args: [BUILTIN_TYPES_ONLY, LANGUAGE] + special-args: *ccxx + # CheckVariableExists + - name: check_variable_exists + # CMakeAddFortranSubdirectory + - + name: cmake_add_fortran_subdirectory + named-args: + - PROJECT + - ARCHIVE_DIR + - RUNTIME_DIR + - LIBRARIES + - LINK_LIBRARIES + - LINK_LIBS + - CMAKE_COMMAND_LINE + - NO_EXTERNAL_INSTALL + # CMakeBackwardCompatibilityCXX + # CMakeDependentOption + - name: cmake_dependent_option + # CMakeFindDependencyMacro + - name: find_dependency + # CMakeFindFrameworks + # CMakeFindPackageMode + # CMakeGraphVizOptions + # CMakePackageConfigHelpers + - + name: configure_package_config_file + named-args: + - INSTALL_DESTINATION + - PATH_VARS + - NO_SET_AND_CHECK_MACRO + - NO_CHECK_REQUIRED_COMPONENTS_MACRO + - INSTALL_PREFIX + - + name: write_basic_package_version_file + named-args: + - VERSION + - COMPATIBILITY + - ARCH_INDEPENDENT + special-args: [AnyNewerVersion, SameMajorVersion, SameMinorVersion, ExactVersion] + # CMakePrintHelpers + - + name: cmake_print_properties + named-args: + - TARGETS + - SOURCES + - DIRECTORIES + - TESTS + - CACHE_ENTRIES + - PROPERTIES + has-target-names-after-kw: TARGETS + # CMakePrintSystemInformation + # CMakePushCheckState + - + name: cmake_push_check_state + named-args: [RESET] + - name: cmake_pop_check_state + - name: cmake_reset_check_state + # CMakeVerifyManifest + # CPack + # CPackComponent + - + name: cpack_add_component + named-args: + - DISPLAY_NAME + - DESCRIPTION + - HIDDEN + - REQUIRED + - DISABLED + - GROUP + - DEPENDS + - INSTALL_TYPES + - DOWNLOADED + - ARCHIVE_FILE + - PLIST + - + name: cpack_add_component_group + named-args: + - DISPLAY_NAME + - DESCRIPTION + - PARENT_GROUP + - EXPANDED + - BOLD_TITLE + - + name: cpack_add_install_type + named-args: [DISPLAY_NAME] + - + name: cpack_configure_downloads + named-args: + - UPLOAD_DIRECTORY + - ALL + - ADD_REMOVE + - NO_ADD_REMOVE + # CPackIFW + - + name: cpack_ifw_configure_component + named-args: + - COMMON + - ESSENTIAL + - VIRTUAL + - FORCED_INSTALLATION + - REQUIRES_ADMIN_RIGHTS] + - NAME + - DISPLAY_NAME + - DESCRIPTION + - UPDATE_TEXT + - VERSION + - RELEASE_DATE + - SCRIPT + - PRIORITY + - SORTING_PRIORITY + - DEPENDS + - DEPENDENCIES + - AUTO_DEPEND_ON + - LICENSES + - DEFAULT + - USER_INTERFACES + - TRANSLATIONS + - REPLACES + - CHECKABLE + - + name: cpack_ifw_configure_component_group + named-args: + - VIRTUAL + - FORCED_INSTALLATION + - REQUIRES_ADMIN_RIGHTS + - NAME + - DISPLAY_NAME + - DESCRIPTION + - UPDATE_TEXT + - VERSION + - RELEASE_DATE + - SCRIPT + - PRIORITY + - SORTING_PRIORITY + - DEPENDS + - DEPENDENCIES + - AUTO_DEPEND_ON + - LICENSES + - DEFAULT + - USER_INTERFACES + - TRANSLATIONS + - REPLACES + - CHECKABLE + - + name: cpack_ifw_add_repository + named-args: + - DISABLED + - URL + - USERNAME + - PASSWORD + - DISPLAY_NAME + - + name: cpack_ifw_update_repository + named-args: + - ADD + - REMOVE + - URL + - REPLACE + - OLD_URL + - NEW_URL + - USERNAME + - PASSWORD + - DISPLAY_NAME + - name: cpack_ifw_add_package_resources + # CPackIFWConfigureFile + - name: cpack_ifw_configure_file + # CSharpUtilities + - name: csharp_set_windows_forms_properties + - name: csharp_set_designer_cs_properties + - name: csharp_set_xaml_cs_properties + - name: csharp_get_filename_keys + - name: csharp_get_filename_key_base + - name: csharp_get_dependentupon_name + # CTest + # CTestCoverageCollectGCOV + - + name: ctest_coverage_collect_gcov + named-args: + - TARBALL + - TARBALL_COMPRESSION + - SOURCE + - BUILD + - GCOV_COMMAND + - GCOV_OPTIONS + - GLOB + - DELETE + - QUIET + # CTestScriptMode + # CTestUseLaunchers + # Dart + # DeployQt4 + - name: write_qt4_conf + - name: resolve_qt4_paths + - name: fixup_qt4_executable + - name: install_qt4_plugin_path + - name: install_qt4_plugin + - name: install_qt4_executable + # ExternalData + - name: ExternalData_Expand_Arguments + - name: ExternalData_Add_Test + - + name: ExternalData_Add_Target + named-args: [SHOW_PROGRESS] + # ExternalProject + - + name: ExternalProject_Add + named-args: + - PREFIX + - TMP_DIR + - STAMP_DIR + - LOG_DIR + - DOWNLOAD_DIR + - SOURCE_DIR + - BINARY_DIR + - INSTALL_DIR + - DOWNLOAD_COMMAND + - URL + - URL_HASH + - URL_MD5 + - DOWNLOAD_NAME + - DOWNLOAD_NO_EXTRACT + - DOWNLOAD_NO_PROGRESS + - TIMEOUT + - INACTIVITY_TIMEOUT + - HTTP_USERNAME + - HTTP_PASSWORD + - HTTP_HEADER + - TLS_VERIFY + - TLS_CAINFO + - NETRC + - NETRC_FILE + - GIT_REPOSITORY + - GIT_TAG + - GIT_REMOTE_NAME + - GIT_SUBMODULES + - GIT_SUBMODULES_RECURSE + - GIT_SHALLOW + - GIT_PROGRESS + - GIT_CONFIG + - GIT_REMOTE_UPDATE_STRATEGY + - SVN_REPOSITORY + - SVN_REVISION + - SVN_USERNAME + - SVN_PASSWORD + - SVN_TRUST_CERT + - HG_REPOSITORY + - HG_TAG + - CVS_REPOSITORY + - CVS_MODULE + - CVS_TAG + - UPDATE_COMMAND + - UPDATE_DISCONNECTED + - PATCH_COMMAND + - CONFIGURE_COMMAND + - CMAKE_COMMAND + - CMAKE_GENERATOR + - CMAKE_GENERATOR_PLATFORM + - CMAKE_GENERATOR_TOOLSET + - CMAKE_GENERATOR_INSTANCE + - CMAKE_ARGS + - CMAKE_CACHE_ARGS + - CMAKE_CACHE_DEFAULT_ARGS + - SOURCE_SUBDIR + - CONFIGURE_HANDLED_BY_BUILD + - BUILD_COMMAND + - BUILD_IN_SOURCE + - BUILD_ALWAYS + - BUILD_BYPRODUCTS + - INSTALL_COMMAND + - TEST_COMMAND + - TEST_BEFORE_INSTALL + - TEST_AFTER_INSTALL + - TEST_EXCLUDE_FROM_MAIN + - LOG_DOWNLOAD + - LOG_UPDATE + - LOG_PATCH + - LOG_CONFIGURE + - LOG_BUILD + - LOG_INSTALL + - LOG_TEST + - LOG_MERGED_STDOUTERR + - LOG_OUTPUT_ON_FAILURE + - USES_TERMINAL_DOWNLOAD + - USES_TERMINAL_UPDATE + - USES_TERMINAL_CONFIGURE + - USES_TERMINAL_BUILD + - USES_TERMINAL_INSTALL + - USES_TERMINAL_TEST + - DEPENDS + - EXCLUDE_FROM_ALL + - STEP_TARGETS + - INDEPENDENT_STEP_TARGETS + - LIST_SEPARATOR + - COMMAND + special-args: [IGNORED, OPTIONAL, REQUIRED, CHECKOUT, REBASE, REBASE_CHECKOUT] + property-args: *get_target_property + - name: ExternalProject_Get_Property + - + name: ExternalProject_Add_Step + named-args: + - COMMAND + - COMMENT + - DEPENDEES + - DEPENDERS + - DEPENDS + - INDEPENDENT + - BYPRODUCTS + - ALWAYS + - EXCLUDE_FROM_MAIN + - WORKING_DIRECTORY + - LOG + - USES_TERMINAL + - + name: ExternalProject_Add_StepTargets + named-args: + - NO_DEPENDS + - name: ExternalProject_Add_StepDependencies + # FeatureSummary + - + name: feature_summary + named-args: + - FILENAME + - APPEND + - VAR + - INCLUDE_QUIET_PACKAGES + - FATAL_ON_MISSING_REQUIRED_PACKAGES + - DESCRIPTION + - DEFAULT_DESCRIPTION + - QUIET_ON_EMPTY + - WHAT + - ALL + - PACKAGES_FOUND + - PACKAGES_NOT_FOUND + - ENABLED_FEATURES + - DISABLED_FEATURES + - + name: set_package_properties + named-args: + - PROPERTIES + - URL + - DESCRIPTION + - TYPE + - RUNTIME + - OPTIONAL + - RECOMMENDED + - REQUIRED + - PURPOSE + - name: add_feature_info + - name: set_package_info + - name: set_feature_info + - name: print_enabled_features + - name: print_disabled_features + # FetchContent + - + name: FetchContent_Declare + named-args: + - DOWNLOAD_COMMAND + - URL + - URL_HASH + - URL_MD5 + - DOWNLOAD_NAME + - DOWNLOAD_NO_EXTRACT + - DOWNLOAD_NO_PROGRESS + - TIMEOUT + - INACTIVITY_TIMEOUT + - HTTP_USERNAME + - HTTP_PASSWORD + - HTTP_HEADER + - TLS_VERIFY + - TLS_CAINFO + - NETRC + - NETRC_FILE + - GIT_REPOSITORY + - GIT_TAG + - GIT_REMOTE_NAME + - GIT_SUBMODULES + - GIT_SUBMODULES_RECURSE + - GIT_SHALLOW + - GIT_PROGRESS + - GIT_CONFIG + - GIT_REMOTE_UPDATE_STRATEGY + - SVN_REPOSITORY + - SVN_REVISION + - SVN_USERNAME + - SVN_PASSWORD + - SVN_TRUST_CERT + - HG_REPOSITORY + - HG_TAG + - CVS_REPOSITORY + - CVS_MODULE + - CVS_TAG + - UPDATE_COMMAND + - UPDATE_DISCONNECTED + - PATCH_COMMAND + - SOURCE_SUBDIR + - + name: FetchContent_Populate + named-args: + - QUIET + - SUBBUILD_DIR + - SOURCE_DIR + - BINARY_DIR + - DOWNLOAD_COMMAND + - URL + - URL_HASH + - URL_MD5 + - DOWNLOAD_NAME + - DOWNLOAD_NO_EXTRACT + - DOWNLOAD_NO_PROGRESS + - TIMEOUT + - INACTIVITY_TIMEOUT + - HTTP_USERNAME + - HTTP_PASSWORD + - HTTP_HEADER + - TLS_VERIFY + - TLS_CAINFO + - NETRC + - NETRC_FILE + - GIT_REPOSITORY + - GIT_TAG + - GIT_REMOTE_NAME + - GIT_SUBMODULES + - GIT_SUBMODULES_RECURSE + - GIT_SHALLOW + - GIT_PROGRESS + - GIT_CONFIG + - GIT_REMOTE_UPDATE_STRATEGY + - SVN_REPOSITORY + - SVN_REVISION + - SVN_USERNAME + - SVN_PASSWORD + - SVN_TRUST_CERT + - HG_REPOSITORY + - HG_TAG + - CVS_REPOSITORY + - CVS_MODULE + - CVS_TAG + - UPDATE_COMMAND + - UPDATE_DISCONNECTED + - PATCH_COMMAND + - SOURCE_SUBDIR + - + name: FetchContent_GetProperties + named-args: + - SOURCE_DIR + - BINARY_DIR + - POPULATED + - name: FetchContent_MakeAvailable + # FindPackageHandleStandardArgs + - + name: find_package_handle_standard_args + named-args: + - DEFAULT_MSG + - FOUND_VAR + - REQUIRED_VARS + - VERSION_VAR + - HANDLE_VERSION_RANGE + - HANDLE_COMPONENTS + - CONFIG_MODE + - NAME_MISMATCHED + - REASON_FAILURE_MESSAGE + - FAIL_MESSAGE + - + name: find_package_check_version + named-args: + - HANDLE_VERSION_RANGE + - RESULT_MESSAGE_VARIABLE + # FindPackageMessage + - name: find_package_message + # FortranCInterface + - + name: FortranCInterface_HEADER + named-args: + - MACRO_NAMESPACE + - SYMBOL_NAMESPACE + - SYMBOLS + - + name: FortranCInterface_VERIFY + named-args: [CXX, QUIET] + # GenerateExportHeader + - + name: generate_export_header + named-args: + - BASE_NAME + - EXPORT_MACRO_NAME + - EXPORT_FILE_NAME + - DEPRECATED_MACRO_NAME + - NO_EXPORT_MACRO_NAME + - INCLUDE_GUARD_NAME + - STATIC_DEFINE + - NO_DEPRECATED_MACRO_NAME + - DEFINE_NO_DEPRECATED + - PREFIX_NAME + - CUSTOM_CONTENT_FROM_VARIABLE + first-arg-is-target?: true + # GetPrerequisites (NOTE The module has functions but has been deprecated) + # GNUInstallDirs + - name: GNUInstallDirs_get_absolute_install_dir + # GoogleTest + - + name: gtest_add_tests + named-args: + - TARGET + - SOURCES + - EXTRA_ARGS + - WORKING_DIRECTORY + - TEST_PREFIX + - TEST_SUFFIX + - SKIP_DEPENDENCY + - TEST_LIST + has-target-name-after-kw: TARGET + - + name: gtest_discover_tests # Since 3.10 + named-args: + - EXTRA_ARGS + - WORKING_DIRECTORY + - TEST_PREFIX + - TEST_SUFFIX + - TEST_FILTER # Since 3.22 + - NO_PRETTY_TYPES + - NO_PRETTY_VALUES + - PROPERTIES + - TEST_LIST + - DISCOVERY_TIMEOUT + - XML_OUTPUT_DIR + - DISCOVERY_MODE + special-args: [POST_BUILD, PRE_TEST] + first-arg-is-target?: true + # InstallRequiredSystemLibraries + # ProcessorCount + - name: processorcount + # SelectLibraryConfigurations + - name: select_library_configurations + # SquishTestScript + # TestBigEndian + - name: test_big_endian + # TestForANSIForScope + # TestForANSIStreamHeaders + # TestForSSTREAM + # TestForSTDNamespace + # UseEcos + - name: ecos_add_include_directories + - name: ecos_add_executable + - name: ecos_add_target_lib + - name: ecos_adjust_directory + - name: ecos_use_arm_elf_tools + - name: ecos_use_i386_elf_tools + - name: ecos_use_ppc_eabi_tools + # UseJava + - + name: add_jar + named-args: + - SOURCES + - RESOURCES + - NAMESPACE + - INCLUDE_JARS + - ENTRY_POINT + - VERSION + - MANIFEST + - OUTPUT_NAME + - OUTPUT_DIR + - GENERATE_NATIVE_HEADERS + - DESTINATION + - INSTALL + - BUILD + first-arg-is-target?: true + - + name: install_jar + named-args: &dc [DESTINATION, COMPONENT] + first-arg-is-target?: true + - + name: install_jni_symlink + named-args: *dc + first-arg-is-target?: true + - + name: create_javah + named-args: + - TARGET + - GENERATED_FILES + - CLASSES + - CLASSPATH + - DEPENDS + - OUTPUT_NAME + - OUTPUT_DIR + has-target-name-after-kw: TARGET + - + name: install_jar_exports + named-args: + - TARGETS + - NAMESPACE + - FILE + - DESTINATION + - COMPONENT + has-target-names-after-kw: TARGETS + - + name: export_jars + named-args: + - TARGETS + - NAMESPACE + - FILE + has-target-names-after-kw: TARGETS + - + name: find_jar + named-args: + - NAMES + - PATHS + - ENV + - VERSIONS + - DOC + - + name: create_javadoc + named-args: + - PACKAGES + - FILES + - SOURCEPATH + - CLASSPATH + - INSTALLPATH + - DOCTITLE + - WINDOWTITLE + - AUTHOR + - USE + - VERSION + # UseSWIG + - + name: swig_add_library + named-args: + - TYPE + - SHARED + - MODULE + - STATIC + - USE_BUILD_SHARED_LIBS + - LANGUAGE + - NO_PROXY + - OUTPUT_DIR + - OUTFILE_DIR + - SOURCES + - name: swig_link_libraries + # UsewxWidgets + # NOTE Some standard finder modules also provide commands + # FindSquish + - + name: squish_add_test + named-args: + - AUT + - SUITE + - TEST + - SETTINGSGROUP + - PRE_COMMAND + - POST_COMMAND + # FindBISON + - + name: bison_target + named-args: + - COMPILE_FLAGS + - DEFINES_FILE + - VERBOSE + - REPORT_FILE + # FindCxxTest + - name: cxxtest_add_test + # FindDoxygen + - + name: doxygen_add_docs + named-args: [ALL, USE_STAMP_FILE, WORKING_DIRECTORY, COMMENT] + # FindEnvModules + - + name: env_module + named-args: [COMMAND, OUTPUT_VARIABLE, RESULT_VARIABLE] + - + name: env_module_swap + named-args: [OUTPUT_VARIABLE, RESULT_VARIABLE] + - name: env_module_list + - name: env_module_avail + # FindFLEX + - + name: flex_target + named-args: + - COMPILE_FLAGS + - DEFINES_FILE + - name: add_flex_bison_dependency + # FindGettext + - + name: gettext_create_translations + named-args: [ALL] + - + name: gettext_process_pot_file + named-args: [ALL, INSTALL_DESTINATION, LANGUAGES] + - + name: gettext_process_po_files + named-args: [ALL, INSTALL_DESTINATION, PO_FILES] + # FindHg + - name: hg_wc_info + # FindMatlab + - name: matlab_get_version_from_release_name + - name: matlab_get_release_name_from_version + - name: matlab_extract_all_installed_versions_from_registry + - name: matlab_get_all_valid_matlab_roots_from_registry + - name: matlab_get_mex_suffix + - name: matlab_get_version_from_matlab_run + - + name: matlab_add_unit_test + named-args: + - NAME + - UNITTEST_FILE + - CUSTOM_TEST_COMMAND + - UNITTEST_PRECOMMAND + - TIMEOUT + - ADDITIONAL_PATH + - MATLAB_ADDITIONAL_STARTUP_OPTIONS + - TEST_ARGS + - NO_UNITTEST_FRAMEWORK + - + name: matlab_add_mex + named-args: + - NAME + - EXECUTABLE + - MODULE + - SHARED + - SRC + - OUTPUT_NAME + - DOCUMENTATION + - LINK_TO + - EXCLUDE_FROM_ALL + special-args: [R2017b, R2018a] + # FindPkgConfig + - + name: pkg_check_modules + named-args: &pkgcm + - REQUIRED + - QUIET + - NO_CMAKE_PATH + - NO_CMAKE_ENVIRONMENT_PATH + - IMPORTED_TARGET + - GLOBAL + - + name: pkg_search_module + named-args: *pkgcm + - + name: pkg_get_variable + # FindProtobuf + - + name: protobuf_generate_cpp + named-args: [DESCRIPTORS, EXPORT_MACRO] + - + name: protobuf_generate_python + # FindPython + - + name: Python_add_library + named-args: [STATIC, SHARED, MODULE, WITH_SOABI] + # FindSubversion + - + name: Subversion_WC_INFO + named-args: [IGNORE_SVN_FAILURE] + - + name: Subversion_WC_LOG + # FindXCTest + - name: xctest_add_bundle + - name: xctest_add_test diff --git a/src/libs/3rdparty/syntax-highlighting/data/generators/generate-cmake-syntax.py b/src/libs/3rdparty/syntax-highlighting/data/generators/generate-cmake-syntax.py index 24b1eb0d7cc..dfe77e4627e 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/generators/generate-cmake-syntax.py +++ b/src/libs/3rdparty/syntax-highlighting/data/generators/generate-cmake-syntax.py @@ -57,7 +57,7 @@ def try_transform_placeholder_string_to_regex(name): if 'ARGV' in m: return 'ARGV[0-9]+' - return '&id_re;'.join(m) if 1 < len(m) else name + return '&var_ref_re;'.join(m) if 1 < len(m) else name def try_placeholders_to_regex(names): @@ -109,6 +109,26 @@ def transform_command(cmd): cmd['nested_parentheses'] = cmd['nested-parentheses?'] if 'nested-parentheses?' in cmd else False + if 'first-arg-is-target?' in cmd: + cmd['first_arg_is_target'] = cmd['first-arg-is-target?'] + can_be_nulary = False + + if 'first-args-are-targets?' in cmd: + cmd['first_args_are_targets'] = cmd['first-args-are-targets?'] + can_be_nulary = False + + if 'has-target-name-after-kw' in cmd: + cmd['has_target_name_after_kw'] = cmd['has-target-name-after-kw'] + can_be_nulary = False + + if 'has-target-names-after-kw' in cmd: + cmd['has_target_names_after_kw'] = cmd['has-target-names-after-kw'] + can_be_nulary = False + + if 'second-arg-is-target?' in cmd: + cmd['second_arg_is_target'] = cmd['second-arg-is-target?'] + can_be_nulary = False + if 'nulary?' in cmd and cmd['nulary?'] and not can_be_nulary: raise RuntimeError('Command `{}` w/ args declared nulary!?'.format(cmd['name'])) @@ -124,8 +144,7 @@ def transform_command(cmd): #BEGIN Jinja filters def cmd_is_nulary(cmd): - assert not ('named-args' in cmd or 'special-args' in cmd or 'property-args' in cmd) - return 'nulary?' in cmd and cmd['nulary?'] + return cmd.setdefault('nulary?', False) #END Jinja filters @@ -134,7 +153,7 @@ def cmd_is_nulary(cmd): @click.argument('input_yaml', type=click.File('r')) @click.argument('template', type=click.File('r'), default='./cmake.xml.tpl') def cli(input_yaml, template): - data = yaml.load(input_yaml) + data = yaml.load(input_yaml, Loader=yaml.BaseLoader) # Partition `variables` and `environment-variables` lists into "pure" (key)words and regexes to match for var_key in _VAR_KIND_LIST: @@ -164,8 +183,16 @@ def cli(input_yaml, template): data['commands'] = list( map( transform_command - , data['scripting-commands'] + data['project-commands'] + data['ctest-commands']) + , data['scripting-commands'] + data['project-commands'] + data['ctest-commands'] + ) ) + data['standard_module_commands'] = list( + map( + transform_command + , data['standard-module-commands'] + ) + ) + del data['standard-module-commands'] # Fix node names to be accessible from Jinja template data['generator_expressions'] = data['generator-expressions'] diff --git a/src/libs/3rdparty/syntax-highlighting/data/generators/spdx-comments.xml.tpl b/src/libs/3rdparty/syntax-highlighting/data/generators/spdx-comments.xml.tpl index 58cc80f960b..b9944a2bd04 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/generators/spdx-comments.xml.tpl +++ b/src/libs/3rdparty/syntax-highlighting/data/generators/spdx-comments.xml.tpl @@ -1,7 +1,12 @@ + - - - + diff --git a/src/libs/3rdparty/syntax-highlighting/data/schema/language.xsd b/src/libs/3rdparty/syntax-highlighting/data/schema/language.xsd index fa510e0d147..fdea0dd7521 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/schema/language.xsd +++ b/src/libs/3rdparty/syntax-highlighting/data/schema/language.xsd @@ -130,8 +130,8 @@ extensions: A file glob or pattern to decide for which documents to use this syntax description style: The style that this highlighter provides. It is used through required-syntax-style by the indenters. [optional] mimetype: A list of mimetypes to decide for which documents to use this syntax description [optional] - version: Version number of this syntax description [optional] - kateversion: Kate version required for using this file [optional] + version: Version number of this syntax description + kateversion: Kate version required for using this file casesensitive: Whether text is matched case sensitive. [boolean, optional, default=true] FIXME: This is not implemented yet priority: Priority of this language, if more than one are usable for the file [optional] author: Name of author of this hl file [optional] diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/bash.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/bash.xml index c7b21cb2a01..72e200cce2d 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/syntax/bash.xml +++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/bash.xml @@ -39,7 +39,7 @@ ]> - + arch awk + b2sum + base32 + base64 bash bunzip2 bzcat @@ -147,11 +150,15 @@ bzmore cat chattr + chcon chgrp chmod chown chvt + cksum cp + crontab + csplit date dd deallocvt @@ -165,9 +172,11 @@ dumpkeys ed egrep + expand false fgconsole fgrep + fold fuser gawk getkeycodes @@ -178,7 +187,9 @@ gunzip gzexe gzip + hostid hostname + iconv igawk install kbd_mode @@ -206,6 +217,7 @@ lzmainfo lzmore mapscrn + md5sum mesg mkdir mkfifo @@ -217,20 +229,29 @@ nano netstat nisdomainname + nproc nroff + numfmt openvt + paste + pathchk pgawk pidof ping + pinky + printenv ps pstree + ptx rbash readlink + realpath red resizecons rm rmdir run-parts + runcon sash sed setfont @@ -239,22 +260,33 @@ setmetamode setserial sh + sha1sum + sha224sum + sha256sum + sha384sum + sha512sum showkey shred + shuf sleep ssed stat + stdbuf stty su sync tar tempfile + timeout touch + tput troff true truncate + tty umount uname + unexpand unicode_start unicode_stop unlink @@ -263,6 +295,7 @@ utmpdump uuidgen vdir + vi wall wc xz @@ -336,6 +369,7 @@ gc gcc clang + clang++ valgrind xdg-open cmake @@ -464,6 +498,19 @@ + + + + + + + + + + + + + @@ -1104,6 +1151,7 @@ + diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/cmake.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/cmake.xml index d8676a250db..e94885b856f 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/syntax/cmake.xml +++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/cmake.xml @@ -1,7 +1,10 @@ + + + + ]> - + + - + - + + - + + - + + - + + - + + - + + - + @@ -3102,154 +4678,175 @@ + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + - + + - + + - + + - + + - + + + - + + - + + - + + - + + - + @@ -3257,9 +4854,10 @@ + - + @@ -3267,17 +4865,19 @@ + - + + - + @@ -3294,101 +4894,116 @@ + - + + - + + - + + + + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + @@ -3405,9 +5020,10 @@ + - + @@ -3424,186 +5040,239 @@ + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + - + + + + + + + + + + - + - + + - + - + + - - + + + + + + - + + + + + + + + + + - + - + + + + + + + + + + - + + + - + + - + + - + - + + - + + - + + + - + + - + @@ -3620,40 +5289,55 @@ + - + + - + + - + + + + + + + + + + + + - + + - + @@ -3661,122 +5345,159 @@ + - + + - + + - + + - + + - + + - + + + + + + + + + + + + - + + - + + - + + - + + - + + - + + - + + - + - + + + + + + + + + + + + - + @@ -3784,268 +5505,1824 @@ + - + + - + - + + + + + + + + + + - + - + + + + + + + + + + - + - + + + + + + + + + + - + - + + + + + + + + + + - + - + + + + + + + + + + - + - + + + + + + + + + + - + - + + + + + + + + + + - + - + + + + + + + + + + - + - + + + + + + + + + + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - - - - - - - - - + - + - + - + - - + + - + - + @@ -4069,6 +7346,15 @@ + + + + + + + + + @@ -4101,12 +7387,12 @@ - - + + - + @@ -4170,9 +7456,12 @@ + + + @@ -4191,8 +7480,10 @@ - + + + @@ -4200,7 +7491,7 @@ - + diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/markdown.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/markdown.xml index f03587977a4..b850cca6733 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/syntax/markdown.xml +++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/markdown.xml @@ -90,7 +90,7 @@ ]> - + @@ -149,32 +149,42 @@ - - - - - - - + + + + + + - + - + - + - + - + + + + + + + + + + + + @@ -320,6 +330,7 @@ + @@ -404,6 +415,10 @@ + + + + diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/spdx-comments.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/spdx-comments.xml index e64399098c3..7d893119279 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/syntax/spdx-comments.xml +++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/spdx-comments.xml @@ -1,7 +1,12 @@ + - 0BSD - AAL - ADSL - AFL-1.1 - AFL-1.2 - AFL-2.0 - AFL-2.1 - AFL-3.0 - AGPL-1.0-only - AGPL-1.0-or-later - AGPL-3.0-only - AGPL-3.0-or-later - AMDPLPA - AML - AMPAS - ANTLR-PD - ANTLR-PD-fallback - APAFML - APL-1.0 - APSL-1.0 - APSL-1.1 - APSL-1.2 - APSL-2.0 - Abstyles - Adobe-2006 - Adobe-Glyph - Afmparse - Aladdin - Apache-1.0 - Apache-1.1 - Apache-2.0 - Artistic-1.0 - Artistic-1.0-Perl - Artistic-1.0-cl8 - Artistic-2.0 - BSD-1-Clause - BSD-2-Clause - BSD-2-Clause-Patent - BSD-2-Clause-Views - BSD-3-Clause - BSD-3-Clause-Attribution - BSD-3-Clause-Clear - BSD-3-Clause-LBNL - BSD-3-Clause-No-Nuclear-License - BSD-3-Clause-No-Nuclear-License-2014 - BSD-3-Clause-No-Nuclear-Warranty - BSD-3-Clause-Open-MPI - BSD-4-Clause - BSD-4-Clause-UC - BSD-Protection - BSD-Source-Code - BSL-1.0 - BUSL-1.1 - Bahyph - Barr - Beerware - BitTorrent-1.0 - BitTorrent-1.1 - BlueOak-1.0.0 - Borceux - CAL-1.0 - CAL-1.0-Combined-Work-Exception - CATOSL-1.1 - CC-BY-1.0 - CC-BY-2.0 - CC-BY-2.5 - CC-BY-3.0 - CC-BY-3.0-AT - CC-BY-3.0-US - CC-BY-4.0 - CC-BY-NC-1.0 - CC-BY-NC-2.0 - CC-BY-NC-2.5 - CC-BY-NC-3.0 - CC-BY-NC-4.0 - CC-BY-NC-ND-1.0 - CC-BY-NC-ND-2.0 - CC-BY-NC-ND-2.5 - CC-BY-NC-ND-3.0 - CC-BY-NC-ND-3.0-IGO - CC-BY-NC-ND-4.0 - CC-BY-NC-SA-1.0 - CC-BY-NC-SA-2.0 - CC-BY-NC-SA-2.5 - CC-BY-NC-SA-3.0 - CC-BY-NC-SA-4.0 - CC-BY-ND-1.0 - CC-BY-ND-2.0 - CC-BY-ND-2.5 - CC-BY-ND-3.0 - CC-BY-ND-4.0 - CC-BY-SA-1.0 - CC-BY-SA-2.0 - CC-BY-SA-2.0-UK - CC-BY-SA-2.5 - CC-BY-SA-3.0 - CC-BY-SA-3.0-AT - CC-BY-SA-4.0 - CC-PDDC - CC0-1.0 - CDDL-1.0 - CDDL-1.1 - CDLA-Permissive-1.0 - CDLA-Sharing-1.0 - CECILL-1.0 - CECILL-1.1 - CECILL-2.0 - CECILL-2.1 - CECILL-B - CECILL-C - CERN-OHL-1.1 - CERN-OHL-1.2 - CERN-OHL-P-2.0 - CERN-OHL-S-2.0 - CERN-OHL-W-2.0 - CNRI-Jython - CNRI-Python - CNRI-Python-GPL-Compatible - CPAL-1.0 - CPL-1.0 - CPOL-1.02 - CUA-OPL-1.0 - Caldera - ClArtistic - Condor-1.1 - Crossword - CrystalStacker - Cube - D-FSL-1.0 - DOC - DSDP - Dotseqn - ECL-1.0 - ECL-2.0 - EFL-1.0 - EFL-2.0 - EPICS - EPL-1.0 - EPL-2.0 - EUDatagrid - EUPL-1.0 - EUPL-1.1 - EUPL-1.2 - Entessa - ErlPL-1.1 - Eurosym - FSFAP - FSFUL - FSFULLR - FTL - Fair - Frameworx-1.0 - FreeImage - GFDL-1.1-invariants-only - GFDL-1.1-invariants-or-later - GFDL-1.1-no-invariants-only - GFDL-1.1-no-invariants-or-later - GFDL-1.1-only - GFDL-1.1-or-later - GFDL-1.2-invariants-only - GFDL-1.2-invariants-or-later - GFDL-1.2-no-invariants-only - GFDL-1.2-no-invariants-or-later - GFDL-1.2-only - GFDL-1.2-or-later - GFDL-1.3-invariants-only - GFDL-1.3-invariants-or-later - GFDL-1.3-no-invariants-only - GFDL-1.3-no-invariants-or-later - GFDL-1.3-only - GFDL-1.3-or-later - GL2PS - GLWTPL - GPL-1.0-only - GPL-1.0-or-later - GPL-2.0-only - GPL-2.0-or-later - GPL-3.0-only - GPL-3.0-or-later - Giftware - Glide - Glulxe - HPND - HPND-sell-variant - HTMLTIDY - HaskellReport - Hippocratic-2.1 - IBM-pibs - ICU - IJG - IPA - IPL-1.0 - ISC - ImageMagick - Imlib2 - Info-ZIP - Intel - Intel-ACPI - Interbase-1.0 - JPNIC - JSON - JasPer-2.0 - LAL-1.2 - LAL-1.3 - LGPL-2.0-only - LGPL-2.0-or-later - LGPL-2.1-only - LGPL-2.1-or-later - LGPL-3.0-only - LGPL-3.0-or-later - LGPLLR - LPL-1.0 - LPL-1.02 - LPPL-1.0 - LPPL-1.1 - LPPL-1.2 - LPPL-1.3a - LPPL-1.3c - Latex2e - Leptonica - LiLiQ-P-1.1 - LiLiQ-R-1.1 - LiLiQ-Rplus-1.1 - Libpng - Linux-OpenIB - MIT - MIT-0 - MIT-CMU - MIT-advertising - MIT-enna - MIT-feh - MIT-open-group - MITNFA - MPL-1.0 - MPL-1.1 - MPL-2.0 - MPL-2.0-no-copyleft-exception - MS-PL - MS-RL - MTLL - MakeIndex - MirOS - Motosoto - MulanPSL-1.0 - MulanPSL-2.0 - Multics - Mup - NASA-1.3 - NBPL-1.0 - NCGL-UK-2.0 - NCSA - NGPL - NIST-PD - NIST-PD-fallback - NLOD-1.0 - NLPL - NOSL - NPL-1.0 - NPL-1.1 - NPOSL-3.0 - NRL - NTP - NTP-0 - Naumen - Net-SNMP - NetCDF - Newsletr - Nokia - Noweb - O-UDA-1.0 - OCCT-PL - OCLC-2.0 - ODC-By-1.0 - ODbL-1.0 - OFL-1.0 - OFL-1.0-RFN - OFL-1.0-no-RFN - OFL-1.1 - OFL-1.1-RFN - OFL-1.1-no-RFN - OGC-1.0 - OGL-Canada-2.0 - OGL-UK-1.0 - OGL-UK-2.0 - OGL-UK-3.0 - OGTSL - OLDAP-1.1 - OLDAP-1.2 - OLDAP-1.3 - OLDAP-1.4 - OLDAP-2.0 - OLDAP-2.0.1 - OLDAP-2.1 - OLDAP-2.2 - OLDAP-2.2.1 - OLDAP-2.2.2 - OLDAP-2.3 - OLDAP-2.4 - OLDAP-2.5 - OLDAP-2.6 - OLDAP-2.7 - OLDAP-2.8 - OML - OPL-1.0 - OSET-PL-2.1 - OSL-1.0 - OSL-1.1 - OSL-2.0 - OSL-2.1 - OSL-3.0 - OpenSSL - PDDL-1.0 - PHP-3.0 - PHP-3.01 - PSF-2.0 - Parity-6.0.0 - Parity-7.0.0 - Plexus - PolyForm-Noncommercial-1.0.0 - PolyForm-Small-Business-1.0.0 - PostgreSQL - Python-2.0 - QPL-1.0 - Qhull - RHeCos-1.1 - RPL-1.1 - RPL-1.5 - RPSL-1.0 - RSA-MD - RSCPL - Rdisc - Ruby - SAX-PD - SCEA - SGI-B-1.0 - SGI-B-1.1 - SGI-B-2.0 - SHL-0.5 - SHL-0.51 - SISSL - SISSL-1.2 - SMLNJ - SMPPL - SNIA - SPL-1.0 - SSH-OpenSSH - SSH-short - SSPL-1.0 - SWL - Saxpath - Sendmail - Sendmail-8.23 - SimPL-2.0 - Sleepycat - Spencer-86 - Spencer-94 - Spencer-99 - SugarCRM-1.1.3 - TAPR-OHL-1.0 - TCL - TCP-wrappers - TMate - TORQUE-1.1 - TOSL - TU-Berlin-1.0 - TU-Berlin-2.0 - UCL-1.0 - UPL-1.0 - Unicode-DFS-2015 - Unicode-DFS-2016 - Unicode-TOU - Unlicense - VOSTROM - VSL-1.0 - Vim - W3C - W3C-19980720 - W3C-20150513 - WTFPL - Watcom-1.0 - Wsuipa - X11 - XFree86-1.1 - XSkat - Xerox - Xnet - YPL-1.0 - YPL-1.1 - ZPL-1.1 - ZPL-2.0 - ZPL-2.1 - Zed - Zend-2.0 - Zimbra-1.3 - Zimbra-1.4 - Zlib - blessing - bzip2-1.0.5 bzip2-1.0.6 - copyleft-next-0.3.0 - copyleft-next-0.3.1 - curl - diffmark - dvipdfm + Intel-ACPI + XSkat + CC-BY-NC-SA-2.0 + Plexus + Giftware + BitTorrent-1.0 + APSL-1.1 + UPL-1.0 + Caldera + Zend-2.0 + CUA-OPL-1.0 + JPNIC + SAX-PD + CC-BY-ND-2.5 eGenix - etalab-2.0 - gSOAP-1.3b + LGPLLR + OLDAP-2.2.2 + CC-BY-ND-3.0-DE + IPA + NCSA + W3C + Adobe-2006 + Net-SNMP + CC-BY-SA-4.0 + YPL-1.0 + MITNFA + PHP-3.01 + BSD-Source-Code + CC-BY-SA-2.5 + Motosoto + OSL-1.1 + NGPL + CC-BY-2.5-AU + Unicode-TOU + BSD-3-Clause-No-Nuclear-License + OPUBL-1.0 + CC-BY-NC-SA-2.0-UK + NLOD-2.0 gnuplot + EPICS + Info-ZIP + OLDAP-2.0 + CERN-OHL-P-2.0 + BSD-3-Clause-No-Nuclear-Warranty + AML + MulanPSL-1.0 + Multics + VSL-1.0 + RSA-MD + CC-PDDC + CC-BY-SA-2.1-JP + LPPL-1.2 + Spencer-94 + OLDAP-1.2 + O-UDA-1.0 + OLDAP-2.7 + Glulxe iMatix - libpng-2.0 - libselinux-1.0 + TAPR-OHL-1.0 + NBPL-1.0 + LiLiQ-R-1.1 + Noweb + CC0-1.0 + BSD-Protection + CC-BY-NC-2.5 + Zlib + GFDL-1.3-invariants-or-later + CC-BY-3.0-AT + LPPL-1.3c + EPL-1.0 + GFDL-1.1-invariants-or-later + ANTLR-PD-fallback + OLDAP-2.4 + OLDAP-2.3 + ZPL-2.1 + Apache-2.0 + SGI-B-2.0 + Hippocratic-2.1 + CC-BY-SA-3.0-DE + CC-BY-NC-SA-1.0 + LGPL-2.1-or-later + CC-BY-3.0-US + TCP-wrappers + GFDL-1.2-invariants-or-later + Eurosym + LPPL-1.0 + SGI-B-1.0 + APL-1.0 libtiff - mpich2 - psfrag - psutils - xinetd + AFL-2.1 + CC-BY-NC-1.0 + GD + AFL-1.1 + CC-BY-NC-ND-3.0-IGO + Unicode-DFS-2015 + GFDL-1.2-only + MPL-1.1 + GPL-2.0-only + CC-BY-NC-4.0 + FreeImage + SHL-0.51 + CNRI-Jython + ZPL-1.1 + Afmparse + OLDAP-2.1 + Rdisc + Imlib2 + BSD-4-Clause-Shortened + Sendmail + CC-BY-2.5 + AAL + MPL-2.0-no-copyleft-exception + CC-BY-NC-ND-2.5 + CC-BY-3.0-NL + LPL-1.02 + ECL-1.0 + OFL-1.0-no-RFN + CC-BY-NC-SA-3.0-DE + CC-BY-SA-3.0 + NTP + MPL-2.0 + APSL-1.2 + GFDL-1.2-no-invariants-only + Artistic-2.0 + RSCPL + Sleepycat xpp + CDLA-Sharing-1.0 + ClArtistic + AGPL-1.0-only + CC-BY-3.0-DE + AFL-2.0 + Intel + GFDL-1.1-no-invariants-or-later + APAFML + SISSL + Naumen + HTMLTIDY + OLDAP-2.8 + blessing + CC-BY-ND-2.0 + OGTSL + LGPL-2.0-or-later + Parity-7.0.0 + CC-BY-ND-1.0 + dvipdfm + CNRI-Python + BSD-4-Clause-UC + NLOD-1.0 + MS-RL + CC-BY-NC-SA-4.0 + HaskellReport + CC-BY-1.0 + UCL-1.0 + Mup + SMPPL + PHP-3.0 + GL2PS + CrystalStacker + W3C-20150513 + NIST-PD-fallback + OGL-UK-1.0 + CPL-1.0 + LGPL-2.1-only + ZPL-2.0 + Frameworx-1.0 + AGPL-3.0-only + DRL-1.0 + EFL-2.0 + Spencer-99 + CAL-1.0-Combined-Work-Exception + GFDL-1.1-invariants-only + TCL + SHL-0.5 + OFL-1.0-RFN + CERN-OHL-W-2.0 + Glide + mpich2 + psutils + SPL-1.0 + Apache-1.1 + CC-BY-ND-4.0 + FreeBSD-DOC + SCEA + Latex2e + Artistic-1.0-cl8 + SGI-B-1.1 + NRL + SWL + Zed + CERN-OHL-1.1 + RHeCos-1.1 + JasPer-2.0 + SSPL-1.0 + OLDAP-1.4 + libpng-2.0 + CNRI-Python-GPL-Compatible + Aladdin + CECILL-1.0 + Ruby + NPL-1.1 + ImageMagick + Cube + GFDL-1.1-only + CC-BY-2.0 + AFL-1.2 + CC-BY-SA-2.0 + CECILL-2.0 + MIT-advertising + CC-BY-NC-SA-2.5 + Artistic-1.0 + OSL-3.0 + X11 + Bahyph + OLDAP-2.0.1 + EUDatagrid + MTLL + GFDL-1.2-invariants-only + GFDL-1.3-no-invariants-or-later + curl + LAL-1.3 + DSDP + CERN-OHL-1.2 + TOSL + CC-BY-3.0 + Qhull + GFDL-1.3-no-invariants-only + TORQUE-1.1 + MS-PL + Apache-1.0 + copyleft-next-0.3.1 + GFDL-1.2-or-later + MulanPSL-2.0 + FSFAP + Xerox + CDDL-1.0 + GFDL-1.3-invariants-only + etalab-2.0 + XFree86-1.1 + SNIA + LPPL-1.1 + CATOSL-1.1 + TU-Berlin-2.0 + GFDL-1.3-or-later + LAL-1.2 + ICU + FTL + MirOS + CC-BY-NC-ND-3.0 + OSET-PL-2.1 + CC-BY-NC-ND-2.0 + SISSL-1.2 + Wsuipa + Zimbra-1.4 + Linux-OpenIB + OLDAP-2.5 + AMPAS + GPL-1.0-or-later + BUSL-1.1 + Adobe-Glyph + 0BSD + W3C-19980720 + FSFUL + CC-BY-NC-SA-3.0 + DOC + TMate + MIT-open-group + AMDPLPA + Condor-1.1 + PolyForm-Noncommercial-1.0.0 + BSD-3-Clause-No-Military-License + CC-BY-4.0 + OGL-Canada-2.0 + CC-BY-NC-SA-3.0-IGO + EFL-1.0 + Newsletr + copyleft-next-0.3.0 + GPL-3.0-or-later + CDLA-Permissive-2.0 + CC-BY-ND-3.0 + C-UDA-1.0 + Barr + Vim + BitTorrent-1.1 + CDL-1.0 + CC-BY-SA-1.0 + ADSL + PostgreSQL + OFL-1.1 + NPL-1.0 + xinetd + LGPL-2.0-only zlib-acknowledgement + OLDAP-2.2.1 + APSL-1.0 + BSD-3-Clause-LBNL + GLWTPL + LGPL-3.0-only + OGC-1.0 + Dotseqn + MakeIndex + GPL-3.0-only + BSD-3-Clause-No-Nuclear-License-2014 + GPL-1.0-only + IJG + AGPL-1.0-or-later + OFL-1.1-no-RFN + BSL-1.0 + Libpng + CC-BY-NC-3.0 + CC-BY-NC-2.0 + Unlicense + LPL-1.0 + bzip2-1.0.5 + Entessa + BSD-2-Clause-Patent + ECL-2.0 + Crossword + CC-BY-NC-ND-1.0 + OCLC-2.0 + CECILL-1.1 + CECILL-2.1 + OGDL-Taiwan-1.0 + Abstyles + libselinux-1.0 + ANTLR-PD + GPL-2.0-or-later + IPL-1.0 + MIT-enna + CPOL-1.02 + CC-BY-SA-3.0-AT + BSD-1-Clause + NTP-0 + SugarCRM-1.1.3 + MIT + OFL-1.1-RFN + Watcom-1.0 + CC-BY-NC-SA-2.0-FR + ODbL-1.0 + FSFULLR + OLDAP-1.3 + SSH-OpenSSH + BSD-2-Clause + HPND + Zimbra-1.3 + Borceux + OLDAP-1.1 + OFL-1.0 + NASA-1.3 + VOSTROM + MIT-0 + ISC + Unicode-DFS-2016 + BlueOak-1.0.0 + LiLiQ-Rplus-1.1 + NOSL + SMLNJ + CPAL-1.0 + PSF-2.0 + RPL-1.5 + MIT-Modern-Variant + Nokia + GFDL-1.1-no-invariants-only + PDDL-1.0 + EUPL-1.0 + CDDL-1.1 + GFDL-1.3-only + OLDAP-2.6 + JSON + LGPL-3.0-or-later + Fair + OSL-2.1 + LPPL-1.3a + NAIST-2003 + CC-BY-NC-ND-4.0 + CC-BY-NC-3.0-DE + OPL-1.0 + HPND-sell-variant + QPL-1.0 + EUPL-1.2 + GFDL-1.2-no-invariants-or-later + NCGL-UK-2.0 + Beerware + BSD-3-Clause-Open-MPI + CECILL-B + EPL-2.0 + MIT-feh + RPL-1.1 + CDLA-Permissive-1.0 + Python-2.0 + MPL-1.0 + GFDL-1.1-or-later + diffmark + OpenSSL + OSL-1.0 + Parity-6.0.0 + YPL-1.1 + SSH-short + IBM-pibs + Xnet + TU-Berlin-1.0 + CAL-1.0 + AFL-3.0 + CECILL-C + OGL-UK-3.0 + BSD-3-Clause-Clear + BSD-3-Clause-Modification + CC-BY-SA-2.0-UK + Saxpath + NLPL + SimPL-2.0 + psfrag + Spencer-86 + OCCT-PL + CERN-OHL-S-2.0 + ErlPL-1.1 + MIT-CMU + NIST-PD + OSL-2.0 + APSL-2.0 + Leptonica + PolyForm-Small-Business-1.0.0 + LiLiQ-P-1.1 + NetCDF + OML + AGPL-3.0-or-later + OLDAP-2.2 + BSD-3-Clause + WTFPL + OGL-UK-2.0 + BSD-3-Clause-Attribution + RPSL-1.0 + CC-BY-NC-ND-3.0-DE + EUPL-1.1 + Sendmail-8.23 + ODC-By-1.0 + D-FSL-1.0 + BSD-4-Clause + BSD-2-Clause-Views + Artistic-1.0-Perl + NPOSL-3.0 + gSOAP-1.3b + Interbase-1.0 + GPL-1.0 + GPL-2.0-with-GCC-exception + wxWindows + Nunit + GFDL-1.1 + GPL-2.0 + GFDL-1.2 + LGPL-2.0 + GPL-3.0-with-autoconf-exception + GFDL-1.3 + BSD-2-Clause-NetBSD + LGPL-3.0 + GPL-2.0-with-classpath-exception + GPL-3.0-with-GCC-exception + BSD-2-Clause-FreeBSD + GPL-3.0 + GPL-2.0-with-font-exception + eCos-2.0 + GPL-2.0-with-bison-exception + GPL-2.0-with-autoconf-exception AGPL-1.0 AGPL-3.0 - BSD-2-Clause-FreeBSD - BSD-2-Clause-NetBSD - GFDL-1.1 - GFDL-1.2 - GFDL-1.3 - GPL-1.0 - GPL-2.0 - GPL-2.0-with-GCC-exception - GPL-2.0-with-autoconf-exception - GPL-2.0-with-bison-exception - GPL-2.0-with-classpath-exception - GPL-2.0-with-font-exception - GPL-3.0 - GPL-3.0-with-GCC-exception - GPL-3.0-with-autoconf-exception - LGPL-2.0 LGPL-2.1 - LGPL-3.0 - Nunit StandardML-NJ - eCos-2.0 - wxWindows - GCC-exception-2.0 - openvpn-openssl-exception - GPL-3.0-linking-exception - Fawkes-Runtime-exception - u-boot-exception-2.0 - PS-or-PDF-font-exception-20170817 - gnu-javamail-exception - LGPL-3.0-linking-exception - DigiRule-FOSS-exception - LLVM-exception - Linux-syscall-note - GPL-3.0-linking-source-exception - Qwt-exception-1.0 - 389-exception - mif-exception - eCos-exception-2.0 - CLISP-exception-2.0 - Bison-exception-2.2 - Libtool-exception - LZMA-exception - OpenJDK-assembly-exception-1.0 - Font-exception-2.0 - OCaml-LGPL-linking-exception - GCC-exception-3.1 - Bootloader-exception - SHL-2.0 - Classpath-exception-2.0 - Swift-exception - Autoconf-exception-2.0 - FLTK-exception - freertos-exception-2.0 - Universal-FOSS-exception-1.0 - WxWindows-exception-3.1 - OCCT-exception-1.0 - Autoconf-exception-3.0 - i2p-gpl-java-exception GPL-CC-1.0 - Qt-LGPL-exception-1.1 - SHL-2.1 + openvpn-openssl-exception + WxWindows-exception-3.1 + GPL-3.0-linking-exception + i2p-gpl-java-exception + OpenJDK-assembly-exception-1.0 + mif-exception + CLISP-exception-2.0 + freertos-exception-2.0 + Bison-exception-2.2 + OCCT-exception-1.0 + Autoconf-exception-2.0 + LLVM-exception + GCC-exception-3.1 + Font-exception-2.0 + Libtool-exception + u-boot-exception-2.0 + Swift-exception + eCos-exception-2.0 + OCaml-LGPL-linking-exception Qt-GPL-exception-1.0 + Linux-syscall-note + Bootloader-exception + PS-or-PDF-font-exception-20170817 + Universal-FOSS-exception-1.0 + Classpath-exception-2.0 + Qwt-exception-1.0 + LZMA-exception + Autoconf-exception-3.0 + DigiRule-FOSS-exception + 389-exception + SHL-2.0 + GCC-exception-2.0 + GPL-3.0-linking-source-exception + Qt-LGPL-exception-1.1 + Fawkes-Runtime-exception + gnu-javamail-exception + FLTK-exception + LGPL-3.0-linking-exception + SHL-2.1 diff --git a/src/libs/3rdparty/syntax-highlighting/data/themes/oblivion.theme b/src/libs/3rdparty/syntax-highlighting/data/themes/oblivion.theme index a433fb883a4..87dac8a5d35 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/themes/oblivion.theme +++ b/src/libs/3rdparty/syntax-highlighting/data/themes/oblivion.theme @@ -162,9 +162,9 @@ "MarkError": "#cc0000", "MarkExecution": "#888a85", "MarkWarning": "#ad7fa8", - "ModifiedLines": "#451e1a", + "ModifiedLines": "#cc0000", "ReplaceHighlight": "#356703", - "SavedLines": "#23321a", + "SavedLines": "#4e9a06", "SearchHighlight": "#4e9a06", "Separator": "#787775", "SpellChecking": "#e85848", diff --git a/src/libs/3rdparty/syntax-highlighting/src/CMakeLists.txt b/src/libs/3rdparty/syntax-highlighting/src/CMakeLists.txt index beac3d50e89..419b8ed5b7c 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/CMakeLists.txt +++ b/src/libs/3rdparty/syntax-highlighting/src/CMakeLists.txt @@ -1,8 +1,11 @@ add_subdirectory(indexer) -if(TARGET Qt5::Gui) +if(TARGET Qt${QT_MAJOR_VERSION}::Gui) add_subdirectory(lib) add_subdirectory(cli) endif() +if(TARGET Qt${QT_MAJOR_VERSION}::Quick) + add_subdirectory(quick) +endif() ecm_qt_install_logging_categories( EXPORT KSYNTAXHIGHLIGHTING diff --git a/src/libs/3rdparty/syntax-highlighting/src/indexer/CMakeLists.txt b/src/libs/3rdparty/syntax-highlighting/src/indexer/CMakeLists.txt index 4a84696ad91..9aede60ad78 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/indexer/CMakeLists.txt +++ b/src/libs/3rdparty/syntax-highlighting/src/indexer/CMakeLists.txt @@ -20,6 +20,7 @@ elseif(CMAKE_CROSSCOMPILING) -DECM_DIR=${ECM_DIR} -DCMAKE_PREFIX_PATH=${NATIVE_PREFIX} -DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR} INSTALL_COMMAND "" + BUILD_BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/native_katehighlightingindexer-prefix/src/native_katehighlightingindexer-build/bin/katehighlightingindexer ) add_executable(katehighlightingindexer IMPORTED GLOBAL) add_dependencies(katehighlightingindexer native_katehighlightingindexer) @@ -32,6 +33,6 @@ else() if(Qt5XmlPatterns_FOUND AND NOT ECM_ENABLE_SANITIZERS) target_link_libraries(katehighlightingindexer Qt5::XmlPatterns) else() - target_link_libraries(katehighlightingindexer Qt5::Core) + target_link_libraries(katehighlightingindexer Qt${QT_MAJOR_VERSION}::Core) endif() endif() diff --git a/src/libs/3rdparty/syntax-highlighting/src/indexer/katehighlightingindexer.cpp b/src/libs/3rdparty/syntax-highlighting/src/indexer/katehighlightingindexer.cpp index 4de51ba7c89..d491e13ab99 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/indexer/katehighlightingindexer.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/indexer/katehighlightingindexer.cpp @@ -350,7 +350,7 @@ private: friend uint qHash(const Item &item, uint seed = 0) { - return uint(qHash(item.content, seed)); + return qHash(item.content, seed); } friend bool operator==(const Item &item0, const Item &item1) @@ -513,7 +513,7 @@ private: static const QRegularExpression isDot(QStringLiteral(R"(^\(?\.(?:[*+][*+?]?|[*+]|\{1\})?\$?$)")); // remove "(?:" and ")" static const QRegularExpression removeParentheses(QStringLiteral(R"(\((?:\?:)?|\))")); - // remove parentheses on a double from the string + // remove parentheses on a copy of string auto reg = QString(string).replace(removeParentheses, QString()); isDotRegex = reg.contains(isDot); } @@ -719,7 +719,7 @@ private: friend uint qHash(const Style &style, uint seed = 0) { - return uint(qHash(style.name, seed)); + return qHash(style.name, seed); } friend bool operator==(const Style &style0, const Style &style1) @@ -995,7 +995,6 @@ private: } success = checkLookAhead(rule) && success; success = checkStringDetect(rule) && success; - success = checkAnyChar(rule) && success; success = checkKeyword(definition, rule, referencedKeywords) && success; success = checkRegExpr(filename, rule, context) && success; success = checkDelimiters(definition, rule) && success; @@ -1053,12 +1052,9 @@ private: "\\.\\*[?*]?" REG_CHAR "|" "\\[\\^(" REG_ESCAPE_CHAR "|.)\\]\\*[?*]?\\1" ")$")); - if (( rule.lookAhead == XmlBool::True - || rule.minimal == XmlBool::True - || rule.string.contains(QStringLiteral(".*?")) - || rule.string.contains(QStringLiteral("[^")) - ) && reg.contains(isRange) - ) { + if ((rule.lookAhead == XmlBool::True || rule.minimal == XmlBool::True || rule.string.contains(QStringLiteral(".*?")) + || rule.string.contains(QStringLiteral("[^"))) + && reg.contains(isRange)) { qWarning() << filename << "line" << rule.line << "RegExpr should be replaced by RangeDetect:" << rule.string; return false; } @@ -1079,13 +1075,10 @@ private: #undef REG_ESCAPE_CHAR // use minimal or lazy operator - static const QRegularExpression isMinimal(QStringLiteral( - R"([.][*+][^][?+*()|$]*$)")); - if (rule.lookAhead == XmlBool::True - && rule.minimal != XmlBool::True - && reg.contains(isMinimal) - ) { - qWarning() << filename << "line" << rule.line << "RegExpr should be have minimal=\"1\" or use lazy operator (i.g, '.*' -> '.*?'):" << rule.string; + static const QRegularExpression isMinimal(QStringLiteral(R"([.][*+][^][?+*()|$]*$)")); + if (rule.lookAhead == XmlBool::True && rule.minimal != XmlBool::True && reg.contains(isMinimal)) { + qWarning() << filename << "line" << rule.line + << "RegExpr should be have minimal=\"1\" or use lazy operator (i.g, '.*' -> '.*?'):" << rule.string; return false; } @@ -1179,19 +1172,18 @@ private: if (*first == QLatin1Char('^')) { hasStartOfLine = true; break; - } - else if (*first == QLatin1Char('(')) { + } else if (*first == QLatin1Char('(')) { if (last - first >= 3 && first[1] == QLatin1Char('?') && first[2] == QLatin1Char(':')) { first += 2; } - } - else { + } else { break; } } if (!hasStartOfLine) { - qWarning() << rule.filename << "line" << rule.line << "start of line missing in the pattern with column=\"0\" (i.e. abc -> ^abc):" << rule.string; + qWarning() << rule.filename << "line" << rule.line + << "start of line missing in the pattern with column=\"0\" (i.e. abc -> ^abc):" << rule.string; return false; } } @@ -1314,14 +1306,12 @@ private: } // unnecessary quantifier - static const QRegularExpression unnecessaryQuantifier1(QStringLiteral( - R"([*+?]([.][*+?]{0,2})?$)")); - static const QRegularExpression unnecessaryQuantifier2(QStringLiteral( - R"([*+?]([.][*+?]{0,2})?[)]*$)")); + static const QRegularExpression unnecessaryQuantifier1(QStringLiteral(R"([*+?]([.][*+?]{0,2})?$)")); + static const QRegularExpression unnecessaryQuantifier2(QStringLiteral(R"([*+?]([.][*+?]{0,2})?[)]*$)")); auto &unnecessaryQuantifier = useCapture ? unnecessaryQuantifier1 : unnecessaryQuantifier2; if (rule.lookAhead == XmlBool::True && rule.minimal != XmlBool::True && reg.contains(unnecessaryQuantifier)) { - qWarning() << filename << "line" << rule.line << "Last quantifier is not necessary (i.g., 'xyz*' -> 'xy', 'xyz+.' -> 'xyz.'):" - << rule.string; + qWarning() << filename << "line" << rule.line + << "Last quantifier is not necessary (i.g., 'xyz*' -> 'xy', 'xyz+.' -> 'xyz.'):" << rule.string; return false; } } @@ -1484,32 +1474,11 @@ private: qWarning() << rule.filename << "line" << rule.line << "broken regex:" << rule.string << "problem: dynamic=true but no %\\d+ placeholder"; return false; } - } else { - if (rule.string.size() <= 1) { - const auto replacement = rule.insensitive == XmlBool::True ? QStringLiteral("AnyChar") : QStringLiteral("DetectChar"); - qWarning() << rule.filename << "line" << rule.line << "StringDetect should be replaced by" << replacement; - return false; - } - - if (rule.string.size() <= 2 && rule.insensitive != XmlBool::True) { - qWarning() << rule.filename << "line" << rule.line << "StringDetect should be replaced by Detect2Chars"; - return false; - } } } return true; } - //! Check that AnyChar contains more that 1 character - bool checkAnyChar(const Context::Rule &rule) const - { - if (rule.type == Context::Rule::Type::AnyChar && rule.string.size() <= 1) { - qWarning() << rule.filename << "line" << rule.line << "AnyChar should be replaced by DetectChar"; - return false; - } - return true; - } - //! Check \ and delimiter in a keyword list bool checkKeywordsList(const Definition &definition, QSet &referencedKeywords) const { @@ -1895,7 +1864,7 @@ private: Rule4 detectIdentifierRule{}; // Contains includedRules and included includedRules - QMap includeContexts; + QMap includeContexts; DotRegex dotRegex; @@ -2232,8 +2201,7 @@ private: if (auto &ruleAndInclude = includeContexts[rule.context.context]) { updateUnreachable1(ruleAndInclude); - } - else { + } else { ruleAndInclude.rule = &rule; } @@ -2378,55 +2346,52 @@ private: const auto end = context.rules.end() - 1; for (; it < end; ++it) { - auto& rule1 = *it; - auto& rule2 = it[1]; + auto &rule1 = *it; + auto &rule2 = it[1]; - auto isCommonCompatible = [&]{ - return rule1.attribute == rule2.attribute - && rule1.beginRegion == rule2.beginRegion - && rule1.endRegion == rule2.endRegion - && rule1.lookAhead == rule2.lookAhead - && rule1.firstNonSpace == rule2.firstNonSpace - && rule1.context.context == rule2.context.context - && rule1.context.popCount == rule2.context.popCount - ; + auto isCommonCompatible = [&] { + return rule1.attribute == rule2.attribute && rule1.beginRegion == rule2.beginRegion && rule1.endRegion == rule2.endRegion + && rule1.lookAhead == rule2.lookAhead && rule1.firstNonSpace == rule2.firstNonSpace && rule1.context.context == rule2.context.context + && rule1.context.popCount == rule2.context.popCount; }; switch (rule1.type) { - // request to merge AnyChar/DetectChar - case Context::Rule::Type::AnyChar: - case Context::Rule::Type::DetectChar: - if ((rule2.type == Context::Rule::Type::AnyChar || rule2.type == Context::Rule::Type::DetectChar) && isCommonCompatible() && rule1.column == rule2.column) { - qWarning() << filename << "line" << rule2.line << "can be merged as AnyChar with the previous rule"; - success = false; - } - break; + // request to merge AnyChar/DetectChar + case Context::Rule::Type::AnyChar: + case Context::Rule::Type::DetectChar: + if ((rule2.type == Context::Rule::Type::AnyChar || rule2.type == Context::Rule::Type::DetectChar) && isCommonCompatible() + && rule1.column == rule2.column) { + qWarning() << filename << "line" << rule2.line << "can be merged as AnyChar with the previous rule"; + success = false; + } + break; - // request to merge multiple RegExpr - case Context::Rule::Type::RegExpr: - if (rule2.type == Context::Rule::Type::RegExpr && isCommonCompatible() && rule1.dynamic == rule2.dynamic && (rule1.column == rule2.column || (rule1.column <= 0 && rule2.column <= 0))) { - qWarning() << filename << "line" << rule2.line << "can be merged with the previous rule"; - success = false; - } - break; + // request to merge multiple RegExpr + case Context::Rule::Type::RegExpr: + if (rule2.type == Context::Rule::Type::RegExpr && isCommonCompatible() && rule1.dynamic == rule2.dynamic + && (rule1.column == rule2.column || (rule1.column <= 0 && rule2.column <= 0))) { + qWarning() << filename << "line" << rule2.line << "can be merged with the previous rule"; + success = false; + } + break; - case Context::Rule::Type::DetectSpaces: - case Context::Rule::Type::HlCChar: - case Context::Rule::Type::HlCHex: - case Context::Rule::Type::HlCOct: - case Context::Rule::Type::HlCStringChar: - case Context::Rule::Type::Int: - case Context::Rule::Type::Float: - case Context::Rule::Type::LineContinue: - case Context::Rule::Type::WordDetect: - case Context::Rule::Type::StringDetect: - case Context::Rule::Type::Detect2Chars: - case Context::Rule::Type::IncludeRules: - case Context::Rule::Type::DetectIdentifier: - case Context::Rule::Type::keyword: - case Context::Rule::Type::Unknown: - case Context::Rule::Type::RangeDetect: - break; + case Context::Rule::Type::DetectSpaces: + case Context::Rule::Type::HlCChar: + case Context::Rule::Type::HlCHex: + case Context::Rule::Type::HlCOct: + case Context::Rule::Type::HlCStringChar: + case Context::Rule::Type::Int: + case Context::Rule::Type::Float: + case Context::Rule::Type::LineContinue: + case Context::Rule::Type::WordDetect: + case Context::Rule::Type::StringDetect: + case Context::Rule::Type::Detect2Chars: + case Context::Rule::Type::IncludeRules: + case Context::Rule::Type::DetectIdentifier: + case Context::Rule::Type::keyword: + case Context::Rule::Type::Unknown: + case Context::Rule::Type::RangeDetect: + break; } } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/CMakeLists.txt b/src/libs/3rdparty/syntax-highlighting/src/lib/CMakeLists.txt index 43a60cc19b0..2ab0e603a29 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/CMakeLists.txt +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/CMakeLists.txt @@ -7,6 +7,7 @@ target_sources(KF5SyntaxHighlighting PRIVATE context.cpp contextswitch.cpp definitiondownloader.cpp + highlightingdata.cpp foldingregion.cpp format.cpp htmlhighlighter.cpp @@ -46,13 +47,13 @@ set_target_properties(KF5SyntaxHighlighting PROPERTIES SOVERSION ${SyntaxHighlighting_SOVERSION} EXPORT_NAME SyntaxHighlighting ) -target_include_directories(KF5SyntaxHighlighting INTERFACE "$") +target_include_directories(KF5SyntaxHighlighting INTERFACE "$") target_include_directories(KF5SyntaxHighlighting PUBLIC "$") target_link_libraries(KF5SyntaxHighlighting PUBLIC - Qt5::Gui + Qt${QT_MAJOR_VERSION}::Gui PRIVATE - Qt5::Network + Qt${QT_MAJOR_VERSION}::Network ) ecm_generate_headers(SyntaxHighlighting_HEADERS @@ -74,7 +75,7 @@ install(TARGETS KF5SyntaxHighlighting EXPORT KF5SyntaxHighlightingTargets ${KDE_ install(FILES ${SyntaxHighlighting_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/ksyntaxhighlighting_export.h - DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/KSyntaxHighlighting) + DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF}/KSyntaxHighlighting) if(BUILD_QCH) ecm_add_qch( @@ -104,6 +105,6 @@ ecm_generate_pri_file( KF5SyntaxHighlighting DEPS "gui" FILENAME_VAR PRI_FILENAME - INCLUDE_INSTALL_DIR ${KDE_INSTALL_INCLUDEDIR_KF5}/KSyntaxHighlighting + INCLUDE_INSTALL_DIR ${KDE_INSTALL_INCLUDEDIR_KF}/KSyntaxHighlighting ) install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp index d6f8cad0c71..5794291ff00 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp @@ -137,8 +137,7 @@ State AbstractHighlighter::highlightLine(QStringView text, const State &state) * see https://phabricator.kde.org/D18509 */ int endlessLoopingCounter = 0; - while (!stateData->topContext()->lineEmptyContext().isStay() - || (stateData->topContext()->lineEmptyContext().isStay() && !stateData->topContext()->lineEndContext().isStay())) { + while (!stateData->topContext()->lineEmptyContext().isStay() || !stateData->topContext()->lineEndContext().isStay()) { /** * line empty context switches */ @@ -153,8 +152,7 @@ State AbstractHighlighter::highlightLine(QStringView text, const State &state) * line end context switches only when lineEmptyContext is #stay. This avoids * skipping empty lines after a line continuation character (see bug 405903) */ - } else if (!stateData->topContext()->lineEndContext().isStay() - && !d->switchContext(stateData, stateData->topContext()->lineEndContext(), QStringList())) { + } else if (!d->switchContext(stateData, stateData->topContext()->lineEndContext(), QStringList())) { break; } @@ -305,7 +303,7 @@ State AbstractHighlighter::highlightLine(QStringView text, const State &state) d->switchContext(stateData, rule->context(), newResult.captures()); newFormat = rule->attributeFormat().isValid() ? &rule->attributeFormat() : &stateData->topContext()->attributeFormat(); - if (newOffset == text.size() && std::dynamic_pointer_cast(rule)) { + if (newOffset == text.size() && rule->isLineContinue()) { lineContinuation = true; } break; diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/ansihighlighter.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/ansihighlighter.cpp index 8ae47d80ebf..95517328045 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/ansihighlighter.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/ansihighlighter.cpp @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include @@ -539,7 +539,7 @@ double calculate_CIEDE2000(const CieLab &color1, const CieLab &color2) } struct AnsiBuffer { - using ColorCache = QMap; + using ColorCache = QHash; void append(char c) { @@ -683,7 +683,8 @@ struct GraphLine { int labelLineLength = 0; int nextLabelOffset = 0; - template void pushLabel(int offset, String const &s, int charCounter) + template + void pushLabel(int offset, String const &s, int charCounter) { Q_ASSERT(offset >= labelLineLength); const int n = offset - labelLineLength; @@ -693,7 +694,8 @@ struct GraphLine { nextLabelOffset = labelLineLength; } - template void pushGraph(int offset, String const &s, int charCounter) + template + void pushGraph(int offset, String const &s, int charCounter) { Q_ASSERT(offset >= graphLineLength); const int n = offset - graphLineLength; @@ -754,8 +756,15 @@ public: void setDefinition(const KSyntaxHighlighting::Definition &def) override { AbstractHighlighter::setDefinition(def); - m_defData = DefinitionData::get(def); m_contextCapture.setDefinition(def); + + const auto &definitions = def.includedDefinitions(); + for (const auto &definition : definitions) { + const auto *defData = DefinitionData::get(definition); + for (const auto &context : defData->contexts) { + m_defDataBycontexts.insert(&context, defData); + } + } } void highlightData(QTextStream &in, @@ -928,8 +937,8 @@ private: } const auto context = stateData->topContext(); - const auto defData = DefinitionData::get(context->definition()); - const auto contextName = (defData != m_defData) ? QString(QLatin1Char('<') % defData->name % QLatin1Char('>')) : QString(); + const auto defDataIt = m_defDataBycontexts.find(context); + const auto contextName = (defDataIt != m_defDataBycontexts.end()) ? QString(QLatin1Char('<') % (*defDataIt)->name % QLatin1Char('>')) : QString(); return QString(label % contextName % QLatin1Char('[') % context->name() % QLatin1Char(']')); } @@ -1128,12 +1137,13 @@ private: std::vector m_highlightedFragments; std::vector m_formatGraph; ContextCaptureHighlighter m_contextCapture; - DefinitionData *m_defData; int m_regionDepth = 0; std::vector m_regions; std::vector m_regionGraph; std::vector m_regionStyles; + + QHash m_defDataBycontexts; }; } // anonymous namespace diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/context.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/context.cpp index 724f37a03f1..2bd940d8aa7 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/context.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/context.cpp @@ -18,177 +18,111 @@ using namespace KSyntaxHighlighting; -Definition Context::definition() const +Context::Context(const DefinitionData &def, const HighlightingContextData &data) + : m_name(data.name) + , m_attributeFormat(data.attribute.isEmpty() ? Format() : def.formatByName(data.attribute)) + , m_indentationBasedFolding(!data.noIndentationBasedFolding && def.indentationBasedFolding) { - return m_def.definition(); -} - -void Context::setDefinition(const DefinitionRef &def) -{ - m_def = def; + if (!data.attribute.isEmpty() && !m_attributeFormat.isValid()) { + qCWarning(Log) << "Context: Unknown format" << data.attribute << "in context" << m_name << "of definition" << def.name; + } } bool Context::indentationBasedFoldingEnabled() const { - if (m_noIndentationBasedFolding) { - return false; - } - - return m_def.definition().indentationBasedFoldingEnabled(); + return m_indentationBasedFolding; } -void Context::load(QXmlStreamReader &reader) +void Context::resolveContexts(DefinitionData &def, const HighlightingContextData &data) { - Q_ASSERT(reader.name() == QLatin1String("context")); - Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement); - - m_name = reader.attributes().value(QLatin1String("name")).toString(); - m_attribute = reader.attributes().value(QLatin1String("attribute")).toString(); - m_lineEndContext.parse(reader.attributes().value(QLatin1String("lineEndContext"))); - m_lineEmptyContext.parse(reader.attributes().value(QLatin1String("lineEmptyContext"))); - m_fallthroughContext.parse(reader.attributes().value(QLatin1String("fallthroughContext"))); + m_lineEndContext.resolve(def, data.lineEndContext); + m_lineEmptyContext.resolve(def, data.lineEmptyContext); + m_fallthroughContext.resolve(def, data.fallthroughContext); m_fallthrough = !m_fallthroughContext.isStay(); - m_noIndentationBasedFolding = Xml::attrToBool(reader.attributes().value(QLatin1String("noIndentationBasedFolding"))); - reader.readNext(); - while (!reader.atEnd()) { - switch (reader.tokenType()) { - case QXmlStreamReader::StartElement: { - auto rule = Rule::create(reader.name()); - if (rule) { - rule->setDefinition(m_def.definition()); - if (rule->load(reader)) { - m_rules.push_back(std::move(rule)); - } - } else { - reader.skipCurrentElement(); - } - reader.readNext(); - break; - } - case QXmlStreamReader::EndElement: - return; - default: - reader.readNext(); - break; + m_rules.reserve(data.rules.size()); + for (const auto &ruleData : data.rules) { + m_rules.push_back(Rule::create(def, ruleData, m_name)); + if (!m_rules.back()) { + m_rules.pop_back(); } } } -void Context::resolveContexts() +void Context::resolveIncludes(DefinitionData &def) { - const auto def = m_def.definition(); - m_lineEndContext.resolve(def); - m_lineEmptyContext.resolve(def); - m_fallthroughContext.resolve(def); - for (const auto &rule : m_rules) { - rule->resolveContext(); - } -} - -Context::ResolveState Context::resolveState() -{ - if (m_resolveState == Unknown) { - for (const auto &rule : m_rules) { - auto inc = std::dynamic_pointer_cast(rule); - if (inc) { - m_resolveState = Unresolved; - return m_resolveState; - } - } - m_resolveState = Resolved; - } - return m_resolveState; -} - -void Context::resolveIncludes() -{ - if (resolveState() == Resolved) { + if (m_resolveState == Resolved) { return; } - if (resolveState() == Resolving) { + if (m_resolveState == Resolving) { qCWarning(Log) << "Cyclic dependency!"; return; } - Q_ASSERT(resolveState() == Unresolved); + Q_ASSERT(m_resolveState == Unresolved); m_resolveState = Resolving; // cycle guard for (auto it = m_rules.begin(); it != m_rules.end();) { - auto inc = std::dynamic_pointer_cast(*it); - if (!inc) { + const IncludeRules *includeRules = it->get()->castToIncludeRules(); + if (!includeRules) { ++it; continue; } + Context *context = nullptr; - auto myDefData = DefinitionData::get(m_def.definition()); - if (inc->definitionName().isEmpty()) { // local include - context = myDefData->contextByName(inc->contextName()); + DefinitionData *defData = &def; + + const auto &contextName = includeRules->contextName(); + const int idx = contextName.indexOf(QLatin1String("##")); + + if (idx == -1) { // local include + context = def.contextByName(contextName); } else { - auto def = myDefData->repo->definitionForName(inc->definitionName()); - if (!def.isValid()) { - qCWarning(Log) << "Unable to resolve external include rule for definition" << inc->definitionName() << "in" << m_def.definition().name(); + auto definitionName = contextName.mid(idx + 2); + auto includedDef = def.repo->definitionForName(definitionName); + if (!includedDef.isValid()) { + qCWarning(Log) << "Unable to resolve external include rule for definition" << definitionName << "in" << def.name; ++it; continue; } - auto defData = DefinitionData::get(def); + defData = DefinitionData::get(includedDef); + def.addImmediateIncludedDefinition(includedDef); defData->load(); - if (inc->contextName().isEmpty()) { + if (idx == 0) { context = defData->initialContext(); } else { - context = defData->contextByName(inc->contextName()); + context = defData->contextByName(contextName.left(idx)); } } + if (!context) { - qCWarning(Log) << "Unable to resolve include rule for definition" << inc->contextName() << "##" << inc->definitionName() << "in" - << m_def.definition().name(); + qCWarning(Log) << "Unable to resolve include rule for definition" << contextName << "in" << def.name; ++it; continue; } - context->resolveIncludes(); + + if (context == this) { + qCWarning(Log) << "Unable to resolve self include rule for definition" << contextName << "in" << def.name; + ++it; + continue; + } + + if (context->m_resolveState != Resolved) { + context->resolveIncludes(*defData); + } /** * handle included attribute * transitive closure: we might include attributes included from somewhere else */ - if (inc->includeAttribute()) { - m_attribute = context->m_attribute; - m_attributeContext = context->m_attributeContext ? context->m_attributeContext : context; + if (includeRules->includeAttribute()) { + m_attributeFormat = context->m_attributeFormat; } it = m_rules.erase(it); - for (const auto &rule : context->rules()) { - it = m_rules.insert(it, rule); - ++it; - } + it = m_rules.insert(it, context->rules().begin(), context->rules().end()); + it += context->rules().size(); } m_resolveState = Resolved; } - -void Context::resolveAttributeFormat() -{ - /** - * try to get our format from the definition we stem from - * we need to handle included attributes via m_attributeContext - */ - if (!m_attribute.isEmpty()) { - const auto def = m_attributeContext ? m_attributeContext->m_def.definition() : m_def.definition(); - m_attributeFormat = DefinitionData::get(def)->formatByName(m_attribute); - if (!m_attributeFormat.isValid()) { - if (m_attributeContext) { - qCWarning(Log) << "Context: Unknown format" << m_attribute << "in context" << m_name << "of definition" << m_def.definition().name() - << "from included context" << m_attributeContext->m_name << "of definition" << def.name(); - } else { - qCWarning(Log) << "Context: Unknown format" << m_attribute << "in context" << m_name << "of definition" << m_def.definition().name(); - } - } - } - - /** - * lookup formats for our rules - */ - for (const auto &rule : m_rules) { - rule->resolveAttributeFormat(this); - } -} diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/context_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/context_p.h index 62630455370..7e077b5a244 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/context_p.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/context_p.h @@ -8,9 +8,8 @@ #define KSYNTAXHIGHLIGHTING_CONTEXT_P_H #include "contextswitch_p.h" -#include "definition.h" -#include "definitionref_p.h" #include "format.h" +#include "highlightingdata_p.hpp" #include "rule_p.h" #include @@ -23,14 +22,18 @@ QT_END_NAMESPACE namespace KSyntaxHighlighting { +class DefinitionData; + class Context { public: - Context() = default; - ~Context() = default; + Q_DISABLE_COPY(Context) - Definition definition() const; - void setDefinition(const DefinitionRef &def); + Context(Context &&) = default; + Context &operator=(Context &&) = default; + + Context(const DefinitionData &def, const HighlightingContextData &data); + ~Context() = default; const QString &name() const { @@ -73,44 +76,28 @@ public: */ bool indentationBasedFoldingEnabled() const; - void load(QXmlStreamReader &reader); - void resolveContexts(); - void resolveIncludes(); - void resolveAttributeFormat(); + void resolveContexts(DefinitionData &def, const HighlightingContextData &data); + void resolveIncludes(DefinitionData &def); private: - Q_DISABLE_COPY(Context) + enum ResolveState : quint8 { Unresolved, Resolving, Resolved }; - enum ResolveState { Unknown, Unresolved, Resolving, Resolved }; - ResolveState resolveState(); + std::vector m_rules; - DefinitionRef m_def; QString m_name; - /** - * attribute name, to lookup our format - */ - QString m_attribute; - - /** - * context to use for lookup, if != this context - */ - const Context *m_attributeContext = nullptr; - - /** - * resolved format for our attribute, done in resolveAttributeFormat - */ - Format m_attributeFormat; - ContextSwitch m_lineEndContext; ContextSwitch m_lineEmptyContext; ContextSwitch m_fallthroughContext; - std::vector m_rules; + /** + * resolved format for our attribute, done in constructor and resolveIncludes + */ + Format m_attributeFormat; - ResolveState m_resolveState = Unknown; + ResolveState m_resolveState = Unresolved; bool m_fallthrough = false; - bool m_noIndentationBasedFolding = false; + bool m_indentationBasedFolding; }; } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/contextswitch.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/contextswitch.cpp index e829af463a3..9cab177dae1 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/contextswitch.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/contextswitch.cpp @@ -7,69 +7,45 @@ #include "contextswitch_p.h" #include "definition.h" #include "definition_p.h" +#include "highlightingdata_p.hpp" #include "ksyntaxhighlighting_logging.h" #include "repository.h" using namespace KSyntaxHighlighting; -bool ContextSwitch::isStay() const +void ContextSwitch::resolve(DefinitionData &def, QStringView contextInstr) { - return m_popCount == 0 && !m_context && m_contextName.isEmpty() && m_defName.isEmpty(); -} + HighlightingContextData::ContextSwitch ctx(contextInstr); -int ContextSwitch::popCount() const -{ - return m_popCount; -} + m_popCount = ctx.popCount(); + m_isStay = !m_popCount; -Context *ContextSwitch::context() const -{ - return m_context; -} + auto contextName = ctx.contextName(); + auto defName = ctx.defName(); -void ContextSwitch::parse(QStringView contextInstr) -{ - if (contextInstr.isEmpty() || contextInstr == QLatin1String("#stay")) { + if (contextName.isEmpty() && defName.isEmpty()) { return; } - if (contextInstr.startsWith(QLatin1String("#pop!"))) { - ++m_popCount; - m_contextName = contextInstr.mid(5).toString(); - return; - } - - if (contextInstr.startsWith(QLatin1String("#pop"))) { - ++m_popCount; - parse(contextInstr.mid(4)); - return; - } - - const auto idx = contextInstr.indexOf(QLatin1String("##")); - if (idx >= 0) { - m_contextName = contextInstr.left(idx).toString(); - m_defName = contextInstr.mid(idx + 2).toString(); + if (defName.isEmpty()) { + m_context = def.contextByName(contextName.toString()); } else { - m_contextName = contextInstr.toString(); - } -} - -void ContextSwitch::resolve(const Definition &def) -{ - auto d = def; - if (!m_defName.isEmpty()) { - d = DefinitionData::get(def)->repo->definitionForName(m_defName); - auto data = DefinitionData::get(d); - data->load(); - if (m_contextName.isEmpty()) { - m_context = data->initialContext(); + auto d = def.repo->definitionForName(defName.toString()); + if (d.isValid()) { + auto data = DefinitionData::get(d); + def.addImmediateIncludedDefinition(d); + data->load(); + if (contextName.isEmpty()) { + m_context = data->initialContext(); + } else { + m_context = data->contextByName(contextName.toString()); + } } } - if (!m_contextName.isEmpty()) { - m_context = DefinitionData::get(d)->contextByName(m_contextName); - if (!m_context) { - qCWarning(Log) << "cannot find context" << m_contextName << "in" << def.name(); - } + if (!m_context) { + qCWarning(Log) << "cannot find context" << contextName << "in" << def.name; + } else { + m_isStay = false; } } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/contextswitch_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/contextswitch_p.h index 8230c4a3884..29b0e685e24 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/contextswitch_p.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/contextswitch_p.h @@ -12,7 +12,7 @@ namespace KSyntaxHighlighting { class Context; -class Definition; +class DefinitionData; class ContextSwitch { @@ -20,19 +20,27 @@ public: ContextSwitch() = default; ~ContextSwitch() = default; - bool isStay() const; + bool isStay() const + { + return m_isStay; + } - int popCount() const; - Context *context() const; + int popCount() const + { + return m_popCount; + } - void parse(QStringView contextInstr); - void resolve(const Definition &def); + Context *context() const + { + return m_context; + } + + void resolve(DefinitionData &def, QStringView contextInstr); private: - QString m_defName; - QString m_contextName; Context *m_context = nullptr; int m_popCount = 0; + bool m_isStay = true; }; } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp index 068907a4e28..0fbc9187c09 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp @@ -14,6 +14,7 @@ #include "context_p.h" #include "format.h" #include "format_p.h" +#include "highlightingdata_p.hpp" #include "ksyntaxhighlighting_logging.h" #include "ksyntaxhighlighting_version.h" #include "repository.h" @@ -39,10 +40,7 @@ DefinitionData::DefinitionData() { } -DefinitionData::~DefinitionData() -{ - qDeleteAll(contexts); -} +DefinitionData::~DefinitionData() = default; DefinitionData *DefinitionData::get(const Definition &def) { @@ -237,45 +235,23 @@ QVector Definition::includedDefinitions() const d->load(); // init worklist and result used as guard with this definition - QVector queue{*this}; + QVector queue{d.get()}; QVector definitions{*this}; - while (!queue.isEmpty()) { - // Iterate all context rules to find associated Definitions. This will - // automatically catch other Definitions referenced with IncludeRuldes or ContextSwitch. - const auto definition = queue.takeLast(); - for (const auto &context : std::as_const(definition.d->contexts)) { - // handle context switch attributes of this context itself - for (const auto switchContext : - {context->lineEndContext().context(), context->lineEmptyContext().context(), context->fallthroughContext().context()}) { - if (switchContext) { - if (!definitions.contains(switchContext->definition())) { - queue.push_back(switchContext->definition()); - definitions.push_back(switchContext->definition()); - } - } - } - - // handle the embedded rules - for (const auto &rule : context->rules()) { - // handle include rules like inclusion - if (!definitions.contains(rule->definition())) { - queue.push_back(rule->definition()); - definitions.push_back(rule->definition()); - } - - // handle context switch context inclusion - if (auto switchContext = rule->context().context()) { - if (!definitions.contains(switchContext->definition())) { - queue.push_back(switchContext->definition()); - definitions.push_back(switchContext->definition()); - } - } + while (!queue.empty()) { + const auto *def = queue.back(); + queue.pop_back(); + for (const auto &defRef : def->immediateIncludedDefinitions) { + const auto definition = defRef.definition(); + if (!definitions.contains(definition)) { + definitions.push_back(definition); + queue.push_back(definition.d.get()); } } } // remove the 1st entry, since it is this Definition - definitions.pop_front(); + definitions.front() = std::move(definitions.back()); + definitions.pop_back(); return definitions; } @@ -304,17 +280,17 @@ QVector> Definition::characterEncodings() const return d->characterEncodings; } -Context *DefinitionData::initialContext() const +Context *DefinitionData::initialContext() { - Q_ASSERT(!contexts.isEmpty()); - return contexts.first(); + Q_ASSERT(!contexts.empty()); + return &contexts.front(); } -Context *DefinitionData::contextByName(const QString &wantedName) const +Context *DefinitionData::contextByName(const QString &wantedName) { - for (const auto context : contexts) { - if (context->name() == wantedName) { - return context; + for (auto &context : contexts) { + if (context.name() == wantedName) { + return &context; } } return nullptr; @@ -338,7 +314,7 @@ Format DefinitionData::formatByName(const QString &wantedName) const bool DefinitionData::isLoaded() const { - return !contexts.isEmpty(); + return !contexts.empty(); } bool DefinitionData::load(OnlyKeywords onlyKeywords) @@ -383,17 +359,7 @@ bool DefinitionData::load(OnlyKeywords onlyKeywords) it->setCaseSensitivity(caseSensitive); } - for (const auto context : std::as_const(contexts)) { - context->resolveContexts(); - context->resolveIncludes(); - context->resolveAttributeFormat(); - } - - for (const auto context : std::as_const(contexts)) { - for (const auto &rule : context->rules()) { - rule->resolvePostProcessing(); - } - } + resolveContexts(); return true; } @@ -402,9 +368,21 @@ void DefinitionData::clear() { // keep only name and repo, so we can re-lookup to make references persist over repo reloads keywordLists.clear(); - qDeleteAll(contexts); contexts.clear(); formats.clear(); + contextDatas.clear(); + immediateIncludedDefinitions.clear(); + wordDelimiters = WordDelimiters(); + wordWrapDelimiters = wordDelimiters; + keywordIsLoaded = false; + hasFoldingRegions = false; + indentationBasedFolding = false; + foldingIgnoreList.clear(); + singleLineCommentMarker.clear(); + singleLineCommentPosition = CommentPosition::StartOfLine; + multiLineCommentStartMarker.clear(); + multiLineCommentEndMarker.clear(); + characterEncodings.clear(); fileName.clear(); section.clear(); @@ -414,8 +392,6 @@ void DefinitionData::clear() license.clear(); mimetypes.clear(); extensions.clear(); - wordDelimiters = WordDelimiters(); - wordWrapDelimiters = wordDelimiters; caseSensitive = Qt::CaseSensitive; version = 0.0f; priority = 0; @@ -563,14 +539,14 @@ void DefinitionData::loadContexts(QXmlStreamReader &reader) Q_ASSERT(reader.name() == QLatin1String("contexts")); Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement); + contextDatas.reserve(32); + while (!reader.atEnd()) { switch (reader.tokenType()) { case QXmlStreamReader::StartElement: if (reader.name() == QLatin1String("context")) { - auto context = new Context; - context->setDefinition(q); - context->load(reader); - contexts.push_back(context); + contextDatas.push_back(HighlightingContextData()); + contextDatas.back().load(name, reader); } reader.readNext(); break; @@ -583,6 +559,50 @@ void DefinitionData::loadContexts(QXmlStreamReader &reader) } } +void DefinitionData::resolveContexts() +{ + contexts.reserve(contextDatas.size()); + + /** + * Transform all HighlightingContextData to Context. + * This is necessary so that Context::resolveContexts() can find the referenced contexts. + */ + for (const auto &contextData : std::as_const(contextDatas)) { + contexts.emplace_back(*this, contextData); + } + + /** + * Resolves contexts and rules. + */ + auto ctxIt = contexts.begin(); + for (const auto &contextData : std::as_const(contextDatas)) { + ctxIt->resolveContexts(*this, contextData); + ++ctxIt; + } + + /** + * To free the memory, constDatas is emptied because it is no longer used. + */ + contextDatas.clear(); + contextDatas.shrink_to_fit(); + + /** + * Resolved includeRules. + */ + for (auto &context : contexts) { + context.resolveIncludes(*this); + } + + /** + * Post-processing on rules. + */ + for (const auto &context : contexts) { + for (auto &rule : context.rules()) { + rule->resolvePostProcessing(); + } + } +} + void DefinitionData::loadItemData(QXmlStreamReader &reader) { Q_ASSERT(reader.name() == QLatin1String("itemDatas")); @@ -635,8 +655,7 @@ void DefinitionData::loadGeneral(QXmlStreamReader &reader) wordDelimiters.remove(reader.attributes().value(QLatin1String("weakDeliminator"))); // adapt WordWrapDelimiters - auto wordWrapDeliminatorAttr = reader.attributes().value( - QLatin1String("wordWrapDeliminator")); + auto wordWrapDeliminatorAttr = reader.attributes().value(QLatin1String("wordWrapDeliminator")); if (wordWrapDeliminatorAttr.isEmpty()) { wordWrapDelimiters = wordDelimiters; } else { @@ -803,21 +822,40 @@ quint16 DefinitionData::foldingRegionId(const QString &foldName) return RepositoryPrivate::get(repo)->foldingRegionId(name, foldName); } -DefinitionRef::DefinitionRef() +void DefinitionData::addImmediateIncludedDefinition(const Definition &def) { + if (get(def) != this) { + DefinitionRef defRef(def); + if (!immediateIncludedDefinitions.contains(defRef)) { + immediateIncludedDefinitions.push_back(std::move(defRef)); + } + } } +DefinitionRef::DefinitionRef() = default; + DefinitionRef::DefinitionRef(const Definition &def) : d(def.d) { } +DefinitionRef::DefinitionRef(Definition &&def) + : d(std::move(def.d)) +{ +} + DefinitionRef &DefinitionRef::operator=(const Definition &def) { d = def.d; return *this; } +DefinitionRef &DefinitionRef::operator=(Definition &&def) +{ + d = std::move(def.d); + return *this; +} + Definition DefinitionRef::definition() const { if (!d.expired()) { @@ -828,9 +866,5 @@ Definition DefinitionRef::definition() const bool DefinitionRef::operator==(const DefinitionRef &other) const { - if (d.expired() != other.d.expired()) { - return false; - } - - return d.expired() || d.lock().get() == other.d.lock().get(); + return !d.owner_before(other.d) && !other.d.owner_before(d); } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/definition_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/definition_p.h index e5455e14e98..7d89a47a48d 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/definition_p.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definition_p.h @@ -8,14 +8,16 @@ #ifndef KSYNTAXHIGHLIGHTING_DEFINITION_P_H #define KSYNTAXHIGHLIGHTING_DEFINITION_P_H -#include "definition.h" #include "definitionref_p.h" +#include "highlightingdata_p.hpp" #include "worddelimiters_p.h" #include #include #include +#include + QT_BEGIN_NAMESPACE class QCborMap; class QXmlStreamReader; @@ -55,23 +57,31 @@ public: void loadSpellchecking(QXmlStreamReader &reader); bool checkKateVersion(QStringView verStr); + void resolveContexts(); + void resolveIncludeKeywords(); KeywordList *keywordList(const QString &name); - Context *initialContext() const; - Context *contextByName(const QString &name) const; + Context *initialContext(); + Context *contextByName(const QString &name); Format formatByName(const QString &name) const; quint16 foldingRegionId(const QString &foldName); + void addImmediateIncludedDefinition(const Definition &def); + DefinitionRef q; Repository *repo = nullptr; QHash keywordLists; - QVector contexts; + std::vector contexts; QHash formats; + // data loaded from xml file and emptied after loading contexts + QVector contextDatas; + // Definition referenced by IncludeRules and ContextSwitch + QVector immediateIncludedDefinitions; WordDelimiters wordDelimiters; WordDelimiters wordWrapDelimiters; bool keywordIsLoaded = false; diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.cpp index b16139b731f..f9dbc298666 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.cpp @@ -172,8 +172,7 @@ void DefinitionDownloader::start() const QString url = QLatin1String("https://www.kate-editor.org/syntax/update-") + QString::number(SyntaxHighlighting_VERSION_MAJOR) + QLatin1Char('.') + QString::number(SyntaxHighlighting_VERSION_MINOR) + QLatin1String(".xml"); auto req = QNetworkRequest(QUrl(url)); - req.setAttribute(QNetworkRequest::RedirectPolicyAttribute, - QNetworkRequest::NoLessSafeRedirectPolicy); + req.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy); auto reply = d->nam->get(req); QObject::connect(reply, &QNetworkReply::finished, this, [=]() { d->definitionListDownloadFinished(reply); diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.h b/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.h index db0c6ee68ae..2eaf0561ef1 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.h @@ -59,7 +59,7 @@ public: /** * Destructor. */ - ~DefinitionDownloader(); + ~DefinitionDownloader() override; /** * Starts the update procedure. diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/definitionref_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/definitionref_p.h index 285fec3e206..a92fc988d90 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/definitionref_p.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definitionref_p.h @@ -7,6 +7,8 @@ #ifndef KSYNTAXHIGHLIGHTING_DEFINITIONREF_P_H #define KSYNTAXHIGHLIGHTING_DEFINITIONREF_P_H +#include "definition.h" + #include namespace KSyntaxHighlighting @@ -29,7 +31,9 @@ class DefinitionRef public: DefinitionRef(); explicit DefinitionRef(const Definition &def); + explicit DefinitionRef(Definition &&def); DefinitionRef &operator=(const Definition &def); + DefinitionRef &operator=(Definition &&def); Definition definition() const; diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/highlightingdata.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/highlightingdata.cpp new file mode 100644 index 00000000000..7f589e252b8 --- /dev/null +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/highlightingdata.cpp @@ -0,0 +1,402 @@ +/* + SPDX-FileCopyrightText: 2021 Jonathan Poelen + + SPDX-License-Identifier: MIT +*/ + +#include "highlightingdata_p.hpp" +#include "ksyntaxhighlighting_logging.h" +#include "xml_p.h" + +#include +#include + +using namespace KSyntaxHighlighting; + +template +static void initRuleData(Data &data, Args &&...args) +{ + new (&data) Data{std::move(args)...}; +} + +static Qt::CaseSensitivity attrToCaseSensitivity(QStringView str) +{ + return Xml::attrToBool(str) ? Qt::CaseInsensitive : Qt::CaseSensitive; +} + +static HighlightingContextData::Rule::WordDelimiters loadAdditionalWordDelimiters(QXmlStreamReader &reader) +{ + return HighlightingContextData::Rule::WordDelimiters{ + reader.attributes().value(QLatin1String("additionalDeliminator")).toString(), + reader.attributes().value(QLatin1String("weakDeliminator")).toString(), + }; +} + +static bool checkIsNotEmpty(QStringView str, const char *attrName, const QString &defName, QXmlStreamReader &reader) +{ + if (!str.isEmpty()) { + return true; + } + + qCWarning(Log) << defName << "at line" << reader.lineNumber() << ": " << attrName << "attribute is empty"; + return false; +} + +static bool checkIsChar(QStringView str, const char *attrName, const QString &defName, QXmlStreamReader &reader) +{ + if (str.size() == 1) { + return true; + } + + qCWarning(Log) << defName << "at line" << reader.lineNumber() << ": " << attrName << "attribute must contain exactly 1 character"; + return false; +} + +static bool loadRule(const QString &defName, HighlightingContextData::Rule &rule, QXmlStreamReader &reader) +{ + using Rule = HighlightingContextData::Rule; + + QStringView name = reader.name(); + const auto attrs = reader.attributes(); + bool isIncludeRules = false; + + if (name == QLatin1String("DetectChar")) { + const auto s = attrs.value(QLatin1String("char")); + if (!checkIsChar(s, "char", defName, reader)) { + return false; + } + const QChar c = s.at(0); + const bool dynamic = Xml::attrToBool(attrs.value(QLatin1String("dynamic"))); + + initRuleData(rule.data.detectChar, c, dynamic); + rule.type = Rule::Type::DetectChar; + } else if (name == QLatin1String("RegExpr")) { + const auto pattern = attrs.value(QLatin1String("String")); + if (!checkIsNotEmpty(pattern, "String", defName, reader)) { + return false; + } + + const auto isCaseInsensitive = attrToCaseSensitivity(attrs.value(QLatin1String("insensitive"))); + const auto isMinimal = Xml::attrToBool(attrs.value(QLatin1String("minimal"))); + const auto dynamic = Xml::attrToBool(attrs.value(QLatin1String("dynamic"))); + + initRuleData(rule.data.regExpr, pattern.toString(), isCaseInsensitive, isMinimal, dynamic); + rule.type = Rule::Type::RegExpr; + } else if (name == QLatin1String("IncludeRules")) { + const auto context = attrs.value(QLatin1String("context")); + if (!checkIsNotEmpty(context, "context", defName, reader)) { + return false; + } + const bool includeAttribute = Xml::attrToBool(attrs.value(QLatin1String("includeAttrib"))); + + initRuleData(rule.data.includeRules, context.toString(), includeAttribute); + rule.type = Rule::Type::IncludeRules; + isIncludeRules = true; + } else if (name == QLatin1String("Detect2Chars")) { + const auto s1 = attrs.value(QLatin1String("char")); + const auto s2 = attrs.value(QLatin1String("char1")); + if (!checkIsChar(s1, "char", defName, reader)) { + return false; + } + if (!checkIsChar(s2, "char1", defName, reader)) { + return false; + } + + initRuleData(rule.data.detect2Chars, s1.at(0), s2.at(0)); + rule.type = Rule::Type::Detect2Chars; + } else if (name == QLatin1String("keyword")) { + const auto s = attrs.value(QLatin1String("String")); + if (!checkIsNotEmpty(s, "String", defName, reader)) { + return false; + } + Qt::CaseSensitivity caseSensitivityOverride = Qt::CaseInsensitive; + bool hasCaseSensitivityOverride = false; + + /** + * we might overwrite the case sensitivity + * then we need to init the list for lookup of that sensitivity setting + */ + if (attrs.hasAttribute(QLatin1String("insensitive"))) { + hasCaseSensitivityOverride = true; + caseSensitivityOverride = attrToCaseSensitivity(attrs.value(QLatin1String("insensitive"))); + } + + initRuleData(rule.data.keyword, s.toString(), loadAdditionalWordDelimiters(reader), caseSensitivityOverride, hasCaseSensitivityOverride); + rule.type = Rule::Type::Keyword; + } else if (name == QLatin1String("DetectSpaces")) { + rule.type = Rule::Type::DetectSpaces; + } else if (name == QLatin1String("StringDetect")) { + const auto string = attrs.value(QLatin1String("String")); + if (!checkIsNotEmpty(string, "String", defName, reader)) { + return false; + } + const auto caseSensitivity = attrToCaseSensitivity(attrs.value(QLatin1String("insensitive"))); + const auto dynamic = Xml::attrToBool(attrs.value(QLatin1String("dynamic"))); + const bool isSensitive = (caseSensitivity == Qt::CaseSensitive); + + // String can be replaced with DetectChar or AnyChar + if (!dynamic && string.size() == 1) { + QChar c = string.at(0); + if (isSensitive || c.toLower() == c.toUpper()) { + initRuleData(rule.data.detectChar, c, dynamic); + rule.type = Rule::Type::DetectChar; + } else { + initRuleData(rule.data.anyChar, c.toLower() + c.toUpper()); + rule.type = Rule::Type::AnyChar; + } + } + // String can be replaced with Detect2Chars + else if (isSensitive && !dynamic && string.size() == 2) { + initRuleData(rule.data.detect2Chars, string.at(0), string.at(1)); + rule.type = Rule::Type::Detect2Chars; + } else { + initRuleData(rule.data.stringDetect, string.toString(), caseSensitivity, dynamic); + rule.type = Rule::Type::StringDetect; + } + } else if (name == QLatin1String("WordDetect")) { + const auto word = attrs.value(QLatin1String("String")); + if (!checkIsNotEmpty(word, "String", defName, reader)) { + return false; + } + const auto caseSensitivity = attrToCaseSensitivity(attrs.value(QLatin1String("insensitive"))); + + initRuleData(rule.data.wordDetect, word.toString(), loadAdditionalWordDelimiters(reader), caseSensitivity); + rule.type = Rule::Type::WordDetect; + } else if (name == QLatin1String("AnyChar")) { + const auto chars = attrs.value(QLatin1String("String")); + if (!checkIsNotEmpty(chars, "String", defName, reader)) { + return false; + } + + // AnyChar can be replaced with DetectChar + if (chars.size() == 1) { + initRuleData(rule.data.detectChar, chars.at(0), false); + rule.type = Rule::Type::DetectChar; + } else { + initRuleData(rule.data.anyChar, chars.toString()); + rule.type = Rule::Type::AnyChar; + } + } else if (name == QLatin1String("DetectIdentifier")) { + rule.type = Rule::Type::DetectIdentifier; + } else if (name == QLatin1String("LineContinue")) { + const auto s = attrs.value(QLatin1String("char")); + const QChar c = s.isEmpty() ? QLatin1Char('\\') : s.at(0); + + initRuleData(rule.data.lineContinue, c); + rule.type = Rule::Type::LineContinue; + } else if (name == QLatin1String("Int")) { + initRuleData(rule.data.detectInt, loadAdditionalWordDelimiters(reader)); + rule.type = Rule::Type::Int; + } else if (name == QLatin1String("Float")) { + initRuleData(rule.data.detectFloat, loadAdditionalWordDelimiters(reader)); + rule.type = Rule::Type::Float; + } else if (name == QLatin1String("HlCStringChar")) { + rule.type = Rule::Type::HlCStringChar; + } else if (name == QLatin1String("RangeDetect")) { + const auto s1 = attrs.value(QLatin1String("char")); + const auto s2 = attrs.value(QLatin1String("char1")); + if (!checkIsChar(s1, "char", defName, reader)) { + return false; + } + if (!checkIsChar(s2, "char1", defName, reader)) { + return false; + } + + initRuleData(rule.data.rangeDetect, s1.at(0), s2.at(0)); + rule.type = Rule::Type::RangeDetect; + } else if (name == QLatin1String("HlCHex")) { + initRuleData(rule.data.hlCHex, loadAdditionalWordDelimiters(reader)); + rule.type = Rule::Type::HlCHex; + } else if (name == QLatin1String("HlCChar")) { + rule.type = Rule::Type::HlCChar; + } else if (name == QLatin1String("HlCOct")) { + initRuleData(rule.data.hlCOct, loadAdditionalWordDelimiters(reader)); + rule.type = Rule::Type::HlCOct; + } else { + qCWarning(Log) << "Unknown rule type:" << name; + return false; + } + + if (!isIncludeRules) { + rule.common.contextName = attrs.value(QLatin1String("context")).toString(); + rule.common.beginRegionName = attrs.value(QLatin1String("beginRegion")).toString(); + rule.common.endRegionName = attrs.value(QLatin1String("endRegion")).toString(); + rule.common.attributeName = attrs.value(QLatin1String("attribute")).toString(); + rule.common.firstNonSpace = Xml::attrToBool(attrs.value(QLatin1String("firstNonSpace"))); + rule.common.lookAhead = Xml::attrToBool(attrs.value(QLatin1String("lookAhead"))); + bool colOk = false; + rule.common.column = attrs.value(QLatin1String("column")).toInt(&colOk); + if (!colOk) { + rule.common.column = -1; + } + } + + return true; +} + +template +static void dataRuleVisit(HighlightingContextData::Rule::Type type, Data1 &&data1, Data2 &&data2, Visitor &&visitor) +{ + using Rule = HighlightingContextData::Rule; + using Type = Rule::Type; + switch (type) { + case Type::AnyChar: + visitor(data1.anyChar, data2.anyChar); + break; + case Type::DetectChar: + visitor(data1.detectChar, data2.detectChar); + break; + case Type::Detect2Chars: + visitor(data1.detect2Chars, data2.detect2Chars); + break; + case Type::HlCOct: + visitor(data1.hlCOct, data2.hlCOct); + break; + case Type::IncludeRules: + visitor(data1.includeRules, data2.includeRules); + break; + case Type::Int: + visitor(data1.detectInt, data2.detectInt); + break; + case Type::Keyword: + visitor(data1.keyword, data2.keyword); + break; + case Type::LineContinue: + visitor(data1.lineContinue, data2.lineContinue); + break; + case Type::RangeDetect: + visitor(data1.rangeDetect, data2.rangeDetect); + break; + case Type::RegExpr: + visitor(data1.regExpr, data2.regExpr); + break; + case Type::StringDetect: + visitor(data1.stringDetect, data2.stringDetect); + break; + case Type::WordDetect: + visitor(data1.wordDetect, data2.wordDetect); + break; + case Type::Float: + visitor(data1.detectFloat, data2.detectFloat); + break; + case Type::HlCHex: + visitor(data1.hlCHex, data2.hlCHex); + break; + + case Type::HlCStringChar: + case Type::DetectIdentifier: + case Type::DetectSpaces: + case Type::HlCChar: + case Type::Unknown:; + } +} + +HighlightingContextData::Rule::Rule() noexcept = default; + +HighlightingContextData::Rule::Rule(Rule &&other) noexcept + : common(std::move(other.common)) +{ + dataRuleVisit(other.type, data, other.data, [](auto &data1, auto &data2) { + using Data = std::remove_reference_t; + new (&data1) Data(std::move(data2)); + }); + type = other.type; +} + +HighlightingContextData::Rule::Rule(const Rule &other) + : common(other.common) +{ + dataRuleVisit(other.type, data, other.data, [](auto &data1, auto &data2) { + using Data = std::remove_reference_t; + new (&data1) Data(data2); + }); + type = other.type; +} + +HighlightingContextData::Rule::~Rule() +{ + dataRuleVisit(type, data, data, [](auto &data, auto &) { + using Data = std::remove_reference_t; + data.~Data(); + }); +} + +HighlightingContextData::ContextSwitch::ContextSwitch(QStringView str) +{ + if (str.isEmpty() || str == QStringLiteral("#stay")) { + return; + } + + while (str.startsWith(QStringLiteral("#pop"))) { + ++m_popCount; + if (str.size() > 4 && str.at(4) == QLatin1Char('!')) { + str = str.mid(5); + break; + } + str = str.mid(4); + } + + if (str.isEmpty()) { + return; + } + + m_contextAndDefName = str.toString(); + m_defNameIndex = str.indexOf(QStringLiteral("##")); +} + +bool HighlightingContextData::ContextSwitch::isStay() const +{ + return m_popCount == -1 && m_contextAndDefName.isEmpty(); +} + +QStringView HighlightingContextData::ContextSwitch::contextName() const +{ + if (m_defNameIndex == -1) { + return m_contextAndDefName; + } + return QStringView(m_contextAndDefName).left(m_defNameIndex); +} + +QStringView HighlightingContextData::ContextSwitch::defName() const +{ + if (m_defNameIndex == -1) { + return QStringView(); + } + return QStringView(m_contextAndDefName).mid(m_defNameIndex + 2); +} + +void HighlightingContextData::load(const QString &defName, QXmlStreamReader &reader) +{ + Q_ASSERT(reader.name() == QLatin1String("context")); + Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement); + + name = reader.attributes().value(QLatin1String("name")).toString(); + attribute = reader.attributes().value(QLatin1String("attribute")).toString(); + lineEndContext = reader.attributes().value(QLatin1String("lineEndContext")).toString(); + lineEmptyContext = reader.attributes().value(QLatin1String("lineEmptyContext")).toString(); + fallthroughContext = reader.attributes().value(QLatin1String("fallthroughContext")).toString(); + noIndentationBasedFolding = Xml::attrToBool(reader.attributes().value(QLatin1String("noIndentationBasedFolding"))); + + rules.reserve(8); + + reader.readNext(); + while (!reader.atEnd()) { + switch (reader.tokenType()) { + case QXmlStreamReader::StartElement: { + auto &rule = rules.emplace_back(); + if (!loadRule(defName, rule, reader)) { + rules.pop_back(); + } + // be done with this rule, skip all subelements, e.g. no longer supported sub-rules + reader.skipCurrentElement(); + reader.readNext(); + break; + } + case QXmlStreamReader::EndElement: + return; + default: + reader.readNext(); + break; + } + } +} diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/highlightingdata_p.hpp b/src/libs/3rdparty/syntax-highlighting/src/lib/highlightingdata_p.hpp new file mode 100644 index 00000000000..80aeaf49340 --- /dev/null +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/highlightingdata_p.hpp @@ -0,0 +1,215 @@ +/* + SPDX-FileCopyrightText: 2021 Jonathan Poelen + + SPDX-License-Identifier: MIT +*/ + +#ifndef KSYNTAXHIGHLIGHTING_HIGHLIGHTING_DATA_P_H +#define KSYNTAXHIGHLIGHTING_HIGHLIGHTING_DATA_P_H + +#include +#include + +#include + +QT_BEGIN_NAMESPACE +class QXmlStreamReader; +QT_END_NAMESPACE + +namespace KSyntaxHighlighting +{ +/** + * Represents the raw xml data of a context and its rules. + * After resolving contexts, members of this class are no longer + * use and the instance can be freed to recover used memory. + */ +class HighlightingContextData +{ +public: + void load(const QString &defName, QXmlStreamReader &reader); + + struct ContextSwitch { + ContextSwitch() = default; + ContextSwitch(QStringView str); + + QStringView contextName() const; + QStringView defName() const; + + bool isStay() const; + + int popCount() const + { + return m_popCount; + } + + private: + int m_popCount = 0; + int m_defNameIndex = -1; + QString m_contextAndDefName; + }; + + struct Rule { + enum class Type : quint8 { + Unknown, + AnyChar, + Detect2Chars, + DetectChar, + HlCOct, + IncludeRules, + Int, + Keyword, + LineContinue, + RangeDetect, + RegExpr, + StringDetect, + WordDetect, + Float, + HlCStringChar, + DetectIdentifier, + DetectSpaces, + HlCChar, + HlCHex, + }; + + struct AnyChar { + QString chars; + }; + + struct Detect2Chars { + QChar char1; + QChar char2; + }; + + struct DetectChar { + QChar char1; + bool dynamic; + }; + + struct WordDelimiters { + QString additionalDeliminator; + QString weakDeliminator; + }; + + struct Float { + WordDelimiters wordDelimiters; + }; + + struct HlCHex { + WordDelimiters wordDelimiters; + }; + + struct HlCOct { + WordDelimiters wordDelimiters; + }; + + struct IncludeRules { + QString contextName; + bool includeAttribute; + }; + + struct Int { + WordDelimiters wordDelimiters; + }; + + struct Keyword { + QString name; + WordDelimiters wordDelimiters; + Qt::CaseSensitivity caseSensitivityOverride; + bool hasCaseSensitivityOverride; + }; + + struct LineContinue { + QChar char1; + }; + + struct RangeDetect { + QChar begin; + QChar end; + }; + + struct RegExpr { + QString pattern; + Qt::CaseSensitivity caseSensitivity; + bool isMinimal; + bool dynamic; + }; + + struct StringDetect { + QString string; + Qt::CaseSensitivity caseSensitivity; + bool dynamic; + }; + + struct WordDetect { + QString word; + WordDelimiters wordDelimiters; + Qt::CaseSensitivity caseSensitivity; + }; + + union Data { + AnyChar anyChar; + Detect2Chars detect2Chars; + DetectChar detectChar; + HlCOct hlCOct; + IncludeRules includeRules; + Int detectInt; + Keyword keyword; + LineContinue lineContinue; + RangeDetect rangeDetect; + RegExpr regExpr; + StringDetect stringDetect; + WordDetect wordDetect; + Float detectFloat; + HlCHex hlCHex; + + Data() noexcept + { + } + + ~Data() + { + } + }; + + struct Common { + QString contextName; + QString attributeName; + QString beginRegionName; + QString endRegionName; + int column = -1; + bool firstNonSpace = false; + bool lookAhead = false; + }; + + Type type = Type::Unknown; + Common common; + Data data; + + Rule() noexcept; + Rule(Rule &&other) noexcept; + Rule(const Rule &other); + ~Rule(); + + // since nothing is deleted in the rules vector, these functions do not need to be implemented + Rule &operator=(Rule &&other) = delete; + Rule &operator=(const Rule &other) = delete; + }; + + QString name; + + /** + * attribute name, to lookup our format + */ + QString attribute; + + QString lineEndContext; + QString lineEmptyContext; + QString fallthroughContext; + + std::vector rules; + + bool noIndentationBasedFolding = false; +}; +} + +#endif diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist_p.h index 3ff06952830..a8578522cba 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist_p.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist_p.h @@ -44,6 +44,11 @@ public: return m_keywords; } + Qt::CaseSensitivity caseSensitivity() const + { + return m_caseSensitive; + } + void setKeywordList(const QStringList &keywords) { m_keywords = keywords; @@ -53,7 +58,10 @@ public: } /** Checks if @p str is a keyword in this list. */ - bool contains(QStringView str) const { return contains(str, m_caseSensitive); } + bool contains(QStringView str) const + { + return contains(str, m_caseSensitive); + } /** Checks if @p str is a keyword in this list, overriding the global case-sensitivity setting. */ bool contains(QStringView str, Qt::CaseSensitivity caseSensitive) const; diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/rule.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/rule.cpp index f4e88b719a7..0357dbf2a3c 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/rule.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/rule.cpp @@ -14,7 +14,6 @@ #include "xml_p.h" #include -#include using namespace KSyntaxHighlighting; @@ -97,172 +96,137 @@ static QString replaceCaptures(const QString &pattern, const QStringList &captur return result; } -Rule::~Rule() +static MatchResult matchString(QStringView pattern, QStringView text, int offset, Qt::CaseSensitivity caseSensitivity) { - if (!m_additionalDeliminator.isEmpty() || !m_weakDeliminator.isEmpty()) { - delete m_wordDelimiters; + if (offset + pattern.size() <= text.size() && text.mid(offset, pattern.size()).compare(pattern, caseSensitivity) == 0) { + return offset + pattern.size(); } + return offset; } -Definition Rule::definition() const +static void resolveAdditionalWordDelimiters(WordDelimiters &wordDelimiters, const HighlightingContextData::Rule::WordDelimiters &delimiters) { - return m_def.definition(); -} - -void Rule::setDefinition(const Definition &def) -{ - m_def = def; -} - -bool Rule::load(QXmlStreamReader &reader) -{ - Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement); - - m_attribute = reader.attributes().value(QLatin1String("attribute")).toString(); - if (reader.name() != QLatin1String("IncludeRules")) { // IncludeRules uses this with a different semantic - m_context.parse(reader.attributes().value(QLatin1String("context"))); - } - m_firstNonSpace = Xml::attrToBool(reader.attributes().value(QLatin1String("firstNonSpace"))); - m_lookAhead = Xml::attrToBool(reader.attributes().value(QLatin1String("lookAhead"))); - bool colOk = false; - m_column = reader.attributes().value(QLatin1String("column")).toInt(&colOk); - if (!colOk) { - m_column = -1; - } - - auto regionName = reader.attributes().value(QLatin1String("beginRegion")); - if (!regionName.isEmpty()) { - m_beginRegion = FoldingRegion(FoldingRegion::Begin, DefinitionData::get(m_def.definition())->foldingRegionId(regionName.toString())); - } - regionName = reader.attributes().value(QLatin1String("endRegion")); - if (!regionName.isEmpty()) { - m_endRegion = FoldingRegion(FoldingRegion::End, DefinitionData::get(m_def.definition())->foldingRegionId(regionName.toString())); - } - - auto result = doLoad(reader); - - if (m_lookAhead && m_context.isStay()) { - result = false; - } - - // be done with this rule, skip all subelements, e.g. no longer supported sub-rules - reader.skipCurrentElement(); - return result; -} - -void Rule::resolveContext() -{ - auto const &def = m_def.definition(); - - m_context.resolve(def); - // cache for DefinitionData::wordDelimiters, is accessed VERY often - m_wordDelimiters = &DefinitionData::get(def)->wordDelimiters; - if (!m_additionalDeliminator.isEmpty() || !m_weakDeliminator.isEmpty()) { - m_wordDelimiters = new WordDelimiters(*m_wordDelimiters); - m_wordDelimiters->append(m_additionalDeliminator); - m_wordDelimiters->remove(m_weakDeliminator); + if (!delimiters.additionalDeliminator.isEmpty() || !delimiters.weakDeliminator.isEmpty()) { + wordDelimiters.append(QStringView(delimiters.additionalDeliminator)); + wordDelimiters.remove(QStringView(delimiters.weakDeliminator)); } } -void Rule::resolveAttributeFormat(Context *lookupContext) +Rule::~Rule() = default; + +const IncludeRules *Rule::castToIncludeRules() const { + if (m_type != Type::IncludeRules) { + return nullptr; + } + return static_cast(this); +} + +bool Rule::resolveCommon(DefinitionData &def, const HighlightingContextData::Rule &ruleData, QStringView lookupContextName) +{ + switch (ruleData.type) { + // IncludeRules uses this with a different semantic + case HighlightingContextData::Rule::Type::IncludeRules: + m_type = Type::IncludeRules; + return true; + case HighlightingContextData::Rule::Type::LineContinue: + m_type = Type::LineContinue; + break; + default: + m_type = Type::OtherRule; + break; + } + /** * try to get our format from the definition we stem from */ - if (!m_attribute.isEmpty()) { - m_attributeFormat = DefinitionData::get(definition())->formatByName(m_attribute); + if (!ruleData.common.attributeName.isEmpty()) { + m_attributeFormat = def.formatByName(ruleData.common.attributeName); if (!m_attributeFormat.isValid()) { - qCWarning(Log) << "Rule: Unknown format" << m_attribute << "in context" << lookupContext->name() << "of definition" << definition().name(); + qCWarning(Log) << "Rule: Unknown format" << ruleData.common.attributeName << "in context" << lookupContextName << "of definition" << def.name; } } + + m_firstNonSpace = ruleData.common.firstNonSpace; + m_lookAhead = ruleData.common.lookAhead; + m_column = ruleData.common.column; + + if (!ruleData.common.beginRegionName.isEmpty()) { + m_beginRegion = FoldingRegion(FoldingRegion::Begin, def.foldingRegionId(ruleData.common.beginRegionName)); + } + if (!ruleData.common.endRegionName.isEmpty()) { + m_endRegion = FoldingRegion(FoldingRegion::End, def.foldingRegionId(ruleData.common.endRegionName)); + } + + m_context.resolve(def, ruleData.common.contextName); + + return !(m_lookAhead && m_context.isStay()); } -bool Rule::doLoad(QXmlStreamReader &reader) +static Rule::Ptr createRule(DefinitionData &def, const HighlightingContextData::Rule &ruleData, QStringView lookupContextName) { - Q_UNUSED(reader); - return true; -} + using Type = HighlightingContextData::Rule::Type; -void Rule::loadAdditionalWordDelimiters(QXmlStreamReader &reader) -{ - m_additionalDeliminator = reader.attributes().value(QLatin1String("additionalDeliminator")).toString(); - m_weakDeliminator = reader.attributes().value(QLatin1String("weakDeliminator")).toString(); -} - -Rule::Ptr Rule::create(QStringView name) -{ - if (name == QLatin1String("AnyChar")) { - return std::make_shared(); - } - if (name == QLatin1String("DetectChar")) { - return std::make_shared(); - } - if (name == QLatin1String("Detect2Chars")) { - return std::make_shared(); - } - if (name == QLatin1String("DetectIdentifier")) { - return std::make_shared(); - } - if (name == QLatin1String("DetectSpaces")) { - return std::make_shared(); - } - if (name == QLatin1String("Float")) { - return std::make_shared(); - } - if (name == QLatin1String("Int")) { - return std::make_shared(); - } - if (name == QLatin1String("HlCChar")) { - return std::make_shared(); - } - if (name == QLatin1String("HlCHex")) { - return std::make_shared(); - } - if (name == QLatin1String("HlCOct")) { - return std::make_shared(); - } - if (name == QLatin1String("HlCStringChar")) { + switch (ruleData.type) { + case Type::AnyChar: + return std::make_shared(ruleData.data.anyChar); + case Type::DetectChar: + return std::make_shared(ruleData.data.detectChar); + case Type::Detect2Chars: + return std::make_shared(ruleData.data.detect2Chars); + case Type::IncludeRules: + return std::make_shared(ruleData.data.includeRules); + case Type::Int: + return std::make_shared(def, ruleData.data.detectInt); + case Type::Keyword: + return KeywordListRule::create(def, ruleData.data.keyword, lookupContextName); + case Type::LineContinue: + return std::make_shared(ruleData.data.lineContinue); + case Type::RangeDetect: + return std::make_shared(ruleData.data.rangeDetect); + case Type::RegExpr: + return std::make_shared(ruleData.data.regExpr); + case Type::StringDetect: + if (ruleData.data.stringDetect.dynamic) { + return std::make_shared(ruleData.data.stringDetect); + } + return std::make_shared(ruleData.data.stringDetect); + case Type::WordDetect: + return std::make_shared(def, ruleData.data.wordDetect); + case Type::Float: + return std::make_shared(def, ruleData.data.detectFloat); + case Type::HlCOct: + return std::make_shared(def, ruleData.data.hlCOct); + case Type::HlCStringChar: return std::make_shared(); - } - if (name == QLatin1String("IncludeRules")) { - return std::make_shared(); - } - if (name == QLatin1String("keyword")) { - return std::make_shared(); - } - if (name == QLatin1String("LineContinue")) { - return std::make_shared(); - } - if (name == QLatin1String("RangeDetect")) { - return std::make_shared(); - } - if (name == QLatin1String("RegExpr")) { - return std::make_shared(); - } - if (name == QLatin1String("StringDetect")) { - return std::make_shared(); - } - if (name == QLatin1String("WordDetect")) { - return std::make_shared(); + case Type::DetectIdentifier: + return std::make_shared(); + case Type::DetectSpaces: + return std::make_shared(); + case Type::HlCChar: + return std::make_shared(); + case Type::HlCHex: + return std::make_shared(def, ruleData.data.hlCHex); + + case Type::Unknown:; } - qCWarning(Log) << "Unknown rule type:" << name; - return Ptr(nullptr); + return Rule::Ptr(nullptr); } -bool Rule::isWordDelimiter(QChar c) const +Rule::Ptr Rule::create(DefinitionData &def, const HighlightingContextData::Rule &ruleData, QStringView lookupContextName) { - return m_wordDelimiters->contains(c); + auto rule = createRule(def, ruleData, lookupContextName); + if (rule && !rule->resolveCommon(def, ruleData, lookupContextName)) { + rule.reset(); + } + return rule; } -bool AnyChar::doLoad(QXmlStreamReader &reader) +AnyChar::AnyChar(const HighlightingContextData::Rule::AnyChar &data) + : m_chars(data.chars) { - m_chars = reader.attributes().value(QLatin1String("String")).toString(); - if (m_chars.size() == 1) { - qCDebug(Log) << "AnyChar rule with just one char: use DetectChar instead."; - } - return !m_chars.isEmpty(); } MatchResult AnyChar::doMatch(QStringView text, int offset, const QStringList &) const @@ -273,18 +237,11 @@ MatchResult AnyChar::doMatch(QStringView text, int offset, const QStringList &) return offset; } -bool DetectChar::doLoad(QXmlStreamReader &reader) +DetectChar::DetectChar(const HighlightingContextData::Rule::DetectChar &data) + : m_char(data.char1) + , m_captureIndex(data.dynamic ? data.char1.digitValue() : 0) { - const auto s = reader.attributes().value(QLatin1String("char")); - if (s.isEmpty()) { - return false; - } - m_char = s.at(0); - m_dynamic = Xml::attrToBool(reader.attributes().value(QLatin1String("dynamic"))); - if (m_dynamic) { - m_captureIndex = m_char.digitValue(); - } - return true; + m_dynamic = data.dynamic; } MatchResult DetectChar::doMatch(QStringView text, int offset, const QStringList &captures) const @@ -305,19 +262,13 @@ MatchResult DetectChar::doMatch(QStringView text, int offset, const QStringList return offset; } -bool Detect2Char::doLoad(QXmlStreamReader &reader) +Detect2Chars::Detect2Chars(const HighlightingContextData::Rule::Detect2Chars &data) + : m_char1(data.char1) + , m_char2(data.char2) { - const auto s1 = reader.attributes().value(QLatin1String("char")); - const auto s2 = reader.attributes().value(QLatin1String("char1")); - if (s1.isEmpty() || s2.isEmpty()) { - return false; - } - m_char1 = s1.at(0); - m_char2 = s2.at(0); - return true; } -MatchResult Detect2Char::doMatch(QStringView text, int offset, const QStringList &) const +MatchResult Detect2Chars::doMatch(QStringView text, int offset, const QStringList &) const { if (text.size() - offset < 2) { return offset; @@ -352,15 +303,15 @@ MatchResult DetectSpaces::doMatch(QStringView text, int offset, const QStringLis return offset; } -bool Float::doLoad(QXmlStreamReader &reader) +Float::Float(DefinitionData &def, const HighlightingContextData::Rule::Float &data) + : m_wordDelimiters(def.wordDelimiters) { - loadAdditionalWordDelimiters(reader); - return true; + resolveAdditionalWordDelimiters(m_wordDelimiters, data.wordDelimiters); } MatchResult Float::doMatch(QStringView text, int offset, const QStringList &) const { - if (offset > 0 && !isWordDelimiter(text.at(offset - 1))) { + if (offset > 0 && !m_wordDelimiters.contains(text.at(offset - 1))) { return offset; } @@ -432,15 +383,15 @@ MatchResult HlCChar::doMatch(QStringView text, int offset, const QStringList &) return offset; } -bool HlCHex::doLoad(QXmlStreamReader &reader) +HlCHex::HlCHex(DefinitionData &def, const HighlightingContextData::Rule::HlCHex &data) + : m_wordDelimiters(def.wordDelimiters) { - loadAdditionalWordDelimiters(reader); - return true; + resolveAdditionalWordDelimiters(m_wordDelimiters, data.wordDelimiters); } MatchResult HlCHex::doMatch(QStringView text, int offset, const QStringList &) const { - if (offset > 0 && !isWordDelimiter(text.at(offset - 1))) { + if (offset > 0 && !m_wordDelimiters.contains(text.at(offset - 1))) { return offset; } @@ -466,15 +417,15 @@ MatchResult HlCHex::doMatch(QStringView text, int offset, const QStringList &) c return offset; } -bool HlCOct::doLoad(QXmlStreamReader &reader) +HlCOct::HlCOct(DefinitionData &def, const HighlightingContextData::Rule::HlCOct &data) + : m_wordDelimiters(def.wordDelimiters) { - loadAdditionalWordDelimiters(reader); - return true; + resolveAdditionalWordDelimiters(m_wordDelimiters, data.wordDelimiters); } MatchResult HlCOct::doMatch(QStringView text, int offset, const QStringList &) const { - if (offset > 0 && !isWordDelimiter(text.at(offset - 1))) { + if (offset > 0 && !m_wordDelimiters.contains(text.at(offset - 1))) { return offset; } @@ -503,53 +454,28 @@ MatchResult HlCStringChar::doMatch(QStringView text, int offset, const QStringLi return matchEscapedChar(text, offset); } -QString IncludeRules::contextName() const +IncludeRules::IncludeRules(const HighlightingContextData::Rule::IncludeRules &data) + : m_contextName(data.contextName) + , m_includeAttribute(data.includeAttribute) { - return m_contextName; -} - -QString IncludeRules::definitionName() const -{ - return m_defName; -} - -bool IncludeRules::includeAttribute() const -{ - return m_includeAttribute; -} - -bool IncludeRules::doLoad(QXmlStreamReader &reader) -{ - const auto s = reader.attributes().value(QLatin1String("context")); - const auto split = s.split(QString::fromLatin1("##"), Qt::KeepEmptyParts); - if (split.isEmpty()) { - return false; - } - m_contextName = split.at(0).toString(); - if (split.size() > 1) { - m_defName = split.at(1).toString(); - } - m_includeAttribute = Xml::attrToBool(reader.attributes().value(QLatin1String("includeAttrib"))); - - return !m_contextName.isEmpty() || !m_defName.isEmpty(); } MatchResult IncludeRules::doMatch(QStringView text, int offset, const QStringList &) const { Q_UNUSED(text); - qCWarning(Log) << "Unresolved include rule for" << m_contextName << "##" << m_defName; + qCWarning(Log) << "Unresolved include rule"; return offset; } -bool Int::doLoad(QXmlStreamReader &reader) +Int::Int(DefinitionData &def, const HighlightingContextData::Rule::Int &data) + : m_wordDelimiters(def.wordDelimiters) { - loadAdditionalWordDelimiters(reader); - return true; + resolveAdditionalWordDelimiters(m_wordDelimiters, data.wordDelimiters); } MatchResult Int::doMatch(QStringView text, int offset, const QStringList &) const { - if (offset > 0 && !isWordDelimiter(text.at(offset - 1))) { + if (offset > 0 && !m_wordDelimiters.contains(text.at(offset - 1))) { return offset; } @@ -559,67 +485,61 @@ MatchResult Int::doMatch(QStringView text, int offset, const QStringList &) cons return offset; } -bool KeywordListRule::doLoad(QXmlStreamReader &reader) +Rule::Ptr KeywordListRule::create(DefinitionData &def, const HighlightingContextData::Rule::Keyword &data, QStringView lookupContextName) { /** * get our keyword list, if not found => bail out */ - auto defData = DefinitionData::get(definition()); - m_keywordList = defData->keywordList(reader.attributes().value(QLatin1String("String")).toString()); - if (!m_keywordList) { - return false; + auto *keywordList = def.keywordList(data.name); + if (!keywordList) { + qCWarning(Log) << "Rule: Unknown keyword list" << data.name << "in context" << lookupContextName << "of definition" << def.name; + return Rule::Ptr(); + } + + if (keywordList->isEmpty()) { + return Rule::Ptr(); } /** * we might overwrite the case sensitivity * then we need to init the list for lookup of that sensitivity setting */ - if (reader.attributes().hasAttribute(QLatin1String("insensitive"))) { - m_hasCaseSensitivityOverride = true; - m_caseSensitivityOverride = Xml::attrToBool(reader.attributes().value(QLatin1String("insensitive"))) ? Qt::CaseInsensitive : Qt::CaseSensitive; - m_keywordList->initLookupForCaseSensitivity(m_caseSensitivityOverride); - } else { - m_hasCaseSensitivityOverride = false; + if (data.hasCaseSensitivityOverride) { + keywordList->initLookupForCaseSensitivity(data.caseSensitivityOverride); } - loadAdditionalWordDelimiters(reader); + return std::make_shared(*keywordList, def, data); +} - return !m_keywordList->isEmpty(); +KeywordListRule::KeywordListRule(const KeywordList &keywordList, DefinitionData &def, const HighlightingContextData::Rule::Keyword &data) + : m_wordDelimiters(def.wordDelimiters) + , m_keywordList(keywordList) + , m_caseSensitivity(data.hasCaseSensitivityOverride ? data.caseSensitivityOverride : keywordList.caseSensitivity()) +{ + resolveAdditionalWordDelimiters(m_wordDelimiters, data.wordDelimiters); } MatchResult KeywordListRule::doMatch(QStringView text, int offset, const QStringList &) const { auto newOffset = offset; - while (text.size() > newOffset && !isWordDelimiter(text.at(newOffset))) { + while (text.size() > newOffset && !m_wordDelimiters.contains(text.at(newOffset))) { ++newOffset; } if (newOffset == offset) { return offset; } - if (m_hasCaseSensitivityOverride) { - if (m_keywordList->contains(text.mid(offset, newOffset - offset), m_caseSensitivityOverride)) { - return newOffset; - } - } else { - if (m_keywordList->contains(text.mid(offset, newOffset - offset))) { - return newOffset; - } + if (m_keywordList.contains(text.mid(offset, newOffset - offset), m_caseSensitivity)) { + return newOffset; } // we don't match, but we can skip until newOffset as we can't start a keyword in-between return MatchResult(offset, newOffset); } -bool LineContinue::doLoad(QXmlStreamReader &reader) +LineContinue::LineContinue(const HighlightingContextData::Rule::LineContinue &data) + : m_char(data.char1) { - const auto s = reader.attributes().value(QLatin1String("char")); - if (s.isEmpty()) { - m_char = QLatin1Char('\\'); - } else { - m_char = s.at(0); - } - return true; } MatchResult LineContinue::doMatch(QStringView text, int offset, const QStringList &) const @@ -630,16 +550,10 @@ MatchResult LineContinue::doMatch(QStringView text, int offset, const QStringLis return offset; } -bool RangeDetect::doLoad(QXmlStreamReader &reader) +RangeDetect::RangeDetect(const HighlightingContextData::Rule::RangeDetect &data) + : m_begin(data.begin) + , m_end(data.end) { - const auto s1 = reader.attributes().value(QLatin1String("char")); - const auto s2 = reader.attributes().value(QLatin1String("char1")); - if (s1.isEmpty() || s2.isEmpty()) { - return false; - } - m_begin = s1.at(0); - m_end = s2.at(0); - return true; } MatchResult RangeDetect::doMatch(QStringView text, int offset, const QStringList &) const @@ -661,25 +575,20 @@ MatchResult RangeDetect::doMatch(QStringView text, int offset, const QStringList return offset; } -bool RegExpr::doLoad(QXmlStreamReader &reader) +RegExpr::RegExpr(const HighlightingContextData::Rule::RegExpr &data) { - m_regexp.setPattern(reader.attributes().value(QLatin1String("String")).toString()); - - const auto isMinimal = Xml::attrToBool(reader.attributes().value(QLatin1String("minimal"))); - const auto isCaseInsensitive = Xml::attrToBool(reader.attributes().value(QLatin1String("insensitive"))); - m_regexp.setPatternOptions((isMinimal ? QRegularExpression::InvertedGreedinessOption : QRegularExpression::NoPatternOption) - | (isCaseInsensitive ? QRegularExpression::CaseInsensitiveOption : QRegularExpression::NoPatternOption) + m_regexp.setPattern(data.pattern); + m_regexp.setPatternOptions((data.isMinimal ? QRegularExpression::InvertedGreedinessOption : QRegularExpression::NoPatternOption) + | (data.caseSensitivity == Qt::CaseInsensitive ? QRegularExpression::CaseInsensitiveOption : QRegularExpression::NoPatternOption) // DontCaptureOption is removed by resolvePostProcessing() when necessary | QRegularExpression::DontCaptureOption // ensure Unicode support is enabled | QRegularExpression::UseUnicodePropertiesOption); - m_dynamic = Xml::attrToBool(reader.attributes().value(QLatin1String("dynamic"))); - - return !m_regexp.pattern().isEmpty(); + m_dynamic = data.dynamic; } -void KSyntaxHighlighting::RegExpr::resolvePostProcessing() +void RegExpr::resolvePostProcessing() { if (m_isResolved) { return; @@ -728,11 +637,7 @@ MatchResult RegExpr::doMatch(QStringView text, int offset, const QStringList &ca /** * match the pattern */ -#if QT_VERSION < QT_VERSION_CHECK(5, 15, 2) - const auto result = regexp.match(text.toString(), offset, QRegularExpression::NormalMatch, QRegularExpression::DontCheckSubjectStringMatchOption); -#else const auto result = regexp.match(text, offset, QRegularExpression::NormalMatch, QRegularExpression::DontCheckSubjectStringMatchOption); -#endif if (result.capturedStart() == offset) { /** * we only need to compute the captured texts if we have real capture groups @@ -756,33 +661,39 @@ MatchResult RegExpr::doMatch(QStringView text, int offset, const QStringList &ca return MatchResult(offset, result.capturedStart()); } -bool StringDetect::doLoad(QXmlStreamReader &reader) +StringDetect::StringDetect(const HighlightingContextData::Rule::StringDetect &data) + : m_string(data.string) + , m_caseSensitivity(data.caseSensitivity) { - m_string = reader.attributes().value(QLatin1String("String")).toString(); - m_caseSensitivity = Xml::attrToBool(reader.attributes().value(QLatin1String("insensitive"))) ? Qt::CaseInsensitive : Qt::CaseSensitive; - m_dynamic = Xml::attrToBool(reader.attributes().value(QLatin1String("dynamic"))); - return !m_string.isEmpty(); } -MatchResult StringDetect::doMatch(QStringView text, int offset, const QStringList &captures) const +MatchResult StringDetect::doMatch(QStringView text, int offset, const QStringList &) const +{ + return matchString(m_string, text, offset, m_caseSensitivity); +} + +DynamicStringDetect::DynamicStringDetect(const HighlightingContextData::Rule::StringDetect &data) + : m_string(data.string) + , m_caseSensitivity(data.caseSensitivity) +{ + m_dynamic = true; +} + +MatchResult DynamicStringDetect::doMatch(QStringView text, int offset, const QStringList &captures) const { /** * for dynamic case: create new pattern with right instantiation */ - const auto &pattern = m_dynamic ? replaceCaptures(m_string, captures, false) : m_string; - - if (offset + pattern.size() <= text.size() && text.mid(offset, pattern.size()).compare(pattern, m_caseSensitivity) == 0) { - return offset + pattern.size(); - } - return offset; + const auto pattern = replaceCaptures(m_string, captures, false); + return matchString(pattern, text, offset, m_caseSensitivity); } -bool WordDetect::doLoad(QXmlStreamReader &reader) +WordDetect::WordDetect(DefinitionData &def, const HighlightingContextData::Rule::WordDetect &data) + : m_wordDelimiters(def.wordDelimiters) + , m_word(data.word) + , m_caseSensitivity(data.caseSensitivity) { - m_word = reader.attributes().value(QLatin1String("String")).toString(); - m_caseSensitivity = Xml::attrToBool(reader.attributes().value(QLatin1String("insensitive"))) ? Qt::CaseInsensitive : Qt::CaseSensitive; - loadAdditionalWordDelimiters(reader); - return !m_word.isEmpty(); + resolveAdditionalWordDelimiters(m_wordDelimiters, data.wordDelimiters); } MatchResult WordDetect::doMatch(QStringView text, int offset, const QStringList &) const @@ -795,7 +706,7 @@ MatchResult WordDetect::doMatch(QStringView text, int offset, const QStringList * detect delimiter characters on the inner and outer boundaries of the string * NOTE: m_word isn't empty */ - if (offset > 0 && !isWordDelimiter(text.at(offset - 1)) && !isWordDelimiter(text.at(offset))) { + if (offset > 0 && !m_wordDelimiters.contains(text.at(offset - 1)) && !m_wordDelimiters.contains(text.at(offset))) { return offset; } @@ -803,7 +714,8 @@ MatchResult WordDetect::doMatch(QStringView text, int offset, const QStringList return offset; } - if (text.size() == offset + m_word.size() || isWordDelimiter(text.at(offset + m_word.size())) || isWordDelimiter(text.at(offset + m_word.size() - 1))) { + if (text.size() == offset + m_word.size() || m_wordDelimiters.contains(text.at(offset + m_word.size())) + || m_wordDelimiters.contains(text.at(offset + m_word.size() - 1))) { return offset + m_word.size(); } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/rule_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/rule_p.h index 374eb87dfaf..faf2a97f484 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/rule_p.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/rule_p.h @@ -9,25 +9,24 @@ #define KSYNTAXHIGHLIGHTING_RULE_P_H #include "contextswitch_p.h" -#include "definition.h" #include "definitionref_p.h" #include "foldingregion.h" #include "format.h" +#include "highlightingdata_p.hpp" #include "keywordlist_p.h" #include "matchresult_p.h" +#include "worddelimiters_p.h" #include #include #include -QT_BEGIN_NAMESPACE -class QXmlStreamReader; -QT_END_NAMESPACE - namespace KSyntaxHighlighting { class WordDelimiters; +class DefinitionData; +class IncludeRules; class Rule { @@ -37,9 +36,6 @@ public: typedef std::shared_ptr Ptr; - Definition definition() const; - void setDefinition(const Definition &def); - const Format &attributeFormat() const { return m_attributeFormat; @@ -80,51 +76,51 @@ public: return m_endRegion; } - bool load(QXmlStreamReader &reader); - void resolveContext(); - void resolveAttributeFormat(Context *lookupContext); + const IncludeRules *castToIncludeRules() const; + + bool isLineContinue() const + { + return m_type == Type::LineContinue; + } + virtual void resolvePostProcessing() { } virtual MatchResult doMatch(QStringView text, int offset, const QStringList &captures) const = 0; - static Rule::Ptr create(QStringView name); - -protected: - virtual bool doLoad(QXmlStreamReader &reader); - - bool isWordDelimiter(QChar c) const; - - void loadAdditionalWordDelimiters(QXmlStreamReader &reader); + static Rule::Ptr create(DefinitionData &def, const HighlightingContextData::Rule &ruleData, QStringView lookupContextName); private: Q_DISABLE_COPY(Rule) - DefinitionRef m_def; - QString m_attribute; + bool resolveCommon(DefinitionData &def, const HighlightingContextData::Rule &ruleData, QStringView lookupContextName); + + enum class Type : quint8 { + OtherRule, + LineContinue, + IncludeRules, + }; + Format m_attributeFormat; ContextSwitch m_context; int m_column = -1; FoldingRegion m_beginRegion; FoldingRegion m_endRegion; + Type m_type; bool m_firstNonSpace = false; bool m_lookAhead = false; - // cache for DefinitionData::wordDelimiters, is accessed VERY often - WordDelimiters *m_wordDelimiters = nullptr; - - QString m_additionalDeliminator; - QString m_weakDeliminator; - protected: bool m_dynamic = false; }; class AnyChar final : public Rule { +public: + AnyChar(const HighlightingContextData::Rule::AnyChar &data); + protected: - bool doLoad(QXmlStreamReader &reader) override; MatchResult doMatch(QStringView text, int offset, const QStringList &) const override; private: @@ -133,20 +129,24 @@ private: class DetectChar final : public Rule { +public: + DetectChar(const HighlightingContextData::Rule::DetectChar &data); + protected: - bool doLoad(QXmlStreamReader &reader) override; - MatchResult doMatch(QStringView text, int offset, const QStringList &captures) const override; + MatchResult doMatch(QStringView text, int offset, const QStringList &) const override; private: QChar m_char; int m_captureIndex = 0; }; -class Detect2Char final : public Rule +class Detect2Chars final : public Rule { +public: + Detect2Chars(const HighlightingContextData::Rule::Detect2Chars &data); + protected: - bool doLoad(QXmlStreamReader &reader) override; - MatchResult doMatch(QStringView text, int offset, const QStringList &captures) const override; + MatchResult doMatch(QStringView text, int offset, const QStringList &) const override; private: QChar m_char1; @@ -167,33 +167,49 @@ protected: class Float final : public Rule { +public: + Float(DefinitionData &def, const HighlightingContextData::Rule::Float &data); + protected: - bool doLoad(QXmlStreamReader &reader) override; MatchResult doMatch(QStringView text, int offset, const QStringList &) const override; + +private: + WordDelimiters m_wordDelimiters; }; class IncludeRules final : public Rule { public: - QString contextName() const; - QString definitionName() const; - bool includeAttribute() const; + IncludeRules(const HighlightingContextData::Rule::IncludeRules &data); + + const QString &contextName() const + { + return m_contextName; + } + + bool includeAttribute() const + { + return m_includeAttribute; + } protected: - bool doLoad(QXmlStreamReader &reader) override; MatchResult doMatch(QStringView text, int offset, const QStringList &) const override; private: QString m_contextName; - QString m_defName; bool m_includeAttribute; }; class Int final : public Rule { +public: + Int(DefinitionData &def, const HighlightingContextData::Rule::Int &data); + protected: - bool doLoad(QXmlStreamReader &reader) override; - MatchResult doMatch(QStringView text, int offset, const QStringList &captures) const override; + MatchResult doMatch(QStringView text, int offset, const QStringList &) const override; + +private: + WordDelimiters m_wordDelimiters; }; class HlCChar final : public Rule @@ -204,16 +220,26 @@ protected: class HlCHex final : public Rule { +public: + HlCHex(DefinitionData &def, const HighlightingContextData::Rule::HlCHex &data); + protected: - bool doLoad(QXmlStreamReader &reader) override; MatchResult doMatch(QStringView text, int offset, const QStringList &) const override; + +private: + WordDelimiters m_wordDelimiters; }; class HlCOct final : public Rule { +public: + HlCOct(DefinitionData &def, const HighlightingContextData::Rule::HlCOct &data); + protected: - bool doLoad(QXmlStreamReader &reader) override; MatchResult doMatch(QStringView text, int offset, const QStringList &) const override; + +private: + WordDelimiters m_wordDelimiters; }; class HlCStringChar final : public Rule @@ -224,20 +250,26 @@ protected: class KeywordListRule final : public Rule { +public: + KeywordListRule(const KeywordList &keywordList, DefinitionData &def, const HighlightingContextData::Rule::Keyword &data); + + static Rule::Ptr create(DefinitionData &def, const HighlightingContextData::Rule::Keyword &data, QStringView lookupContextName); + protected: - bool doLoad(QXmlStreamReader &reader) override; MatchResult doMatch(QStringView text, int offset, const QStringList &) const override; private: - KeywordList *m_keywordList; - bool m_hasCaseSensitivityOverride; - Qt::CaseSensitivity m_caseSensitivityOverride; + WordDelimiters m_wordDelimiters; + const KeywordList &m_keywordList; + Qt::CaseSensitivity m_caseSensitivity; }; class LineContinue final : public Rule { +public: + LineContinue(const HighlightingContextData::Rule::LineContinue &data); + protected: - bool doLoad(QXmlStreamReader &reader) override; MatchResult doMatch(QStringView text, int offset, const QStringList &) const override; private: @@ -246,8 +278,10 @@ private: class RangeDetect final : public Rule { +public: + RangeDetect(const HighlightingContextData::Rule::RangeDetect &data); + protected: - bool doLoad(QXmlStreamReader &reader) override; MatchResult doMatch(QStringView text, int offset, const QStringList &) const override; private: @@ -257,10 +291,12 @@ private: class RegExpr final : public Rule { +public: + RegExpr(const HighlightingContextData::Rule::RegExpr &data); + protected: + MatchResult doMatch(QStringView text, int offset, const QStringList &) const override; void resolvePostProcessing() override; - bool doLoad(QXmlStreamReader &reader) override; - MatchResult doMatch(QStringView text, int offset, const QStringList &captures) const override; private: QRegularExpression m_regexp; @@ -269,9 +305,24 @@ private: class StringDetect final : public Rule { +public: + StringDetect(const HighlightingContextData::Rule::StringDetect &data); + protected: - bool doLoad(QXmlStreamReader &reader) override; - MatchResult doMatch(QStringView text, int offset, const QStringList &captures) const override; + MatchResult doMatch(QStringView text, int offset, const QStringList &) const override; + +private: + QString m_string; + Qt::CaseSensitivity m_caseSensitivity; +}; + +class DynamicStringDetect final : public Rule +{ +public: + DynamicStringDetect(const HighlightingContextData::Rule::StringDetect &data); + +protected: + MatchResult doMatch(QStringView text, int offset, const QStringList &) const override; private: QString m_string; @@ -280,11 +331,14 @@ private: class WordDetect final : public Rule { +public: + WordDetect(DefinitionData &def, const HighlightingContextData::Rule::WordDetect &data); + protected: - bool doLoad(QXmlStreamReader &reader) override; - MatchResult doMatch(QStringView text, int offset, const QStringList &captures) const override; + MatchResult doMatch(QStringView text, int offset, const QStringList &) const override; private: + WordDelimiters m_wordDelimiters; QString m_word; Qt::CaseSensitivity m_caseSensitivity; }; diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/wildcardmatcher.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/wildcardmatcher.cpp index 98daff19d6e..ab62f88b7e3 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/wildcardmatcher.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/wildcardmatcher.cpp @@ -9,7 +9,6 @@ using namespace KSyntaxHighlighting; #include -#include namespace { diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters.cpp index f9079ea1f3d..c5401a57cc9 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters.cpp @@ -12,15 +12,14 @@ WordDelimiters::WordDelimiters() : asciiDelimiters{} { for (const char *p = "\t !%&()*+,-./:;<=>?[\\]^{|}~"; *p; ++p) { - // int(*p) fix -Wchar-subscripts - asciiDelimiters[int(*p)] = true; + asciiDelimiters.set(*p); } } bool WordDelimiters::contains(QChar c) const { if (c.unicode() < 128) { - return asciiDelimiters[c.unicode()]; + return asciiDelimiters.test(c.unicode()); } // perf tells contains is MUCH faster than binary search here, very short array return notAsciiDelimiters.contains(c); @@ -30,7 +29,7 @@ void WordDelimiters::append(QStringView s) { for (QChar c : s) { if (c.unicode() < 128) { - asciiDelimiters[c.unicode()] = true; + asciiDelimiters.set(c.unicode()); } else { notAsciiDelimiters.append(c); } @@ -41,7 +40,7 @@ void WordDelimiters::remove(QStringView s) { for (QChar c : s) { if (c.unicode() < 128) { - asciiDelimiters[c.unicode()] = false; + asciiDelimiters.set(c.unicode(), false); } else { notAsciiDelimiters.remove(c); } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters_p.h index c1afaaa6bb0..ccad679a4ef 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters_p.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters_p.h @@ -9,6 +9,8 @@ #include +#include + namespace KSyntaxHighlighting { /** @@ -44,7 +46,7 @@ private: * An array which represents ascii characters for very fast lookup. * The character is used as an index and the value @c true indicates a word delimiter. */ - bool asciiDelimiters[128]; + std::bitset<128> asciiDelimiters; /** * Contains characters that are not ascii and is empty for most syntax definition. From 4c7a5b07c109f0eecc02d3b6e9e48830d87f1b26 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 10 Feb 2022 12:00:00 +0100 Subject: [PATCH 90/94] Docker: Fix and enable open shell in container So far this had been restricted to Unix, but it works on all platforms. Change-Id: I578623341c906eca80a0dbc5fcc9b15e820d3597 Reviewed-by: David Schulz --- src/plugins/docker/dockerdevice.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index 7652ef935f8..4cff9e89a84 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -551,11 +551,9 @@ DockerDevice::DockerDevice(const DockerDeviceData &data) proc->start(); }); - if (HostOsInfo::isAnyUnixHost()) { - addDeviceAction({tr("Open Shell in Container"), [this](const IDevice::Ptr &device, QWidget *) { - device->openTerminal(Environment(), FilePath()); - }}); - } + addDeviceAction({tr("Open Shell in Container"), [](const IDevice::Ptr &device, QWidget *) { + device->openTerminal(device->systemEnvironment(), FilePath()); + }}); } DockerDevice::~DockerDevice() From 9e0b7a0d601e9b2b354980a11106fc0ee1f693cf Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Tue, 8 Feb 2022 19:11:09 +0100 Subject: [PATCH 91/94] QmlDesigner: Do not update instantly after creating component If the update happens instantly the new component is not parsed in sone cases, yet. Change-Id: Ib43fc5e3dfd2e14f87a9e4fb46b1e2ba720768a5 Reviewed-by: Qt CI Bot Reviewed-by: Thomas Hartmann --- src/plugins/qmldesigner/designercore/model/rewriterview.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/plugins/qmldesigner/designercore/model/rewriterview.cpp b/src/plugins/qmldesigner/designercore/model/rewriterview.cpp index 1f730ce0f6d..a988fe26a30 100644 --- a/src/plugins/qmldesigner/designercore/model/rewriterview.cpp +++ b/src/plugins/qmldesigner/designercore/model/rewriterview.cpp @@ -1041,12 +1041,9 @@ void RewriterView::moveToComponent(const ModelNode &modelNode) { int offset = nodeOffset(modelNode); - bool instant = m_instantQmlTextUpdate; - m_instantQmlTextUpdate = true; textModifier()->moveToComponent(offset); - m_instantQmlTextUpdate = instant; } QStringList RewriterView::autoComplete(const QString &text, int pos, bool explicitComplete) From 756a67c5638312cb00a6af238675495986f47ebb Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Thu, 10 Feb 2022 14:34:29 +0100 Subject: [PATCH 92/94] Doc: Update CMake build settings - Describe context menu options for syncing configurations - Describe options for getting help on variables and options Task-number: QTCREATORBUG-26983 Change-Id: Ide88172bc2e8032434ee657a9995528b6917a871 Reviewed-by: Cristian Adam --- ...qtcreator-cmake-build-settings-initial.png | Bin 22943 -> 22319 bytes .../qtcreator-cmake-kit-configuration.png | Bin 7645 -> 7531 bytes .../creator-projects-cmake-building.qdoc | 21 +++++++++++------- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/doc/qtcreator/images/qtcreator-cmake-build-settings-initial.png b/doc/qtcreator/images/qtcreator-cmake-build-settings-initial.png index 90c632411b35078c3c01bc600ba0afe14aeefaf3..ca0dbd741b3f9100aa713bc1c5241b19e95a9a7c 100644 GIT binary patch literal 22319 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 z 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 gkzopr0Jp)NLjV8( diff --git a/doc/qtcreator/images/qtcreator-cmake-kit-configuration.png b/doc/qtcreator/images/qtcreator-cmake-kit-configuration.png index 6a305822caf858993b0805a9d1fa4af3ab3dfe99..d6dd2f6ed10078441b5cb40bbb69c781dfbdfbed 100644 GIT binary patch literal 7531 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 URjo*6U|?YIboFyt=akR{0HS`)<^TWy literal 7645 zcmeAS@N?(olHy`uVBq!ia0y~yVA{>Vz|h6P#K6FyxDRT8=%cweM=}Ytx>cId`Vc zu2g6K%gf7m*Wa!E_1*Ta?dI9f7#SECPTf%X_uHOGZP&f*N|IOC;R(6%?Eg=R3RS+l6lX--o`}e?Kh$_n&(F->cg1|DJ1awXpd0OF916 z(fxlul-rB7TL{YMc0D|`(s%pZdSlD_&wp}fo6X%N^xvMpM9|&O<8jxLN4Ir9#;iQK zlRfEKbnA|ui@lC!+q`o-y^lq&+V%S?D+9w`SB+--ABXKPxip(@*pzhR&r8{8yV}p{ z`+whAz5m~{!}n*+uljnV+rIkc)A;>mKen>}|E6C5|5^V3$F}$XEfC=94fpq{d%Ppw z@W!6)hZm<`Qu<%<&r2$D!LjqPCFUZ{w)eBD9$uL`D{3e2*UN1&8eRI5!7FF}I;Y3L z@Zm+X!%l%E68Ap+IU)W(`>XK%pS$hr3QMksFMA%{U;lf1{=VP$@Bcq<|ND`6-9D?2 zy~+1NJFm#QoICo+d+ohLg64fSucl~8y4+Y9ynNSUiI|_?IzO+zxjAZ$xT9y^)LEQI z85j%<7AeN)v1qo<)xY!clzx2ur>m}odVMor^KY;F{LFp-@9@?8e|-A<|L@LCwLBZ` zE!JDM9`RJU%zTVx$7SKC*tNCcdz$Xt6MiBtS`zt`K>|9mE%_y4u|yvoPd?`Q2P z`Lpc&eZ#L_H_y30O})NaV$W}hM<+Ha@19hhbh-8v_lJ!s6RsQ1d4H!b`}HD;H`_{_ z4MS$6WaP^?2QyB&-I~O}@M2-ihPpQ%h8>Tmi60B!_rL%C@B8w9etfqVJ^p*&H*uv8 z{`2K?>)snH1=Q^R^fkWr^OfuO%708{xBch*%WFZrp~U^gQ}$^qo>zSle1FrTfXmn4 zmHd)V-}fnGXFa1*L8#NGUf0emNme<9s&Qf4imt4hxS!)v5)_I$AABiX{VKMsTTe@D?R_i-a;|HBR5uO>|1?G_|~-b>0PIv z^|yXB7Mhihy*QJOmU=lAKl9Ho+u zxjV{com`WvloTbV%tt}sl^J^we<0v?>^>3WB?$W32 zGZ`2b#2!tsoxrWQ;iWtSLtB`k!}hqVhwCdO85kIjf{G*bk_x*ho2y|CI|BnlK{KKZ zTOa|_kJS)xamRpcbfWUc+}qo9qqp5*U|`s)*miSm^!8oH9`1erHzoPuuZ7R+ERVDs z6nw9?>r0Zz*{SePR$hMoym|Y$85pu0cs3->INKf*toNq=QR_=(^}hKvPu~5$Z#t#j zz*oZJ>k<36KR^2~kYE#4tai1(w>|&7*H=&1)r!&K5@OsgbuSI{)yo`f;`8 z?LP$AxQtsjYP31Jo|!6ZQ}H2}fg!*+X@jWqI!nH8$={E^+nJaZ7QEn3TxKA4)Zjpu zqtEn@D$ER5dL?pVyB^-C<$pid!s1K2f$&j-55+wBtPBmaKAtg@+5LUt-f}sKUymh< zc|ab25n%Xc=jQ_#(q=!}W0~DO z{g{Ek_8oeWi?UkoMH())3*lksliA_=?2K0!yLNisOI!Ep>(YM4$6C!2KcV3*qu-mT zkXIP{s_Nq>nXO7(OgpKbN1w<(+buFEMSqsPh^ouG|X| z5i@-EZgMC+)4BM4Q__nw-}xsdb-3Nm@vz;srDWOm!>Moly98}@9j5GaIIC1xXR66| z{Oz|#J8J?bcARhh8f91#l`J;>_TjM4Aw?CUR}>@zcrI*A+VQ;cZn+PujFVx^{<6Qn zezI>l5Vk}@ZU)rua#80c;yo){u4tRjUX>z{cs5P==!Ka{H}=>6KR4&+)N8jcO`JP5 znVtUPy^Gdyx z*I!O}uA8`hrv4%|#Y`zz#Y-ALm;UJ5o3QHaQPIPTiq6lNqNF)B-f&5siSI6rNmEM1 zc5K^{viEdejt6hF%C97=H@A%YRXimxetTQ>;Lui+bFDU8Z8n5Hx$#f&%$sdV8?5hMkrtn%*qd3E z8L81B9NFwKF@5&7nkQG3<_11d?c|Ssz@Xi>a^=d|qG@7}A7)kR{WIAn%rEWv3F;varOPID%Es0 z?NW_U_es-Yq`kO;9?!^}c0FDC@7Z5H9lt-V;(EFILiwAUo1d>-K2NB~@sIYowS`9# zUI+2G_uaR*+NS@Yjcy06#3mXZ(q6};(BS*GIQ^oWDONpHCYkC1$ogv+w462VrIz|oH6oP zxl+}0^JX@_AFEmxN^sqrU^z8MLA&kQw5z6RNzP?ne71>Ie3g5)_MM(te2Qxc&zi_- zM>+PXRWo@XTr=;=YKb>Ti+={)w0&-#RT`=?Lu#o-LVMH4sn?D0b=o@T z)tOV*)D)ah*uH7=6#E5s)-Us~c~9D=`EvDz`->i)RG(jRveoElK~YJL(F2c|A1P`g zYRNAZTDvX!W6xFj3n|5Zaycz@rFdd>vWm5uwPnl9y|<4GR6mU{I`b@8aMC0VF}bdv z4IV}(UQ3i&HYF8gv{h{JI#%;G)kyMMiTs6oKcXK^{yd{l@Y$!L6MlO2y3^xMU0?FV z=HI=#-9NL$H6(NLXI{IN;cqx)$~Nt;gGo!T+?h4=^@XfHuXD-Mwb)9ZEzatH8&!YV zboFiz1C5R<2fO?z=I4zKA;i{M}`L?<9+_i`!k$FH`sFP^e+|2J`NMpnXTB z-=@r)Vj5KrDzx@%FRbkk`n9gbX1YRcKsZa!QKq+k>+`>_@lsj7?f_%l)C?0T>!N33 z;^~t%muxe$jg5|ri$1OQ_C)d#$CDnj?#(|l-+SYh)z^wO^Gx!@Bz4ZMG~67Sq}uwY zD)5Pk$L`A~{B=7DcdIUow9#GXq0*b^>#}~eN!}xsD+k`(y|;ofKJ%~X8_tRTZ$zh> zZclqwwPjY&$sm2*R~O=qi@1X9`QL2JopvYq@Wuwu|6jj_N)#MPcpb*`z4y&r4huV> z-=BWi%v0I%>&s!U9UMI}|6Sg^nLOi?uIj}jC9WcG=cR-yai7_Afh%F&6!}AEr0V(| zAS&+dGRoz3eOASvqG;ZoggS`tQ-pvL}68Lkv%>^lXg$x=vT`md*U*H`Zye zEnd{~%}-cywJcD2Elu7@8sR_EU? zPCp>H^ZD|3-sj}2Ufp{7{pCX?gPZ#*em>f&;{#D_qiYCcZ#k4_D(8DENzhlTeP8%pWnR~PcGcds498;W});#brsQh=iKKn zvtwxE09z32?!Tw@`j1_5{C1%=`j0Lx{`y4ejEf=9#v}%YhF_wGC+@z#?{(io`<9s+ zZH#H3pPgO2cyV%avdtL=hOdfkk%l+A6tBy)f3JP>>c_s9wd`qmvU_Vg_!ARSo*iGe zNP=yuZuGXC+uL$eQc{wVl7wJQ9nt2u*Vaa#Ev&fyX0x#TE|onmznm%jC}sy~?tFZB zdiVXmJY9(mg0>MS?nyH+EHFD_kUf=~bNBtvg&#l3<~GXQbC!@$5)a^EU|H_kV>zwOdvLHh|26}M@!I-sZjf4mB@#!L{B;Z9IphOs z0XeuA^W@)UFgOnG2|IxL#tS5VMHrfhg+*(w=I+%<*`|4J_U3IBnLNye-LHjs1kx_2 z>q?vM-`)8)eC^H^wd!|G$8iSCpW?VmtiejO z+1o&+D={vn_r%s_4qwmwuEn}b7q%X;m~?+fh(^E8hSc*LIr#8ScoaOW9qz zW4dX_qmnDPyE;=d^IIh2r7XIv-(2LeUX#D>QcIbkwBFr&%tt5m^#96uvFS?Otp=-` z_uk!jeSw{~U1Q6%g@5Ln7K9$U+HsI~mPn}9Ru#`#o7WkA%amr7%;P>YPw4eGk*AhM zPwz97#x?{TH83?TEmkn@&d%;Op2l5#dg9@Jeb?oui+^2x6jimcBWzCRlcgb><~*DB zwld6R#?8}~ZB9Wci+in>Y3NtK{I&h7s&oC_oEvI;bwB3TEmE1aH{p_uTOeO|pzW*} zgU!W}uk_b0_w#D2{Qjl?))B9-zy5Ato^P@0;HR{guVclI3dFgFPBZ(pwAZHV;H>rg z4Q}mwdg*ya!YbAUX-5~VX7m+)anA1b**3lt=S4-8SWlgAGCf}!#&fTh=cdoHJ*#s2 zICg&SkAL$-x7g3}Q6Nv=dr^tAaU1M{c={G@_?&os%`27ZtCpR7ss1u7glC$X#_WXh zZ!FQu*Vaq?+S+Rs%rh%gwg0w4S!{!pNOQ1}#S#a@@(XQAFWP)o1RF{O*Iz1EJ(C%m z+O|1DI`mk{TfgJZ@1v$>NOp^doqy8zOm9Z6-gP7WTen}b?KjreUc27U=APA_ke}KK zqDK=lo4UFd?h$O3-tuM7pS`>4Z)qGUs84(nb9mlj$5*=;7IrPXnDK@~JvQQm-8mh- zbE*puU4Cx(=(CMZ(f^Y(b#L{hgeJL51#+EPEcNm1l~aOg*FIG9d^)lq)iv_ouADcE zwDtuqjJxzb>ZaQMT5I{ctA$iAo@q*rd}%G8tGWL6cP%en-Qvc1tKPX7-Y}o_BV4sd zZNrsS;f7O87G*OhEUj#HIJ!YD_lZu>%7^z3&G;SI`$=T#o%X9t8{)bYi{Bj0I?Oj+ z|ZU1 z(~l+{d0BNyERAn=(g&T`0}Yl|&u1IT2^?f-NZL?f71d=?Epar!YU2TyCleODDP>@I zQGV3G(z5b#RndzzTmBU6+LqHY^N*?)14F~XP##+*P`P%&Znk;8oUE*@w6t{IP6Zy3 zG_K@8P+9wSL+a^ixwp6V_VoDp`1tT?9x_Q>U{L(}+FDSDu)$2QE@V&5eS<3;%+61k zz{PSCxEN#rv%$qR(hwoIh-Q=h=*;>kT(a%=?Wu|2LJ2!&OKh-fk|Do^E`=xtIR|rBnxoiv!4P^qx-`M%(YHqVR%s3gph>3wABi^vX z^LOt8iI$mQjeXA~?(Jes=mQN@9tFF=!SKt*qzs)k+k(Qxr2iw8+ru-jY0MMy&AVe!RT8S% zH}O@OH_O)kl=(3)BX%#1IrnAp@~E7)8I?0*uV+UUUR=?tR37eja^+2dEXgO|v|ra& z-m%$hBfWF$9@)iVPHt_N_FXx>sgg^^Naly!D?hf|QuDl?I&Lftzt1t{>*qIJPcQPF zj50s_*I_1q=4|E71&cua=A}}g?lSAHT_q-5mYXNd{i=KDOrADdvPa2^lOt;ogSW96tl)^ z!IJ1G@6_|>vOVUwzT4l-zW9;e+RMARgH0ONNVr&^kd4ren0O`U^8K^vvnx&2)E||( zhkq>Zu}UrMNLsOy;op?iT5P`kq17v_rE;<>w3hZgd$n%qdDlScZSK}8*{d@d{mb=5 zo!1~L9)34e z^V|)eq)t2*YdmXxbelF?zv8RPsRvI~9u1bTRL<0yH`ROE@s+&F<@5qpqxp%Q+wOBD>}Ny-#Vn^M1EIJTEruSV&Uo(FrPh zUdcZ8+LijieY+y>=eH|z41%opB_F$LdpzLI>OFfSl|rvy`n0NLnRrQJ+ItE4P^&$L zS92?8rCt7@;{KeaymjKiPYN&mC#M=*Y&xSJTRlxSb@th_IX9kF+hp5?%Dv)ayM1e( z*KCUo=VDqk*iJ8&owW7pmbxHNhhC$tvd~oNI-in>>R!#hZByFBgdTg;Jq}uEv+2Mz z+v9ZsJom)ak{6x4oO81CPlU$a3!lC{kI&X%>nh`TwtLmgv$mdan|;-wbpDW1SyyvxI@N$qYwOE@cHT~%k|B zyY*C4^ZuVzk8kbLVB4+xRin-B#_cB-`VmsyH9ZHwpTMguUMt=ea-Eg@m8^`h2Cx2x>IYR{r7vm@AmQB z`Oaqkx@@`s*7xiAWM^-&EWbW2C;WSW&*$2kItM0X74x|2M@*3I`OTfmXf6NseUO)F zPW{i%YrLLFOKj<#@Jl-(;J8NQ)DK#1X6|g$wS)HcXPtAge7;P}=4H{|+1YN_)bEjX%33Dt>7>Y~i-|v<6!7rn zXNixMa$-CGKRF|o>%K{AqjIkX>$AY#A8A=nIgGP^*s`6TzTfm^?yG$@y{7k{td6^6 zuD$h5(%qN|T1|wqDr9tCe$s=Sp^;spVDokm~m( zccL$?c{jbb_S3aLvMrm|$EW|ka3!%xr7ynyw z`uwK7IUo5lj=wLyVXPa<<7j_ez~aWW4WO6sYwwU(S-_s$Ob?$c7u7g`e4*f8wV0MbvY`c6h=*Z2(8f~RD z!pD;tzvQiBO1SV$LQP#gKgOSL?$l}We%Gh<8VG}0C3xaot-BYU1zBAh@|D+-6aY#;DXwr{;uiorQ4(u6FMNX zk`4l(wgSF6O|XTK=>u>hf&tX)W4N*mJWcTDk9`ue-RJ!RbAN+o4Ln`_T-G@yGywoO CM{bV* diff --git a/doc/qtcreator/src/cmake/creator-projects-cmake-building.qdoc b/doc/qtcreator/src/cmake/creator-projects-cmake-building.qdoc index 8b72312a817..2932e1c9d81 100644 --- a/doc/qtcreator/src/cmake/creator-projects-cmake-building.qdoc +++ b/doc/qtcreator/src/cmake/creator-projects-cmake-building.qdoc @@ -41,15 +41,16 @@ You can view and edit the actual values of the variables that are passed to CMake. Variable names are listed in the \uicontrol Key column and their - current values in the \uicontrol Value column. For more information - about the available variables, see \l{CMake: cmake-variables(7)}. - For more information about Qt-specific variables, see - \l{CMake Variable Reference}. + current values in the \uicontrol Value column. For more information about + the available variables, select \uicontrol Help in the context menu or see + \l{CMake: cmake-variables(7)}. For more information about Qt-specific + variables, see \l{CMake Variable Reference}. You can specify additional CMake options, such as \c {--find-debug}, \c {--preset}, \c {--trace-expand}, or \c {--warn-uninitialized}, in \uicontrol {Additional CMake options}. For more information about - the available options, see \l{CMake: cmake(1)}. + the available options, click the link in the field name or see + \l{CMake: cmake(1)}. After successfully running CMake, you can view and modify the current configuration in \uicontrol {Current Configuration}. @@ -97,7 +98,10 @@ select \uicontrol Copy in the context menu. To modify the value of a variable, double-click it, or select it, - and then select \uicontrol Edit. + and then select \uicontrol Edit. If the initial, current, and kit + configuration get out of sync, select \uicontrol {Apply Kit Value} or + \uicontrol {Apply Initial Configuration Value} in the context menu in + \uicontrol {Initial Configuration} or \uicontrol {Current Configuration}. You can apply actions to multiple variables at a time. To clear the selection, select \uicontrol {Clear Selection}. @@ -194,8 +198,9 @@ \image qtcreator-cmake-generator.png "CMake Generator dialog" \li In \uicontrol Generator, select \uicontrol Ninja. \li Select \uicontrol OK to save your changes and close the dialog. - \li Close the \uicontrol {Kit CMake Configuration} dialog to return to - \uicontrol {Build Settings}. + \li Select \uicontrol Close to close the + \uicontrol {Kit CMake Configuration} dialog + and return to \uicontrol {Build Settings}. \endlist \note To make sure that old build artifacts don't get in the way From ce27886eebe9809afcdc49a17806e8c3a81d585e Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 10 Feb 2022 14:01:14 +0100 Subject: [PATCH 93/94] ClangCodeModel: Fix dot-to-arrow completion with extra characters We failed to overwrite existing characters that match the completion if clangd also changes "." to "->" at the same time. Note that it still doesn't work as expected if the cursor is after the dot and before the extra character. I'm not sure yet how to fix that. Fixes: QTCREATORBUG-27034 Change-Id: I852145fc41f34ab60d9e944783e822bc9505453b Reviewed-by: Reviewed-by: Qt CI Bot Reviewed-by: David Schulz --- src/plugins/clangcodemodel/clangdclient.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index 5988d04d40d..c3240846904 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -3230,7 +3230,8 @@ void ClangdCompletionItem::apply(TextDocumentManipulatorInterface &manipulator, QTextCursor cursor = manipulator.textCursorAt(rangeStart); cursor.movePosition(QTextCursor::EndOfWord); const QString textAfterCursor = manipulator.textAt(currentPos, cursor.position() - currentPos); - if (textToBeInserted != textAfterCursor + if (currentPos < cursor.position() + && textToBeInserted != textAfterCursor && textToBeInserted.indexOf(textAfterCursor, currentPos - rangeStart) >= 0) { currentPos = cursor.position(); } From b0d572789b4b1d845b6d53eb2978a28b07e3ef7b Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Mon, 31 Jan 2022 11:29:46 +0200 Subject: [PATCH 94/94] Git: Fix assertion when upstream branch no longer exists MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I5033d43571026ab0d9b8b94892b4075e130211be Reviewed-by: André Hartmann --- src/plugins/git/branchmodel.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/git/branchmodel.cpp b/src/plugins/git/branchmodel.cpp index b6217011c28..0bc75d7813f 100644 --- a/src/plugins/git/branchmodel.cpp +++ b/src/plugins/git/branchmodel.cpp @@ -911,6 +911,8 @@ void BranchModel::updateUpstreamStatus(BranchNode *node) VcsCommand *command = d->client->asyncUpstreamStatus( d->workingDirectory, node->fullRef(), node->tracking); QObject::connect(command, &VcsCommand::stdOutText, node, [this, node](const QString &text) { + if (text.isEmpty()) + return; const QStringList split = text.trimmed().split('\t'); QTC_ASSERT(split.size() == 2, return);