summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--CMakeLists.txt37
-rw-r--r--README.md6
-rw-r--r--cmake/FindQt5.cmake2
-rw-r--r--cmake/QtCreatorAPI.cmake613
-rw-r--r--cmake/QtCreatorAPIInternal.cmake449
-rw-r--r--cmake/QtCreatorDocumentation.cmake285
-rw-r--r--cmake/QtCreatorIDEBranding.cmake7
-rw-r--r--doc/CMakeLists.txt287
-rw-r--r--doc/qtcreator/config/qtcreator-project.qdocconf2
-rw-r--r--doc/qtcreator/src/cmake/creator-projects-cmake.qdoc10
-rw-r--r--doc/qtcreator/src/editors/creator-code-refactoring.qdoc11
-rw-r--r--doc/qtcreator/src/editors/creator-only/creator-code-pasting.qdoc3
-rw-r--r--doc/qtcreator/src/howto/creator-only/creator-autotest.qdoc83
-rw-r--r--doc/qtcreator/src/projects/creator-only/creator-projects-creating.qdoc6
-rw-r--r--doc/qtcreator/src/projects/creator-only/creator-projects-custom-wizards-json.qdocinc12
-rw-r--r--doc/qtcreatordev/config/qtcreator-developer.qdocconf2
-rw-r--r--qbs/imports/QtcProduct.qbs2
-rw-r--r--qbs/modules/libclang/functions.js20
-rw-r--r--qbs/modules/libclang/libclang.qbs3
-rw-r--r--qbs/modules/qtc/qtc.qbs6
-rw-r--r--qtcreator.pro14
-rw-r--r--qtcreator_ide_branding.pri7
-rwxr-xr-xscripts/build.py11
-rwxr-xr-xscripts/build_plugin.py14
-rw-r--r--share/qtcreator/CMakeLists.txt19
-rw-r--r--share/qtcreator/debugger/creatortypes.py35
-rw-r--r--share/qtcreator/debugger/lldbbridge.py135
-rw-r--r--share/qtcreator/debugger/utils.py22
-rw-r--r--share/qtcreator/modeleditor/standard.def22
-rw-r--r--share/qtcreator/qml-type-descriptions/builtins.qmltypes6
-rw-r--r--share/qtcreator/qml/qmlpuppet/commands/inputeventcommand.cpp4
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/AxisHelper.qml2
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/EditCameraController.qml5
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml2
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/IconRenderer3D.qml2
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp6
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h5
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/icongizmoimageprovider.cpp3
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/iconrenderer/iconrenderer.cpp2
-rw-r--r--share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml2
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/AdvancedSection.qml62
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/AnimatedImageSpecifics.qml95
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/BorderImageSpecifics.qml68
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/GridSpecifics.qml25
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/ImageSpecifics.qml132
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/MouseAreaSpecifics.qml193
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/TextInputSection.qml13
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FlickableSection.qml60
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontSection.qml31
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/StandardTextSection.qml72
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Constants.qml96
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml131
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttfbin10568 -> 11448 bytes
-rwxr-xr-xshare/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/qmldir2
-rw-r--r--share/qtcreator/qmldesigner/statesEditorQmlSources/StatesDelegate.qml18
-rw-r--r--share/qtcreator/templates/wizards/autotest/files/catch2_tst.cpp6
-rw-r--r--share/qtcreator/templates/wizards/autotest/files/tst.pro27
-rw-r--r--share/qtcreator/templates/wizards/autotest/files/tst.qbs35
-rw-r--r--share/qtcreator/templates/wizards/autotest/files/tst.txt24
-rw-r--r--share/qtcreator/templates/wizards/autotest/files/tst_main.cpp17
-rw-r--r--share/qtcreator/templates/wizards/autotest/wizard.json31
-rw-r--r--share/qtcreator/templates/wizards/classes/cpp/file.h1
-rw-r--r--share/qtcreator/templates/wizards/classes/cpp/wizard.json2
-rw-r--r--share/qtcreator/templates/wizards/files/cppheader/wizard.json11
-rw-r--r--share/qtcreator/templates/wizards/files/cppsource/wizard.json11
-rw-r--r--share/qtcreator/templates/wizards/files/glsl/gl/fragment/wizard.json4
-rw-r--r--share/qtcreator/templates/wizards/files/glsl/gl/vertex/wizard.json4
-rw-r--r--share/qtcreator/templates/wizards/files/glsl/gles/fragment/wizard.json4
-rw-r--r--share/qtcreator/templates/wizards/files/glsl/gles/vertex/wizard.json4
-rw-r--r--share/qtcreator/templates/wizards/files/java/wizard.json7
-rw-r--r--share/qtcreator/templates/wizards/files/js/wizard.json4
-rw-r--r--share/qtcreator/templates/wizards/files/nim/wizard.json4
-rw-r--r--share/qtcreator/templates/wizards/files/nimscript/wizard.json4
-rw-r--r--share/qtcreator/templates/wizards/files/python/wizard.json4
-rw-r--r--share/qtcreator/templates/wizards/files/qrc/wizard.json4
-rw-r--r--share/qtcreator/templates/wizards/files/qtquick2/wizard.json4
-rw-r--r--share/qtcreator/templates/wizards/files/scratch/wizard.json3
-rw-r--r--share/qtcreator/templates/wizards/projects/qtforpythonapplication/qtquickapplication/main.qml.tpl2
-rw-r--r--share/qtcreator/templates/wizards/projects/qtquickapplication/empty/main.qml.tpl2
-rw-r--r--share/qtcreator/templates/wizards/projects/qtquickapplication/scroll/main.qml.tpl2
-rw-r--r--share/qtcreator/templates/wizards/projects/qtquickapplication/stack/main.qml.tpl2
-rw-r--r--share/qtcreator/templates/wizards/projects/qtquickapplication/swipe/main.qml.tpl2
-rw-r--r--share/qtcreator/templates/wizards/projects/vcs/git/wizard.json6
-rw-r--r--share/qtcreator/themes/dark.creatortheme6
-rw-r--r--share/qtcreator/themes/default.creatortheme6
-rw-r--r--share/qtcreator/themes/design.creatortheme6
-rw-r--r--share/qtcreator/themes/flat-dark.creatortheme6
-rw-r--r--share/qtcreator/themes/flat-light.creatortheme6
-rw-r--r--share/qtcreator/themes/flat.creatortheme6
-rw-r--r--share/qtcreator/welcomescreen/welcomescreen.qml77
-rw-r--r--share/qtcreator/welcomescreen/welcomescreen.qmlproject18
-rw-r--r--src/CMakeLists.txt9
-rw-r--r--src/app/main.cpp36
-rw-r--r--src/libs/3rdparty/syntax-highlighting/.gitignore3
-rw-r--r--src/libs/3rdparty/syntax-highlighting/CMakeLists.txt11
-rw-r--r--src/libs/3rdparty/syntax-highlighting/KF5SyntaxHighlightingConfig.cmake.in4
-rw-r--r--src/libs/3rdparty/syntax-highlighting/data/CMakeLists.txt20
-rw-r--r--src/libs/3rdparty/syntax-highlighting/data/generators/cmake.xml.tpl7
-rw-r--r--src/libs/3rdparty/syntax-highlighting/data/generators/cmake.yaml211
-rw-r--r--src/libs/3rdparty/syntax-highlighting/data/generators/generate-cmake-syntax.py6
-rw-r--r--src/libs/3rdparty/syntax-highlighting/data/syntax/cmake.xml157
-rw-r--r--src/libs/3rdparty/syntax-highlighting/data/syntax/html.xml74
-rw-r--r--src/libs/3rdparty/syntax-highlighting/data/syntax/makefile.xml27
-rw-r--r--src/libs/3rdparty/syntax-highlighting/data/syntax/markdown.xml10
-rw-r--r--src/libs/3rdparty/syntax-highlighting/data/syntax/modelines.xml14
-rw-r--r--src/libs/3rdparty/syntax-highlighting/data/syntax/perl.xml3
-rw-r--r--src/libs/3rdparty/syntax-highlighting/data/syntax/powershell.xml8
-rw-r--r--src/libs/3rdparty/syntax-highlighting/data/syntax/python.xml37
-rw-r--r--src/libs/3rdparty/syntax-highlighting/data/syntax/xml.xml14
-rw-r--r--src/libs/3rdparty/syntax-highlighting/data/syntax/yacc.xml26
-rw-r--r--src/libs/3rdparty/syntax-highlighting/examples/CMakeLists.txt4
-rw-r--r--src/libs/3rdparty/syntax-highlighting/examples/codeeditor.cpp358
-rw-r--r--src/libs/3rdparty/syntax-highlighting/examples/codeeditor.h69
-rw-r--r--src/libs/3rdparty/syntax-highlighting/examples/main.cpp46
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/cli/kate-syntax-highlighter.cpp29
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/indexer/katehighlightingindexer.cpp107
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/CMakeLists.txt2
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp49
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.h4
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter_p.h6
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/context.cpp39
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/context_p.h13
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/contextswitch.cpp7
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/contextswitch_p.h6
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp416
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/definition.h15
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/definition_p.h14
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.cpp42
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.h4
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/definitionref_p.h7
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/foldingregion.cpp12
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/foldingregion.h6
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/format.cpp35
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/format.h6
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/format_p.h6
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/htmlhighlighter.cpp10
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/htmlhighlighter.h8
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist.cpp49
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist_p.h6
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/matchresult_p.h5
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/repository.cpp24
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/repository.h8
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/repository_p.h6
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/rule.cpp108
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/rule_p.h72
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/state.cpp14
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/state.h6
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/state_p.h5
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.cpp32
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.h6
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/textstyledata_p.h26
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/theme.cpp5
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/theme.h9
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/themedata.cpp7
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/themedata_p.h10
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/wildcardmatcher.cpp8
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/wildcardmatcher_p.h24
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/xml_p.h7
-rw-r--r--src/libs/advanceddockingsystem/CMakeLists.txt2
-rw-r--r--src/libs/advanceddockingsystem/ads_globals.h11
-rw-r--r--src/libs/advanceddockingsystem/dockareatitlebar.cpp5
-rw-r--r--src/libs/advanceddockingsystem/dockmanager.cpp174
-rw-r--r--src/libs/advanceddockingsystem/dockmanager.h45
-rw-r--r--src/libs/advanceddockingsystem/dockwidgettab.cpp16
-rw-r--r--src/libs/advanceddockingsystem/iconprovider.cpp2
-rw-r--r--src/libs/advanceddockingsystem/linux/floatingwidgettitlebar.cpp24
-rw-r--r--src/libs/advanceddockingsystem/workspacedialog.cpp10
-rw-r--r--src/libs/advanceddockingsystem/workspacedialog.ui18
-rw-r--r--src/libs/advanceddockingsystem/workspacemodel.cpp12
-rw-r--r--src/libs/advanceddockingsystem/workspacemodel.h3
-rw-r--r--src/libs/advanceddockingsystem/workspaceview.cpp35
-rw-r--r--src/libs/advanceddockingsystem/workspaceview.h3
-rw-r--r--src/libs/clangsupport/CMakeLists.txt26
-rw-r--r--src/libs/clangsupport/tooltipinfo.h6
-rw-r--r--src/libs/languageserverprotocol/clientcapabilities.cpp8
-rw-r--r--src/libs/languageserverprotocol/clientcapabilities.h24
-rw-r--r--src/libs/languageserverprotocol/jsonkeys.h2
-rw-r--r--src/libs/languageserverprotocol/languagefeatures.cpp54
-rw-r--r--src/libs/languageserverprotocol/languagefeatures.h43
-rw-r--r--src/libs/languageserverprotocol/lsptypes.cpp12
-rw-r--r--src/libs/libs.pro2
-rw-r--r--src/libs/modelinglib/qmt/config/stereotypedefinitionparser.cpp23
-rw-r--r--src/libs/modelinglib/qmt/controller/namecontroller.cpp2
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/diagramscenemodel.cpp2
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/items/classitem.cpp19
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/items/componentitem.cpp37
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/items/diagramitem.cpp25
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/items/itemitem.cpp29
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/items/packageitem.cpp37
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/items/stereotypedisplayvisitor.cpp4
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/parts/customiconitem.cpp23
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/parts/customiconitem.h2
-rw-r--r--src/libs/modelinglib/qmt/diagram_widgets_ui/diagramview.cpp6
-rw-r--r--src/libs/modelinglib/qmt/infrastructure/geometryutilities.cpp73
-rw-r--r--src/libs/modelinglib/qmt/infrastructure/geometryutilities.h6
-rw-r--r--src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.cpp2
-rw-r--r--src/libs/modelinglib/qmt/stereotype/iconshape.cpp5
-rw-r--r--src/libs/modelinglib/qmt/stereotype/iconshape.h1
-rw-r--r--src/libs/modelinglib/qmt/stereotype/shapepaintvisitor.cpp148
-rw-r--r--src/libs/modelinglib/qmt/stereotype/shapepaintvisitor.h29
-rw-r--r--src/libs/modelinglib/qmt/stereotype/stereotypeicon.cpp5
-rw-r--r--src/libs/modelinglib/qmt/stereotype/stereotypeicon.h3
-rw-r--r--src/libs/modelinglib/qmt/tasks/diagramscenecontroller.cpp2
-rw-r--r--src/libs/qmleditorwidgets/fontsizespinbox.cpp5
-rw-r--r--src/libs/qmljs/qmljsdocument.cpp6
-rw-r--r--src/libs/qmljs/qmljsdocument.h9
-rw-r--r--src/libs/qmljs/qmljslink.cpp50
-rw-r--r--src/libs/qmljs/qmljsmodelmanagerinterface.cpp48
-rw-r--r--src/libs/qmljs/qmljsmodelmanagerinterface.h7
-rw-r--r--src/libs/qmljs/qmljsplugindumper.cpp341
-rw-r--r--src/libs/qmljs/qmljsplugindumper.h37
-rw-r--r--src/libs/qtcreatorcdbext/CMakeLists.txt2
-rw-r--r--src/libs/qtcreatorcdbext/extensioncontext.h4
-rw-r--r--src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp132
-rw-r--r--src/libs/qtcreatorcdbext/symbolgroup.cpp2
-rw-r--r--src/libs/sqlite/CMakeLists.txt1
-rw-r--r--src/libs/sqlite/sqlite-lib.pri1
-rw-r--r--src/libs/sqlite/sqlitebasestatement.cpp43
-rw-r--r--src/libs/sqlite/sqlitebasestatement.h42
-rw-r--r--src/libs/sqlite/sqliteexception.h8
-rw-r--r--src/libs/sqlite/sqlitevalue.h300
-rw-r--r--src/libs/ssh/sshprocess.cpp8
-rw-r--r--src/libs/ssh/sshprocess.h2
-rw-r--r--src/libs/utils/CMakeLists.txt7
-rw-r--r--src/libs/utils/ansiescapecodehandler.cpp45
-rw-r--r--src/libs/utils/ansiescapecodehandler.h2
-rw-r--r--src/libs/utils/categorysortfiltermodel.cpp6
-rw-r--r--src/libs/utils/checkablemessagebox.cpp45
-rw-r--r--src/libs/utils/checkablemessagebox.h3
-rw-r--r--src/libs/utils/consoleprocess.cpp5
-rw-r--r--src/libs/utils/consoleprocess.h1
-rw-r--r--src/libs/utils/delegates.cpp2
-rw-r--r--src/libs/utils/environmentdialog.cpp2
-rw-r--r--src/libs/utils/fileutils.cpp11
-rw-r--r--src/libs/utils/fileutils.h2
-rw-r--r--src/libs/utils/filewizardpage.cpp15
-rw-r--r--src/libs/utils/filewizardpage.h1
-rw-r--r--src/libs/utils/filewizardpage.ui21
-rw-r--r--src/libs/utils/listmodel.h25
-rw-r--r--src/libs/utils/outputformat.h2
-rw-r--r--src/libs/utils/outputformatter.cpp529
-rw-r--r--src/libs/utils/outputformatter.h154
-rw-r--r--src/libs/utils/overlaywidget.cpp (renamed from src/plugins/boot2qt/qdbdeploystepfactory.cpp)64
-rw-r--r--src/libs/utils/overlaywidget.h (renamed from src/plugins/projectexplorer/buildenvironmentwidget.h)37
-rw-r--r--src/libs/utils/pathchooser.cpp88
-rw-r--r--src/libs/utils/pathchooser.h21
-rw-r--r--src/libs/utils/progressindicator.cpp49
-rw-r--r--src/libs/utils/progressindicator.h9
-rw-r--r--src/libs/utils/projectintropage.cpp2
-rw-r--r--src/libs/utils/qtcprocess.cpp17
-rw-r--r--src/libs/utils/qtcprocess.h5
-rw-r--r--src/libs/utils/stylehelper.cpp45
-rw-r--r--src/libs/utils/stylehelper.h3
-rw-r--r--src/libs/utils/synchronousprocess.cpp14
-rw-r--r--src/libs/utils/textfileformat.cpp2
-rw-r--r--src/libs/utils/theme/theme.h7
-rw-r--r--src/libs/utils/touchbar/touchbar_appdelegate_mac.mm8
-rw-r--r--src/libs/utils/touchbar/touchbar_appdelegate_mac_p.h1
-rw-r--r--src/libs/utils/utils-lib.pri6
-rw-r--r--src/libs/utils/utils.qbs2
-rw-r--r--src/plugins/android/CMakeLists.txt3
-rw-r--r--src/plugins/android/android.pro7
-rw-r--r--src/plugins/android/android.qbs7
-rw-r--r--src/plugins/android/androidavdmanager.cpp1
-rw-r--r--src/plugins/android/androidbuildapkstep.cpp125
-rw-r--r--src/plugins/android/androidbuildapkstep.h3
-rw-r--r--src/plugins/android/androidbuildapkwidget.cpp11
-rw-r--r--src/plugins/android/androidconfigurations.cpp60
-rw-r--r--src/plugins/android/androidconfigurations.h1
-rw-r--r--src/plugins/android/androiddebugsupport.cpp38
-rw-r--r--src/plugins/android/androiddeployqtstep.cpp7
-rw-r--r--src/plugins/android/androidextralibrarylistmodel.cpp36
-rw-r--r--src/plugins/android/androidextralibrarylistmodel.h11
-rw-r--r--src/plugins/android/androidmanager.cpp157
-rw-r--r--src/plugins/android/androidmanager.h24
-rw-r--r--src/plugins/android/androidmanifesteditoriconcontainerwidget.cpp111
-rw-r--r--src/plugins/android/androidmanifesteditoriconcontainerwidget.h52
-rw-r--r--src/plugins/android/androidmanifesteditoriconwidget.cpp213
-rw-r--r--src/plugins/android/androidmanifesteditoriconwidget.h77
-rw-r--r--src/plugins/android/androidmanifesteditorwidget.cpp574
-rw-r--r--src/plugins/android/androidmanifesteditorwidget.h49
-rw-r--r--src/plugins/android/androidpackageinstallationstep.cpp81
-rw-r--r--src/plugins/android/androidpackageinstallationstep.h29
-rw-r--r--src/plugins/android/androidqtversion.cpp4
-rw-r--r--src/plugins/android/androidrunner.cpp79
-rw-r--r--src/plugins/android/androidrunner.h6
-rw-r--r--src/plugins/android/androidrunnerworker.cpp277
-rw-r--r--src/plugins/android/androidrunnerworker.h14
-rw-r--r--src/plugins/android/androidsdkmanager.cpp29
-rw-r--r--src/plugins/android/androidsdkmanager.h4
-rw-r--r--src/plugins/android/androidsdkmanagerwidget.cpp11
-rw-r--r--src/plugins/android/androidsdkmodel.cpp12
-rw-r--r--src/plugins/android/androidsdkmodel.h3
-rw-r--r--src/plugins/android/androidsdkpackage.cpp15
-rw-r--r--src/plugins/android/androidsdkpackage.h15
-rw-r--r--src/plugins/android/androidservicewidget.cpp410
-rw-r--r--src/plugins/android/androidservicewidget.h89
-rw-r--r--src/plugins/android/androidservicewidget_p.h59
-rw-r--r--src/plugins/android/androidsettingswidget.cpp637
-rw-r--r--src/plugins/android/androidsettingswidget.ui111
-rw-r--r--src/plugins/android/androidtoolchain.cpp4
-rw-r--r--src/plugins/android/androidtoolchain.h4
-rw-r--r--src/plugins/android/avddialog.cpp4
-rw-r--r--src/plugins/android/avddialog.h2
-rw-r--r--src/plugins/android/createandroidmanifestwizard.cpp35
-rw-r--r--src/plugins/android/javaparser.cpp65
-rw-r--r--src/plugins/android/javaparser.h6
-rw-r--r--src/plugins/autotest/CMakeLists.txt10
-rw-r--r--src/plugins/autotest/autotest.pro20
-rw-r--r--src/plugins/autotest/autotest.qbs8
-rw-r--r--src/plugins/autotest/autotestplugin.cpp116
-rw-r--r--src/plugins/autotest/autotestplugin.h6
-rw-r--r--src/plugins/autotest/autotestunittests.cpp3
-rw-r--r--src/plugins/autotest/boost/boosttestconfiguration.cpp14
-rw-r--r--src/plugins/autotest/boost/boosttestconfiguration.h3
-rw-r--r--src/plugins/autotest/boost/boosttestframework.cpp24
-rw-r--r--src/plugins/autotest/boost/boosttestframework.h17
-rw-r--r--src/plugins/autotest/boost/boosttestparser.cpp16
-rw-r--r--src/plugins/autotest/boost/boosttestparser.h3
-rw-r--r--src/plugins/autotest/boost/boosttestsettingspage.cpp13
-rw-r--r--src/plugins/autotest/boost/boosttestsettingspage.h7
-rw-r--r--src/plugins/autotest/boost/boosttesttreeitem.cpp12
-rw-r--r--src/plugins/autotest/boost/boosttesttreeitem.h8
-rw-r--r--src/plugins/autotest/catch/catchcodeparser.cpp286
-rw-r--r--src/plugins/autotest/catch/catchcodeparser.h63
-rw-r--r--src/plugins/autotest/catch/catchconfiguration.cpp141
-rw-r--r--src/plugins/autotest/catch/catchconfiguration.h43
-rw-r--r--src/plugins/autotest/catch/catchframework.cpp56
-rw-r--r--src/plugins/autotest/catch/catchframework.h54
-rw-r--r--src/plugins/autotest/catch/catchoutputreader.cpp323
-rw-r--r--src/plugins/autotest/catch/catchoutputreader.h90
-rw-r--r--src/plugins/autotest/catch/catchresult.cpp61
-rw-r--r--src/plugins/autotest/catch/catchresult.h47
-rw-r--r--src/plugins/autotest/catch/catchtestparser.cpp168
-rw-r--r--src/plugins/autotest/catch/catchtestparser.h52
-rw-r--r--src/plugins/autotest/catch/catchtestsettings.cpp94
-rw-r--r--src/plugins/autotest/catch/catchtestsettings.h (renamed from src/plugins/cmakeprojectmanager/builddirreader.cpp)59
-rw-r--r--src/plugins/autotest/catch/catchtestsettingspage.cpp113
-rw-r--r--src/plugins/autotest/catch/catchtestsettingspage.h (renamed from src/plugins/boot2qt/qdbdeploystepfactory.h)18
-rw-r--r--src/plugins/autotest/catch/catchtestsettingspage.ui306
-rw-r--r--src/plugins/autotest/catch/catchtreeitem.cpp293
-rw-r--r--src/plugins/autotest/catch/catchtreeitem.h83
-rw-r--r--src/plugins/autotest/gtest/gtestconfiguration.cpp10
-rw-r--r--src/plugins/autotest/gtest/gtestconfiguration.h4
-rw-r--r--src/plugins/autotest/gtest/gtestframework.cpp48
-rw-r--r--src/plugins/autotest/gtest/gtestframework.h23
-rw-r--r--src/plugins/autotest/gtest/gtestoutputreader.h2
-rw-r--r--src/plugins/autotest/gtest/gtestparser.cpp10
-rw-r--r--src/plugins/autotest/gtest/gtestparser.h3
-rw-r--r--src/plugins/autotest/gtest/gtestresult.cpp4
-rw-r--r--src/plugins/autotest/gtest/gtestsettingspage.cpp11
-rw-r--r--src/plugins/autotest/gtest/gtestsettingspage.h7
-rw-r--r--src/plugins/autotest/gtest/gtesttreeitem.cpp16
-rw-r--r--src/plugins/autotest/gtest/gtesttreeitem.h8
-rw-r--r--src/plugins/autotest/itestframework.cpp76
-rw-r--r--src/plugins/autotest/itestframework.h41
-rw-r--r--src/plugins/autotest/itestparser.cpp3
-rw-r--r--src/plugins/autotest/itestparser.h15
-rw-r--r--src/plugins/autotest/projectsettingswidget.cpp16
-rw-r--r--src/plugins/autotest/projectsettingswidget.h6
-rw-r--r--src/plugins/autotest/qtest/qttest_utils.cpp8
-rw-r--r--src/plugins/autotest/qtest/qttest_utils.h7
-rw-r--r--src/plugins/autotest/qtest/qttestconfiguration.cpp15
-rw-r--r--src/plugins/autotest/qtest/qttestconfiguration.h3
-rw-r--r--src/plugins/autotest/qtest/qttestframework.cpp24
-rw-r--r--src/plugins/autotest/qtest/qttestframework.h16
-rw-r--r--src/plugins/autotest/qtest/qttestparser.cpp16
-rw-r--r--src/plugins/autotest/qtest/qttestparser.h4
-rw-r--r--src/plugins/autotest/qtest/qttestresult.cpp4
-rw-r--r--src/plugins/autotest/qtest/qttestsettingspage.cpp13
-rw-r--r--src/plugins/autotest/qtest/qttestsettingspage.h7
-rw-r--r--src/plugins/autotest/qtest/qttesttreeitem.cpp19
-rw-r--r--src/plugins/autotest/qtest/qttesttreeitem.h2
-rw-r--r--src/plugins/autotest/quick/quicktest_utils.cpp4
-rw-r--r--src/plugins/autotest/quick/quicktest_utils.h5
-rw-r--r--src/plugins/autotest/quick/quicktestconfiguration.cpp18
-rw-r--r--src/plugins/autotest/quick/quicktestconfiguration.h2
-rw-r--r--src/plugins/autotest/quick/quicktestframework.cpp19
-rw-r--r--src/plugins/autotest/quick/quicktestframework.h5
-rw-r--r--src/plugins/autotest/quick/quicktestparser.cpp24
-rw-r--r--src/plugins/autotest/quick/quicktestparser.h6
-rw-r--r--src/plugins/autotest/quick/quicktesttreeitem.cpp22
-rw-r--r--src/plugins/autotest/quick/quicktesttreeitem.h8
-rw-r--r--src/plugins/autotest/testcodeparser.cpp59
-rw-r--r--src/plugins/autotest/testcodeparser.h18
-rw-r--r--src/plugins/autotest/testconfiguration.cpp15
-rw-r--r--src/plugins/autotest/testconfiguration.h10
-rw-r--r--src/plugins/autotest/testframeworkmanager.cpp170
-rw-r--r--src/plugins/autotest/testframeworkmanager.h49
-rw-r--r--src/plugins/autotest/testnavigationwidget.cpp4
-rw-r--r--src/plugins/autotest/testprojectsettings.cpp27
-rw-r--r--src/plugins/autotest/testprojectsettings.h9
-rw-r--r--src/plugins/autotest/testrunner.cpp13
-rw-r--r--src/plugins/autotest/testrunner.h8
-rw-r--r--src/plugins/autotest/testsettings.cpp17
-rw-r--r--src/plugins/autotest/testsettingspage.cpp24
-rw-r--r--src/plugins/autotest/testsettingspage.h4
-rw-r--r--src/plugins/autotest/testtreeitem.cpp11
-rw-r--r--src/plugins/autotest/testtreeitem.h8
-rw-r--r--src/plugins/autotest/testtreemodel.cpp96
-rw-r--r--src/plugins/autotest/testtreemodel.h7
-rw-r--r--src/plugins/autotoolsprojectmanager/autogenstep.cpp20
-rw-r--r--src/plugins/autotoolsprojectmanager/autoreconfstep.cpp20
-rw-r--r--src/plugins/autotoolsprojectmanager/autotoolsopenprojectwizard.cpp2
-rw-r--r--src/plugins/autotoolsprojectmanager/configurestep.cpp18
-rw-r--r--src/plugins/baremetal/CMakeLists.txt1
-rw-r--r--src/plugins/baremetal/baremetal.qbs1
-rw-r--r--src/plugins/baremetal/baremetalconstants.h1
-rw-r--r--src/plugins/baremetal/baremetalplugin.cpp2
-rw-r--r--src/plugins/baremetal/debugserverprovidermanager.cpp4
-rw-r--r--src/plugins/baremetal/debugservers/gdb/eblinkgdbserverprovider.cpp8
-rw-r--r--src/plugins/baremetal/debugservers/gdb/gdbserverprovider.cpp4
-rw-r--r--src/plugins/baremetal/debugservers/gdb/jlinkgdbserverprovider.cpp4
-rw-r--r--src/plugins/baremetal/debugservers/gdb/openocdgdbserverprovider.cpp12
-rw-r--r--src/plugins/baremetal/debugservers/gdb/stlinkutilgdbserverprovider.cpp4
-rw-r--r--src/plugins/baremetal/debugservers/uvsc/jlinkuvscserverprovider.cpp373
-rw-r--r--src/plugins/baremetal/debugservers/uvsc/jlinkuvscserverprovider.h133
-rw-r--r--src/plugins/baremetal/debugservers/uvsc/stlinkuvscserverprovider.cpp16
-rw-r--r--src/plugins/baremetal/debugservers/uvsc/uvproject.cpp5
-rw-r--r--src/plugins/baremetal/debugservers/uvsc/uvproject.h5
-rw-r--r--src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.cpp23
-rw-r--r--src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.h3
-rw-r--r--src/plugins/baremetal/debugservers/uvsc/uvscservers.pri2
-rw-r--r--src/plugins/baremetal/debugservers/uvsc/uvtargetdevicemodel.cpp115
-rw-r--r--src/plugins/baremetal/debugservers/uvsc/uvtargetdeviceselection.cpp94
-rw-r--r--src/plugins/baremetal/debugservers/uvsc/uvtargetdeviceselection.h6
-rw-r--r--src/plugins/baremetal/debugservers/uvsc/uvtargetdeviceviewer.cpp27
-rw-r--r--src/plugins/baremetal/debugservers/uvsc/uvtargetdeviceviewer.h5
-rw-r--r--src/plugins/baremetal/iarewparser.cpp151
-rw-r--r--src/plugins/baremetal/iarewparser.h9
-rw-r--r--src/plugins/baremetal/iarewtoolchain.cpp138
-rw-r--r--src/plugins/baremetal/iarewtoolchain.h11
-rw-r--r--src/plugins/baremetal/keilparser.cpp221
-rw-r--r--src/plugins/baremetal/keilparser.h14
-rw-r--r--src/plugins/baremetal/keiltoolchain.cpp426
-rw-r--r--src/plugins/baremetal/keiltoolchain.h35
-rw-r--r--src/plugins/baremetal/sdccparser.cpp83
-rw-r--r--src/plugins/baremetal/sdccparser.h7
-rw-r--r--src/plugins/baremetal/sdcctoolchain.cpp20
-rw-r--r--src/plugins/baremetal/sdcctoolchain.h4
-rw-r--r--src/plugins/bazaar/pullorpushdialog.cpp2
-rw-r--r--src/plugins/beautifier/artisticstyle/artisticstyleoptionspage.cpp8
-rw-r--r--src/plugins/beautifier/clangformat/clangformatoptionspage.cpp4
-rw-r--r--src/plugins/beautifier/uncrustify/uncrustifyoptionspage.cpp8
-rw-r--r--src/plugins/bineditor/bineditorplugin.cpp4
-rw-r--r--src/plugins/bookmarks/bookmarkmanager.cpp2
-rw-r--r--src/plugins/boot2qt/CMakeLists.txt1
-rw-r--r--src/plugins/boot2qt/boot2qt.pro2
-rw-r--r--src/plugins/boot2qt/boot2qt.qbs2
-rw-r--r--src/plugins/boot2qt/qdbconstants.h3
-rw-r--r--src/plugins/boot2qt/qdbdeployconfigurationfactory.cpp15
-rw-r--r--src/plugins/boot2qt/qdbdeployconfigurationfactory.h2
-rw-r--r--src/plugins/boot2qt/qdbmakedefaultappstep.cpp25
-rw-r--r--src/plugins/boot2qt/qdbmakedefaultappstep.h11
-rw-r--r--src/plugins/boot2qt/qdbplugin.cpp18
-rw-r--r--src/plugins/boot2qt/qdbstopapplicationstep.cpp31
-rw-r--r--src/plugins/boot2qt/qdbstopapplicationstep.h10
-rw-r--r--src/plugins/clangcodemodel/clangbackendcommunicator.cpp5
-rw-r--r--src/plugins/clangcodemodel/clangbackendcommunicator.h3
-rw-r--r--src/plugins/clangcodemodel/clangbackendreceiver.cpp17
-rw-r--r--src/plugins/clangcodemodel/clangbackendreceiver.h6
-rw-r--r--src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp6
-rw-r--r--src/plugins/clangcodemodel/clangcompletionassistprocessor.h1
-rw-r--r--src/plugins/clangcodemodel/clanghoverhandler.cpp16
-rw-r--r--src/plugins/clangcodemodel/clangutils.cpp6
-rw-r--r--src/plugins/clangformat/clangformatplugin.cpp6
-rw-r--r--src/plugins/clangrefactoring/refactoringengine.cpp1
-rw-r--r--src/plugins/clangtools/clangselectablefilesdialog.cpp24
-rw-r--r--src/plugins/clangtools/clangtidyclazyrunner.cpp36
-rw-r--r--src/plugins/clangtools/clangtidyclazyrunner.h8
-rw-r--r--src/plugins/clangtools/clangtool.cpp49
-rw-r--r--src/plugins/clangtools/clangtool.h8
-rw-r--r--src/plugins/clangtools/clangtoolruncontrol.cpp12
-rw-r--r--src/plugins/clangtools/clangtools.pro3
-rw-r--r--src/plugins/clangtools/clangtools.qbs8
-rw-r--r--src/plugins/clangtools/clangtoolsdiagnosticmodel.cpp86
-rw-r--r--src/plugins/clangtools/clangtoolsdiagnosticmodel.h3
-rw-r--r--src/plugins/clangtools/clangtoolslogfilereader.cpp192
-rw-r--r--src/plugins/clangtools/clangtoolslogfilereader.h8
-rw-r--r--src/plugins/clangtools/clangtoolsplugin.cpp59
-rw-r--r--src/plugins/clangtools/clangtoolsplugin.h2
-rw-r--r--src/plugins/clangtools/clangtoolspreconfiguredsessiontests.cpp4
-rw-r--r--src/plugins/clangtools/clangtoolsunittests.cpp9
-rw-r--r--src/plugins/clangtools/clangtoolsutils.cpp1
-rw-r--r--src/plugins/clangtools/settingswidget.cpp25
-rw-r--r--src/plugins/cmakeprojectmanager/CMakeLists.txt6
-rw-r--r--src/plugins/cmakeprojectmanager/builddirmanager.cpp599
-rw-r--r--src/plugins/cmakeprojectmanager/builddirmanager.h138
-rw-r--r--src/plugins/cmakeprojectmanager/builddirparameters.cpp26
-rw-r--r--src/plugins/cmakeprojectmanager/builddirparameters.h3
-rw-r--r--src/plugins/cmakeprojectmanager/builddirreader.h86
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeautocompleter.cpp7
-rw-r--r--src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp88
-rw-r--r--src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h16
-rw-r--r--src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.cpp58
-rw-r--r--src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.h2
-rw-r--r--src/plugins/cmakeprojectmanager/cmakebuildstep.cpp164
-rw-r--r--src/plugins/cmakeprojectmanager/cmakebuildstep.h40
-rw-r--r--src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp811
-rw-r--r--src/plugins/cmakeprojectmanager/cmakebuildsystem.h83
-rw-r--r--src/plugins/cmakeprojectmanager/cmakebuildsystem.md150
-rw-r--r--src/plugins/cmakeprojectmanager/cmakecbpparser.cpp511
-rw-r--r--src/plugins/cmakeprojectmanager/cmakecbpparser.h94
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp3
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeconfigitem.h9
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeeditor.cpp25
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeeditor.h1
-rw-r--r--src/plugins/cmakeprojectmanager/cmakefilecompletionassist.cpp10
-rw-r--r--src/plugins/cmakeprojectmanager/cmakefilecompletionassist.h1
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeindenter.cpp6
-rw-r--r--src/plugins/cmakeprojectmanager/cmakekitinformation.cpp110
-rw-r--r--src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp5
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeparser.cpp83
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeparser.h11
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeprocess.cpp28
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeprocess.h7
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeproject.cpp43
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeproject.h14
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeprojectconstants.h26
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp9
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp40
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeprojectmanager.pro20
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs14
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp108
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp30
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeprojectplugin.h15
-rw-r--r--src/plugins/cmakeprojectmanager/cmakesettingspage.cpp43
-rw-r--r--src/plugins/cmakeprojectmanager/cmakespecificsettings.h2
-rw-r--r--src/plugins/cmakeprojectmanager/cmaketool.cpp207
-rw-r--r--src/plugins/cmakeprojectmanager/cmaketool.h22
-rw-r--r--src/plugins/cmakeprojectmanager/cmaketoolmanager.cpp4
-rw-r--r--src/plugins/cmakeprojectmanager/cmaketoolmanager.h9
-rw-r--r--src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.cpp2
-rw-r--r--src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.h4
-rw-r--r--src/plugins/cmakeprojectmanager/configmodel.cpp1
-rw-r--r--src/plugins/cmakeprojectmanager/configmodel.h3
-rw-r--r--src/plugins/cmakeprojectmanager/configmodelitemdelegate.cpp8
-rw-r--r--src/plugins/cmakeprojectmanager/configmodelitemdelegate.h4
-rw-r--r--src/plugins/cmakeprojectmanager/fileapidataextractor.cpp6
-rw-r--r--src/plugins/cmakeprojectmanager/fileapidataextractor.h11
-rw-r--r--src/plugins/cmakeprojectmanager/fileapiparser.cpp80
-rw-r--r--src/plugins/cmakeprojectmanager/fileapiparser.h37
-rw-r--r--src/plugins/cmakeprojectmanager/fileapireader.cpp73
-rw-r--r--src/plugins/cmakeprojectmanager/fileapireader.h50
-rw-r--r--src/plugins/cmakeprojectmanager/projecttreehelper.cpp7
-rw-r--r--src/plugins/cmakeprojectmanager/projecttreehelper.h2
-rw-r--r--src/plugins/cmakeprojectmanager/servermode.cpp495
-rw-r--r--src/plugins/cmakeprojectmanager/servermode.h125
-rw-r--r--src/plugins/cmakeprojectmanager/servermodereader.cpp935
-rw-r--r--src/plugins/cmakeprojectmanager/servermodereader.h191
-rw-r--r--src/plugins/cmakeprojectmanager/tealeafreader.cpp528
-rw-r--r--src/plugins/cmakeprojectmanager/tealeafreader.h92
-rw-r--r--src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.cpp16
-rw-r--r--src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.h5
-rw-r--r--src/plugins/coreplugin/CMakeLists.txt4
-rw-r--r--src/plugins/coreplugin/actionmanager/actionmanager.cpp230
-rw-r--r--src/plugins/coreplugin/actionmanager/command.cpp120
-rw-r--r--src/plugins/coreplugin/actionmanager/command.h6
-rw-r--r--src/plugins/coreplugin/actionmanager/command_p.h8
-rw-r--r--src/plugins/coreplugin/actionmanager/commandmappings.cpp12
-rw-r--r--src/plugins/coreplugin/actionmanager/commandmappings.h4
-rw-r--r--src/plugins/coreplugin/actionmanager/commandsfile.cpp24
-rw-r--r--src/plugins/coreplugin/actionmanager/commandsfile.h2
-rw-r--r--src/plugins/coreplugin/coreconstants.h14
-rw-r--r--src/plugins/coreplugin/coreplugin.cpp8
-rw-r--r--src/plugins/coreplugin/coreplugin.h2
-rw-r--r--src/plugins/coreplugin/coreplugin.pro6
-rw-r--r--src/plugins/coreplugin/coreplugin.qbs8
-rw-r--r--src/plugins/coreplugin/dialogs/codecselector.cpp (renamed from src/plugins/texteditor/codecselector.cpp)15
-rw-r--r--src/plugins/coreplugin/dialogs/codecselector.h (renamed from src/plugins/texteditor/codecselector.h)16
-rw-r--r--src/plugins/coreplugin/dialogs/ioptionspage.cpp7
-rw-r--r--src/plugins/coreplugin/dialogs/ioptionspage.h4
-rw-r--r--src/plugins/coreplugin/dialogs/settingsdialog.cpp27
-rw-r--r--src/plugins/coreplugin/dialogs/shortcutsettings.cpp393
-rw-r--r--src/plugins/coreplugin/dialogs/shortcutsettings.h30
-rw-r--r--src/plugins/coreplugin/documentmanager.cpp40
-rw-r--r--src/plugins/coreplugin/documentmanager.h2
-rw-r--r--src/plugins/coreplugin/find/searchresultwidget.cpp19
-rw-r--r--src/plugins/coreplugin/find/searchresultwidget.h4
-rw-r--r--src/plugins/coreplugin/find/searchresultwindow.cpp10
-rw-r--r--src/plugins/coreplugin/find/searchresultwindow.h2
-rw-r--r--src/plugins/coreplugin/generatedfile.h26
-rw-r--r--src/plugins/coreplugin/helpitem.cpp2
-rw-r--r--src/plugins/coreplugin/helpmanager.cpp8
-rw-r--r--src/plugins/coreplugin/helpmanager.h4
-rw-r--r--src/plugins/coreplugin/helpmanager_implementation.h4
-rw-r--r--src/plugins/coreplugin/icontext.cpp213
-rw-r--r--src/plugins/coreplugin/icore.cpp22
-rw-r--r--src/plugins/coreplugin/icore.h2
-rw-r--r--src/plugins/coreplugin/locator/javascriptfilter.cpp9
-rw-r--r--src/plugins/coreplugin/locator/javascriptfilter.h4
-rw-r--r--src/plugins/coreplugin/locator/locator.pri4
-rw-r--r--src/plugins/coreplugin/mainwindow.cpp39
-rw-r--r--src/plugins/coreplugin/mainwindow.h1
-rw-r--r--src/plugins/coreplugin/messageoutputwindow.cpp2
-rw-r--r--src/plugins/coreplugin/outputpanemanager.cpp6
-rw-r--r--src/plugins/coreplugin/outputwindow.cpp309
-rw-r--r--src/plugins/coreplugin/outputwindow.h20
-rw-r--r--src/plugins/coreplugin/plugindialog.cpp323
-rw-r--r--src/plugins/coreplugin/plugindialog.h2
-rw-r--r--src/plugins/coreplugin/systemsettings.cpp2
-rw-r--r--src/plugins/coreplugin/variablechooser.cpp6
-rw-r--r--src/plugins/coreplugin/welcomepagehelper.cpp4
-rw-r--r--src/plugins/cpaster/CMakeLists.txt2
-rw-r--r--src/plugins/cpaster/cpaster.pro4
-rw-r--r--src/plugins/cpaster/cpaster.qbs4
-rw-r--r--src/plugins/cpaster/cpasterplugin.cpp14
-rw-r--r--src/plugins/cpaster/dpastedotcomprotocol.cpp134
-rw-r--r--src/plugins/cpaster/dpastedotcomprotocol.h (renamed from src/plugins/cpaster/pastecodedotxyzprotocol.h)6
-rw-r--r--src/plugins/cpaster/fileshareprotocol.cpp14
-rw-r--r--src/plugins/cpaster/fileshareprotocol.h2
-rw-r--r--src/plugins/cpaster/fileshareprotocolsettingspage.cpp2
-rw-r--r--src/plugins/cpaster/frontend/CMakeLists.txt2
-rw-r--r--src/plugins/cpaster/frontend/frontend.pro4
-rw-r--r--src/plugins/cpaster/frontend/frontend.qbs2
-rw-r--r--src/plugins/cpaster/frontend/main.cpp10
-rw-r--r--src/plugins/cpaster/pastebindotcomprotocol.cpp15
-rw-r--r--src/plugins/cpaster/pastebindotcomprotocol.h1
-rw-r--r--src/plugins/cpaster/pastecodedotxyzprotocol.cpp147
-rw-r--r--src/plugins/cpaster/pasteview.cpp26
-rw-r--r--src/plugins/cpaster/pasteview.h6
-rw-r--r--src/plugins/cpaster/pasteview.ui22
-rw-r--r--src/plugins/cpaster/protocol.h1
-rw-r--r--src/plugins/cpaster/settings.cpp7
-rw-r--r--src/plugins/cpaster/settings.h1
-rw-r--r--src/plugins/cpaster/settingspage.cpp2
-rw-r--r--src/plugins/cpaster/settingspage.ui9
-rw-r--r--src/plugins/cpaster/stickynotespasteprotocol.cpp15
-rw-r--r--src/plugins/cpaster/stickynotespasteprotocol.h1
-rw-r--r--src/plugins/cpaster/urlopenprotocol.cpp4
-rw-r--r--src/plugins/cpaster/urlopenprotocol.h2
-rw-r--r--src/plugins/cppcheck/cppcheckoptions.cpp2
-rw-r--r--src/plugins/cppcheck/cppcheckplugin.cpp2
-rw-r--r--src/plugins/cppeditor/CMakeLists.txt1
-rw-r--r--src/plugins/cppeditor/cppeditorconstants.h1
-rw-r--r--src/plugins/cppeditor/cppeditorplugin.cpp23
-rw-r--r--src/plugins/cppeditor/cppeditorwidget.cpp2
-rw-r--r--src/plugins/cppeditor/cppeditorwidget.h2
-rw-r--r--src/plugins/cpptools/baseeditordocumentprocessor.h3
-rw-r--r--src/plugins/cpptools/cppclassesfilter.h3
-rw-r--r--src/plugins/cpptools/cppcodeformatter.cpp3
-rw-r--r--src/plugins/cpptools/cppfilesettingspage.cpp2
-rw-r--r--src/plugins/cpptools/cppfindreferences.cpp6
-rw-r--r--src/plugins/cpptools/cpptoolsjsextension.cpp69
-rw-r--r--src/plugins/cpptools/cpptoolsjsextension.h8
-rw-r--r--src/plugins/debugger/breakhandler.cpp21
-rw-r--r--src/plugins/debugger/breakhandler.h1
-rw-r--r--src/plugins/debugger/cdb/cdbengine.cpp68
-rw-r--r--src/plugins/debugger/cdb/stringinputstream.h1
-rw-r--r--src/plugins/debugger/commonoptionspage.cpp2
-rw-r--r--src/plugins/debugger/debuggeractions.cpp4
-rw-r--r--src/plugins/debugger/debuggerdialogs.cpp12
-rw-r--r--src/plugins/debugger/debuggerengine.cpp4
-rw-r--r--src/plugins/debugger/debuggeritem.cpp8
-rw-r--r--src/plugins/debugger/debuggeritemmanager.cpp10
-rw-r--r--src/plugins/debugger/debuggermainwindow.cpp10
-rw-r--r--src/plugins/debugger/debuggerrunconfigurationaspect.cpp16
-rw-r--r--src/plugins/debugger/debuggerruncontrol.cpp24
-rw-r--r--src/plugins/debugger/debuggerruncontrol.h5
-rw-r--r--src/plugins/debugger/debuggertooltipmanager.cpp3
-rw-r--r--src/plugins/debugger/disassembleragent.cpp2
-rw-r--r--src/plugins/debugger/enginemanager.cpp2
-rw-r--r--src/plugins/debugger/gdb/gdbengine.cpp1
-rw-r--r--src/plugins/debugger/lldb/lldbengine.cpp11
-rw-r--r--src/plugins/debugger/loadcoredialog.cpp10
-rw-r--r--src/plugins/debugger/shared/cdbsymbolpathlisteditor.cpp2
-rw-r--r--src/plugins/debugger/shared/symbolpathsdialog.cpp2
-rw-r--r--src/plugins/debugger/stackhandler.cpp3
-rw-r--r--src/plugins/debugger/unstartedappwatcherdialog.cpp8
-rw-r--r--src/plugins/debugger/uvsc/uvscclient.cpp193
-rw-r--r--src/plugins/debugger/uvsc/uvscclient.h8
-rw-r--r--src/plugins/debugger/uvsc/uvscdatatypes.h4
-rw-r--r--src/plugins/debugger/uvsc/uvscengine.cpp41
-rw-r--r--src/plugins/debugger/uvsc/uvscengine.h4
-rw-r--r--src/plugins/debugger/uvsc/uvscutils.cpp36
-rw-r--r--src/plugins/debugger/uvsc/uvscutils.h5
-rw-r--r--src/plugins/debugger/watchhandler.cpp24
-rw-r--r--src/plugins/designer/cpp/newclasswidget.cpp2
-rw-r--r--src/plugins/designer/formeditorw.cpp2
-rw-r--r--src/plugins/designer/settingspage.cpp4
-rw-r--r--src/plugins/designer/settingspage.h2
-rw-r--r--src/plugins/diffeditor/diffeditorconstants.h1
-rw-r--r--src/plugins/diffeditor/diffeditordocument.cpp28
-rw-r--r--src/plugins/diffeditor/diffeditordocument.h1
-rw-r--r--src/plugins/diffeditor/diffeditorwidgetcontroller.cpp33
-rw-r--r--src/plugins/diffeditor/diffeditorwidgetcontroller.h2
-rw-r--r--src/plugins/diffeditor/sidebysidediffeditorwidget.cpp1
-rw-r--r--src/plugins/diffeditor/unifieddiffeditorwidget.h2
-rw-r--r--src/plugins/emacskeys/emacskeysplugin.cpp20
-rw-r--r--src/plugins/fakevim/fakevimhandler.cpp7
-rw-r--r--src/plugins/genericprojectmanager/genericmakestep.cpp6
-rw-r--r--src/plugins/genericprojectmanager/genericmakestep.h12
-rw-r--r--src/plugins/genericprojectmanager/genericproject.cpp3
-rw-r--r--src/plugins/git/branchview.cpp18
-rw-r--r--src/plugins/git/changeselectiondialog.cpp14
-rw-r--r--src/plugins/git/changeselectiondialog.h2
-rw-r--r--src/plugins/git/gerrit/gerritoptionspage.cpp4
-rw-r--r--src/plugins/git/gerrit/gerritparameters.cpp2
-rw-r--r--src/plugins/git/gerrit/gerritpushdialog.cpp4
-rw-r--r--src/plugins/git/gitclient.cpp313
-rw-r--r--src/plugins/git/gitclient.h28
-rw-r--r--src/plugins/git/giteditor.cpp15
-rw-r--r--src/plugins/git/gitplugin.cpp22
-rw-r--r--src/plugins/git/gitsettings.cpp2
-rw-r--r--src/plugins/git/gitsettings.h1
-rw-r--r--src/plugins/git/gitsubmiteditorwidget.cpp4
-rw-r--r--src/plugins/git/remotedialog.cpp2
-rw-r--r--src/plugins/help/CMakeLists.txt5
-rw-r--r--src/plugins/help/docsettingspage.cpp1
-rw-r--r--src/plugins/help/filtersettingspage.cpp60
-rw-r--r--src/plugins/help/filtersettingspage.h15
-rw-r--r--src/plugins/help/help.pro4
-rw-r--r--src/plugins/help/help.qbs4
-rw-r--r--src/plugins/help/helpindexfilter.cpp101
-rw-r--r--src/plugins/help/helpindexfilter.h18
-rw-r--r--src/plugins/help/helpmanager.cpp36
-rw-r--r--src/plugins/help/helpmanager.h10
-rw-r--r--src/plugins/help/helpplugin.cpp17
-rw-r--r--src/plugins/help/helpwidget.cpp53
-rw-r--r--src/plugins/help/helpwidget.h8
-rw-r--r--src/plugins/help/localhelpmanager.cpp23
-rw-r--r--src/plugins/help/localhelpmanager.h13
-rw-r--r--src/plugins/help/qlitehtml/CMakeLists.txt2
-rw-r--r--src/plugins/help/searchtaskhandler.cpp7
-rw-r--r--src/plugins/imageviewer/exportdialog.cpp4
-rw-r--r--src/plugins/imageviewer/multiexportdialog.cpp4
-rw-r--r--src/plugins/ios/iosbuildstep.cpp73
-rw-r--r--src/plugins/ios/iosbuildstep.h41
-rw-r--r--src/plugins/ios/iosconfigurations.cpp4
-rw-r--r--src/plugins/ios/iosconfigurations.h2
-rw-r--r--src/plugins/ios/iosdeploystep.cpp99
-rw-r--r--src/plugins/ios/iosdeploystep.h51
-rw-r--r--src/plugins/ios/iosdsymbuildstep.cpp27
-rw-r--r--src/plugins/ios/iosdsymbuildstep.h1
-rw-r--r--src/plugins/ios/iosplugin.cpp15
-rw-r--r--src/plugins/ios/iosqtversion.cpp6
-rw-r--r--src/plugins/ios/iosqtversion.h2
-rw-r--r--src/plugins/ios/iosrunconfiguration.cpp2
-rw-r--r--src/plugins/ios/iossettingswidget.cpp6
-rw-r--r--src/plugins/ios/iossettingswidget.h1
-rw-r--r--src/plugins/languageclient/CMakeLists.txt1
-rw-r--r--src/plugins/languageclient/client.cpp181
-rw-r--r--src/plugins/languageclient/client.h14
-rw-r--r--src/plugins/languageclient/languageclient.pro2
-rw-r--r--src/plugins/languageclient/languageclient.qbs2
-rw-r--r--src/plugins/languageclient/languageclientcompletionassist.cpp25
-rw-r--r--src/plugins/languageclient/languageclientfunctionhint.cpp26
-rw-r--r--src/plugins/languageclient/languageclienthoverhandler.cpp11
-rw-r--r--src/plugins/languageclient/languageclientmanager.cpp181
-rw-r--r--src/plugins/languageclient/languageclientmanager.h13
-rw-r--r--src/plugins/languageclient/languageclientoutline.cpp6
-rw-r--r--src/plugins/languageclient/languageclientquickfix.cpp12
-rw-r--r--src/plugins/languageclient/languageclientsettings.cpp50
-rw-r--r--src/plugins/languageclient/languageclientsettings.h7
-rw-r--r--src/plugins/languageclient/languageclientsymbolsupport.cpp198
-rw-r--r--src/plugins/languageclient/languageclientsymbolsupport.h56
-rw-r--r--src/plugins/languageclient/languageclientutils.cpp2
-rw-r--r--src/plugins/languageclient/lsplogger.cpp6
-rw-r--r--src/plugins/languageclient/semantichighlightsupport.cpp4
-rw-r--r--src/plugins/macros/savedialog.cpp4
-rw-r--r--src/plugins/marketplace/productlistmodel.cpp244
-rw-r--r--src/plugins/marketplace/productlistmodel.h57
-rw-r--r--src/plugins/marketplace/qtmarketplacewelcomepage.cpp49
-rw-r--r--src/plugins/mcusupport/mcusupportoptions.cpp4
-rw-r--r--src/plugins/mcusupport/mcusupportoptionspage.cpp2
-rw-r--r--src/plugins/mcusupport/mcusupportsdk.cpp2
-rw-r--r--src/plugins/mercurial/srcdestdialog.cpp2
-rw-r--r--src/plugins/modeleditor/CMakeLists.txt1
-rw-r--r--src/plugins/modeleditor/componentviewcontroller.cpp2
-rw-r--r--src/plugins/modeleditor/modeleditor.cpp4
-rw-r--r--src/plugins/modeleditor/packageviewcontroller.cpp6
-rw-r--r--src/plugins/modeleditor/pxnodecontroller.cpp4
-rw-r--r--src/plugins/nim/project/nimblebuildstep.cpp61
-rw-r--r--src/plugins/nim/project/nimblebuildstep.h2
-rw-r--r--src/plugins/nim/project/nimblebuildsystem.cpp8
-rw-r--r--src/plugins/nim/project/nimbletaskstep.cpp4
-rw-r--r--src/plugins/nim/project/nimbletaskstep.h2
-rw-r--r--src/plugins/nim/project/nimcompilerbuildstep.cpp65
-rw-r--r--src/plugins/nim/project/nimcompilerbuildstep.h2
-rw-r--r--src/plugins/nim/project/nimcompilercleanstep.cpp35
-rw-r--r--src/plugins/nim/project/nimcompilercleanstep.h22
-rw-r--r--src/plugins/nim/project/nimtoolchain.cpp6
-rw-r--r--src/plugins/nim/project/nimtoolchain.h4
-rw-r--r--src/plugins/nim/project/nimtoolchainfactory.cpp6
-rw-r--r--src/plugins/nim/project/nimtoolchainfactory.h2
-rw-r--r--src/plugins/nim/settings/nimtoolssettingspage.cpp8
-rw-r--r--src/plugins/nim/settings/nimtoolssettingspage.h3
-rw-r--r--src/plugins/perfprofiler/perfdatareader.cpp27
-rw-r--r--src/plugins/perfprofiler/perfprofilerstatisticsview.cpp3
-rw-r--r--src/plugins/perfprofiler/perfprofilertool.cpp3
-rw-r--r--src/plugins/plugins.qbs1
-rw-r--r--src/plugins/projectexplorer/CMakeLists.txt3
-rw-r--r--src/plugins/projectexplorer/abi.cpp76
-rw-r--r--src/plugins/projectexplorer/abi.h10
-rw-r--r--src/plugins/projectexplorer/abstractprocessstep.cpp173
-rw-r--r--src/plugins/projectexplorer/abstractprocessstep.h14
-rw-r--r--src/plugins/projectexplorer/addrunconfigdialog.cpp2
-rw-r--r--src/plugins/projectexplorer/ansifilterparser.cpp175
-rw-r--r--src/plugins/projectexplorer/applicationlauncher.cpp4
-rw-r--r--src/plugins/projectexplorer/appoutputpane.cpp26
-rw-r--r--src/plugins/projectexplorer/buildaspects.cpp2
-rw-r--r--src/plugins/projectexplorer/buildaspects.h3
-rw-r--r--src/plugins/projectexplorer/buildconfiguration.cpp111
-rw-r--r--src/plugins/projectexplorer/buildconfiguration.h9
-rw-r--r--src/plugins/projectexplorer/buildenvironmentwidget.cpp82
-rw-r--r--src/plugins/projectexplorer/buildmanager.cpp23
-rw-r--r--src/plugins/projectexplorer/buildmanager.h2
-rw-r--r--src/plugins/projectexplorer/buildstep.cpp72
-rw-r--r--src/plugins/projectexplorer/buildstep.h21
-rw-r--r--src/plugins/projectexplorer/buildsystem.cpp41
-rw-r--r--src/plugins/projectexplorer/buildsystem.h8
-rw-r--r--src/plugins/projectexplorer/clangparser.cpp78
-rw-r--r--src/plugins/projectexplorer/clangparser.h5
-rw-r--r--src/plugins/projectexplorer/compileoutputwindow.cpp113
-rw-r--r--src/plugins/projectexplorer/compileoutputwindow.h14
-rw-r--r--src/plugins/projectexplorer/configtaskhandler.cpp2
-rw-r--r--src/plugins/projectexplorer/copytaskhandler.cpp2
-rw-r--r--src/plugins/projectexplorer/customparser.cpp287
-rw-r--r--src/plugins/projectexplorer/customparser.h66
-rw-r--r--src/plugins/projectexplorer/customparserconfigdialog.cpp2
-rw-r--r--src/plugins/projectexplorer/customparserconfigdialog.h2
-rw-r--r--src/plugins/projectexplorer/customparserssettingspage.cpp144
-rw-r--r--src/plugins/projectexplorer/customparserssettingspage.h (renamed from src/plugins/projectexplorer/ansifilterparser.h)19
-rw-r--r--src/plugins/projectexplorer/customtoolchain.cpp171
-rw-r--r--src/plugins/projectexplorer/customtoolchain.h14
-rw-r--r--src/plugins/projectexplorer/customwizard/customwizardpage.cpp12
-rw-r--r--src/plugins/projectexplorer/deployconfiguration.cpp8
-rw-r--r--src/plugins/projectexplorer/deploymentdata.cpp6
-rw-r--r--src/plugins/projectexplorer/desktoprunconfiguration.cpp2
-rw-r--r--src/plugins/projectexplorer/devicesupport/deviceprocessesdialog.cpp4
-rw-r--r--src/plugins/projectexplorer/devicesupport/sshsettingspage.cpp10
-rw-r--r--src/plugins/projectexplorer/environmentwidget.cpp102
-rw-r--r--src/plugins/projectexplorer/extracompiler.cpp2
-rw-r--r--src/plugins/projectexplorer/gccparser.cpp381
-rw-r--r--src/plugins/projectexplorer/gccparser.h26
-rw-r--r--src/plugins/projectexplorer/gcctoolchain.cpp54
-rw-r--r--src/plugins/projectexplorer/gcctoolchain.h14
-rw-r--r--src/plugins/projectexplorer/gcctoolchainfactories.h9
-rw-r--r--src/plugins/projectexplorer/gnumakeparser.cpp228
-rw-r--r--src/plugins/projectexplorer/gnumakeparser.h21
-rw-r--r--src/plugins/projectexplorer/images/fileoverlay_group.png (renamed from src/plugins/qbsprojectmanager/images/groups.png)bin1223 -> 1223 bytes
-rw-r--r--src/plugins/projectexplorer/images/fileoverlay_group@2x.png (renamed from src/plugins/qbsprojectmanager/images/groups@2x.png)bin1548 -> 1548 bytes
-rw-r--r--src/plugins/projectexplorer/images/fileoverlay_product.png (renamed from src/plugins/qbsprojectmanager/images/productgear.png)bin1152 -> 1152 bytes
-rw-r--r--src/plugins/projectexplorer/images/fileoverlay_product@2x.png (renamed from src/plugins/qbsprojectmanager/images/productgear@2x.png)bin1453 -> 1453 bytes
-rw-r--r--src/plugins/projectexplorer/importwidget.cpp6
-rw-r--r--src/plugins/projectexplorer/ioutputparser.cpp201
-rw-r--r--src/plugins/projectexplorer/ioutputparser.h56
-rw-r--r--src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp6
-rw-r--r--src/plugins/projectexplorer/jsonwizard/jsonfilepage.cpp1
-rw-r--r--src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp6
-rw-r--r--src/plugins/projectexplorer/jsonwizard/jsonwizardfilegenerator.cpp3
-rw-r--r--src/plugins/projectexplorer/jsonwizard/jsonwizardfilegenerator.h1
-rw-r--r--src/plugins/projectexplorer/kit.cpp8
-rw-r--r--src/plugins/projectexplorer/kit.h4
-rw-r--r--src/plugins/projectexplorer/kitinformation.cpp43
-rw-r--r--src/plugins/projectexplorer/kitinformation.h5
-rw-r--r--src/plugins/projectexplorer/kitmanager.cpp4
-rw-r--r--src/plugins/projectexplorer/kitmanager.h4
-rw-r--r--src/plugins/projectexplorer/ldparser.cpp57
-rw-r--r--src/plugins/projectexplorer/ldparser.h6
-rw-r--r--src/plugins/projectexplorer/linuxiccparser.cpp76
-rw-r--r--src/plugins/projectexplorer/linuxiccparser.h10
-rw-r--r--src/plugins/projectexplorer/lldparser.cpp22
-rw-r--r--src/plugins/projectexplorer/lldparser.h4
-rw-r--r--src/plugins/projectexplorer/makestep.cpp42
-rw-r--r--src/plugins/projectexplorer/makestep.h3
-rw-r--r--src/plugins/projectexplorer/miniprojecttargetselector.cpp419
-rw-r--r--src/plugins/projectexplorer/miniprojecttargetselector.h19
-rw-r--r--src/plugins/projectexplorer/msvcparser.cpp188
-rw-r--r--src/plugins/projectexplorer/msvcparser.h19
-rw-r--r--src/plugins/projectexplorer/msvctoolchain.cpp145
-rw-r--r--src/plugins/projectexplorer/msvctoolchain.h16
-rw-r--r--src/plugins/projectexplorer/osparser.cpp43
-rw-r--r--src/plugins/projectexplorer/osparser.h10
-rw-r--r--src/plugins/projectexplorer/outputparser_test.cpp177
-rw-r--r--src/plugins/projectexplorer/outputparser_test.h19
-rw-r--r--src/plugins/projectexplorer/panelswidget.cpp61
-rw-r--r--src/plugins/projectexplorer/panelswidget.h3
-rw-r--r--src/plugins/projectexplorer/parseissuesdialog.cpp14
-rw-r--r--src/plugins/projectexplorer/processstep.cpp56
-rw-r--r--src/plugins/projectexplorer/processstep.h25
-rw-r--r--src/plugins/projectexplorer/project.cpp21
-rw-r--r--src/plugins/projectexplorer/project.h5
-rw-r--r--src/plugins/projectexplorer/projectconfiguration.h5
-rw-r--r--src/plugins/projectexplorer/projectconfigurationaspects.cpp47
-rw-r--r--src/plugins/projectexplorer/projectconfigurationaspects.h6
-rw-r--r--src/plugins/projectexplorer/projectexplorer.cpp143
-rw-r--r--src/plugins/projectexplorer/projectexplorer.h10
-rw-r--r--src/plugins/projectexplorer/projectexplorer.pro6
-rw-r--r--src/plugins/projectexplorer/projectexplorer.qbs3
-rw-r--r--src/plugins/projectexplorer/projectexplorer.qrc4
-rw-r--r--src/plugins/projectexplorer/projectexplorerconstants.h3
-rw-r--r--src/plugins/projectexplorer/projectexplorersettings.h2
-rw-r--r--src/plugins/projectexplorer/projectexplorersettingspage.cpp2
-rw-r--r--src/plugins/projectexplorer/projectmodels.cpp51
-rw-r--r--src/plugins/projectexplorer/projecttree.cpp35
-rw-r--r--src/plugins/projectexplorer/projecttree.h6
-rw-r--r--src/plugins/projectexplorer/projecttreewidget.cpp14
-rw-r--r--src/plugins/projectexplorer/projecttreewidget.h3
-rw-r--r--src/plugins/projectexplorer/rawprojectpart.cpp4
-rw-r--r--src/plugins/projectexplorer/removetaskhandler.cpp2
-rw-r--r--src/plugins/projectexplorer/runconfiguration.cpp27
-rw-r--r--src/plugins/projectexplorer/runconfiguration.h8
-rw-r--r--src/plugins/projectexplorer/runconfigurationaspects.cpp10
-rw-r--r--src/plugins/projectexplorer/runcontrol.cpp57
-rw-r--r--src/plugins/projectexplorer/runcontrol.h13
-rw-r--r--src/plugins/projectexplorer/selectablefilesmodel.cpp4
-rw-r--r--src/plugins/projectexplorer/sessionview.cpp2
-rw-r--r--src/plugins/projectexplorer/simpleprojectwizard.cpp2
-rw-r--r--src/plugins/projectexplorer/target.cpp53
-rw-r--r--src/plugins/projectexplorer/target.h8
-rw-r--r--src/plugins/projectexplorer/targetsetuppage.cpp8
-rw-r--r--src/plugins/projectexplorer/targetsetupwidget.cpp8
-rw-r--r--src/plugins/projectexplorer/task.cpp30
-rw-r--r--src/plugins/projectexplorer/task.h6
-rw-r--r--src/plugins/projectexplorer/taskhub.cpp6
-rw-r--r--src/plugins/projectexplorer/taskmodel.cpp4
-rw-r--r--src/plugins/projectexplorer/taskwindow.cpp112
-rw-r--r--src/plugins/projectexplorer/toolchain.h12
-rw-r--r--src/plugins/projectexplorer/toolchainconfigwidget.cpp17
-rw-r--r--src/plugins/projectexplorer/toolchainconfigwidget.h1
-rw-r--r--src/plugins/projectexplorer/toolchainsettingsaccessor.cpp2
-rw-r--r--src/plugins/projectexplorer/xcodebuildparser.cpp74
-rw-r--r--src/plugins/projectexplorer/xcodebuildparser.h10
-rw-r--r--src/plugins/python/pythonconstants.h4
-rw-r--r--src/plugins/python/pythoneditor.cpp66
-rw-r--r--src/plugins/python/pythonrunconfiguration.cpp94
-rw-r--r--src/plugins/python/pythonsettings.cpp14
-rw-r--r--src/plugins/python/pythonutils.cpp67
-rw-r--r--src/plugins/python/pythonutils.h4
-rw-r--r--src/plugins/qbsprojectmanager/CMakeLists.txt1
-rw-r--r--src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp23
-rw-r--r--src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp5
-rw-r--r--src/plugins/qbsprojectmanager/qbsbuildconfiguration.h6
-rw-r--r--src/plugins/qbsprojectmanager/qbsbuildstep.cpp49
-rw-r--r--src/plugins/qbsprojectmanager/qbsbuildstep.h2
-rw-r--r--src/plugins/qbsprojectmanager/qbscleanstep.cpp2
-rw-r--r--src/plugins/qbsprojectmanager/qbscleanstep.h1
-rw-r--r--src/plugins/qbsprojectmanager/qbsinstallstep.cpp5
-rw-r--r--src/plugins/qbsprojectmanager/qbsinstallstep.h1
-rw-r--r--src/plugins/qbsprojectmanager/qbsnodes.cpp4
-rw-r--r--src/plugins/qbsprojectmanager/qbsproject.cpp10
-rw-r--r--src/plugins/qbsprojectmanager/qbsproject.h2
-rw-r--r--src/plugins/qbsprojectmanager/qbsprojectimporter.cpp6
-rw-r--r--src/plugins/qbsprojectmanager/qbsprojectmanager.pro2
-rw-r--r--src/plugins/qbsprojectmanager/qbsprojectmanager.qbs2
-rw-r--r--src/plugins/qbsprojectmanager/qbsprojectmanager.qrc4
-rw-r--r--src/plugins/qbsprojectmanager/qbsprojectmanagerconstants.h4
-rw-r--r--src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp10
-rw-r--r--src/plugins/qbsprojectmanager/qbssettings.cpp6
-rw-r--r--src/plugins/qmakeprojectmanager/CMakeLists.txt1
-rw-r--r--src/plugins/qmakeprojectmanager/addlibrarywizard.cpp2
-rw-r--r--src/plugins/qmakeprojectmanager/customwidgetwizard/classdefinition.cpp2
-rw-r--r--src/plugins/qmakeprojectmanager/customwidgetwizard/classlist.cpp1
-rw-r--r--src/plugins/qmakeprojectmanager/librarydetailscontroller.cpp16
-rw-r--r--src/plugins/qmakeprojectmanager/profileeditor.cpp2
-rw-r--r--src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp11
-rw-r--r--src/plugins/qmakeprojectmanager/qmakebuildconfiguration.h4
-rw-r--r--src/plugins/qmakeprojectmanager/qmakekitinformation.cpp3
-rw-r--r--src/plugins/qmakeprojectmanager/qmakemakestep.cpp48
-rw-r--r--src/plugins/qmakeprojectmanager/qmakemakestep.h1
-rw-r--r--src/plugins/qmakeprojectmanager/qmakenodes.cpp9
-rw-r--r--src/plugins/qmakeprojectmanager/qmakenodes.h1
-rw-r--r--src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp29
-rw-r--r--src/plugins/qmakeprojectmanager/qmakeparser.cpp35
-rw-r--r--src/plugins/qmakeprojectmanager/qmakeparser.h5
-rw-r--r--src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp20
-rw-r--r--src/plugins/qmakeprojectmanager/qmakeparsernodes.h4
-rw-r--r--src/plugins/qmakeprojectmanager/qmakeproject.cpp222
-rw-r--r--src/plugins/qmakeprojectmanager/qmakeproject.h21
-rw-r--r--src/plugins/qmakeprojectmanager/qmakeprojectimporter.cpp2
-rw-r--r--src/plugins/qmakeprojectmanager/qmakeprojectmanager.cpp256
-rw-r--r--src/plugins/qmakeprojectmanager/qmakeprojectmanager.h77
-rw-r--r--src/plugins/qmakeprojectmanager/qmakeprojectmanager.pro2
-rw-r--r--src/plugins/qmakeprojectmanager/qmakeprojectmanager.qbs1
-rw-r--r--src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp182
-rw-r--r--src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.h5
-rw-r--r--src/plugins/qmakeprojectmanager/qmakestep.cpp48
-rw-r--r--src/plugins/qmakeprojectmanager/qmakestep.h2
-rw-r--r--src/plugins/qmakeprojectmanager/wizards/qtwizard.cpp1
-rw-r--r--src/plugins/qmldesigner/CMakeLists.txt9
-rw-r--r--src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.cpp9
-rw-r--r--src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.h3
-rw-r--r--src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.ui8
-rw-r--r--src/plugins/qmldesigner/components/annotationeditor/annotationeditor.cpp6
-rw-r--r--src/plugins/qmldesigner/components/annotationeditor/annotationeditor.pri2
-rw-r--r--src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.cpp38
-rw-r--r--src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.h13
-rw-r--r--src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.ui4
-rw-r--r--src/plugins/qmldesigner/components/annotationeditor/globalannotationeditor.cpp148
-rw-r--r--src/plugins/qmldesigner/components/annotationeditor/globalannotationeditor.h75
-rw-r--r--src/plugins/qmldesigner/components/componentcore/componentcore_constants.h4
-rw-r--r--src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp38
-rw-r--r--src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.h8
-rw-r--r--src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp52
-rw-r--r--src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h1
-rw-r--r--src/plugins/qmldesigner/components/componentcore/theme.cpp46
-rw-r--r--src/plugins/qmldesigner/components/componentcore/theme.h82
-rw-r--r--src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.cpp10
-rw-r--r--src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.h1
-rw-r--r--src/plugins/qmldesigner/components/curveeditor/curveeditormodel.cpp2
-rw-r--r--src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.cpp4
-rw-r--r--src/plugins/qmldesigner/components/curveeditor/detail/selectionmodel.cpp2
-rw-r--r--src/plugins/qmldesigner/components/curveeditor/detail/selectionmodel.h2
-rw-r--r--src/plugins/qmldesigner/components/curveeditor/detail/selector.cpp2
-rw-r--r--src/plugins/qmldesigner/components/edit3d/edit3dview.cpp29
-rw-r--r--src/plugins/qmldesigner/components/edit3d/edit3dview.h1
-rw-r--r--src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp11
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditor.pri6
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditorannotationicon.cpp7
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp111
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditoritem.h17
-rw-r--r--src/plugins/qmldesigner/components/formeditor/selectionindicator.cpp1
-rw-r--r--src/plugins/qmldesigner/components/formeditor/selectionindicator.h3
-rw-r--r--src/plugins/qmldesigner/components/formeditor/transitiontool.cpp438
-rw-r--r--src/plugins/qmldesigner/components/formeditor/transitiontool.h98
-rw-r--r--src/plugins/qmldesigner/components/importmanager/importmanagerview.cpp8
-rw-r--r--src/plugins/qmldesigner/components/integration/designdocument.cpp2
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp29
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp37
-rw-r--r--src/plugins/qmldesigner/components/navigator/navigatormodelinterface.h1
-rw-r--r--src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp7
-rw-r--r--src/plugins/qmldesigner/components/navigator/navigatortreemodel.h1
-rw-r--r--src/plugins/qmldesigner/components/navigator/navigatorview.cpp19
-rw-r--r--src/plugins/qmldesigner/components/navigator/navigatorview.h4
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp1
-rw-r--r--src/plugins/qmldesigner/components/richtexteditor/hyperlinkdialog.cpp (renamed from src/plugins/qbsprojectmanager/qbsparser.cpp)51
-rw-r--r--src/plugins/qmldesigner/components/richtexteditor/hyperlinkdialog.h (renamed from src/plugins/qbsprojectmanager/qbsparser.h)32
-rw-r--r--src/plugins/qmldesigner/components/richtexteditor/hyperlinkdialog.ui88
-rw-r--r--src/plugins/qmldesigner/components/richtexteditor/richtexteditor.cpp684
-rw-r--r--src/plugins/qmldesigner/components/richtexteditor/richtexteditor.h130
-rw-r--r--src/plugins/qmldesigner/components/richtexteditor/richtexteditor.pri8
-rw-r--r--src/plugins/qmldesigner/components/richtexteditor/richtexteditor.ui50
-rw-r--r--src/plugins/qmldesigner/components/timelineeditor/easingcurvedialog.cpp2
-rw-r--r--src/plugins/qmldesigner/components/timelineeditor/timelinewidget.cpp48
-rw-r--r--src/plugins/qmldesigner/components/timelineeditor/timelinewidget.h2
-rw-r--r--src/plugins/qmldesigner/designercore/filemanager/changeimportsvisitor.cpp23
-rw-r--r--src/plugins/qmldesigner/designercore/include/annotation.h1
-rw-r--r--src/plugins/qmldesigner/designercore/include/modelnode.h5
-rw-r--r--src/plugins/qmldesigner/designercore/include/qmlitemnode.h5
-rw-r--r--src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp8
-rw-r--r--src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp3
-rw-r--r--src/plugins/qmldesigner/designercore/model/modelnode.cpp29
-rw-r--r--src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp60
-rw-r--r--src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp9
-rw-r--r--src/plugins/qmldesigner/designmodewidget.cpp41
-rw-r--r--src/plugins/qmldesigner/designmodewidget.h2
-rw-r--r--src/plugins/qmldesigner/qmldesigner.qbs1
-rw-r--r--src/plugins/qmldesigner/qmldesignerplugin.cpp7
-rw-r--r--src/plugins/qmldesigner/qmldesignerplugin.pro1
-rw-r--r--src/plugins/qmldesigner/qmldesignerplugin.qbs10
-rw-r--r--src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewplugin.qbs40
-rw-r--r--src/plugins/qmldesigner/shortcutmanager.cpp9
-rw-r--r--src/plugins/qmljseditor/qmljscomponentnamedialog.cpp2
-rw-r--r--src/plugins/qmljseditor/qmljseditor.cpp9
-rw-r--r--src/plugins/qmljseditor/qmljseditor.h2
-rw-r--r--src/plugins/qmljseditor/qmljseditorplugin.cpp7
-rw-r--r--src/plugins/qmljstools/qmljsmodelmanager.cpp4
-rw-r--r--src/plugins/qmljstools/qmljstools_test.cpp2
-rw-r--r--src/plugins/qmlprofiler/qmlprofileractions.cpp2
-rw-r--r--src/plugins/qmlprofiler/qmlprofilerstatisticsview.cpp6
-rw-r--r--src/plugins/qnx/qnxconfiguration.cpp2
-rw-r--r--src/plugins/qnx/qnxdebugsupport.cpp4
-rw-r--r--src/plugins/qnx/qnxtoolchain.cpp22
-rw-r--r--src/plugins/qnx/qnxtoolchain.h4
-rw-r--r--src/plugins/qtsupport/baseqtversion.cpp5
-rw-r--r--src/plugins/qtsupport/baseqtversion.h3
-rw-r--r--src/plugins/qtsupport/gettingstartedwelcomepage.cpp2
-rw-r--r--src/plugins/qtsupport/qtkitinformation.cpp14
-rw-r--r--src/plugins/qtsupport/qtkitinformation.h2
-rw-r--r--src/plugins/qtsupport/qtoptionspage.cpp8
-rw-r--r--src/plugins/qtsupport/qtoutputformatter.cpp196
-rw-r--r--src/plugins/qtsupport/qtparser.cpp60
-rw-r--r--src/plugins/qtsupport/qtparser.h7
-rw-r--r--src/plugins/qtsupport/qttestparser.cpp29
-rw-r--r--src/plugins/qtsupport/qttestparser.h6
-rw-r--r--src/plugins/remotelinux/abstractpackagingstep.cpp2
-rw-r--r--src/plugins/remotelinux/abstractremotelinuxdeploystep.cpp4
-rw-r--r--src/plugins/remotelinux/genericdirectuploadstep.cpp3
-rw-r--r--src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp6
-rw-r--r--src/plugins/remotelinux/genericlinuxdeviceconfigurationwizardpages.cpp10
-rw-r--r--src/plugins/remotelinux/linuxdevice.cpp10
-rw-r--r--src/plugins/remotelinux/linuxdevice.h3
-rw-r--r--src/plugins/remotelinux/linuxdevicetester.cpp4
-rw-r--r--src/plugins/remotelinux/makeinstallstep.cpp4
-rw-r--r--src/plugins/remotelinux/publickeydeploymentdialog.cpp10
-rw-r--r--src/plugins/remotelinux/remotelinux_constants.h5
-rw-r--r--src/plugins/remotelinux/remotelinuxdeployconfiguration.cpp9
-rw-r--r--src/plugins/resourceeditor/qrceditor/resourcefile.cpp19
-rw-r--r--src/plugins/resourceeditor/qrceditor/resourcefile_p.h4
-rw-r--r--src/plugins/resourceeditor/qrceditor/resourceview.cpp2
-rw-r--r--src/plugins/resourceeditor/resourceeditorw.cpp6
-rw-r--r--src/plugins/resourceeditor/resourceeditorw.h2
-rw-r--r--src/plugins/scxmleditor/common/structure.cpp10
-rw-r--r--src/plugins/scxmleditor/plugin_interface/graphicsscene.cpp2
-rw-r--r--src/plugins/scxmleditor/plugin_interface/scattributeitemdelegate.cpp9
-rw-r--r--src/plugins/scxmleditor/plugin_interface/transitionitem.cpp2
-rw-r--r--src/plugins/serialterminal/serialcontrol.cpp5
-rw-r--r--src/plugins/serialterminal/serialcontrol.h2
-rw-r--r--src/plugins/serialterminal/serialoutputpane.cpp7
-rw-r--r--src/plugins/studiowelcome/studiowelcome.qbs36
-rw-r--r--src/plugins/texteditor/CMakeLists.txt1
-rw-r--r--src/plugins/texteditor/behaviorsettingswidget.cpp11
-rw-r--r--src/plugins/texteditor/behaviorsettingswidget.ui137
-rw-r--r--src/plugins/texteditor/codeassist/codeassistant.cpp32
-rw-r--r--src/plugins/texteditor/findinfiles.cpp6
-rw-r--r--src/plugins/texteditor/highlighter.cpp63
-rw-r--r--src/plugins/texteditor/highlighter.h9
-rw-r--r--src/plugins/texteditor/highlightersettingspage.cpp6
-rw-r--r--src/plugins/texteditor/indenter.h1
-rw-r--r--src/plugins/texteditor/storagesettings.cpp67
-rw-r--r--src/plugins/texteditor/storagesettings.h5
-rw-r--r--src/plugins/texteditor/textdocument.cpp26
-rw-r--r--src/plugins/texteditor/textdocument.h2
-rw-r--r--src/plugins/texteditor/texteditor.cpp31
-rw-r--r--src/plugins/texteditor/texteditor.h2
-rw-r--r--src/plugins/texteditor/texteditor.pro2
-rw-r--r--src/plugins/texteditor/texteditor.qbs2
-rw-r--r--src/plugins/texteditor/texteditoractionhandler.cpp5
-rw-r--r--src/plugins/texteditor/texteditoractionhandler.h3
-rw-r--r--src/plugins/texteditor/texteditorconstants.h2
-rw-r--r--src/plugins/todo/todooutputpane.cpp2
-rw-r--r--src/plugins/valgrind/callgrind/callgrindproxymodel.cpp2
-rw-r--r--src/plugins/valgrind/callgrindtool.cpp4
-rw-r--r--src/plugins/valgrind/memcheckerrorview.cpp2
-rw-r--r--src/plugins/valgrind/memchecktool.cpp4
-rw-r--r--src/plugins/valgrind/suppressiondialog.cpp2
-rw-r--r--src/plugins/vcsbase/basevcseditorfactory.cpp1
-rw-r--r--src/plugins/vcsbase/basevcseditorfactory.h2
-rw-r--r--src/plugins/vcsbase/commonsettingspage.cpp8
-rw-r--r--src/plugins/vcsbase/diffandloghighlighter.cpp18
-rw-r--r--src/plugins/vcsbase/diffandloghighlighter.h2
-rw-r--r--src/plugins/vcsbase/vcsbaseeditor.cpp14
-rw-r--r--src/plugins/vcsbase/vcsbaseeditor.h2
-rw-r--r--src/plugins/vcsbase/vcsoutputformatter.cpp30
-rw-r--r--src/plugins/vcsbase/vcsoutputformatter.h10
-rw-r--r--src/plugins/vcsbase/vcsoutputwindow.cpp56
-rw-r--r--src/plugins/webassembly/webassemblytoolchain.cpp4
-rw-r--r--src/plugins/webassembly/webassemblytoolchain.h4
-rw-r--r--src/plugins/winrt/winrtdeployconfiguration.cpp12
-rw-r--r--src/plugins/winrt/winrtdeployconfiguration.h6
-rw-r--r--src/plugins/winrt/winrtpackagedeploymentstep.cpp98
-rw-r--r--src/plugins/winrt/winrtpackagedeploymentstep.h57
-rw-r--r--src/plugins/winrt/winrtplugin.cpp8
-rw-r--r--src/share/3rdparty/CMakeLists.txt10
-rw-r--r--src/shared/help/bookmarkmanager.cpp14
-rw-r--r--src/shared/help/bookmarkmanager.h2
-rw-r--r--src/shared/help/indexwindow.cpp17
-rw-r--r--src/shared/help/indexwindow.h2
-rw-r--r--src/shared/help/topicchooser.cpp4
-rw-r--r--src/shared/help/topicchooser.h2
-rw-r--r--src/shared/proparser/CMakeLists.txt2
-rw-r--r--src/shared/proparser/qmakebuiltins.cpp4
m---------src/shared/qbs0
-rw-r--r--src/shared/shared.pro5
-rw-r--r--src/tools/CMakeLists.txt4
-rw-r--r--src/tools/buildoutputparser/outputprocessor.cpp28
-rw-r--r--src/tools/clangbackend/source/clangtooltipinfocollector.cpp23
-rw-r--r--src/tools/clangbackend/source/codecompleter.cpp2
-rw-r--r--src/tools/clangbackend/source/skippedsourceranges.cpp1
-rw-r--r--src/tools/clangpchmanagerbackend/source/pchtaskqueue.h4
-rw-r--r--src/tools/clangpchmanagerbackend/source/projectpartsmanager.h4
-rw-r--r--src/tools/cplusplus-shared/utils.cpp10
-rw-r--r--src/tools/cplusplus-update-frontend/cplusplus-update-frontend.cpp4
-rw-r--r--src/tools/qml2puppet/CMakeLists.txt20
-rw-r--r--src/tools/qml2puppet/qml2puppet.qbs35
-rw-r--r--src/tools/sdktool/CMakeLists.txt2
-rw-r--r--tests/auto/cplusplus/codeformatter/tst_codeformatter.cpp25
-rw-r--r--tests/auto/debugger/tst_dumpers.cpp32
-rw-r--r--tests/auto/qml/codemodel/importscheck/004_cppOnly copy/QtQuick.2/plugins.qmltypes10
-rw-r--r--tests/auto/qml/codemodel/importscheck/base/QtQuick.2/plugins.qmltypes10
-rw-r--r--tests/auto/qml/codemodel/importscheck/importTypes/importQtQuick.qml5
-rw-r--r--tests/auto/qml/codemodel/importscheck/importTypes/imports-QtQuick-qmldir-import/QtQml/plugins.qmltypes26
-rw-r--r--tests/auto/qml/codemodel/importscheck/importTypes/imports-QtQuick-qmldir-import/QtQml/qmldir2
-rw-r--r--tests/auto/qml/codemodel/importscheck/importTypes/imports-QtQuick-qmldir-import/QtQuick.2/plugins.qmltypes175
-rw-r--r--tests/auto/qml/codemodel/importscheck/importTypes/imports-QtQuick-qmldir-import/QtQuick.2/qmldir5
-rw-r--r--tests/auto/qml/codemodel/importscheck/importTypes/imports-QtQuick-simple/QtQuick.2/plugins.qmltypes174
-rw-r--r--tests/auto/qml/codemodel/importscheck/importTypes/imports-QtQuick-simple/QtQuick.2/qmldir4
-rw-r--r--tests/auto/qml/codemodel/importscheck/importTypes/imports-QtQuick-workaround-QtQml/QtQml/plugins.qmltypes26
-rw-r--r--tests/auto/qml/codemodel/importscheck/importTypes/imports-QtQuick-workaround-QtQml/QtQml/qmldir2
-rw-r--r--tests/auto/qml/codemodel/importscheck/importTypes/imports-QtQuick-workaround-QtQml/QtQuick.2/plugins.qmltypes174
-rw-r--r--tests/auto/qml/codemodel/importscheck/importTypes/imports-QtQuick-workaround-QtQml/QtQuick.2/qmldir4
-rw-r--r--tests/auto/qml/codemodel/importscheck/tst_importscheck.cpp97
-rw-r--r--tests/manual/debugger/simple/simple_test_app.cpp4
-rw-r--r--tests/tests.qbs5
-rw-r--r--tests/unit/echoserver/echoserver.qbs30
-rw-r--r--tests/unit/echoserver/echoserverprocessmain.cpp5
-rw-r--r--tests/unit/unit.qbs7
-rw-r--r--tests/unit/unittest/CMakeLists.txt78
-rw-r--r--tests/unit/unittest/clangformat-test.cpp9
-rw-r--r--tests/unit/unittest/clangsupportivetranslationunitinitializer-test.cpp2
-rw-r--r--tests/unit/unittest/clangtooltipinfo-test.cpp9
-rw-r--r--tests/unit/unittest/codecompleter-test.cpp4
-rw-r--r--tests/unit/unittest/conditionally-disabled-tests.h8
-rw-r--r--tests/unit/unittest/creator_dependency.pri2
-rw-r--r--tests/unit/unittest/data/tooltipinfo.cpp3
-rw-r--r--tests/unit/unittest/diagnostic-test.cpp4
-rw-r--r--tests/unit/unittest/gtest-creator-printing.cpp30
-rw-r--r--tests/unit/unittest/gtest-creator-printing.h6
-rw-r--r--tests/unit/unittest/readexporteddiagnostics-test.cpp4
-rw-r--r--tests/unit/unittest/sqlitestatement-test.cpp48
-rw-r--r--tests/unit/unittest/sqlitevalue-test.cpp348
-rw-r--r--tests/unit/unittest/translationunitupdater-test.cpp1
-rw-r--r--tests/unit/unittest/unittest.pro19
-rw-r--r--tests/unit/unittest/unittest.qbs826
1206 files changed, 27701 insertions, 17201 deletions
diff --git a/.gitignore b/.gitignore
index 1579006f2a..c9064490e9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -29,6 +29,7 @@
.DS_Store
.qmake.cache
.qmake.stash
+.vscode
Makefile*
Thumbs.db
core
@@ -114,6 +115,7 @@ compile_commands.json
.pch/
.rcc/
.uic/
+.clangd/
/*-debug/
/*-release/
/dist/gdb/*.gz
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 926cd34165..e355b1d0f2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.9)
+cmake_minimum_required(VERSION 3.10)
## Add paths to check for cmake modules:
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
@@ -6,6 +6,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
include(FeatureSummary)
include(QtCreatorIDEBranding)
include(QtCreatorTranslations)
+include(QtCreatorDocumentation)
set(IDE_REVISION FALSE CACHE BOOL "Marks the presence of IDE revision string.")
set(IDE_REVISION_STR "" CACHE STRING "The IDE revision string.")
@@ -46,40 +47,6 @@ find_package(Qt5 COMPONENTS LinguistTools)
find_package(Threads)
-# Get information on directories from qmake
-# as this is not yet exported by cmake.
-function(qt5_query_qmake)
- if (NOT TARGET Qt5::qmake)
- message(FATAL_ERROR "Qmake was not found.")
- endif()
-
- get_target_property(_qmake_binary Qt5::qmake IMPORTED_LOCATION)
- execute_process(COMMAND "${_qmake_binary}" "-query"
- TIMEOUT 10
- RESULT_VARIABLE _qmake_result
- OUTPUT_VARIABLE _qmake_stdout
- OUTPUT_STRIP_TRAILING_WHITESPACE)
-
- if (NOT "${_qmake_result}" STREQUAL "0")
- message(FATAL_ERROR "Qmake did not execute successfully: ${_qmake_result}.")
- endif()
-
- # split into lines:
- string(REPLACE "\n" ";" _lines "${_qmake_stdout}")
-
- foreach(_line ${_lines})
- # split line into key/value pairs
- string(REPLACE ":" ";" _parts "${_line}")
- list(GET _parts 0 _key)
- list(REMOVE_AT _parts 0)
- string(REPLACE ";" ":" _value "${_parts}")
-
- set("${_key}" "${_value}" CACHE PATH "qmake import of ${_key}" FORCE)
- endforeach()
-endfunction()
-
-qt5_query_qmake()
-
find_package(Qt5 COMPONENTS Designer Help Script SerialPort Svg QUIET)
function (set_if_target var target)
if (TARGET "${target}")
diff --git a/README.md b/README.md
index 896d2e8b71..5281eba9e5 100644
--- a/README.md
+++ b/README.md
@@ -19,13 +19,13 @@ https://wiki.qt.io/Setting_up_Gerrit
See the following page for information about our coding standard:
-https://doc-snapshots.qt.io/qtcreator-extending/coding-style.html
+https://doc.qt.io/qtcreator-extending/coding-style.html
## Compiling Qt Creator
Prerequisites:
-* Qt 5.11.0 or later
+* Qt 5.12.0 or later
* Qt WebEngine module for QtWebEngine based help viewer
* On Windows:
* ActiveState Active Perl
@@ -89,7 +89,7 @@ For detailed information on the supported compilers, see
for example, `c:\work`. If you plan to use MinGW and Microsoft Visual
Studio simultaneously or mix different Qt versions, we recommend
creating a directory structure which reflects that. For example:
- `C:\work\qt5.11.0-vs15, C:\work\qt5.11.0-mingw`.
+ `C:\work\qt5.12.0-vs15, C:\work\qt5.12.0-mingw`.
4. Download and install Perl from <https://www.activestate.com/activeperl>
and check that perl.exe is added to the path. Run `perl -v` to verify
diff --git a/cmake/FindQt5.cmake b/cmake/FindQt5.cmake
index 762ec8810c..304c3fc07d 100644
--- a/cmake/FindQt5.cmake
+++ b/cmake/FindQt5.cmake
@@ -52,7 +52,7 @@ endforeach()
set(Qt5_FOUND ${Qt6_FOUND})
-foreach(tool qmake lrelease)
+foreach(tool qmake lrelease moc)
if (TARGET Qt6::${tool} AND NOT TARGET Qt5::${tool})
add_executable(Qt5::${tool} IMPORTED GLOBAL)
get_target_property(imported_location Qt6::${tool} IMPORTED_LOCATION_RELEASE)
diff --git a/cmake/QtCreatorAPI.cmake b/cmake/QtCreatorAPI.cmake
index d88cff2fc6..4eed007b0e 100644
--- a/cmake/QtCreatorAPI.cmake
+++ b/cmake/QtCreatorAPI.cmake
@@ -3,76 +3,7 @@ if(QT_CREATOR_API_DEFINED)
endif()
set(QT_CREATOR_API_DEFINED TRUE)
-if (CMAKE_VERSION VERSION_LESS 3.16)
- set(BUILD_WITH_PCH OFF)
-endif()
-
-include(FeatureSummary)
-
-#
-# Default Qt compilation defines
-#
-
-list(APPEND DEFAULT_DEFINES
- QT_CREATOR
- QT_NO_JAVA_STYLE_ITERATORS
- QT_NO_CAST_TO_ASCII QT_RESTRICTED_CAST_FROM_ASCII
- QT_DISABLE_DEPRECATED_BEFORE=0x050900
- QT_USE_FAST_OPERATOR_PLUS
- QT_USE_FAST_CONCATENATION
-)
-
-if (WIN32)
- list(APPEND DEFAULT_DEFINES UNICODE _UNICODE _CRT_SECURE_NO_WARNINGS)
-
- if (NOT BUILD_WITH_PCH)
- # Windows 8 0x0602
- list(APPEND DEFAULT_DEFINES
- WINVER=0x0602 _WIN32_WINNT=0x0602
- WIN32_LEAN_AND_MEAN)
- endif()
-endif()
-
-#
-# Setup path handling
-#
-
-if (APPLE)
- set(_IDE_APP_PATH ".")
- set(_IDE_APP_TARGET "${IDE_DISPLAY_NAME}")
-
- set(_IDE_OUTPUT_PATH "${_IDE_APP_PATH}/${_IDE_APP_TARGET}.app/Contents")
-
- set(_IDE_PLUGIN_PATH "${_IDE_OUTPUT_PATH}/PlugIns")
- set(_IDE_LIBRARY_BASE_PATH "Frameworks")
- set(_IDE_LIBRARY_PATH "${_IDE_OUTPUT_PATH}/Frameworks")
- set(_IDE_LIBEXEC_PATH "${_IDE_OUTPUT_PATH}/Resources/libexec")
- set(_IDE_DATA_PATH "${_IDE_OUTPUT_PATH}/Resources")
- set(_IDE_DOC_PATH "${_IDE_OUTPUT_PATH}/Resources/doc")
- set(_IDE_BIN_PATH "${_IDE_OUTPUT_PATH}/MacOS")
-
- set(QT_DEST_PLUGIN_PATH "${_IDE_PLUGIN_PATH}")
- set(QT_DEST_QML_PATH "${_IDE_DATA_PATH}/../Imports/qtquick2")
-else ()
- set(_IDE_APP_PATH "bin")
- set(_IDE_APP_TARGET "${IDE_ID}")
-
- set(_IDE_LIBRARY_BASE_PATH "lib")
- set(_IDE_LIBRARY_PATH "lib/${IDE_ID}")
- set(_IDE_PLUGIN_PATH "lib/${IDE_ID}/plugins")
- if (WIN32)
- set(_IDE_LIBEXEC_PATH "bin")
- set(QT_DEST_PLUGIN_PATH "bin/plugins")
- set(QT_DEST_QML_PATH "bin/qml")
- else ()
- set(_IDE_LIBEXEC_PATH "libexec/${IDE_ID}")
- set(QT_DEST_PLUGIN_PATH "lib/Qt/plugins")
- set(QT_DEST_QML_PATH "lib/Qt/qml")
- endif ()
- set(_IDE_DATA_PATH "share/${IDE_ID}")
- set(_IDE_DOC_PATH "share/doc/${IDE_ID}")
- set(_IDE_BIN_PATH "bin")
-endif ()
+include(${CMAKE_CURRENT_LIST_DIR}/QtCreatorAPIInternal.cmake)
set(IDE_APP_PATH "${_IDE_APP_PATH}") # The target path of the IDE application (relative to CMAKE_INSTALL_PREFIX).
set(IDE_APP_TARGET "${_IDE_APP_TARGET}") # The IDE application name.
@@ -96,232 +27,9 @@ list(APPEND DEFAULT_DEFINES
RELATIVE_DOC_PATH="${RELATIVE_DOC_PATH}"
)
-file(RELATIVE_PATH _PLUGIN_TO_LIB "/${IDE_PLUGIN_PATH}" "/${IDE_LIBRARY_PATH}")
-file(RELATIVE_PATH _PLUGIN_TO_QT "/${IDE_PLUGIN_PATH}" "/${IDE_LIBRARY_BASE_PATH}/Qt/lib")
-file(RELATIVE_PATH _LIB_TO_QT "/${IDE_LIBRARY_PATH}" "/${IDE_LIBRARY_BASE_PATH}/Qt/lib")
-
-if (APPLE)
- set(_RPATH_BASE "@executable_path")
- set(_LIB_RPATH "@loader_path")
- set(_PLUGIN_RPATH "@loader_path;@loader_path/${_PLUGIN_TO_LIB}")
-elseif (WIN32)
- set(_RPATH_BASE "")
- set(_LIB_RPATH "")
- set(_PLUGIN_RPATH "")
-else()
- set(_RPATH_BASE "\$ORIGIN")
- set(_LIB_RPATH "\$ORIGIN;\$ORIGIN/${_LIB_TO_QT}")
- set(_PLUGIN_RPATH "\$ORIGIN;\$ORIGIN/${_PLUGIN_TO_LIB};\$ORIGIN/${_PLUGIN_TO_QT}")
-endif ()
-
-set(__QTC_PLUGINS "" CACHE INTERNAL "*** Internal ***")
-set(__QTC_INSTALLED_PLUGINS "" CACHE INTERNAL "*** Internal ***")
-set(__QTC_LIBRARIES "" CACHE INTERNAL "*** Internal ***")
-set(__QTC_INSTALLED_LIBRARIES "" CACHE INTERNAL "*** Internal ***")
-set(__QTC_EXECUTABLES "" CACHE INTERNAL "*** Internal ***")
-set(__QTC_INSTALLED_EXECUTABLES "" CACHE INTERNAL "*** Internal ***")
-set(__QTC_TESTS "" CACHE INTERNAL "*** Internal ***")
-
-#
-# Internal functions
-#
-
-function(append_extra_translations target_name)
- if(NOT ARGN)
- return()
- endif()
-
- if(TARGET "${target_name}")
- get_target_property(_input "${target_name}" QT_EXTRA_TRANSLATIONS)
- if (_input)
- set(_output "${_input}" "${ARGN}")
- else()
- set(_output "${ARGN}")
- endif()
- set_target_properties("${target_name}" PROPERTIES QT_EXTRA_TRANSLATIONS "${_output}")
- endif()
-endfunction()
-
-function(update_cached_list name value)
- set(_tmp_list "${${name}}")
- list(APPEND _tmp_list "${value}")
- set("${name}" "${_tmp_list}" CACHE INTERNAL "*** Internal ***")
-endfunction()
-
-function(compare_sources_with_existing_disk_files target_name sources)
- if(NOT WITH_DEBUG_CMAKE)
- return()
- endif()
-
- file(GLOB_RECURSE existing_files RELATIVE ${CMAKE_CURRENT_LIST_DIR} "*.cpp" "*.hpp" "*.c" "*.h" "*.ui" "*.qrc")
- foreach(file IN LISTS existing_files)
- if(NOT ${file} IN_LIST sources)
- if (NOT WITH_TESTS AND ${file} MATCHES "test")
- continue()
- endif()
- message(STATUS "${target_name} doesn't include ${file}")
- endif()
- endforeach()
-
- foreach(source IN LISTS "${sources}")
- if(NOT ${source} IN_LIST existing_files)
- if (NOT WITH_TESTS AND ${file} MATCHES "test")
- continue()
- endif()
- message(STATUS "${target_name} contains non existing ${source}")
- endif()
- endforeach()
-endfunction(compare_sources_with_existing_disk_files)
-
-function(separate_object_libraries libraries REGULAR_LIBS OBJECT_LIBS OBJECT_LIB_OBJECTS)
- if (CMAKE_VERSION VERSION_LESS 3.14)
- foreach(lib IN LISTS libraries)
- if (TARGET ${lib})
- get_target_property(lib_type ${lib} TYPE)
- if (lib_type STREQUAL "OBJECT_LIBRARY")
- list(APPEND object_libs ${lib})
- list(APPEND object_libs_objects $<TARGET_OBJECTS:${lib}>)
- else()
- list(APPEND regular_libs ${lib})
- endif()
- else()
- list(APPEND regular_libs ${lib})
- endif()
- set(${REGULAR_LIBS} ${regular_libs} PARENT_SCOPE)
- set(${OBJECT_LIBS} ${object_libs} PARENT_SCOPE)
- set(${OBJECT_LIB_OBJECTS} ${object_libs_objects} PARENT_SCOPE)
- endforeach()
- else()
- set(${REGULAR_LIBS} ${libraries} PARENT_SCOPE)
- unset(${OBJECT_LIBS} PARENT_SCOPE)
- unset(${OBJECT_LIB_OBJECTS} PARENT_SCOPE)
- endif()
-endfunction(separate_object_libraries)
-
-function(set_explicit_moc target_name file)
- unset(file_dependencies)
- if (file MATCHES "^.*plugin.h$")
- set(file_dependencies DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${target_name}.json")
- endif()
- set_property(SOURCE "${file}" PROPERTY SKIP_AUTOMOC ON)
- qt5_wrap_cpp(file_moc "${file}" ${file_dependencies})
- target_sources(${target_name} PRIVATE "${file_moc}")
-endfunction()
-
-function(set_public_headers target sources)
- foreach(source IN LISTS sources)
- if (source MATCHES "\.h$|\.hpp$")
-
- if (NOT IS_ABSOLUTE ${source})
- set(source "${CMAKE_CURRENT_SOURCE_DIR}/${source}")
- endif()
-
- get_filename_component(source_dir ${source} DIRECTORY)
- file(RELATIVE_PATH include_dir_relative_path ${PROJECT_SOURCE_DIR} ${source_dir})
-
- install(
- FILES ${source}
- DESTINATION "include/${include_dir_relative_path}"
- COMPONENT Devel EXCLUDE_FROM_ALL
- )
- endif()
- endforeach()
-endfunction()
-
-function(set_public_includes target includes)
- foreach(inc_dir IN LISTS includes)
- if (NOT IS_ABSOLUTE ${inc_dir})
- set(inc_dir "${CMAKE_CURRENT_SOURCE_DIR}/${inc_dir}")
- endif()
- file(RELATIVE_PATH include_dir_relative_path ${PROJECT_SOURCE_DIR} ${inc_dir})
- target_include_directories(${target} PUBLIC
- $<BUILD_INTERFACE:${inc_dir}>
- $<INSTALL_INTERFACE:include/${include_dir_relative_path}>
- )
- endforeach()
-endfunction()
-
-function(finalize_test_setup test_name)
- # Never translate tests:
- set_tests_properties(${name}
- PROPERTIES
- QT_SKIP_TRANSLATION ON
- TIMEOUT 5
- )
-
- if (WIN32)
- list(APPEND env_path $ENV{PATH})
- list(APPEND env_path ${CMAKE_BINARY_DIR}/${IDE_PLUGIN_PATH})
- list(APPEND env_path ${CMAKE_BINARY_DIR}/${IDE_BIN_PATH})
- list(APPEND env_path $<TARGET_FILE_DIR:Qt5::Test>)
- if (TARGET libclang)
- list(APPEND env_path $<TARGET_FILE_DIR:libclang>)
- endif()
-
- if (TARGET elfutils::elf)
- list(APPEND env_path $<TARGET_FILE_DIR:elfutils::elf>)
- endif()
-
- string(REPLACE "/" "\\" env_path "${env_path}")
- string(REPLACE ";" "\\;" env_path "${env_path}")
-
- set_tests_properties(${test_name} PROPERTIES ENVIRONMENT "PATH=${env_path}")
- endif()
-endfunction()
-
-function(add_qtc_depends target_name)
- cmake_parse_arguments(_arg "" "" "PRIVATE;PUBLIC" ${ARGN})
- if (${_arg_UNPARSED_ARGUMENTS})
- message(FATAL_ERROR "add_qtc_depends had unparsed arguments")
- endif()
-
- separate_object_libraries("${_arg_PRIVATE}"
- depends object_lib_depends object_lib_depends_objects)
- separate_object_libraries("${_arg_PUBLIC}"
- public_depends object_public_depends object_public_depends_objects)
-
- target_sources(${target_name} PRIVATE ${object_lib_depends_objects} ${object_public_depends_objects})
-
- get_target_property(target_type ${target_name} TYPE)
- if (NOT target_type STREQUAL "OBJECT_LIBRARY")
- target_link_libraries(${target_name} PRIVATE ${depends} PUBLIC ${public_depends})
- else()
- list(APPEND object_lib_depends ${depends})
- list(APPEND object_public_depends ${public_depends})
- endif()
-
- foreach(obj_lib IN LISTS object_lib_depends)
- target_compile_definitions(${target_name} PRIVATE $<TARGET_PROPERTY:${obj_lib},INTERFACE_COMPILE_DEFINITIONS>)
- target_include_directories(${target_name} PRIVATE $<TARGET_PROPERTY:${obj_lib},INTERFACE_INCLUDE_DIRECTORIES>)
- endforeach()
- foreach(obj_lib IN LISTS object_public_depends)
- target_compile_definitions(${target_name} PUBLIC $<TARGET_PROPERTY:${obj_lib},INTERFACE_COMPILE_DEFINITIONS>)
- target_include_directories(${target_name} PUBLIC $<TARGET_PROPERTY:${obj_lib},INTERFACE_INCLUDE_DIRECTORIES>)
- endforeach()
-endfunction()
-
-function(find_dependent_plugins varName)
- set(_RESULT ${ARGN})
-
- foreach(i ${ARGN})
- get_property(_dep TARGET "${i}" PROPERTY _arg_DEPENDS)
- if (_dep)
- find_dependent_plugins(_REC ${_dep})
- list(APPEND _RESULT ${_REC})
- endif()
- endforeach()
-
- if (_RESULT)
- list(REMOVE_DUPLICATES _RESULT)
- list(SORT _RESULT)
- endif()
-
- set("${varName}" ${_RESULT} PARENT_SCOPE)
-endfunction()
-
function(qtc_plugin_enabled varName name)
if (NOT (name IN_LIST __QTC_PLUGINS))
- message(FATAL_ERROR "extend_qtc_plugin: Unknown plugin target \"${name}\"")
+ message(FATAL_ERROR "qtc_plugin_enabled: Unknown plugin target \"${name}\"")
endif()
if (TARGET ${name})
set(${varName} ON PARENT_SCOPE)
@@ -332,7 +40,7 @@ endfunction()
function(qtc_library_enabled varName name)
if (NOT (name IN_LIST __QTC_LIBRARIES))
- message(FATAL_ERROR "extend_qtc_library: Unknown library target \"${name}\"")
+ message(FATAL_ERROR "qtc_library_enabled: Unknown library target \"${name}\"")
endif()
if (TARGET ${name})
set(${varName} ON PARENT_SCOPE)
@@ -341,82 +49,6 @@ function(qtc_library_enabled varName name)
endif()
endfunction()
-function(enable_pch target)
- if (BUILD_WITH_PCH)
- # Skip PCH for targets that do not use the expected visibility settings:
- get_target_property(visibility_property "${target}" CXX_VISIBILITY_PRESET)
- get_target_property(inlines_property "${target}" VISIBILITY_INLINES_HIDDEN)
-
- if (NOT visibility_property STREQUAL "hidden" OR NOT inlines_property)
- return()
- endif()
-
- # Skip PCH for targets that do not have QT_NO_CAST_TO_ASCII
- get_target_property(target_defines "${target}" COMPILE_DEFINITIONS)
- if (NOT "QT_NO_CAST_TO_ASCII" IN_LIST target_defines)
- return()
- endif()
-
- get_target_property(target_type ${target} TYPE)
- if (NOT ${target_type} STREQUAL "OBJECT_LIBRARY")
- function(_recursively_collect_dependencies input_target)
- get_target_property(input_type ${input_target} TYPE)
- if (${input_type} STREQUAL "INTERFACE_LIBRARY")
- set(prefix "INTERFACE_")
- endif()
- get_target_property(link_libraries ${input_target} ${prefix}LINK_LIBRARIES)
- foreach(library IN LISTS link_libraries)
- if(TARGET ${library} AND NOT ${library} IN_LIST dependencies)
- list(APPEND dependencies ${library})
- _recursively_collect_dependencies(${library})
- endif()
- endforeach()
- set(dependencies ${dependencies} PARENT_SCOPE)
- endfunction()
- _recursively_collect_dependencies(${target})
-
- function(_add_pch_target pch_target pch_file pch_dependency)
- if (EXISTS ${pch_file})
- add_library(${pch_target} STATIC
- ${CMAKE_CURRENT_BINARY_DIR}/empty_pch.cpp
- ${CMAKE_CURRENT_BINARY_DIR}/empty_pch.c)
- target_compile_definitions(${pch_target} PRIVATE ${DEFAULT_DEFINES})
- set_target_properties(${pch_target} PROPERTIES
- PRECOMPILE_HEADERS ${pch_file}
- CXX_VISIBILITY_PRESET hidden
- VISIBILITY_INLINES_HIDDEN ON)
- target_link_libraries(${pch_target} PRIVATE ${pch_dependency})
- endif()
- endfunction()
-
- if (NOT TARGET QtCreatorPchGui AND NOT TARGET QtCreatorPchConsole)
- file(GENERATE
- OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/empty_pch.c
- CONTENT "/*empty file*/")
- file(GENERATE
- OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/empty_pch.cpp
- CONTENT "/*empty file*/")
- _add_pch_target(QtCreatorPchGui
- "${PROJECT_SOURCE_DIR}/src/shared/qtcreator_gui_pch.h" Qt5::Widgets)
- _add_pch_target(QtCreatorPchConsole
- "${PROJECT_SOURCE_DIR}/src/shared/qtcreator_pch.h" Qt5::Core)
- endif()
-
- unset(PCH_TARGET)
- if ("Qt5::Widgets" IN_LIST dependencies)
- set(PCH_TARGET QtCreatorPchGui)
- elseif ("Qt5::Core" IN_LIST dependencies)
- set(PCH_TARGET QtCreatorPchConsole)
- endif()
-
- if (TARGET "${PCH_TARGET}")
- set_target_properties(${target} PROPERTIES
- PRECOMPILE_HEADERS_REUSE_FROM ${PCH_TARGET})
- endif()
- endif()
- endif()
-endfunction()
-
function(qtc_output_binary_dir varName)
if (QTC_MERGE_BINARY_DIR)
set(${varName} ${QtCreator_BINARY_DIR} PARENT_SCOPE)
@@ -425,23 +57,10 @@ function(qtc_output_binary_dir varName)
endif()
endfunction()
-function(condition_info varName condition)
- if (NOT ${condition})
- set(${varName} "" PARENT_SCOPE)
- else()
- string(REPLACE ";" " " _contents "${${condition}}")
- set(${varName} "with CONDITION ${_contents}" PARENT_SCOPE)
- endif()
-endfunction()
-
-#
-# Public API functions
-#
-
function(add_qtc_library name)
cmake_parse_arguments(_arg "STATIC;OBJECT;SKIP_TRANSLATION;BUILD_BY_DEFAULT;ALLOW_ASCII_CASTS;UNVERSIONED"
"DESTINATION;COMPONENT"
- "DEFINES;DEPENDS;EXTRA_TRANSLATIONS;INCLUDES;PUBLIC_DEFINES;PUBLIC_DEPENDS;PUBLIC_INCLUDES;SOURCES;EXPLICIT_MOC;SKIP_AUTOMOC;PROPERTIES" ${ARGN}
+ "DEPENDS;PUBLIC_DEPENDS;DEFINES;PUBLIC_DEFINES;INCLUDES;PUBLIC_INCLUDES;SOURCES;EXPLICIT_MOC;SKIP_AUTOMOC;EXTRA_TRANSLATIONS;PROPERTIES" ${ARGN}
)
set(default_defines_copy ${DEFAULT_DEFINES})
@@ -497,35 +116,26 @@ function(add_qtc_library name)
set(TEST_DEFINES WITH_TESTS SRCDIR="${CMAKE_CURRENT_SOURCE_DIR}")
endif()
- file(RELATIVE_PATH include_dir_relative_path ${PROJECT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
+ extend_qtc_target(${name}
+ INCLUDES ${_arg_INCLUDES}
+ PUBLIC_INCLUDES ${_arg_PUBLIC_INCLUDES}
+ DEFINES ${EXPORT_SYMBOL} ${default_defines_copy} ${_arg_DEFINES} ${TEST_DEFINES}
+ PUBLIC_DEFINES ${_arg_PUBLIC_DEFINES}
+ DEPENDS ${_arg_DEPENDS} ${IMPLICIT_DEPENDS}
+ PUBLIC_DEPENDS ${_arg_PUBLIC_DEPENDS}
+ EXPLICIT_MOC ${_arg_EXPLICIT_MOC}
+ SKIP_AUTOMOC ${_arg_SKIP_AUTOMOC}
+ EXTRA_TRANSLATIONS ${_arg_EXTRA_TRANSLATIONS}
+ )
+ file(RELATIVE_PATH include_dir_relative_path ${PROJECT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
target_include_directories(${name}
PRIVATE
- ${_arg_INCLUDES}
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>"
PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>"
"$<INSTALL_INTERFACE:include/${include_dir_relative_path}/..>"
)
- set_public_includes(${name} "${_arg_PUBLIC_INCLUDES}")
-
- target_compile_definitions(${name}
- PRIVATE ${EXPORT_SYMBOL} ${default_defines_copy} ${_arg_DEFINES} ${TEST_DEFINES}
- PUBLIC ${_arg_PUBLIC_DEFINES}
- )
-
- add_qtc_depends(${name}
- PRIVATE ${_arg_DEPENDS} ${IMPLICIT_DEPENDS}
- PUBLIC ${_arg_PUBLIC_DEPENDS}
- )
-
- foreach(file IN LISTS _arg_EXPLICIT_MOC)
- set_explicit_moc(${name} "${file}")
- endforeach()
-
- foreach(file IN LISTS _arg_SKIP_AUTOMOC)
- set_property(SOURCE ${file} PROPERTY SKIP_AUTOMOC ON)
- endforeach()
set(skip_translation OFF)
if (_arg_SKIP_TRANSLATION)
@@ -619,15 +229,13 @@ function(add_qtc_library name)
OPTIONAL
)
endif()
-
- append_extra_translations("${name}" "${_arg_EXTRA_TRANSLATIONS}")
endfunction(add_qtc_library)
function(add_qtc_plugin target_name)
cmake_parse_arguments(_arg
"EXPERIMENTAL;SKIP_DEBUG_CMAKE_FILE_CHECK;SKIP_INSTALL;INTERNAL_ONLY;SKIP_TRANSLATION"
"VERSION;COMPAT_VERSION;PLUGIN_JSON_IN;PLUGIN_PATH;PLUGIN_NAME;OUTPUT_NAME"
- "CONDITION;DEPENDS;EXTRA_TRANSLATIONS;PUBLIC_DEPENDS;DEFINES;PUBLIC_DEFINES;INCLUDES;PUBLIC_INCLUDES;PLUGIN_DEPENDS;PLUGIN_RECOMMENDS;SOURCES;EXPLICIT_MOC"
+ "CONDITION;DEPENDS;PUBLIC_DEPENDS;DEFINES;PUBLIC_DEFINES;INCLUDES;PUBLIC_INCLUDES;SOURCES;EXPLICIT_MOC;SKIP_AUTOMOC;EXTRA_TRANSLATIONS;PLUGIN_DEPENDS;PLUGIN_RECOMMENDS"
${ARGN}
)
@@ -752,11 +360,21 @@ function(add_qtc_plugin target_name)
set(TEST_DEFINES WITH_TESTS SRCDIR="${CMAKE_CURRENT_SOURCE_DIR}")
endif()
- file(RELATIVE_PATH include_dir_relative_path ${PROJECT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
+ extend_qtc_target(${target_name}
+ INCLUDES ${_arg_INCLUDES}
+ PUBLIC_INCLUDES ${_arg_PUBLIC_INCLUDES}
+ DEFINES ${EXPORT_SYMBOL} ${DEFAULT_DEFINES} ${_arg_DEFINES} ${TEST_DEFINES}
+ PUBLIC_DEFINES ${_arg_PUBLIC_DEFINES}
+ DEPENDS ${_arg_DEPENDS} ${_DEP_PLUGINS} ${IMPLICIT_DEPENDS}
+ PUBLIC_DEPENDS ${_arg_PUBLIC_DEPENDS}
+ EXPLICIT_MOC ${_arg_EXPLICIT_MOC}
+ SKIP_AUTOMOC ${_arg_SKIP_AUTOMOC}
+ EXTRA_TRANSLATIONS ${_arg_EXTRA_TRANSLATIONS}
+ )
+ file(RELATIVE_PATH include_dir_relative_path ${PROJECT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
target_include_directories(${target_name}
PRIVATE
- ${_arg_INCLUDES}
"${CMAKE_CURRENT_BINARY_DIR}"
"${CMAKE_BINARY_DIR}/src"
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>"
@@ -764,17 +382,6 @@ function(add_qtc_plugin target_name)
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>"
"$<INSTALL_INTERFACE:include/${include_dir_relative_path}/..>"
)
- set_public_includes(${target_name} "${_arg_PUBLIC_INCLUDES}")
-
- target_compile_definitions(${target_name}
- PRIVATE ${EXPORT_SYMBOL} ${DEFAULT_DEFINES} ${_arg_DEFINES} ${TEST_DEFINES}
- PUBLIC ${_arg_PUBLIC_DEFINES}
- )
-
- add_qtc_depends(${target_name}
- PRIVATE ${_arg_DEPENDS} ${_DEP_PLUGINS} ${IMPLICIT_DEPENDS}
- PUBLIC ${_arg_PUBLIC_DEPENDS}
- )
set(plugin_dir "${IDE_PLUGIN_PATH}")
if (_arg_PLUGIN_PATH)
@@ -811,13 +418,8 @@ function(add_qtc_plugin target_name)
PREFIX ""
)
endif()
- append_extra_translations("${target_name}" "${_arg_EXTRA_TRANSLATIONS}")
enable_pch(${target_name})
- foreach(file IN LISTS _arg_EXPLICIT_MOC)
- set_explicit_moc(${target_name} "${file}")
- endforeach()
-
if (NOT _arg_SKIP_INSTALL)
install(TARGETS ${target_name}
EXPORT ${IDE_CASED_ID}
@@ -841,76 +443,6 @@ function(add_qtc_plugin target_name)
endif()
endfunction()
-function(extend_qtc_target target_name)
- cmake_parse_arguments(_arg
- ""
- "SOURCES_PREFIX;FEATURE_INFO"
- "CONDITION;DEPENDS;PUBLIC_DEPENDS;DEFINES;PUBLIC_DEFINES;INCLUDES;PUBLIC_INCLUDES;SOURCES;EXPLICIT_MOC"
- ${ARGN}
- )
-
- if (${_arg_UNPARSED_ARGUMENTS})
- message(FATAL_ERROR "extend_qtc_target had unparsed arguments")
- endif()
-
- condition_info(_extra_text _arg_CONDITION)
- if (NOT _arg_CONDITION)
- set(_arg_CONDITION ON)
- endif()
- if (${_arg_CONDITION})
- set(_feature_enabled ON)
- else()
- set(_feature_enabled OFF)
- endif()
- if (_arg_FEATURE_INFO)
- add_feature_info(${_arg_FEATURE_INFO} _feature_enabled "${_extra_text}")
- endif()
- if (NOT _feature_enabled)
- return()
- endif()
-
- add_qtc_depends(${target_name}
- PRIVATE ${_arg_DEPENDS}
- PUBLIC ${_arg_PUBLIC_DEPENDS}
- )
- target_compile_definitions(${target_name}
- PRIVATE ${_arg_DEFINES}
- PUBLIC ${_arg_PUBLIC_DEFINES}
- )
- target_include_directories(${target_name} PRIVATE ${_arg_INCLUDES})
-
- set_public_includes(${target_name} "${_arg_PUBLIC_INCLUDES}")
-
- if (_arg_SOURCES_PREFIX)
- foreach(source IN LISTS _arg_SOURCES)
- list(APPEND prefixed_sources "${_arg_SOURCES_PREFIX}/${source}")
- endforeach()
-
- if (NOT IS_ABSOLUTE ${_arg_SOURCES_PREFIX})
- set(_arg_SOURCES_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/${_arg_SOURCES_PREFIX}")
- endif()
- target_include_directories(${target_name} PRIVATE $<BUILD_INTERFACE:${_arg_SOURCES_PREFIX}>)
-
- set(_arg_SOURCES ${prefixed_sources})
- endif()
- target_sources(${target_name} PRIVATE ${_arg_SOURCES})
-
- if (APPLE AND BUILD_WITH_PCH)
- foreach(source IN LISTS _arg_SOURCES)
- if (source MATCHES "^.*\.mm$")
- set_source_files_properties(${source} PROPERTIES SKIP_PRECOMPILE_HEADERS ON)
- endif()
- endforeach()
- endif()
-
- set_public_headers(${target_name} "${_arg_SOURCES}")
-
- foreach(file IN LISTS _arg_EXPLICIT_MOC)
- set_explicit_moc(${target_name} "${file}")
- endforeach()
-
-endfunction()
-
function(extend_qtc_plugin target_name)
qtc_plugin_enabled(_plugin_enabled ${target_name})
if (NOT _plugin_enabled)
@@ -929,10 +461,17 @@ function(extend_qtc_library target_name)
extend_qtc_target(${target_name} ${ARGN})
endfunction()
+function(extend_qtc_test target_name)
+ if (NOT (target_name IN_LIST __QTC_TESTS))
+ message(FATAL_ERROR "extend_qtc_test: Unknown test target \"${name}\"")
+ endif()
+ extend_qtc_target(${target_name} ${ARGN})
+endfunction()
+
function(add_qtc_executable name)
cmake_parse_arguments(_arg "SKIP_INSTALL;SKIP_TRANSLATION;ALLOW_ASCII_CASTS"
"DESTINATION;COMPONENT"
- "DEFINES;DEPENDS;EXTRA_TRANSLATIONS;INCLUDES;SOURCES;PROPERTIES" ${ARGN})
+ "DEPENDS;DEFINES;INCLUDES;SOURCES;EXPLICIT_MOC;SKIP_AUTOMOC;EXTRA_TRANSLATIONS;PROPERTIES" ${ARGN})
if ($_arg_UNPARSED_ARGUMENTS)
message(FATAL_ERROR "add_qtc_executable had unparsed arguments!")
@@ -975,9 +514,15 @@ function(add_qtc_executable name)
endif()
add_executable("${name}" ${_arg_SOURCES})
- target_include_directories("${name}" PRIVATE "${CMAKE_BINARY_DIR}/src" ${_arg_INCLUDES})
- target_compile_definitions("${name}" PRIVATE ${default_defines_copy} ${TEST_DEFINES} ${_arg_DEFINES} )
- target_link_libraries("${name}" PRIVATE ${_arg_DEPENDS} ${IMPLICIT_DEPENDS})
+
+ extend_qtc_target("${name}"
+ INCLUDES "${CMAKE_BINARY_DIR}/src" ${_arg_INCLUDES}
+ DEFINES ${default_defines_copy} ${TEST_DEFINES} ${_arg_DEFINES}
+ DEPENDS ${_arg_DEPENDS} ${IMPLICIT_DEPENDS}
+ EXPLICIT_MOC ${_arg_EXPLICIT_MOC}
+ SKIP_AUTOMOC ${_arg_SKIP_AUTOMOC}
+ EXTRA_TRANSLATIONS ${_arg_EXTRA_TRANSLATIONS}
+ )
set(skip_translation OFF)
if (_arg_SKIP_TRANSLATION)
@@ -1005,7 +550,6 @@ function(add_qtc_executable name)
VISIBILITY_INLINES_HIDDEN ON
${_arg_PROPERTIES}
)
- append_extra_translations("${name}" "${_arg_EXTRA_TRANSLATIONS}")
enable_pch(${name})
if (NOT _arg_SKIP_INSTALL)
@@ -1089,7 +633,7 @@ function(extend_qtc_executable name)
endfunction()
function(add_qtc_test name)
- cmake_parse_arguments(_arg "GTEST" "" "DEFINES;DEPENDS;INCLUDES;SOURCES" ${ARGN})
+ cmake_parse_arguments(_arg "GTEST" "" "DEFINES;DEPENDS;INCLUDES;SOURCES;EXPLICIT_MOC;SKIP_AUTOMOC" ${ARGN})
foreach(dependency ${_arg_DEPENDS})
if (NOT TARGET ${dependency} AND NOT _arg_GTEST)
@@ -1111,13 +655,14 @@ function(add_qtc_test name)
add_executable(${name} ${_arg_SOURCES})
- add_qtc_depends(${name}
- PRIVATE ${_arg_DEPENDS} ${IMPLICIT_DEPENDS}
+ extend_qtc_target(${name}
+ DEPENDS ${_arg_DEPENDS} ${IMPLICIT_DEPENDS}
+ INCLUDES "${CMAKE_BINARY_DIR}/src" ${_arg_INCLUDES}
+ DEFINES ${_arg_DEFINES} ${TEST_DEFINES} ${DEFAULT_DEFINES}
+ EXPLICIT_MOC ${_arg_EXPLICIT_MOC}
+ SKIP_AUTOMOC ${_arg_SKIP_AUTOMOC}
)
- target_include_directories(${name} PRIVATE "${CMAKE_BINARY_DIR}/src" ${_arg_INCLUDES})
- target_compile_definitions(${name} PRIVATE ${_arg_DEFINES} ${TEST_DEFINES} ${DEFAULT_DEFINES})
-
set_target_properties(${name} PROPERTIES
BUILD_RPATH "${_RPATH_BASE}/${_RPATH}"
INSTALL_RPATH "${_RPATH_BASE}/${_RPATH}"
@@ -1155,3 +700,55 @@ function(qtc_glob_resources)
string(APPEND qrcData "</qresource></RCC>")
file(WRITE "${_arg_QRC_FILE}" "${qrcData}")
endfunction()
+
+function(qtc_copy_to_builddir custom_target_name)
+ cmake_parse_arguments(_arg "CREATE_SUBDIRS" "DESTINATION" "FILES;DIRECTORIES" ${ARGN})
+ set(timestampFiles)
+
+ qtc_output_binary_dir(_output_binary_dir)
+
+ foreach(srcFile ${_arg_FILES})
+ string(MAKE_C_IDENTIFIER "${srcFile}" destinationTimestampFilePart)
+ set(destinationTimestampFileName "${CMAKE_CURRENT_BINARY_DIR}/.${destinationTimestampFilePart}_timestamp")
+ list(APPEND timestampFiles "${destinationTimestampFileName}")
+
+ if (IS_ABSOLUTE "${srcFile}")
+ set(srcPath "")
+ else()
+ get_filename_component(srcPath "${srcFile}" DIRECTORY)
+ endif()
+
+ add_custom_command(OUTPUT "${destinationTimestampFileName}"
+ COMMAND "${CMAKE_COMMAND}" -E make_directory "${_output_binary_dir}/${_arg_DESTINATION}/${srcPath}"
+ COMMAND "${CMAKE_COMMAND}" -E copy "${srcFile}" "${_output_binary_dir}/${_arg_DESTINATION}/${srcPath}"
+ COMMAND "${CMAKE_COMMAND}" -E touch "${destinationTimestampFileName}"
+ WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
+ COMMENT "Copy ${srcFile} into build directory"
+ DEPENDS "${srcFile}"
+ VERBATIM
+ )
+ endforeach()
+
+ foreach(srcDirectory ${_arg_DIRECTORIES})
+ string(MAKE_C_IDENTIFIER "${srcDirectory}" destinationTimestampFilePart)
+ set(destinationTimestampFileName "${CMAKE_CURRENT_BINARY_DIR}/.${destinationTimestampFilePart}_timestamp")
+ list(APPEND timestampFiles "${destinationTimestampFileName}")
+ set(destinationDirectory "${_output_binary_dir}/${_arg_DESTINATION}")
+
+ if(_arg_CREATE_SUBDIRS)
+ set(destinationDirectory "${destinationDirectory}/${srcDirectory}")
+ endif()
+
+ file(GLOB_RECURSE filesToCopy "${srcDirectory}/*")
+ add_custom_command(OUTPUT "${destinationTimestampFileName}"
+ COMMAND "${CMAKE_COMMAND}" -E copy_directory "${srcDirectory}" "${destinationDirectory}"
+ COMMAND "${CMAKE_COMMAND}" -E touch "${destinationTimestampFileName}"
+ WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
+ COMMENT "Copy ${srcDirectory}/ into build directory"
+ DEPENDS ${filesToCopy}
+ VERBATIM
+ )
+ endforeach()
+
+ add_custom_target("${custom_target_name}" ALL DEPENDS ${timestampFiles})
+endfunction()
diff --git a/cmake/QtCreatorAPIInternal.cmake b/cmake/QtCreatorAPIInternal.cmake
new file mode 100644
index 0000000000..2a743968d9
--- /dev/null
+++ b/cmake/QtCreatorAPIInternal.cmake
@@ -0,0 +1,449 @@
+if (CMAKE_VERSION VERSION_LESS 3.16)
+ set(BUILD_WITH_PCH OFF)
+endif()
+
+include(FeatureSummary)
+
+#
+# Default Qt compilation defines
+#
+
+list(APPEND DEFAULT_DEFINES
+ QT_CREATOR
+ QT_NO_JAVA_STYLE_ITERATORS
+ QT_NO_CAST_TO_ASCII QT_RESTRICTED_CAST_FROM_ASCII
+ QT_DISABLE_DEPRECATED_BEFORE=0x050900
+ QT_USE_FAST_OPERATOR_PLUS
+ QT_USE_FAST_CONCATENATION
+)
+
+if (WIN32)
+ list(APPEND DEFAULT_DEFINES UNICODE _UNICODE _CRT_SECURE_NO_WARNINGS)
+
+ if (NOT BUILD_WITH_PCH)
+ # Windows 8 0x0602
+ list(APPEND DEFAULT_DEFINES
+ WINVER=0x0602 _WIN32_WINNT=0x0602
+ WIN32_LEAN_AND_MEAN)
+ endif()
+endif()
+
+#
+# Setup path handling
+#
+
+if (APPLE)
+ set(_IDE_APP_PATH ".")
+ set(_IDE_APP_TARGET "${IDE_DISPLAY_NAME}")
+
+ set(_IDE_OUTPUT_PATH "${_IDE_APP_PATH}/${_IDE_APP_TARGET}.app/Contents")
+
+ set(_IDE_PLUGIN_PATH "${_IDE_OUTPUT_PATH}/PlugIns")
+ set(_IDE_LIBRARY_BASE_PATH "Frameworks")
+ set(_IDE_LIBRARY_PATH "${_IDE_OUTPUT_PATH}/Frameworks")
+ set(_IDE_LIBEXEC_PATH "${_IDE_OUTPUT_PATH}/Resources/libexec")
+ set(_IDE_DATA_PATH "${_IDE_OUTPUT_PATH}/Resources")
+ set(_IDE_DOC_PATH "${_IDE_OUTPUT_PATH}/Resources/doc")
+ set(_IDE_BIN_PATH "${_IDE_OUTPUT_PATH}/MacOS")
+
+ set(QT_DEST_PLUGIN_PATH "${_IDE_PLUGIN_PATH}")
+ set(QT_DEST_QML_PATH "${_IDE_DATA_PATH}/../Imports/qtquick2")
+else ()
+ set(_IDE_APP_PATH "bin")
+ set(_IDE_APP_TARGET "${IDE_ID}")
+
+ set(_IDE_LIBRARY_BASE_PATH "lib")
+ set(_IDE_LIBRARY_PATH "lib/${IDE_ID}")
+ set(_IDE_PLUGIN_PATH "lib/${IDE_ID}/plugins")
+ if (WIN32)
+ set(_IDE_LIBEXEC_PATH "bin")
+ set(QT_DEST_PLUGIN_PATH "bin/plugins")
+ set(QT_DEST_QML_PATH "bin/qml")
+ else ()
+ set(_IDE_LIBEXEC_PATH "libexec/${IDE_ID}")
+ set(QT_DEST_PLUGIN_PATH "lib/Qt/plugins")
+ set(QT_DEST_QML_PATH "lib/Qt/qml")
+ endif ()
+ set(_IDE_DATA_PATH "share/${IDE_ID}")
+ set(_IDE_DOC_PATH "share/doc/${IDE_ID}")
+ set(_IDE_BIN_PATH "bin")
+endif ()
+
+file(RELATIVE_PATH _PLUGIN_TO_LIB "/${_IDE_PLUGIN_PATH}" "/${_IDE_LIBRARY_PATH}")
+file(RELATIVE_PATH _PLUGIN_TO_QT "/${_IDE_PLUGIN_PATH}" "/${_IDE_LIBRARY_BASE_PATH}/Qt/lib")
+file(RELATIVE_PATH _LIB_TO_QT "/${_IDE_LIBRARY_PATH}" "/${_IDE_LIBRARY_BASE_PATH}/Qt/lib")
+
+if (APPLE)
+ set(_RPATH_BASE "@executable_path")
+ set(_LIB_RPATH "@loader_path")
+ set(_PLUGIN_RPATH "@loader_path;@loader_path/${_PLUGIN_TO_LIB}")
+elseif (WIN32)
+ set(_RPATH_BASE "")
+ set(_LIB_RPATH "")
+ set(_PLUGIN_RPATH "")
+else()
+ set(_RPATH_BASE "\$ORIGIN")
+ set(_LIB_RPATH "\$ORIGIN;\$ORIGIN/${_LIB_TO_QT}")
+ set(_PLUGIN_RPATH "\$ORIGIN;\$ORIGIN/${_PLUGIN_TO_LIB};\$ORIGIN/${_PLUGIN_TO_QT}")
+endif ()
+
+set(__QTC_PLUGINS "" CACHE INTERNAL "*** Internal ***")
+set(__QTC_INSTALLED_PLUGINS "" CACHE INTERNAL "*** Internal ***")
+set(__QTC_LIBRARIES "" CACHE INTERNAL "*** Internal ***")
+set(__QTC_INSTALLED_LIBRARIES "" CACHE INTERNAL "*** Internal ***")
+set(__QTC_EXECUTABLES "" CACHE INTERNAL "*** Internal ***")
+set(__QTC_INSTALLED_EXECUTABLES "" CACHE INTERNAL "*** Internal ***")
+set(__QTC_TESTS "" CACHE INTERNAL "*** Internal ***")
+
+function(append_extra_translations target_name)
+ if(NOT ARGN)
+ return()
+ endif()
+
+ if(TARGET "${target_name}")
+ get_target_property(_input "${target_name}" QT_EXTRA_TRANSLATIONS)
+ if (_input)
+ set(_output "${_input}" "${ARGN}")
+ else()
+ set(_output "${ARGN}")
+ endif()
+ set_target_properties("${target_name}" PROPERTIES QT_EXTRA_TRANSLATIONS "${_output}")
+ endif()
+endfunction()
+
+function(update_cached_list name value)
+ set(_tmp_list "${${name}}")
+ list(APPEND _tmp_list "${value}")
+ set("${name}" "${_tmp_list}" CACHE INTERNAL "*** Internal ***")
+endfunction()
+
+function(compare_sources_with_existing_disk_files target_name sources)
+ if(NOT WITH_DEBUG_CMAKE)
+ return()
+ endif()
+
+ file(GLOB_RECURSE existing_files RELATIVE ${CMAKE_CURRENT_LIST_DIR} "*.cpp" "*.hpp" "*.c" "*.h" "*.ui" "*.qrc")
+ foreach(file IN LISTS existing_files)
+ if(NOT ${file} IN_LIST sources)
+ if (NOT WITH_TESTS AND ${file} MATCHES "test")
+ continue()
+ endif()
+ message(STATUS "${target_name} doesn't include ${file}")
+ endif()
+ endforeach()
+
+ foreach(source IN LISTS "${sources}")
+ if(NOT ${source} IN_LIST existing_files)
+ if (NOT WITH_TESTS AND ${file} MATCHES "test")
+ continue()
+ endif()
+ message(STATUS "${target_name} contains non existing ${source}")
+ endif()
+ endforeach()
+endfunction(compare_sources_with_existing_disk_files)
+
+function(separate_object_libraries libraries REGULAR_LIBS OBJECT_LIBS OBJECT_LIB_OBJECTS)
+ if (CMAKE_VERSION VERSION_LESS 3.14)
+ foreach(lib IN LISTS libraries)
+ if (TARGET ${lib})
+ get_target_property(lib_type ${lib} TYPE)
+ if (lib_type STREQUAL "OBJECT_LIBRARY")
+ list(APPEND object_libs ${lib})
+ list(APPEND object_libs_objects $<TARGET_OBJECTS:${lib}>)
+ else()
+ list(APPEND regular_libs ${lib})
+ endif()
+ else()
+ list(APPEND regular_libs ${lib})
+ endif()
+ set(${REGULAR_LIBS} ${regular_libs} PARENT_SCOPE)
+ set(${OBJECT_LIBS} ${object_libs} PARENT_SCOPE)
+ set(${OBJECT_LIB_OBJECTS} ${object_libs_objects} PARENT_SCOPE)
+ endforeach()
+ else()
+ set(${REGULAR_LIBS} ${libraries} PARENT_SCOPE)
+ unset(${OBJECT_LIBS} PARENT_SCOPE)
+ unset(${OBJECT_LIB_OBJECTS} PARENT_SCOPE)
+ endif()
+endfunction(separate_object_libraries)
+
+function(set_explicit_moc target_name file)
+ unset(file_dependencies)
+ if (file MATCHES "^.*plugin.h$")
+ set(file_dependencies DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${target_name}.json")
+ endif()
+ set_property(SOURCE "${file}" PROPERTY SKIP_AUTOMOC ON)
+ qt5_wrap_cpp(file_moc "${file}" ${file_dependencies})
+ target_sources(${target_name} PRIVATE "${file_moc}")
+endfunction()
+
+function(set_public_headers target sources)
+ foreach(source IN LISTS sources)
+ if (source MATCHES "\.h$|\.hpp$")
+
+ if (NOT IS_ABSOLUTE ${source})
+ set(source "${CMAKE_CURRENT_SOURCE_DIR}/${source}")
+ endif()
+
+ get_filename_component(source_dir ${source} DIRECTORY)
+ file(RELATIVE_PATH include_dir_relative_path ${PROJECT_SOURCE_DIR} ${source_dir})
+
+ install(
+ FILES ${source}
+ DESTINATION "include/${include_dir_relative_path}"
+ COMPONENT Devel EXCLUDE_FROM_ALL
+ )
+ endif()
+ endforeach()
+endfunction()
+
+function(set_public_includes target includes)
+ foreach(inc_dir IN LISTS includes)
+ if (NOT IS_ABSOLUTE ${inc_dir})
+ set(inc_dir "${CMAKE_CURRENT_SOURCE_DIR}/${inc_dir}")
+ endif()
+ file(RELATIVE_PATH include_dir_relative_path ${PROJECT_SOURCE_DIR} ${inc_dir})
+ target_include_directories(${target} PUBLIC
+ $<BUILD_INTERFACE:${inc_dir}>
+ $<INSTALL_INTERFACE:include/${include_dir_relative_path}>
+ )
+ endforeach()
+endfunction()
+
+function(finalize_test_setup test_name)
+ # Never translate tests:
+ set_tests_properties(${name}
+ PROPERTIES
+ QT_SKIP_TRANSLATION ON
+ TIMEOUT 5
+ )
+
+ if (WIN32)
+ list(APPEND env_path $ENV{PATH})
+ list(APPEND env_path ${CMAKE_BINARY_DIR}/${_IDE_PLUGIN_PATH})
+ list(APPEND env_path ${CMAKE_BINARY_DIR}/${_IDE_BIN_PATH})
+ list(APPEND env_path $<TARGET_FILE_DIR:Qt5::Test>)
+ if (TARGET libclang)
+ list(APPEND env_path $<TARGET_FILE_DIR:libclang>)
+ endif()
+
+ if (TARGET elfutils::elf)
+ list(APPEND env_path $<TARGET_FILE_DIR:elfutils::elf>)
+ endif()
+
+ string(REPLACE "/" "\\" env_path "${env_path}")
+ string(REPLACE ";" "\\;" env_path "${env_path}")
+
+ set_tests_properties(${test_name} PROPERTIES ENVIRONMENT "PATH=${env_path}")
+ endif()
+endfunction()
+
+function(add_qtc_depends target_name)
+ cmake_parse_arguments(_arg "" "" "PRIVATE;PUBLIC" ${ARGN})
+ if (${_arg_UNPARSED_ARGUMENTS})
+ message(FATAL_ERROR "add_qtc_depends had unparsed arguments")
+ endif()
+
+ separate_object_libraries("${_arg_PRIVATE}"
+ depends object_lib_depends object_lib_depends_objects)
+ separate_object_libraries("${_arg_PUBLIC}"
+ public_depends object_public_depends object_public_depends_objects)
+
+ target_sources(${target_name} PRIVATE ${object_lib_depends_objects} ${object_public_depends_objects})
+
+ get_target_property(target_type ${target_name} TYPE)
+ if (NOT target_type STREQUAL "OBJECT_LIBRARY")
+ target_link_libraries(${target_name} PRIVATE ${depends} PUBLIC ${public_depends})
+ else()
+ list(APPEND object_lib_depends ${depends})
+ list(APPEND object_public_depends ${public_depends})
+ endif()
+
+ foreach(obj_lib IN LISTS object_lib_depends)
+ target_compile_definitions(${target_name} PRIVATE $<TARGET_PROPERTY:${obj_lib},INTERFACE_COMPILE_DEFINITIONS>)
+ target_include_directories(${target_name} PRIVATE $<TARGET_PROPERTY:${obj_lib},INTERFACE_INCLUDE_DIRECTORIES>)
+ endforeach()
+ foreach(obj_lib IN LISTS object_public_depends)
+ target_compile_definitions(${target_name} PUBLIC $<TARGET_PROPERTY:${obj_lib},INTERFACE_COMPILE_DEFINITIONS>)
+ target_include_directories(${target_name} PUBLIC $<TARGET_PROPERTY:${obj_lib},INTERFACE_INCLUDE_DIRECTORIES>)
+ endforeach()
+endfunction()
+
+function(find_dependent_plugins varName)
+ set(_RESULT ${ARGN})
+
+ foreach(i ${ARGN})
+ get_property(_dep TARGET "${i}" PROPERTY _arg_DEPENDS)
+ if (_dep)
+ find_dependent_plugins(_REC ${_dep})
+ list(APPEND _RESULT ${_REC})
+ endif()
+ endforeach()
+
+ if (_RESULT)
+ list(REMOVE_DUPLICATES _RESULT)
+ list(SORT _RESULT)
+ endif()
+
+ set("${varName}" ${_RESULT} PARENT_SCOPE)
+endfunction()
+
+function(enable_pch target)
+ if (BUILD_WITH_PCH)
+ # Skip PCH for targets that do not use the expected visibility settings:
+ get_target_property(visibility_property "${target}" CXX_VISIBILITY_PRESET)
+ get_target_property(inlines_property "${target}" VISIBILITY_INLINES_HIDDEN)
+
+ if (NOT visibility_property STREQUAL "hidden" OR NOT inlines_property)
+ return()
+ endif()
+
+ # Skip PCH for targets that do not have QT_NO_CAST_TO_ASCII
+ get_target_property(target_defines "${target}" COMPILE_DEFINITIONS)
+ if (NOT "QT_NO_CAST_TO_ASCII" IN_LIST target_defines)
+ return()
+ endif()
+
+ get_target_property(target_type ${target} TYPE)
+ if (NOT ${target_type} STREQUAL "OBJECT_LIBRARY")
+ function(_recursively_collect_dependencies input_target)
+ get_target_property(input_type ${input_target} TYPE)
+ if (${input_type} STREQUAL "INTERFACE_LIBRARY")
+ set(prefix "INTERFACE_")
+ endif()
+ get_target_property(link_libraries ${input_target} ${prefix}LINK_LIBRARIES)
+ foreach(library IN LISTS link_libraries)
+ if(TARGET ${library} AND NOT ${library} IN_LIST dependencies)
+ list(APPEND dependencies ${library})
+ _recursively_collect_dependencies(${library})
+ endif()
+ endforeach()
+ set(dependencies ${dependencies} PARENT_SCOPE)
+ endfunction()
+ _recursively_collect_dependencies(${target})
+
+ function(_add_pch_target pch_target pch_file pch_dependency)
+ if (EXISTS ${pch_file})
+ add_library(${pch_target} STATIC
+ ${CMAKE_CURRENT_BINARY_DIR}/empty_pch.cpp
+ ${CMAKE_CURRENT_BINARY_DIR}/empty_pch.c)
+ target_compile_definitions(${pch_target} PRIVATE ${DEFAULT_DEFINES})
+ set_target_properties(${pch_target} PROPERTIES
+ PRECOMPILE_HEADERS ${pch_file}
+ CXX_VISIBILITY_PRESET hidden
+ VISIBILITY_INLINES_HIDDEN ON)
+ target_link_libraries(${pch_target} PRIVATE ${pch_dependency})
+ endif()
+ endfunction()
+
+ if (NOT TARGET QtCreatorPchGui AND NOT TARGET QtCreatorPchConsole)
+ file(GENERATE
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/empty_pch.c
+ CONTENT "/*empty file*/")
+ file(GENERATE
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/empty_pch.cpp
+ CONTENT "/*empty file*/")
+ _add_pch_target(QtCreatorPchGui
+ "${PROJECT_SOURCE_DIR}/src/shared/qtcreator_gui_pch.h" Qt5::Widgets)
+ _add_pch_target(QtCreatorPchConsole
+ "${PROJECT_SOURCE_DIR}/src/shared/qtcreator_pch.h" Qt5::Core)
+ endif()
+
+ unset(PCH_TARGET)
+ if ("Qt5::Widgets" IN_LIST dependencies)
+ set(PCH_TARGET QtCreatorPchGui)
+ elseif ("Qt5::Core" IN_LIST dependencies)
+ set(PCH_TARGET QtCreatorPchConsole)
+ endif()
+
+ if (TARGET "${PCH_TARGET}")
+ set_target_properties(${target} PROPERTIES
+ PRECOMPILE_HEADERS_REUSE_FROM ${PCH_TARGET})
+ endif()
+ endif()
+ endif()
+endfunction()
+
+function(condition_info varName condition)
+ if (NOT ${condition})
+ set(${varName} "" PARENT_SCOPE)
+ else()
+ string(REPLACE ";" " " _contents "${${condition}}")
+ set(${varName} "with CONDITION ${_contents}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(extend_qtc_target target_name)
+ cmake_parse_arguments(_arg
+ ""
+ "SOURCES_PREFIX;FEATURE_INFO"
+ "CONDITION;DEPENDS;PUBLIC_DEPENDS;DEFINES;PUBLIC_DEFINES;INCLUDES;PUBLIC_INCLUDES;SOURCES;EXPLICIT_MOC;SKIP_AUTOMOC;EXTRA_TRANSLATIONS"
+ ${ARGN}
+ )
+
+ if (${_arg_UNPARSED_ARGUMENTS})
+ message(FATAL_ERROR "extend_qtc_target had unparsed arguments")
+ endif()
+
+ condition_info(_extra_text _arg_CONDITION)
+ if (NOT _arg_CONDITION)
+ set(_arg_CONDITION ON)
+ endif()
+ if (${_arg_CONDITION})
+ set(_feature_enabled ON)
+ else()
+ set(_feature_enabled OFF)
+ endif()
+ if (_arg_FEATURE_INFO)
+ add_feature_info(${_arg_FEATURE_INFO} _feature_enabled "${_extra_text}")
+ endif()
+ if (NOT _feature_enabled)
+ return()
+ endif()
+
+ add_qtc_depends(${target_name}
+ PRIVATE ${_arg_DEPENDS}
+ PUBLIC ${_arg_PUBLIC_DEPENDS}
+ )
+ target_compile_definitions(${target_name}
+ PRIVATE ${_arg_DEFINES}
+ PUBLIC ${_arg_PUBLIC_DEFINES}
+ )
+ target_include_directories(${target_name} PRIVATE ${_arg_INCLUDES})
+
+ set_public_includes(${target_name} "${_arg_PUBLIC_INCLUDES}")
+
+ if (_arg_SOURCES_PREFIX)
+ foreach(source IN LISTS _arg_SOURCES)
+ list(APPEND prefixed_sources "${_arg_SOURCES_PREFIX}/${source}")
+ endforeach()
+
+ if (NOT IS_ABSOLUTE ${_arg_SOURCES_PREFIX})
+ set(_arg_SOURCES_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/${_arg_SOURCES_PREFIX}")
+ endif()
+ target_include_directories(${target_name} PRIVATE $<BUILD_INTERFACE:${_arg_SOURCES_PREFIX}>)
+
+ set(_arg_SOURCES ${prefixed_sources})
+ endif()
+ target_sources(${target_name} PRIVATE ${_arg_SOURCES})
+
+ if (APPLE AND BUILD_WITH_PCH)
+ foreach(source IN LISTS _arg_SOURCES)
+ if (source MATCHES "^.*\.mm$")
+ set_source_files_properties(${source} PROPERTIES SKIP_PRECOMPILE_HEADERS ON)
+ endif()
+ endforeach()
+ endif()
+
+ set_public_headers(${target_name} "${_arg_SOURCES}")
+
+ foreach(file IN LISTS _arg_EXPLICIT_MOC)
+ set_explicit_moc(${target_name} "${file}")
+ endforeach()
+
+ foreach(file IN LISTS _arg_SKIP_AUTOMOC)
+ set_property(SOURCE ${file} PROPERTY SKIP_AUTOMOC ON)
+ endforeach()
+
+ append_extra_translations(${target_name} "${_arg_EXTRA_TRANSLATIONS}")
+endfunction()
diff --git a/cmake/QtCreatorDocumentation.cmake b/cmake/QtCreatorDocumentation.cmake
new file mode 100644
index 0000000000..82735999f9
--- /dev/null
+++ b/cmake/QtCreatorDocumentation.cmake
@@ -0,0 +1,285 @@
+# Options:
+option(WITH_DOCS "Build documentation" OFF)
+add_feature_info("Build documentation" WITH_DOCS "")
+
+option(WITH_ONLINE_DOCS "Build online documentation" OFF)
+add_feature_info("Build online documentation" WITH_ONLINE_DOCS "")
+
+# Get information on directories from qmake
+# as this is not yet exported by cmake.
+# Used for QT_INSTALL_DOCS
+function(qt5_query_qmake)
+ if (NOT TARGET Qt5::qmake)
+ message(FATAL_ERROR "Qmake was not found. Add find_package(Qt5 COMPONENTS Core) to CMake to enable.")
+ endif()
+ # dummy check for if we already queried qmake
+ if (QT_INSTALL_BINS)
+ return()
+ endif()
+
+ get_target_property(_qmake_binary Qt5::qmake IMPORTED_LOCATION)
+ execute_process(COMMAND "${_qmake_binary}" "-query"
+ TIMEOUT 10
+ RESULT_VARIABLE _qmake_result
+ OUTPUT_VARIABLE _qmake_stdout
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ if (NOT "${_qmake_result}" STREQUAL "0")
+ message(FATAL_ERROR "Qmake did not execute successfully: ${_qmake_result}.")
+ endif()
+
+ # split into lines:
+ string(REPLACE "\n" ";" _lines "${_qmake_stdout}")
+
+ foreach(_line ${_lines})
+ # split line into key/value pairs
+ string(REPLACE ":" ";" _parts "${_line}")
+ list(GET _parts 0 _key)
+ list(REMOVE_AT _parts 0)
+ string(REPLACE ";" ":" _value "${_parts}")
+
+ set("${_key}" "${_value}" CACHE PATH "qmake import of ${_key}" FORCE)
+ endforeach()
+endfunction()
+
+# Find programs:
+function(_doc_find_program result_var)
+ if (NOT TARGET Qt5::qmake)
+ message(FATAL_ERROR "QDoc is only available in Qt5 projects")
+ endif()
+
+ get_target_property(_qmake_binary Qt5::qmake IMPORTED_LOCATION)
+ get_filename_component(_qmake_dir "${_qmake_binary}" DIRECTORY)
+ find_program("_prg_${result_var}" ${ARGN} HINTS "${_qmake_dir}")
+ if ("_prg_${result_var}" STREQUAL "_prg_${result_var}-NOTFOUND")
+ set("_prg_${result_var}" "${result_var}-NOTFOUND")
+ message(WARNING "Could not find binary for ${result_var}")
+ endif()
+
+ set(${result_var} "${_prg_${result_var}}" PARENT_SCOPE)
+endfunction()
+
+function(_setup_doc_targets)
+ # Set up important targets:
+ if (NOT TARGET html_docs)
+ add_custom_target(html_docs COMMENT "Build HTML documentation")
+ endif()
+ if (NOT TARGET qch_docs)
+ add_custom_target(qch_docs COMMENT "Build QCH documentation")
+ endif()
+ if (NOT TARGET docs)
+ add_custom_target(docs COMMENT "Build documentation")
+ add_dependencies(docs html_docs qch_docs)
+ endif()
+endfunction()
+
+function(_setup_qdoc_targets _qdocconf_file _retval)
+ cmake_parse_arguments(_arg "" "HTML_DIR;INSTALL_DIR;POSTFIX"
+ "INDEXES;INCLUDE_DIRECTORIES;FRAMEWORK_PATHS;ENVIRONMENT_EXPORTS" ${ARGN})
+
+ foreach(_index ${_arg_INDEXES})
+ list(APPEND _qdoc_index_args "-indexdir;${_index}")
+ endforeach()
+
+ set(_env "")
+ foreach(_export ${_arg_ENVIRONMENT_EXPORTS})
+ if (NOT DEFINED "${_export}")
+ message(FATAL_ERROR "${_export} is not known when trying to export it to qdoc.")
+ endif()
+ list(APPEND _env "${_export}=${${_export}}")
+ endforeach()
+
+ set(_full_qdoc_command "${_qdoc}")
+ if (_env)
+ set(_full_qdoc_command "${CMAKE_COMMAND}" "-E" "env" ${_env} "${_qdoc}")
+ endif()
+
+ if (_arg_HTML_DIR STREQUAL "")
+ set(_arg_HTML_DIR "${CMAKE_CURRENT_BINARY_DIR}/doc")
+ endif()
+
+ get_filename_component(_target "${_qdocconf_file}" NAME_WE)
+
+ set(_html_outputdir "${_arg_HTML_DIR}/${_target}${_arg_POSTFIX}")
+ file(MAKE_DIRECTORY "${_html_outputdir}")
+
+ set(_qdoc_include_args "")
+ if (_arg_INCLUDE_DIRECTORIES OR _arg_FRAMEWORK_PATHS)
+ # pass include directories to qdoc via hidden @ option, since we need to generate a file
+ # to be able to resolve the generators inside the include paths
+ set(_qdoc_includes "${CMAKE_CURRENT_BINARY_DIR}/cmake/qdoc_${_target}.inc")
+ set(_qdoc_include_args "@${_qdoc_includes}")
+ set(_includes "")
+ if (_arg_INCLUDE_DIRECTORIES)
+ set(_includes "-I$<JOIN:${_arg_INCLUDE_DIRECTORIES},\n-I>\n")
+ endif()
+ set(_frameworks "")
+ if (_arg_FRAMEWORK_PATHS)
+ set(_frameworks "-F$<JOIN:${_arg_FRAMEWORK_PATHS},\n-F>\n")
+ endif()
+ file(GENERATE
+ OUTPUT "${_qdoc_includes}"
+ CONTENT "${_includes}${_frameworks}"
+ )
+ endif()
+
+ set(_html_target "html_docs_${_target}")
+ add_custom_target("${_html_target}"
+ ${_full_qdoc_command} -outputdir "${_html_outputdir}" "${_qdocconf_file}"
+ ${_qdoc_index_args} ${_qdoc_include_args}
+ COMMENT "Build HTML documentation from ${_qdocconf_file}"
+ DEPENDS "${_qdocconf_file}"
+ SOURCES "${_qdocconf_file}"
+ WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
+ VERBATIM
+ )
+ add_dependencies(html_docs "${_html_target}")
+
+ # Install HTML files as a special component
+ install(DIRECTORY "${_html_outputdir}" DESTINATION "${_arg_INSTALL_DIR}"
+ COMPONENT html_docs EXCLUDE_FROM_ALL)
+
+ set("${_retval}" "${_html_outputdir}" PARENT_SCOPE)
+endfunction()
+
+function(_setup_qhelpgenerator_targets _qdocconf_file _html_outputdir)
+ cmake_parse_arguments(_arg "" "QCH_DIR;INSTALL_DIR" "" ${ARGN})
+ if (_arg_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "qdoc_build_qdocconf_file has unknown arguments: ${_arg_UNPARSED_ARGUMENTS}.")
+ endif()
+
+ if (NOT _arg_QCH_DIR)
+ set(_arg_QCH_DIR "${CMAKE_CURRENT_BINARY_DIR}/doc")
+ endif()
+
+ if (NOT TARGET Qt5::qhelpgenerator)
+ message(WARNING "qhelpgenerator missing: No QCH documentation targets were generated. Add find_package(Qt5 COMPONENTS Help) to CMake to enable.")
+ return()
+ endif()
+
+ get_filename_component(_target "${_qdocconf_file}" NAME_WE)
+
+ set(_qch_outputdir "${_arg_QCH_DIR}")
+ file(MAKE_DIRECTORY "${_qch_outputdir}")
+
+ set(_qch_target "qch_docs_${_target}")
+ set(_html_target "html_docs_${_target}")
+ add_custom_target("${_qch_target}"
+ Qt5::qhelpgenerator "${_html_outputdir}/${_target}.qhp" -o "${_qch_outputdir}/${_target}.qch"
+ COMMENT "Build QCH documentation from ${_qdocconf_file}"
+ WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
+ VERBATIM
+ )
+ add_dependencies("${_qch_target}" "${_html_target}")
+ add_dependencies(qch_docs "${_qch_target}")
+
+ install(FILES "${_qch_outputdir}/${_target}.qch" DESTINATION "${_arg_INSTALL_DIR}"
+ COMPONENT qch_docs EXCLUDE_FROM_ALL)
+endfunction()
+
+# Helper functions:
+function(qdoc_build_qdocconf_file _qdocconf_file)
+ _setup_doc_targets()
+
+ _doc_find_program(_qdoc NAMES qdoc qdoc-qt5)
+ if (_qdoc STREQUAL "_qdoc-NOTFOUND")
+ message(WARNING "No qdoc binary found: No documentation targets were generated")
+ return()
+ endif()
+
+ cmake_parse_arguments(_arg "QCH" "HTML_DIR;QCH_DIR;INSTALL_DIR;POSTFIX"
+ "INDEXES;INCLUDE_DIRECTORIES;FRAMEWORK_PATHS;ENVIRONMENT_EXPORTS" ${ARGN})
+ if (_arg_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "qdoc_build_qdocconf_file has unknown arguments: ${_arg_UNPARSED_ARGUMENTS}.")
+ endif()
+
+ if (NOT _arg_INSTALL_DIR)
+ message(FATAL_ERROR "No INSTALL_DIR set when calling qdoc_build_qdocconf_file")
+ endif()
+
+ _setup_qdoc_targets("${_qdocconf_file}" _html_outputdir
+ HTML_DIR "${_arg_HTML_DIR}" INSTALL_DIR "${_arg_INSTALL_DIR}"
+ INDEXES ${_arg_INDEXES} ENVIRONMENT_EXPORTS ${_arg_ENVIRONMENT_EXPORTS}
+ POSTFIX "${_arg_POSTFIX}"
+ INCLUDE_DIRECTORIES ${_arg_INCLUDE_DIRECTORIES}
+ FRAMEWORK_PATHS ${_arg_FRAMEWORK_PATHS}
+ )
+
+ if (_arg_QCH)
+ _setup_qhelpgenerator_targets("${_qdocconf_file}" "${_html_outputdir}"
+ QCH_DIR "${_arg_QCH_DIR}" INSTALL_DIR "${_arg_INSTALL_DIR}")
+ endif()
+endfunction()
+
+set(QtCreatorDocumentation_LIST_DIR ${CMAKE_CURRENT_LIST_DIR})
+
+function(qtc_docs_dir varName)
+ if (QtCreator_SOURCE_DIR)
+ # Qt Creator build or super-repo
+ set(${varName} "${QtCreator_SOURCE_DIR}/doc" PARENT_SCOPE)
+ elseif(QtCreatorDocumentation_LIST_DIR MATCHES /lib/cmake/QtCreator$)
+ # Dev package
+ set(${varName} "${QtCreatorDocumentation_LIST_DIR}/../../../doc" PARENT_SCOPE)
+ else()
+ message(FATAL_ERROR "Could not find qtc_docs_dir")
+ endif()
+endfunction()
+
+function(qtc_index_dir varName)
+ if (QtCreator_BINARY_DIR)
+ # Qt Creator build or super-repo
+ set(${varName} "${QtCreator_BINARY_DIR}/doc/html" PARENT_SCOPE)
+ elseif(QtCreatorDocumentation_LIST_DIR MATCHES /lib/cmake/QtCreator$)
+ # Dev package
+ set(${varName} "${QtCreatorDocumentation_LIST_DIR}/../../../${IDE_DOC_PATH}" PARENT_SCOPE)
+ else()
+ message(FATAL_ERROR "Could not find qtc_index_dir")
+ endif()
+endfunction()
+
+function(add_qtc_documentation qdocconf_file)
+ cmake_parse_arguments(_arg "" ""
+ "INCLUDE_DIRECTORIES;FRAMEWORK_PATHS" ${ARGN})
+ if (_arg_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "add_qtc_documentation has unknown arguments: ${_arg_UNPARSED_ARGUMENTS}.")
+ endif()
+
+ ### Skip docs setup if that is not needed!
+ if (NOT WITH_ONLINE_DOCS AND NOT WITH_DOCS)
+ return()
+ endif()
+
+
+ qt5_query_qmake()
+ qtc_output_binary_dir(_output_binary_dir)
+ qtc_docs_dir(QTC_DOCS_DIR)
+ qtc_index_dir(QTC_INDEX_DIR)
+
+ set(_qch_params)
+ if (WITH_DOCS)
+ set(_qch_params QCH QCH_DIR "${_output_binary_dir}/${IDE_DOC_PATH}")
+ endif()
+ set(_qdoc_params HTML_DIR "${_output_binary_dir}/doc/html")
+ list(APPEND _qdoc_params INDEXES "${QT_INSTALL_DOCS}" "${QTC_INDEX_DIR}")
+ list(APPEND _qdoc_params INSTALL_DIR "${IDE_DOC_PATH}")
+
+ # Set up environment for qdoc:
+ set(QTC_VERSION "${IDE_VERSION_DISPLAY}")
+ set(QTCREATOR_COPYRIGHT_YEAR "${IDE_COPYRIGHT_YEAR}")
+ string(REPLACE "." "" QTC_VERSION_TAG "${IDE_VERSION}")
+ set(QDOC_INDEX_DIR "${QT_INSTALL_DOCS}")
+ if (QT_INSTALL_DOCS_src)
+ set(QT_INSTALL_DOCS "${QT_INSTALL_DOCS_src}")
+ endif()
+ list(APPEND _qdoc_params ENVIRONMENT_EXPORTS
+ IDE_ID IDE_CASED_ID IDE_DISPLAY_NAME
+ QTC_DOCS_DIR QTC_VERSION QTC_VERSION_TAG
+ QTCREATOR_COPYRIGHT_YEAR
+ QT_INSTALL_DOCS QDOC_INDEX_DIR
+ )
+
+ qdoc_build_qdocconf_file(${qdocconf_file} ${_qch_params} ${_qdoc_params}
+ INCLUDE_DIRECTORIES ${_arg_INCLUDE_DIRECTORIES}
+ FRAMEWORK_PATHS ${_arg_FRAMEWORK_PATHS}
+ )
+endfunction()
diff --git a/cmake/QtCreatorIDEBranding.cmake b/cmake/QtCreatorIDEBranding.cmake
index ca406149df..e82e06f29d 100644
--- a/cmake/QtCreatorIDEBranding.cmake
+++ b/cmake/QtCreatorIDEBranding.cmake
@@ -1,9 +1,8 @@
-#BINARY_ARTIFACTS_BRANCH = master
#PROJECT_USER_FILE_EXTENSION = .user
-set(IDE_VERSION "4.12.2") # The IDE version.
-set(IDE_VERSION_COMPAT "4.12.0") # The IDE Compatibility version.
-set(IDE_VERSION_DISPLAY "4.12.2") # The IDE display version.
+set(IDE_VERSION "4.12.82") # The IDE version.
+set(IDE_VERSION_COMPAT "4.12.82") # The IDE Compatibility version.
+set(IDE_VERSION_DISPLAY "4.13.0-beta1") # The IDE display version.
set(IDE_COPYRIGHT_YEAR "2020") # The IDE current copyright year.
set(IDE_SETTINGSVARIANT "QtProject") # The IDE settings variation.
diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt
index 80f2b4cf66..c453903cf0 100644
--- a/doc/CMakeLists.txt
+++ b/doc/CMakeLists.txt
@@ -1,12 +1,5 @@
# Generate documentation
-# Options:
-option(WITH_DOCS "Build documentation" OFF)
-add_feature_info("Build documentation" WITH_DOCS "")
-
-option(WITH_ONLINE_DOCS "Build online documentation" OFF)
-add_feature_info("Build online documentation" WITH_ONLINE_DOCS "")
-
option(BUILD_DEVELOPER_DOCS "Include developer documentation" OFF)
add_feature_info("Include developer documentation" BUILD_DEVELOPER_DOCS "")
@@ -38,265 +31,29 @@ function(_find_all_includes _ret_includes _ret_framework_paths)
endif()
endfunction()
-# Find programs:
-function(_doc_find_program result_var)
- if (NOT TARGET Qt5::qmake)
- message(FATAL_ERROR "QDoc is only available in Qt5 projects")
- endif()
-
- get_target_property(_qmake_binary Qt5::qmake IMPORTED_LOCATION)
- get_filename_component(_qmake_dir "${_qmake_binary}" DIRECTORY)
- find_program("_prg_${result_var}" ${ARGN} HINTS "${_qmake_dir}")
- if ("_prg_${result_var}" STREQUAL "_prg_${result_var}-NOTFOUND")
- set("_prg_${result_var}" "${result_var}-NOTFOUND")
- message(WARNING "Could not find binary for ${result_var}")
- endif()
-
- set(${result_var} "${_prg_${result_var}}" PARENT_SCOPE)
-endfunction()
-
-function(_setup_doc_targets)
- # Set up important targets:
- if (NOT TARGET html_docs)
- add_custom_target(html_docs COMMENT "Build HTML documentation")
- endif()
- if (NOT TARGET qch_docs)
- add_custom_target(qch_docs COMMENT "Build QCH documentation")
- endif()
- if (NOT TARGET docs)
- add_custom_target(docs COMMENT "Build documentation")
- add_dependencies(docs html_docs qch_docs)
- endif()
- if (NOT TARGET install_docs)
- add_custom_target(install_docs COMMENT "Install documentation")
- add_dependencies(install_docs docs)
- endif()
- if (NOT TARGET clean_docs)
- add_custom_target(clean_docs COMMENT "Clean documentation files from build directory")
- endif()
-endfunction()
-
-function(_setup_qdoc_targets _qdocconf_file _retval)
- cmake_parse_arguments(_arg "" "HTML_DIR;INSTALL_DIR;POSTFIX"
- "INDEXES;INCLUDE_DIRECTORIES;FRAMEWORK_PATHS;ENVIRONMENT_EXPORTS" ${ARGN})
-
- foreach(_index ${_arg_INDEXES})
- list(APPEND _qdoc_index_args "-indexdir;${_index}")
- endforeach()
-
- set(_env "")
- foreach(_export ${_arg_ENVIRONMENT_EXPORTS})
- if (NOT DEFINED "${_export}")
- message(FATAL_ERROR "${_export} is not known when trying to export it to qdoc.")
- endif()
- list(APPEND _env "${_export}=${${_export}}")
- endforeach()
-
- set(_full_qdoc_command "${_qdoc}")
- if (_env)
- set(_full_qdoc_command "${CMAKE_COMMAND}" "-E" "env" ${_env} "${_qdoc}")
- endif()
-
- if (_arg_HTML_DIR STREQUAL "")
- set(_arg_HTML_DIR "${CMAKE_CURRENT_BINARY_DIR}/doc")
- endif()
-
- get_filename_component(_target "${_qdocconf_file}" NAME_WE)
-
- set(_html_outputdir "${_arg_HTML_DIR}/${_target}${_arg_POSTFIX}")
- file(MAKE_DIRECTORY "${_html_outputdir}")
-
- set(_qdoc_include_args "")
- if (_arg_INCLUDE_DIRECTORIES OR _arg_FRAMEWORK_PATHS)
- # pass include directories to qdoc via hidden @ option, since we need to generate a file
- # to be able to resolve the generators inside the include paths
- set(_qdoc_includes "${CMAKE_CURRENT_BINARY_DIR}/cmake/qdoc_${_target}.inc")
- set(_qdoc_include_args "@${_qdoc_includes}")
- set(_includes "")
- if (_arg_INCLUDE_DIRECTORIES)
- set(_includes "-I$<JOIN:${_arg_INCLUDE_DIRECTORIES},\n-I>\n")
- endif()
- set(_frameworks "")
- if (_arg_FRAMEWORK_PATHS)
- set(_frameworks "-F$<JOIN:${_arg_FRAMEWORK_PATHS},\n-F>\n")
- endif()
- file(GENERATE
- OUTPUT "${_qdoc_includes}"
- CONTENT "${_includes}${_frameworks}"
+if (WITH_DOCS)
+ add_qtc_documentation("qtcreator/qtcreator.qdocconf")
+ if (BUILD_DEVELOPER_DOCS)
+ _find_all_includes(_all_includes _framework_paths)
+ add_qtc_documentation("qtcreatordev/qtcreator-dev.qdocconf"
+ INCLUDE_DIRECTORIES ${_all_includes}
+ FRAMEWORK_PATHS ${_framework_paths}
)
endif()
-
- set(_html_target "html_docs_${_target}")
- add_custom_target("${_html_target}"
- ${_full_qdoc_command} -outputdir "${_html_outputdir}" "${_qdocconf_file}"
- ${_qdoc_index_args} ${_qdoc_include_args}
- COMMENT "Build HTML documentation from ${_qdocconf_file}"
- DEPENDS "${_qdocconf_file}"
- SOURCES "${_qdocconf_file}"
- WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
- VERBATIM
- )
- add_dependencies(html_docs "${_html_target}")
-
- # Install HTML files as a special component
- install(DIRECTORY "${_html_outputdir}" DESTINATION "${_arg_INSTALL_DIR}"
- COMPONENT ${_html_target} EXCLUDE_FROM_ALL)
-
- add_custom_target("install_${_html_target}"
- "${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=${_html_target}
- -P "${CMAKE_BINARY_DIR}/cmake_install.cmake"
- COMMENT "Install HTML documentation from ${_qdocconf_file}"
- WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
- VERBATIM
- )
- add_dependencies(install_docs "install_${_html_target}")
-
- add_custom_target("clean_${_html_target}"
- "${CMAKE_COMMAND}" -E remove_directory "${_html_outputdir}"
- COMMENT "Clean HTML documentation from ${_qdocconf_file}"
- WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
- VERBATIM
- )
- add_dependencies(clean_docs "clean_${_html_target}")
-
- set("${_retval}" "${_html_outputdir}" PARENT_SCOPE)
-endfunction()
-
-function(_setup_qhelpgenerator_targets _qdocconf_file _html_outputdir)
- cmake_parse_arguments(_arg "" "QCH_DIR;INSTALL_DIR" "" ${ARGN})
- if (_arg_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "qdoc_build_qdocconf_file has unknown arguments: ${_arg_UNPARSED_ARGUMENTS}.")
- endif()
-
- if (NOT _arg_QCH_DIR)
- set(_arg_QCH_DIR "${CMAKE_CURRENT_BINARY_DIR}/doc")
- endif()
-
- if (NOT TARGET Qt5::qhelpgenerator)
- message(WARNING "qhelpgenerator missing: No QCH documentation targets were generated")
- return()
- endif()
-
- get_filename_component(_target "${_qdocconf_file}" NAME_WE)
-
- set(_qch_outputdir "${_arg_QCH_DIR}")
- file(MAKE_DIRECTORY "${_qch_outputdir}")
-
- set(_qch_target "qch_docs_${_target}")
- set(_html_target "html_docs_${_target}")
- add_custom_target("${_qch_target}"
- Qt5::qhelpgenerator "${_html_outputdir}/${_target}.qhp" -o "${_qch_outputdir}/${_target}.qch"
- COMMENT "Build QCH documentation from ${_qdocconf_file}"
- WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
- VERBATIM
- )
- add_dependencies("${_qch_target}" "${_html_target}")
- add_dependencies(qch_docs "${_qch_target}")
-
- install(FILES "${_qch_outputdir}/${_target}.qch" DESTINATION "${_arg_INSTALL_DIR}"
- COMPONENT ${_qch_target} EXCLUDE_FROM_ALL)
-
- add_custom_target("install_${_qch_target}"
- "${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=${_qch_target}
- -P "${CMAKE_BINARY_DIR}/cmake_install.cmake"
- WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
- VERBATIM
- )
- add_dependencies(install_docs "install_${_qch_target}")
-
- add_custom_target("clean_${_qch_target}"
- "${CMAKE_COMMAND}" -E remove -f "${_qch_outputdir}/${_target}.qch"
- COMMENT "Clean QCH documentation generated from ${_qdocconf_file}"
- WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
- VERBATIM
- )
- add_dependencies(clean_docs "clean_${_qch_target}")
-endfunction()
-
-# Helper functions:
-function(qdoc_build_qdocconf_file _qdocconf_file)
- _setup_doc_targets()
-
- _doc_find_program(_qdoc NAMES qdoc qdoc-qt5)
- if (_qdoc STREQUAL "_qdoc-NOTFOUND")
- message(WARNING "No qdoc binary found: No documentation targets were generated")
- return()
- endif()
-
- cmake_parse_arguments(_arg "QCH" "HTML_DIR;QCH_DIR;INSTALL_DIR;POSTFIX"
- "INDEXES;INCLUDE_DIRECTORIES;FRAMEWORK_PATHS;ENVIRONMENT_EXPORTS" ${ARGN})
- if (_arg_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "qdoc_build_qdocconf_file has unknown arguments: ${_arg_UNPARSED_ARGUMENTS}.")
- endif()
-
- if (NOT _arg_INSTALL_DIR)
- message(FATAL_ERROR "No INSTALL_DIR set when calling qdoc_build_qdocconf_file")
- endif()
-
- _setup_qdoc_targets("${_qdocconf_file}" _html_outputdir
- HTML_DIR "${_arg_HTML_DIR}" INSTALL_DIR "${_arg_INSTALL_DIR}"
- INDEXES ${_arg_INDEXES} ENVIRONMENT_EXPORTS ${_arg_ENVIRONMENT_EXPORTS}
- POSTFIX "${_arg_POSTFIX}"
- INCLUDE_DIRECTORIES ${_arg_INCLUDE_DIRECTORIES}
- FRAMEWORK_PATHS ${_arg_FRAMEWORK_PATHS}
- )
-
- if (_arg_QCH)
- _setup_qhelpgenerator_targets("${_qdocconf_file}" "${_html_outputdir}"
- QCH_DIR "${_arg_QCH_DIR}" INSTALL_DIR "${_arg_INSTALL_DIR}")
- endif()
-endfunction()
-
-### Skip docs setup if that is not needed!
-if (WITH_ONLINE_DOCS OR WITH_DOCS)
- if (WITH_DOCS)
- set(_qch_params "QCH;QCH_DIR;${PROJECT_BINARY_DIR}/${IDE_DOC_PATH}")
- endif()
-
- set(_qdoc_params HTML_DIR "${PROJECT_BINARY_DIR}/doc/html")
- list(APPEND _qdoc_params INDEXES "${QT_INSTALL_DOCS}" "${PROJECT_BINARY_DIR}/doc")
- list(APPEND _qdoc_params INSTALL_DIR "${IDE_DOC_PATH}")
-
- # Set up environment for qdoc:
- set(QTC_VERSION "${IDE_VERSION_DISPLAY}")
- set(QTCREATOR_COPYRIGHT_YEAR "${IDE_COPYRIGHT_YEAR}")
- set(IDE_SOURCE_TREE "${PROJECT_SOURCE_DIR}")
- string(REPLACE "." "" QTC_VERSION_TAG "${IDE_VERSION}")
- set(QTC_DOCS_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
- set(QDOC_INDEX_DIR "${QT_INSTALL_DOCS}")
- if (QT_INSTALL_DOCS_src)
- set(QT_INSTALL_DOCS "${QT_INSTALL_DOCS_src}")
- endif()
-
- list(APPEND _qdoc_params ENVIRONMENT_EXPORTS
- IDE_ID IDE_CASED_ID IDE_DISPLAY_NAME
-
- IDE_SOURCE_TREE
-
- QTC_DOCS_DIR QTC_VERSION QTC_VERSION_TAG
-
- QTCREATOR_COPYRIGHT_YEAR
-
- QT_INSTALL_DOCS QDOC_INDEX_DIR)
-
- if (WITH_DOCS)
- qdoc_build_qdocconf_file("qtcreator/qtcreator.qdocconf" ${_qch_params} ${_qdoc_params})
- if (BUILD_DEVELOPER_DOCS)
- _find_all_includes(_all_includes _framework_paths)
- qdoc_build_qdocconf_file("qtcreatordev/qtcreator-dev.qdocconf" ${_qch_params} ${_qdoc_params}
- INCLUDE_DIRECTORIES ${_all_includes}
- FRAMEWORK_PATHS ${_framework_paths}
- )
- endif()
- endif()
- if(WITH_ONLINE_DOCS)
- qdoc_build_qdocconf_file("qtcreator/qtcreator-online.qdocconf" ${_qdoc_params})
- if (BUILD_DEVELOPER_DOCS)
- _find_all_includes(_all_includes _framework_paths)
- qdoc_build_qdocconf_file("qtcreatordev/qtcreator-dev-online.qdocconf" ${_qdoc_params}
- INCLUDE_DIRECTORIES ${_all_includes}
- FRAMEWORK_PATHS ${_framework_paths}
- )
- endif()
+endif()
+if(WITH_ONLINE_DOCS)
+ add_qtc_documentation("qtcreator/qtcreator-online.qdocconf")
+ if (BUILD_DEVELOPER_DOCS)
+ _find_all_includes(_all_includes _framework_paths)
+ add_qtc_documentation("qtcreatordev/qtcreator-dev-online.qdocconf"
+ INCLUDE_DIRECTORIES ${_all_includes}
+ FRAMEWORK_PATHS ${_framework_paths}
+ )
endif()
endif()
+
+install(DIRECTORY config
+ DESTINATION doc
+ COMPONENT Devel
+ EXCLUDE_FROM_ALL
+)
diff --git a/doc/qtcreator/config/qtcreator-project.qdocconf b/doc/qtcreator/config/qtcreator-project.qdocconf
index 414ac30c9a..96559fbdf4 100644
--- a/doc/qtcreator/config/qtcreator-project.qdocconf
+++ b/doc/qtcreator/config/qtcreator-project.qdocconf
@@ -1,4 +1,4 @@
-project = "$IDE_DISPLAY_NAME"
+project = qtcreator
description = "$IDE_DISPLAY_NAME Manual"
url = http://doc.qt.io/$IDE_ID
diff --git a/doc/qtcreator/src/cmake/creator-projects-cmake.qdoc b/doc/qtcreator/src/cmake/creator-projects-cmake.qdoc
index e5f61c7caf..3dd3a9197a 100644
--- a/doc/qtcreator/src/cmake/creator-projects-cmake.qdoc
+++ b/doc/qtcreator/src/cmake/creator-projects-cmake.qdoc
@@ -59,14 +59,8 @@
\section1 Adding CMake Tools
- \QC supports CMake version 3.0, or later. For best results you should use
- CMake version 3.7.2 with server-mode support, or later. Earlier versions
- provide less information to the code model, which will then fail to resolve
- includes and defines.
-
- For CMake version 3.14, or later, \QC supports the
- \l {https://cmake.org/cmake/help/latest/manual/cmake-file-api.7.html}
- {file-based API}.
+ \QC requires CMake's {https://cmake.org/cmake/help/latest/manual/cmake-file-api.7.html}
+ {file-based API}. Please make sure to use CMake version 3.14, or later.
To specify paths to CMake executables:
diff --git a/doc/qtcreator/src/editors/creator-code-refactoring.qdoc b/doc/qtcreator/src/editors/creator-code-refactoring.qdoc
index cd1177b427..8e94c1622e 100644
--- a/doc/qtcreator/src/editors/creator-code-refactoring.qdoc
+++ b/doc/qtcreator/src/editors/creator-code-refactoring.qdoc
@@ -152,9 +152,14 @@
\section1 Column Editing
- To apply a change to several rows in a column simultaneously, press
- \key Alt, select the rows, and enter or remove text. The changes are made
- simultaneously at the cursor position on all the selected rows.
+ To apply a change to several rows in a column simultaneously, hold
+ \key Alt, select the rows using the mouse, and enter or remove text.
+ The changes are made simultaneously at the cursor position on all the
+ selected rows.
+
+ On Windows and Linux, you can also hold \key {Alt+Shift} and select
+ the rows using the arrow keys and the \key PageUp, \key PageDown,
+ \key Home, \key End keys.
\section1 Applying Refactoring Actions
diff --git a/doc/qtcreator/src/editors/creator-only/creator-code-pasting.qdoc b/doc/qtcreator/src/editors/creator-only/creator-code-pasting.qdoc
index 5fbc28c832..852500d1b0 100644
--- a/doc/qtcreator/src/editors/creator-only/creator-code-pasting.qdoc
+++ b/doc/qtcreator/src/editors/creator-only/creator-code-pasting.qdoc
@@ -59,6 +59,9 @@
\li Select the \uicontrol {Display Output pane after sending a post}
check box to display the URL in the \uicontrol {General Messages}
output pane when you paste a post.
+ \li Select the \uicontrol {Make pasted content public by default}
+ check box to make the posted URL get listed on the service's website,
+ rather than only being available via the direct link.
\endlist
Select \uicontrol Fileshare to specify the path to a shared network drive.
diff --git a/doc/qtcreator/src/howto/creator-only/creator-autotest.qdoc b/doc/qtcreator/src/howto/creator-only/creator-autotest.qdoc
index 3c7703a866..78c7ffb680 100644
--- a/doc/qtcreator/src/howto/creator-only/creator-autotest.qdoc
+++ b/doc/qtcreator/src/howto/creator-only/creator-autotest.qdoc
@@ -31,11 +31,13 @@
\title Running Autotests
\QC integrates the \l{Qt Test} framework,
- \l{https://github.com/google/googletest}{Google C++ Testing Framework}, and
+ \l{https://github.com/google/googletest}{Google C++ Testing Framework},
\l{https://www.boost.org/doc/libs/1_70_0/libs/test/doc/html/index.html}
- {Boost.Test} for unit testing applications and libraries. You can use \QC to
- create, build, and run Qt tests, Qt Quick tests (QML-based Qt tests), Google
- tests, and Boost tests for your projects.
+ {Boost.Test}, and \l{https://github.com/catchorg/Catch2}
+ {Catch2 test framework} for unit testing applications and libraries.
+ You can use \QC to create, build, and run Qt tests,
+ Qt Quick tests (QML-based Qt tests), Google tests, Boost tests, and
+ Catch2 tests for your projects.
\image qtcreator-autotests.png
@@ -175,6 +177,47 @@
\l{https://www.boost.org/doc/libs/1_70_0/libs/test/doc/html/index.html}
{Boost.Test}.
+ \section2 Creating Catch2 Tests
+
+ To build and run Catch2 tests, you either must have Catch2 libraries and
+ headers installed, or you can use the single include header file provided
+ by the Catch2 repository.
+
+ If the Catch2 headers can be found by the used compiler and build system
+ automatically, you do not need to specify the include directory when
+ creating the test.
+
+ To create a basic Catch2 test:
+
+ \list 1
+ \li Select \uicontrol File > \uicontrol {New File or Project} >
+ \uicontrol {Other Project} > \uicontrol {Auto Test Project} >
+ \uicontrol Choose to create a project with boilerplate code for a
+ Catch2 test.
+ \li In the \uicontrol {Project and Test Information} dialog, specify
+ settings for the project and test:
+ \list 1
+ \li In the \uicontrol {Test framework} field, select
+ \uicontrol {Catch2}.
+ \li In the \uicontrol {Test case name} field, specify a name
+ to be used for the test case file.
+ \li Select the \uicontrol {Use Qt libraries} check box
+ to use a self defined main function and set up the project
+ to use Qt features.
+ \li In the \uicontrol {Catch2 include directory (optional)} field,
+ you may enter a path to the directory that contains the
+ Catch2 header files.
+ \li In the \uicontrol {Build system} field, select the build
+ system to use for building the project: qmake, CMake, or
+ Qbs.
+ \endlist
+ \endlist
+
+ \QC creates the test in the specified project directory.
+ For more information about creating Catch2 tests, see
+ \l{https://github.com/catchorg/Catch2/blob/master/docs/Readme.md}
+ {Catch2}.
+
\section1 Setting Up the Google C++ Testing Framework
To build and run Google tests, you must have the Google C++ Testing
@@ -374,6 +417,38 @@
memory leaks.
\endlist
+ \section2 Specifying Settings for Running Catch2 Tests
+ \list 1
+ \li To specify settings for running Catch2 tests, select
+ \uicontrol Tools > \uicontrol Options > \uicontrol {Testing} >
+ \uicontrol {Catch Test}.
+ //! insert image here
+ \li Select the \uicontrol {Show success} check box to show succeeding
+ expressions as well. By default Catch2 will print only fails.
+ \li Select the \uicontrol {Break on failure while debugging} check box
+ to turn failures into debugger breakpoints.
+ \li Select the \uicontrol {Skip throwing assertions} check box to skip
+ any assertion that test for throwing an exception.
+ \li Select the \uicontrol {Visualize whitespace} check box to turn
+ whitespace into escape sequences.
+ \li Select the \uicontrol {Warn on empty tests} check box to get a
+ warning when a test case does not check any assertion.
+ \li Select the \uicontrol {Abort after} check box to abort the test
+ after the number of failures specified inside the spin box.
+ \li Select the \uicontrol {Benchmark samples} check box to specify
+ the number of samples to be collected while running benchmarks.
+ \li Select the \uicontrol {Benchmark resamples} check box to specify
+ the number of resamples to be used for the statistical
+ bootstrapping performed after the benchmarking.
+ \li Select the \uicontrol {Benchmark confidence interval} check box
+ to specify the confidence interval used for the statistical
+ bootstrapping.
+ \li Select the \uicontrol {Benchmark warmup time} check box to specify
+ the warmup time for each test before benchmarking start.
+ \li Select the \uicontrol {Disable analysis} check box to disable the
+ statistical analysis and bootstrapping.
+ \endlist
+
\section1 Viewing Test Output
The test results are displayed in the \uicontrol {Test Results} output pane
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 2ff19db916..4622b2cc45 100644
--- a/doc/qtcreator/src/projects/creator-only/creator-projects-creating.qdoc
+++ b/doc/qtcreator/src/projects/creator-only/creator-projects-creating.qdoc
@@ -282,11 +282,9 @@
\list
- \li C++
+ \li C/C++
- C++ class, source, or header files that you can use to write the
- application logic in both Qt Quick projects and
- Qt widget based projects
+ C or C++ source and header files
\li Qt
diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-custom-wizards-json.qdocinc b/doc/qtcreator/src/projects/creator-only/creator-projects-custom-wizards-json.qdocinc
index b53d8e9b92..3ef9ff43b9 100644
--- a/doc/qtcreator/src/projects/creator-only/creator-projects-custom-wizards-json.qdocinc
+++ b/doc/qtcreator/src/projects/creator-only/creator-projects-custom-wizards-json.qdocinc
@@ -785,7 +785,9 @@
"data":
{
"trText": "%{BaseCB}",
- "trDisabledText": "%{BaseCB}"
+ "trDisabledText": "%{BaseCB}",
+ "historyId": "EditValues",
+ "restoreLastHistoryItem": false
}
},
\endcode
@@ -808,6 +810,14 @@
\li \c isPassword is a boolean value that specifies that the line edit
contains a password, which will be masked.
+ \li \c historyId is a key that specifies the name for a list of items
+ for the history completer.
+
+ \li \c restoreLastHistoryItem is a boolean that specifies that the
+ last history item is automatically set as the default text in
+ the line edit. This key can only be set to true if \c historyId
+ is also set.
+
\endlist
\section2 Path Chooser
diff --git a/doc/qtcreatordev/config/qtcreator-developer.qdocconf b/doc/qtcreatordev/config/qtcreator-developer.qdocconf
index f6a4b9a25c..6825b41f94 100644
--- a/doc/qtcreatordev/config/qtcreator-developer.qdocconf
+++ b/doc/qtcreatordev/config/qtcreator-developer.qdocconf
@@ -1,4 +1,4 @@
-project = "Qt Creator"
+project = qtcreator-dev
description = "Extending Qt Creator Manual"
language = Cpp
diff --git a/qbs/imports/QtcProduct.qbs b/qbs/imports/QtcProduct.qbs
index d96c096f8f..206b5c2ada 100644
--- a/qbs/imports/QtcProduct.qbs
+++ b/qbs/imports/QtcProduct.qbs
@@ -27,7 +27,7 @@ Product {
enableFallback: false
}
}
- Depends { name: "Qt.core"; versionAtLeast: "5.11.0" }
+ Depends { name: "Qt.core"; versionAtLeast: "5.12.0" }
// TODO: Should fall back to what came from Qt.core for Qt < 5.7, but we cannot express that
// atm. Conditionally pulling in a module that sets the property is also not possible,
diff --git a/qbs/modules/libclang/functions.js b/qbs/modules/libclang/functions.js
index d03358b3c6..dd9dc1bb09 100644
--- a/qbs/modules/libclang/functions.js
+++ b/qbs/modules/libclang/functions.js
@@ -110,11 +110,11 @@ function formattingLibs(llvmConfig, qtcFunctions, targetOS)
return [];
var clangVersion = version(llvmConfig)
- if (Utilities.versionCompare(clangVersion, "10") >= 0)
- return [];
var libs = []
if (qtcFunctions.versionIsAtLeast(clangVersion, MinimumLLVMVersion)) {
- if (qtcFunctions.versionIsAtLeast(clangVersion, "8.0.0")) {
+ var hasLibClangFormat = File.directoryEntries(libDir(llvmConfig), File.Files)
+ .some(function(p) { return p.contains("clangFormat"); });
+ if (hasLibClangFormat) {
libs.push(
"clangFormat",
"clangToolingInclusions",
@@ -124,13 +124,7 @@ function formattingLibs(llvmConfig, qtcFunctions, targetOS)
"clangBasic"
);
} else {
- libs.push(
- "clangFormat",
- "clangToolingCore",
- "clangRewrite",
- "clangLex",
- "clangBasic"
- );
+ libs.push("clang-cpp");
}
libs = libs.concat(extraLibraries(llvmConfig, targetOS));
}
@@ -140,7 +134,9 @@ function formattingLibs(llvmConfig, qtcFunctions, targetOS)
function toolingLibs(llvmConfig, targetOS)
{
- var fixedList = [
+ var hasLibClangTooling = File.directoryEntries(libDir(llvmConfig), File.Files)
+ .some(function(p) { return p.contains("clangTooling"); });
+ var fixedList = hasLibClangTooling ? [
"clangTooling",
"clangFrontend",
"clangIndex",
@@ -156,7 +152,7 @@ function toolingLibs(llvmConfig, targetOS)
"clangAST",
"clangLex",
"clangBasic",
- ];
+ ] : ["clang-cpp"];
return fixedList.concat(extraLibraries(llvmConfig, targetOS));
}
diff --git a/qbs/modules/libclang/libclang.qbs b/qbs/modules/libclang/libclang.qbs
index bb2878f198..9c2cfae23d 100644
--- a/qbs/modules/libclang/libclang.qbs
+++ b/qbs/modules/libclang/libclang.qbs
@@ -64,8 +64,7 @@ Module {
return incl != llvmIncludeDir;
})
property stringList llvmToolingCxxFlags: clangProbe.llvmToolingCxxFlags
- property bool toolingEnabled: Utilities.versionCompare(llvmVersion, "10") < 0
- && !Environment.getEnv("QTC_DISABLE_CLANG_REFACTORING")
+ property bool toolingEnabled: !Environment.getEnv("QTC_DISABLE_CLANG_REFACTORING")
validate: {
if (!clangProbe.found) {
diff --git a/qbs/modules/qtc/qtc.qbs b/qbs/modules/qtc/qtc.qbs
index 93d08ab97f..92245dfc17 100644
--- a/qbs/modules/qtc/qtc.qbs
+++ b/qbs/modules/qtc/qtc.qbs
@@ -4,16 +4,16 @@ import qbs.FileInfo
import "qtc.js" as HelperFunctions
Module {
- property string qtcreator_display_version: '4.12.2'
+ property string qtcreator_display_version: '4.13.0-beta1'
property string ide_version_major: '4'
property string ide_version_minor: '12'
- property string ide_version_release: '2'
+ property string ide_version_release: '82'
property string qtcreator_version: ide_version_major + '.' + ide_version_minor + '.'
+ ide_version_release
property string ide_compat_version_major: '4'
property string ide_compat_version_minor: '12'
- property string ide_compat_version_release: '0'
+ property string ide_compat_version_release: '82'
property string qtcreator_compat_version: ide_compat_version_major + '.'
+ ide_compat_version_minor + '.' + ide_compat_version_release
diff --git a/qtcreator.pro b/qtcreator.pro
index b17bad660a..a8cb39fac3 100644
--- a/qtcreator.pro
+++ b/qtcreator.pro
@@ -1,9 +1,9 @@
include(qtcreator.pri)
#version check qt
-!minQtVersion(5, 11, 0) {
+!minQtVersion(5, 12, 0) {
message("Cannot build $$IDE_DISPLAY_NAME with Qt version $${QT_VERSION}.")
- error("Use at least Qt 5.11.0.")
+ error("Use at least Qt 5.12.0.")
}
include(doc/doc.pri)
@@ -124,14 +124,8 @@ macx {
BINDIST_EXCLUDE_ARG.debug = $${BINDIST_EXCLUDE_ARG.release}
deployqt.commands = python -u $$PWD/scripts/deployqt.py -i \"$(INSTALL_ROOT)$$QTC_PREFIX/bin/$${IDE_APP_TARGET}\" \"$(QMAKE)\"
deployqt.depends = install
- win32:!isEmpty(BINARY_ARTIFACTS_BRANCH) {
- deployartifacts.depends = install
- deployartifacts.commands = git clone --depth 1 -b $$BINARY_ARTIFACTS_BRANCH \
- "http://code.qt.io/qt-creator/binary-artifacts.git" \
- && xcopy /s /q /y /i "binary-artifacts\\win32" \"$(INSTALL_ROOT)$$QTC_PREFIX\" \
- && rmdir /s /q binary-artifacts
- QMAKE_EXTRA_TARGETS += deployartifacts
- }
+ # legacy dummy target
+ win32: QMAKE_EXTRA_TARGETS += deployartifacts
}
INSTALLER_ARCHIVE_FROM_ENV = $$(INSTALLER_ARCHIVE)
diff --git a/qtcreator_ide_branding.pri b/qtcreator_ide_branding.pri
index baed3a6626..465db489e6 100644
--- a/qtcreator_ide_branding.pri
+++ b/qtcreator_ide_branding.pri
@@ -1,8 +1,7 @@
-QTCREATOR_VERSION = 4.12.2
-QTCREATOR_COMPAT_VERSION = 4.12.0
-QTCREATOR_DISPLAY_VERSION = 4.12.2
+QTCREATOR_VERSION = 4.12.82
+QTCREATOR_COMPAT_VERSION = 4.12.82
+QTCREATOR_DISPLAY_VERSION = 4.13.0-beta1
QTCREATOR_COPYRIGHT_YEAR = 2020
-BINARY_ARTIFACTS_BRANCH = 4.12
IDE_DISPLAY_NAME = Qt Creator
IDE_ID = qtcreator
diff --git a/scripts/build.py b/scripts/build.py
index e7e414f508..4547bf647c 100755
--- a/scripts/build.py
+++ b/scripts/build.py
@@ -153,17 +153,12 @@ def build_qtcreator(args, paths):
paths.build)
if not args.no_docs:
common.check_print_call(['cmake', '--install', '.', '--prefix', paths.install,
- '--component', 'qtc_docs_qtcreator'],
+ '--component', 'qch_docs'],
paths.build)
common.check_print_call(['cmake', '--install', '.', '--prefix', paths.install,
- '--component', 'html_docs_qtcreator'],
- paths.build)
- common.check_print_call(['cmake', '--install', '.', '--prefix', paths.install,
- '--component', 'html_docs_qtcreator-dev'],
- paths.build)
- common.check_print_call(['cmake', '--install', '.', '--prefix', paths.install,
- '--component', 'html_docs_qtcreator-dev'],
+ '--component', 'html_docs'],
paths.build)
+
def build_wininterrupt(args, paths):
if not common.is_windows_platform():
return
diff --git a/scripts/build_plugin.py b/scripts/build_plugin.py
index 97c4829745..9df8c64f74 100755
--- a/scripts/build_plugin.py
+++ b/scripts/build_plugin.py
@@ -51,6 +51,8 @@ def get_arguments():
parser.add_argument('--add-config', help=('Adds the argument to the CMake configuration call. '
'Use "--add-config=-DSOMEVAR=SOMEVALUE" if the argument begins with a dash.'),
action='append', dest='config_args', default=[])
+ parser.add_argument('--with-docs', help='Build and install documentation.',
+ action='store_true', default=False)
parser.add_argument('--deploy', help='Installs the "Dependencies" component of the plugin.',
action='store_true', default=False)
parser.add_argument('--debug', help='Enable debug builds', action='store_true', default=False)
@@ -79,6 +81,9 @@ def build(args, paths):
# TODO this works around a CMake bug https://gitlab.kitware.com/cmake/cmake/issues/20119
cmake_args += ['-DBUILD_WITH_PCH=OFF']
+ if args.with_docs:
+ cmake_args += ['-DWITH_DOCS=ON']
+
ide_revision = common.get_commit_SHA(paths.src)
if ide_revision:
cmake_args += ['-DQTC_PLUGIN_REVISION=' + ide_revision]
@@ -88,8 +93,17 @@ def build(args, paths):
cmake_args += args.config_args
common.check_print_call(cmake_args + [paths.src], paths.build)
common.check_print_call(['cmake', '--build', '.'], paths.build)
+ if args.with_docs:
+ common.check_print_call(['cmake', '--build', '.', '--target', 'docs'], paths.build)
common.check_print_call(['cmake', '--install', '.', '--prefix', paths.install, '--strip'],
paths.build)
+ if args.with_docs:
+ common.check_print_call(['cmake', '--install', '.', '--prefix', paths.install,
+ '--component', 'qch_docs'],
+ paths.build)
+ common.check_print_call(['cmake', '--install', '.', '--prefix', paths.install,
+ '--component', 'html_docs'],
+ paths.build)
if args.deploy:
common.check_print_call(['cmake', '--install', '.', '--prefix', paths.install,
'--component', 'Dependencies'],
diff --git a/share/qtcreator/CMakeLists.txt b/share/qtcreator/CMakeLists.txt
index 303fb9c7d0..622761f4d8 100644
--- a/share/qtcreator/CMakeLists.txt
+++ b/share/qtcreator/CMakeLists.txt
@@ -20,21 +20,12 @@ if (APPLE)
set(resource_directories ${resource_directories} scripts)
endif()
-add_custom_target(copy_share_to_builddir ALL
- COMMENT Copy files into build directory
- VERBATIM
-)
-
# copy resource directories during build
-foreach(dir IN ITEMS ${resource_directories})
- add_custom_command(TARGET copy_share_to_builddir POST_BUILD
- COMMAND "${CMAKE_COMMAND}" -E copy_directory "${dir}"
- "${PROJECT_BINARY_DIR}/${IDE_DATA_PATH}/${dir}"
- WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
- COMMENT Copy resource directories into build directory
- VERBATIM
- )
-endforeach()
+qtc_copy_to_builddir(copy_share_to_builddir
+ DIRECTORIES ${resource_directories}
+ DESTINATION "${IDE_DATA_PATH}"
+ CREATE_SUBDIRS
+)
# create install rule for resource directories
install(DIRECTORY ${resource_directories} DESTINATION "${IDE_DATA_PATH}")
diff --git a/share/qtcreator/debugger/creatortypes.py b/share/qtcreator/debugger/creatortypes.py
index 0bb0be0699..07e124f877 100644
--- a/share/qtcreator/debugger/creatortypes.py
+++ b/share/qtcreator/debugger/creatortypes.py
@@ -23,6 +23,8 @@
#
############################################################################
+from dumper import Children
+
def typeTarget(type):
target = type.target()
@@ -242,6 +244,39 @@ def qdump__Utils__Port(d, value):
d.putPlainChildren(value)
+
+def qdump__Utils__Environment(d, value):
+ qdump__Utils__NameValueDictionary(d, value)
+
+
+def qdump__Utils__NameValueDictionary(d, value):
+ dptr = d.extractPointer(value["m_values"])
+ (ref, n) = d.split('ii', dptr)
+ d.check(0 <= n and n <= 100 * 1000 * 1000)
+ d.check(-1 <= ref and ref < 100000)
+
+ d.putItemCount(n)
+ if d.isExpanded():
+ if n > 10000:
+ n = 10000
+
+ typeCode = 'ppp@{%s}@{%s}' % ("Utils::DictKey", "QString")
+
+ def helper(node):
+ (p, left, right, padding1, key, padding2, value) = d.split(typeCode, node)
+ if left:
+ for res in helper(left):
+ yield res
+ yield (key["name"], value)
+ if right:
+ for res in helper(right):
+ yield res
+
+ with Children(d, n):
+ for (pair, i) in zip(helper(dptr + 8), range(n)):
+ d.putPairItem(i, pair, 'key', 'value')
+
+
def qdump__Utf8String(d, value):
d.putByteArrayValue(value['byteArray'])
d.putPlainChildren(value)
diff --git a/share/qtcreator/debugger/lldbbridge.py b/share/qtcreator/debugger/lldbbridge.py
index e3d9196345..ca6777ea4e 100644
--- a/share/qtcreator/debugger/lldbbridge.py
+++ b/share/qtcreator/debugger/lldbbridge.py
@@ -32,7 +32,7 @@ import threading
import time
import lldb
import utils
-from utils import DebuggerStartMode, BreakpointType, TypeCode
+from utils import DebuggerStartMode, BreakpointType, TypeCode, LogChannel
from contextlib import contextmanager
@@ -40,6 +40,11 @@ sys.path.insert(1, os.path.dirname(os.path.abspath(inspect.getfile(inspect.curre
# Simplify development of this module by reloading deps
if 'dumper' in sys.modules:
+ if sys.version_info[0] >= 3:
+ if sys.version_info[1] > 3:
+ from importlib import reload
+ else:
+ reload = lambda x: print('Unsupported Python version - not reloading %s' % str(x))
reload(sys.modules['dumper'])
from dumper import DumperBase, SubItem, Children, TopLevelItem
@@ -108,7 +113,6 @@ class Dumper(DumperBase):
self.process = None
self.target = None
self.eventState = lldb.eStateInvalid
- self.runEngineAttempted = False
self.executable_ = None
self.symbolFile_ = None
@@ -123,8 +127,15 @@ class Dumper(DumperBase):
self.isInterrupting_ = False
self.interpreterBreakpointResolvers = []
+ DumperBase.warn = Dumper.warn_impl
self.report('lldbversion=\"%s\"' % lldb.SBDebugger.GetVersionString())
- self.reportState('enginesetupok')
+
+ @staticmethod
+ def warn_impl(message):
+ if message[-1:] == '\n':
+ message += '\n'
+ print('@\nbridgemessage={msg="%s",channel="%s"}\n@'
+ % (message.replace('"', '$'), LogChannel.AppError))
def fromNativeFrameValue(self, nativeValue):
return self.fromNativeValue(nativeValue)
@@ -843,6 +854,8 @@ class Dumper(DumperBase):
return None
def setupInferior(self, args):
+ """ Set up SBTarget instance """
+
error = lldb.SBError()
self.executable_ = args['executable']
@@ -880,6 +893,12 @@ class Dumper(DumperBase):
if self.sysRoot_:
self.debugger.SetCurrentPlatformSDKRoot(self.sysRoot_)
+ # There seems to be some kind of unexpected behavior, or bug in LLDB
+ # such that target.Attach(attachInfo, error) below does not create
+ # a valid process if this symbolFile here is valid.
+ if self.startMode_ == DebuggerStartMode.AttachExternal:
+ self.symbolFile_ = ''
+
self.target = self.debugger.CreateTarget(
self.symbolFile_, None, self.platform_, True, error)
@@ -888,19 +907,6 @@ class Dumper(DumperBase):
self.reportState('enginerunfailed')
return
- if (self.startMode_ == DebuggerStartMode.AttachToRemoteServer
- or self.startMode_ == DebuggerStartMode.AttachToRemoteProcess):
-
-
- remote_channel = 'connect://' + self.remoteChannel_
- connect_options = lldb.SBPlatformConnectOptions(remote_channel)
-
- res = self.target.GetPlatform().ConnectRemote(connect_options)
- DumperBase.warn("CONNECT: %s %s %s" % (res,
- self.target.GetPlatform().GetName(),
- self.target.GetPlatform().IsConnected()))
-
-
broadcaster = self.target.GetBroadcaster()
listener = self.debugger.GetListener()
broadcaster.AddListener(listener, lldb.SBProcess.eBroadcastBitStateChanged)
@@ -918,32 +924,43 @@ class Dumper(DumperBase):
% (state, error, self.executable_), args)
def runEngine(self, args):
- if self.runEngineAttempted:
- return
- self.runEngineAttempted = True
- self.prepare(args)
- s = threading.Thread(target=self.loop, args=[])
- s.start()
+ """ Set up SBProcess instance """
- def prepare(self, args):
error = lldb.SBError()
- if self.attachPid_ > 0:
- attachInfo = lldb.SBAttachInfo(self.attachPid_)
- self.process = self.target.Attach(attachInfo, error)
+ if self.startMode_ == DebuggerStartMode.AttachExternal:
+ attach_info = lldb.SBAttachInfo(self.attachPid_)
+ self.process = self.target.Attach(attach_info, error)
if not error.Success():
- self.reportState('inferiorrunfailed')
- return
- self.report('pid="%s"' % self.process.GetProcessID())
- # Even if it stops it seems that LLDB assumes it is running
- # and later detects that it did stop after all, so it is be
- # better to mirror that and wait for the spontaneous stop
- if self.process and self.process.GetState() == lldb.eStateStopped:
- # lldb stops the process after attaching. This happens before the
- # eventloop starts. Relay the correct state back.
+ self.reportState('enginerunfailed')
+ else:
+ self.report('pid="%s"' % self.process.GetProcessID())
self.reportState('enginerunandinferiorstopok')
+
+ elif (self.startMode_ == DebuggerStartMode.AttachToRemoteServer
+ and self.platform_ == 'remote-android'):
+
+ connect_options = lldb.SBPlatformConnectOptions(self.remoteChannel_)
+ res = self.target.GetPlatform().ConnectRemote(connect_options)
+
+ DumperBase.warn("CONNECT: %s %s platform: %s %s" % (res,
+ self.remoteChannel_,
+ self.target.GetPlatform().GetName(),
+ self.target.GetPlatform().IsConnected()))
+ if not res.Success():
+ self.report(self.describeError(error))
+ self.reportState('enginerunfailed')
+ return
+
+ attach_info = lldb.SBAttachInfo(self.attachPid_)
+ self.process = self.target.Attach(attach_info, error)
+ if not error.Success():
+ self.report(self.describeError(error))
+ self.reportState('enginerunfailed')
else:
- self.reportState('enginerunandinferiorrunok')
+ self.report('pid="%s"' % self.process.GetProcessID())
+ self.reportState('enginerunandinferiorstopok')
+
elif (self.startMode_ == DebuggerStartMode.AttachToRemoteServer
or self.startMode_ == DebuggerStartMode.AttachToRemoteProcess):
@@ -953,6 +970,9 @@ class Dumper(DumperBase):
launchInfo = lldb.SBLaunchInfo(self.processArgs_)
#launchInfo.SetWorkingDirectory(self.workingDirectory_)
launchInfo.SetWorkingDirectory('/tmp')
+ if self.platform_ == 'remote-android':
+ launchInfo.SetWorkingDirectory('/data/local/tmp')
+ launchInfo.SetEnvironmentEntries(self.environment_, False)
launchInfo.SetExecutableFile(f, True)
DumperBase.warn("TARGET: %s" % self.target)
@@ -990,6 +1010,9 @@ class Dumper(DumperBase):
self.report('pid="%s"' % self.process.GetProcessID())
self.reportState('enginerunandinferiorrunok')
+ s = threading.Thread(target=self.loop, args=[])
+ s.start()
+
def loop(self):
event = lldb.SBEvent()
#broadcaster = self.target.GetBroadcaster()
@@ -1257,23 +1280,29 @@ class Dumper(DumperBase):
self.put('],partial="%d"' % isPartial)
self.reportResult(self.output, args)
+
def fetchRegisters(self, args=None):
- if self.process is None:
- result = 'process="none"'
- else:
- frame = self.currentFrame()
- if frame:
- result = 'registers=['
- for group in frame.GetRegisters():
- for reg in group:
- value = ''.join(["%02x" % x for x in reg.GetData().uint8s])
- result += '{name="%s"' % reg.GetName()
- result += ',value="0x%s"' % value
- result += ',size="%s"' % reg.GetByteSize()
- result += ',type="%s"},' % reg.GetType()
- result += ']'
+ if not self.process:
+ self.reportResult('process="none",registers=[]', args)
+ return
+
+ frame = self.currentFrame()
+ if not frame or not frame.IsValid():
+ self.reportResult('frame="none",registers=[]', args)
+ return
+
+ result = 'registers=['
+ for group in frame.GetRegisters():
+ for reg in group:
+ value = ''.join(["%02x" % x for x in reg.GetData().uint8s])
+ result += '{name="%s"' % reg.GetName()
+ result += ',value="0x%s"' % value
+ result += ',size="%s"' % reg.GetByteSize()
+ result += ',type="%s"},' % reg.GetType()
+ result += ']'
self.reportResult(result, args)
+
def setRegister(self, args):
name = args["name"]
value = args["value"]
@@ -1698,7 +1727,8 @@ class Dumper(DumperBase):
def activateFrame(self, args):
self.reportToken(args)
- self.currentThread().SetSelectedFrame(args['index'])
+ frame = max(0, int(args['index'])) # Can be -1 in all-asm stacks
+ self.currentThread().SetSelectedFrame(frame)
self.reportResult('', args)
def selectThread(self, args):
@@ -1722,6 +1752,9 @@ class Dumper(DumperBase):
error = str(result.GetError())
self.report('success="%d",output="%s",error="%s"' % (success, output, error))
+ def executeRoundtrip(self, args):
+ self.reportResult('', args)
+
def fetchDisassembler(self, args):
functionName = args.get('function', '')
flavor = args.get('flavor', '')
diff --git a/share/qtcreator/debugger/utils.py b/share/qtcreator/debugger/utils.py
index feec4379cd..e1335add66 100644
--- a/share/qtcreator/debugger/utils.py
+++ b/share/qtcreator/debugger/utils.py
@@ -86,7 +86,7 @@ class BreakpointType():
) = range(0, 14)
-# Internal codes for types keep in sync with cdbextensions pytype.cpp
+# Internal codes for types. Keep in sync with cdbextensions pytype.cpp
class TypeCode():
(
Typedef,
@@ -108,6 +108,26 @@ class TypeCode():
) = range(0, 16)
+# Internal codes for logging channels. Keep in sync woth debuggerconstants.h
+class LogChannel():
+ (
+ LogInput, # Used for user input
+ LogMiscInput, # Used for misc stuff in the input pane
+ LogOutput,
+ LogWarning,
+ LogError,
+ LogStatus, # Used for status changed messages
+ LogTime, # Used for time stamp messages
+ LogDebug,
+ LogMisc,
+ AppOutput, # stdout
+ AppError, # stderr
+ AppStuff, # (possibly) windows debug channel
+ StatusBar, # LogStatus and also put to the status bar
+ ConsoleOutput # Used to output to console
+ ) = range(0, 14)
+
+
def isIntegralTypeName(name):
return name in (
"int",
diff --git a/share/qtcreator/modeleditor/standard.def b/share/qtcreator/modeleditor/standard.def
index af6c08a035..34249aa515 100644
--- a/share/qtcreator/modeleditor/standard.def
+++ b/share/qtcreator/modeleditor/standard.def
@@ -42,6 +42,10 @@
// ArcTo { x: <center_x>; y: <center_y>; radiusX: <radius_x>; radiusY: <radius_y>; start: <start_angle>; span: <span_angle> }
// Close
// }
+// Outline {
+// // same as in Shape to define the geometrical ouline of the icon
+// // if the outline is not defined it defaults to the shape
+// }
// }
//
//
@@ -165,6 +169,10 @@ Icon {
Line { x0: 0.0; y0: 0.0; x1: 0.0; y1: 20.0 }
Line { x0: 0.0; y0: 10.0; x1: 4.0; y1: 10.0 }
}
+ Outline {
+ Circle { x: 14.0; y: 10.0; radius: 10.0 }
+ Rect { x: 0; y: 0; width: 14; height: 20 }
+ }
}
Icon {
@@ -178,6 +186,9 @@ Icon {
Line { x0: 10.0; y0: 0.0; x1: 14.0; y1: -2.0 }
Line { x0: 10.0; y0: 0.0; x1: 14.0; y1: 4.0 }
}
+ Outline {
+ Circle { x: 10.0; y: 10.0; radius: 10.0 }
+ }
}
Icon {
@@ -190,6 +201,10 @@ Icon {
Circle { x: 10.0; y: 10.0; radius: 10.0 }
Line { x0: 0.0; y0: 20.0; x1: 20.0; y1: 20.0 }
}
+ Outline {
+ Circle { x: 10.0; y: 10.0; radius: 10.0 }
+ Rect { x: 0; y: 10; width: 20; height: 10 }
+ }
}
Association {
@@ -313,6 +328,10 @@ Icon {
Line { x0: 10; y0: 25; x1: 3; y1: 40 }
Line { x0: 10; y0: 25; x1: 17; y1: 40 }
}
+ Outline {
+ Circle { x: 10; y: 5; radius: 5 }
+ Rect { x: 3; y: 5; width: 14; height: 35 }
+ }
}
Relation {
@@ -522,6 +541,9 @@ Icon {
Line { x0: 0; y0: 0; x1: 10; y1: 10 }
Line { x0: 0; y0: 10; x1: 10; y1: 0 }
}
+ Outline {
+ Circle { x: 5; y: 5; radius: 2 }
+ }
}
Icon {
diff --git a/share/qtcreator/qml-type-descriptions/builtins.qmltypes b/share/qtcreator/qml-type-descriptions/builtins.qmltypes
index ec31791827..a7c009027c 100644
--- a/share/qtcreator/qml-type-descriptions/builtins.qmltypes
+++ b/share/qtcreator/qml-type-descriptions/builtins.qmltypes
@@ -3223,15 +3223,15 @@ Module {
Method { name: "deleteLater" }
}
Component {
- name: "QRegExpValidator"
+ name: "QRegularExpressionValidator"
prototype: "QValidator"
exports: [
- "QtQuick/RegExpValidator 1.0"
+ "QtQuick/RegularExpressionValidator 2.14"
]
exportMetaObjectRevisions: [
0
]
- Property { name: "regExp"; type: "QRegExp" }
+ Property { name: "regularExpression"; type: "QRegularExpression" }
}
Component { name: "QValidator"; prototype: "QObject" }
Component {
diff --git a/share/qtcreator/qml/qmlpuppet/commands/inputeventcommand.cpp b/share/qtcreator/qml/qmlpuppet/commands/inputeventcommand.cpp
index 73a68b0620..4eb4f3380a 100644
--- a/share/qtcreator/qml/qmlpuppet/commands/inputeventcommand.cpp
+++ b/share/qtcreator/qml/qmlpuppet/commands/inputeventcommand.cpp
@@ -55,9 +55,9 @@ InputEventCommand::InputEventCommand(QInputEvent *e)
QDataStream &operator<<(QDataStream &out, const InputEventCommand &command)
{
- out << command.type();
+ out << int(command.type());
out << command.pos();
- out << command.button();
+ out << int(command.button());
out << command.buttons();
out << command.modifiers();
out << command.angleDelta();
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/AxisHelper.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/AxisHelper.qml
index 7481d24225..7ae7bd44d9 100644
--- a/share/qtcreator/qml/qmlpuppet/mockfiles/AxisHelper.qml
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/AxisHelper.qml
@@ -121,7 +121,7 @@ View3D {
pick(mouse);
if (pickObj) {
axisHelperView.editCameraCtrl.focusObject(axisHelperView.selectedNode,
- pickObj.cameraRotation, false);
+ pickObj.cameraRotation, false, false);
} else {
mouse.accepted = false;
}
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/EditCameraController.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/EditCameraController.qml
index 207dc94199..20dd112d61 100644
--- a/share/qtcreator/qml/qmlpuppet/mockfiles/EditCameraController.qml
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/EditCameraController.qml
@@ -87,14 +87,15 @@ Item {
}
- function focusObject(targetObject, rotation, updateZoom)
+ function focusObject(targetObject, rotation, updateZoom, closeUp)
{
if (!camera)
return;
camera.eulerRotation = rotation;
var newLookAtAndZoom = _generalHelper.focusObjectToCamera(
- camera, _defaultCameraLookAtDistance, targetObject, view3d, _zoomFactor, updateZoom);
+ camera, _defaultCameraLookAtDistance, targetObject, view3d, _zoomFactor,
+ updateZoom, closeUp);
_lookAtPoint = newLookAtAndZoom.toVector3d();
_zoomFactor = newLookAtAndZoom.w;
storeCameraState(0);
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml
index db8d4fb4ea..6527d06e6e 100644
--- a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml
@@ -146,7 +146,7 @@ Item {
if (editView) {
var targetNode = selectionBoxes.length > 0
? selectionBoxes[0].model : null;
- cameraControl.focusObject(targetNode, editView.camera.eulerRotation, true);
+ cameraControl.focusObject(targetNode, editView.camera.eulerRotation, true, false);
}
}
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/IconRenderer3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/IconRenderer3D.qml
index b16b27406d..afaf8481ca 100644
--- a/share/qtcreator/qml/qmlpuppet/mockfiles/IconRenderer3D.qml
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/IconRenderer3D.qml
@@ -42,7 +42,7 @@ Item {
function fitAndHideBox() : bool
{
- cameraControl.focusObject(selectionBox.model, viewCamera.eulerRotation, true);
+ cameraControl.focusObject(selectionBox.model, viewCamera.eulerRotation, true, true);
if (cameraControl._zoomFactor < 0.1) {
view3D.importScene.scale = view3D.importScene.scale.times(10);
return false;
diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp
index f99d219c5c..f62a7e5173 100644
--- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp
+++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp
@@ -148,7 +148,7 @@ float GeneralHelper::zoomCamera(QQuick3DCamera *camera, float distance, float de
// Return value contains new lookAt point (xyz) and zoom factor (w)
QVector4D GeneralHelper::focusObjectToCamera(QQuick3DCamera *camera, float defaultLookAtDistance,
QQuick3DNode *targetObject, QQuick3DViewport *viewPort,
- float oldZoom, bool updateZoom)
+ float oldZoom, bool updateZoom, bool closeUp)
{
if (!camera)
return QVector4D(0.f, 0.f, 0.f, 1.f);
@@ -200,7 +200,9 @@ QVector4D GeneralHelper::focusObjectToCamera(QQuick3DCamera *camera, float defau
camera->setPosition(lookAt + newLookVector);
- float newZoomFactor = updateZoom ? qBound(.01f, float(maxExtent / 900.), 100.f) : oldZoom;
+ qreal divisor = closeUp ? 900. : 725.;
+
+ float newZoomFactor = updateZoom ? qBound(.01f, float(maxExtent / divisor), 100.f) : oldZoom;
float cameraZoomFactor = zoomCamera(camera, 0, defaultLookAtDistance, lookAt, newZoomFactor, false);
return QVector4D(lookAt, cameraZoomFactor);
diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h
index e9d8e52545..15795ac28b 100644
--- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h
+++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h
@@ -66,8 +66,9 @@ public:
float defaultLookAtDistance, const QVector3D &lookAt,
float zoomFactor, bool relative);
Q_INVOKABLE QVector4D focusObjectToCamera(QQuick3DCamera *camera, float defaultLookAtDistance,
- QQuick3DNode *targetObject, QQuick3DViewport *viewPort,
- float oldZoom, bool updateZoom = true);
+ QQuick3DNode *targetObject, QQuick3DViewport *viewPort,
+ float oldZoom, bool updateZoom = true,
+ bool closeUp = false);
Q_INVOKABLE void delayedPropertySet(QObject *obj, int delay, const QString &property,
const QVariant& value);
Q_INVOKABLE QQuick3DNode *resolvePick(QQuick3DNode *pickNode);
diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/icongizmoimageprovider.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/icongizmoimageprovider.cpp
index 2e5a2b0d0a..cf2be48316 100644
--- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/icongizmoimageprovider.cpp
+++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/icongizmoimageprovider.cpp
@@ -35,6 +35,9 @@ IconGizmoImageProvider::IconGizmoImageProvider()
QImage IconGizmoImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
{
+ Q_UNUSED(size)
+ Q_UNUSED(requestedSize)
+
// id format: <file name>:<color name>
QStringList parts = id.split(':');
if (parts.size() == 2) {
diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/iconrenderer/iconrenderer.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/iconrenderer/iconrenderer.cpp
index 48830caee6..9f9b7736d7 100644
--- a/share/qtcreator/qml/qmlpuppet/qml2puppet/iconrenderer/iconrenderer.cpp
+++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/iconrenderer/iconrenderer.cpp
@@ -108,7 +108,7 @@ void IconRenderer::setupRender()
if (m_contentItem->height() > containerItem->height())
containerItem->setHeight(m_contentItem->height());
- QTimer::singleShot(0, this, [this, containerItem, is3D]() {
+ QTimer::singleShot(0, this, [this, is3D, containerItem]() {
m_designerSupport.refFromEffectItem(m_quickView->rootObject(), false);
QQuickDesignerSupportItems::disableNativeTextRendering(m_quickView->rootObject());
diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml
index 37f9712678..cd3ddef34d 100644
--- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml
+++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml
@@ -47,6 +47,8 @@ Item {
width: itemLibraryIconWidth // to be set in Qml context
height: itemLibraryIconHeight // to be set in Qml context
source: itemLibraryIconPath // to be set by model
+
+ cache: false // Allow thumbnail to be dynamically updated
}
Text {
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/AdvancedSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/AdvancedSection.qml
index 4eb7420d74..5434e4705b 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/AdvancedSection.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/AdvancedSection.qml
@@ -100,14 +100,17 @@ Section {
}
Label {
- text: "State"
+ text: qsTr("State")
}
SecondColumnLayout {
- LineEdit {
+
+ ComboBox {
+ Layout.fillWidth: true
backendValue: backendValues.state
- showTranslateCheckBox: false
- enabled: anchorBackend.hasParent || isBaseState
+ model: allStateNames
+ valueType: ComboBox.String
}
+
ExpandingSpacer {
}
}
@@ -158,5 +161,56 @@ Section {
}
}
+ Label {
+ text: qsTr("Focus")
+ tooltip: qsTr("Holds whether the item has focus within the enclosing FocusScope.")
+ disabledState: !backendValues.focus.isAvailable
+ }
+ SecondColumnLayout {
+ CheckBox {
+ backendValue: backendValues.focus
+ text: backendValues.focus.valueToString
+ enabled: backendValues.focus.isAvailable
+ implicitWidth: 180
+ }
+ ExpandingSpacer {
+ }
+ }
+
+ Label {
+ text: qsTr("Active focus on tab")
+ tooltip: qsTr("Holds whether the item wants to be in the tab focus chain.")
+ disabledState: !backendValues.activeFocusOnTab.isAvailable
+ }
+ SecondColumnLayout {
+ CheckBox {
+ backendValue: backendValues.activeFocusOnTab
+ text: backendValues.activeFocusOnTab.valueToString
+ enabled: backendValues.activeFocusOnTab.isAvailable
+ implicitWidth: 180
+ }
+ ExpandingSpacer {
+ }
+ }
+
+ Label {
+ text: qsTr("Baseline offset")
+ tooltip: qsTr("Specifies the position of the item's baseline in local coordinates.")
+ disabledState: !backendValues.baselineOffset.isAvailable
+ }
+ SecondColumnLayout {
+ SpinBox {
+ sliderIndicatorVisible: true
+ backendValue: backendValues.baselineOffset
+ hasSlider: true
+ decimals: 0
+ minimumValue: -1000
+ maximumValue: 1000
+ Layout.preferredWidth: 140
+ enabled: backendValues.baselineOffset.isAvailable
+ }
+ ExpandingSpacer {
+ }
+ }
}
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/AnimatedImageSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/AnimatedImageSpecifics.qml
new file mode 100644
index 0000000000..787e390cbd
--- /dev/null
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/AnimatedImageSpecifics.qml
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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.1
+import HelperWidgets 2.0
+import QtQuick.Layouts 1.0
+
+Column {
+ anchors.left: parent.left
+ anchors.right: parent.right
+
+ ImageSpecifics {
+ }
+
+ Section {
+ anchors.left: parent.left
+ anchors.right: parent.right
+ caption: qsTr("Animated Image")
+
+ SectionLayout {
+ Label {
+ text: qsTr("Speed")
+ disabledState: !backendValues.speed.isAvailable
+ }
+ SecondColumnLayout {
+ SpinBox {
+ sliderIndicatorVisible: true
+ backendValue: backendValues.speed
+ hasSlider: true
+ decimals: 2
+ minimumValue: 0
+ maximumValue: 100
+ Layout.preferredWidth: 140
+ enabled: backendValues.speed.isAvailable
+ }
+ ExpandingSpacer {
+ }
+ }
+
+ Label {
+ text: qsTr("Paused")
+ tooltip: qsTr("Holds whether the animated image is paused.")
+ disabledState: !backendValues.paused.isAvailable
+ }
+
+ SecondColumnLayout {
+ CheckBox {
+ enabled: backendValues.paused.isAvailable
+ text: backendValues.paused.valueToString
+ backendValue: backendValues.paused
+ implicitWidth: 180
+ }
+ ExpandingSpacer {}
+ }
+
+ Label {
+ text: qsTr("Playing")
+ tooltip: qsTr("Holds whether the animated image is playing.")
+ disabledState: !backendValues.playing.isAvailable
+ }
+
+ SecondColumnLayout {
+ CheckBox {
+ enabled: backendValues.playing.isAvailable
+ text: backendValues.playing.valueToString
+ backendValue: backendValues.playing
+ implicitWidth: 180
+ }
+ ExpandingSpacer {}
+ }
+ }
+ }
+}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/BorderImageSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/BorderImageSpecifics.qml
index 3d39d44e8f..362ba144c5 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/BorderImageSpecifics.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/BorderImageSpecifics.qml
@@ -124,7 +124,7 @@ Column {
}
Label {
- text: qsTr("Horizontal Fill mode")
+ text: qsTr("Horizontal Tile mode")
}
SecondColumnLayout {
@@ -138,7 +138,7 @@ Column {
}
Label {
- text: qsTr("Vertical Fill mode")
+ text: qsTr("Vertical Tile mode")
}
SecondColumnLayout {
@@ -186,6 +186,70 @@ Column {
}
}
+
+ Label {
+ text: qsTr("Mirror")
+ tooltip: qsTr("Specifies whether the image should be horizontally inverted.")
+ disabledState: !backendValues.mirror.isAvailable
+ }
+
+ SecondColumnLayout {
+ CheckBox {
+ enabled: backendValues.mirror.isAvailable
+ text: backendValues.mirror.valueToString
+ backendValue: backendValues.mirror
+ implicitWidth: 180
+ }
+ ExpandingSpacer {}
+ }
+
+ Label {
+ text: qsTr("Smooth")
+ tooltip: qsTr("Specifies whether the image is smoothly filtered when scaled or transformed.")
+ disabledState: !backendValues.smooth.isAvailable
+ }
+
+ SecondColumnLayout {
+ CheckBox {
+ enabled: backendValues.smooth.isAvailable
+ text: backendValues.smooth.valueToString
+ backendValue: backendValues.smooth
+ implicitWidth: 180
+ }
+ ExpandingSpacer {}
+ }
+
+ Label {
+ text: qsTr("Cache")
+ tooltip: qsTr("Specifies whether the image should be cached.")
+ disabledState: !backendValues.cache.isAvailable
+ }
+
+ SecondColumnLayout {
+ CheckBox {
+ enabled: backendValues.cache.isAvailable
+ text: backendValues.cache.valueToString
+ backendValue: backendValues.cache
+ implicitWidth: 180
+ }
+ ExpandingSpacer {}
+ }
+
+ Label {
+ text: qsTr("Asynchronous")
+ tooltip: qsTr("Specifies that images on the local filesystem should be loaded asynchronously in a separate thread.")
+ disabledState: !backendValues.asynchronous.isAvailable
+ }
+
+ SecondColumnLayout {
+ CheckBox {
+ enabled: backendValues.asynchronous.isAvailable
+ text: backendValues.asynchronous.valueToString
+ backendValue: backendValues.asynchronous
+ implicitWidth: 180
+ }
+ ExpandingSpacer {}
+ }
}
}
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/GridSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/GridSpecifics.qml
index 37be5e5770..284849a415 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/GridSpecifics.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/GridSpecifics.qml
@@ -95,7 +95,32 @@ Column {
Layout.fillWidth: true
scope: "Qt"
}
+ }
+ Label {
+ text: qsTr("Horizontal item alignment")
+ }
+
+ SecondColumnLayout {
+ ComboBox {
+ model: ["AlignLeft", "AlignRight" ,"AlignHCenter"]
+ backendValue: backendValues.horizontalItemAlignment
+ Layout.fillWidth: true
+ scope: "Grid"
+ }
+ }
+
+ Label {
+ text: qsTr("Vertical item alignment")
+ }
+
+ SecondColumnLayout {
+ ComboBox {
+ model: ["AlignTop", "AlignBottom" ,"AlignVCenter"]
+ backendValue: backendValues.verticalItemAlignment
+ Layout.fillWidth: true
+ scope: "Grid"
+ }
}
Label {
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/ImageSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/ImageSpecifics.qml
index 8f742f06e2..60b97a1179 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/ImageSpecifics.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/ImageSpecifics.qml
@@ -58,7 +58,7 @@ Column {
SecondColumnLayout {
ComboBox {
scope: "Image"
- model: ["Stretch", "PreserveAspectFit", "PreserveAspectCrop", "Tile", "TileVertically", "TileHorizontally"]
+ model: ["Stretch", "PreserveAspectFit", "PreserveAspectCrop", "Tile", "TileVertically", "TileHorizontally", "Pad"]
backendValue: backendValues.fillMode
implicitWidth: 180
Layout.fillWidth: true
@@ -105,6 +105,136 @@ Column {
ExpandingSpacer {
}
}
+
+ Label {
+ text: qsTr("Horizontal alignment")
+ }
+
+ SecondColumnLayout {
+ ComboBox {
+ scope: "Image"
+ model: ["AlignLeft", "AlignRight", "AlignHCenter"]
+ backendValue: backendValues.horizontalAlignment
+ implicitWidth: 180
+ Layout.fillWidth: true
+ }
+
+ ExpandingSpacer {
+ }
+ }
+
+ Label {
+ text: qsTr("Vertical alignment")
+ }
+
+ SecondColumnLayout {
+ ComboBox {
+ scope: "Image"
+ model: ["AlignTop", "AlignBottom", "AlignVCenter"]
+ backendValue: backendValues.verticalAlignment
+ implicitWidth: 180
+ Layout.fillWidth: true
+ }
+
+ ExpandingSpacer {
+ }
+ }
+
+ Label {
+ text: qsTr("Asynchronous")
+ tooltip: qsTr("Specifies that images on the local filesystem should be loaded asynchronously in a separate thread.")
+ disabledState: !backendValues.asynchronous.isAvailable
+ }
+
+ SecondColumnLayout {
+ CheckBox {
+ enabled: backendValues.asynchronous.isAvailable
+ text: backendValues.asynchronous.valueToString
+ backendValue: backendValues.asynchronous
+ implicitWidth: 180
+ }
+ ExpandingSpacer {}
+ }
+
+ Label {
+ text: qsTr("Auto transform")
+ tooltip: qsTr("Specifies whether the image should automatically apply image transformation metadata such as EXIF orientation.")
+ disabledState: !backendValues.autoTransform.isAvailable
+ }
+
+ SecondColumnLayout {
+ CheckBox {
+ enabled: backendValues.autoTransform.isAvailable
+ text: backendValues.autoTransform.valueToString
+ backendValue: backendValues.autoTransform
+ implicitWidth: 180
+ }
+ ExpandingSpacer {}
+ }
+
+ Label {
+ text: qsTr("Cache")
+ tooltip: qsTr("Specifies whether the image should be cached.")
+ disabledState: !backendValues.cache.isAvailable
+ }
+
+ SecondColumnLayout {
+ CheckBox {
+ enabled: backendValues.cache.isAvailable
+ text: backendValues.cache.valueToString
+ backendValue: backendValues.cache
+ implicitWidth: 180
+ }
+ ExpandingSpacer {}
+ }
+
+ Label {
+ text: qsTr("Mipmap")
+ tooltip: qsTr("Specifies whether the image uses mipmap filtering when scaled or transformed.")
+ disabledState: !backendValues.mipmap.isAvailable
+ }
+
+ SecondColumnLayout {
+ CheckBox {
+ enabled: backendValues.mipmap.isAvailable
+ text: backendValues.mipmap.valueToString
+ backendValue: backendValues.mipmap
+ implicitWidth: 180
+ }
+ ExpandingSpacer {}
+ }
+
+ Label {
+ text: qsTr("Mirror")
+ tooltip: qsTr("Specifies whether the image should be horizontally inverted.")
+ disabledState: !backendValues.mirror.isAvailable
+ }
+
+ SecondColumnLayout {
+ CheckBox {
+ enabled: backendValues.mirror.isAvailable
+ text: backendValues.mirror.valueToString
+ backendValue: backendValues.mirror
+ implicitWidth: 180
+ }
+ ExpandingSpacer {}
+ }
+
+ Label {
+ text: qsTr("Smooth")
+ tooltip: qsTr("Specifies whether the image is smoothly filtered when scaled or transformed.")
+ disabledState: !backendValues.smooth.isAvailable
+ }
+
+ SecondColumnLayout {
+ CheckBox {
+ enabled: backendValues.smooth.isAvailable
+ text: backendValues.smooth.valueToString
+ backendValue: backendValues.smooth
+ implicitWidth: 180
+ }
+ ExpandingSpacer {}
+ }
}
}
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/MouseAreaSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/MouseAreaSpecifics.qml
index 71ff0260ba..0ca7f3d888 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/MouseAreaSpecifics.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/MouseAreaSpecifics.qml
@@ -54,7 +54,7 @@ Column {
}
Label {
- text: qsTr("Hover Enabled")
+ text: qsTr("Hover enabled")
tooltip: qsTr("This property holds whether hover events are handled.")
}
@@ -68,6 +68,197 @@ Column {
ExpandingSpacer {
}
}
+
+ Label {
+ text: qsTr("Accepted buttons")
+ tooltip: qsTr("This property holds the mouse buttons that the mouse area reacts to.")
+ }
+
+ SecondColumnLayout {
+ ComboBox {
+ backendValue: backendValues.acceptedButtons
+ model: ["LeftButton", "RightButton", "MiddleButton", "BackButton", "ForwardButton", "AllButtons"]
+ Layout.fillWidth: true
+ scope: "Qt"
+ }
+ ExpandingSpacer {
+ }
+ }
+
+ Label {
+ text: qsTr("Press and hold interval")
+ tooltip: qsTr("This property overrides the elapsed time in milliseconds before pressAndHold is emitted.")
+ }
+
+ SecondColumnLayout {
+ SpinBox {
+ backendValue: backendValues.pressAndHoldInterval
+ minimumValue: 0
+ maximumValue: 2000
+ decimals: 0
+ }
+ ExpandingSpacer {
+ }
+ }
+
+ Label {
+ text: qsTr("Scroll gesture enabled")
+ tooltip: qsTr("This property controls whether this MouseArea responds to scroll gestures from non-mouse devices.")
+ }
+
+ SecondColumnLayout {
+ CheckBox {
+ Layout.fillWidth: true
+ backendValue: backendValues.scrollGestureEnabled
+ text: backendValues.scrollGestureEnabled.valueToString
+ }
+
+ ExpandingSpacer {
+ }
+ }
+
+ Label {
+ text: qsTr("Cursor shape")
+ tooltip: qsTr("This property holds the cursor shape for this mouse area.")
+ }
+
+ SecondColumnLayout {
+ ComboBox {
+ backendValue: backendValues.cursorShape
+ model: ["ArrowCursor", "UpArrowCursor", "CrossCursor", "WaitCursor",
+ "IBeamCursor", "SizeVerCursor", "SizeHorCursor", "SizeBDiagCursor",
+ "SizeFDiagCursor", "SizeAllCursor", "BlankCursor", "SplitVCursor",
+ "SplitHCursor", "PointingHandCursor", "ForbiddenCursor", "WhatsThisCursor",
+ "BusyCursor", "OpenHandCursor", "ClosedHandCursor", "DragCopyCursor",
+ "DragMoveCursor", "DragLinkCursor"]
+ Layout.fillWidth: true
+ scope: "Qt"
+ }
+ ExpandingSpacer {
+ }
+ }
+
+ Label {
+ text: qsTr("Prevent stealing")
+ tooltip: qsTr("This property controls whether the mouse events may be stolen from this MouseArea.")
+ }
+
+ SecondColumnLayout {
+ CheckBox {
+ Layout.fillWidth: true
+ backendValue: backendValues.preventStealing
+ text: backendValues.preventStealing.valueToString
+ }
+
+ ExpandingSpacer {
+ }
+ }
+
+ Label {
+ text: qsTr("Propagate composed events")
+ tooltip: qsTr("This property controls whether composed mouse events will automatically propagate to other MouseAreas.")
+ }
+
+ SecondColumnLayout {
+ CheckBox {
+ Layout.fillWidth: true
+ backendValue: backendValues.propagateComposedEvents
+ text: backendValues.propagateComposedEvents.valueToString
+ }
+
+ ExpandingSpacer {
+ }
+ }
+ }
+ }
+
+ Section {
+ anchors.left: parent.left
+ anchors.right: parent.right
+ caption: qsTr("Drag")
+
+ SectionLayout {
+ Label {
+ text: qsTr("Target")
+ tooltip: qsTr("Sets the id of the item to drag.")
+ }
+ SecondColumnLayout {
+ ItemFilterComboBox {
+ typeFilter: "QtQuick.QtObject"
+ validator: RegExpValidator { regExp: /(^$|^[a-z_]\w*)/ }
+ backendValue: backendValues.drag_target
+ Layout.fillWidth: true
+ }
+
+ ExpandingSpacer {
+ }
+ }
+
+ Label {
+ text: qsTr("Axis")
+ tooltip: qsTr("Specifies whether dragging can be done horizontally, vertically, or both.")
+ }
+ SecondColumnLayout {
+ ComboBox {
+ scope: "Drag"
+ model: ["XAxis", "YAxis", "XAndYAxis"]
+ backendValue: backendValues.drag_axis
+ Layout.fillWidth: true
+ }
+
+ ExpandingSpacer {
+ }
+ }
+
+ Label {
+ text: qsTr("Filter children")
+ tooltip: qsTr("Specifies whether a drag overrides descendant MouseAreas.")
+ }
+
+ SecondColumnLayout {
+ CheckBox {
+ Layout.fillWidth: true
+ backendValue: backendValues.drag_filterChildren
+ text: backendValues.drag_filterChildren.valueToString
+ }
+
+ ExpandingSpacer {
+ }
+ }
+
+ Label {
+ text: qsTr("Threshold")
+ tooltip: qsTr("Determines the threshold in pixels of when the drag operation should start.")
+ }
+
+ SecondColumnLayout {
+ SpinBox {
+ backendValue: backendValues.drag_threshold
+ minimumValue: 0
+ maximumValue: 5000
+ decimals: 0
+ }
+
+ ExpandingSpacer {
+ }
+ }
+
+ Label {
+ text: qsTr("Smoothed")
+ tooltip: qsTr("If set to true, the target will be moved only after the drag operation has started.\n"
+ + "If set to false, the target will be moved straight to the current mouse position.")
+ }
+
+ SecondColumnLayout {
+ CheckBox {
+ Layout.fillWidth: true
+ backendValue: backendValues.drag_smoothed
+ text: backendValues.drag_smoothed.valueToString
+ }
+
+ ExpandingSpacer {
+ }
+ }
}
}
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/TextInputSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/TextInputSection.qml
index cfd972b085..5c0e84d039 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/TextInputSection.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/TextInputSection.qml
@@ -114,6 +114,19 @@ Section {
}
Label {
+ visible: textInputSection.isTextInput
+ text: qsTr("Maximum length")
+ tooltip: qsTr("Sets the maximum permitted length of the text in the TextInput.")
+ }
+ SpinBox {
+ visible: textInputSection.isTextInput
+ Layout.fillWidth: true
+ backendValue: backendValues.maximumLength
+ minimumValue: 0
+ maximumValue: 32767
+ }
+
+ Label {
text: qsTr("Flags")
Layout.alignment: Qt.AlignTop
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FlickableSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FlickableSection.qml
index 2b97df0646..11f46d29c5 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FlickableSection.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FlickableSection.qml
@@ -47,7 +47,7 @@ Section {
SecondColumnLayout {
ComboBox {
backendValue: backendValues.flickableDirection
- model: ["AutoFlickDirection", "HorizontalFlick", "VerticalFlick", "HorizontalAndVerticalFlick"]
+ model: ["AutoFlickDirection", "AutoFlickIfNeeded", "HorizontalFlick", "VerticalFlick", "HorizontalAndVerticalFlick"]
Layout.fillWidth: true
scope: "Flickable"
}
@@ -63,7 +63,7 @@ Section {
SecondColumnLayout {
ComboBox {
backendValue: backendValues.boundsBehavior
- model: ["StopAtBounds", "DragOverBounds", "DragAndOvershootBounds"]
+ model: ["StopAtBounds", "DragOverBounds", "OvershootBounds", "DragAndOvershootBounds"]
Layout.fillWidth: true
scope: "Flickable"
}
@@ -167,6 +167,23 @@ Section {
}
Label {
+ text: qsTr("Synchronous drag")
+ tooltip: qsTr("If set to true, then when the mouse or touchpoint moves far enough to begin dragging\n"
+ + "the content, the content will jump, such that the content pixel which was under the\n"
+ + "cursor or touchpoint when pressed remains under that point.")
+ }
+
+ SecondColumnLayout {
+ CheckBox {
+ Layout.fillWidth: true
+ backendValue: backendValues.synchronousDrag
+ text: backendValues.synchronousDrag.valueToString
+ }
+ ExpandingSpacer {
+ }
+ }
+
+ Label {
text: qsTr("Content size")
}
@@ -247,6 +264,45 @@ Section {
}
Label {
+ text: qsTr("Origin")
+ }
+
+ SecondColumnLayout {
+ Label {
+ text: "X"
+ width: root.labelWidth
+ }
+
+ SpinBox {
+ backendValue: backendValues.originX
+ minimumValue: -8000
+ maximumValue: 8000
+ implicitWidth: root.spinBoxWidth
+ Layout.fillWidth: true
+ }
+
+ Item {
+ width: 4
+ height: 4
+ }
+
+ Label {
+ text: "Y"
+ width: root.labelWidth
+ }
+
+ SpinBox {
+ backendValue: backendValues.originY
+ minimumValue: -8000
+ maximumValue: 8000
+ implicitWidth: root.spinBoxWidth
+ Layout.fillWidth: true
+ }
+ ExpandingSpacer {
+ }
+ }
+
+ Label {
text: qsTr("Margins")
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontSection.qml
index a97923a032..94a43424da 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontSection.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontSection.qml
@@ -68,9 +68,12 @@ Section {
text: qsTr("Font")
}
FontComboBox {
+ id: fontComboBox
backendValue: fontSection.fontFamily
Layout.fillWidth: true
width: 160
+ property string familyName: backendValue.value
+ onFamilyNameChanged: print(styleNamesForFamily(familyName))
}
Label {
@@ -151,6 +154,7 @@ Section {
italic: fontSection.italicStyle
underline: fontSection.underlineStyle
strikeout: fontSection.strikeoutStyle
+ enabled: !styleComboBox.styleSet
}
Label {
@@ -175,6 +179,21 @@ Section {
backendValue: getBackendValue("weight")
model: ["Normal", "Light", "ExtraLight", "Thin", "Medium", "DemiBold", "Bold", "ExtraBold", "Black"]
scope: "Font"
+ enabled: !styleComboBox.styleSet
+ }
+
+ Label {
+ text: qsTr("Style name")
+ toolTip: qsTr("Sets the font's style.")
+ }
+
+ ComboBox {
+ id: styleComboBox
+ property bool styleSet: backendValue.isInModel
+ Layout.fillWidth: true
+ backendValue: getBackendValue("styleName")
+ model: styleNamesForFamily(fontComboBox.familyName)
+ useString: true
}
Label {
@@ -257,5 +276,17 @@ Section {
"Latin script,\n it is merely a cosmetic feature. Setting the preferShaping property to false will disable all such features\nwhen they are not required, which will improve performance in most cases.")
}
}
+
+ Label {
+ text: qsTr("Hinting preference")
+ toolTip: qsTr("Sets the preferred hinting on the text.")
+ }
+
+ ComboBox {
+ Layout.fillWidth: true
+ backendValue: getBackendValue("hintingPreference")
+ model: ["PreferDefaultHinting", "PreferNoHinting", "PreferVerticalHinting", "PreferFullHinting"]
+ scope: "Font"
+ }
}
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/StandardTextSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/StandardTextSection.qml
index 6ecc8d525c..6c5e6fde86 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/StandardTextSection.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/StandardTextSection.qml
@@ -61,7 +61,7 @@ Section {
Layout.fillWidth: true
backendValue: backendValues.wrapMode
scope: "Text"
- model: ["NoWrap", "WordWrap", "WrapAnywhere", "WrapAtWordBoundaryOrAnywhere"]
+ model: ["NoWrap", "WordWrap", "WrapAnywhere", "Wrap"]
}
Label {
@@ -78,6 +78,21 @@ Section {
}
Label {
+ visible: showElide
+ text: qsTr("Maximum line count")
+ tooltip: qsTr("Limits the number of lines that the text item will show.")
+ }
+
+ SpinBox {
+ visible: showElide
+ Layout.fillWidth: true
+ backendValue: backendValues.maximumLineCount
+ minimumValue: 0
+ maximumValue: 10000
+ decimals: 0
+ }
+
+ Label {
text: qsTr("Alignment")
}
@@ -124,6 +139,7 @@ Section {
toolTip: qsTr("Specifies how the font size of the displayed text is determined.")
}
ComboBox {
+ id: fontSizeMode
visible: showFontSizeMode
scope: "Text"
model: ["FixedSize", "HorizontalFit", "VerticalFit", "Fit"]
@@ -131,6 +147,48 @@ Section {
Layout.fillWidth: true
}
+ Label {
+ visible: showFontSizeMode
+ text: qsTr("Minimum size")
+ }
+ SecondColumnLayout {
+ visible: showFontSizeMode
+
+ SpinBox {
+ enabled: fontSizeMode.currentIndex !== 0
+ minimumValue: 0
+ maximumValue: 500
+ decimals: 0
+ backendValue: backendValues.minimumPixelSize
+ Layout.fillWidth: true
+ Layout.minimumWidth: 60
+ }
+ Label {
+ text: qsTr("Pixel")
+ tooltip: qsTr("Specifies the minimum font pixel size of scaled text.")
+ width: 42
+ }
+
+ Item {
+ width: 4
+ height: 4
+ }
+
+ SpinBox {
+ enabled: fontSizeMode.currentIndex !== 0
+ minimumValue: 0
+ maximumValue: 500
+ decimals: 0
+ backendValue: backendValues.minimumPointSize
+ Layout.fillWidth: true
+ Layout.minimumWidth: 60
+ }
+ Label {
+ text: qsTr("Point")
+ tooltip: qsTr("Specifies the minimum font point size of scaled text.")
+ width: 42
+ }
+ }
Label {
visible: showLineHeight
@@ -148,5 +206,17 @@ Section {
stepSize: 0.1
}
+ Label {
+ visible: showLineHeight
+ text: qsTr("Line height mode")
+ toolTip: qsTr("Determines how the line height is specified.")
+ }
+ ComboBox {
+ visible: showLineHeight
+ scope: "Text"
+ model: ["ProportionalHeight", "FixedHeight"]
+ backendValue: backendValues.lineHeightMode
+ Layout.fillWidth: true
+ }
}
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Constants.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Constants.qml
index 3d692af671..74edf9ccee 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Constants.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Constants.qml
@@ -26,98 +26,4 @@
pragma Singleton
import QtQuick 2.10
-QtObject {
- readonly property int width: 1920
- readonly property int height: 1080
- readonly property FontLoader mySystemFont: FontLoader {
- name: "Arial"
- }
- readonly property FontLoader controlIcons: FontLoader {
- source: "icons.ttf"
- }
-
- readonly property string actionIcon: "\u0021"
- readonly property string actionIconBinding: "\u0022"
- readonly property string addColumnAfter: "\u0023"
- readonly property string addColumnBefore: "\u0024"
- readonly property string addFile: "\u0025"
- readonly property string addRowAfter: "\u0026"
- readonly property string addRowBefore: "\u0027"
- readonly property string addTable: "\u0028"
- readonly property string alignBottom: "\u0029"
- readonly property string alignCenterHorizontal: "\u002A"
- readonly property string alignCenterVertical: "\u002B"
- readonly property string alignLeft: "\u002C"
- readonly property string alignRight: "\u002D"
- readonly property string alignTo: "\u002E"
- readonly property string alignTop: "\u002F"
- readonly property string anchorBaseline: "\u0030"
- readonly property string anchorBottom: "\u0031"
- readonly property string anchorFill: "\u0032"
- readonly property string anchorLeft: "\u0033"
- readonly property string anchorRight: "\u0034"
- readonly property string anchorTop: "\u0035"
- readonly property string annotationBubble: "\u0036"
- readonly property string annotationDecal: "\u0037"
- readonly property string centerHorizontal: "\u0038"
- readonly property string centerVertical: "\u0039"
- readonly property string closeCross: "\u003A"
- readonly property string deleteColumn: "\u003B"
- readonly property string deleteRow: "\u003C"
- readonly property string deleteTable: "\u003D"
- readonly property string distributeBottom: "\u003E"
- readonly property string distributeCenterHorizontal: "\u003F"
- readonly property string distributeCenterVertical: "\u0040"
- readonly property string distributeLeft: "\u0041"
- readonly property string distributeOriginBottomRight: "\u0042"
- readonly property string distributeOriginCenter: "\u0043"
- readonly property string distributeOriginNone: "\u0044"
- readonly property string distributeOriginTopLeft: "\u0045"
- readonly property string distributeRight: "\u0046"
- readonly property string distributeSpacingHorizontal: "\u0047"
- readonly property string distributeSpacingVertical: "\u0048"
- readonly property string distributeTop: "\u0049"
- readonly property string edit: "\u004A"
- readonly property string fontStyleBold: "\u004B"
- readonly property string fontStyleItalic: "\u004C"
- readonly property string fontStyleStrikethrough: "\u004D"
- readonly property string fontStyleUnderline: "\u004E"
- readonly property string mergeCells: "\u004F"
- readonly property string redo: "\u0050"
- readonly property string splitColumns: "\u0051"
- readonly property string splitRows: "\u0052"
- readonly property string testIcon: "\u0053"
- readonly property string textAlignBottom: "\u0054"
- readonly property string textAlignCenter: "\u0055"
- readonly property string textAlignLeft: "\u0056"
- readonly property string textAlignMiddle: "\u0057"
- readonly property string textAlignRight: "\u0058"
- readonly property string textAlignTop: "\u0059"
- readonly property string textBulletList: "\u005A"
- readonly property string textFullJustification: "\u005B"
- readonly property string textNumberedList: "\u005C"
- readonly property string tickIcon: "\u005D"
- readonly property string triState: "\u005E"
- readonly property string undo: "\u005F"
- readonly property string upDownIcon: "\u0060"
- readonly property string upDownSquare2: "\u0061"
-
- readonly property font iconFont: Qt.font({
- "family": controlIcons.name,
- "pixelSize": 12
- })
-
- readonly property font font: Qt.font({
- "family": mySystemFont.name,
- "pointSize": Qt.application.font.pixelSize
- })
-
- readonly property font largeFont: Qt.font({
- "family": mySystemFont.name,
- "pointSize": Qt.application.font.pixelSize * 1.6
- })
-
- readonly property color backgroundColor: "#c2c2c2"
-
- readonly property bool showActionIndicatorBackground: false
-}
+InternalConstants {}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml
new file mode 100644
index 0000000000..4d45032eae
--- /dev/null
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** 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.
+**
+****************************************************************************/
+
+import QtQuick 2.10
+
+QtObject {
+ readonly property int width: 1920
+ readonly property int height: 1080
+ readonly property FontLoader mySystemFont: FontLoader {
+ name: "Arial"
+ }
+ readonly property FontLoader controlIcons: FontLoader {
+ source: "icons.ttf"
+ }
+
+ objectName: "internalConstantsObject"
+
+ readonly property string actionIcon: "\u0021"
+ readonly property string actionIconBinding: "\u0022"
+ readonly property string addColumnAfter: "\u0023"
+ readonly property string addColumnBefore: "\u0024"
+ readonly property string addFile: "\u0025"
+ readonly property string addRowAfter: "\u0026"
+ readonly property string addRowBefore: "\u0027"
+ readonly property string addTable: "\u0028"
+ readonly property string adsClose: "\u0029"
+ readonly property string adsDetach: "\u002A"
+ readonly property string adsDropDown: "\u002B"
+ readonly property string alignBottom: "\u002C"
+ readonly property string alignCenterHorizontal: "\u002D"
+ readonly property string alignCenterVertical: "\u002E"
+ readonly property string alignLeft: "\u002F"
+ readonly property string alignRight: "\u0030"
+ readonly property string alignTo: "\u0031"
+ readonly property string alignTop: "\u0032"
+ readonly property string anchorBaseline: "\u0033"
+ readonly property string anchorBottom: "\u0034"
+ readonly property string anchorFill: "\u0035"
+ readonly property string anchorLeft: "\u0036"
+ readonly property string anchorRight: "\u0037"
+ readonly property string anchorTop: "\u0038"
+ readonly property string annotationBubble: "\u0039"
+ readonly property string annotationDecal: "\u003A"
+ readonly property string centerHorizontal: "\u003B"
+ readonly property string centerVertical: "\u003C"
+ readonly property string closeCross: "\u003D"
+ readonly property string decisionNode: "\u003E"
+ readonly property string deleteColumn: "\u003F"
+ readonly property string deleteRow: "\u0040"
+ readonly property string deleteTable: "\u0041"
+ readonly property string detach: "\u0042"
+ readonly property string distributeBottom: "\u0043"
+ readonly property string distributeCenterHorizontal: "\u0044"
+ readonly property string distributeCenterVertical: "\u0045"
+ readonly property string distributeLeft: "\u0046"
+ readonly property string distributeOriginBottomRight: "\u0047"
+ readonly property string distributeOriginCenter: "\u0048"
+ readonly property string distributeOriginNone: "\u0049"
+ readonly property string distributeOriginTopLeft: "\u004A"
+ readonly property string distributeRight: "\u004B"
+ readonly property string distributeSpacingHorizontal: "\u004C"
+ readonly property string distributeSpacingVertical: "\u004D"
+ readonly property string distributeTop: "\u004E"
+ readonly property string edit: "\u004F"
+ readonly property string fontStyleBold: "\u0050"
+ readonly property string fontStyleItalic: "\u0051"
+ readonly property string fontStyleStrikethrough: "\u0052"
+ readonly property string fontStyleUnderline: "\u0053"
+ readonly property string mergeCells: "\u0054"
+ readonly property string redo: "\u0055"
+ readonly property string splitColumns: "\u0056"
+ readonly property string splitRows: "\u0057"
+ readonly property string startNode: "\u0058"
+ readonly property string testIcon: "\u0059"
+ readonly property string textAlignBottom: "\u005A"
+ readonly property string textAlignCenter: "\u005B"
+ readonly property string textAlignLeft: "\u005C"
+ readonly property string textAlignMiddle: "\u005D"
+ readonly property string textAlignRight: "\u005E"
+ readonly property string textAlignTop: "\u005F"
+ readonly property string textBulletList: "\u0060"
+ readonly property string textFullJustification: "\u0061"
+ readonly property string textNumberedList: "\u0062"
+ readonly property string tickIcon: "\u0063"
+ readonly property string triState: "\u0064"
+ readonly property string undo: "\u0065"
+ readonly property string upDownIcon: "\u0066"
+ readonly property string upDownSquare2: "\u0067"
+ readonly property string wildcard: "\u0068"
+
+ readonly property font iconFont: Qt.font({
+ "family": controlIcons.name,
+ "pixelSize": 12
+ })
+
+ readonly property font font: Qt.font({
+ "family": mySystemFont.name,
+ "pointSize": Qt.application.font.pixelSize
+ })
+
+ readonly property font largeFont: Qt.font({
+ "family": mySystemFont.name,
+ "pointSize": Qt.application.font.pixelSize * 1.6
+ })
+
+ readonly property color backgroundColor: "#c2c2c2"
+
+ readonly property bool showActionIndicatorBackground: false
+}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf
index d65b065195..9e3ed42406 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf
Binary files differ
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/qmldir b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/qmldir
index b768fe63a2..4f689f9f63 100755
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/qmldir
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/qmldir
@@ -1,2 +1,4 @@
singleton Values 1.0 Values.qml
singleton Constants 1.0 Constants.qml
+InternalConstants 1.0 InternalConstants.qml
+
diff --git a/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesDelegate.qml b/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesDelegate.qml
index 1d1d65bed7..0e94897d5a 100644
--- a/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesDelegate.qml
+++ b/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesDelegate.qml
@@ -220,6 +220,24 @@ Rectangle {
}
}
+ Text {
+ id: stateDefaultIndicator
+ anchors.left: whenButton.left
+ anchors.leftMargin: 0
+ anchors.right: removeStateButton.left
+ anchors.rightMargin: 4
+ anchors.bottom: parent.bottom
+ anchors.bottomMargin: 4
+
+ color: Theme.color(Theme.PanelTextColorLight)
+ font.italic: true
+ font.pixelSize: Theme.smallFontPixelSize()
+
+ visible: expanded && (isDefaultState || (isBaseState && !modelHasDefaultState))
+
+ text: ("* " + qsTr("Default"))
+ }
+
BindingEditor {
property string newWhenCondition
diff --git a/share/qtcreator/templates/wizards/autotest/files/catch2_tst.cpp b/share/qtcreator/templates/wizards/autotest/files/catch2_tst.cpp
new file mode 100644
index 0000000000..604b339e1c
--- /dev/null
+++ b/share/qtcreator/templates/wizards/autotest/files/catch2_tst.cpp
@@ -0,0 +1,6 @@
+#include <catch2/catch.hpp>
+
+TEST_CASE("My first test with Catch2", "[fancy]")
+{
+ REQUIRE(0 == 0);
+}
diff --git a/share/qtcreator/templates/wizards/autotest/files/tst.pro b/share/qtcreator/templates/wizards/autotest/files/tst.pro
index 1d59f9c05f..a92e58f06e 100644
--- a/share/qtcreator/templates/wizards/autotest/files/tst.pro
+++ b/share/qtcreator/templates/wizards/autotest/files/tst.pro
@@ -64,3 +64,30 @@ isEmpty(BOOST_INCLUDE_DIR): {
SOURCES += \\
%{MainCppName}
@endif
+@if "%{TestFrameWork}" == "Catch2"
+TEMPLATE = app
+@if "%{Catch2NeedsQt}" == "true"
+QT += gui
+@else
+CONFIG -= qt
+CONFIG -= app_bundle
+CONFIG += console
+@endif
+
+CONFIG += c++11
+
+isEmpty(CATCH_INCLUDE_DIR): CATCH_INCLUDE_DIR=$$(CATCH_INCLUDE_DIR)
+@if "%{CatchIncDir}" != ""
+# set by Qt Creator wizard
+isEmpty(CATCH_INCLUDE_DIR): CATCH_INCLUDE_DIR="%{CatchIncDir}"
+@endif
+!isEmpty(CATCH_INCLUDE_DIR): INCLUDEPATH *= $${CATCH_INCLUDE_DIR}
+
+isEmpty(CATCH_INCLUDE_DIR): {
+ message("CATCH_INCLUDE_DIR is not set, assuming Catch2 can be found automatically in your system")
+}
+
+SOURCES += \
+ main.cpp \
+ %{TestCaseFileWithCppSuffix}
+@endif
diff --git a/share/qtcreator/templates/wizards/autotest/files/tst.qbs b/share/qtcreator/templates/wizards/autotest/files/tst.qbs
index e66605f0a5..a33cecd599 100644
--- a/share/qtcreator/templates/wizards/autotest/files/tst.qbs
+++ b/share/qtcreator/templates/wizards/autotest/files/tst.qbs
@@ -7,6 +7,10 @@ import "googlecommon.js" as googleCommon
import qbs.Environment
import qbs.File
@endif
+@if "%{TestFrameWork}" == "Catch2"
+import qbs.Environment
+import qbs.File
+@endif
CppApplication {
@if "%{TestFrameWork}" == "QtTest"
@@ -104,4 +108,35 @@ CppApplication {
files: [ "%{MainCppName}" ]
@endif
+@if "%{TestFrameWork}" == "Catch2"
+ type: "application"
+
+@if "%{Catch2NeedsQt}" == "true"
+ Depends { name: "Qt.gui" }
+@endif
+
+ property string catchIncDir: {
+ if (typeof Environment.getEnv("CATCH_INCLUDE_DIR") !== 'undefined')
+ return Environment.getEnv("CATCH_INCLUDE_DIR");
+ return "%{CatchIncDir}"; // set by Qt Creator wizard
+ }
+
+ Properties {
+ condition: catchIncDir && File.exists(catchIncDir)
+ cpp.includePaths: [catchIncDir];
+ }
+
+ condition: {
+ if (!catchIncDir)
+ console.log("CATCH_INCLUDE_DIR is not set, assuming Catch2 can be "
+ + "found automatically in your system");
+ return true;
+ }
+
+ files: [
+ "%{MainCppName}",
+ "%{TestCaseFileWithCppSuffix}",
+ ]
+@endif
+
}
diff --git a/share/qtcreator/templates/wizards/autotest/files/tst.txt b/share/qtcreator/templates/wizards/autotest/files/tst.txt
index 93e51d3695..569bf4d01d 100644
--- a/share/qtcreator/templates/wizards/autotest/files/tst.txt
+++ b/share/qtcreator/templates/wizards/autotest/files/tst.txt
@@ -116,3 +116,27 @@ elseif (EXISTS ${BOOST_INCLUDE_DIR})
include_directories(${BOOST_INCLUDE_DIR})
endif ()
@endif
+@if "%{TestFrameWork}" == "Catch2"
+SET(CMAKE_CXX_STANDARD 11)
+
+@if "%{Catch2NeedsQt}" == "true"
+find_package(Qt5Gui REQUIRED)
+@endif
+
+add_executable(${PROJECT_NAME} %{TestCaseFileWithCppSuffix} main.cpp)
+
+@if "%{Catch2NeedsQt}" == "true"
+target_link_libraries(%{TestCaseName} PRIVATE Qt5::Gui)
+@endif
+
+if (DEFINED ENV{CATCH_INCLUDE_DIR})
+ set(CATCH_INCLUDE_DIR $ENV{CATCH_INCLUDE_DIR})
+else ()
+ set(CATCH_INCLUDE_DIR "%{CatchIncDir}") # set by Qt Creator wizard
+endif ()
+if (CATCH_INCLUDE_DIR STREQUAL "")
+ message("CATCH_INCLUDE_DIR is not set, assuming Catch2 can be found automatically in your system")
+elseif (EXISTS ${CATCH_INCLUDE_DIR})
+ include_directories(${CATCH_INCLUDE_DIR})
+endif ()
+@endif
diff --git a/share/qtcreator/templates/wizards/autotest/files/tst_main.cpp b/share/qtcreator/templates/wizards/autotest/files/tst_main.cpp
index 923fad9f9b..e4f33d2716 100644
--- a/share/qtcreator/templates/wizards/autotest/files/tst_main.cpp
+++ b/share/qtcreator/templates/wizards/autotest/files/tst_main.cpp
@@ -24,3 +24,20 @@ BOOST_AUTO_TEST_CASE( %{TestCaseName} )
BOOST_TEST( true /* test assertion */ );
}
@endif
+@if "%{TestFrameWork}" == "Catch2"
+@if "%{Catch2NeedsQt}" == "true"
+#define CATCH_CONFIG_RUNNER
+@else
+#define CATCH_CONFIG_MAIN
+@endif
+#include <catch2/catch.hpp>
+@if "%{Catch2NeedsQt}" == "true"
+#include <QtGui/QGuiApplication>
+
+int main(int argc, char** argv)
+{
+ QGuiApplication app(argc, argv);
+ return Catch::Session().run(argc, argv);
+}
+@endif
+@endif
diff --git a/share/qtcreator/templates/wizards/autotest/wizard.json b/share/qtcreator/templates/wizards/autotest/wizard.json
index e35f9cd980..1ba0101a09 100644
--- a/share/qtcreator/templates/wizards/autotest/wizard.json
+++ b/share/qtcreator/templates/wizards/autotest/wizard.json
@@ -91,6 +91,10 @@
{
"trKey": "Boost Test",
"value": "BoostTest"
+ },
+ {
+ "trKey": "Catch2",
+ "value": "Catch2"
}
]
@@ -168,6 +172,25 @@
}
},
{
+ "name": "CatchIncDir",
+ "trDisplayName": "Catch2 include directory (optional):",
+ "visible": "%{JS: value('TestFrameWork') === 'Catch2'}",
+ "mandatory": false,
+ "type": "PathChooser",
+ "data": {
+ "kind": "existingDirectory"
+ }
+ },
+ {
+ "name": "Catch2NeedsQt",
+ "trDisplayName": "Use Qt libraries",
+ "visible": "%{JS: '%{TestFrameWork}' === 'Catch2'}",
+ "type": "CheckBox",
+ "data": {
+ "checked": true
+ }
+ },
+ {
"name": "BuildSystem",
"trDisplayName": "Build system:",
"type": "ComboBox",
@@ -267,7 +290,7 @@
{
"source": "files/tst_main.cpp",
"target": "%{MainCppName}",
- "condition": "%{JS: ['GTest', 'QtQuickTest', 'BoostTest'].indexOf(value('TestFrameWork')) >= 0}",
+ "condition": "%{JS: ['GTest', 'QtQuickTest', 'BoostTest', 'Catch2'].indexOf(value('TestFrameWork')) >= 0}",
"openInEditor": true
},
{
@@ -277,6 +300,12 @@
"openInEditor": true
},
{
+ "source": "files/catch2_tst.cpp",
+ "target": "%{TestCaseFileWithCppSuffix}",
+ "condition": "%{JS: '%{TestFrameWork}' === 'Catch2'}",
+ "openInEditor": true
+ },
+ {
"source": "../projects/git.ignore",
"target": ".gitignore",
"condition": "%{JS: ( %{IsTopLevelProject} && value('VersionControl') === 'G.Git' )}"
diff --git a/share/qtcreator/templates/wizards/classes/cpp/file.h b/share/qtcreator/templates/wizards/classes/cpp/file.h
index aa2fa7faaf..67e4dfd4d1 100644
--- a/share/qtcreator/templates/wizards/classes/cpp/file.h
+++ b/share/qtcreator/templates/wizards/classes/cpp/file.h
@@ -6,6 +6,7 @@
#define %{GUARD}
@endif
+%{JS: Cpp.includeStatement('%{Base}', Util.preferredSuffix('text/x-c++hdr'), ['QObject', 'QWidget', 'QMainWindow', 'QQuickItem', 'QSharedData'], '%{TargetPath}')}\
%{JS: QtSupport.qtIncludes([ ( '%{IncludeQObject}' ) ? 'QtCore/%{IncludeQObject}' : '',
( '%{IncludeQWidget}' ) ? 'QtGui/%{IncludeQWidget}' : '',
( '%{IncludeQMainWindow}' ) ? 'QtGui/%{IncludeQMainWindow}' : '',
diff --git a/share/qtcreator/templates/wizards/classes/cpp/wizard.json b/share/qtcreator/templates/wizards/classes/cpp/wizard.json
index bb8a1f9fef..117139ed82 100644
--- a/share/qtcreator/templates/wizards/classes/cpp/wizard.json
+++ b/share/qtcreator/templates/wizards/classes/cpp/wizard.json
@@ -5,7 +5,7 @@
"category": "O.C++",
"trDescription": "Creates a C++ header and a source file for a new class that you can add to a C++ project.",
"trDisplayName": "C++ Class",
- "trDisplayCategory": "C++",
+ "trDisplayCategory": "C/C++",
"iconText": "h/cpp",
"enabled": "%{JS: value('Plugins').indexOf('CppEditor') >= 0}",
diff --git a/share/qtcreator/templates/wizards/files/cppheader/wizard.json b/share/qtcreator/templates/wizards/files/cppheader/wizard.json
index efb0ea8119..36956636a3 100644
--- a/share/qtcreator/templates/wizards/files/cppheader/wizard.json
+++ b/share/qtcreator/templates/wizards/files/cppheader/wizard.json
@@ -3,13 +3,16 @@
"supportedProjectTypes": [ ],
"id": "C.Header",
"category": "O.C++",
- "trDescription": "Creates a C++ header file that you can add to a C++ project.",
- "trDisplayName": "C++ Header File",
- "trDisplayCategory": "C++",
+ "trDescription": "Creates a header file that you can add to a C/C++ project.",
+ "trDisplayName": "C/C++ Header File",
+ "trDisplayCategory": "C/C++",
"iconText": "h",
"enabled": "%{JS: value('Plugins').indexOf('CppEditor') >= 0}",
- "options": { "key": "FileName", "value": "%{JS: Util.fileName(value('TargetPath'), Util.preferredSuffix('text/x-c++hdr'))}" },
+ "options": [
+ { "key": "DefaultSuffix", "value": "%{JS: Util.preferredSuffix('text/x-c++hdr')}" },
+ { "key": "FileName", "value": "%{JS: Util.fileName(value('TargetPath'), value('DefaultSuffix'))}" }
+ ],
"pages" :
[
diff --git a/share/qtcreator/templates/wizards/files/cppsource/wizard.json b/share/qtcreator/templates/wizards/files/cppsource/wizard.json
index 775cd892ab..c75600ff8a 100644
--- a/share/qtcreator/templates/wizards/files/cppsource/wizard.json
+++ b/share/qtcreator/templates/wizards/files/cppsource/wizard.json
@@ -3,13 +3,16 @@
"supportedProjectTypes": [ ],
"id": "B.Source",
"category": "O.C++",
- "trDescription": "Creates a C++ source file that you can add to a C++ project.",
- "trDisplayName": "C++ Source File",
- "trDisplayCategory": "C++",
+ "trDescription": "Creates a source file that you can add to a C/C++ project.",
+ "trDisplayName": "C/C++ Source File",
+ "trDisplayCategory": "C/C++",
"iconText": "cpp",
"enabled": "%{JS: value('Plugins').indexOf('CppEditor') >= 0}",
- "options": { "key": "FileName", "value": "%{JS: Util.fileName(value('TargetPath'), Util.preferredSuffix('text/x-c++src'))}" },
+ "options": [
+ { "key": "FileName", "value": "%{JS: Util.fileName(value('TargetPath'), value('DefaultSuffix'))}" },
+ { "key": "DefaultSuffix", "value": "%{JS: Util.preferredSuffix('text/x-c++src')}" }
+ ],
"pages" :
[
diff --git a/share/qtcreator/templates/wizards/files/glsl/gl/fragment/wizard.json b/share/qtcreator/templates/wizards/files/glsl/gl/fragment/wizard.json
index 900e4f8f68..28a018945b 100644
--- a/share/qtcreator/templates/wizards/files/glsl/gl/fragment/wizard.json
+++ b/share/qtcreator/templates/wizards/files/glsl/gl/fragment/wizard.json
@@ -10,6 +10,8 @@
"platformIndependent": true,
"enabled": "%{JS: value('Plugins').indexOf('GLSLEditor') >= 0}",
+ "options": { "key": "DefaultSuffix", "value": "%{JS: Util.preferredSuffix('text/x-glsl-frag')}" },
+
"pages" :
[
{
@@ -30,7 +32,7 @@
"data":
{
"source": "file.frag",
- "target": "%{JS: Util.fileName(value('TargetPath'), Util.preferredSuffix('text/x-glsl-frag'))}",
+ "target": "%{JS: Util.fileName(value('TargetPath'), value('DefaultSuffix'))}",
"openInEditor": true
}
}
diff --git a/share/qtcreator/templates/wizards/files/glsl/gl/vertex/wizard.json b/share/qtcreator/templates/wizards/files/glsl/gl/vertex/wizard.json
index 38d2df2947..48f1f68afd 100644
--- a/share/qtcreator/templates/wizards/files/glsl/gl/vertex/wizard.json
+++ b/share/qtcreator/templates/wizards/files/glsl/gl/vertex/wizard.json
@@ -10,6 +10,8 @@
"platformIndependent": true,
"enabled": "%{JS: value('Plugins').indexOf('GLSLEditor') >= 0}",
+ "options": { "key": "DefaultSuffix", "value": "%{JS: Util.preferredSuffix('text/x-glsl-vert')}" },
+
"pages" :
[
{
@@ -30,7 +32,7 @@
"data":
{
"source": "file.vert",
- "target": "%{JS: Util.fileName(value('TargetPath'), Util.preferredSuffix('text/x-glsl-vert'))}",
+ "target": "%{JS: Util.fileName(value('TargetPath'), value('DefaultSuffix'))}",
"openInEditor": true
}
}
diff --git a/share/qtcreator/templates/wizards/files/glsl/gles/fragment/wizard.json b/share/qtcreator/templates/wizards/files/glsl/gles/fragment/wizard.json
index a993a3cfce..d636d0eb21 100644
--- a/share/qtcreator/templates/wizards/files/glsl/gles/fragment/wizard.json
+++ b/share/qtcreator/templates/wizards/files/glsl/gles/fragment/wizard.json
@@ -10,6 +10,8 @@
"platformIndependent": true,
"enabled": "%{JS: value('Plugins').indexOf('GLSLEditor') >= 0}",
+ "options": { "key": "DefaultSuffix", "value": "%{JS: Util.preferredSuffix('text/x-glsl-es-frag')}" },
+
"pages" :
[
{
@@ -30,7 +32,7 @@
"data":
{
"source": "file.fsh",
- "target": "%{JS: Util.fileName(value('TargetPath'), Util.preferredSuffix('text/x-glsl-es-frag'))}",
+ "target": "%{JS: Util.fileName(value('TargetPath'), value('DefaultSuffix'))}",
"openInEditor": true
}
}
diff --git a/share/qtcreator/templates/wizards/files/glsl/gles/vertex/wizard.json b/share/qtcreator/templates/wizards/files/glsl/gles/vertex/wizard.json
index 54231aadd5..83a042d91b 100644
--- a/share/qtcreator/templates/wizards/files/glsl/gles/vertex/wizard.json
+++ b/share/qtcreator/templates/wizards/files/glsl/gles/vertex/wizard.json
@@ -10,6 +10,8 @@
"platformIndependent": true,
"enabled": "%{JS: value('Plugins').indexOf('GLSLEditor') >= 0}",
+ "options": { "key": "DefaultSuffix", "value": "%{JS: Util.preferredSuffix('text/x-glsl-es-vert')}" },
+
"pages" :
[
{
@@ -30,7 +32,7 @@
"data":
{
"source": "file.vsh",
- "target": "%{JS: Util.fileName(value('TargetPath'), Util.preferredSuffix('text/x-glsl-es-vert'))}",
+ "target": "%{JS: Util.fileName(value('TargetPath'), value('DefaultSuffix'))}",
"openInEditor": true
}
}
diff --git a/share/qtcreator/templates/wizards/files/java/wizard.json b/share/qtcreator/templates/wizards/files/java/wizard.json
index 5a8fae5dc1..83087984fc 100644
--- a/share/qtcreator/templates/wizards/files/java/wizard.json
+++ b/share/qtcreator/templates/wizards/files/java/wizard.json
@@ -9,7 +9,10 @@
"iconText": "java",
"enabled": "%{JS: value('Plugins').indexOf('Android') >= 0}",
- "options": [ { "key": "ClassName", "value": "%{JS: value('FileName').charAt(0).toUpperCase() + value('FileName').substr(1).replace(/[.]java$/,'')}" } ],
+ "options": [
+ { "key": "ClassName", "value": "%{JS: value('FileName').charAt(0).toUpperCase() + value('FileName').substr(1).replace(/[.]java$/,'')}" },
+ { "key": "DefaultSuffix", "value": "%{JS: Util.preferredSuffix('text/x-java')}" }
+ ],
"pages" :
[
@@ -31,7 +34,7 @@
"data":
{
"source": "source.java",
- "target": "%{JS: Util.fileName(value('Path') + '/' + value('ClassName'), Util.preferredSuffix('text/x-java'))}",
+ "target": "%{JS: Util.fileName(value('Path') + '/' + value('ClassName'), value('DefaultSuffix'))}",
"openInEditor": true
}
}
diff --git a/share/qtcreator/templates/wizards/files/js/wizard.json b/share/qtcreator/templates/wizards/files/js/wizard.json
index d47721bb46..505ca57817 100644
--- a/share/qtcreator/templates/wizards/files/js/wizard.json
+++ b/share/qtcreator/templates/wizards/files/js/wizard.json
@@ -9,6 +9,8 @@
"iconText": "js",
"enabled": "%{JS: value('Plugins').indexOf('QmlJSEditor') >= 0}",
+ "options": { "key": "DefaultSuffix", "value": "%{JS: Util.preferredSuffix('application/javascript')}" },
+
"pages" :
[
{
@@ -47,7 +49,7 @@
"data":
{
"source": "file.js",
- "target": "%{JS: Util.fileName(value('TargetPath'), Util.preferredSuffix('application/javascript'))}",
+ "target": "%{JS: Util.fileName(value('TargetPath'), value('DefaultSuffix'))}",
"openInEditor": true
}
}
diff --git a/share/qtcreator/templates/wizards/files/nim/wizard.json b/share/qtcreator/templates/wizards/files/nim/wizard.json
index 723531ced5..1baf376aa4 100644
--- a/share/qtcreator/templates/wizards/files/nim/wizard.json
+++ b/share/qtcreator/templates/wizards/files/nim/wizard.json
@@ -9,6 +9,8 @@
"icon": "../../projects/nim/icon.png",
"enabled": "%{JS: value('Plugins').indexOf('Nim') >= 0}",
+ "options": { "key": "DefaultSuffix", "value": "nim" },
+
"pages" :
[
{
@@ -29,7 +31,7 @@
"data":
{
"source": "file.nim",
- "target": "%{JS: Util.fileName(value('TargetPath'), 'nim')}",
+ "target": "%{JS: Util.fileName(value('TargetPath'), value('DefaultSuffix'))}",
"openInEditor": true
}
}
diff --git a/share/qtcreator/templates/wizards/files/nimscript/wizard.json b/share/qtcreator/templates/wizards/files/nimscript/wizard.json
index 15f366773b..94012a7167 100644
--- a/share/qtcreator/templates/wizards/files/nimscript/wizard.json
+++ b/share/qtcreator/templates/wizards/files/nimscript/wizard.json
@@ -9,6 +9,8 @@
"icon": "../../projects/nim/icon.png",
"enabled": "%{JS: value('Plugins').indexOf('Nim') >= 0}",
+ "options": { "key": "DefaultSuffix", "value": "nims" },
+
"pages" :
[
{
@@ -29,7 +31,7 @@
"data":
{
"source": "file.nims",
- "target": "%{JS: Util.fileName(value('TargetPath'), 'nims')}",
+ "target": "%{JS: Util.fileName(value('TargetPath'), value('DefaultSuffix'))}",
"openInEditor": true
}
}
diff --git a/share/qtcreator/templates/wizards/files/python/wizard.json b/share/qtcreator/templates/wizards/files/python/wizard.json
index f3bff037b5..a01e32bf4a 100644
--- a/share/qtcreator/templates/wizards/files/python/wizard.json
+++ b/share/qtcreator/templates/wizards/files/python/wizard.json
@@ -9,6 +9,8 @@
"icon": "icon.png",
"enabled": "%{JS: value('Plugins').indexOf('Python') >= 0}",
+ "options": { "key": "DefaultSuffix", "value": "%{JS: Util.preferredSuffix('text/x-python')}" },
+
"pages" :
[
{
@@ -29,7 +31,7 @@
"data":
{
"source": "file.py",
- "target": "%{JS: Util.fileName(value('TargetPath'), Util.preferredSuffix('text/x-python'))}",
+ "target": "%{JS: Util.fileName(value('TargetPath'), value('DefaultSuffix'))}",
"openInEditor": true
}
}
diff --git a/share/qtcreator/templates/wizards/files/qrc/wizard.json b/share/qtcreator/templates/wizards/files/qrc/wizard.json
index 578eed58a1..fe8ea73d17 100644
--- a/share/qtcreator/templates/wizards/files/qrc/wizard.json
+++ b/share/qtcreator/templates/wizards/files/qrc/wizard.json
@@ -9,6 +9,8 @@
"iconText": "qrc",
"enabled": "%{JS: value('Plugins').indexOf('ResourceEditor') >= 0}",
+ "options": { "key": "DefaultSuffix", "value": "%{JS: Util.preferredSuffix('application/vnd.qt.xml.resource')}" },
+
"pages" :
[
{
@@ -29,7 +31,7 @@
"data":
{
"source": "file.qrc",
- "target": "%{JS: Util.fileName(value('TargetPath'), Util.preferredSuffix('application/vnd.qt.xml.resource'))}",
+ "target": "%{JS: Util.fileName(value('TargetPath'), value('DefaultSuffix'))}",
"openInEditor": true
}
}
diff --git a/share/qtcreator/templates/wizards/files/qtquick2/wizard.json b/share/qtcreator/templates/wizards/files/qtquick2/wizard.json
index ead52b1687..0fa070cf93 100644
--- a/share/qtcreator/templates/wizards/files/qtquick2/wizard.json
+++ b/share/qtcreator/templates/wizards/files/qtquick2/wizard.json
@@ -9,6 +9,8 @@
"iconText": "qml",
"enabled": "%{JS: value('Plugins').indexOf('QmlJSEditor') >= 0}",
+ "options": { "key": "DefaultSuffix", "value": "%{JS: Util.preferredSuffix('text/x-qml')}" },
+
"pages" :
[
{
@@ -29,7 +31,7 @@
"data":
{
"source": "file.qml.tpl",
- "target": "%{JS: Util.fileName(value('TargetPath'), Util.preferredSuffix('text/x-qml'))}",
+ "target": "%{JS: Util.fileName(value('TargetPath'), value('DefaultSuffix'))}",
"openInEditor": true
}
}
diff --git a/share/qtcreator/templates/wizards/files/scratch/wizard.json b/share/qtcreator/templates/wizards/files/scratch/wizard.json
index aa0efb0e10..7dcaf0ec23 100644
--- a/share/qtcreator/templates/wizards/files/scratch/wizard.json
+++ b/share/qtcreator/templates/wizards/files/scratch/wizard.json
@@ -21,7 +21,8 @@
"source": "file.txt",
"target": "%{TargetPath}",
"overwrite": true,
- "openInEditor": true
+ "openInEditor": true,
+ "temporary": true
}
}
]
diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/qtquickapplication/main.qml.tpl b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/qtquickapplication/main.qml.tpl
index 6f9e90d517..5d6951fb6f 100644
--- a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/qtquickapplication/main.qml.tpl
+++ b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/qtquickapplication/main.qml.tpl
@@ -2,8 +2,8 @@ import QtQuick %{QtQuickVersion}
import QtQuick.Window %{QtQuickWindowVersion}
Window {
- title: qsTr("Hello World")
width: 640
height: 480
visible: true
+ title: qsTr("Hello World")
}
diff --git a/share/qtcreator/templates/wizards/projects/qtquickapplication/empty/main.qml.tpl b/share/qtcreator/templates/wizards/projects/qtquickapplication/empty/main.qml.tpl
index 6d8fab6a21..f915cf35dc 100644
--- a/share/qtcreator/templates/wizards/projects/qtquickapplication/empty/main.qml.tpl
+++ b/share/qtcreator/templates/wizards/projects/qtquickapplication/empty/main.qml.tpl
@@ -8,9 +8,9 @@ Window {
@if %{UseVirtualKeyboard}
id: window
@endif
- visible: true
width: 640
height: 480
+ visible: true
title: qsTr("Hello World")
@if %{UseVirtualKeyboard}
diff --git a/share/qtcreator/templates/wizards/projects/qtquickapplication/scroll/main.qml.tpl b/share/qtcreator/templates/wizards/projects/qtquickapplication/scroll/main.qml.tpl
index da4fdc8c2c..0ee9d19083 100644
--- a/share/qtcreator/templates/wizards/projects/qtquickapplication/scroll/main.qml.tpl
+++ b/share/qtcreator/templates/wizards/projects/qtquickapplication/scroll/main.qml.tpl
@@ -8,9 +8,9 @@ ApplicationWindow {
@if %{UseVirtualKeyboard}
id: window
@endif
- visible: true
width: 640
height: 480
+ visible: true
title: qsTr("Scroll")
ScrollView {
diff --git a/share/qtcreator/templates/wizards/projects/qtquickapplication/stack/main.qml.tpl b/share/qtcreator/templates/wizards/projects/qtquickapplication/stack/main.qml.tpl
index b6505572c3..f2285c512d 100644
--- a/share/qtcreator/templates/wizards/projects/qtquickapplication/stack/main.qml.tpl
+++ b/share/qtcreator/templates/wizards/projects/qtquickapplication/stack/main.qml.tpl
@@ -6,9 +6,9 @@ import %{QtQuickVirtualKeyboardImport}
ApplicationWindow {
id: window
- visible: true
width: 640
height: 480
+ visible: true
title: qsTr("Stack")
header: ToolBar {
diff --git a/share/qtcreator/templates/wizards/projects/qtquickapplication/swipe/main.qml.tpl b/share/qtcreator/templates/wizards/projects/qtquickapplication/swipe/main.qml.tpl
index bf0da44833..e7f201ccab 100644
--- a/share/qtcreator/templates/wizards/projects/qtquickapplication/swipe/main.qml.tpl
+++ b/share/qtcreator/templates/wizards/projects/qtquickapplication/swipe/main.qml.tpl
@@ -8,9 +8,9 @@ ApplicationWindow {
@if %{UseVirtualKeyboard}
id: window
@endif
- visible: true
width: 640
height: 480
+ visible: true
title: qsTr("Tabs")
SwipeView {
diff --git a/share/qtcreator/templates/wizards/projects/vcs/git/wizard.json b/share/qtcreator/templates/wizards/projects/vcs/git/wizard.json
index 401be45a75..62bad7ee12 100644
--- a/share/qtcreator/templates/wizards/projects/vcs/git/wizard.json
+++ b/share/qtcreator/templates/wizards/projects/vcs/git/wizard.json
@@ -41,7 +41,11 @@
"trDisplayName": "Repository:",
"type": "LineEdit",
"isComplete": "%{JS: Vcs.isValidRepoUrl('%{vcsId}', '%{Repo}')}",
- "trIncompleteMessage": "Repository URL is not valid"
+ "trIncompleteMessage": "Repository URL is not valid",
+ "data":
+ {
+ "historyId": "Git.RemoteUrls"
+ }
},
{
"name": "Branch",
diff --git a/share/qtcreator/themes/dark.creatortheme b/share/qtcreator/themes/dark.creatortheme
index fa4a6ab330..58f1d1d4cb 100644
--- a/share/qtcreator/themes/dark.creatortheme
+++ b/share/qtcreator/themes/dark.creatortheme
@@ -223,6 +223,12 @@ VcsBase_FileDeleted_TextColor=ffff6c6c
VcsBase_FileRenamed_TextColor=ffffa500
VcsBase_FileUnmerged_TextColor=ffff4040
+Git_AuthorName_TextColor=ceffe5
+Git_CommitDate_TextColor=00ff00
+Git_CommitHash_TextColor=ff0000
+Git_CommitSubject_TextColor=text
+Git_Decoration_TextColor=ff00ff
+
Bookmarks_TextMarkColor=ff8080ff
TextEditor_SearchResult_ScrollBarColor=ff00c000
diff --git a/share/qtcreator/themes/default.creatortheme b/share/qtcreator/themes/default.creatortheme
index 8686733ab4..49df633ca3 100644
--- a/share/qtcreator/themes/default.creatortheme
+++ b/share/qtcreator/themes/default.creatortheme
@@ -214,6 +214,12 @@ VcsBase_FileDeleted_TextColor=ff800000
VcsBase_FileRenamed_TextColor=ffd77d00
VcsBase_FileUnmerged_TextColor=ffee0000
+Git_AuthorName_TextColor=007af4
+Git_CommitDate_TextColor=006600
+Git_CommitHash_TextColor=ff0000
+Git_CommitSubject_TextColor=text
+Git_Decoration_TextColor=ff00ff
+
Bookmarks_TextMarkColor=ffa0a0ff
TextEditor_SearchResult_ScrollBarColor=ff00c000
diff --git a/share/qtcreator/themes/design.creatortheme b/share/qtcreator/themes/design.creatortheme
index 914a717bdf..1f053a3091 100644
--- a/share/qtcreator/themes/design.creatortheme
+++ b/share/qtcreator/themes/design.creatortheme
@@ -227,6 +227,12 @@ VcsBase_FileDeleted_TextColor=fffff6c6c
VcsBase_FileRenamed_TextColor=ffffa500
VcsBase_FileUnmerged_TextColor=ffff4040
+Git_AuthorName_TextColor=ceffe5
+Git_CommitDate_TextColor=00ff00
+Git_CommitHash_TextColor=ff4343
+Git_CommitSubject_TextColor=text
+Git_Decoration_TextColor=ff00ff
+
Bookmarks_TextMarkColor=ff8080ff
TextEditor_SearchResult_ScrollBarColor=ff00c000
diff --git a/share/qtcreator/themes/flat-dark.creatortheme b/share/qtcreator/themes/flat-dark.creatortheme
index 1df02cd463..985f8827aa 100644
--- a/share/qtcreator/themes/flat-dark.creatortheme
+++ b/share/qtcreator/themes/flat-dark.creatortheme
@@ -227,6 +227,12 @@ VcsBase_FileDeleted_TextColor=fffff6c6c
VcsBase_FileRenamed_TextColor=ffffa500
VcsBase_FileUnmerged_TextColor=ffff4040
+Git_AuthorName_TextColor=ceffe5
+Git_CommitDate_TextColor=00ff00
+Git_CommitHash_TextColor=ff4343
+Git_CommitSubject_TextColor=text
+Git_Decoration_TextColor=ff00ff
+
Bookmarks_TextMarkColor=ff8080ff
TextEditor_SearchResult_ScrollBarColor=ff00c000
diff --git a/share/qtcreator/themes/flat-light.creatortheme b/share/qtcreator/themes/flat-light.creatortheme
index b8b4e7eabd..4fd823c976 100644
--- a/share/qtcreator/themes/flat-light.creatortheme
+++ b/share/qtcreator/themes/flat-light.creatortheme
@@ -223,6 +223,12 @@ VcsBase_FileDeleted_TextColor=ff800000
VcsBase_FileRenamed_TextColor=ffd77d00
VcsBase_FileUnmerged_TextColor=ffee0000
+Git_AuthorName_TextColor=007af4
+Git_CommitDate_TextColor=006600
+Git_CommitHash_TextColor=ff0000
+Git_CommitSubject_TextColor=text
+Git_Decoration_TextColor=ff00ff
+
Bookmarks_TextMarkColor=ffa0a0ff
TextEditor_SearchResult_ScrollBarColor=ff00c000
diff --git a/share/qtcreator/themes/flat.creatortheme b/share/qtcreator/themes/flat.creatortheme
index e80a8d85f1..27de98e08a 100644
--- a/share/qtcreator/themes/flat.creatortheme
+++ b/share/qtcreator/themes/flat.creatortheme
@@ -221,6 +221,12 @@ VcsBase_FileDeleted_TextColor=ff800000
VcsBase_FileRenamed_TextColor=ffd77d00
VcsBase_FileUnmerged_TextColor=ffee0000
+Git_AuthorName_TextColor=007af4
+Git_CommitDate_TextColor=006600
+Git_CommitHash_TextColor=ff0000
+Git_CommitSubject_TextColor=text
+Git_Decoration_TextColor=ff00ff
+
Bookmarks_TextMarkColor=ffa0a0ff
TextEditor_SearchResult_ScrollBarColor=ff00c000
diff --git a/share/qtcreator/welcomescreen/welcomescreen.qml b/share/qtcreator/welcomescreen/welcomescreen.qml
deleted file mode 100644
index 36489f8e13..0000000000
--- a/share/qtcreator/welcomescreen/welcomescreen.qml
+++ /dev/null
@@ -1,77 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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.1
-import widgets 1.0
-
-Item {
- id: root
-
- property var fonts: CustomFonts {}
-
- property int screenDependHeightDistance: Math.min(50, Math.max(16, height / 30))
-
- DropArea {
- anchors.fill: parent
- keys: ["text/uri-list"]
- onDropped: {
- if ((drop.supportedActions & Qt.CopyAction != 0)
- && welcomeMode.openDroppedFiles(drop.urls))
- drop.accept(Qt.CopyAction);
- }
- }
-
- SideBar {
- id: sideBar
- model: pagesModel
- anchors.top: parent.top
- anchors.bottom: parent.bottom
- }
-
- Rectangle {
- id: splitter
- color: creatorTheme.Welcome_DividerColor // divider between left and right pane
- width: 1
- anchors.top: parent.top
- anchors.bottom: parent.bottom
-
- anchors.left: sideBar.right
-
- }
-
- PageLoader {
- id: loader
-
- model: pagesModel
- currentIndex: sideBar.currentIndex
-
- anchors.top: parent.top
- anchors.left: splitter.right
- anchors.right: parent.right
- anchors.bottom: parent.bottom
-
- color: creatorTheme.Welcome_BackgroundColor
- }
-}
diff --git a/share/qtcreator/welcomescreen/welcomescreen.qmlproject b/share/qtcreator/welcomescreen/welcomescreen.qmlproject
deleted file mode 100644
index 0f74672546..0000000000
--- a/share/qtcreator/welcomescreen/welcomescreen.qmlproject
+++ /dev/null
@@ -1,18 +0,0 @@
-import QmlProject 1.1
-
-Project {
- mainFile: "welcomescreen.qml"
-
- /* Include .qml, .js, and image files from current directory and subdirectories */
- QmlFiles {
- directory: "."
- }
- JavaScriptFiles {
- directory: "."
- }
- ImageFiles {
- directory: "."
- }
-
- importPaths: [ "." ]
-}
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 25276f1de1..af0c062c7b 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -22,7 +22,6 @@ install(
install(
DIRECTORY
- ${PROJECT_SOURCE_DIR}/doc
${PROJECT_SOURCE_DIR}/scripts
DESTINATION ./
COMPONENT Devel EXCLUDE_FROM_ALL
@@ -53,6 +52,10 @@ if (NOT DEFINED add_translation_targets)
include(\${CMAKE_CURRENT_LIST_DIR}/QtCreatorTranslations.cmake)
endif()
+if (NOT DEFINED add_qtc_documentation)
+ include(\${CMAKE_CURRENT_LIST_DIR}/QtCreatorDocumentation.cmake)
+endif()
+
if (NOT TARGET QtCreator::Core)
include(\${CMAKE_CURRENT_LIST_DIR}/QtCreatorTargets.cmake)
endif()
@@ -66,7 +69,9 @@ export(EXPORT QtCreator
file(COPY
${PROJECT_SOURCE_DIR}/cmake/QtCreatorIDEBranding.cmake
${PROJECT_SOURCE_DIR}/cmake/QtCreatorTranslations.cmake
+ ${PROJECT_SOURCE_DIR}/cmake/QtCreatorDocumentation.cmake
${PROJECT_SOURCE_DIR}/cmake/QtCreatorAPI.cmake
+ ${PROJECT_SOURCE_DIR}/cmake/QtCreatorAPIInternal.cmake
DESTINATION ${CMAKE_BINARY_DIR}/cmake
)
@@ -75,7 +80,9 @@ install(
FILES
${PROJECT_SOURCE_DIR}/cmake/QtCreatorIDEBranding.cmake
${PROJECT_SOURCE_DIR}/cmake/QtCreatorTranslations.cmake
+ ${PROJECT_SOURCE_DIR}/cmake/QtCreatorDocumentation.cmake
${PROJECT_SOURCE_DIR}/cmake/QtCreatorAPI.cmake
+ ${PROJECT_SOURCE_DIR}/cmake/QtCreatorAPIInternal.cmake
${CMAKE_BINARY_DIR}/cmake/QtCreatorConfig.cmake
DESTINATION lib/cmake/QtCreator
COMPONENT Devel EXCLUDE_FROM_ALL
diff --git a/src/app/main.cpp b/src/app/main.cpp
index cd566f218f..4302e9018c 100644
--- a/src/app/main.cpp
+++ b/src/app/main.cpp
@@ -69,6 +69,10 @@
#include <qtsystemexceptionhandler.h>
#endif
+#ifdef Q_OS_LINUX
+#include <malloc.h>
+#endif
+
using namespace ExtensionSystem;
enum { OptionIndent = 4, DescriptionIndent = 34 };
@@ -459,6 +463,11 @@ int main(int argc, char **argv)
Options options = parseCommandLine(argc, argv);
applicationDirPath(argv[0]);
+ if (qEnvironmentVariableIsSet("QTC_DO_NOT_PROPAGATE_LD_PRELOAD")) {
+ Utils::Environment::modifySystemEnvironment(
+ {{"LD_PRELOAD", "", Utils::EnvironmentItem::Unset}});
+ }
+
if (options.userLibraryPath) {
if ((*options.userLibraryPath).isEmpty()) {
Utils::Environment::modifySystemEnvironment(
@@ -699,5 +708,32 @@ int main(int argc, char **argv)
// shutdown plugin manager on the exit
QObject::connect(&app, &QCoreApplication::aboutToQuit, &pluginManager, &PluginManager::shutdown);
+#ifdef Q_OS_LINUX
+ class MemoryTrimmer : public QObject
+ {
+ public:
+ MemoryTrimmer()
+ {
+ m_trimTimer.setSingleShot(true);
+ m_trimTimer.setInterval(60000);
+ // glibc may not actually free memory in free().
+ connect(&m_trimTimer, &QTimer::timeout, this, [] { malloc_trim(0); });
+ }
+
+ bool eventFilter(QObject *, QEvent *e) override
+ {
+ if ((e->type() == QEvent::MouseButtonPress || e->type() == QEvent::KeyPress)
+ && !m_trimTimer.isActive()) {
+ m_trimTimer.start();
+ }
+ return false;
+ }
+
+ QTimer m_trimTimer;
+ };
+ MemoryTrimmer trimmer;
+ app.installEventFilter(&trimmer);
+#endif
+
return restarter.restartOrExit(app.exec());
}
diff --git a/src/libs/3rdparty/syntax-highlighting/.gitignore b/src/libs/3rdparty/syntax-highlighting/.gitignore
index 52f10e28a5..7df2675d19 100644
--- a/src/libs/3rdparty/syntax-highlighting/.gitignore
+++ b/src/libs/3rdparty/syntax-highlighting/.gitignore
@@ -9,4 +9,5 @@ callgrind.*
heaptrack.*
/build*/
*.unc-backup*
-
+.clang-format
+.cmake/
diff --git a/src/libs/3rdparty/syntax-highlighting/CMakeLists.txt b/src/libs/3rdparty/syntax-highlighting/CMakeLists.txt
index 1304c1a004..ca0a039106 100644
--- a/src/libs/3rdparty/syntax-highlighting/CMakeLists.txt
+++ b/src/libs/3rdparty/syntax-highlighting/CMakeLists.txt
@@ -37,11 +37,8 @@ install(
DESTINATION "${IDE_DATA_PATH}/generic-highlighter/"
)
-add_custom_target(copy_generic_highligher_to_builddir ALL VERBATIM)
-add_custom_command(TARGET copy_generic_highligher_to_builddir POST_BUILD
- COMMAND "${CMAKE_COMMAND}" -E copy_directory data/syntax
- "${PROJECT_BINARY_DIR}/${IDE_DATA_PATH}/generic-highlighter/syntax"
- WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
- COMMENT Copy files into build directory
- VERBATIM
+# copy resource directories during build
+qtc_copy_to_builddir(copy_generic_highligher_to_builddir
+ DIRECTORIES data/syntax
+ DESTINATION "${IDE_DATA_PATH}/generic-highlighter/syntax"
)
diff --git a/src/libs/3rdparty/syntax-highlighting/KF5SyntaxHighlightingConfig.cmake.in b/src/libs/3rdparty/syntax-highlighting/KF5SyntaxHighlightingConfig.cmake.in
index 0fd1778fb8..aa822b88dc 100644
--- a/src/libs/3rdparty/syntax-highlighting/KF5SyntaxHighlightingConfig.cmake.in
+++ b/src/libs/3rdparty/syntax-highlighting/KF5SyntaxHighlightingConfig.cmake.in
@@ -1,6 +1,8 @@
@PACKAGE_INIT@
-find_package(Qt5 @Qt5Core_VERSION_MAJOR@.@Qt5Core_VERSION_MINOR@ NO_MODULE REQUIRED COMPONENTS Core Gui)
+include(CMakeFindDependencyMacro)
+find_dependency(Qt5Core @REQUIRED_QT_VERSION@)
+find_dependency(Qt5Gui @REQUIRED_QT_VERSION@)
include("${CMAKE_CURRENT_LIST_DIR}/KF5SyntaxHighlightingTargets.cmake")
@PACKAGE_INCLUDE_QCHTARGETS@
diff --git a/src/libs/3rdparty/syntax-highlighting/data/CMakeLists.txt b/src/libs/3rdparty/syntax-highlighting/data/CMakeLists.txt
index 73adbe6d20..cab8c885dc 100644
--- a/src/libs/3rdparty/syntax-highlighting/data/CMakeLists.txt
+++ b/src/libs/3rdparty/syntax-highlighting/data/CMakeLists.txt
@@ -1,22 +1,28 @@
# generate PHP definitions
macro(generate_php_syntax_definition targetFile srcFile)
- execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/syntax)
+ execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/generated/syntax)
execute_process(COMMAND ${PERL_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/generators/generate-php.pl
INPUT_FILE ${CMAKE_CURRENT_SOURCE_DIR}/syntax/${srcFile}
- OUTPUT_FILE ${CMAKE_CURRENT_BINARY_DIR}/syntax/${targetFile})
+ OUTPUT_FILE ${CMAKE_CURRENT_BINARY_DIR}/generated/syntax/${targetFile})
endmacro()
generate_php_syntax_definition(javascript-php.xml javascript.xml)
generate_php_syntax_definition(css-php.xml css.xml)
generate_php_syntax_definition(html-php.xml html.xml)
+generate_php_syntax_definition(javascript-react-php.xml javascript-react.xml)
+generate_php_syntax_definition(typescript-php.xml typescript.xml)
+generate_php_syntax_definition(mustache-php.xml mustache.xml)
# find all definitions
file(GLOB src_defs "${CMAKE_CURRENT_SOURCE_DIR}/syntax/*.xml")
set(defs
${src_defs}
- ${CMAKE_CURRENT_BINARY_DIR}/syntax/html-php.xml
- ${CMAKE_CURRENT_BINARY_DIR}/syntax/css-php.xml
- ${CMAKE_CURRENT_BINARY_DIR}/syntax/javascript-php.xml
+ ${CMAKE_CURRENT_BINARY_DIR}/generated/syntax/html-php.xml
+ ${CMAKE_CURRENT_BINARY_DIR}/generated/syntax/css-php.xml
+ ${CMAKE_CURRENT_BINARY_DIR}/generated/syntax/javascript-php.xml
+ ${CMAKE_CURRENT_BINARY_DIR}/generated/syntax/javascript-react-php.xml
+ ${CMAKE_CURRENT_BINARY_DIR}/generated/syntax/typescript-php.xml
+ ${CMAKE_CURRENT_BINARY_DIR}/generated/syntax/mustache-php.xml
)
# theme data resource
@@ -58,4 +64,8 @@ else()
endif()
# set PIC to allow use in static and shared libs
+# 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)
+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 f7b7570cf4..f52084c569 100644
--- a/src/libs/3rdparty/syntax-highlighting/data/generators/cmake.xml.tpl
+++ b/src/libs/3rdparty/syntax-highlighting/data/generators/cmake.xml.tpl
@@ -9,7 +9,7 @@
Copyright 2004 Alexander Neundorf (neundorf@kde.org)
Copyright 2005 Dominik Haumann (dhdev@gmx.de)
Copyright 2007,2008,2013,2014 Matthew Woehlke (mw_triad@users.sourceforge.net)
- Copyright 2013-2015,2017-2019 Alex Turbov (i.zaufi@gmail.com)
+ Copyright 2013-2015,2017-2020 Alex Turbov (i.zaufi@gmail.com)
**********************************************************************
* This library is free software; you can redistribute it and/or *
@@ -31,7 +31,7 @@
<language
name="CMake"
- version="16"
+ version="22"
kateversion="2.4"
section="Other"
extensions="CMakeLists.txt;*.cmake;*.cmake.in"
@@ -191,9 +191,9 @@
</context>
<context attribute="Normal Text" lineEndContext="#stay" name="Detect Builtin Variables">
+ <RegExpr attribute="Internal Name" context="#stay" String="\b_&id_re;\b" />
<keyword attribute="Builtin Variable" context="#stay" String="variables" insensitive="false" />
<IncludeRules context="Detect More Builtin Variables" />
- <RegExpr attribute="Internal Name" context="#stay" String="\b_&id_re;\b" />
</context>
<context attribute="Normal Text" lineEndContext="#stay" name="Detect More Builtin Variables">
@@ -278,6 +278,7 @@
</context>
<context attribute="Comment" lineEndContext="#stay" name="Bracketed Comment" dynamic="true">
+ <LineContinue attribute="Comment" context="#stay" />
<RegExpr attribute="Comment" context="#pop" String=".*\]%1\]" dynamic="true" />
<IncludeRules context="##Alerts" />
<IncludeRules context="##Modelines" />
diff --git a/src/libs/3rdparty/syntax-highlighting/data/generators/cmake.yaml b/src/libs/3rdparty/syntax-highlighting/data/generators/cmake.yaml
index f3fa77756f..3b1e8327ca 100644
--- a/src/libs/3rdparty/syntax-highlighting/data/generators/cmake.yaml
+++ b/src/libs/3rdparty/syntax-highlighting/data/generators/cmake.yaml
@@ -6,6 +6,7 @@ global-properties:
- AUTOMOC_TARGETS_FOLDER
- AUTORCC_SOURCE_GROUP
- CMAKE_C_KNOWN_FEATURES
+ - CMAKE_CUDA_KNOWN_FEATURES # Since 3.17
- CMAKE_CXX_KNOWN_FEATURES
- CMAKE_ROLE # Since 3.14
- DEBUG_CONFIGURATIONS
@@ -81,6 +82,7 @@ directory-properties:
# NOTE Copy-n-pasting this list from official docs may contain a redudant item `Example`! Check it!
target-properties:
- ADDITIONAL_CLEAN_FILES # Since 3.15
+ - AIX_EXPORT_ALL_SYMBOLS # Since 3.17
- ALIASED_TARGET
- ANDROID_ANT_ADDITIONAL_OPTIONS
- ANDROID_API
@@ -111,6 +113,7 @@ target-properties:
- AUTOMOC_EXECUTABLE # Since 3.14
- AUTOMOC_MACRO_NAMES
- AUTOMOC_MOC_OPTIONS # Since ???
+ - AUTOMOC_PATH_PREFIX # Since 3.16
- AUTOMOC
- AUTOUIC
- AUTOUIC_EXECUTABLE # Since 3.14
@@ -148,6 +151,7 @@ target-properties:
- CUDA_PTX_COMPILATION
- CUDA_SEPARABLE_COMPILATION
- CUDA_RESOLVE_DEVICE_SYMBOLS
+ - CUDA_RUNTIME_LIBRARY # Since 3.17
- CUDA_EXTENSIONS
- CUDA_STANDARD
- CUDA_STANDARD_REQUIRED
@@ -158,6 +162,9 @@ target-properties:
- DEFINE_SYMBOL
- DEPLOYMENT_ADDITIONAL_FILES # Since 3.13
- DEPLOYMENT_REMOTE_DIRECTORY
+ - DEPRECATION # Since 3.17
+ - DISABLE_PRECOMPILE_HEADERS # Since 3.16
+ - DOTNET_TARGET_FRAMEWORK # Since 3.17
- DOTNET_TARGET_FRAMEWORK_VERSION # Since 3.12
- EchoString
- ENABLE_EXPORTS
@@ -203,6 +210,7 @@ target-properties:
- IMPORT_SUFFIX
- INCLUDE_DIRECTORIES
- INSTALL_NAME_DIR
+ - INSTALL_REMOVE_ENVIRONMENT_RPATH # Since 3.16
- INSTALL_RPATH
- INSTALL_RPATH_USE_LINK_PATH
- INTERFACE_AUTOUIC_OPTIONS
@@ -214,6 +222,7 @@ target-properties:
- INTERFACE_LINK_DIRECTORIES # Since 3.13
- INTERFACE_LINK_LIBRARIES
- INTERFACE_LINK_OPTIONS # Since 3.13
+ - INTERFACE_PRECOMPILE_HEADERS # Since 3.16
- INTERFACE_POSITION_INDEPENDENT_CODE
- INTERFACE_SOURCES
- INTERFACE_SYSTEM_INCLUDE_DIRECTORIES
@@ -262,6 +271,8 @@ target-properties:
- NO_SYSTEM_FROM_IMPORTED
- OSX_ARCHITECTURES_<CONFIG>
- OSX_ARCHITECTURES
+ - OSX_CURRENT_VERSION # Since 3.17
+ - OSX_COMPATIBILITY_VERSION # Since 3.17
- OUTPUT_NAME_<CONFIG>
- OUTPUT_NAME
- PDB_NAME_<CONFIG>
@@ -269,6 +280,8 @@ target-properties:
- PDB_OUTPUT_DIRECTORY_<CONFIG>
- PDB_OUTPUT_DIRECTORY
- POSITION_INDEPENDENT_CODE
+ - PRECOMPILE_HEADERS # Since 3.16
+ - PRECOMPILE_HEADERS_REUSE_FROM # Since 3.16
- PREFIX
- PRIVATE_HEADER
- PROJECT_LABEL
@@ -293,6 +306,10 @@ target-properties:
- Swift_MODULE_DIRECTORY # Since 3.15
- Swift_MODULE_NAME # Since 3.15
- TYPE
+ - UNITY_BUILD # Since 3.16
+ - UNITY_BUILD_BATCH_SIZE # Since 3.16
+ - UNITY_BUILD_CODE_AFTER_INCLUDE # Since 3.16
+ - UNITY_BUILD_CODE_BEFORE_INCLUDE # Since 3.16
- VERSION
- VISIBILITY_INLINES_HIDDEN
- VS_CONFIGURATION_TYPE
@@ -306,6 +323,8 @@ target-properties:
- VS_DOTNET_REFERENCES
- VS_DOTNET_REFERENCES_COPY_LOCAL
- VS_DOTNET_TARGET_FRAMEWORK_VERSION
+ - VS_DOTNET_DOCUMENTATION_FILE # Since 3.17
+ - VS_DPI_AWARE # Since 3.16
- VS_GLOBAL_KEYWORD
- VS_GLOBAL_PROJECT_TYPES
- VS_GLOBAL_ROOTNAMESPACE
@@ -339,21 +358,23 @@ target-properties:
- XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN # Since 3.13
- XCODE_SCHEME_ARGUMENTS # Since 3.13
- XCODE_SCHEME_DEBUG_AS_ROOT # Since 3.15
- - XCODE_SCHEME_THREAD_SANITIZER # Since 3.13
- - XCODE_SCHEME_THREAD_SANITIZER_STOP # Since 3.13
- - XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER # Since 3.13
- - XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP # Since 3.13
+ - XCODE_SCHEME_DEBUG_DOCUMENT_VERSIONING # Since 3.16
- XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER # Since 3.13
- - XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP # Since 3.13
- - XCODE_SCHEME_MALLOC_SCRIBBLE # Since 3.13
- - XCODE_SCHEME_MALLOC_GUARD_EDGES # Since 3.13
- - XCODE_SCHEME_GUARD_MALLOC # Since 3.13
- - XCODE_SCHEME_ZOMBIE_OBJECTS # Since 3.13
- - XCODE_SCHEME_MALLOC_STACK # Since 3.13
- XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE # Since 3.13
- XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS # Since 3.13
- XCODE_SCHEME_EXECUTABLE # Since 3.13
- XCODE_SCHEME_ENVIRONMENT # Since 3.13
+ - XCODE_SCHEME_GUARD_MALLOC # Since 3.13
+ - XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP # Since 3.13
+ - XCODE_SCHEME_MALLOC_GUARD_EDGES # Since 3.13
+ - XCODE_SCHEME_MALLOC_SCRIBBLE # Since 3.13
+ - XCODE_SCHEME_MALLOC_STACK # Since 3.13
+ - XCODE_SCHEME_THREAD_SANITIZER # Since 3.13
+ - XCODE_SCHEME_THREAD_SANITIZER_STOP # Since 3.13
+ - XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER # Since 3.13
+ - XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP # Since 3.13
+ - XCODE_SCHEME_WORKING_DIRECTORY # Since 3.1?
+ - XCODE_SCHEME_ZOMBIE_OBJECTS # Since 3.13
- XCTEST
test-properties:
@@ -375,6 +396,7 @@ test-properties:
- REQUIRED_FILES
- RESOURCE_LOCK
- RUN_SERIAL
+ - SKIP_REGULAR_EXPRESSION # Since 3.16
- SKIP_RETURN_CODE
- TIMEOUT
- TIMEOUT_AFTER_MATCH
@@ -404,6 +426,8 @@ source-properties:
- SKIP_AUTOMOC
- SKIP_AUTORCC
- SKIP_AUTOUIC
+ - SKIP_PRECOMPILE_HEADERS # Since 3.16
+ - SKIP_UNITY_BUILD_INCLUSION # Since 3.16
- Swift_DEPENDENCIES_FILE # Since 3.15
- Swift_DIAGNOSTICS_FILE # Since 3.15
- SYMBOLIC
@@ -547,22 +571,29 @@ variables:
- CMAKE_CROSSCOMPILING_EMULATOR
- CMAKE_CTEST_COMMAND
- CMAKE_CURRENT_BINARY_DIR
+ - CMAKE_CURRENT_FUNCTION # Since 3.17
+ - CMAKE_CURRENT_FUNCTION_LIST_DIR # Since 3.17
+ - CMAKE_CURRENT_FUNCTION_LIST_FILE # Since 3.17
+ - CMAKE_CURRENT_FUNCTION_LIST_LINE # Since 3.17
- CMAKE_CURRENT_LIST_DIR
- CMAKE_CURRENT_LIST_FILE
- CMAKE_CURRENT_LIST_LINE
- CMAKE_CURRENT_SOURCE_DIR
- CMAKE_DIRECTORY_LABELS # Since 3.10
- CMAKE_DL_LIBS
+ - CMAKE_DOTNET_TARGET_FRAMEWORK # Since 3.17
- CMAKE_DOTNET_TARGET_FRAMEWORK_VERSION # Since 3.12
- CMAKE_EDIT_COMMAND
- CMAKE_EXECUTABLE_SUFFIX
- CMAKE_EXTRA_GENERATOR
- CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES
+ - CMAKE_FIND_DEBUG_MODE # Since 3.17
- CMAKE_FIND_PACKAGE_NAME
- CMAKE_FIND_PACKAGE_SORT_DIRECTION
- CMAKE_FIND_PACKAGE_SORT_ORDER
- CMAKE_GENERATOR
- CMAKE_GENERATOR_INSTANCE # Since 3.11
+ - CMAKE_GENERATOR_NO_COMPILER_ENV # "Professional CMake" §17.4
- CMAKE_GENERATOR_PLATFORM
- CMAKE_GENERATOR_TOOLSET
- CMAKE_HOME_DIRECTORY
@@ -580,6 +611,10 @@ variables:
- CMAKE_MAKE_PROGRAM
- CMAKE_MATCH_COUNT
- CMAKE_MATCH_<n>
+ - CMAKE_MESSAGE_CONTEXT # Since 3.17
+ - CMAKE_MESSAGE_CONTEXT_SHOW # Since 3.17
+ - CMAKE_MESSAGE_INDENT # Since 3.16
+ - CMAKE_MESSAGE_LOG_LEVEL # Since 3.17
- CMAKE_MINIMUM_REQUIRED_VERSION
- CMAKE_MINOR_VERSION
- CMAKE_NETRC # Since 3.11
@@ -658,6 +693,7 @@ variables:
- CMAKE_ECLIPSE_GENERATE_LINKED_RESOURCES
- CMAKE_ECLIPSE_GENERATE_SOURCE_PROJECT
- CMAKE_ECLIPSE_MAKE_ARGUMENTS
+ - CMAKE_ECLIPSE_RESOURCE_ENCODING # Since 3.16
- CMAKE_ECLIPSE_VERSION
- CMAKE_ERROR_DEPRECATED
- CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION
@@ -671,7 +707,7 @@ variables:
- CMAKE_FIND_LIBRARY_PREFIXES
- CMAKE_FIND_LIBRARY_SUFFIXES
- CMAKE_FIND_NO_INSTALL_PREFIX
- - CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY
+ - CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY # Deprecated since 3.16
- CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY
- CMAKE_FIND_PACKAGE_PREFER_CONFIG # Since 3.15
- CMAKE_FIND_PACKAGE_RESOLVE_SYMLINKS # Since 3.14
@@ -681,6 +717,13 @@ variables:
- CMAKE_FIND_ROOT_PATH_MODE_LIBRARY
- CMAKE_FIND_ROOT_PATH_MODE_PACKAGE
- CMAKE_FIND_ROOT_PATH_MODE_PROGRAM
+ - CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH # Since 3.16
+ - CMAKE_FIND_USE_CMAKE_PATH # Since 3.16
+ - CMAKE_FIND_USE_CMAKE_SYSTEM_PATH # Since 3.16
+ - CMAKE_FIND_USE_PACKAGE_ROOT_PATH # Since 3.16
+ - CMAKE_FIND_USE_PACKAGE_REGISTRY # Since 3.16
+ - CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH # Since 3.16
+ - CMAKE_FIND_USE_SYSTEM_PACKAGE_REGISTRY # Since 3.16
- CMAKE_FRAMEWORK_PATH
- CMAKE_IGNORE_PATH
- CMAKE_INCLUDE_DIRECTORIES_BEFORE
@@ -725,19 +768,22 @@ variables:
- CMAKE_XCODE_GENERATE_TOP_LEVEL_PROJECT_ONLY # Since 3.13
- CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER # Since 3.13
- CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN # Since 3.13
+ - CMAKE_XCODE_SCHEME_WORKING_DIRECTORY # Since 3.1?
+ - CMAKE_XCODE_SCHEME_DEBUG_DOCUMENT_VERSIONING # Since 3.16
+ - CMAKE_XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER # Since 3.13
+ - CMAKE_XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE # Since 3.13
+ - CMAKE_XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS # Since 3.13
+ - CMAKE_XCODE_SCHEME_ENVIRONMENT # Since 3.17
+ - CMAKE_XCODE_SCHEME_GUARD_MALLOC # Since 3.13
+ - CMAKE_XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP # Since 3.13
+ - CMAKE_XCODE_SCHEME_MALLOC_GUARD_EDGES # Since 3.13
+ - CMAKE_XCODE_SCHEME_MALLOC_SCRIBBLE # Since 3.13
+ - CMAKE_XCODE_SCHEME_MALLOC_STACK # Since 3.13
- CMAKE_XCODE_SCHEME_THREAD_SANITIZER # Since 3.13
- CMAKE_XCODE_SCHEME_THREAD_SANITIZER_STOP # Since 3.13
- CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER # Since 3.13
- CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP # Since 3.13
- - CMAKE_XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER # Since 3.13
- - CMAKE_XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP # Since 3.13
- - CMAKE_XCODE_SCHEME_MALLOC_SCRIBBLE # Since 3.13
- - CMAKE_XCODE_SCHEME_MALLOC_GUARD_EDGES # Since 3.13
- - CMAKE_XCODE_SCHEME_GUARD_MALLOC # Since 3.13
- CMAKE_XCODE_SCHEME_ZOMBIE_OBJECTS # Since 3.13
- - CMAKE_XCODE_SCHEME_MALLOC_STACK # Since 3.13
- - CMAKE_XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE # Since 3.13
- - CMAKE_XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS # Since 3.13
- CMAKE_SUPPRESS_DEVELOPER_WARNINGS # Undocumented yet (CMake <= 3.10)
- CMAKE_SUPPRESS_DEVELOPER_ERRORS # Undocumented yet (CMake <= 3.10)
# Variables that Describe the System
@@ -787,6 +833,7 @@ variables:
- XCODE
- XCODE_VERSION
# Variables that Control the Build
+ - CMAKE_AIX_EXPORT_ALL_SYMBOLS # Since 3.17
- CMAKE_ANDROID_ANT_ADDITIONAL_OPTIONS
- CMAKE_ANDROID_API
- CMAKE_ANDROID_API_MIN
@@ -820,6 +867,7 @@ variables:
- CMAKE_AUTOMOC
- CMAKE_AUTOMOC_DEPEND_FILTERS
- CMAKE_AUTOMOC_MOC_OPTIONS
+ - CMAKE_AUTOMOC_PATH_PREFIX # Since 3.16
- CMAKE_AUTORCC
- CMAKE_AUTORCC_OPTIONS
- CMAKE_AUTOUIC
@@ -832,8 +880,15 @@ variables:
- CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY
- CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY_<CONFIG>
- CMAKE_<CONFIG>_POSTFIX
+ - CMAKE_CROSS_CONFIGS # Since 3.17
+ - CMAKE_CTEST_ARGUMENTS # Since 3.17
- CMAKE_CUDA_SEPARABLE_COMPILATION # Since 3.11
+ - CMAKE_CUDA_RESOLVE_DEVICE_SYMBOLS # Since 3.16
+ - CMAKE_CUDA_RUNTIME_LIBRARY # Since 3.17
- CMAKE_DEBUG_POSTFIX
+ - CMAKE_DEFAULT_BUILD_TYPE # Since 3.17
+ - CMAKE_DEFAULT_CONFIGS # Since 3.17
+ - CMAKE_DISABLE_PRECOMPILE_HEADERS # Since 3.17
- CMAKE_ENABLE_EXPORTS
- CMAKE_EXE_LINKER_FLAGS
- CMAKE_EXE_LINKER_FLAGS_<CONFIG>
@@ -851,6 +906,7 @@ variables:
- CMAKE_INCLUDE_CURRENT_DIR
- CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE
- CMAKE_INSTALL_NAME_DIR
+ - CMAKE_INSTALL_REMOVE_ENVIRONMENT_RPATH # Since 3.16
- CMAKE_INSTALL_RPATH
- CMAKE_INSTALL_RPATH_USE_LINK_PATH
- CMAKE_INTERPROCEDURAL_OPTIMIZATION
@@ -904,6 +960,8 @@ variables:
- CMAKE_TRY_COMPILE_CONFIGURATION
- CMAKE_TRY_COMPILE_PLATFORM_VARIABLES
- CMAKE_TRY_COMPILE_TARGET_TYPE
+ - CMAKE_UNITY_BUILD # Since 3.16
+ - CMAKE_UNITY_BUILD_BATCH_SIZE # Since 3.16
- CMAKE_USE_RELATIVE_PATHS
- CMAKE_VISIBILITY_INLINES_HIDDEN
- CMAKE_VS_GLOBALS # Since 3.13
@@ -926,6 +984,8 @@ variables:
- CMAKE_COMPILER_IS_GNUCC
- CMAKE_COMPILER_IS_GNUCXX
- CMAKE_COMPILER_IS_GNUG77
+ - CMAKE_CUDA_COMPILE_FEATURES # Since 3.17
+ - CMAKE_CUDA_HOST_COMPILER # Since 3.17
- CMAKE_CUDA_EXTENSIONS
- CMAKE_CUDA_STANDARD
- CMAKE_CUDA_STANDARD_REQUIRED
@@ -1072,7 +1132,8 @@ variables:
- CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION
- CPACK_INCLUDE_TOPLEVEL_DIRECTORY
- CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS # Since 3.11
- - CPACK_INSTALL_SCRIPT
+ - CPACK_INSTALL_SCRIPT # Deprecated since 3.16
+ - CPACK_INSTALL_SCRIPTS # Since 3.16
- CPACK_PACKAGING_INSTALL_PREFIX
- CPACK_SET_DESTDIR
- CPACK_WARN_ON_ABSOLUTE_INSTALL_DESTINATION
@@ -1201,7 +1262,7 @@ variables:
- CPACK_DEBIAN_ENABLE_COMPONENT_DEPENDS
- CPACK_DEBIAN_PACKAGE_MAINTAINER
- CPACK_DEBIAN_PACKAGE_DESCRIPTION
- - CPACK_COMPONENT_<COMPONENT>_DESCRIPTION
+ - CPACK_DEBIAN_<COMPONENT>_DESCRIPTION # Since 3.16
- CPACK_DEBIAN_PACKAGE_SECTION
- CPACK_DEBIAN_<COMPONENT>_PACKAGE_SECTION
- CPACK_DEBIAN_ARCHIVE_TYPE
@@ -1247,6 +1308,7 @@ variables:
- CPACK_DMG_DISABLE_APPLICATIONS_SYMLINK
- CPACK_DMG_SLA_DIR
- CPACK_DMG_SLA_LANGUAGES
+ - CPACK_DMG_<component>_FILE_NAME # Since 3.17
- CPACK_COMMAND_HDIUTIL
- CPACK_COMMAND_SETFILE
- CPACK_COMMAND_REZ
@@ -1318,6 +1380,12 @@ variables:
- CPACK_NSIS_EXECUTABLES_DIRECTORY
- CPACK_NSIS_MUI_FINISHPAGE_RUN
- CPACK_NSIS_MENU_LINKS
+ - CPACK_NSIS_UNINSTALL_NAME # Since 3.17
+ - CPACK_NSIS_WELCOME_TITLE # Since 3.17
+ - CPACK_NSIS_WELCOME_TITLE_3LINES # Since 3.17
+ - CPACK_NSIS_FINISH_TITLE # Since 3.17
+ - CPACK_NSIS_FINISH_TITLE_3LINES # Since 3.17
+ - CPACK_NSIS_MUI_HEADERIMAGE # Since 3.17
# - CPackNuGet (since 3.12)
- CPACK_NUGET_COMPONENT_INSTALL
- CPACK_NUGET_PACKAGE_NAME
@@ -1351,8 +1419,7 @@ variables:
- CPACK_NUGET_PACKAGE_DEPENDENCIES_<dependency>_VERSION
- CPACK_NUGET_<compName>_PACKAGE_DEPENDENCIES_<dependency>_VERSION
- CPACK_NUGET_PACKAGE_DEBUG
- # - CPackPackageMaker
- - CPACK_OSX_PACKAGE_VERSION
+ # - CPackPackageMaker is deprecated and gonna be removed in next versions of CPack
# - CPackProductBuild
- CPACK_COMMAND_PRODUCTBUILD
- CPACK_PRODUCTBUILD_IDENTITY_NAME
@@ -1360,7 +1427,19 @@ variables:
- CPACK_COMMAND_PKGBUILD
- CPACK_PKGBUILD_IDENTITY_NAME
- CPACK_PKGBUILD_KEYCHAIN_PATH
+ - CPACK_PREFLIGHT_<COMP>_SCRIPT # Since 3.1?
+ - CPACK_POSTFLIGHT_<COMP>_SCRIPT # Since 3.1?
- CPACK_PRODUCTBUILD_RESOURCES_DIR
+ - CPACK_PRODUCTBUILD_BACKGROUND # Since 3.17
+ - CPACK_PRODUCTBUILD_BACKGROUND_ALIGNMENT # Since 3.17
+ - CPACK_PRODUCTBUILD_BACKGROUND_SCALING # Since 3.17
+ - CPACK_PRODUCTBUILD_BACKGROUND_MIME_TYPE # Since 3.17
+ - CPACK_PRODUCTBUILD_BACKGROUND_UTI # Since 3.17
+ - CPACK_PRODUCTBUILD_BACKGROUND_DARKAQUA # Since 3.17
+ - CPACK_PRODUCTBUILD_BACKGROUND_DARKAQUA_ALIGNMENT # Since 3.17
+ - CPACK_PRODUCTBUILD_BACKGROUND_DARKAQUA_SCALING # Since 3.17
+ - CPACK_PRODUCTBUILD_BACKGROUND_DARKAQUA_MIME_TYPE # Since 3.17
+ - CPACK_PRODUCTBUILD_BACKGROUND_DARKAQUA_UTI # Since 3.17
# - CPackRPM
- CPACK_RPM_COMPONENT_INSTALL
- CPACK_RPM_PACKAGE_SUMMARY
@@ -1457,8 +1536,6 @@ variables:
# - CPack
- CPACK_PACKAGE_NAME
- CPACK_PACKAGE_VENDOR
- # `CPACK_PACKAGE_CONTACT` used by some modules (like Deb and NSIS),
- # but not documented yet...
- CPACK_PACKAGE_CONTACT
- CPACK_PACKAGE_DIRECTORY
- CPACK_PACKAGE_VERSION_MAJOR
@@ -1497,6 +1574,12 @@ variables:
- CPACK_PACKAGE_INSTALL_REGISTRY_KEY
- CPACK_CREATE_DESKTOP_LINKS
- CPACK_BINARY_<GENNAME>
+ # The following variables used by CPack and some CMake modules,
+ # but not documented (yet):
+ # used by some modules like Deb and NSIS
+ - CPACK_PACKAGE_CONTACT
+ # - used in CPack.cmake as default value for `CPACK_RPM_PACKAGE_RELOCATABLE`
+ - CPACK_PACKAGE_RELOCATABLE
# - CPackWIX
- CPACK_WIX_UPGRADE_GUID
- CPACK_WIX_PRODUCT_GUID
@@ -1554,6 +1637,7 @@ variables:
- PKG_CONFIG_EXECUTABLE
- PKG_CONFIG_VERSION_STRING
- PKG_CONFIG_USE_CMAKE_PREFIX_PATH
+ - <prefix>_MODULE_NAME # Since 3.16
# - FindThreads
- CMAKE_THREAD_LIBS_INIT
- CMAKE_USE_SPROC_INIT
@@ -1627,10 +1711,12 @@ environment-variables:
# Environment Variables that Control the Build
- CMAKE_BUILD_PARALLEL_LEVEL
- CMAKE_CONFIG_TYPE
+ - CMAKE_EXPORT_COMPILE_COMMANDS # Since 3.17
- CMAKE_GENERATOR
- CMAKE_GENERATOR_INSTANCE
- CMAKE_GENERATOR_PLATFORM
- CMAKE_GENERATOR_TOOLSET
+ - CMAKE_<LANG>_COMPILER_LAUNCHER # Since 3.17
- CMAKE_MSVCIDE_RUN_PATH
- CMAKE_NO_VERBOSE
- CMAKE_OSX_ARCHITECTURES
@@ -1897,6 +1983,8 @@ scripting-commands:
# New sub-options since 3.14
, READ_SYMLINK
, SIZE
+ # New sub-options since 3.16
+ , GET_RUNTIME_DEPENDENCIES
]
special-args: [
UTF-8
@@ -1996,12 +2084,25 @@ scripting-commands:
named-args: *find_library
-
name: foreach
- named-args: [RANGE, IN, LISTS, ITEMS]
+ named-args: [
+ RANGE
+ , IN
+ , LISTS
+ , ITEMS
+ , ZIP_LISTS # Since 3.17
+ ]
-
name: function
-
name: get_cmake_property
property-args: [global-properties]
+ special-args: [
+ COMMANDS
+ , COMPONENTS
+ , MACROS
+ , VARIABLES
+ , CACHE_VARIABLES
+ ]
-
name: get_directory_property
named-args: [DIRECTORY, DEFINITION]
@@ -2118,6 +2219,10 @@ scripting-commands:
, VERBOSE
, DEBUG
, TRACE
+ # Since 3.17
+ , CHECK_START
+ , CHECK_PASS
+ , CHECK_FAIL
]
-
name: option
@@ -2270,7 +2375,7 @@ project-commands:
named-args: [EXCLUDE_FROM_ALL]
-
name: add_test
- named-args: [NAME, COMMAND, CONFIGURATIONS, WORKING_DIRECTORY]
+ named-args: [NAME, COMMAND, COMMAND_EXPAND_LISTS, CONFIGURATIONS, WORKING_DIRECTORY]
nested-parentheses?: true
-
name: aux_source_directory
@@ -2287,7 +2392,22 @@ project-commands:
-
name: enable_language
named-args: [OPTIONAL]
- special-args: [C, CXX, RC, Fortran]
+ special-args: [
+ ASM
+ , ASM-ATT
+ , ASM_NASM
+ , ASM_MASM
+ , C
+ , CSharp
+ , CXX
+ , CUDA
+ , Java
+ , OBJC # Since 3.16
+ , OBJCXX # Since 3.16
+ , RC
+ , Fortran
+ , Swift
+ ]
-
name: enable_testing
-
@@ -2391,7 +2511,23 @@ project-commands:
, HOMEPAGE_URL # Since 3.12
, LANGUAGES
]
- special-args: [NONE, C, CXX, RC, CUDA, Fortran, ASM]
+ special-args: [
+ ASM
+ , ASM-ATT
+ , ASM_NASM
+ , ASM_MASM
+ , C
+ , CSharp
+ , CXX
+ , CUDA
+ , Java
+ , OBJC # Since 3.16
+ , OBJCXX # Since 3.16
+ , RC
+ , Fortran
+ , Swift
+ , NONE # This one is different from `enable_language`
+ ]
-
name: qt_wrap_cpp
-
@@ -2491,6 +2627,12 @@ project-commands:
, c_restrict
, c_static_assert
, c_variadic_macros
+ # CMAKE_CUDA_KNOWN_FEATURES (since 3.17)
+ , cuda_std_03
+ , cuda_std_11
+ , cuda_std_14
+ , cuda_std_17
+ , cuda_std_20
]
-
name: target_compile_options
@@ -2509,6 +2651,10 @@ project-commands:
name: target_link_options
named-args: *target_compile_definitions
-
+ # Since 3.16
+ name: target_precompile_headers
+ named-args: [INTERFACE, PUBLIC, PRIVATE, REUSE_FROM]
+ -
name: target_sources
named-args: *target_compile_definitions
-
@@ -2623,8 +2769,15 @@ ctest-commands:
, STOP_TIME
, RETURN_VALUE
, CAPTURE_CMAKE_ERROR
+ , REPEAT # Since 3.17
, QUIET
]
+ special-args: [
+ # Since 3.17
+ UNTIL_FAIL
+ , UNTIL_PASS
+ , AFTER_TIMEOUT
+ ]
-
name: ctest_update
named-args: [SOURCE, RETURN_VALUE, QUIET]
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 ff94189b81..c092d27f8f 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
@@ -48,6 +48,12 @@ def try_transform_placeholder_string_to_regex(name):
if 'CMAKE_ARGV' in m:
return '\\bCMAKE_ARGV[0-9]+\\b'
+ if 'CMAKE_POLICY_DEFAULT_CMP' in m:
+ return '\\bCMAKE_POLICY_DEFAULT_CMP[0-9]{4}\\b'
+
+ if 'CMAKE_POLICY_WARNING_CMP' in m:
+ return '\\bCMAKE_POLICY_WARNING_CMP[0-9]{4}\\b'
+
return '\\b{}\\b'.format('&id_re;'.join(list(m))) if 1 < len(m) else name
diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/cmake.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/cmake.xml
index def91cc4dd..1f476858fd 100644
--- a/src/libs/3rdparty/syntax-highlighting/data/syntax/cmake.xml
+++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/cmake.xml
@@ -9,7 +9,7 @@
Copyright 2004 Alexander Neundorf (neundorf@kde.org)
Copyright 2005 Dominik Haumann (dhdev@gmx.de)
Copyright 2007,2008,2013,2014 Matthew Woehlke (mw_triad@users.sourceforge.net)
- Copyright 2013-2015,2017-2019 Alex Turbov (i.zaufi@gmail.com)
+ Copyright 2013-2015,2017-2020 Alex Turbov (i.zaufi@gmail.com)
**********************************************************************
* This library is free software; you can redistribute it and/or *
@@ -31,7 +31,7 @@
<language
name="CMake"
- version="16"
+ version="22"
kateversion="2.4"
section="Other"
extensions="CMakeLists.txt;*.cmake;*.cmake.in"
@@ -133,6 +133,7 @@
<item>target_link_directories</item>
<item>target_link_libraries</item>
<item>target_link_options</item>
+ <item>target_precompile_headers</item>
<item>target_sources</item>
<item>try_compile</item>
<item>try_run</item>
@@ -292,6 +293,7 @@
<item>FOLLOW_SYMLINKS</item>
<item>FOLLOW_SYMLINK_CHAIN</item>
<item>GENERATE</item>
+ <item>GET_RUNTIME_DEPENDENCIES</item>
<item>GLOB</item>
<item>GLOB_RECURSE</item>
<item>GUARD</item>
@@ -479,6 +481,14 @@
<item>ITEMS</item>
<item>LISTS</item>
<item>RANGE</item>
+ <item>ZIP_LISTS</item>
+ </list>
+ <list name="get_cmake_property_sargs">
+ <item>CACHE_VARIABLES</item>
+ <item>COMMANDS</item>
+ <item>COMPONENTS</item>
+ <item>MACROS</item>
+ <item>VARIABLES</item>
</list>
<list name="get_directory_property_nargs">
<item>DEFINITION</item>
@@ -608,6 +618,9 @@
</list>
<list name="message_nargs">
<item>AUTHOR_WARNING</item>
+ <item>CHECK_FAIL</item>
+ <item>CHECK_PASS</item>
+ <item>CHECK_START</item>
<item>DEBUG</item>
<item>DEPRECATION</item>
<item>FATAL_ERROR</item>
@@ -800,6 +813,7 @@
</list>
<list name="add_test_nargs">
<item>COMMAND</item>
+ <item>COMMAND_EXPAND_LISTS</item>
<item>CONFIGURATIONS</item>
<item>NAME</item>
<item>WORKING_DIRECTORY</item>
@@ -828,10 +842,20 @@
<item>OPTIONAL</item>
</list>
<list name="enable_language_sargs">
+ <item>ASM</item>
+ <item>ASM-ATT</item>
+ <item>ASM_MASM</item>
+ <item>ASM_NASM</item>
<item>C</item>
+ <item>CSharp</item>
+ <item>CUDA</item>
<item>CXX</item>
<item>Fortran</item>
+ <item>Java</item>
+ <item>OBJC</item>
+ <item>OBJCXX</item>
<item>RC</item>
+ <item>Swift</item>
</list>
<list name="export_nargs">
<item>ANDROID_MK</item>
@@ -928,12 +952,20 @@
</list>
<list name="project_sargs">
<item>ASM</item>
+ <item>ASM-ATT</item>
+ <item>ASM_MASM</item>
+ <item>ASM_NASM</item>
<item>C</item>
+ <item>CSharp</item>
<item>CUDA</item>
<item>CXX</item>
<item>Fortran</item>
+ <item>Java</item>
<item>NONE</item>
+ <item>OBJC</item>
+ <item>OBJCXX</item>
<item>RC</item>
+ <item>Swift</item>
</list>
<list name="set_source_files_properties_nargs">
<item>PROPERTIES</item>
@@ -968,6 +1000,11 @@
<item>c_std_90</item>
<item>c_std_99</item>
<item>c_variadic_macros</item>
+ <item>cuda_std_03</item>
+ <item>cuda_std_11</item>
+ <item>cuda_std_14</item>
+ <item>cuda_std_17</item>
+ <item>cuda_std_20</item>
<item>cxx_aggregate_default_initializers</item>
<item>cxx_alias_templates</item>
<item>cxx_alignas</item>
@@ -1060,6 +1097,12 @@
<item>PRIVATE</item>
<item>PUBLIC</item>
</list>
+ <list name="target_precompile_headers_nargs">
+ <item>INTERFACE</item>
+ <item>PRIVATE</item>
+ <item>PUBLIC</item>
+ <item>REUSE_FROM</item>
+ </list>
<list name="target_sources_nargs">
<item>INTERFACE</item>
<item>PRIVATE</item>
@@ -1174,6 +1217,7 @@
<item>INCLUDE_LABEL</item>
<item>PARALLEL_LEVEL</item>
<item>QUIET</item>
+ <item>REPEAT</item>
<item>RETURN_VALUE</item>
<item>SCHEDULE_RANDOM</item>
<item>START</item>
@@ -1181,6 +1225,11 @@
<item>STRIDE</item>
<item>TEST_LOAD</item>
</list>
+ <list name="ctest_test_sargs">
+ <item>AFTER_TIMEOUT</item>
+ <item>UNTIL_FAIL</item>
+ <item>UNTIL_PASS</item>
+ </list>
<list name="ctest_update_nargs">
<item>QUIET</item>
<item>RETURN_VALUE</item>
@@ -1199,6 +1248,7 @@
<item>BUILD_SHARED_LIBS</item>
<item>BUILD_TESTING</item>
<item>CMAKE_ABSOLUTE_DESTINATION_FILES</item>
+ <item>CMAKE_AIX_EXPORT_ALL_SYMBOLS</item>
<item>CMAKE_ANDROID_ANT_ADDITIONAL_OPTIONS</item>
<item>CMAKE_ANDROID_API</item>
<item>CMAKE_ANDROID_API_MIN</item>
@@ -1235,6 +1285,7 @@
<item>CMAKE_AUTOMOC</item>
<item>CMAKE_AUTOMOC_DEPEND_FILTERS</item>
<item>CMAKE_AUTOMOC_MOC_OPTIONS</item>
+ <item>CMAKE_AUTOMOC_PATH_PREFIX</item>
<item>CMAKE_AUTOMOC_RELAXED_MODE</item>
<item>CMAKE_AUTORCC</item>
<item>CMAKE_AUTORCC_OPTIONS</item>
@@ -1268,13 +1319,23 @@
<item>CMAKE_CONFIGURATION_TYPES</item>
<item>CMAKE_CROSSCOMPILING</item>
<item>CMAKE_CROSSCOMPILING_EMULATOR</item>
+ <item>CMAKE_CROSS_CONFIGS</item>
+ <item>CMAKE_CTEST_ARGUMENTS</item>
<item>CMAKE_CTEST_COMMAND</item>
+ <item>CMAKE_CUDA_COMPILE_FEATURES</item>
<item>CMAKE_CUDA_EXTENSIONS</item>
+ <item>CMAKE_CUDA_HOST_COMPILER</item>
+ <item>CMAKE_CUDA_RESOLVE_DEVICE_SYMBOLS</item>
+ <item>CMAKE_CUDA_RUNTIME_LIBRARY</item>
<item>CMAKE_CUDA_SEPARABLE_COMPILATION</item>
<item>CMAKE_CUDA_STANDARD</item>
<item>CMAKE_CUDA_STANDARD_REQUIRED</item>
<item>CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES</item>
<item>CMAKE_CURRENT_BINARY_DIR</item>
+ <item>CMAKE_CURRENT_FUNCTION</item>
+ <item>CMAKE_CURRENT_FUNCTION_LIST_DIR</item>
+ <item>CMAKE_CURRENT_FUNCTION_LIST_FILE</item>
+ <item>CMAKE_CURRENT_FUNCTION_LIST_LINE</item>
<item>CMAKE_CURRENT_LIST_DIR</item>
<item>CMAKE_CURRENT_LIST_FILE</item>
<item>CMAKE_CURRENT_LIST_LINE</item>
@@ -1289,13 +1350,18 @@
<item>CMAKE_C_STANDARD_REQUIRED</item>
<item>CMAKE_DEBUG_POSTFIX</item>
<item>CMAKE_DEBUG_TARGET_PROPERTIES</item>
+ <item>CMAKE_DEFAULT_BUILD_TYPE</item>
+ <item>CMAKE_DEFAULT_CONFIGS</item>
<item>CMAKE_DEPENDS_IN_PROJECT_ONLY</item>
<item>CMAKE_DIRECTORY_LABELS</item>
+ <item>CMAKE_DISABLE_PRECOMPILE_HEADERS</item>
<item>CMAKE_DL_LIBS</item>
+ <item>CMAKE_DOTNET_TARGET_FRAMEWORK</item>
<item>CMAKE_DOTNET_TARGET_FRAMEWORK_VERSION</item>
<item>CMAKE_ECLIPSE_GENERATE_LINKED_RESOURCES</item>
<item>CMAKE_ECLIPSE_GENERATE_SOURCE_PROJECT</item>
<item>CMAKE_ECLIPSE_MAKE_ARGUMENTS</item>
+ <item>CMAKE_ECLIPSE_RESOURCE_ENCODING</item>
<item>CMAKE_ECLIPSE_VERSION</item>
<item>CMAKE_EDIT_COMMAND</item>
<item>CMAKE_ENABLE_EXPORTS</item>
@@ -1312,6 +1378,7 @@
<item>CMAKE_EXTRA_INCLUDE_FILES</item>
<item>CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES</item>
<item>CMAKE_FIND_APPBUNDLE</item>
+ <item>CMAKE_FIND_DEBUG_MODE</item>
<item>CMAKE_FIND_FRAMEWORK</item>
<item>CMAKE_FIND_FRAMEWORK_EXTRA_LOCATIONS</item>
<item>CMAKE_FIND_LIBRARY_CUSTOM_LIB_SUFFIX</item>
@@ -1331,6 +1398,13 @@
<item>CMAKE_FIND_ROOT_PATH_MODE_LIBRARY</item>
<item>CMAKE_FIND_ROOT_PATH_MODE_PACKAGE</item>
<item>CMAKE_FIND_ROOT_PATH_MODE_PROGRAM</item>
+ <item>CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH</item>
+ <item>CMAKE_FIND_USE_CMAKE_PATH</item>
+ <item>CMAKE_FIND_USE_CMAKE_SYSTEM_PATH</item>
+ <item>CMAKE_FIND_USE_PACKAGE_REGISTRY</item>
+ <item>CMAKE_FIND_USE_PACKAGE_ROOT_PATH</item>
+ <item>CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH</item>
+ <item>CMAKE_FIND_USE_SYSTEM_PACKAGE_REGISTRY</item>
<item>CMAKE_FOLDER</item>
<item>CMAKE_FRAMEWORK</item>
<item>CMAKE_FRAMEWORK_PATH</item>
@@ -1341,6 +1415,7 @@
<item>CMAKE_Fortran_MODULE_DIRECTORY</item>
<item>CMAKE_GENERATOR</item>
<item>CMAKE_GENERATOR_INSTANCE</item>
+ <item>CMAKE_GENERATOR_NO_COMPILER_ENV</item>
<item>CMAKE_GENERATOR_PLATFORM</item>
<item>CMAKE_GENERATOR_TOOLSET</item>
<item>CMAKE_GLOBAL_AUTOGEN_TARGET</item>
@@ -1405,6 +1480,7 @@
<item>CMAKE_INSTALL_OPENMP_LIBRARIES</item>
<item>CMAKE_INSTALL_PREFIX</item>
<item>CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT</item>
+ <item>CMAKE_INSTALL_REMOVE_ENVIRONMENT_RPATH</item>
<item>CMAKE_INSTALL_RPATH</item>
<item>CMAKE_INSTALL_RPATH_USE_LINK_PATH</item>
<item>CMAKE_INSTALL_RUNSTATEDIR</item>
@@ -1444,6 +1520,10 @@
<item>CMAKE_MAKE_PROGRAM</item>
<item>CMAKE_MATCH_COUNT</item>
<item>CMAKE_MAXIMUM_RECURSION_DEPTH</item>
+ <item>CMAKE_MESSAGE_CONTEXT</item>
+ <item>CMAKE_MESSAGE_CONTEXT_SHOW</item>
+ <item>CMAKE_MESSAGE_INDENT</item>
+ <item>CMAKE_MESSAGE_LOG_LEVEL</item>
<item>CMAKE_MFC_FLAG</item>
<item>CMAKE_MINIMUM_REQUIRED_VERSION</item>
<item>CMAKE_MINOR_VERSION</item>
@@ -1540,6 +1620,8 @@
<item>CMAKE_TRY_COMPILE_PLATFORM_VARIABLES</item>
<item>CMAKE_TRY_COMPILE_TARGET_TYPE</item>
<item>CMAKE_TWEAK_VERSION</item>
+ <item>CMAKE_UNITY_BUILD</item>
+ <item>CMAKE_UNITY_BUILD_BATCH_SIZE</item>
<item>CMAKE_USER_MAKE_RULES_OVERRIDE</item>
<item>CMAKE_USE_PTHREADS_INIT</item>
<item>CMAKE_USE_RELATIVE_PATHS</item>
@@ -1577,9 +1659,11 @@
<item>CMAKE_XCODE_PLATFORM_TOOLSET</item>
<item>CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER</item>
<item>CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN</item>
+ <item>CMAKE_XCODE_SCHEME_DEBUG_DOCUMENT_VERSIONING</item>
<item>CMAKE_XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER</item>
<item>CMAKE_XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS</item>
<item>CMAKE_XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE</item>
+ <item>CMAKE_XCODE_SCHEME_ENVIRONMENT</item>
<item>CMAKE_XCODE_SCHEME_GUARD_MALLOC</item>
<item>CMAKE_XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP</item>
<item>CMAKE_XCODE_SCHEME_MALLOC_GUARD_EDGES</item>
@@ -1589,6 +1673,7 @@
<item>CMAKE_XCODE_SCHEME_THREAD_SANITIZER_STOP</item>
<item>CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER</item>
<item>CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP</item>
+ <item>CMAKE_XCODE_SCHEME_WORKING_DIRECTORY</item>
<item>CMAKE_XCODE_SCHEME_ZOMBIE_OBJECTS</item>
<item>CPACK_ABSOLUTE_DESTINATION_FILES</item>
<item>CPACK_ARCHIVE_COMPONENT_INSTALL</item>
@@ -1704,6 +1789,7 @@
<item>CPACK_INSTALL_COMMANDS</item>
<item>CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS</item>
<item>CPACK_INSTALL_SCRIPT</item>
+ <item>CPACK_INSTALL_SCRIPTS</item>
<item>CPACK_MONOLITHIC_INSTALL</item>
<item>CPACK_NSIS_COMPRESSOR</item>
<item>CPACK_NSIS_CONTACT</item>
@@ -1715,6 +1801,8 @@
<item>CPACK_NSIS_EXTRA_INSTALL_COMMANDS</item>
<item>CPACK_NSIS_EXTRA_PREINSTALL_COMMANDS</item>
<item>CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS</item>
+ <item>CPACK_NSIS_FINISH_TITLE</item>
+ <item>CPACK_NSIS_FINISH_TITLE_3LINES</item>
<item>CPACK_NSIS_HELP_LINK</item>
<item>CPACK_NSIS_INSTALLED_ICON_NAME</item>
<item>CPACK_NSIS_INSTALLER_MUI_ICON_CODE</item>
@@ -1722,12 +1810,16 @@
<item>CPACK_NSIS_MENU_LINKS</item>
<item>CPACK_NSIS_MODIFY_PATH</item>
<item>CPACK_NSIS_MUI_FINISHPAGE_RUN</item>
+ <item>CPACK_NSIS_MUI_HEADERIMAGE</item>
<item>CPACK_NSIS_MUI_ICON</item>
<item>CPACK_NSIS_MUI_UNIICON</item>
<item>CPACK_NSIS_MUI_UNWELCOMEFINISHPAGE_BITMAP</item>
<item>CPACK_NSIS_MUI_WELCOMEFINISHPAGE_BITMAP</item>
<item>CPACK_NSIS_PACKAGE_NAME</item>
+ <item>CPACK_NSIS_UNINSTALL_NAME</item>
<item>CPACK_NSIS_URL_INFO_ABOUT</item>
+ <item>CPACK_NSIS_WELCOME_TITLE</item>
+ <item>CPACK_NSIS_WELCOME_TITLE_3LINES</item>
<item>CPACK_NUGET_COMPONENT_INSTALL</item>
<item>CPACK_NUGET_PACKAGE_AUTHORS</item>
<item>CPACK_NUGET_PACKAGE_COPYRIGHT</item>
@@ -1744,7 +1836,6 @@
<item>CPACK_NUGET_PACKAGE_TAGS</item>
<item>CPACK_NUGET_PACKAGE_TITLE</item>
<item>CPACK_NUGET_PACKAGE_VERSION</item>
- <item>CPACK_OSX_PACKAGE_VERSION</item>
<item>CPACK_OUTPUT_CONFIG_FILE</item>
<item>CPACK_PACKAGE_CHECKSUM</item>
<item>CPACK_PACKAGE_CONTACT</item>
@@ -1759,6 +1850,7 @@
<item>CPACK_PACKAGE_INSTALL_DIRECTORY</item>
<item>CPACK_PACKAGE_INSTALL_REGISTRY_KEY</item>
<item>CPACK_PACKAGE_NAME</item>
+ <item>CPACK_PACKAGE_RELOCATABLE</item>
<item>CPACK_PACKAGE_VENDOR</item>
<item>CPACK_PACKAGE_VERSION</item>
<item>CPACK_PACKAGE_VERSION_MAJOR</item>
@@ -1767,6 +1859,16 @@
<item>CPACK_PACKAGING_INSTALL_PREFIX</item>
<item>CPACK_PKGBUILD_IDENTITY_NAME</item>
<item>CPACK_PKGBUILD_KEYCHAIN_PATH</item>
+ <item>CPACK_PRODUCTBUILD_BACKGROUND</item>
+ <item>CPACK_PRODUCTBUILD_BACKGROUND_ALIGNMENT</item>
+ <item>CPACK_PRODUCTBUILD_BACKGROUND_DARKAQUA</item>
+ <item>CPACK_PRODUCTBUILD_BACKGROUND_DARKAQUA_ALIGNMENT</item>
+ <item>CPACK_PRODUCTBUILD_BACKGROUND_DARKAQUA_MIME_TYPE</item>
+ <item>CPACK_PRODUCTBUILD_BACKGROUND_DARKAQUA_SCALING</item>
+ <item>CPACK_PRODUCTBUILD_BACKGROUND_DARKAQUA_UTI</item>
+ <item>CPACK_PRODUCTBUILD_BACKGROUND_MIME_TYPE</item>
+ <item>CPACK_PRODUCTBUILD_BACKGROUND_SCALING</item>
+ <item>CPACK_PRODUCTBUILD_BACKGROUND_UTI</item>
<item>CPACK_PRODUCTBUILD_IDENTITY_NAME</item>
<item>CPACK_PRODUCTBUILD_KEYCHAIN_PATH</item>
<item>CPACK_PRODUCTBUILD_RESOURCES_DIR</item>
@@ -2024,6 +2126,7 @@
<item>CMAKE_APPBUNDLE_PATH</item>
<item>CMAKE_BUILD_PARALLEL_LEVEL</item>
<item>CMAKE_CONFIG_TYPE</item>
+ <item>CMAKE_EXPORT_COMPILE_COMMANDS</item>
<item>CMAKE_FRAMEWORK_PATH</item>
<item>CMAKE_GENERATOR</item>
<item>CMAKE_GENERATOR_INSTANCE</item>
@@ -2063,6 +2166,7 @@
<item>AUTOMOC_SOURCE_GROUP</item>
<item>AUTOMOC_TARGETS_FOLDER</item>
<item>AUTORCC_SOURCE_GROUP</item>
+ <item>CMAKE_CUDA_KNOWN_FEATURES</item>
<item>CMAKE_CXX_KNOWN_FEATURES</item>
<item>CMAKE_C_KNOWN_FEATURES</item>
<item>CMAKE_ROLE</item>
@@ -2132,6 +2236,7 @@
</list>
<list name="target-properties">
<item>ADDITIONAL_CLEAN_FILES</item>
+ <item>AIX_EXPORT_ALL_SYMBOLS</item>
<item>ALIASED_TARGET</item>
<item>ANDROID_ANT_ADDITIONAL_OPTIONS</item>
<item>ANDROID_API</item>
@@ -2161,6 +2266,7 @@
<item>AUTOMOC_EXECUTABLE</item>
<item>AUTOMOC_MACRO_NAMES</item>
<item>AUTOMOC_MOC_OPTIONS</item>
+ <item>AUTOMOC_PATH_PREFIX</item>
<item>AUTORCC</item>
<item>AUTORCC_EXECUTABLE</item>
<item>AUTORCC_OPTIONS</item>
@@ -2190,6 +2296,7 @@
<item>CUDA_EXTENSIONS</item>
<item>CUDA_PTX_COMPILATION</item>
<item>CUDA_RESOLVE_DEVICE_SYMBOLS</item>
+ <item>CUDA_RUNTIME_LIBRARY</item>
<item>CUDA_SEPARABLE_COMPILATION</item>
<item>CUDA_STANDARD</item>
<item>CUDA_STANDARD_REQUIRED</item>
@@ -2202,6 +2309,9 @@
<item>DEFINE_SYMBOL</item>
<item>DEPLOYMENT_ADDITIONAL_FILES</item>
<item>DEPLOYMENT_REMOTE_DIRECTORY</item>
+ <item>DEPRECATION</item>
+ <item>DISABLE_PRECOMPILE_HEADERS</item>
+ <item>DOTNET_TARGET_FRAMEWORK</item>
<item>DOTNET_TARGET_FRAMEWORK_VERSION</item>
<item>ENABLE_EXPORTS</item>
<item>EXCLUDE_FROM_ALL</item>
@@ -2236,6 +2346,7 @@
<item>IMPORT_SUFFIX</item>
<item>INCLUDE_DIRECTORIES</item>
<item>INSTALL_NAME_DIR</item>
+ <item>INSTALL_REMOVE_ENVIRONMENT_RPATH</item>
<item>INSTALL_RPATH</item>
<item>INSTALL_RPATH_USE_LINK_PATH</item>
<item>INTERFACE_AUTOUIC_OPTIONS</item>
@@ -2248,6 +2359,7 @@
<item>INTERFACE_LINK_LIBRARIES</item>
<item>INTERFACE_LINK_OPTIONS</item>
<item>INTERFACE_POSITION_INDEPENDENT_CODE</item>
+ <item>INTERFACE_PRECOMPILE_HEADERS</item>
<item>INTERFACE_SOURCES</item>
<item>INTERFACE_SYSTEM_INCLUDE_DIRECTORIES</item>
<item>INTERPROCEDURAL_OPTIMIZATION</item>
@@ -2280,10 +2392,14 @@
<item>NO_SONAME</item>
<item>NO_SYSTEM_FROM_IMPORTED</item>
<item>OSX_ARCHITECTURES</item>
+ <item>OSX_COMPATIBILITY_VERSION</item>
+ <item>OSX_CURRENT_VERSION</item>
<item>OUTPUT_NAME</item>
<item>PDB_NAME</item>
<item>PDB_OUTPUT_DIRECTORY</item>
<item>POSITION_INDEPENDENT_CODE</item>
+ <item>PRECOMPILE_HEADERS</item>
+ <item>PRECOMPILE_HEADERS_REUSE_FROM</item>
<item>PREFIX</item>
<item>PRIVATE_HEADER</item>
<item>PROJECT_LABEL</item>
@@ -2305,6 +2421,10 @@
<item>Swift_MODULE_DIRECTORY</item>
<item>Swift_MODULE_NAME</item>
<item>TYPE</item>
+ <item>UNITY_BUILD</item>
+ <item>UNITY_BUILD_BATCH_SIZE</item>
+ <item>UNITY_BUILD_CODE_AFTER_INCLUDE</item>
+ <item>UNITY_BUILD_CODE_BEFORE_INCLUDE</item>
<item>VERSION</item>
<item>VISIBILITY_INLINES_HIDDEN</item>
<item>VS_CONFIGURATION_TYPE</item>
@@ -2313,9 +2433,11 @@
<item>VS_DEBUGGER_ENVIRONMENT</item>
<item>VS_DEBUGGER_WORKING_DIRECTORY</item>
<item>VS_DESKTOP_EXTENSIONS_VERSION</item>
+ <item>VS_DOTNET_DOCUMENTATION_FILE</item>
<item>VS_DOTNET_REFERENCES</item>
<item>VS_DOTNET_REFERENCES_COPY_LOCAL</item>
<item>VS_DOTNET_TARGET_FRAMEWORK_VERSION</item>
+ <item>VS_DPI_AWARE</item>
<item>VS_GLOBAL_KEYWORD</item>
<item>VS_GLOBAL_PROJECT_TYPES</item>
<item>VS_GLOBAL_ROOTNAMESPACE</item>
@@ -2346,6 +2468,7 @@
<item>XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN</item>
<item>XCODE_SCHEME_ARGUMENTS</item>
<item>XCODE_SCHEME_DEBUG_AS_ROOT</item>
+ <item>XCODE_SCHEME_DEBUG_DOCUMENT_VERSIONING</item>
<item>XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER</item>
<item>XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS</item>
<item>XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE</item>
@@ -2360,6 +2483,7 @@
<item>XCODE_SCHEME_THREAD_SANITIZER_STOP</item>
<item>XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER</item>
<item>XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP</item>
+ <item>XCODE_SCHEME_WORKING_DIRECTORY</item>
<item>XCODE_SCHEME_ZOMBIE_OBJECTS</item>
<item>XCTEST</item>
</list>
@@ -2386,6 +2510,8 @@
<item>SKIP_AUTOMOC</item>
<item>SKIP_AUTORCC</item>
<item>SKIP_AUTOUIC</item>
+ <item>SKIP_PRECOMPILE_HEADERS</item>
+ <item>SKIP_UNITY_BUILD_INCLUSION</item>
<item>SYMBOLIC</item>
<item>Swift_DEPENDENCIES_FILE</item>
<item>Swift_DIAGNOSTICS_FILE</item>
@@ -2429,6 +2555,7 @@
<item>REQUIRED_FILES</item>
<item>RESOURCE_LOCK</item>
<item>RUN_SERIAL</item>
+ <item>SKIP_REGULAR_EXPRESSION</item>
<item>SKIP_RETURN_CODE</item>
<item>TIMEOUT</item>
<item>TIMEOUT_AFTER_MATCH</item>
@@ -2621,6 +2748,7 @@
<WordDetect String="target_link_directories" insensitive="true" attribute="Command" context="target_link_directories_ctx" />
<WordDetect String="target_link_libraries" insensitive="true" attribute="Command" context="target_link_libraries_ctx" />
<WordDetect String="target_link_options" insensitive="true" attribute="Command" context="target_link_options_ctx" />
+ <WordDetect String="target_precompile_headers" insensitive="true" attribute="Command" context="target_precompile_headers_ctx" />
<WordDetect String="target_sources" insensitive="true" attribute="Command" context="target_sources_ctx" />
<WordDetect String="try_compile" insensitive="true" attribute="Command" context="try_compile_ctx" />
<WordDetect String="try_run" insensitive="true" attribute="Command" context="try_run_ctx" />
@@ -2838,6 +2966,7 @@
</context>
<context attribute="Normal Text" lineEndContext="#stay" name="get_cmake_property_ctx_op">
<IncludeRules context="EndCmdPop2" />
+ <keyword attribute="Special Args" context="#stay" String="get_cmake_property_sargs" />
<keyword attribute="Property" context="#stay" String="global-properties" />
<IncludeRules context="Detect More global-properties" />
<IncludeRules context="User Function Args" />
@@ -3442,6 +3571,14 @@
<keyword attribute="Named Args" context="#stay" String="target_link_options_nargs" />
<IncludeRules context="User Function Args" />
</context>
+ <context attribute="Normal Text" lineEndContext="#stay" name="target_precompile_headers_ctx">
+ <DetectChar attribute="Normal Text" context="target_precompile_headers_ctx_op" char="(" />
+ </context>
+ <context attribute="Normal Text" lineEndContext="#stay" name="target_precompile_headers_ctx_op">
+ <IncludeRules context="EndCmdPop2" />
+ <keyword attribute="Named Args" context="#stay" String="target_precompile_headers_nargs" />
+ <IncludeRules context="User Function Args" />
+ </context>
<context attribute="Normal Text" lineEndContext="#stay" name="target_sources_ctx">
<DetectChar attribute="Normal Text" context="target_sources_ctx_op" char="(" />
</context>
@@ -3549,6 +3686,7 @@
<context attribute="Normal Text" lineEndContext="#stay" name="ctest_test_ctx_op">
<IncludeRules context="EndCmdPop2" />
<keyword attribute="Named Args" context="#stay" String="ctest_test_nargs" />
+ <keyword attribute="Special Args" context="#stay" String="ctest_test_sargs" />
<IncludeRules context="User Function Args" />
</context>
<context attribute="Normal Text" lineEndContext="#stay" name="ctest_update_ctx">
@@ -3645,9 +3783,9 @@
</context>
<context attribute="Normal Text" lineEndContext="#stay" name="Detect Builtin Variables">
+ <RegExpr attribute="Internal Name" context="#stay" String="\b_&id_re;\b" />
<keyword attribute="Builtin Variable" context="#stay" String="variables" insensitive="false" />
<IncludeRules context="Detect More Builtin Variables" />
- <RegExpr attribute="Internal Name" context="#stay" String="\b_&id_re;\b" />
</context>
<context attribute="Normal Text" lineEndContext="#stay" name="Detect More Builtin Variables">
@@ -3679,6 +3817,7 @@
<RegExpr attribute="Builtin Variable" context="#stay" String="\b&id_re;_LIBRARY_DIRS\b" />
<RegExpr attribute="Builtin Variable" context="#stay" String="\b&id_re;_VERSION_COUNT\b" />
<RegExpr attribute="Builtin Variable" context="#stay" String="\b&id_re;_VERSION_STRING\b" />
+ <RegExpr attribute="Builtin Variable" context="#stay" String="\b&id_re;_MODULE_NAME\b" />
<RegExpr attribute="Builtin Variable" context="#stay" String="\bCMAKE_&id_re;_POSTFIX\b" />
<RegExpr attribute="Builtin Variable" context="#stay" String="\bCMAKE_&id_re;_ANDROID_TOOLCHAIN_MACHINE\b" />
<RegExpr attribute="Builtin Variable" context="#stay" String="\bCMAKE_&id_re;_ANDROID_TOOLCHAIN_PREFIX\b" />
@@ -3751,8 +3890,8 @@
<RegExpr attribute="Builtin Variable" context="#stay" String="\bCMAKE_MODULE_LINKER_FLAGS_&id_re;\b" />
<RegExpr attribute="Builtin Variable" context="#stay" String="\bCMAKE_MODULE_LINKER_FLAGS_&id_re;_INIT\b" />
<RegExpr attribute="Builtin Variable" context="#stay" String="\bCMAKE_PDB_OUTPUT_DIRECTORY_&id_re;\b" />
- <RegExpr attribute="Builtin Variable" context="#stay" String="\bCMAKE_POLICY_DEFAULT_CMP&id_re;\b" />
- <RegExpr attribute="Builtin Variable" context="#stay" String="\bCMAKE_POLICY_WARNING_CMP&id_re;\b" />
+ <RegExpr attribute="Builtin Variable" context="#stay" String="\bCMAKE_POLICY_DEFAULT_CMP[0-9]{4}\b" />
+ <RegExpr attribute="Builtin Variable" context="#stay" String="\bCMAKE_POLICY_WARNING_CMP[0-9]{4}\b" />
<RegExpr attribute="Builtin Variable" context="#stay" String="\bCMAKE_PROJECT_&id_re;_INCLUDE\b" />
<RegExpr attribute="Builtin Variable" context="#stay" String="\bCMAKE_RUNTIME_OUTPUT_DIRECTORY_&id_re;\b" />
<RegExpr attribute="Builtin Variable" context="#stay" String="\bCMAKE_SHARED_LINKER_FLAGS_&id_re;\b" />
@@ -3771,7 +3910,7 @@
<RegExpr attribute="Builtin Variable" context="#stay" String="\bCPACK_COMPONENT_&id_re;_GROUP\b" />
<RegExpr attribute="Builtin Variable" context="#stay" String="\bCPACK_COMPONENT_&id_re;_HIDDEN\b" />
<RegExpr attribute="Builtin Variable" context="#stay" String="\bCPACK_COMPONENT_&id_re;_REQUIRED\b" />
- <RegExpr attribute="Builtin Variable" context="#stay" String="\bCPACK_COMPONENT_&id_re;_DESCRIPTION\b" />
+ <RegExpr attribute="Builtin Variable" context="#stay" String="\bCPACK_DEBIAN_&id_re;_DESCRIPTION\b" />
<RegExpr attribute="Builtin Variable" context="#stay" String="\bCPACK_DEBIAN_&id_re;_FILE_NAME\b" />
<RegExpr attribute="Builtin Variable" context="#stay" String="\bCPACK_DEBIAN_&id_re;_PACKAGE_ARCHITECTURE\b" />
<RegExpr attribute="Builtin Variable" context="#stay" String="\bCPACK_DEBIAN_&id_re;_PACKAGE_BREAKS\b" />
@@ -3791,6 +3930,7 @@
<RegExpr attribute="Builtin Variable" context="#stay" String="\bCPACK_DEBIAN_&id_re;_PACKAGE_SOURCE\b" />
<RegExpr attribute="Builtin Variable" context="#stay" String="\bCPACK_DEBIAN_&id_re;_PACKAGE_SUGGESTS\b" />
<RegExpr attribute="Builtin Variable" context="#stay" String="\bCPACK_DEBIAN_&id_re;_DEBUGINFO_PACKAGE\b" />
+ <RegExpr attribute="Builtin Variable" context="#stay" String="\bCPACK_DMG_&id_re;_FILE_NAME\b" />
<RegExpr attribute="Builtin Variable" context="#stay" String="\bCPACK_NSIS_&id_re;_INSTALL_DIRECTORY\b" />
<RegExpr attribute="Builtin Variable" context="#stay" String="\bCPACK_NUGET_&id_re;_PACKAGE_AUTHORS\b" />
<RegExpr attribute="Builtin Variable" context="#stay" String="\bCPACK_NUGET_&id_re;_PACKAGE_COPYRIGHT\b" />
@@ -3808,6 +3948,8 @@
<RegExpr attribute="Builtin Variable" context="#stay" String="\bCPACK_NUGET_&id_re;_PACKAGE_TITLE\b" />
<RegExpr attribute="Builtin Variable" context="#stay" String="\bCPACK_NUGET_&id_re;_PACKAGE_VERSION\b" />
<RegExpr attribute="Builtin Variable" context="#stay" String="\bCPACK_NUGET_PACKAGE_DEPENDENCIES_&id_re;_VERSION\b" />
+ <RegExpr attribute="Builtin Variable" context="#stay" String="\bCPACK_POSTFLIGHT_&id_re;_SCRIPT\b" />
+ <RegExpr attribute="Builtin Variable" context="#stay" String="\bCPACK_PREFLIGHT_&id_re;_SCRIPT\b" />
<RegExpr attribute="Builtin Variable" context="#stay" String="\bCPACK_RPM_&id_re;_DEFAULT_DIR_PERMISSIONS\b" />
<RegExpr attribute="Builtin Variable" context="#stay" String="\bCPACK_RPM_&id_re;_DEFAULT_FILE_PERMISSIONS\b" />
<RegExpr attribute="Builtin Variable" context="#stay" String="\bCPACK_RPM_&id_re;_DEFAULT_GROUP\b" />
@@ -3866,6 +4008,7 @@
<RegExpr attribute="Standard Environment Variable" context="#stay" String="\b&id_re;_ROOT\b" />
<RegExpr attribute="Standard Environment Variable" context="#stay" String="\bASM&id_re;\b" />
<RegExpr attribute="Standard Environment Variable" context="#stay" String="\bASM&id_re;FLAGS\b" />
+ <RegExpr attribute="Standard Environment Variable" context="#stay" String="\bCMAKE_&id_re;_COMPILER_LAUNCHER\b" />
<DetectIdentifier />
<DetectChar attribute="Environment Variable Substitution" context="#pop#pop" char="}" />
</context>
diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/html.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/html.xml
index 7f0d52b353..ecbd46624c 100644
--- a/src/libs/3rdparty/syntax-highlighting/data/syntax/html.xml
+++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/html.xml
@@ -3,9 +3,9 @@
[
<!ENTITY name "[A-Za-z_:][\w.:_-]*">
<!ENTITY attributeName "[A-Za-z_:*#\(\[][\)\]\w.:_-]*">
- <!ENTITY entref "&amp;(#[0-9]+|#[xX][0-9A-Fa-f]+|&name;);">
+ <!ENTITY entref "&amp;(?:#[0-9]+|#[xX][0-9A-Fa-f]+|&name;);">
]>
-<language name="HTML" version="9" kateversion="5.53" section="Markup" extensions="*.htm;*.html;*.shtml;*.shtm" mimetype="text/html" author="Wilbert Berendsen (wilbert@kde.nl)" license="LGPL" priority="10">
+<language name="HTML" version="11" kateversion="5.53" section="Markup" extensions="*.htm;*.html;*.shtml;*.shtm" mimetype="text/html" author="Wilbert Berendsen (wilbert@kde.nl)" license="LGPL" priority="10">
<highlighting>
<contexts>
@@ -33,37 +33,37 @@
</context>
<context name="FindHTMLTags" attribute="Normal Text" lineEndContext="#stay">
- <RegExpr attribute="Element" context="El Open" String="&lt;pre\b" insensitive="true" beginRegion="pre" />
- <RegExpr attribute="Element" context="El Open" String="&lt;div\b" insensitive="true" beginRegion="div" />
- <RegExpr attribute="Element" context="El Open" String="&lt;table\b" insensitive="true" beginRegion="table" />
- <RegExpr attribute="Element" context="El Open" String="&lt;ul\b" insensitive="true" beginRegion="ul" />
- <RegExpr attribute="Element" context="El Open" String="&lt;ol\b" insensitive="true" beginRegion="ol" />
- <RegExpr attribute="Element" context="El Open" String="&lt;dl\b" insensitive="true" beginRegion="dl" />
- <RegExpr attribute="Element" context="El Open" String="&lt;article\b" insensitive="true" beginRegion="article" />
- <RegExpr attribute="Element" context="El Open" String="&lt;aside\b" insensitive="true" beginRegion="aside" />
- <RegExpr attribute="Element" context="El Open" String="&lt;details\b" insensitive="true" beginRegion="details" />
- <RegExpr attribute="Element" context="El Open" String="&lt;figure\b" insensitive="true" beginRegion="figure" />
- <RegExpr attribute="Element" context="El Open" String="&lt;footer\b" insensitive="true" beginRegion="footer" />
- <RegExpr attribute="Element" context="El Open" String="&lt;header\b" insensitive="true" beginRegion="header" />
- <RegExpr attribute="Element" context="El Open" String="&lt;main\b" insensitive="true" beginRegion="main" />
- <RegExpr attribute="Element" context="El Open" String="&lt;nav\b" insensitive="true" beginRegion="nav" />
- <RegExpr attribute="Element" context="El Open" String="&lt;section\b" insensitive="true" beginRegion="section" />
+ <WordDetect attribute="Element" context="El Open" String="&lt;pre" insensitive="true" beginRegion="pre" />
+ <WordDetect attribute="Element" context="El Open" String="&lt;div" insensitive="true" beginRegion="div" />
+ <WordDetect attribute="Element" context="El Open" String="&lt;table" insensitive="true" beginRegion="table" />
+ <WordDetect attribute="Element" context="El Open" String="&lt;ul" insensitive="true" beginRegion="ul" />
+ <WordDetect attribute="Element" context="El Open" String="&lt;ol" insensitive="true" beginRegion="ol" />
+ <WordDetect attribute="Element" context="El Open" String="&lt;dl" insensitive="true" beginRegion="dl" />
+ <WordDetect attribute="Element" context="El Open" String="&lt;article" insensitive="true" beginRegion="article" />
+ <WordDetect attribute="Element" context="El Open" String="&lt;aside" insensitive="true" beginRegion="aside" />
+ <WordDetect attribute="Element" context="El Open" String="&lt;details" insensitive="true" beginRegion="details" />
+ <WordDetect attribute="Element" context="El Open" String="&lt;figure" insensitive="true" beginRegion="figure" />
+ <WordDetect attribute="Element" context="El Open" String="&lt;footer" insensitive="true" beginRegion="footer" />
+ <WordDetect attribute="Element" context="El Open" String="&lt;header" insensitive="true" beginRegion="header" />
+ <WordDetect attribute="Element" context="El Open" String="&lt;main" insensitive="true" beginRegion="main" />
+ <WordDetect attribute="Element" context="El Open" String="&lt;nav" insensitive="true" beginRegion="nav" />
+ <WordDetect attribute="Element" context="El Open" String="&lt;section" insensitive="true" beginRegion="section" />
<RegExpr attribute="Element" context="El Open" String="&lt;&name;" />
- <RegExpr attribute="Element" context="El Close" String="&lt;/pre\b" insensitive="true" endRegion="pre" />
- <RegExpr attribute="Element" context="El Close" String="&lt;/div\b" insensitive="true" endRegion="div" />
- <RegExpr attribute="Element" context="El Close" String="&lt;/table\b" insensitive="true" endRegion="table" />
- <RegExpr attribute="Element" context="El Close" String="&lt;/ul\b" insensitive="true" endRegion="ul" />
- <RegExpr attribute="Element" context="El Close" String="&lt;/ol\b" insensitive="true" endRegion="ol" />
- <RegExpr attribute="Element" context="El Close" String="&lt;/dl\b" insensitive="true" endRegion="dl" />
- <RegExpr attribute="Element" context="El Close" String="&lt;/article\b" insensitive="true" endRegion="article" />
- <RegExpr attribute="Element" context="El Close" String="&lt;/aside\b" insensitive="true" endRegion="aside" />
- <RegExpr attribute="Element" context="El Close" String="&lt;/details\b" insensitive="true" endRegion="details" />
- <RegExpr attribute="Element" context="El Close" String="&lt;/figure\b" insensitive="true" endRegion="figure" />
- <RegExpr attribute="Element" context="El Close" String="&lt;/footer\b" insensitive="true" endRegion="footer" />
- <RegExpr attribute="Element" context="El Close" String="&lt;/header\b" insensitive="true" endRegion="header" />
- <RegExpr attribute="Element" context="El Close" String="&lt;/main\b" insensitive="true" endRegion="main" />
- <RegExpr attribute="Element" context="El Close" String="&lt;/nav\b" insensitive="true" endRegion="nav" />
- <RegExpr attribute="Element" context="El Close" String="&lt;/section\b" insensitive="true" endRegion="section" />
+ <WordDetect attribute="Element" context="El Close" String="&lt;/pre" insensitive="true" endRegion="pre" />
+ <WordDetect attribute="Element" context="El Close" String="&lt;/div" insensitive="true" endRegion="div" />
+ <WordDetect attribute="Element" context="El Close" String="&lt;/table" insensitive="true" endRegion="table" />
+ <WordDetect attribute="Element" context="El Close" String="&lt;/ul" insensitive="true" endRegion="ul" />
+ <WordDetect attribute="Element" context="El Close" String="&lt;/ol" insensitive="true" endRegion="ol" />
+ <WordDetect attribute="Element" context="El Close" String="&lt;/dl" insensitive="true" endRegion="dl" />
+ <WordDetect attribute="Element" context="El Close" String="&lt;/article" insensitive="true" endRegion="article" />
+ <WordDetect attribute="Element" context="El Close" String="&lt;/aside" insensitive="true" endRegion="aside" />
+ <WordDetect attribute="Element" context="El Close" String="&lt;/details" insensitive="true" endRegion="details" />
+ <WordDetect attribute="Element" context="El Close" String="&lt;/figure" insensitive="true" endRegion="figure" />
+ <WordDetect attribute="Element" context="El Close" String="&lt;/footer" insensitive="true" endRegion="footer" />
+ <WordDetect attribute="Element" context="El Close" String="&lt;/header" insensitive="true" endRegion="header" />
+ <WordDetect attribute="Element" context="El Close" String="&lt;/main" insensitive="true" endRegion="main" />
+ <WordDetect attribute="Element" context="El Close" String="&lt;/nav" insensitive="true" endRegion="nav" />
+ <WordDetect attribute="Element" context="El Close" String="&lt;/section" insensitive="true" endRegion="section" />
<RegExpr attribute="Element" context="El Close" String="&lt;/&name;" />
</context>
@@ -85,7 +85,7 @@
</context>
<context name="FindDTDRules" attribute="Other Text" lineEndContext="#stay">
- <RegExpr attribute="Doctype" context="Doctype Markupdecl" String="&lt;!(ELEMENT|ENTITY|ATTLIST|NOTATION)\b" />
+ <RegExpr attribute="Doctype" context="Doctype Markupdecl" String="&lt;!(?:ELEMENT|ENTITY|ATTLIST|NOTATION)\b" />
</context>
@@ -94,7 +94,7 @@
<IncludeRules context="##Alerts" />
<DetectIdentifier/>
<StringDetect attribute="Comment" context="#pop" String="--&gt;" endRegion="comment" />
- <RegExpr attribute="Error" context="#stay" String="-(-(?!-&gt;))+" />
+ <RegExpr attribute="Error" context="#stay" String="-(?:-(?!-&gt;))+" />
</context>
<context name="CDATA" attribute="Other Text" lineEndContext="#stay">
@@ -172,7 +172,7 @@
</context>
<context name="JS" attribute="Other Text" lineEndContext="#stay">
- <RegExpr attribute="Attribute" context="Script-Type" String="(\s+|^)type(?=\=|\s|$)" insensitive="true"/>
+ <RegExpr attribute="Attribute" context="Script-Type" String="(?:\s+|^)type(?=\=|\s|$)" insensitive="true"/>
<DetectChar attribute="Element" context="JS content" char="&gt;" />
<IncludeRules context="DefaultJS" />
</context>
@@ -257,7 +257,7 @@
</context>
<context name="JSX content" attribute="Other Text" lineEndContext="#stay">
<IncludeRules context="Default JS content"/>
- <IncludeRules context="Normal##JavaScript React" includeAttrib="true"/>
+ <IncludeRules context="Normal##JavaScript React (JSX)" includeAttrib="true"/>
</context>
<context name="TypeScript" attribute="Other Text" lineEndContext="#stay">
@@ -310,7 +310,7 @@
</highlighting>
<general>
<comments>
- <comment name="multiLine" start="&lt;!--" end="--&gt;" />
+ <comment name="multiLine" start="&lt;!--" end="--&gt;" region="comment" />
</comments>
</general>
</language>
diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/makefile.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/makefile.xml
index 6067a2470f..db158d532f 100644
--- a/src/libs/3rdparty/syntax-highlighting/data/syntax/makefile.xml
+++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/makefile.xml
@@ -10,7 +10,7 @@
<!-- v4 by Alex Richardson <arichardson.kde@gmail.com>
added bmake support -->
<language name="Makefile" section="Other"
- version="7" kateversion="3.4"
+ version="9" kateversion="3.4"
extensions="GNUmakefile;Makefile;makefile;GNUmakefile.*;Makefile.*;makefile.*;*.mk"
mimetype="text/x-makefile" priority="11"
author="Per Wigren (wigren@home.se)" license="">
@@ -185,8 +185,8 @@
<keyword attribute="Keyword" context="bmake_for_loop" String="bmake_for_stmt" firstNonSpace="true" beginRegion="for"/>
<keyword attribute="Keyword" context="#stay" String="bmake_endfor_stmt" firstNonSpace="true" endRegion="for"/>
- <RegExpr attribute="Section" context="prereq" String="^\.[^.][^:]*:"/>
- <RegExpr attribute="Target" context="prereq" String="^[^:]*:"/>
+ <RegExpr attribute="Section" context="prereq" String="^\.[^.][^:]*:" column="0"/>
+ <RegExpr attribute="Target" context="prereq" String="^[^:]*:" column="0"/>
<DetectIdentifier/>
<DetectChar attribute="String" context="string&quot;" char="&quot;"/>
<DetectChar attribute="String" context="string'" char="'"/>
@@ -203,10 +203,16 @@
<DetectChar attribute="Comment" context="Comment" char="#"/>
</context>
- <context name="gmake_else" attribute="Error" lineEndContext="#pop">
+ <context name="gmake_else" attribute="Normal" lineEndContext="#pop">
<DetectSpaces attribute="Normal"/>
<keyword attribute="ControlFlow" String="gmake_if_keywords" context="#stay"/>
<IncludeRules context="strings_and_vars"/>
+ <Detect2Chars attribute="Special" context="#stay" char="\" char1="#"/>
+ <Detect2Chars attribute="Special" context="#stay" char="\" char1="\"/>
+ <!-- NOTE: Allow highlighting any variable name (see bug #417379), for example:
+ else ifdef foo
+ else ifeq (bar, foo)
+ -->
</context>
<context name="bmake_include" attribute="Normal" lineEndContext="#pop">
@@ -341,7 +347,8 @@
<DetectChar attribute="Operator" char=")" context="#pop#pop#pop"/>
<DetectChar attribute="Operator" context="dollar" char="$"/>
<DetectSpaces attribute="Error" context="#stay"/>
- <AnyChar attribute="Error" context="#stay" String="=#:"/>
+ <DetectChar attribute="RealOperator" context="SubstitutionRefs" char=":"/>
+ <AnyChar attribute="Error" context="#stay" String="=#"/>
</context>
<context name="callVar{" attribute="Variable" lineEndContext="#stay">
@@ -456,6 +463,16 @@
<DetectChar attribute="String" context="string'" char="'"/>
</context>
+ <!-- $(var:pattern=replacement) -->
+ <context name="SubstitutionRefs" attribute="VarModifier" lineEndContext="#stay">
+ <DetectChar attribute="RealOperator" context="#pop!SubstitutionRefsReplacement" char="="/>
+ <IncludeRules context="SubstitutionRefsReplacement"/>
+ </context>
+ <context name="SubstitutionRefsReplacement" attribute="VarModifier" lineEndContext="#stay">
+ <DetectChar attribute="Operator" char=")" context="#pop#pop#pop#pop"/>
+ <DetectChar attribute="Operator" context="dollar" char="$"/>
+ </context>
+
<context attribute="Comment" lineEndContext="#pop" name="Comment">
<LineContinue attribute="Comment" context="#stay" />
<IncludeRules context="##Alerts" />
diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/markdown.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/markdown.xml
index 7d11b34e6b..b47b1afcee 100644
--- a/src/libs/3rdparty/syntax-highlighting/data/syntax/markdown.xml
+++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/markdown.xml
@@ -40,10 +40,12 @@
<!-- emphasis text -->
<!ENTITY emphasisregex_ast "\*(?:&contentregex_ast;\*|\*{1,4}&contentregex_ast;\*(?!\*))">
<!ENTITY emphasisregex_und "\b_(?:&contentregex_und;_+|_{1,4}&contentregex_und;_)\b">
-<!-- links -->
+<!-- links.
+ Keep in sync with reStructuredText (rest) -->
<!ENTITY startlink "(?:https?|ftp)\://">
<!ENTITY link "&startlink;[^&quot;&gt;\s]+">
-<!-- link in normal text -->
+<!-- link in normal text.
+ Keep in sync with reStructuredText’s (rest) StandaloneHyperlink attribute -->
<!ENTITY implicitlink "\b&startlink;[^&quot;&gt;\s`\)]*[^\s!&quot;&apos;`\(\)\*,\.:;&lt;&gt;\?~\]\}\\](?=[[:punct:]]*(?:[\s\)]|$))">
<!-- references: [name], [name][id], [name][id] "title", [name](https://example.com) -->
<!ENTITY refchar "(?:\\.|[^\]\\])">
@@ -88,7 +90,7 @@
<!ENTITY checkbox "\[[ x]\](?=\s)">
]>
-<language name="Markdown" version="10" kateversion="5.53" section="Markup" extensions="*.md;*.mmd;*.markdown" priority="15" author="Darrin Yeager, Claes Holmerson" license="GPL,BSD">
+<language name="Markdown" version="11" kateversion="5.53" section="Markup" extensions="*.md;*.mmd;*.markdown" priority="15" author="Darrin Yeager, Claes Holmerson" license="GPL,BSD">
<highlighting>
<contexts>
<!-- Start of the Markdown document: find metadata or code block -->
@@ -392,7 +394,7 @@
</context>
<context attribute="Normal Text" lineEndContext="#stay" name="jsx-code">
<IncludeRules context="code"/>
- <IncludeRules context="Normal##JavaScript React" includeAttrib="true"/>
+ <IncludeRules context="Normal##JavaScript React (JSX)" includeAttrib="true"/>
</context>
<context attribute="Normal Text" lineEndContext="#stay" name="json-code">
<IncludeRules context="code"/>
diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/modelines.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/modelines.xml
index 0f3c882b6c..b39c136acc 100644
--- a/src/libs/3rdparty/syntax-highlighting/data/syntax/modelines.xml
+++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/modelines.xml
@@ -8,7 +8,7 @@
Copyright (c) 2012-2014 by Alex Turbov (i.zaufi@gmail.com)
-->
<language name="Modelines"
- version="4"
+ version="5"
kateversion="5.0"
section="Other"
extensions=""
@@ -130,10 +130,10 @@
<context name="Normal" attribute="Comment" lineEndContext="#pop">
<DetectSpaces />
<keyword String="ModelineStartKeyword" context="Modeline" attribute="Keyword" />
- <RegExpr String="kate-(mimetype|wildcard)\(.*\):" context="Modeline" attribute="Keyword" />
+ <RegExpr String="kate-(?:mimetype|wildcard)\(.*\):" context="Modeline" attribute="Keyword" />
</context>
- <context name="Modeline" attribute="Comment" lineEndContext="#pop">
+ <context name="Modeline" attribute="Comment" lineEndContext="#pop" fallthrough="true" fallthroughContext="#pop">
<DetectSpaces />
<keyword String="Booleans" context="Booleans" attribute="Variable" />
<keyword String="Integrals" context="Integrals" attribute="Variable" />
@@ -142,7 +142,7 @@
<LineContinue context="#pop" />
</context>
- <context name="Booleans" attribute="Comment" lineEndContext="#pop">
+ <context name="Booleans" attribute="Comment" lineEndContext="#pop" fallthrough="true" fallthroughContext="#pop">
<DetectSpaces />
<keyword String="True" attribute="Option ON" context="#stay" />
<keyword String="False" attribute="Option OFF" context="#stay" />
@@ -150,7 +150,7 @@
<LineContinue context="#pop" />
</context>
- <context name="Integrals" attribute="Comment" lineEndContext="#pop">
+ <context name="Integrals" attribute="Comment" lineEndContext="#pop" fallthrough="true" fallthroughContext="#pop">
<DetectSpaces />
<Int attribute="Number" context="#stay" />
<DetectChar char="&end;" context="#pop" attribute="Variable" />
@@ -164,13 +164,13 @@
<LineContinue context="#pop" />
</context>
- <context name="RemoveSpaces" attribute="Comment" lineEndContext="#pop">
+ <context name="RemoveSpaces" attribute="Comment" lineEndContext="#pop" fallthrough="true" fallthroughContext="#pop">
<DetectSpaces />
<keyword String="RemoveSpacesOptions" attribute="Value" context="#pop!RemoveSpacesEnd" />
<DetectChar char="&end;" context="#pop" attribute="Variable" />
<LineContinue context="#pop" />
</context>
- <context name="RemoveSpacesEnd" attribute="Comment" lineEndContext="#pop">
+ <context name="RemoveSpacesEnd" attribute="Comment" lineEndContext="#pop" fallthrough="true" fallthroughContext="#pop">
<DetectChar char="&end;" context="#pop" attribute="Variable" />
</context>
diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/perl.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/perl.xml
index c2d366d1f3..26c82cd66e 100644
--- a/src/libs/3rdparty/syntax-highlighting/data/syntax/perl.xml
+++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/perl.xml
@@ -39,7 +39,7 @@
Enhance tr/// and y/// support.
-->
-<language name="Perl" version="9" kateversion="2.4" section="Scripts" extensions="*.pl;*.PL;*.pm" mimetype="application/x-perl;text/x-perl" priority="5" author="Anders Lund (anders@alweb.dk)" license="LGPLv2">
+<language name="Perl" version="10" kateversion="2.4" section="Scripts" extensions="*.pl;*.PL;*.pm" mimetype="application/x-perl;text/x-perl" priority="5" author="Anders Lund (anders@alweb.dk)" license="LGPLv2">
<highlighting>
<list name="keywords">
<item>if</item>
@@ -252,6 +252,7 @@
<item>rewinddir</item>
<item>rindex</item>
<item>rmdir</item>
+ <item>say</item>
<item>scalar</item>
<item>seek</item>
<item>seekdir</item>
diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/powershell.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/powershell.xml
index 8208fd7aae..e5c1e44c45 100644
--- a/src/libs/3rdparty/syntax-highlighting/data/syntax/powershell.xml
+++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/powershell.xml
@@ -1,7 +1,7 @@
<!DOCTYPE language SYSTEM "language.dtd">
<language
name="PowerShell"
- version="4"
+ version="5"
kateversion="5.0"
extensions="*.ps1;*.ps1m;*.ps1d"
section="Scripts"
@@ -892,7 +892,12 @@
<RegExpr attribute="Symbol" context="Member" String="[.]{1,1}" />
<AnyChar attribute="Symbol" context="#stay" String=":!%&amp;()+,-/.*&lt;=&gt;?[]|~^&#59;"/>
</context>
+ <context attribute="String Char" lineEndContext="#stay" name="StringEscape">
+ <RegExpr attribute="String Char" String="`[`&quot;0abefnrtv]" context="#stay"/>
+ <RegExpr attribute="String Char" String="`u\{[0-9A-Fa-f]+\}" context="#stay"/>
+ </context>
<context attribute="String" lineEndContext="#pop" name="String">
+ <IncludeRules context="StringEscape"/>
<LineContinue attribute="String" context="#pop"/>
<DetectChar attribute="String" context="#pop" char="&quot;"/>
</context>
@@ -916,6 +921,7 @@
<itemData name="Function" defStyleNum="dsFunction" spellChecking="false"/>
<itemData name="Data Type" defStyleNum="dsDataType" spellChecking="false"/>
<itemData name="String" defStyleNum="dsString"/>
+ <itemData name="String Char" defStyleNum="dsChar" spellChecking="false"/>
<itemData name="HereString" defStyleNum="dsVerbatimString"/>
<itemData name="Comment" defStyleNum="dsComment"/>
<itemData name="Cmdlets" defStyleNum="dsBuiltIn" spellChecking="false"/>
diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/python.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/python.xml
index 33a313a694..2c0c24bf00 100644
--- a/src/libs/3rdparty/syntax-highlighting/data/syntax/python.xml
+++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/python.xml
@@ -1,5 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE language>
+<!DOCTYPE language SYSTEM "language.dtd"
+[
+ <!ENTITY digitPart "[0-9](?:_?[0-9])*">
+ <!ENTITY beforeDigit "(?&lt;![\.\w[:^ascii:]])">
+ <!ENTITY beforePointFloat "(?&lt;![\w[:^ascii:]])">
+]>
<!-- Python syntax highlightning v0.9 by Per Wigren -->
<!-- Python syntax highlighting v1.9 by Michael Bueker (improved keyword differentiation) -->
<!-- Python syntax highlighting v1.97 by Paul Giannaros -->
@@ -14,7 +19,7 @@
<!-- v2.07 add support for %prog and co, see bug 142832 -->
<!-- v2.08 add missing overloaders, new Python 3 statements, builtins, and keywords -->
<!-- v2.29 recognize escape sequenzes correctly -->
-<language name="Python" version="9" style="python" indenter="python" kateversion="5.0" section="Scripts" extensions="*.py;*.pyw;SConstruct;SConscript" mimetype="application/x-python;text/x-python;text/x-python3" casesensitive="1" author="Michael Bueker" license="">
+<language name="Python" version="11" style="python" indenter="python" kateversion="5.0" section="Scripts" extensions="*.py;*.pyw;SConstruct;SConscript;*.FCMacro" mimetype="application/x-python;text/x-python;text/x-python3" casesensitive="1" author="Michael Bueker" license="">
<highlighting>
<list name="import">
<item>import</item>
@@ -65,6 +70,7 @@
<item>ascii</item>
<item>basestring</item>
<item>bin</item>
+ <item>breakpoint</item>
<item>bool</item>
<item>buffer</item>
<item>bytearray</item>
@@ -342,15 +348,17 @@
<keyword attribute="Overloaders" String="overloaders" context="#stay"/>
<RegExpr attribute="Normal Text" String="[a-zA-Z_][a-zA-Z_0-9]{2,}" context="#stay"/>
- <RegExpr attribute="Complex" String=" ((([0-9]*\.[0-9]+|[0-9]+\.)|([0-9]+|([0-9]*\.[0-9]+|[0-9]+\.))[eE](\+|-)?[0-9]+)|[0-9]+)[jJ]" context="#stay"/>
- <Float attribute="Float" context="#stay" />
- <HlCHex attribute="Hex" context="#stay"/>
- <HlCOct attribute="Octal" context="#stay"/>
- <Int attribute="Int" context="Int Suffixes"/>
-
- <RegExpr attribute="Int" String=" ([0-9]+_)+[0-9]+" context="#stay"/>
- <RegExpr attribute="Float" String=" ([0-9]+_)+[0-9]+\.[0-9]+" context="#stay"/>
- <RegExpr attribute="Hex" String=" [0-9]x([A-F0-9]+_)+[A-F0-9]+" context="#stay"/>
+ <!-- Complex: 1j ; 1.1j ; 1.j ; .1j ; 1e3j ; 1.1e3j ; 1.e3j ; .1e3j -->
+ <RegExpr attribute="Complex" String="(?:&beforeDigit;&digitPart;(?:\.(?:&digitPart;)?)?|&beforePointFloat;\.&digitPart;)(?:[eE][\+\-]?&digitPart;)?[jJ]\b" context="#stay"/>
+ <!-- Hexadecimal: 0xA1, Binary: 0b01, Octal: 0o71 -->
+ <RegExpr attribute="Hex" String="&beforeDigit;0[xX](?:_?[\da-fA-F])+\b" context="#stay"/>
+ <RegExpr attribute="Binary" String="&beforeDigit;0[bB](?:_?[01])+\b" context="#stay"/>
+ <RegExpr attribute="Octal" String="&beforeDigit;0[oO](?:_?[0-7])+\b" context="#stay"/>
+ <!-- Float: 1.1 ; 1. ; .1 ; 1e3 ; 1.1e3 ; 1.e3 ; .1e3 -->
+ <RegExpr attribute="Float" String="(?:&beforeDigit;&digitPart;(?:\.(?:&digitPart;)?)?|&beforePointFloat;\.&digitPart;)[eE][\+\-]?&digitPart;\b" context="#stay"/>
+ <RegExpr attribute="Float" String="(?:&beforeDigit;&digitPart;\.(?:&digitPart;\b)?|&beforePointFloat;\.&digitPart;\b)" context="#stay"/>
+ <!-- Decimal: 123 ; 000 -->
+ <RegExpr attribute="Int" String="&beforeDigit;(?:[1-9](?:_?\d)*|0(?:_?0)*)[lL]?\b" context="#stay"/>
<DetectChar attribute="Normal Text" char="{" context="Dictionary" beginRegion="Dictionary"/>
<DetectChar attribute="Normal Text" char="[" context="List" beginRegion="List"/>
@@ -362,14 +370,10 @@
<IncludeRules context="StringVariants" />
- <RegExpr attribute="Decorator" String="@[_a-zA-Z][\._a-zA-Z0-9]*" firstNonSpace="true"/>
+ <RegExpr attribute="Decorator" String="@[_a-zA-Z[:^ascii:]][\._a-zA-Z0-9[:^ascii:]]*" firstNonSpace="true"/>
<AnyChar attribute="Operator" String="+*/%\|=;\!&lt;&gt;!^&amp;~-@" context="#stay"/>
</context>
- <context name="Int Suffixes" attribute="Int" lineEndContext="#pop" fallthrough="true" fallthroughContext="#pop">
- <StringDetect attribute="Int" context="#pop" String="L" insensitive="true"/>
- </context>
-
<context name="#CheckForString" attribute="Normal Text" lineEndContext="#pop" fallthrough="true" fallthroughContext="#pop">
<DetectSpaces/>
<LineContinue attribute="Normal Text" context="CheckForStringNext"/>
@@ -661,6 +665,7 @@
<itemData name="Int" defStyleNum="dsDecVal" spellChecking="false"/>
<itemData name="Hex" defStyleNum="dsBaseN" spellChecking="false"/>
<itemData name="Octal" defStyleNum="dsBaseN" spellChecking="false"/>
+ <itemData name="Binary" defStyleNum="dsBaseN" spellChecking="false"/>
<itemData name="Complex" defStyleNum="dsOthers" spellChecking="false"/>
<itemData name="Comment" defStyleNum="dsComment"/>
<itemData name="String" defStyleNum="dsString"/>
diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/xml.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/xml.xml
index ad34a450b6..ddfc4e705f 100644
--- a/src/libs/3rdparty/syntax-highlighting/data/syntax/xml.xml
+++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/xml.xml
@@ -4,9 +4,9 @@
<!-- names must start with a letter, ideogram or underscore. \w matches any
word character *or* a number, hence the lookahead -->
<!ENTITY name "(?![0-9])[\w_:][\w.:_-]*">
- <!ENTITY entref "&amp;(#[0-9]+|#[xX][0-9A-Fa-f]+|&name;);">
+ <!ENTITY entref "&amp;(?:#[0-9]+|#[xX][0-9A-Fa-f]+|&name;);">
]>
-<language name="XML" version="9" kateversion="3.4" section="Markup" extensions="*.docbook;*.xml;*.rc;*.daml;*.rdf;*.rss;*.xspf;*.xsd;*.svg;*.ui;*.kcfg;*.qrc;*.wsdl;*.scxml;*.xbel;*.dae;*.sch;*.brd" mimetype="text/xml;text/book;text/daml;text/rdf;application/rss+xml;application/xspf+xml;image/svg+xml;application/x-designer;application/x-xbel;application/xml;application/scxml+xml" casesensitive="1" indenter="xml" author="Wilbert Berendsen (wilbert@kde.nl)" license="LGPL">
+<language name="XML" version="10" kateversion="3.4" section="Markup" extensions="*.docbook;*.xml;*.rc;*.daml;*.rdf;*.rss;*.xspf;*.xsd;*.svg;*.ui;*.kcfg;*.qrc;*.wsdl;*.scxml;*.xbel;*.dae;*.sch;*.brd" mimetype="text/xml;text/book;text/daml;text/rdf;application/rss+xml;application/xspf+xml;image/svg+xml;application/x-designer;application/x-xbel;application/xml;application/scxml+xml" casesensitive="1" indenter="xml" author="Wilbert Berendsen (wilbert@kde.nl)" license="LGPL">
<highlighting>
<contexts>
@@ -40,8 +40,9 @@
<context name="Comment" attribute="Comment" lineEndContext="#stay">
<DetectSpaces />
<StringDetect attribute="Comment" context="#pop" String="--&gt;" endRegion="comment" />
- <RegExpr attribute="Error" context="#stay" String="-(-(?!-&gt;))+" />
+ <RegExpr attribute="Error" context="#stay" String="-(?:\-(?!-&gt;))+" />
<IncludeRules context="##Alerts" />
+ <IncludeRules context="##Modelines" />
<DetectIdentifier />
</context>
@@ -63,7 +64,7 @@
<context name="Doctype Internal Subset" attribute="Other Text" lineEndContext="#stay">
<DetectChar attribute="Doctype" context="#pop" char="]" endRegion="int_subset" />
- <RegExpr attribute="Doctype" context="Doctype Markupdecl" String="&lt;!(ELEMENT|ENTITY|ATTLIST|NOTATION)\b" />
+ <RegExpr attribute="Doctype" context="Doctype Markupdecl" String="&lt;!(?:ELEMENT|ENTITY|ATTLIST|NOTATION)\b" />
<StringDetect attribute="Comment" context="Comment" String="&lt;!--" beginRegion="comment" />
<RegExpr attribute="Processing Instruction" context="PI" String="&lt;\?[\w:_-]*" beginRegion="pi" />
<IncludeRules context="FindPEntityRefs" />
@@ -88,8 +89,7 @@
<context name="Element" attribute="Other Text" lineEndContext="#stay">
<Detect2Chars attribute="Element" context="#pop" char="/" char1="&gt;" endRegion="element" />
<DetectChar attribute="Element" context="El Content" char="&gt;" />
- <RegExpr attribute="Attribute" context="Attribute" String="^&name;" />
- <RegExpr attribute="Attribute" context="Attribute" String="\s+&name;" />
+ <RegExpr attribute="Attribute" context="Attribute" String="(?:^|\s+)&name;" />
<RegExpr attribute="Error" context="#stay" String="\S" />
</context>
@@ -143,7 +143,7 @@
</highlighting>
<general>
<comments>
- <comment name="multiLine" start="&lt;!--" end="--&gt;" />
+ <comment name="multiLine" start="&lt;!--" end="--&gt;" region="comment" />
</comments>
</general>
</language>
diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/yacc.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/yacc.xml
index 06d6492ff1..ecb1a0d6a2 100644
--- a/src/libs/3rdparty/syntax-highlighting/data/syntax/yacc.xml
+++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/yacc.xml
@@ -12,12 +12,12 @@ This code is released under the LGPL as part of kdelibs/kate.
== UPDATE HISTORY ==
2018-02-20 // Nibaldo González <nibgonz@gmail.com>
- Fix '$' symbol, highlighted as 'dsError' by C++ (isocpp.xml).
+ Fix '$' symbol, highlighted as 'dsError' by C++ (isocpp.xml).
Update syntax for Bison (3.0.4):
- Add declarations, directives in rules and the '@' variable.
- - Allow a tag in '%union', declarations in multiple lines and
+ - Allow a tag in '%union', declarations in multiple lines and
grammar declarations in the grammar rules section.
- - The ';' char is not necessary to finish a rule. Allow '; |'
+ - The ';' char is not necessary to finish a rule. Allow '; |'
within rules.
Add mimetypes and extensions '*.ypp' & '*.y++'.
@@ -32,7 +32,7 @@ This code is released under the LGPL as part of kdelibs/kate.
========================================================================
-->
-<language name="Yacc/Bison" version="5" kateversion="5.0" section="Sources" extensions="*.y;*.yy;*.ypp;*.y++" mimetype="text/x-yacc;text/x-bison" priority="5" author="Jan Villat (jan.villat@net2000.ch)" license="LGPL">
+<language name="Yacc/Bison" version="6" kateversion="5.0" section="Sources" extensions="*.y;*.yy;*.ypp;*.y++" mimetype="text/x-yacc;text/x-bison" priority="5" author="Jan Villat (jan.villat@net2000.ch)" license="LGPL">
<highlighting>
<contexts>
@@ -62,7 +62,7 @@ This code is released under the LGPL as part of kdelibs/kate.
<WordDetect attribute="Directive" context="Percent Command In" String="%&lt;flag&gt;" />
<!-- Any word followed by '%' (End with ';' or '%') -->
<DetectChar attribute="Directive" context="Percent Command" char="%" />
- </context>
+ </context>
<context name="Grammar Declarations" attribute="Normal Text" lineEndContext="#stay">
<WordDetect attribute="Directive" context="Union Start" String="%union" />
<WordDetect attribute="Directive" context="Union Start" String="%code" />
@@ -74,7 +74,7 @@ This code is released under the LGPL as part of kdelibs/kate.
<IncludeRules context="Comment" />
<DetectSpaces />
<DetectChar attribute="Normal Text" context="Union In" char="{" beginRegion="union" />
- <RegExpr attribute="Normal Text" context="#pop!Union Tag" String="[^\s\{](?=(\s|$|//))" />
+ <RegExpr attribute="Normal Text" context="#pop!Union Tag" String="[^\s\{](?=\s|$|//)" />
</context>
<context name="Union Tag" attribute="Normal Text" lineEndContext="#stay">
<IncludeRules context="Comment" />
@@ -141,9 +141,9 @@ This code is released under the LGPL as part of kdelibs/kate.
<!-- Finish rule without the ';' character (see the 'rhses.1' rule in the 'src/parse-gram.y' file, from the Bison source) -->
<RegExpr attribute="Open Rule" context="#pop" String="[\w\-\.](?=[\w\-\.]*:)" column="0" endRegion="rule" />
<Detect2Chars attribute="Content-Type Delimiter" context="#pop" char="%" char1="%" lookAhead="true" firstNonSpace="true" endRegion="rule" />
- <RegExpr attribute="Directive" context="#pop" String="%(union|code|destructor|printer|start|(no\-)?default\-prec|nterm|token|type|left|right|nonassoc|precedence)\b" lookAhead="true" column="0" endRegion="rule" />
+ <RegExpr attribute="Directive" context="#pop" String="%(?:union|code|destructor|printer|start|(?:no\-)?default\-prec|nterm|token|type|left|right|nonassoc|precedence)\b" lookAhead="true" column="0" endRegion="rule" />
</context>
- <!-- The Bison parser allows to have ';' followed by '|', without the rule ending.
+ <!-- The Bison parser allows to have ';' followed by '|', without the rule ending.
The problem here is that the ';' char has endRegion="rule" (although it is not very relevant). -->
<context name="Rule End" attribute="Normal Text" lineEndContext="#stay" fallthrough="true" fallthroughContext="#pop#pop">
<DetectSpaces />
@@ -164,7 +164,7 @@ This code is released under the LGPL as part of kdelibs/kate.
<WordDetect attribute="Directive" context="Percent Command In" String="%left" />
<WordDetect attribute="Directive" context="Percent Command In" String="%right" />
<WordDetect attribute="Directive" context="Percent Command In" String="%nonassoc" />
- <WordDetect attribute="Directive" context="Percent Command In" String="%precedence" />
+ <WordDetect attribute="Directive" context="Percent Command In" String="%precedence" />
<DetectChar attribute="Rule" context="#pop" char="%" /> <!-- End when there is an invalid declaration -->
<DetectChar attribute="Normal Text" context="#pop" char=";" />
@@ -195,11 +195,11 @@ This code is released under the LGPL as part of kdelibs/kate.
</context>
<context name="Comment" attribute="Comment" lineEndContext="#stay">
- <Detect2Chars attribute="Comment" context="CommentStar" char="/" char1="*" />
+ <Detect2Chars attribute="Comment" context="CommentStar" char="/" char1="*" beginRegion="comment" />
<Detect2Chars attribute="Comment" context="CommentSlash" char="/" char1="/" />
</context>
<context name="CommentStar" attribute="Comment" lineEndContext="#stay">
- <Detect2Chars attribute="Comment" context="#pop" char="*" char1="/" />
+ <Detect2Chars attribute="Comment" context="#pop" char="*" char1="/" endRegion="comment" />
<IncludeRules context="##Alerts" />
<IncludeRules context="##Modelines" />
</context>
@@ -229,7 +229,7 @@ This code is released under the LGPL as part of kdelibs/kate.
</context>
<context name="Symbol-Variable" attribute="Normal Text" lineEndContext="#stay">
<DetectChar attribute="Directive" context="Dol" char="$" />
- <RegExpr attribute="Directive" context="#stay" String="@(\$?)(\d+|[A-Za-z_]\w*)?" />
+ <RegExpr attribute="Directive" context="#stay" String="@\$?(?:\d+|[A-Za-z_]\w*)?" />
</context>
<context name="Dol" attribute="Normal Text" fallthrough="true" fallthroughContext="DolEnd" lineEndContext="#stay">
<RegExpr attribute="Data Type" context="DolEnd" String="&lt;[^&gt;]+&gt;" />
@@ -259,7 +259,7 @@ This code is released under the LGPL as part of kdelibs/kate.
</highlighting>
<general>
<comments>
- <comment name="multiLine" start="/*" end="*/" />
+ <comment name="multiLine" start="/*" end="*/" region="comment" />
<comment name="singleLine" start="//" />
</comments>
</general>
diff --git a/src/libs/3rdparty/syntax-highlighting/examples/CMakeLists.txt b/src/libs/3rdparty/syntax-highlighting/examples/CMakeLists.txt
deleted file mode 100644
index 652b72cb0a..0000000000
--- a/src/libs/3rdparty/syntax-highlighting/examples/CMakeLists.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-if(Qt5Widgets_FOUND)
- add_executable(codeeditor codeeditor.cpp main.cpp)
- target_link_libraries(codeeditor Qt5::Widgets KF5SyntaxHighlighting)
-endif()
diff --git a/src/libs/3rdparty/syntax-highlighting/examples/codeeditor.cpp b/src/libs/3rdparty/syntax-highlighting/examples/codeeditor.cpp
deleted file mode 100644
index 88f315462d..0000000000
--- a/src/libs/3rdparty/syntax-highlighting/examples/codeeditor.cpp
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
- Copyright (C) 2016 Volker Krause <vkrause@kde.org>
-
- Permission is hereby granted, free of charge, to any person obtaining
- a copy of this software and associated documentation files (the
- "Software"), to deal in the Software without restriction, including
- without limitation the rights to use, copy, modify, merge, publish,
- distribute, sublicense, and/or sell copies of the Software, and to
- permit persons to whom the Software is furnished to do so, subject to
- the following conditions:
-
- The above copyright notice and this permission notice shall be included
- in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
-
-#include "codeeditor.h"
-
-#include <definition.h>
-#include <foldingregion.h>
-#include <syntaxhighlighter.h>
-#include <theme.h>
-
-#include <QApplication>
-#include <QDebug>
-#include <QFile>
-#include <QFileDialog>
-#include <QFontDatabase>
-#include <QMenu>
-#include <QPainter>
-#include <QPalette>
-
-class CodeEditorSidebar : public QWidget
-{
- Q_OBJECT
-public:
- explicit CodeEditorSidebar(CodeEditor *editor);
- QSize sizeHint() const Q_DECL_OVERRIDE;
-
-protected:
- void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE;
- void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
-
-private:
- CodeEditor *m_codeEditor;
-};
-
-CodeEditorSidebar::CodeEditorSidebar(CodeEditor *editor) :
- QWidget(editor),
- m_codeEditor(editor)
-{
-}
-
-QSize CodeEditorSidebar::sizeHint() const
-{
- return QSize(m_codeEditor->sidebarWidth(), 0);
-}
-
-void CodeEditorSidebar::paintEvent(QPaintEvent *event)
-{
- m_codeEditor->sidebarPaintEvent(event);
-}
-
-void CodeEditorSidebar::mouseReleaseEvent(QMouseEvent *event)
-{
- if (event->x() >= width() - m_codeEditor->fontMetrics().lineSpacing()) {
- auto block = m_codeEditor->blockAtPosition(event->y());
- if (!block.isValid() || !m_codeEditor->isFoldable(block))
- return;
- m_codeEditor->toggleFold(block);
- }
- QWidget::mouseReleaseEvent(event);
-}
-
-
-CodeEditor::CodeEditor(QWidget *parent) :
- QPlainTextEdit(parent),
- m_highlighter(new KSyntaxHighlighting::SyntaxHighlighter(document())),
- m_sideBar(new CodeEditorSidebar(this))
-{
- setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
-
- setTheme((palette().color(QPalette::Base).lightness() < 128)
- ? m_repository.defaultTheme(KSyntaxHighlighting::Repository::DarkTheme)
- : m_repository.defaultTheme(KSyntaxHighlighting::Repository::LightTheme));
-
- connect(this, &QPlainTextEdit::blockCountChanged, this, &CodeEditor::updateSidebarGeometry);
- connect(this, &QPlainTextEdit::updateRequest, this, &CodeEditor::updateSidebarArea);
- connect(this, &QPlainTextEdit::cursorPositionChanged, this, &CodeEditor::highlightCurrentLine);
-
- updateSidebarGeometry();
- highlightCurrentLine();
-}
-
-CodeEditor::~CodeEditor()
-{
-}
-
-void CodeEditor::openFile(const QString& fileName)
-{
- QFile f(fileName);
- if (!f.open(QFile::ReadOnly)) {
- qWarning() << "Failed to open" << fileName << ":" << f.errorString();
- return;
- }
-
- clear();
-
- const auto def = m_repository.definitionForFileName(fileName);
- m_highlighter->setDefinition(def);
-
- setWindowTitle(fileName);
- setPlainText(QString::fromUtf8(f.readAll()));
-}
-
-void CodeEditor::contextMenuEvent(QContextMenuEvent *event)
-{
- auto menu = createStandardContextMenu(event->pos());
- menu->addSeparator();
- auto openAction = menu->addAction(QStringLiteral("Open File..."));
- connect(openAction, &QAction::triggered, this, [this]() {
- const auto fileName = QFileDialog::getOpenFileName(this, QStringLiteral("Open File"));
- if (!fileName.isEmpty())
- openFile(fileName);
- });
-
- // syntax selection
- auto hlActionGroup = new QActionGroup(menu);
- hlActionGroup->setExclusive(true);
- auto hlGroupMenu = menu->addMenu(QStringLiteral("Syntax"));
- QMenu *hlSubMenu = hlGroupMenu;
- QString currentGroup;
- foreach (const auto &def, m_repository.definitions()) {
- if (def.isHidden())
- continue;
- if (currentGroup != def.section()) {
- currentGroup = def.section();
- hlSubMenu = hlGroupMenu->addMenu(def.translatedSection());
- }
-
- Q_ASSERT(hlSubMenu);
- auto action = hlSubMenu->addAction(def.translatedName());
- action->setCheckable(true);
- action->setData(def.name());
- hlActionGroup->addAction(action);
- if (def.name() == m_highlighter->definition().name())
- action->setChecked(true);
- }
- connect(hlActionGroup, &QActionGroup::triggered, this, [this](QAction *action) {
- const auto defName = action->data().toString();
- const auto def = m_repository.definitionForName(defName);
- m_highlighter->setDefinition(def);
- });
-
- // theme selection
- auto themeGroup = new QActionGroup(menu);
- themeGroup->setExclusive(true);
- auto themeMenu = menu->addMenu(QStringLiteral("Theme"));
- foreach (const auto &theme, m_repository.themes()) {
- auto action = themeMenu->addAction(theme.translatedName());
- action->setCheckable(true);
- action->setData(theme.name());
- themeGroup->addAction(action);
- if (theme.name() == m_highlighter->theme().name())
- action->setChecked(true);
- }
- connect(themeGroup, &QActionGroup::triggered, this, [this](QAction *action) {
- const auto themeName = action->data().toString();
- const auto theme = m_repository.theme(themeName);
- setTheme(theme);
- });
-
- menu->exec(event->globalPos());
- delete menu;
-}
-
-void CodeEditor::resizeEvent(QResizeEvent *event)
-{
- QPlainTextEdit::resizeEvent(event);
- updateSidebarGeometry();
-}
-
-void CodeEditor::setTheme(const KSyntaxHighlighting::Theme &theme)
-{
- auto pal = qApp->palette();
- if (theme.isValid()) {
- pal.setColor(QPalette::Base, theme.editorColor(KSyntaxHighlighting::Theme::BackgroundColor));
- pal.setColor(QPalette::Text, theme.textColor(KSyntaxHighlighting::Theme::Normal));
- pal.setColor(QPalette::Highlight, theme.editorColor(KSyntaxHighlighting::Theme::TextSelection));
- }
- setPalette(pal);
-
- m_highlighter->setTheme(theme);
- m_highlighter->rehighlight();
- highlightCurrentLine();
-}
-
-int CodeEditor::sidebarWidth() const
-{
- int digits = 1;
- auto count = blockCount();
- while (count >= 10) {
- ++digits;
- count /= 10;
- }
- return 4 + fontMetrics().width(QLatin1Char('9')) * digits + fontMetrics().lineSpacing();
-}
-
-void CodeEditor::sidebarPaintEvent(QPaintEvent *event)
-{
- QPainter painter(m_sideBar);
- painter.fillRect(event->rect(), m_highlighter->theme().editorColor(KSyntaxHighlighting::Theme::IconBorder));
-
- auto block = firstVisibleBlock();
- auto blockNumber = block.blockNumber();
- int top = blockBoundingGeometry(block).translated(contentOffset()).top();
- int bottom = top + blockBoundingRect(block).height();
- const int currentBlockNumber = textCursor().blockNumber();
-
- const auto foldingMarkerSize = fontMetrics().lineSpacing();
-
- while (block.isValid() && top <= event->rect().bottom()) {
- if (block.isVisible() && bottom >= event->rect().top()) {
- const auto number = QString::number(blockNumber + 1);
- painter.setPen(m_highlighter->theme().editorColor(
- (blockNumber == currentBlockNumber) ? KSyntaxHighlighting::Theme::CurrentLineNumber
- : KSyntaxHighlighting::Theme::LineNumbers));
- painter.drawText(0, top, m_sideBar->width() - 2 - foldingMarkerSize, fontMetrics().height(), Qt::AlignRight, number);
- }
-
- // folding marker
- if (block.isVisible() && isFoldable(block)) {
- QPolygonF polygon;
- if (isFolded(block)) {
- polygon << QPointF(foldingMarkerSize * 0.4, foldingMarkerSize * 0.25);
- polygon << QPointF(foldingMarkerSize * 0.4, foldingMarkerSize * 0.75);
- polygon << QPointF(foldingMarkerSize * 0.8, foldingMarkerSize * 0.5);
- } else {
- polygon << QPointF(foldingMarkerSize * 0.25, foldingMarkerSize * 0.4);
- polygon << QPointF(foldingMarkerSize * 0.75, foldingMarkerSize * 0.4);
- polygon << QPointF(foldingMarkerSize * 0.5, foldingMarkerSize * 0.8);
- }
- painter.save();
- painter.setRenderHint(QPainter::Antialiasing);
- painter.setPen(Qt::NoPen);
- painter.setBrush(QColor(m_highlighter->theme().editorColor(KSyntaxHighlighting::Theme::CodeFolding)));
- painter.translate(m_sideBar->width() - foldingMarkerSize, top);
- painter.drawPolygon(polygon);
- painter.restore();
- }
-
- block = block.next();
- top = bottom;
- bottom = top + blockBoundingRect(block).height();
- ++blockNumber;
- }
-}
-
-void CodeEditor::updateSidebarGeometry()
-{
- setViewportMargins(sidebarWidth(), 0, 0, 0);
- const auto r = contentsRect();
- m_sideBar->setGeometry(QRect(r.left(), r.top(), sidebarWidth(), r.height()));
-}
-
-void CodeEditor::updateSidebarArea(const QRect& rect, int dy)
-{
- if (dy)
- m_sideBar->scroll(0, dy);
- else
- m_sideBar->update(0, rect.y(), m_sideBar->width(), rect.height());
-}
-
-void CodeEditor::highlightCurrentLine()
-{
- QTextEdit::ExtraSelection selection;
- selection.format.setBackground(QColor(m_highlighter->theme().editorColor(KSyntaxHighlighting::Theme::CurrentLine)));
- selection.format.setProperty(QTextFormat::FullWidthSelection, true);
- selection.cursor = textCursor();
- selection.cursor.clearSelection();
-
- QList<QTextEdit::ExtraSelection> extraSelections;
- extraSelections.append(selection);
- setExtraSelections(extraSelections);
-}
-
-QTextBlock CodeEditor::blockAtPosition(int y) const
-{
- auto block = firstVisibleBlock();
- if (!block.isValid())
- return QTextBlock();
-
- int top = blockBoundingGeometry(block).translated(contentOffset()).top();
- int bottom = top + blockBoundingRect(block).height();
- do {
- if (top <= y && y <= bottom)
- return block;
- block = block.next();
- top = bottom;
- bottom = top + blockBoundingRect(block).height();
- } while (block.isValid());
- return QTextBlock();
-}
-
-bool CodeEditor::isFoldable(const QTextBlock &block) const
-{
- return m_highlighter->startsFoldingRegion(block);
-}
-
-bool CodeEditor::isFolded(const QTextBlock &block) const
-{
- if (!block.isValid())
- return false;
- const auto nextBlock = block.next();
- if (!nextBlock.isValid())
- return false;
- return !nextBlock.isVisible();
-}
-
-void CodeEditor::toggleFold(const QTextBlock &startBlock)
-{
- // we also want to fold the last line of the region, therefore the ".next()"
- const auto endBlock = m_highlighter->findFoldingRegionEnd(startBlock).next();
-
- if (isFolded(startBlock)) {
- // unfold
- auto block = startBlock.next();
- while (block.isValid() && !block.isVisible()) {
- block.setVisible(true);
- block.setLineCount(block.layout()->lineCount());
- block = block.next();
- }
-
- } else {
- // fold
- auto block = startBlock.next();
- while (block.isValid() && block != endBlock) {
- block.setVisible(false);
- block.setLineCount(0);
- block = block.next();
- }
- }
-
- // redraw document
- document()->markContentsDirty(startBlock.position(), endBlock.position() - startBlock.position() + 1);
-
- // update scrollbars
- emit document()->documentLayout()->documentSizeChanged(document()->documentLayout()->documentSize());
-}
-
-#include "codeeditor.moc"
diff --git a/src/libs/3rdparty/syntax-highlighting/examples/codeeditor.h b/src/libs/3rdparty/syntax-highlighting/examples/codeeditor.h
deleted file mode 100644
index 1823b43e85..0000000000
--- a/src/libs/3rdparty/syntax-highlighting/examples/codeeditor.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- Copyright (C) 2016 Volker Krause <vkrause@kde.org>
-
- Permission is hereby granted, free of charge, to any person obtaining
- a copy of this software and associated documentation files (the
- "Software"), to deal in the Software without restriction, including
- without limitation the rights to use, copy, modify, merge, publish,
- distribute, sublicense, and/or sell copies of the Software, and to
- permit persons to whom the Software is furnished to do so, subject to
- the following conditions:
-
- The above copyright notice and this permission notice shall be included
- in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
-
-#ifndef CODEEDITOR_H
-#define CODEEDITOR_H
-
-#include <repository.h>
-
-#include <QPlainTextEdit>
-
-namespace KSyntaxHighlighting {
-class SyntaxHighlighter;
-}
-
-class CodeEditorSidebar;
-
-class CodeEditor : public QPlainTextEdit
-{
- Q_OBJECT
-public:
- explicit CodeEditor(QWidget *parent = nullptr);
- ~CodeEditor();
-
- void openFile(const QString &fileName);
-
-protected:
- void contextMenuEvent(QContextMenuEvent *event) override;
- void resizeEvent(QResizeEvent *event) override;
-
-private:
- friend class CodeEditorSidebar;
- void setTheme(const KSyntaxHighlighting::Theme &theme);
- int sidebarWidth() const;
- void sidebarPaintEvent(QPaintEvent *event);
- void updateSidebarGeometry();
- void updateSidebarArea(const QRect &rect, int dy);
- void highlightCurrentLine();
-
- QTextBlock blockAtPosition(int y) const;
- bool isFoldable(const QTextBlock &block) const;
- bool isFolded(const QTextBlock &block) const;
- void toggleFold(const QTextBlock &block);
-
- KSyntaxHighlighting::Repository m_repository;
- KSyntaxHighlighting::SyntaxHighlighter *m_highlighter;
- CodeEditorSidebar *m_sideBar;
-};
-
-#endif // CODEEDITOR_H
diff --git a/src/libs/3rdparty/syntax-highlighting/examples/main.cpp b/src/libs/3rdparty/syntax-highlighting/examples/main.cpp
deleted file mode 100644
index 3fb542954d..0000000000
--- a/src/libs/3rdparty/syntax-highlighting/examples/main.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- Copyright (C) 2016 Volker Krause <vkrause@kde.org>
-
- Permission is hereby granted, free of charge, to any person obtaining
- a copy of this software and associated documentation files (the
- "Software"), to deal in the Software without restriction, including
- without limitation the rights to use, copy, modify, merge, publish,
- distribute, sublicense, and/or sell copies of the Software, and to
- permit persons to whom the Software is furnished to do so, subject to
- the following conditions:
-
- The above copyright notice and this permission notice shall be included
- in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
-
-#include "codeeditor.h"
-
-#include <QApplication>
-#include <QCommandLineParser>
-#include <QFile>
-#include <QTextEdit>
-
-int main(int argc, char **argv)
-{
- QApplication app(argc, argv);
-
- QCommandLineParser parser;
- parser.addHelpOption();
- parser.addPositionalArgument(QStringLiteral("source"), QStringLiteral("The source file to highlight."));
- parser.process(app);
-
- CodeEditor edit;
- edit.resize(1024, 1024);
- edit.show();
- if (parser.positionalArguments().size() == 1)
- edit.openFile(parser.positionalArguments().at(0));
- return app.exec();
-}
diff --git a/src/libs/3rdparty/syntax-highlighting/src/cli/kate-syntax-highlighter.cpp b/src/libs/3rdparty/syntax-highlighting/src/cli/kate-syntax-highlighter.cpp
index 92df89dc46..82207c0099 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/cli/kate-syntax-highlighter.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/cli/kate-syntax-highlighter.cpp
@@ -49,23 +49,18 @@ int main(int argc, char **argv)
parser.setApplicationDescription(app.translate("SyntaxHighlightingCLI", "Command line syntax highlighter using Kate syntax definitions."));
parser.addHelpOption();
parser.addVersionOption();
- parser.addPositionalArgument(app.translate("SyntaxHighlightingCLI", "source"),
- app.translate("SyntaxHighlightingCLI", "The source file to highlight."));
+ parser.addPositionalArgument(app.translate("SyntaxHighlightingCLI", "source"), app.translate("SyntaxHighlightingCLI", "The source file to highlight."));
- QCommandLineOption listDefs(QStringList() << QStringLiteral("l") << QStringLiteral("list"),
- app.translate("SyntaxHighlightingCLI", "List all available syntax definitions."));
+ QCommandLineOption listDefs(QStringList() << QStringLiteral("l") << QStringLiteral("list"), app.translate("SyntaxHighlightingCLI", "List all available syntax definitions."));
parser.addOption(listDefs);
- QCommandLineOption listThemes(QStringList() << QStringLiteral("list-themes"),
- app.translate("SyntaxHighlightingCLI", "List all available themes."));
+ QCommandLineOption listThemes(QStringList() << QStringLiteral("list-themes"), app.translate("SyntaxHighlightingCLI", "List all available themes."));
parser.addOption(listThemes);
- QCommandLineOption updateDefs(QStringList() << QStringLiteral("u") << QStringLiteral("update"),
- app.translate("SyntaxHighlightingCLI", "Download new/updated syntax definitions."));
+ QCommandLineOption updateDefs(QStringList() << QStringLiteral("u") << QStringLiteral("update"), app.translate("SyntaxHighlightingCLI", "Download new/updated syntax definitions."));
parser.addOption(updateDefs);
- QCommandLineOption outputName(QStringList() << QStringLiteral("o") << QStringLiteral("output"),
- app.translate("SyntaxHighlightingCLI", "File to write HTML output to (default: stdout)."),
- app.translate("SyntaxHighlightingCLI", "output"));
+ QCommandLineOption outputName(
+ QStringList() << QStringLiteral("o") << QStringLiteral("output"), app.translate("SyntaxHighlightingCLI", "File to write HTML output to (default: stdout)."), app.translate("SyntaxHighlightingCLI", "output"));
parser.addOption(outputName);
QCommandLineOption syntaxName(QStringList() << QStringLiteral("s") << QStringLiteral("syntax"),
@@ -73,9 +68,8 @@ int main(int argc, char **argv)
app.translate("SyntaxHighlightingCLI", "syntax"));
parser.addOption(syntaxName);
- QCommandLineOption themeName(QStringList() << QStringLiteral("t") << QStringLiteral("theme"),
- app.translate("SyntaxHighlightingCLI", "Color theme to use for highlighting."),
- app.translate("SyntaxHighlightingCLI", "theme"), QStringLiteral("Default"));
+ QCommandLineOption themeName(
+ QStringList() << QStringLiteral("t") << QStringLiteral("theme"), app.translate("SyntaxHighlightingCLI", "Color theme to use for highlighting."), app.translate("SyntaxHighlightingCLI", "theme"), QStringLiteral("Default"));
parser.addOption(themeName);
QCommandLineOption titleOption(QStringList() << QStringLiteral("T") << QStringLiteral("title"),
@@ -83,8 +77,7 @@ int main(int argc, char **argv)
app.translate("SyntaxHighlightingCLI", "title"));
parser.addOption(titleOption);
- QCommandLineOption stdinOption(QStringList() << QStringLiteral("stdin"),
- app.translate("SyntaxHighlightingCLI", "Read file from stdin. The -s option must also be used."));
+ QCommandLineOption stdinOption(QStringList() << QStringLiteral("stdin"), app.translate("SyntaxHighlightingCLI", "Read file from stdin. The -s option must also be used."));
parser.addOption(stdinOption);
parser.process(app);
@@ -105,9 +98,7 @@ int main(int argc, char **argv)
if (parser.isSet(updateDefs)) {
DefinitionDownloader downloader(&repo);
- QObject::connect(&downloader, &DefinitionDownloader::informationMessage, [](const QString &msg) {
- std::cout << qPrintable(msg) << std::endl;
- });
+ QObject::connect(&downloader, &DefinitionDownloader::informationMessage, [](const QString &msg) { std::cout << qPrintable(msg) << std::endl; });
QObject::connect(&downloader, &DefinitionDownloader::done, &app, &QCoreApplication::quit);
downloader.start();
return app.exec();
diff --git a/src/libs/3rdparty/syntax-highlighting/src/indexer/katehighlightingindexer.cpp b/src/libs/3rdparty/syntax-highlighting/src/indexer/katehighlightingindexer.cpp
index 2a2ea0081e..82235819a1 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/indexer/katehighlightingindexer.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/indexer/katehighlightingindexer.cpp
@@ -22,21 +22,21 @@
*/
#include <QCoreApplication>
+#include <QDebug>
#include <QFile>
#include <QFileInfo>
-#include <QVariant>
-#include <QXmlStreamReader>
#include <QJsonDocument>
#include <QRegularExpression>
-#include <QDebug>
+#include <QVariant>
+#include <QXmlStreamReader>
#ifdef QT_XMLPATTERNS_LIB
#include <QXmlSchema>
#include <QXmlSchemaValidator>
#endif
-namespace {
-
+namespace
+{
QStringList readListing(const QString &fileName)
{
QFile file(fileName);
@@ -56,8 +56,7 @@ QStringList readListing(const QString &fileName)
}
if (xml.hasError()) {
- qWarning() << "XML error while reading" << fileName << " - "
- << qPrintable(xml.errorString()) << "@ offset" << xml.characterOffset();
+ qWarning() << "XML error while reading" << fileName << " - " << qPrintable(xml.errorString()) << "@ offset" << xml.characterOffset();
listing.clear();
}
@@ -72,7 +71,11 @@ QStringList readListing(const QString &fileName)
bool checkExtensions(const QString &extensions)
{
// get list of extensions
+#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
const QStringList extensionParts = extensions.split(QLatin1Char(';'), QString::SkipEmptyParts);
+#else
+ const QStringList extensionParts = extensions.split(QLatin1Char(';'), Qt::SkipEmptyParts);
+#endif
// ok if empty
if (extensionParts.isEmpty()) {
@@ -80,7 +83,7 @@ bool checkExtensions(const QString &extensions)
}
// check that only valid wildcard things are inside the parts
- for (const auto& extension : extensionParts) {
+ for (const auto &extension : extensionParts) {
for (const auto c : extension) {
// eat normal things
if (c.isDigit() || c.isLetter()) {
@@ -110,14 +113,15 @@ bool checkExtensions(const QString &extensions)
//! - is not empty
//! - isValid()
//! - character ranges such as [A-Z] are valid and not accidentally e.g. [A-z].
+//! - dynamic=true but no place holder used?
bool checkRegularExpression(const QString &hlFilename, QXmlStreamReader &xml)
{
if (xml.name() == QLatin1String("RegExpr") || xml.name() == QLatin1String("emptyLine")) {
// get right attribute
- const QString string (xml.attributes().value((xml.name() == QLatin1String("RegExpr")) ? QLatin1String("String") : QLatin1String("regexpr")).toString());
+ const QString string(xml.attributes().value((xml.name() == QLatin1String("RegExpr")) ? QLatin1String("String") : QLatin1String("regexpr")).toString());
// validate regexp
- const QRegularExpression regexp (string);
+ const QRegularExpression regexp(string);
if (!regexp.isValid()) {
qWarning() << hlFilename << "line" << xml.lineNumber() << "broken regex:" << string << "problem:" << regexp.errorString() << "at offset" << regexp.patternErrorOffset();
return false;
@@ -132,6 +136,15 @@ bool checkRegularExpression(const QString &hlFilename, QXmlStreamReader &xml)
qWarning() << hlFilename << "line" << xml.lineNumber() << "broken regex:" << string << "problem: [a-Z] or [A-z] at offset" << azOffset;
return false;
}
+
+ // dynamic == true and no place holder?
+ if (xml.name() == QLatin1String("RegExpr") && xml.attributes().value(QStringLiteral("dynamic")) == QStringLiteral("true")) {
+ static const QRegularExpression placeHolder(QStringLiteral("%\\d+"));
+ if (!string.contains(placeHolder)) {
+ qWarning() << hlFilename << "line" << xml.lineNumber() << "broken regex:" << string << "problem: dynamic=true but no %\\d+ placeholder";
+ return false;
+ }
+ }
}
return true;
@@ -203,20 +216,19 @@ class KeywordIncludeChecker
public:
void processElement(const QString &hlFilename, const QString &hlName, QXmlStreamReader &xml)
{
- if (xml.name() == QLatin1String("list")) {
- auto &keywords = m_keywordMap[hlName];
- keywords.filename = hlFilename;
- auto name = xml.attributes().value(QLatin1String("name")).toString();
- m_currentIncludes = &keywords.includes[name];
- }
- else if (xml.name() == QLatin1String("include")) {
- if (!m_currentIncludes) {
- qWarning() << hlFilename << "line" << xml.lineNumber() << "<include> tag ouside <list>";
- m_success = false;
- } else {
- m_currentIncludes->push_back({xml.lineNumber(), xml.readElementText()});
- }
- }
+ if (xml.name() == QLatin1String("list")) {
+ auto &keywords = m_keywordMap[hlName];
+ keywords.filename = hlFilename;
+ auto name = xml.attributes().value(QLatin1String("name")).toString();
+ m_currentIncludes = &keywords.includes[name];
+ } else if (xml.name() == QLatin1String("include")) {
+ if (!m_currentIncludes) {
+ qWarning() << hlFilename << "line" << xml.lineNumber() << "<include> tag ouside <list>";
+ m_success = false;
+ } else {
+ m_currentIncludes->push_back({xml.lineNumber(), xml.readElementText()});
+ }
+ }
}
bool check() const
@@ -232,8 +244,7 @@ public:
if (idx == -1) {
auto &keywordName = includes.key();
containsKeywordName = keywords.includes.contains(keywordName);
- }
- else {
+ } else {
auto defName = include.name.mid(idx + 2);
auto listName = include.name.left(idx);
auto it = m_keywordMap.find(defName);
@@ -256,11 +267,9 @@ public:
}
private:
- struct Keywords
- {
+ struct Keywords {
QString filename;
- struct Include
- {
+ struct Include {
qint64 line;
QString name;
};
@@ -279,7 +288,8 @@ class KeywordChecker
public:
KeywordChecker(const QString &filename)
: m_filename(filename)
- {}
+ {
+ }
void processElement(QXmlStreamReader &xml)
{
@@ -343,7 +353,7 @@ public:
void processElement(const QString &hlFilename, const QString &hlName, QXmlStreamReader &xml)
{
if (xml.name() == QLatin1String("context")) {
- auto & language = m_contextMap[hlName];
+ auto &language = m_contextMap[hlName];
language.hlFilename = hlFilename;
const QString name = xml.attributes().value(QLatin1String("name")).toString();
if (language.isFirstContext) {
@@ -387,13 +397,12 @@ public:
bool success = m_success;
// recursive search for the required miximal version
- struct GetRequiredVersion
- {
- QHash<const Language*, Version> versionMap;
+ struct GetRequiredVersion {
+ QHash<const Language *, Version> versionMap;
Version operator()(const QHash<QString, Language> &contextMap, const Language &language)
{
- auto& version = versionMap[&language];
+ auto &version = versionMap[&language];
if (version < language.version) {
version = language.version;
for (auto &languageName : language.usedLanguageName) {
@@ -451,7 +460,11 @@ private:
// handle cross-language context references
if (context.contains(QStringLiteral("##"))) {
+#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
const QStringList list = context.split(QStringLiteral("##"), QString::SkipEmptyParts);
+#else
+ const QStringList list = context.split(QStringLiteral("##"), Qt::SkipEmptyParts);
+#endif
if (list.size() == 1) {
// nothing to do, other language is included: e.g. ##Doxygen
} else if (list.size() == 2) {
@@ -471,15 +484,15 @@ private:
}
private:
- struct Version
- {
+ struct Version {
int majorRevision;
int minorRevision;
Version(int majorRevision = 0, int minorRevision = 0)
: majorRevision(majorRevision)
, minorRevision(minorRevision)
- {}
+ {
+ }
bool operator<(const Version &version) const
{
@@ -487,12 +500,13 @@ private:
}
};
- void processVersion(const QString &hlFilename, const QString &hlName, QXmlStreamReader &xml, Version const& requiredVersion, QLatin1String item)
+ void processVersion(const QString &hlFilename, const QString &hlName, QXmlStreamReader &xml, Version const &requiredVersion, QLatin1String item)
{
auto &language = m_contextMap[hlName];
if (language.version < requiredVersion) {
- qWarning().nospace() << hlFilename << " " << item << " in line " << xml.lineNumber() << " is only available since version " << requiredVersion.majorRevision << "." << requiredVersion.minorRevision << ". Please, increase kateversion.";
+ qWarning().nospace() << hlFilename << " " << item << " in line " << xml.lineNumber() << " is only available since version " << requiredVersion.majorRevision << "." << requiredVersion.minorRevision
+ << ". Please, increase kateversion.";
// update the version to cancel future warnings
language.version = requiredVersion;
m_success = false;
@@ -540,7 +554,8 @@ class AttributeChecker
public:
AttributeChecker(const QString &filename)
: m_filename(filename)
- {}
+ {
+ }
void processElement(QXmlStreamReader &xml)
{
@@ -620,9 +635,8 @@ int main(int argc, char *argv[])
}
// text attributes
- const QStringList textAttributes = QStringList() << QStringLiteral("name") << QStringLiteral("section") << QStringLiteral("mimetype")
- << QStringLiteral("extensions") << QStringLiteral("style")
- << QStringLiteral("author") << QStringLiteral("license") << QStringLiteral("indenter");
+ const QStringList textAttributes = QStringList() << QStringLiteral("name") << QStringLiteral("section") << QStringLiteral("mimetype") << QStringLiteral("extensions") << QStringLiteral("style") << QStringLiteral("author")
+ << QStringLiteral("license") << QStringLiteral("indenter");
// index all given highlightings
ContextChecker contextChecker;
@@ -632,7 +646,7 @@ int main(int argc, char *argv[])
for (const QString &hlFilename : qAsConst(hlFilenames)) {
QFile hlFile(hlFilename);
if (!hlFile.open(QIODevice::ReadOnly)) {
- qWarning ("Failed to open %s", qPrintable(hlFilename));
+ qWarning("Failed to open %s", qPrintable(hlFilename));
anyError = 3;
continue;
}
@@ -750,7 +764,6 @@ int main(int argc, char *argv[])
if (!keywordIncludeChecker.check())
anyError = 7;
-
// bail out if any problem was seen
if (anyError)
return anyError;
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/CMakeLists.txt b/src/libs/3rdparty/syntax-highlighting/src/lib/CMakeLists.txt
index 9e95772f6e..02c889d7a2 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/CMakeLists.txt
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/CMakeLists.txt
@@ -23,6 +23,8 @@ ecm_qt_declare_logging_category(syntax_highlighting_srcs
HEADER ksyntaxhighlighting_logging.h
IDENTIFIER KSyntaxHighlighting::Log
CATEGORY_NAME org.kde.ksyntaxhighlighting
+ DESCRIPTION "Syntax Highlighting"
+ EXPORT KSYNTAXHIGHLIGHTING
)
add_library(KF5SyntaxHighlighting ${syntax_highlighting_srcs} $<TARGET_OBJECTS:SyntaxHighlightingData>)
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp
index c4ef86a771..fc5c627812 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp
@@ -27,11 +27,11 @@
#include "definition_p.h"
#include "foldingregion.h"
#include "format.h"
+#include "ksyntaxhighlighting_logging.h"
#include "repository.h"
#include "rule_p.h"
#include "state.h"
#include "state_p.h"
-#include "ksyntaxhighlighting_logging.h"
#include "theme.h"
using namespace KSyntaxHighlighting;
@@ -60,13 +60,13 @@ void AbstractHighlighterPrivate::ensureDefinitionLoaded()
defData->load();
}
-AbstractHighlighter::AbstractHighlighter() :
- d_ptr(new AbstractHighlighterPrivate)
+AbstractHighlighter::AbstractHighlighter()
+ : d_ptr(new AbstractHighlighterPrivate)
{
}
-AbstractHighlighter::AbstractHighlighter(AbstractHighlighterPrivate *dd) :
- d_ptr(dd)
+AbstractHighlighter::AbstractHighlighter(AbstractHighlighterPrivate *dd)
+ : d_ptr(dd)
{
}
@@ -102,7 +102,7 @@ void AbstractHighlighter::setTheme(const Theme &theme)
* Returns the index of the first non-space character. If the line is empty,
* or only contains white spaces, text.size() is returned.
*/
-static inline int firstNonSpaceChar(const QString & text)
+static inline int firstNonSpaceChar(const QString &text)
{
for (int i = 0; i < text.length(); ++i) {
if (!text[i].isSpace()) {
@@ -112,7 +112,7 @@ static inline int firstNonSpaceChar(const QString & text)
return text.size();
}
-State AbstractHighlighter::highlightLine(const QString& text, const State &state)
+State AbstractHighlighter::highlightLine(const QString &text, const State &state)
{
Q_D(AbstractHighlighter);
@@ -156,12 +156,11 @@ State AbstractHighlighter::highlightLine(const QString& text, const State &state
*/
break;
}
- /**
- * 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()))
+ /**
+ * 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()))
break;
// guard against endless loops
@@ -178,7 +177,15 @@ State AbstractHighlighter::highlightLine(const QString& text, const State &state
int offset = 0, beginOffset = 0;
bool lineContinuation = false;
- QHash<Rule*, int> skipOffsets;
+
+ /**
+ * for expensive rules like regexes we do:
+ * - match them for the complete line, as this is faster than re-trying them at all positions
+ * - store the result of the first position that matches (or -1 for no match in the full line) in the skipOffsets hash for re-use
+ * - have capturesForLastDynamicSkipOffset as guard for dynamic regexes to invalidate the cache if they might have changed
+ */
+ QHash<Rule *, int> skipOffsets;
+ QStringList capturesForLastDynamicSkipOffset;
/**
* current active format
@@ -248,21 +255,31 @@ State AbstractHighlighter::highlightLine(const QString& text, const State &state
* shall we skip application of this rule? two cases:
* - rule can't match at all => currentSkipOffset < 0
* - rule will only match for some higher offset => currentSkipOffset > offset
+ *
+ * we need to invalidate this if we are dynamic and have different captures then last time
*/
+ if (rule->isDynamic() && (capturesForLastDynamicSkipOffset != stateData->topCaptures())) {
+ skipOffsets.clear();
+ }
const auto currentSkipOffset = skipOffsets.value(rule.get());
if (currentSkipOffset < 0 || currentSkipOffset > offset)
continue;
-
const auto newResult = rule->doMatch(text, offset, stateData->topCaptures());
newOffset = newResult.offset();
/**
* update skip offset if new one rules out any later match or is larger than current one
*/
- if (newResult.skipOffset() < 0 || newResult.skipOffset() > currentSkipOffset)
+ if (newResult.skipOffset() < 0 || newResult.skipOffset() > currentSkipOffset) {
skipOffsets.insert(rule.get(), newResult.skipOffset());
+ // remember new captures, if dynamic to enforce proper reset above on change!
+ if (rule->isDynamic()) {
+ capturesForLastDynamicSkipOffset = stateData->topCaptures();
+ }
+ }
+
if (newOffset <= offset)
continue;
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.h b/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.h
index 2b88729697..575a723527 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.h
@@ -34,8 +34,8 @@ QT_BEGIN_NAMESPACE
class QString;
QT_END_NAMESPACE
-namespace KSyntaxHighlighting {
-
+namespace KSyntaxHighlighting
+{
class AbstractHighlighterPrivate;
class Definition;
class FoldingRegion;
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter_p.h
index bdfdf23bc1..c36932c29d 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter_p.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter_p.h
@@ -31,8 +31,8 @@ QT_BEGIN_NAMESPACE
class QStringList;
QT_END_NAMESPACE
-namespace KSyntaxHighlighting {
-
+namespace KSyntaxHighlighting
+{
class ContextSwitch;
class StateData;
@@ -43,7 +43,7 @@ public:
virtual ~AbstractHighlighterPrivate();
void ensureDefinitionLoaded();
- bool switchContext(StateData* data, const ContextSwitch &contextSwitch, const QStringList &captures);
+ bool switchContext(StateData *data, const ContextSwitch &contextSwitch, const QStringList &captures);
Definition m_definition;
Theme m_theme;
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/context.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/context.cpp
index 9d5597e7d2..2327cfe584 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/context.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/context.cpp
@@ -24,9 +24,9 @@
#include "context_p.h"
#include "definition_p.h"
#include "format.h"
+#include "ksyntaxhighlighting_logging.h"
#include "repository.h"
#include "rule_p.h"
-#include "ksyntaxhighlighting_logging.h"
#include "xml_p.h"
#include <QString>
@@ -52,7 +52,7 @@ bool Context::indentationBasedFoldingEnabled() const
return m_def.definition().indentationBasedFoldingEnabled();
}
-void Context::load(QXmlStreamReader& reader)
+void Context::load(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("context"));
Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
@@ -68,24 +68,23 @@ void Context::load(QXmlStreamReader& reader)
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(rule);
- } else {
- reader.skipCurrentElement();
- }
- reader.readNext();
- break;
+ case QXmlStreamReader::StartElement: {
+ auto rule = Rule::create(reader.name());
+ if (rule) {
+ rule->setDefinition(m_def.definition());
+ if (rule->load(reader))
+ m_rules.push_back(rule);
+ } else {
+ reader.skipCurrentElement();
}
- case QXmlStreamReader::EndElement:
- return;
- default:
- reader.readNext();
- break;
+ reader.readNext();
+ break;
+ }
+ case QXmlStreamReader::EndElement:
+ return;
+ default:
+ reader.readNext();
+ break;
}
}
}
@@ -133,7 +132,7 @@ void Context::resolveIncludes()
++it;
continue;
}
- Context* context = nullptr;
+ Context *context = nullptr;
auto myDefData = DefinitionData::get(m_def.definition());
if (inc->definitionName().isEmpty()) { // local include
context = myDefData->contextByName(inc->contextName());
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 a034d0e27d..5d23ee2400 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/context_p.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/context_p.h
@@ -24,11 +24,11 @@
#ifndef KSYNTAXHIGHLIGHTING_CONTEXT_P_H
#define KSYNTAXHIGHLIGHTING_CONTEXT_P_H
-#include "rule_p.h"
#include "contextswitch_p.h"
#include "definition.h"
#include "definitionref_p.h"
#include "format.h"
+#include "rule_p.h"
#include <QString>
@@ -38,8 +38,8 @@ QT_BEGIN_NAMESPACE
class QXmlStreamReader;
QT_END_NAMESPACE
-namespace KSyntaxHighlighting {
-
+namespace KSyntaxHighlighting
+{
class Context
{
public:
@@ -98,12 +98,7 @@ public:
private:
Q_DISABLE_COPY(Context)
- enum ResolveState {
- Unknown,
- Unresolved,
- Resolving,
- Resolved
- };
+ enum ResolveState { Unknown, Unresolved, Resolving, Resolved };
ResolveState resolveState();
DefinitionRef m_def;
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/contextswitch.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/contextswitch.cpp
index a4d1dbbd85..2536792154 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/contextswitch.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/contextswitch.cpp
@@ -24,9 +24,8 @@
#include "contextswitch_p.h"
#include "definition.h"
#include "definition_p.h"
-#include "repository.h"
#include "ksyntaxhighlighting_logging.h"
-
+#include "repository.h"
using namespace KSyntaxHighlighting;
@@ -40,12 +39,12 @@ int ContextSwitch::popCount() const
return m_popCount;
}
-Context* ContextSwitch::context() const
+Context *ContextSwitch::context() const
{
return m_context;
}
-void ContextSwitch::parse(const QStringRef& contextInstr)
+void ContextSwitch::parse(const QStringRef &contextInstr)
{
if (contextInstr.isEmpty() || contextInstr == QLatin1String("#stay"))
return;
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 669855af7a..79fb86f044 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/contextswitch_p.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/contextswitch_p.h
@@ -26,8 +26,8 @@
#include <QString>
-namespace KSyntaxHighlighting {
-
+namespace KSyntaxHighlighting
+{
class Context;
class Definition;
@@ -40,7 +40,7 @@ public:
bool isStay() const;
int popCount() const;
- Context* context() const;
+ Context *context() const;
void parse(const QStringRef &contextInstr);
void resolve(const Definition &def);
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp
index 6a204dc3ac..bc43473bf2 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp
@@ -23,7 +23,6 @@
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-
#include "definition.h"
#include "definition_p.h"
#include "definitionref_p.h"
@@ -31,11 +30,11 @@
#include "context_p.h"
#include "format.h"
#include "format_p.h"
+#include "ksyntaxhighlighting_logging.h"
+#include "ksyntaxhighlighting_version.h"
#include "repository.h"
#include "repository_p.h"
#include "rule_p.h"
-#include "ksyntaxhighlighting_logging.h"
-#include "ksyntaxhighlighting_version.h"
#include "xml_p.h"
#include <QCoreApplication>
@@ -61,24 +60,24 @@ DefinitionData::~DefinitionData()
qDeleteAll(contexts);
}
-DefinitionData* DefinitionData::get(const Definition &def)
+DefinitionData *DefinitionData::get(const Definition &def)
{
return def.d.get();
}
-Definition::Definition() :
- d(new DefinitionData)
+Definition::Definition()
+ : d(new DefinitionData)
{
}
-Definition::Definition(const Definition &other) :
- d(other.d)
+Definition::Definition(const Definition &other)
+ : d(other.d)
{
d->q = *this;
}
-Definition::Definition(const std::shared_ptr<DefinitionData> &dd) :
- d(dd)
+Definition::Definition(const std::shared_ptr<DefinitionData> &dd)
+ : d(dd)
{
}
@@ -86,7 +85,7 @@ Definition::~Definition()
{
}
-Definition& Definition::operator=(const Definition &rhs)
+Definition &Definition::operator=(const Definition &rhs)
{
d = rhs.d;
return *this;
@@ -97,7 +96,7 @@ bool Definition::operator==(const Definition &other) const
return d->fileName == other.d->fileName;
}
-bool Definition::operator!=(const Definition& other) const
+bool Definition::operator!=(const Definition &other) const
{
return d->fileName != other.d->fileName;
}
@@ -226,23 +225,21 @@ QStringList Definition::keywordLists() const
return d->keywordLists.keys();
}
-QStringList Definition::keywordList(const QString& name) const
+QStringList Definition::keywordList(const QString &name) const
{
d->load(DefinitionData::OnlyKeywords(true));
const auto list = d->keywordList(name);
return list ? list->keywords() : QStringList();
}
-bool Definition::setKeywordList(const QString& name, const QStringList& content)
+bool Definition::setKeywordList(const QString &name, const QStringList &content)
{
d->load(DefinitionData::OnlyKeywords(true));
- KeywordList* list = d->keywordList(name);
- if (list)
- {
+ KeywordList *list = d->keywordList(name);
+ if (list) {
list->setKeywordList(content);
return true;
- }
- else
+ } else
return false;
}
@@ -252,9 +249,7 @@ QVector<Format> Definition::formats() const
// sort formats so that the order matches the order of the itemDatas in the xml files.
auto formatList = QVector<Format>::fromList(d->formats.values());
- std::sort(formatList.begin(), formatList.end(), [](const KSyntaxHighlighting::Format & lhs, const KSyntaxHighlighting::Format & rhs){
- return lhs.id() < rhs.id();
- });
+ std::sort(formatList.begin(), formatList.end(), [](const KSyntaxHighlighting::Format &lhs, const KSyntaxHighlighting::Format &rhs) { return lhs.id() < rhs.id(); });
return formatList;
}
@@ -264,13 +259,13 @@ QVector<Definition> Definition::includedDefinitions() const
d->load();
// init worklist and result used as guard with this definition
- QVector<Definition> queue{*this};
- QVector<Definition> definitions{*this};
+ QVector<Definition> queue {*this};
+ QVector<Definition> 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 : qAsConst(definition.d->contexts)) {
+ for (const auto &context : qAsConst(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) {
@@ -321,7 +316,7 @@ CommentPosition Definition::singleLineCommentPosition() const
QPair<QString, QString> Definition::multiLineCommentMarker() const
{
d->load();
- return { d->multiLineCommentStartMarker, d->multiLineCommentEndMarker };
+ return {d->multiLineCommentStartMarker, d->multiLineCommentEndMarker};
}
QVector<QPair<QChar, QString>> Definition::characterEncodings() const
@@ -330,13 +325,13 @@ QVector<QPair<QChar, QString>> Definition::characterEncodings() const
return d->characterEncodings;
}
-Context* DefinitionData::initialContext() const
+Context *DefinitionData::initialContext() const
{
Q_ASSERT(!contexts.isEmpty());
return contexts.first();
}
-Context* DefinitionData::contextByName(const QString& wantedName) const
+Context *DefinitionData::contextByName(const QString &wantedName) const
{
for (const auto context : contexts) {
if (context->name() == wantedName)
@@ -345,7 +340,7 @@ Context* DefinitionData::contextByName(const QString& wantedName) const
return nullptr;
}
-KeywordList *DefinitionData::keywordList(const QString& wantedName)
+KeywordList *DefinitionData::keywordList(const QString &wantedName)
{
auto it = keywordLists.find(wantedName);
return (it == keywordLists.end()) ? nullptr : &it.value();
@@ -356,7 +351,7 @@ bool DefinitionData::isWordDelimiter(QChar c) const
return std::binary_search(wordDelimiters.constBegin(), wordDelimiters.constEnd(), c);
}
-Format DefinitionData::formatByName(const QString& wantedName) const
+Format DefinitionData::formatByName(const QString &wantedName) const
{
const auto it = formats.constFind(wantedName);
if (it != formats.constEnd())
@@ -440,7 +435,7 @@ void DefinitionData::clear()
hidden = false;
}
-bool DefinitionData::loadMetaData(const QString& definitionFileName)
+bool DefinitionData::loadMetaData(const QString &definitionFileName)
{
fileName = definitionFileName;
@@ -463,22 +458,30 @@ bool DefinitionData::loadMetaData(const QString& definitionFileName)
bool DefinitionData::loadMetaData(const QString &file, const QJsonObject &obj)
{
- name = obj.value(QLatin1String("name")).toString();
- section = obj.value(QLatin1String("section")).toString();
- version = obj.value(QLatin1String("version")).toInt();
+ name = obj.value(QLatin1String("name")).toString();
+ section = obj.value(QLatin1String("section")).toString();
+ version = obj.value(QLatin1String("version")).toInt();
priority = obj.value(QLatin1String("priority")).toInt();
- style = obj.value(QLatin1String("style")).toString();
- author = obj.value(QLatin1String("author")).toString();
- license = obj.value(QLatin1String("license")).toString();
+ style = obj.value(QLatin1String("style")).toString();
+ author = obj.value(QLatin1String("author")).toString();
+ license = obj.value(QLatin1String("license")).toString();
indenter = obj.value(QLatin1String("indenter")).toString();
- hidden = obj.value(QLatin1String("hidden")).toBool();
+ hidden = obj.value(QLatin1String("hidden")).toBool();
fileName = file;
const auto exts = obj.value(QLatin1String("extensions")).toString();
+#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
for (const auto &ext : exts.split(QLatin1Char(';'), QString::SkipEmptyParts))
+#else
+ for (const auto &ext : exts.split(QLatin1Char(';'), Qt::SkipEmptyParts))
+#endif
extensions.push_back(ext);
const auto mts = obj.value(QLatin1String("mimetype")).toString();
+#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
for (const auto &mt : mts.split(QLatin1Char(';'), QString::SkipEmptyParts))
+#else
+ for (const auto &mt : mts.split(QLatin1Char(';'), Qt::SkipEmptyParts))
+#endif
mimetypes.push_back(mt);
return true;
@@ -503,17 +506,25 @@ bool DefinitionData::loadLanguage(QXmlStreamReader &reader)
author = reader.attributes().value(QStringLiteral("author")).toString();
license = reader.attributes().value(QStringLiteral("license")).toString();
const auto exts = reader.attributes().value(QStringLiteral("extensions")).toString();
+#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
for (const auto &ext : exts.split(QLatin1Char(';'), QString::SkipEmptyParts))
+#else
+ for (const auto &ext : exts.split(QLatin1Char(';'), Qt::SkipEmptyParts))
+#endif
extensions.push_back(ext);
const auto mts = reader.attributes().value(QStringLiteral("mimetype")).toString();
+#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
for (const auto &mt : mts.split(QLatin1Char(';'), QString::SkipEmptyParts))
+#else
+ for (const auto &mt : mts.split(QLatin1Char(';'), Qt::SkipEmptyParts))
+#endif
mimetypes.push_back(mt);
if (reader.attributes().hasAttribute(QStringLiteral("casesensitive")))
caseSensitive = Xml::attrToBool(reader.attributes().value(QStringLiteral("casesensitive"))) ? Qt::CaseSensitive : Qt::CaseInsensitive;
return true;
}
-void DefinitionData::loadHighlighting(QXmlStreamReader& reader, OnlyKeywords onlyKeywords)
+void DefinitionData::loadHighlighting(QXmlStreamReader &reader, OnlyKeywords onlyKeywords)
{
Q_ASSERT(reader.name() == QLatin1String("highlighting"));
Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
@@ -523,35 +534,34 @@ void DefinitionData::loadHighlighting(QXmlStreamReader& reader, OnlyKeywords onl
while (!reader.atEnd()) {
switch (reader.tokenType()) {
- case QXmlStreamReader::StartElement:
- if (reader.name() == QLatin1String("list")) {
- if (!keywordIsLoaded) {
- KeywordList keywords;
- keywords.load(reader);
- keywordLists.insert(keywords.name(), keywords);
- }
- else {
- reader.skipCurrentElement();
- reader.readNext(); // Skip </list>
- }
- } else if (bool(onlyKeywords)) {
- resolveIncludeKeywords();
- return;
- } else if (reader.name() == QLatin1String("contexts")) {
- resolveIncludeKeywords();
- loadContexts(reader);
- reader.readNext();
- } else if (reader.name() == QLatin1String("itemDatas")) {
- loadItemData(reader);
+ case QXmlStreamReader::StartElement:
+ if (reader.name() == QLatin1String("list")) {
+ if (!keywordIsLoaded) {
+ KeywordList keywords;
+ keywords.load(reader);
+ keywordLists.insert(keywords.name(), keywords);
} else {
- reader.readNext();
+ reader.skipCurrentElement();
+ reader.readNext(); // Skip </list>
}
- break;
- case QXmlStreamReader::EndElement:
+ } else if (bool(onlyKeywords)) {
+ resolveIncludeKeywords();
return;
- default:
+ } else if (reader.name() == QLatin1String("contexts")) {
+ resolveIncludeKeywords();
+ loadContexts(reader);
reader.readNext();
- break;
+ } else if (reader.name() == QLatin1String("itemDatas")) {
+ loadItemData(reader);
+ } else {
+ reader.readNext();
+ }
+ break;
+ case QXmlStreamReader::EndElement:
+ return;
+ default:
+ reader.readNext();
+ break;
}
}
}
@@ -569,60 +579,60 @@ void DefinitionData::resolveIncludeKeywords()
}
}
-void DefinitionData::loadContexts(QXmlStreamReader& reader)
+void DefinitionData::loadContexts(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("contexts"));
Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
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);
- }
- reader.readNext();
- break;
- case QXmlStreamReader::EndElement:
- return;
- default:
- reader.readNext();
- break;
+ case QXmlStreamReader::StartElement:
+ if (reader.name() == QLatin1String("context")) {
+ auto context = new Context;
+ context->setDefinition(q);
+ context->load(reader);
+ contexts.push_back(context);
+ }
+ reader.readNext();
+ break;
+ case QXmlStreamReader::EndElement:
+ return;
+ default:
+ reader.readNext();
+ break;
}
}
}
-void DefinitionData::loadItemData(QXmlStreamReader& reader)
+void DefinitionData::loadItemData(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("itemDatas"));
Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
while (!reader.atEnd()) {
switch (reader.tokenType()) {
- case QXmlStreamReader::StartElement:
- if (reader.name() == QLatin1String("itemData")) {
- Format f;
- auto formatData = FormatPrivate::detachAndGet(f);
- formatData->definition = q;
- formatData->load(reader);
- formatData->id = RepositoryPrivate::get(repo)->nextFormatId();
- formats.insert(f.name(), f);
- reader.readNext();
- }
+ case QXmlStreamReader::StartElement:
+ if (reader.name() == QLatin1String("itemData")) {
+ Format f;
+ auto formatData = FormatPrivate::detachAndGet(f);
+ formatData->definition = q;
+ formatData->load(reader);
+ formatData->id = RepositoryPrivate::get(repo)->nextFormatId();
+ formats.insert(f.name(), f);
reader.readNext();
- break;
- case QXmlStreamReader::EndElement:
- return;
- default:
- reader.readNext();
- break;
+ }
+ reader.readNext();
+ break;
+ case QXmlStreamReader::EndElement:
+ return;
+ default:
+ reader.readNext();
+ break;
}
}
}
-void DefinitionData::loadGeneral(QXmlStreamReader& reader)
+void DefinitionData::loadGeneral(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("general"));
Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
@@ -633,49 +643,49 @@ void DefinitionData::loadGeneral(QXmlStreamReader& reader)
while (!reader.atEnd()) {
switch (reader.tokenType()) {
- case QXmlStreamReader::StartElement:
- ++elementRefCounter;
-
- if (reader.name() == QLatin1String("keywords")) {
- if (reader.attributes().hasAttribute(QStringLiteral("casesensitive")))
- caseSensitive = Xml::attrToBool(reader.attributes().value(QStringLiteral("casesensitive"))) ? Qt::CaseSensitive : Qt::CaseInsensitive;
-
- // adapt sorted wordDelimiters
- wordDelimiters += reader.attributes().value(QStringLiteral("additionalDeliminator"));
- std::sort(wordDelimiters.begin(), wordDelimiters.end());
- auto it = std::unique(wordDelimiters.begin(), wordDelimiters.end());
- wordDelimiters.truncate(std::distance(wordDelimiters.begin(), it));
- for (const auto c : reader.attributes().value(QLatin1String("weakDeliminator")))
- wordDelimiters.remove(c);
-
- // adaptWordWrapDelimiters, and sort
- wordWrapDelimiters = reader.attributes().value(QStringLiteral("wordWrapDeliminator")).toString();
- std::sort(wordWrapDelimiters.begin(), wordWrapDelimiters.end());
- if (wordWrapDelimiters.isEmpty())
- wordWrapDelimiters = wordDelimiters;
- } else if (reader.name() == QLatin1String("folding")) {
- if (reader.attributes().hasAttribute(QStringLiteral("indentationsensitive")))
- indentationBasedFolding = Xml::attrToBool(reader.attributes().value(QStringLiteral("indentationsensitive")));
- } else if (reader.name() == QLatin1String("emptyLines")) {
- loadFoldingIgnoreList(reader);
- } else if (reader.name() == QLatin1String("comments")) {
- loadComments(reader);
- } else if (reader.name() == QLatin1String("spellchecking")) {
- loadSpellchecking(reader);
- } else {
- reader.skipCurrentElement();
- }
- reader.readNext();
- break;
- case QXmlStreamReader::EndElement:
- --elementRefCounter;
- if (elementRefCounter == 0)
- return;
- reader.readNext();
- break;
- default:
- reader.readNext();
- break;
+ case QXmlStreamReader::StartElement:
+ ++elementRefCounter;
+
+ if (reader.name() == QLatin1String("keywords")) {
+ if (reader.attributes().hasAttribute(QStringLiteral("casesensitive")))
+ caseSensitive = Xml::attrToBool(reader.attributes().value(QStringLiteral("casesensitive"))) ? Qt::CaseSensitive : Qt::CaseInsensitive;
+
+ // adapt sorted wordDelimiters
+ wordDelimiters += reader.attributes().value(QStringLiteral("additionalDeliminator"));
+ std::sort(wordDelimiters.begin(), wordDelimiters.end());
+ auto it = std::unique(wordDelimiters.begin(), wordDelimiters.end());
+ wordDelimiters.truncate(std::distance(wordDelimiters.begin(), it));
+ for (const auto c : reader.attributes().value(QLatin1String("weakDeliminator")))
+ wordDelimiters.remove(c);
+
+ // adaptWordWrapDelimiters, and sort
+ wordWrapDelimiters = reader.attributes().value(QStringLiteral("wordWrapDeliminator")).toString();
+ std::sort(wordWrapDelimiters.begin(), wordWrapDelimiters.end());
+ if (wordWrapDelimiters.isEmpty())
+ wordWrapDelimiters = wordDelimiters;
+ } else if (reader.name() == QLatin1String("folding")) {
+ if (reader.attributes().hasAttribute(QStringLiteral("indentationsensitive")))
+ indentationBasedFolding = Xml::attrToBool(reader.attributes().value(QStringLiteral("indentationsensitive")));
+ } else if (reader.name() == QLatin1String("emptyLines")) {
+ loadFoldingIgnoreList(reader);
+ } else if (reader.name() == QLatin1String("comments")) {
+ loadComments(reader);
+ } else if (reader.name() == QLatin1String("spellchecking")) {
+ loadSpellchecking(reader);
+ } else {
+ reader.skipCurrentElement();
+ }
+ reader.readNext();
+ break;
+ case QXmlStreamReader::EndElement:
+ --elementRefCounter;
+ if (elementRefCounter == 0)
+ return;
+ reader.readNext();
+ break;
+ default:
+ reader.readNext();
+ break;
}
}
}
@@ -691,35 +701,35 @@ void DefinitionData::loadComments(QXmlStreamReader &reader)
while (!reader.atEnd()) {
switch (reader.tokenType()) {
- case QXmlStreamReader::StartElement:
- ++elementRefCounter;
- if (reader.name() == QLatin1String("comment")) {
- const bool isSingleLine = reader.attributes().value(QStringLiteral("name")) == QStringLiteral("singleLine");
- if (isSingleLine) {
- singleLineCommentMarker = reader.attributes().value(QStringLiteral("start")).toString();
- const bool afterWhiteSpace = reader.attributes().value(QStringLiteral("position")).toString() == QStringLiteral("afterwhitespace");
- singleLineCommentPosition = afterWhiteSpace ? CommentPosition::AfterWhitespace : CommentPosition::StartOfLine;
- } else {
- multiLineCommentStartMarker = reader.attributes().value(QStringLiteral("start")).toString();
- multiLineCommentEndMarker = reader.attributes().value(QStringLiteral("end")).toString();
- }
+ case QXmlStreamReader::StartElement:
+ ++elementRefCounter;
+ if (reader.name() == QLatin1String("comment")) {
+ const bool isSingleLine = reader.attributes().value(QStringLiteral("name")) == QStringLiteral("singleLine");
+ if (isSingleLine) {
+ singleLineCommentMarker = reader.attributes().value(QStringLiteral("start")).toString();
+ const bool afterWhiteSpace = reader.attributes().value(QStringLiteral("position")).toString() == QStringLiteral("afterwhitespace");
+ singleLineCommentPosition = afterWhiteSpace ? CommentPosition::AfterWhitespace : CommentPosition::StartOfLine;
+ } else {
+ multiLineCommentStartMarker = reader.attributes().value(QStringLiteral("start")).toString();
+ multiLineCommentEndMarker = reader.attributes().value(QStringLiteral("end")).toString();
}
- reader.readNext();
- break;
- case QXmlStreamReader::EndElement:
- --elementRefCounter;
- if (elementRefCounter == 0)
- return;
- reader.readNext();
- break;
- default:
- reader.readNext();
- break;
+ }
+ reader.readNext();
+ break;
+ case QXmlStreamReader::EndElement:
+ --elementRefCounter;
+ if (elementRefCounter == 0)
+ return;
+ reader.readNext();
+ break;
+ default:
+ reader.readNext();
+ break;
}
}
}
-void DefinitionData::loadFoldingIgnoreList(QXmlStreamReader& reader)
+void DefinitionData::loadFoldingIgnoreList(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("emptyLines"));
Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
@@ -730,22 +740,22 @@ void DefinitionData::loadFoldingIgnoreList(QXmlStreamReader& reader)
while (!reader.atEnd()) {
switch (reader.tokenType()) {
- case QXmlStreamReader::StartElement:
- ++elementRefCounter;
- if (reader.name() == QLatin1String("emptyLine")) {
- foldingIgnoreList << reader.attributes().value(QStringLiteral("regexpr")).toString();
- }
- reader.readNext();
- break;
- case QXmlStreamReader::EndElement:
- --elementRefCounter;
- if (elementRefCounter == 0)
- return;
- reader.readNext();
- break;
- default:
- reader.readNext();
- break;
+ case QXmlStreamReader::StartElement:
+ ++elementRefCounter;
+ if (reader.name() == QLatin1String("emptyLine")) {
+ foldingIgnoreList << reader.attributes().value(QStringLiteral("regexpr")).toString();
+ }
+ reader.readNext();
+ break;
+ case QXmlStreamReader::EndElement:
+ --elementRefCounter;
+ if (elementRefCounter == 0)
+ return;
+ reader.readNext();
+ break;
+ default:
+ reader.readNext();
+ break;
}
}
}
@@ -761,31 +771,31 @@ void DefinitionData::loadSpellchecking(QXmlStreamReader &reader)
while (!reader.atEnd()) {
switch (reader.tokenType()) {
- case QXmlStreamReader::StartElement:
- ++elementRefCounter;
- if (reader.name() == QLatin1String("encoding")) {
- const auto charRef = reader.attributes().value(QStringLiteral("char"));
- if (!charRef.isEmpty()) {
- const auto str = reader.attributes().value(QStringLiteral("string")).toString();
- characterEncodings.push_back({ charRef[0], str });
- }
+ case QXmlStreamReader::StartElement:
+ ++elementRefCounter;
+ if (reader.name() == QLatin1String("encoding")) {
+ const auto charRef = reader.attributes().value(QStringLiteral("char"));
+ if (!charRef.isEmpty()) {
+ const auto str = reader.attributes().value(QStringLiteral("string")).toString();
+ characterEncodings.push_back({charRef[0], str});
}
- reader.readNext();
- break;
- case QXmlStreamReader::EndElement:
- --elementRefCounter;
- if (elementRefCounter == 0)
- return;
- reader.readNext();
- break;
- default:
- reader.readNext();
- break;
+ }
+ reader.readNext();
+ break;
+ case QXmlStreamReader::EndElement:
+ --elementRefCounter;
+ if (elementRefCounter == 0)
+ return;
+ reader.readNext();
+ break;
+ default:
+ reader.readNext();
+ break;
}
}
}
-bool DefinitionData::checkKateVersion(const QStringRef& verStr)
+bool DefinitionData::checkKateVersion(const QStringRef &verStr)
{
const auto idx = verStr.indexOf(QLatin1Char('.'));
if (idx <= 0) {
@@ -813,8 +823,8 @@ DefinitionRef::DefinitionRef()
{
}
-DefinitionRef::DefinitionRef(const Definition &def) :
- d(def.d)
+DefinitionRef::DefinitionRef(const Definition &def)
+ : d(def.d)
{
}
@@ -822,7 +832,7 @@ DefinitionRef::~DefinitionRef()
{
}
-DefinitionRef& DefinitionRef::operator=(const Definition &def)
+DefinitionRef &DefinitionRef::operator=(const Definition &def)
{
d = def.d;
return *this;
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/definition.h b/src/libs/3rdparty/syntax-highlighting/src/lib/definition.h
index 3ba5be9a7a..e47d2c4287 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/definition.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definition.h
@@ -34,11 +34,11 @@ QT_BEGIN_NAMESPACE
class QChar;
class QString;
class QStringList;
-template <typename T> class QVector;
+template<typename T> class QVector;
QT_END_NAMESPACE
-namespace KSyntaxHighlighting {
-
+namespace KSyntaxHighlighting
+{
class Context;
class Format;
class KeywordList;
@@ -50,8 +50,7 @@ class DefinitionData;
* @since 5.50
* @see Definition::singleLineCommentPosition()
*/
-enum class CommentPosition
-{
+enum class CommentPosition {
//! The comment marker is inserted at the beginning of a line at column 0
StartOfLine = 0,
//! The comment marker is inserted after leading whitespaces right befire
@@ -127,7 +126,7 @@ public:
* Assignment operator.
* Both this definition as well as @p rhs share the Definition data.
*/
- Definition& operator=(const Definition &rhs);
+ Definition &operator=(const Definition &rhs);
/**
* Checks two definitions for equality.
@@ -330,7 +329,7 @@ public:
* @since 5.49
* @see keywordLists(), setKeywordList()
*/
- QStringList keywordList(const QString& name) const;
+ QStringList keywordList(const QString &name) const;
/**
* Set the contents of the keyword list @p name to @p content.
@@ -348,7 +347,7 @@ public:
* @see keywordList(), keywordLists()
* @since 5.62
*/
- bool setKeywordList(const QString& name, const QStringList& content);
+ bool setKeywordList(const QString &name, const QStringList &content);
/**
* Returns a list of all Format items used by this definition.
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 c73ca86eb9..f9b779482e 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/definition_p.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definition_p.h
@@ -24,8 +24,8 @@
#ifndef KSYNTAXHIGHLIGHTING_DEFINITION_P_H
#define KSYNTAXHIGHLIGHTING_DEFINITION_P_H
-#include "definitionref_p.h"
#include "definition.h"
+#include "definitionref_p.h"
#include <QHash>
#include <QString>
@@ -36,8 +36,8 @@ class QXmlStreamReader;
class QJsonObject;
QT_END_NAMESPACE
-namespace KSyntaxHighlighting {
-
+namespace KSyntaxHighlighting
+{
class Repository;
class DefinitionData
@@ -49,7 +49,7 @@ public:
DefinitionData(const DefinitionData &) = delete;
DefinitionData &operator=(const DefinitionData &) = delete;
- static DefinitionData* get(const Definition &def);
+ static DefinitionData *get(const Definition &def);
bool isLoaded() const;
bool loadMetaData(const QString &definitionFileName);
@@ -75,8 +75,8 @@ public:
KeywordList *keywordList(const QString &name);
bool isWordDelimiter(QChar c) const;
- Context* initialContext() const;
- Context* contextByName(const QString &name) const;
+ Context *initialContext() const;
+ Context *contextByName(const QString &name) const;
Format formatByName(const QString &name) const;
@@ -86,7 +86,7 @@ public:
Repository *repo = nullptr;
QHash<QString, KeywordList> keywordLists;
- QVector<Context*> contexts;
+ QVector<Context *> contexts;
QHash<QString, Format> formats;
QString wordDelimiters;
QString wordWrapDelimiters;
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.cpp
index 89a5952a3e..b1008dc44a 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.cpp
@@ -23,9 +23,9 @@
#include "definitiondownloader.h"
#include "definition.h"
-#include "repository.h"
#include "ksyntaxhighlighting_logging.h"
#include "ksyntaxhighlighting_version.h"
+#include "repository.h"
#include <QDir>
#include <QFile>
@@ -57,8 +57,9 @@ public:
void DefinitionDownloaderPrivate::definitionListDownloadFinished(QNetworkReply *reply)
{
- if (reply->error() != QNetworkReply::NoError) {
- qCWarning(Log) << reply->error();
+ const auto networkError = reply->error();
+ if (networkError != QNetworkReply::NoError) {
+ qCWarning(Log) << networkError;
emit q->done(); // TODO return error
return;
}
@@ -66,12 +67,12 @@ void DefinitionDownloaderPrivate::definitionListDownloadFinished(QNetworkReply *
QXmlStreamReader parser(reply);
while (!parser.atEnd()) {
switch (parser.readNext()) {
- case QXmlStreamReader::StartElement:
- if (parser.name() == QLatin1String("Definition"))
- updateDefinition(parser);
- break;
- default:
- break;
+ case QXmlStreamReader::StartElement:
+ if (parser.name() == QLatin1String("Definition"))
+ updateDefinition(parser);
+ break;
+ default:
+ break;
}
}
@@ -100,7 +101,7 @@ void DefinitionDownloaderPrivate::updateDefinition(QXmlStreamReader &parser)
}
}
-void DefinitionDownloaderPrivate::downloadDefinition(const QUrl& downloadUrl)
+void DefinitionDownloaderPrivate::downloadDefinition(const QUrl &downloadUrl)
{
if (!downloadUrl.isValid())
return;
@@ -110,9 +111,7 @@ void DefinitionDownloaderPrivate::downloadDefinition(const QUrl& downloadUrl)
QNetworkRequest req(url);
auto reply = nam->get(req);
- QObject::connect(reply, &QNetworkReply::finished, q, [this, reply]() {
- downloadDefinitionFinished(reply);
- });
+ QObject::connect(reply, &QNetworkReply::finished, q, [this, reply]() { downloadDefinitionFinished(reply); });
++pendingDownloads;
needsReload = true;
}
@@ -120,8 +119,10 @@ void DefinitionDownloaderPrivate::downloadDefinition(const QUrl& downloadUrl)
void DefinitionDownloaderPrivate::downloadDefinitionFinished(QNetworkReply *reply)
{
--pendingDownloads;
- if (reply->error() != QNetworkReply::NoError) {
- qCWarning(Log) << "Failed to download definition file" << reply->url() << reply->error();
+
+ const auto networkError = reply->error();
+ if (networkError != QNetworkReply::NoError) {
+ qCWarning(Log) << "Failed to download definition file" << reply->url() << networkError;
checkDone();
return;
}
@@ -154,7 +155,6 @@ void DefinitionDownloaderPrivate::checkDone()
}
}
-
DefinitionDownloader::DefinitionDownloader(Repository *repo, QObject *parent)
: QObject(parent)
, d(new DefinitionDownloaderPrivate())
@@ -178,15 +178,9 @@ DefinitionDownloader::~DefinitionDownloader()
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");
+ 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::FollowRedirectsAttribute, true);
auto reply = d->nam->get(req);
- QObject::connect(reply, &QNetworkReply::finished, this, [=]() {
- d->definitionListDownloadFinished(reply);
- });
+ 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 06e28f6a65..a1300d57e6 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.h
@@ -29,8 +29,8 @@
#include <QObject>
#include <memory>
-namespace KSyntaxHighlighting {
-
+namespace KSyntaxHighlighting
+{
class DefinitionDownloaderPrivate;
class Repository;
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 08604a4821..0e072db415 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/definitionref_p.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definitionref_p.h
@@ -26,8 +26,8 @@
#include <memory>
-namespace KSyntaxHighlighting {
-
+namespace KSyntaxHighlighting
+{
class Definition;
class DefinitionData;
class DefinitionPrivate;
@@ -46,7 +46,7 @@ public:
DefinitionRef();
explicit DefinitionRef(const Definition &def);
~DefinitionRef();
- DefinitionRef& operator=(const Definition &def);
+ DefinitionRef &operator=(const Definition &def);
Definition definition() const;
@@ -71,4 +71,3 @@ private:
}
#endif
-
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/foldingregion.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/foldingregion.cpp
index e8f89bd788..72a410cb2a 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/foldingregion.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/foldingregion.cpp
@@ -27,15 +27,15 @@ using namespace KSyntaxHighlighting;
static_assert(sizeof(FoldingRegion) == 2, "FoldingRegion is size-sensitive to frequent use in KTextEditor!");
-FoldingRegion::FoldingRegion() :
- m_type(None),
- m_id(0)
+FoldingRegion::FoldingRegion()
+ : m_type(None)
+ , m_id(0)
{
}
-FoldingRegion::FoldingRegion(Type type, quint16 id) :
- m_type(type),
- m_id(id)
+FoldingRegion::FoldingRegion(Type type, quint16 id)
+ : m_type(type)
+ , m_id(id)
{
}
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/foldingregion.h b/src/libs/3rdparty/syntax-highlighting/src/lib/foldingregion.h
index 074b9478be..ea26aba9b2 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/foldingregion.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/foldingregion.h
@@ -28,8 +28,8 @@
#include <QTypeInfo>
-namespace KSyntaxHighlighting {
-
+namespace KSyntaxHighlighting
+{
/** Represents a begin or end of a folding region.
* @since 5.28 */
class KSYNTAXHIGHLIGHTING_EXPORT FoldingRegion
@@ -96,7 +96,7 @@ private:
FoldingRegion(Type type, quint16 id);
quint16 m_type : 2;
- quint16 m_id: 14;
+ quint16 m_id : 14;
};
}
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/format.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/format.cpp
index 3407fee9f3..4c8adbedc6 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/format.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/format.cpp
@@ -22,9 +22,9 @@
*/
#include "format.h"
-#include "format_p.h"
#include "definition.h"
#include "definitionref_p.h"
+#include "format_p.h"
#include "textstyledata_p.h"
#include "themedata_p.h"
#include "xml_p.h"
@@ -51,7 +51,7 @@ static Theme::TextStyle stringToDefaultFormat(const QStringRef &str)
return static_cast<Theme::TextStyle>(value);
}
-FormatPrivate* FormatPrivate::detachAndGet(Format &format)
+FormatPrivate *FormatPrivate::detachAndGet(Format &format)
{
format.d.detach();
return format.d.data();
@@ -71,12 +71,13 @@ static QExplicitlySharedDataPointer<FormatPrivate> &sharedDefaultPrivate()
return def;
}
-Format::Format() : d(sharedDefaultPrivate())
+Format::Format()
+ : d(sharedDefaultPrivate())
{
}
-Format::Format(const Format &other) :
- d(other.d)
+Format::Format(const Format &other)
+ : d(other.d)
{
}
@@ -84,7 +85,7 @@ Format::~Format()
{
}
-Format& Format::operator=(const Format& other)
+Format &Format::operator=(const Format &other)
{
d = other.d;
return *this;
@@ -112,21 +113,14 @@ Theme::TextStyle Format::textStyle() const
bool Format::isDefaultTextStyle(const Theme &theme) const
{
- return (!hasTextColor(theme))
- && (!hasBackgroundColor(theme))
- && (selectedTextColor(theme) == theme.selectedTextColor(Theme::Normal))
- && (selectedBackgroundColor(theme) == theme.selectedBackgroundColor(Theme::Normal))
- && (isBold(theme) == theme.isBold(Theme::Normal))
- && (isItalic(theme) == theme.isItalic(Theme::Normal))
- && (isUnderline(theme) == theme.isUnderline(Theme::Normal))
- && (isStrikeThrough(theme) == theme.isStrikeThrough(Theme::Normal));
+ return (!hasTextColor(theme)) && (!hasBackgroundColor(theme)) && (selectedTextColor(theme) == theme.selectedTextColor(Theme::Normal)) && (selectedBackgroundColor(theme) == theme.selectedBackgroundColor(Theme::Normal)) &&
+ (isBold(theme) == theme.isBold(Theme::Normal)) && (isItalic(theme) == theme.isItalic(Theme::Normal)) && (isUnderline(theme) == theme.isUnderline(Theme::Normal)) && (isStrikeThrough(theme) == theme.isStrikeThrough(Theme::Normal));
}
bool Format::hasTextColor(const Theme &theme) const
{
const auto overrideStyle = d->styleOverride(theme);
- return textColor(theme) != theme.textColor(Theme::Normal)
- && (d->style.textColor || theme.textColor(d->defaultStyle) || overrideStyle.textColor);
+ return textColor(theme) != theme.textColor(Theme::Normal) && (d->style.textColor || theme.textColor(d->defaultStyle) || overrideStyle.textColor);
}
QColor Format::textColor(const Theme &theme) const
@@ -148,8 +142,7 @@ QColor Format::selectedTextColor(const Theme &theme) const
bool Format::hasBackgroundColor(const Theme &theme) const
{
const auto overrideStyle = d->styleOverride(theme);
- return backgroundColor(theme) != theme.backgroundColor(Theme::Normal)
- && (d->style.backgroundColor || theme.backgroundColor(d->defaultStyle) || overrideStyle.backgroundColor);
+ return backgroundColor(theme) != theme.backgroundColor(Theme::Normal) && (d->style.backgroundColor || theme.backgroundColor(d->defaultStyle) || overrideStyle.backgroundColor);
}
QColor Format::backgroundColor(const Theme &theme) const
@@ -165,8 +158,7 @@ QColor Format::selectedBackgroundColor(const Theme &theme) const
const auto overrideStyle = d->styleOverride(theme);
if (overrideStyle.selectedBackgroundColor)
return overrideStyle.selectedBackgroundColor;
- return d->style.selectedBackgroundColor ? d->style.selectedBackgroundColor
- : theme.selectedBackgroundColor(d->defaultStyle);
+ return d->style.selectedBackgroundColor ? d->style.selectedBackgroundColor : theme.selectedBackgroundColor(d->defaultStyle);
}
bool Format::isBold(const Theme &theme) const
@@ -246,8 +238,7 @@ bool Format::hasSelectedBackgroundColorOverride() const
return d->style.selectedBackgroundColor;
}
-
-void FormatPrivate::load(QXmlStreamReader& reader)
+void FormatPrivate::load(QXmlStreamReader &reader)
{
name = reader.attributes().value(QStringLiteral("name")).toString();
defaultStyle = stringToDefaultFormat(reader.attributes().value(QStringLiteral("defStyleNum")));
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/format.h b/src/libs/3rdparty/syntax-highlighting/src/lib/format.h
index 7c1b9602ba..25491809ae 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/format.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/format.h
@@ -35,8 +35,8 @@ class QString;
class QXmlStreamReader;
QT_END_NAMESPACE
-namespace KSyntaxHighlighting {
-
+namespace KSyntaxHighlighting
+{
class DefinitionRef;
class FormatPrivate;
@@ -55,7 +55,7 @@ public:
Format(const Format &other);
~Format();
- Format& operator=(const Format &other);
+ Format &operator=(const Format &other);
/** Returns @c true if this is a valid format, ie. one that
* was read from a syntax definition file.
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/format_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/format_p.h
index e79b26b6a7..91a4f1e912 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/format_p.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/format_p.h
@@ -31,13 +31,13 @@
#include <QSharedData>
#include <QString>
-namespace KSyntaxHighlighting {
-
+namespace KSyntaxHighlighting
+{
class FormatPrivate : public QSharedData
{
public:
FormatPrivate() = default;
- static FormatPrivate* detachAndGet(Format &format);
+ static FormatPrivate *detachAndGet(Format &format);
TextStyleData styleOverride(const Theme &theme) const;
void load(QXmlStreamReader &reader);
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/htmlhighlighter.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/htmlhighlighter.cpp
index 224fb72c34..1dad170744 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/htmlhighlighter.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/htmlhighlighter.cpp
@@ -25,9 +25,9 @@
#include "htmlhighlighter.h"
#include "definition.h"
#include "format.h"
+#include "ksyntaxhighlighting_logging.h"
#include "state.h"
#include "theme.h"
-#include "ksyntaxhighlighting_logging.h"
#include <QFile>
#include <QFileInfo>
@@ -53,7 +53,7 @@ HtmlHighlighter::~HtmlHighlighter()
{
}
-void HtmlHighlighter::setOutputFile(const QString& fileName)
+void HtmlHighlighter::setOutputFile(const QString &fileName)
{
d->file.reset(new QFile(fileName));
if (!d->file->open(QFile::WriteOnly | QFile::Truncate)) {
@@ -70,7 +70,7 @@ void HtmlHighlighter::setOutputFile(FILE *fileHandle)
d->out->setCodec("UTF-8");
}
-void HtmlHighlighter::highlightFile(const QString& fileName, const QString& title)
+void HtmlHighlighter::highlightFile(const QString &fileName, const QString &title)
{
QFileInfo fi(fileName);
QFile f(fileName);
@@ -85,7 +85,7 @@ void HtmlHighlighter::highlightFile(const QString& fileName, const QString& titl
highlightData(&f, title);
}
-void HtmlHighlighter::highlightData(QIODevice *dev, const QString& title)
+void HtmlHighlighter::highlightData(QIODevice *dev, const QString &title)
{
if (!d->out) {
qCWarning(Log) << "No output stream defined!";
@@ -124,7 +124,7 @@ void HtmlHighlighter::highlightData(QIODevice *dev, const QString& title)
d->file.reset();
}
-void HtmlHighlighter::applyFormat(int offset, int length, const Format& format)
+void HtmlHighlighter::applyFormat(int offset, int length, const Format &format)
{
if (length == 0)
return;
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/htmlhighlighter.h b/src/libs/3rdparty/syntax-highlighting/src/lib/htmlhighlighter.h
index b7eda02d54..7479ee2b63 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/htmlhighlighter.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/htmlhighlighter.h
@@ -24,11 +24,11 @@
#ifndef KSYNTAXHIGHLIGHTING_HTMLHIGHLIGHTER_H
#define KSYNTAXHIGHLIGHTING_HTMLHIGHLIGHTER_H
-#include "ksyntaxhighlighting_export.h"
#include "abstracthighlighter.h"
+#include "ksyntaxhighlighting_export.h"
-#include <QString>
#include <QIODevice>
+#include <QString>
#include <memory>
@@ -37,8 +37,8 @@ class QFile;
class QTextStream;
QT_END_NAMESPACE
-namespace KSyntaxHighlighting {
-
+namespace KSyntaxHighlighting
+{
class HtmlHighlighterPrivate;
class KSYNTAXHIGHLIGHTING_EXPORT HtmlHighlighter : public AbstractHighlighter
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist.cpp
index 144ced2c00..7cbbaecacf 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist.cpp
@@ -21,10 +21,10 @@
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#include "keywordlist_p.h"
-#include "repository.h"
#include "definition_p.h"
+#include "keywordlist_p.h"
#include "ksyntaxhighlighting_logging.h"
+#include "repository.h"
#include <QXmlStreamReader>
@@ -42,10 +42,10 @@ bool KeywordList::contains(const QStringRef &str, Qt::CaseSensitivity caseSensit
/**
* search with right predicate
*/
- return std::binary_search(vectorToSearch.begin(), vectorToSearch.end(), str, [caseSensitive] (const QStringRef &a, const QStringRef &b) { return a.compare(b, caseSensitive) < 0; });
+ return std::binary_search(vectorToSearch.begin(), vectorToSearch.end(), str, [caseSensitive](const QStringRef &a, const QStringRef &b) { return a.compare(b, caseSensitive) < 0; });
}
-void KeywordList::load(QXmlStreamReader& reader)
+void KeywordList::load(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("list"));
Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
@@ -54,25 +54,24 @@ void KeywordList::load(QXmlStreamReader& reader)
while (!reader.atEnd()) {
switch (reader.tokenType()) {
- case QXmlStreamReader::StartElement:
- if (reader.name() == QLatin1String("item")) {
- m_keywords.append(reader.readElementText().trimmed());
- reader.readNextStartElement();
- break;
- }
- else if (reader.name() == QLatin1String("include")) {
- m_includes.append(reader.readElementText().trimmed());
- reader.readNextStartElement();
- break;
- }
- reader.readNext();
+ case QXmlStreamReader::StartElement:
+ if (reader.name() == QLatin1String("item")) {
+ m_keywords.append(reader.readElementText().trimmed());
+ reader.readNextStartElement();
break;
- case QXmlStreamReader::EndElement:
- reader.readNext();
- return;
- default:
- reader.readNext();
+ } else if (reader.name() == QLatin1String("include")) {
+ m_includes.append(reader.readElementText().trimmed());
+ reader.readNextStartElement();
break;
+ }
+ reader.readNext();
+ break;
+ case QXmlStreamReader::EndElement:
+ reader.readNext();
+ return;
+ default:
+ reader.readNext();
+ break;
}
}
}
@@ -107,7 +106,7 @@ void KeywordList::initLookupForCaseSensitivity(Qt::CaseSensitivity caseSensitive
/**
* sort with right predicate
*/
- std::sort(vectorToSort.begin(), vectorToSort.end(), [caseSensitive] (const QStringRef &a, const QStringRef &b) { return a.compare(b, caseSensitive) < 0; });
+ std::sort(vectorToSort.begin(), vectorToSort.end(), [caseSensitive](const QStringRef &a, const QStringRef &b) { return a.compare(b, caseSensitive) < 0; });
}
void KeywordList::resolveIncludeKeywords(DefinitionData &def)
@@ -127,8 +126,7 @@ void KeywordList::resolveIncludeKeywords(DefinitionData &def)
auto defData = DefinitionData::get(includeDef);
defData->load(DefinitionData::OnlyKeywords(true));
keywords = defData->keywordList(listName);
- }
- else {
+ } else {
qCWarning(Log) << "Unable to resolve external include keyword for definition" << defName << "in" << def.name;
}
} else {
@@ -140,8 +138,7 @@ void KeywordList::resolveIncludeKeywords(DefinitionData &def)
keywords->resolveIncludeKeywords(def);
}
m_keywords += keywords->m_keywords;
- }
- else {
+ } else {
qCWarning(Log) << "Unresolved include keyword" << kw_include << "in" << def.name;
}
}
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 f99a027823..e21149e909 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist_p.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist_p.h
@@ -33,8 +33,8 @@ QT_BEGIN_NAMESPACE
class QXmlStreamReader;
QT_END_NAMESPACE
-namespace KSyntaxHighlighting {
-
+namespace KSyntaxHighlighting
+{
class Repository;
class DefinitionData;
@@ -59,7 +59,7 @@ public:
return m_keywords;
}
- void setKeywordList(const QStringList& keywords)
+ void setKeywordList(const QStringList &keywords)
{
m_keywords = keywords;
m_keywordsSortedCaseSensitive.clear();
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/matchresult_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/matchresult_p.h
index b1a05ee636..c79801dd3d 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/matchresult_p.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/matchresult_p.h
@@ -26,8 +26,8 @@
#include <QStringList>
-namespace KSyntaxHighlighting {
-
+namespace KSyntaxHighlighting
+{
/**
* Storage for match result of a Rule.
* Heavily used internally during highlightLine, therefore completely inline.
@@ -73,7 +73,6 @@ public:
return m_offset;
}
-
/**
* Skip offset of the match
* @return skip offset of the match, no match possible until this offset is reached
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/repository.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/repository.cpp
index c4e4889fa2..f61365869e 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/repository.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/repository.cpp
@@ -22,12 +22,12 @@
*/
#include "repository.h"
-#include "repository_p.h"
#include "definition.h"
#include "definition_p.h"
+#include "ksyntaxhighlighting_logging.h"
+#include "repository_p.h"
#include "theme.h"
#include "themedata_p.h"
-#include "ksyntaxhighlighting_logging.h"
#include "wildcardmatcher_p.h"
#include <QDirIterator>
@@ -52,13 +52,13 @@ static void initResource()
Q_INIT_RESOURCE(theme_data);
}
-RepositoryPrivate* RepositoryPrivate::get(Repository *repo)
+RepositoryPrivate *RepositoryPrivate::get(Repository *repo)
{
return repo->d.get();
}
-Repository::Repository() :
- d(new RepositoryPrivate)
+Repository::Repository()
+ : d(new RepositoryPrivate)
{
initResource();
d->load(this);
@@ -72,19 +72,17 @@ Repository::~Repository()
DefinitionData::get(def)->repo = nullptr;
}
-Definition Repository::definitionForName(const QString& defName) const
+Definition Repository::definitionForName(const QString &defName) const
{
return d->m_defs.value(defName);
}
static void sortDefinitions(QVector<Definition> &definitions)
{
- std::stable_sort(definitions.begin(), definitions.end(), [](const Definition &lhs, const Definition &rhs) {
- return lhs.priority() > rhs.priority();
- });
+ std::stable_sort(definitions.begin(), definitions.end(), [](const Definition &lhs, const Definition &rhs) { return lhs.priority() > rhs.priority(); });
}
-Definition Repository::definitionForFileName(const QString& fileName) const
+Definition Repository::definitionForFileName(const QString &fileName) const
{
return definitionsForFileName(fileName).value(0);
}
@@ -108,7 +106,7 @@ QVector<Definition> Repository::definitionsForFileName(const QString &fileName)
return candidates;
}
-Definition Repository::definitionForMimeType(const QString& mimeType) const
+Definition Repository::definitionForMimeType(const QString &mimeType) const
{
return definitionsForMimeType(mimeType).value(0);
}
@@ -273,9 +271,7 @@ static int themeRevision(const Theme &theme)
void RepositoryPrivate::addTheme(const Theme &theme)
{
- const auto it = std::lower_bound(m_themes.begin(), m_themes.end(), theme, [](const Theme &lhs, const Theme &rhs) {
- return lhs.name() < rhs.name();
- });
+ const auto it = std::lower_bound(m_themes.begin(), m_themes.end(), theme, [](const Theme &lhs, const Theme &rhs) { return lhs.name() < rhs.name(); });
if (it == m_themes.end() || (*it).name() != theme.name()) {
m_themes.insert(it, theme);
return;
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/repository.h b/src/libs/3rdparty/syntax-highlighting/src/lib/repository.h
index 2bc66965cf..8c0ef76306 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/repository.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/repository.h
@@ -26,12 +26,12 @@
#include "ksyntaxhighlighting_export.h"
-#include <qglobal.h>
#include <memory>
+#include <qglobal.h>
QT_BEGIN_NAMESPACE
class QString;
-template <typename T> class QVector;
+template<typename T> class QVector;
QT_END_NAMESPACE
/**
@@ -43,8 +43,8 @@ QT_END_NAMESPACE
*
* @see Repository
*/
-namespace KSyntaxHighlighting {
-
+namespace KSyntaxHighlighting
+{
class Definition;
class RepositoryPrivate;
class Theme;
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/repository_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/repository_p.h
index 9db876be59..81cba47942 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/repository_p.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/repository_p.h
@@ -31,8 +31,8 @@ QT_BEGIN_NAMESPACE
class QString;
QT_END_NAMESPACE
-namespace KSyntaxHighlighting {
-
+namespace KSyntaxHighlighting
+{
class Definition;
class Repository;
class Theme;
@@ -42,7 +42,7 @@ class RepositoryPrivate
public:
RepositoryPrivate() = default;
- static RepositoryPrivate* get(Repository *repo);
+ static RepositoryPrivate *get(Repository *repo);
void load(Repository *repo);
void loadSyntaxFolder(Repository *repo, const QString &path);
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/rule.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/rule.cpp
index 79b110d70a..0d7d843c00 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/rule.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/rule.cpp
@@ -22,10 +22,10 @@
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#include "rule_p.h"
#include "context_p.h"
#include "definition_p.h"
#include "ksyntaxhighlighting_logging.h"
+#include "rule_p.h"
#include "xml_p.h"
#include <QString>
@@ -40,13 +40,8 @@ static bool isOctalChar(QChar c)
static bool isHexChar(QChar c)
{
- return c.isNumber()
- || c == QLatin1Char('a') || c == QLatin1Char('A')
- || c == QLatin1Char('b') || c == QLatin1Char('B')
- || c == QLatin1Char('c') || c == QLatin1Char('C')
- || c == QLatin1Char('d') || c == QLatin1Char('D')
- || c == QLatin1Char('e') || c == QLatin1Char('E')
- || c == QLatin1Char('f') || c == QLatin1Char('F');
+ return c.isNumber() || c == QLatin1Char('a') || c == QLatin1Char('A') || c == QLatin1Char('b') || c == QLatin1Char('B') || c == QLatin1Char('c') || c == QLatin1Char('C') || c == QLatin1Char('d') || c == QLatin1Char('D') ||
+ c == QLatin1Char('e') || c == QLatin1Char('E') || c == QLatin1Char('f') || c == QLatin1Char('F');
}
static int matchEscapedChar(const QString &text, int offset)
@@ -155,13 +150,13 @@ void Rule::resolveAttributeFormat(Context *lookupContext)
}
}
-bool Rule::doLoad(QXmlStreamReader& reader)
+bool Rule::doLoad(QXmlStreamReader &reader)
{
Q_UNUSED(reader);
return true;
}
-Rule::Ptr Rule::create(const QStringRef& name)
+Rule::Ptr Rule::create(const QStringRef &name)
{
Rule *rule = nullptr;
if (name == QLatin1String("AnyChar"))
@@ -212,8 +207,7 @@ bool Rule::isWordDelimiter(QChar c) const
return m_wordDelimiter.contains(c);
}
-
-bool AnyChar::doLoad(QXmlStreamReader& reader)
+bool AnyChar::doLoad(QXmlStreamReader &reader)
{
m_chars = reader.attributes().value(QStringLiteral("String")).toString();
if (m_chars.size() == 1)
@@ -221,15 +215,14 @@ bool AnyChar::doLoad(QXmlStreamReader& reader)
return !m_chars.isEmpty();
}
-MatchResult AnyChar::doMatch(const QString& text, int offset, const QStringList&) const
+MatchResult AnyChar::doMatch(const QString &text, int offset, const QStringList &) const
{
if (m_chars.contains(text.at(offset)))
return offset + 1;
return offset;
}
-
-bool DetectChar::doLoad(QXmlStreamReader& reader)
+bool DetectChar::doLoad(QXmlStreamReader &reader)
{
const auto s = reader.attributes().value(QStringLiteral("char"));
if (s.isEmpty())
@@ -242,7 +235,7 @@ bool DetectChar::doLoad(QXmlStreamReader& reader)
return true;
}
-MatchResult DetectChar::doMatch(const QString& text, int offset, const QStringList &captures) const
+MatchResult DetectChar::doMatch(const QString &text, int offset, const QStringList &captures) const
{
if (m_dynamic) {
if (m_captureIndex == 0 || captures.size() <= m_captureIndex || captures.at(m_captureIndex).isEmpty())
@@ -257,8 +250,7 @@ MatchResult DetectChar::doMatch(const QString& text, int offset, const QStringLi
return offset;
}
-
-bool Detect2Char::doLoad(QXmlStreamReader& reader)
+bool Detect2Char::doLoad(QXmlStreamReader &reader)
{
const auto s1 = reader.attributes().value(QStringLiteral("char"));
const auto s2 = reader.attributes().value(QStringLiteral("char1"));
@@ -269,7 +261,7 @@ bool Detect2Char::doLoad(QXmlStreamReader& reader)
return true;
}
-MatchResult Detect2Char::doMatch(const QString& text, int offset, const QStringList &) const
+MatchResult Detect2Char::doMatch(const QString &text, int offset, const QStringList &) const
{
if (text.size() - offset < 2)
return offset;
@@ -278,8 +270,7 @@ MatchResult Detect2Char::doMatch(const QString& text, int offset, const QStringL
return offset;
}
-
-MatchResult DetectIdentifier::doMatch(const QString& text, int offset, const QStringList&) const
+MatchResult DetectIdentifier::doMatch(const QString &text, int offset, const QStringList &) const
{
if (!text.at(offset).isLetter() && text.at(offset) != QLatin1Char('_'))
return offset;
@@ -293,16 +284,14 @@ MatchResult DetectIdentifier::doMatch(const QString& text, int offset, const QSt
return text.size();
}
-
-MatchResult DetectSpaces::doMatch(const QString& text, int offset, const QStringList&) const
+MatchResult DetectSpaces::doMatch(const QString &text, int offset, const QStringList &) const
{
- while(offset < text.size() && text.at(offset).isSpace())
+ while (offset < text.size() && text.at(offset).isSpace())
++offset;
return offset;
}
-
-MatchResult Float::doMatch(const QString& text, int offset, const QStringList&) const
+MatchResult Float::doMatch(const QString &text, int offset, const QStringList &) const
{
if (offset > 0 && !isWordDelimiter(text.at(offset - 1)))
return offset;
@@ -339,8 +328,7 @@ MatchResult Float::doMatch(const QString& text, int offset, const QStringList&)
return expOffset;
}
-
-MatchResult HlCChar::doMatch(const QString& text, int offset, const QStringList&) const
+MatchResult HlCChar::doMatch(const QString &text, int offset, const QStringList &) const
{
if (text.size() < offset + 3)
return offset;
@@ -364,8 +352,7 @@ MatchResult HlCChar::doMatch(const QString& text, int offset, const QStringList&
return offset;
}
-
-MatchResult HlCHex::doMatch(const QString& text, int offset, const QStringList&) const
+MatchResult HlCHex::doMatch(const QString &text, int offset, const QStringList &) const
{
if (offset > 0 && !isWordDelimiter(text.at(offset - 1)))
return offset;
@@ -388,8 +375,7 @@ MatchResult HlCHex::doMatch(const QString& text, int offset, const QStringList&)
return offset;
}
-
-MatchResult HlCOct::doMatch(const QString& text, int offset, const QStringList&) const
+MatchResult HlCOct::doMatch(const QString &text, int offset, const QStringList &) const
{
if (offset > 0 && !isWordDelimiter(text.at(offset - 1)))
return offset;
@@ -410,13 +396,11 @@ MatchResult HlCOct::doMatch(const QString& text, int offset, const QStringList&)
return offset;
}
-
-MatchResult HlCStringChar::doMatch(const QString& text, int offset, const QStringList&) const
+MatchResult HlCStringChar::doMatch(const QString &text, int offset, const QStringList &) const
{
return matchEscapedChar(text, offset);
}
-
QString IncludeRules::contextName() const
{
return m_contextName;
@@ -432,10 +416,14 @@ bool IncludeRules::includeAttribute() const
return m_includeAttribute;
}
-bool IncludeRules::doLoad(QXmlStreamReader& reader)
+bool IncludeRules::doLoad(QXmlStreamReader &reader)
{
const auto s = reader.attributes().value(QLatin1String("context"));
+#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
const auto split = s.split(QLatin1String("##"), QString::KeepEmptyParts);
+#else
+ const auto split = s.split(QLatin1String("##"), Qt::KeepEmptyParts);
+#endif
if (split.isEmpty())
return false;
m_contextName = split.at(0).toString();
@@ -446,26 +434,24 @@ bool IncludeRules::doLoad(QXmlStreamReader& reader)
return !m_contextName.isEmpty() || !m_defName.isEmpty();
}
-MatchResult IncludeRules::doMatch(const QString& text, int offset, const QStringList&) const
+MatchResult IncludeRules::doMatch(const QString &text, int offset, const QStringList &) const
{
Q_UNUSED(text);
qCWarning(Log) << "Unresolved include rule for" << m_contextName << "##" << m_defName;
return offset;
}
-
-MatchResult Int::doMatch(const QString& text, int offset, const QStringList &) const
+MatchResult Int::doMatch(const QString &text, int offset, const QStringList &) const
{
if (offset > 0 && !isWordDelimiter(text.at(offset - 1)))
return offset;
- while(offset < text.size() && text.at(offset).isDigit())
+ while (offset < text.size() && text.at(offset).isDigit())
++offset;
return offset;
}
-
-bool KeywordListRule::doLoad(QXmlStreamReader& reader)
+bool KeywordListRule::doLoad(QXmlStreamReader &reader)
{
/**
* get our keyword list, if not found => bail out
@@ -482,8 +468,7 @@ bool KeywordListRule::doLoad(QXmlStreamReader& reader)
*/
if (reader.attributes().hasAttribute(QLatin1String("insensitive"))) {
m_hasCaseSensitivityOverride = true;
- m_caseSensitivityOverride = Xml::attrToBool(reader.attributes().value(QLatin1String("insensitive"))) ?
- Qt::CaseInsensitive : Qt::CaseSensitive;
+ m_caseSensitivityOverride = Xml::attrToBool(reader.attributes().value(QLatin1String("insensitive"))) ? Qt::CaseInsensitive : Qt::CaseSensitive;
m_keywordList->initLookupForCaseSensitivity(m_caseSensitivityOverride);
} else {
m_hasCaseSensitivityOverride = false;
@@ -492,7 +477,7 @@ bool KeywordListRule::doLoad(QXmlStreamReader& reader)
return !m_keywordList->isEmpty();
}
-MatchResult KeywordListRule::doMatch(const QString& text, int offset, const QStringList&) const
+MatchResult KeywordListRule::doMatch(const QString &text, int offset, const QStringList &) const
{
auto newOffset = offset;
while (text.size() > newOffset && !isWordDelimiter(text.at(newOffset)))
@@ -512,8 +497,7 @@ MatchResult KeywordListRule::doMatch(const QString& text, int offset, const QStr
return MatchResult(offset, newOffset);
}
-
-bool LineContinue::doLoad(QXmlStreamReader& reader)
+bool LineContinue::doLoad(QXmlStreamReader &reader)
{
const auto s = reader.attributes().value(QStringLiteral("char"));
if (s.isEmpty())
@@ -523,15 +507,14 @@ bool LineContinue::doLoad(QXmlStreamReader& reader)
return true;
}
-MatchResult LineContinue::doMatch(const QString& text, int offset, const QStringList&) const
+MatchResult LineContinue::doMatch(const QString &text, int offset, const QStringList &) const
{
if (offset == text.size() - 1 && text.at(offset) == m_char)
return offset + 1;
return offset;
}
-
-bool RangeDetect::doLoad(QXmlStreamReader& reader)
+bool RangeDetect::doLoad(QXmlStreamReader &reader)
{
const auto s1 = reader.attributes().value(QStringLiteral("char"));
const auto s2 = reader.attributes().value(QStringLiteral("char1"));
@@ -542,7 +525,7 @@ bool RangeDetect::doLoad(QXmlStreamReader& reader)
return true;
}
-MatchResult RangeDetect::doMatch(const QString& text, int offset, const QStringList&) const
+MatchResult RangeDetect::doMatch(const QString &text, int offset, const QStringList &) const
{
if (text.size() - offset < 2)
return offset;
@@ -558,15 +541,13 @@ MatchResult RangeDetect::doMatch(const QString& text, int offset, const QStringL
return offset;
}
-bool RegExpr::doLoad(QXmlStreamReader& reader)
+bool RegExpr::doLoad(QXmlStreamReader &reader)
{
m_regexp.setPattern(reader.attributes().value(QStringLiteral("String")).toString());
const auto isMinimal = Xml::attrToBool(reader.attributes().value(QStringLiteral("minimal")));
const auto isCaseInsensitive = Xml::attrToBool(reader.attributes().value(QStringLiteral("insensitive")));
- m_regexp.setPatternOptions(
- (isMinimal ? QRegularExpression::InvertedGreedinessOption : QRegularExpression::NoPatternOption) |
- (isCaseInsensitive ? QRegularExpression::CaseInsensitiveOption : QRegularExpression::NoPatternOption));
+ m_regexp.setPatternOptions((isMinimal ? QRegularExpression::InvertedGreedinessOption : QRegularExpression::NoPatternOption) | (isCaseInsensitive ? QRegularExpression::CaseInsensitiveOption : QRegularExpression::NoPatternOption));
// optimize the pattern for the non-dynamic case, we use them OFTEN
m_dynamic = Xml::attrToBool(reader.attributes().value(QStringLiteral("dynamic")));
@@ -583,7 +564,7 @@ bool RegExpr::doLoad(QXmlStreamReader& reader)
return !m_regexp.pattern().isEmpty();
}
-MatchResult RegExpr::doMatch(const QString& text, int offset, const QStringList &captures) const
+MatchResult RegExpr::doMatch(const QString &text, int offset, const QStringList &captures) const
{
/**
* for dynamic case: create new pattern with right instantiation
@@ -612,14 +593,12 @@ MatchResult RegExpr::doMatch(const QString& text, int offset, const QStringList
/**
* no match
- * the pattern of a dynamic regex depends on the previous contexts
- * so that skipOffset cannot be computed
+ * we can always compute the skip offset as the highlighter will invalidate the cache for changed captures for dynamic rules!
*/
- return MatchResult(offset, m_dynamic ? 0 : result.capturedStart());
+ return MatchResult(offset, result.capturedStart());
}
-
-bool StringDetect::doLoad(QXmlStreamReader& reader)
+bool StringDetect::doLoad(QXmlStreamReader &reader)
{
m_string = reader.attributes().value(QStringLiteral("String")).toString();
m_caseSensitivity = Xml::attrToBool(reader.attributes().value(QStringLiteral("insensitive"))) ? Qt::CaseInsensitive : Qt::CaseSensitive;
@@ -627,7 +606,7 @@ bool StringDetect::doLoad(QXmlStreamReader& reader)
return !m_string.isEmpty();
}
-MatchResult StringDetect::doMatch(const QString& text, int offset, const QStringList &captures) const
+MatchResult StringDetect::doMatch(const QString &text, int offset, const QStringList &captures) const
{
/**
* for dynamic case: create new pattern with right instantiation
@@ -639,15 +618,14 @@ MatchResult StringDetect::doMatch(const QString& text, int offset, const QString
return offset;
}
-
-bool WordDetect::doLoad(QXmlStreamReader& reader)
+bool WordDetect::doLoad(QXmlStreamReader &reader)
{
m_word = reader.attributes().value(QStringLiteral("String")).toString();
m_caseSensitivity = Xml::attrToBool(reader.attributes().value(QStringLiteral("insensitive"))) ? Qt::CaseInsensitive : Qt::CaseSensitive;
return !m_word.isEmpty();
}
-MatchResult WordDetect::doMatch(const QString& text, int offset, const QStringList &) const
+MatchResult WordDetect::doMatch(const QString &text, int offset, const QStringList &) const
{
if (text.size() - offset < m_word.size())
return offset;
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 4ddee3cbfd..c30ea29a54 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/rule_p.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/rule_p.h
@@ -41,8 +41,8 @@ QT_BEGIN_NAMESPACE
class QXmlStreamReader;
QT_END_NAMESPACE
-namespace KSyntaxHighlighting {
-
+namespace KSyntaxHighlighting
+{
class Rule
{
public:
@@ -69,6 +69,11 @@ public:
return m_lookAhead;
}
+ bool isDynamic() const
+ {
+ return m_dynamic;
+ }
+
bool firstNonSpace() const
{
return m_firstNonSpace;
@@ -117,14 +122,16 @@ private:
// cache for DefinitionData::wordDelimiters, is accessed VERY often
QStringRef m_wordDelimiter;
-};
+protected:
+ bool m_dynamic = false;
+};
class AnyChar : public Rule
{
protected:
- bool doLoad(QXmlStreamReader & reader) override;
- MatchResult doMatch(const QString & text, int offset, const QStringList&) const override;
+ bool doLoad(QXmlStreamReader &reader) override;
+ MatchResult doMatch(const QString &text, int offset, const QStringList &) const override;
private:
QString m_chars;
@@ -133,20 +140,19 @@ private:
class DetectChar : public Rule
{
protected:
- bool doLoad(QXmlStreamReader & reader) override;
- MatchResult doMatch(const QString & text, int offset, const QStringList &captures) const override;
+ bool doLoad(QXmlStreamReader &reader) override;
+ MatchResult doMatch(const QString &text, int offset, const QStringList &captures) const override;
private:
QChar m_char;
- bool m_dynamic = false;
int m_captureIndex = 0;
};
class Detect2Char : public Rule
{
protected:
- bool doLoad(QXmlStreamReader & reader) override;
- MatchResult doMatch(const QString & text, int offset, const QStringList &captures) const override;
+ bool doLoad(QXmlStreamReader &reader) override;
+ MatchResult doMatch(const QString &text, int offset, const QStringList &captures) const override;
private:
QChar m_char1;
@@ -156,19 +162,19 @@ private:
class DetectIdentifier : public Rule
{
protected:
- MatchResult doMatch(const QString & text, int offset, const QStringList&) const override;
+ MatchResult doMatch(const QString &text, int offset, const QStringList &) const override;
};
class DetectSpaces : public Rule
{
protected:
- MatchResult doMatch(const QString & text, int offset, const QStringList&) const override;
+ MatchResult doMatch(const QString &text, int offset, const QStringList &) const override;
};
class Float : public Rule
{
protected:
- MatchResult doMatch(const QString & text, int offset, const QStringList&) const override;
+ MatchResult doMatch(const QString &text, int offset, const QStringList &) const override;
};
class IncludeRules : public Rule
@@ -179,8 +185,8 @@ public:
bool includeAttribute() const;
protected:
- bool doLoad(QXmlStreamReader & reader) override;
- MatchResult doMatch(const QString & text, int offset, const QStringList&) const override;
+ bool doLoad(QXmlStreamReader &reader) override;
+ MatchResult doMatch(const QString &text, int offset, const QStringList &) const override;
private:
QString m_contextName;
@@ -191,38 +197,38 @@ private:
class Int : public Rule
{
protected:
- MatchResult doMatch(const QString & text, int offset, const QStringList &captures) const override;
+ MatchResult doMatch(const QString &text, int offset, const QStringList &captures) const override;
};
class HlCChar : public Rule
{
protected:
- MatchResult doMatch(const QString & text, int offset, const QStringList&) const override;
+ MatchResult doMatch(const QString &text, int offset, const QStringList &) const override;
};
class HlCHex : public Rule
{
protected:
- MatchResult doMatch(const QString & text, int offset, const QStringList&) const override;
+ MatchResult doMatch(const QString &text, int offset, const QStringList &) const override;
};
class HlCOct : public Rule
{
protected:
- MatchResult doMatch(const QString & text, int offset, const QStringList&) const override;
+ MatchResult doMatch(const QString &text, int offset, const QStringList &) const override;
};
class HlCStringChar : public Rule
{
protected:
- MatchResult doMatch(const QString & text, int offset, const QStringList&) const override;
+ MatchResult doMatch(const QString &text, int offset, const QStringList &) const override;
};
class KeywordListRule : public Rule
{
protected:
- bool doLoad(QXmlStreamReader & reader) override;
- MatchResult doMatch(const QString & text, int offset, const QStringList&) const override;
+ bool doLoad(QXmlStreamReader &reader) override;
+ MatchResult doMatch(const QString &text, int offset, const QStringList &) const override;
private:
KeywordList *m_keywordList;
@@ -233,8 +239,8 @@ private:
class LineContinue : public Rule
{
protected:
- bool doLoad(QXmlStreamReader & reader) override;
- MatchResult doMatch(const QString & text, int offset, const QStringList&) const override;
+ bool doLoad(QXmlStreamReader &reader) override;
+ MatchResult doMatch(const QString &text, int offset, const QStringList &) const override;
private:
QChar m_char;
@@ -243,8 +249,8 @@ private:
class RangeDetect : public Rule
{
protected:
- bool doLoad(QXmlStreamReader & reader) override;
- MatchResult doMatch(const QString & text, int offset, const QStringList&) const override;
+ bool doLoad(QXmlStreamReader &reader) override;
+ MatchResult doMatch(const QString &text, int offset, const QStringList &) const override;
private:
QChar m_begin;
@@ -254,31 +260,29 @@ private:
class RegExpr : public Rule
{
protected:
- bool doLoad(QXmlStreamReader & reader) override;
- MatchResult doMatch(const QString & text, int offset, const QStringList &captures) const override;
+ bool doLoad(QXmlStreamReader &reader) override;
+ MatchResult doMatch(const QString &text, int offset, const QStringList &captures) const override;
private:
QRegularExpression m_regexp;
- bool m_dynamic = false;
};
class StringDetect : public Rule
{
protected:
- bool doLoad(QXmlStreamReader & reader) override;
- MatchResult doMatch(const QString & text, int offset, const QStringList &captures) const override;
+ bool doLoad(QXmlStreamReader &reader) override;
+ MatchResult doMatch(const QString &text, int offset, const QStringList &captures) const override;
private:
QString m_string;
Qt::CaseSensitivity m_caseSensitivity;
- bool m_dynamic = false;
};
class WordDetect : public Rule
{
protected:
- bool doLoad(QXmlStreamReader & reader) override;
- MatchResult doMatch(const QString & text, int offset, const QStringList &captures) const override;
+ bool doLoad(QXmlStreamReader &reader) override;
+ MatchResult doMatch(const QString &text, int offset, const QStringList &captures) const override;
private:
QString m_word;
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/state.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/state.cpp
index f970e13f8b..4b4faa956d 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/state.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/state.cpp
@@ -31,7 +31,7 @@
using namespace KSyntaxHighlighting;
-StateData* StateData::get(State &state)
+StateData *StateData::get(State &state)
{
state.d.detach();
return state.d.data();
@@ -72,7 +72,7 @@ bool StateData::pop(int popCount)
return initialContextSurvived;
}
-Context* StateData::topContext() const
+Context *StateData::topContext() const
{
Q_ASSERT(!isEmpty());
return m_contextStack.last().first;
@@ -84,13 +84,13 @@ const QStringList &StateData::topCaptures() const
return m_contextStack.last().second;
}
-State::State() :
- d(new StateData)
+State::State()
+ : d(new StateData)
{
}
-State::State(const State &other) :
- d(other.d)
+State::State(const State &other)
+ : d(other.d)
{
}
@@ -98,7 +98,7 @@ State::~State()
{
}
-State& State::operator=(const State &other)
+State &State::operator=(const State &other)
{
d = other.d;
return *this;
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/state.h b/src/libs/3rdparty/syntax-highlighting/src/lib/state.h
index 865589f28e..ed63274695 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/state.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/state.h
@@ -28,8 +28,8 @@
#include <QExplicitlySharedDataPointer>
-namespace KSyntaxHighlighting {
-
+namespace KSyntaxHighlighting
+{
class StateData;
/** Opaque handle to the state of the highlighting engine.
@@ -48,7 +48,7 @@ public:
State();
State(const State &other);
~State();
- State& operator=(const State &rhs);
+ State &operator=(const State &rhs);
/** Compares two states for equality.
* For two equal states and identical text input, AbstractHighlighter
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/state_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/state_p.h
index a99192b4c6..fbc1686143 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/state_p.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/state_p.h
@@ -36,7 +36,6 @@ QT_END_NAMESPACE
namespace KSyntaxHighlighting
{
-
class Context;
class StateData : public QSharedData
@@ -46,7 +45,7 @@ class StateData : public QSharedData
public:
StateData() = default;
- static StateData* get(State &state);
+ static StateData *get(State &state);
bool isEmpty() const;
void clear();
@@ -61,7 +60,7 @@ public:
*/
bool pop(int popCount);
- Context* topContext() const;
+ Context *topContext() const;
const QStringList &topCaptures() const;
private:
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.cpp
index 89663d8af3..a6bccffdd4 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.cpp
@@ -29,12 +29,12 @@
#include "state.h"
#include "theme.h"
-
Q_DECLARE_METATYPE(QTextBlock)
using namespace KSyntaxHighlighting;
-namespace KSyntaxHighlighting {
+namespace KSyntaxHighlighting
+{
class TextBlockUserData : public QTextBlockUserData
{
public:
@@ -51,9 +51,9 @@ public:
}
-FoldingRegion SyntaxHighlighterPrivate::foldingRegion(const QTextBlock& startBlock)
+FoldingRegion SyntaxHighlighterPrivate::foldingRegion(const QTextBlock &startBlock)
{
- const auto data = dynamic_cast<TextBlockUserData*>(startBlock.userData());
+ const auto data = dynamic_cast<TextBlockUserData *>(startBlock.userData());
if (!data)
return FoldingRegion();
for (int i = data->foldingRegions.size() - 1; i >= 0; --i) {
@@ -63,16 +63,16 @@ FoldingRegion SyntaxHighlighterPrivate::foldingRegion(const QTextBlock& startBlo
return FoldingRegion();
}
-SyntaxHighlighter::SyntaxHighlighter(QObject* parent) :
- QSyntaxHighlighter(parent),
- AbstractHighlighter(new SyntaxHighlighterPrivate)
+SyntaxHighlighter::SyntaxHighlighter(QObject *parent)
+ : QSyntaxHighlighter(parent)
+ , AbstractHighlighter(new SyntaxHighlighterPrivate)
{
qRegisterMetaType<QTextBlock>();
}
-SyntaxHighlighter::SyntaxHighlighter(QTextDocument *document) :
- QSyntaxHighlighter(document),
- AbstractHighlighter(new SyntaxHighlighterPrivate)
+SyntaxHighlighter::SyntaxHighlighter(QTextDocument *document)
+ : QSyntaxHighlighter(document)
+ , AbstractHighlighter(new SyntaxHighlighterPrivate)
{
qRegisterMetaType<QTextBlock>();
}
@@ -81,7 +81,7 @@ SyntaxHighlighter::~SyntaxHighlighter()
{
}
-void SyntaxHighlighter::setDefinition(const Definition& def)
+void SyntaxHighlighter::setDefinition(const Definition &def)
{
const auto needsRehighlight = definition() != def;
AbstractHighlighter::setDefinition(def);
@@ -102,7 +102,7 @@ QTextBlock SyntaxHighlighter::findFoldingRegionEnd(const QTextBlock &startBlock)
int depth = 1;
while (block.isValid()) {
block = block.next();
- const auto data = dynamic_cast<TextBlockUserData*>(block.userData());
+ const auto data = dynamic_cast<TextBlockUserData *>(block.userData());
if (!data)
continue;
for (auto it = data->foldingRegions.constBegin(); it != data->foldingRegions.constEnd(); ++it) {
@@ -120,21 +120,21 @@ QTextBlock SyntaxHighlighter::findFoldingRegionEnd(const QTextBlock &startBlock)
return QTextBlock();
}
-void SyntaxHighlighter::highlightBlock(const QString& text)
+void SyntaxHighlighter::highlightBlock(const QString &text)
{
Q_D(SyntaxHighlighter);
State state;
if (currentBlock().position() > 0) {
const auto prevBlock = currentBlock().previous();
- const auto prevData = dynamic_cast<TextBlockUserData*>(prevBlock.userData());
+ const auto prevData = dynamic_cast<TextBlockUserData *>(prevBlock.userData());
if (prevData)
state = prevData->state;
}
d->foldingRegions.clear();
state = highlightLine(text, state);
- auto data = dynamic_cast<TextBlockUserData*>(currentBlockUserData());
+ auto data = dynamic_cast<TextBlockUserData *>(currentBlockUserData());
if (!data) { // first time we highlight this
data = new TextBlockUserData;
data->state = state;
@@ -153,7 +153,7 @@ void SyntaxHighlighter::highlightBlock(const QString& text)
QMetaObject::invokeMethod(this, "rehighlightBlock", Qt::QueuedConnection, Q_ARG(QTextBlock, nextBlock));
}
-void SyntaxHighlighter::applyFormat(int offset, int length, const KSyntaxHighlighting::Format& format)
+void SyntaxHighlighter::applyFormat(int offset, int length, const KSyntaxHighlighting::Format &format)
{
if (length == 0)
return;
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.h b/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.h
index f5d2a5e219..7f5dadefeb 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.h
@@ -30,8 +30,8 @@
#include <QSyntaxHighlighter>
-namespace KSyntaxHighlighting {
-
+namespace KSyntaxHighlighting
+{
class SyntaxHighlighterPrivate;
/** A QSyntaxHighlighter implementation for use with QTextDocument.
@@ -73,7 +73,7 @@ public:
QTextBlock findFoldingRegionEnd(const QTextBlock &startBlock) const;
protected:
- void highlightBlock(const QString & text) override;
+ void highlightBlock(const QString &text) override;
void applyFormat(int offset, int length, const Format &format) override;
void applyFolding(int offset, int length, FoldingRegion region) override;
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/textstyledata_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/textstyledata_p.h
index 50980e0aa0..4b6cef7e98 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/textstyledata_p.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/textstyledata_p.h
@@ -24,9 +24,10 @@
#ifndef KSYNTAXHIGHLIGHTING_TEXTSTYLEDATA_P_H
#define KSYNTAXHIGHLIGHTING_TEXTSTYLEDATA_P_H
+#include <QColor>
-namespace KSyntaxHighlighting {
-
+namespace KSyntaxHighlighting
+{
class TextStyleData
{
public:
@@ -40,21 +41,22 @@ public:
, hasItalic(false)
, hasUnderline(false)
, hasStrikeThrough(false)
- {}
+ {
+ }
QRgb textColor = 0x0;
QRgb backgroundColor = 0x0;
QRgb selectedTextColor = 0x0;
QRgb selectedBackgroundColor = 0x0;
- bool bold :1;
- bool italic :1;
- bool underline :1;
- bool strikeThrough :1;
-
- bool hasBold :1;
- bool hasItalic :1;
- bool hasUnderline :1;
- bool hasStrikeThrough :1;
+ bool bold : 1;
+ bool italic : 1;
+ bool underline : 1;
+ bool strikeThrough : 1;
+
+ bool hasBold : 1;
+ bool hasItalic : 1;
+ bool hasUnderline : 1;
+ bool hasStrikeThrough : 1;
};
}
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/theme.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/theme.cpp
index 57f62ef6ab..c6f31a5182 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/theme.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/theme.cpp
@@ -37,7 +37,7 @@ Theme::Theme(const Theme &copy)
m_data = copy.m_data;
}
-Theme::Theme(ThemeData* data)
+Theme::Theme(ThemeData *data)
: m_data(data)
{
}
@@ -64,8 +64,7 @@ QString Theme::name() const
QString Theme::translatedName() const
{
- return m_data ? QCoreApplication::instance()->translate("Theme", m_data->name().toUtf8().constData())
- : QString();
+ return m_data ? QCoreApplication::instance()->translate("Theme", m_data->name().toUtf8().constData()) : QString();
}
bool Theme::isReadOnly() const
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/theme.h b/src/libs/3rdparty/syntax-highlighting/src/lib/theme.h
index adb8431f6a..3379aec853 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/theme.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/theme.h
@@ -28,11 +28,11 @@
#include <QColor>
#include <QExplicitlySharedDataPointer>
-#include <qobjectdefs.h>
#include <QTypeInfo>
+#include <qobjectdefs.h>
-namespace KSyntaxHighlighting {
-
+namespace KSyntaxHighlighting
+{
class ThemeData;
class RepositoryPrivate;
@@ -82,7 +82,6 @@ class KSYNTAXHIGHLIGHTING_EXPORT Theme
{
Q_GADGET
public:
-
// TODO KF6:
// - make TextStyle an enum class
// - move out of Theme into KSyntaxHighlighting
@@ -358,7 +357,7 @@ private:
/**
* Constructor taking a shared ThemeData instance.
*/
- explicit Theme(ThemeData* data);
+ explicit Theme(ThemeData *data);
friend class RepositoryPrivate;
friend class ThemeData;
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/themedata.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/themedata.cpp
index 9e9f7b913c..03a5ea8e32 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/themedata.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/themedata.cpp
@@ -22,8 +22,8 @@
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#include "themedata_p.h"
#include "ksyntaxhighlighting_logging.h"
+#include "themedata_p.h"
#include <QFile>
#include <QFileInfo>
@@ -32,10 +32,9 @@
#include <QJsonValue>
#include <QMetaEnum>
-
using namespace KSyntaxHighlighting;
-ThemeData* ThemeData::get(const Theme &theme)
+ThemeData *ThemeData::get(const Theme &theme)
{
return theme.m_data.data();
}
@@ -248,7 +247,7 @@ QRgb ThemeData::editorColor(Theme::EditorColorRole role) const
return m_editorColors[role];
}
-TextStyleData ThemeData::textStyleOverride(const QString& definitionName, const QString& attributeName) const
+TextStyleData ThemeData::textStyleOverride(const QString &definitionName, const QString &attributeName) const
{
return m_textStyleOverrides.value(definitionName).value(attributeName);
}
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/themedata_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/themedata_p.h
index 3b5f4637a9..052d297599 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/themedata_p.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/themedata_p.h
@@ -25,21 +25,21 @@
#ifndef KSYNTAXHIGHLIGHTING_THEMEDATA_P_H
#define KSYNTAXHIGHLIGHTING_THEMEDATA_P_H
-#include "theme.h"
#include "textstyledata_p.h"
+#include "theme.h"
#include <QHash>
#include <QSharedData>
-namespace KSyntaxHighlighting {
-
+namespace KSyntaxHighlighting
+{
/**
* Data container for a Theme.
*/
class ThemeData : public QSharedData
{
public:
- static ThemeData* get(const Theme &theme);
+ static ThemeData *get(const Theme &theme);
/**
* Default constructor, creating an uninitialized ThemeData instance.
@@ -155,7 +155,7 @@ private:
//! style overrides for individual itemData entries
//! definition name -> attribute name -> style
- QHash<QString, QHash<QString, TextStyleData> > m_textStyleOverrides;
+ QHash<QString, QHash<QString, TextStyleData>> m_textStyleOverrides;
//! Editor area colors
QRgb m_editorColors[Theme::TemplateReadOnlyPlaceholder + 1];
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/wildcardmatcher.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/wildcardmatcher.cpp
index 167295a930..604318200b 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/wildcardmatcher.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/wildcardmatcher.cpp
@@ -25,11 +25,10 @@
using namespace KSyntaxHighlighting;
-#include <QString>
#include <QChar>
+#include <QString>
-static bool exactMatch(const QString &candidate, const QString &wildcard, int candidatePosFromRight,
- int wildcardPosFromRight, bool caseSensitive = true)
+static bool exactMatch(const QString &candidate, const QString &wildcard, int candidatePosFromRight, int wildcardPosFromRight, bool caseSensitive = true)
{
for (; wildcardPosFromRight >= 0; wildcardPosFromRight--) {
const auto ch = wildcard.at(wildcardPosFromRight).unicode();
@@ -76,8 +75,7 @@ static bool exactMatch(const QString &candidate, const QString &wildcard, int ca
return true;
}
-bool WildcardMatcher::exactMatch(const QString &candidate, const QString &wildcard,
- bool caseSensitive)
+bool WildcardMatcher::exactMatch(const QString &candidate, const QString &wildcard, bool caseSensitive)
{
return ::exactMatch(candidate, wildcard, candidate.length() - 1, wildcard.length() - 1, caseSensitive);
}
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/wildcardmatcher_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/wildcardmatcher_p.h
index 016b10fe66..feeca66217 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/wildcardmatcher_p.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/wildcardmatcher_p.h
@@ -30,20 +30,20 @@ QT_BEGIN_NAMESPACE
class QString;
QT_END_NAMESPACE
-namespace KSyntaxHighlighting {
-
+namespace KSyntaxHighlighting
+{
namespace WildcardMatcher
{
- /**
- * Matches a string against a given wildcard.
- * The wildcard supports '*' (".*" in regex) and '?' ("." in regex), not more.
- *
- * @param candidate Text to match
- * @param wildcard Wildcard to use
- * @param caseSensitive Case-sensitivity flag
- * @return True for an exact match, false otherwise
- */
- bool exactMatch(const QString &candidate, const QString &wildcard, bool caseSensitive = true);
+/**
+ * Matches a string against a given wildcard.
+ * The wildcard supports '*' (".*" in regex) and '?' ("." in regex), not more.
+ *
+ * @param candidate Text to match
+ * @param wildcard Wildcard to use
+ * @param caseSensitive Case-sensitivity flag
+ * @return True for an exact match, false otherwise
+ */
+bool exactMatch(const QString &candidate, const QString &wildcard, bool caseSensitive = true);
}
}
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/xml_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/xml_p.h
index 5f1f066dfd..6d73edfb52 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/xml_p.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/xml_p.h
@@ -26,10 +26,11 @@
#include <QString>
-namespace KSyntaxHighlighting {
+namespace KSyntaxHighlighting
+{
/** Utilities for XML parsing. */
-namespace Xml {
-
+namespace Xml
+{
/** Parse a xs:boolean attribute. */
inline bool attrToBool(const QStringRef &str)
{
diff --git a/src/libs/advanceddockingsystem/CMakeLists.txt b/src/libs/advanceddockingsystem/CMakeLists.txt
index ba5deced26..70be4cbe10 100644
--- a/src/libs/advanceddockingsystem/CMakeLists.txt
+++ b/src/libs/advanceddockingsystem/CMakeLists.txt
@@ -24,7 +24,7 @@ add_qtc_library(AdvancedDockingSystem
resources.qrc
)
-extend_qtc_target(AdvancedDockingSystem
+extend_qtc_library(AdvancedDockingSystem
INCLUDES linux
SOURCES
linux/floatingwidgettitlebar.cpp linux/floatingwidgettitlebar.h
diff --git a/src/libs/advanceddockingsystem/ads_globals.h b/src/libs/advanceddockingsystem/ads_globals.h
index 4c0b8d6896..eede7a171a 100644
--- a/src/libs/advanceddockingsystem/ads_globals.h
+++ b/src/libs/advanceddockingsystem/ads_globals.h
@@ -107,10 +107,11 @@ enum eDragState {
* The different icons used in the UI
*/
enum eIcon {
- TabCloseIcon, //!< TabCloseIcon
- DockAreaMenuIcon, //!< DockAreaMenuIcon
- DockAreaUndockIcon, //!< DockAreaUndockIcon
- DockAreaCloseIcon, //!< DockAreaCloseIcon
+ TabCloseIcon, //!< TabCloseIcon
+ DockAreaMenuIcon, //!< DockAreaMenuIcon
+ DockAreaUndockIcon, //!< DockAreaUndockIcon
+ DockAreaCloseIcon, //!< DockAreaCloseIcon
+ FloatingWidgetCloseIcon, //!< FloatingWidgetCloseIcon
IconCount, //!< just a delimiter for range checks
};
@@ -125,8 +126,6 @@ enum eBitwiseOperator
};
namespace internal {
-const bool restoreTesting = true;
-const bool restore = false;
const char *const closedProperty = "close";
const char *const dirtyProperty = "dirty";
diff --git a/src/libs/advanceddockingsystem/dockareatitlebar.cpp b/src/libs/advanceddockingsystem/dockareatitlebar.cpp
index 9ee647265d..79ba7ae70d 100644
--- a/src/libs/advanceddockingsystem/dockareatitlebar.cpp
+++ b/src/libs/advanceddockingsystem/dockareatitlebar.cpp
@@ -132,6 +132,7 @@ namespace ADS
void DockAreaTitleBarPrivate::createButtons()
{
+ const QSize iconSize(14, 14);
QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
// Tabs menu button
m_tabsMenuButton = new TitleBarButton(testConfigFlag(DockManager::DockAreaHasTabsMenuButton));
@@ -149,6 +150,7 @@ namespace ADS
m_tabsMenuButton->setMenu(tabsMenu);
internal::setToolTip(m_tabsMenuButton, QObject::tr("List All Tabs"));
m_tabsMenuButton->setSizePolicy(sizePolicy);
+ m_tabsMenuButton->setIconSize(iconSize);
m_layout->addWidget(m_tabsMenuButton, 0);
QObject::connect(m_tabsMenuButton->menu(),
&QMenu::triggered,
@@ -164,6 +166,7 @@ namespace ADS
QStyle::SP_TitleBarNormalButton,
ADS::DockAreaUndockIcon);
m_undockButton->setSizePolicy(sizePolicy);
+ m_undockButton->setIconSize(iconSize);
m_layout->addWidget(m_undockButton, 0);
QObject::connect(m_undockButton,
&QToolButton::clicked,
@@ -183,7 +186,7 @@ namespace ADS
internal::setToolTip(m_closeButton, QObject::tr("Close Group"));
}
m_closeButton->setSizePolicy(sizePolicy);
- m_closeButton->setIconSize(QSize(16, 16));
+ m_closeButton->setIconSize(iconSize);
m_layout->addWidget(m_closeButton, 0);
QObject::connect(m_closeButton,
&QToolButton::clicked,
diff --git a/src/libs/advanceddockingsystem/dockmanager.cpp b/src/libs/advanceddockingsystem/dockmanager.cpp
index 051fa68a40..2e0d7c0dd6 100644
--- a/src/libs/advanceddockingsystem/dockmanager.cpp
+++ b/src/libs/advanceddockingsystem/dockmanager.cpp
@@ -106,17 +106,12 @@ namespace ADS
DockManagerPrivate(DockManager *parent);
/**
- * Checks if the given data stream is a valid docking system state
- * file.
- */
- bool checkFormat(const QByteArray &state, int version);
-
- /**
- * Restores the state
+ * Restores the state. If testing is set to true it will check if
+ * the given data stream is a valid docking system state file.
*/
bool restoreStateFromXml(const QByteArray &state,
int version,
- bool testing = internal::restore);
+ bool testing = false);
/**
* Restore state
@@ -174,11 +169,6 @@ namespace ADS
return result;
}
- bool DockManagerPrivate::checkFormat(const QByteArray &state, int version)
- {
- return restoreStateFromXml(state, version, internal::restoreTesting);
- }
-
bool DockManagerPrivate::restoreStateFromXml(const QByteArray &state, int version, bool testing)
{
Q_UNUSED(version) // TODO version is not needed, why is it in here in the first place?
@@ -297,7 +287,8 @@ namespace ADS
bool DockManagerPrivate::restoreState(const QByteArray &state, int version)
{
QByteArray currentState = state.startsWith("<?xml") ? state : qUncompress(state);
- if (!checkFormat(currentState, version)) {
+ // Check the format of the given data stream
+ if (!restoreStateFromXml(currentState, version, true)) {
qCInfo(adsLog) << "checkFormat: Error checking format!!!";
return false;
}
@@ -589,7 +580,7 @@ namespace ADS
QMessageBox::warning(parentWidget(),
tr("Cannot Save Workspace"),
tr("Could not save workspace to file %1")
- .arg(workspaceNameToFileName(d->m_workspaceName)
+ .arg(workspaceNameToFilePath(d->m_workspaceName)
.toUserOutput()));
}
@@ -613,6 +604,8 @@ namespace ADS
const QString m_dirName = QLatin1String("workspaces");
const QString m_fileExt = QLatin1String(".wrk"); // TODO
+ QString DockManager::workspaceFileExtension() const { return m_fileExt; }
+
QStringList DockManager::workspaces()
{
if (d->m_workspaces.isEmpty() || d->m_workspaceListDirty) {
@@ -622,14 +615,13 @@ namespace ADS
QDir workspaceDir(QFileInfo(d->m_settings->fileName()).path() + QLatin1Char('/')
+ m_dirName);
QFileInfoList workspaceFiles
- = workspaceDir.entryInfoList(QStringList() << QLatin1String("*.wrk"),
+ = workspaceDir.entryInfoList(QStringList() << QLatin1Char('*') + m_fileExt,
QDir::NoFilter,
QDir::Time);
for (const QFileInfo &fileInfo : workspaceFiles) {
- QString filename = fileInfo.completeBaseName();
- filename.replace("_", " ");
- d->m_workspaceDateTimes.insert(filename, fileInfo.lastModified());
- tmp.insert(filename);
+ QString workspaceName = fileNameToWorkspaceName(fileInfo.completeBaseName());
+ d->m_workspaceDateTimes.insert(workspaceName, fileInfo.lastModified());
+ tmp.insert(workspaceName);
}
d->m_workspaceListDirty = false;
@@ -643,13 +635,11 @@ namespace ADS
if (d->m_workspacePresets.isEmpty()) {
QDir workspacePresetsDir(d->m_workspacePresetsPath);
QFileInfoList workspacePresetsFiles
- = workspacePresetsDir.entryInfoList(QStringList() << QLatin1String("*.wrk"),
+ = workspacePresetsDir.entryInfoList(QStringList() << QLatin1Char('*') + m_fileExt,
QDir::NoFilter,
QDir::Time);
for (const QFileInfo &fileInfo : workspacePresetsFiles) {
- QString filename = fileInfo.completeBaseName();
- filename.replace("_", " ");
- d->m_workspacePresets.insert(filename);
+ d->m_workspacePresets.insert(fileNameToWorkspaceName(fileInfo.completeBaseName()));
}
}
return d->m_workspacePresets;
@@ -660,13 +650,27 @@ namespace ADS
return d->m_workspaceDateTimes.value(workspace);
}
- Utils::FilePath DockManager::workspaceNameToFileName(const QString &workspaceName) const
+ Utils::FilePath DockManager::workspaceNameToFilePath(const QString &workspaceName) const
{
QTC_ASSERT(d->m_settings, return {});
- QString workspaceNameCopy = workspaceName;
return Utils::FilePath::fromString(
QFileInfo(d->m_settings->fileName()).path() + QLatin1Char('/') + m_dirName
- + QLatin1Char('/') + workspaceNameCopy.replace(" ", "_") + QLatin1String(".wrk"));
+ + QLatin1Char('/') + workspaceNameToFileName(workspaceName));
+ }
+
+ QString DockManager::fileNameToWorkspaceName(const QString &fileName) const
+ {
+ QString copy = QFileInfo(fileName).baseName();
+ copy.replace("_", " ");
+ return copy;
+ }
+
+ QString DockManager::workspaceNameToFileName(const QString &workspaceName) const
+ {
+ QString copy = workspaceName;
+ copy.replace(" ", "_");
+ copy.append(m_fileExt);
+ return copy;
}
/**
@@ -686,7 +690,7 @@ namespace ADS
QMessageBox::warning(parentWidget(),
tr("Cannot Save Workspace"),
tr("Could not save workspace to file %1")
- .arg(workspaceNameToFileName(d->m_workspaceName)
+ .arg(workspaceNameToFilePath(d->m_workspaceName)
.toUserOutput()));
}
@@ -775,7 +779,7 @@ namespace ADS
return false;
// Remove corresponding workspace file
- QFile fi(workspaceNameToFileName(workspace).toString());
+ QFile fi(workspaceNameToFilePath(workspace).toString());
if (fi.exists()) {
if (fi.remove()) {
d->m_workspaces.removeOne(workspace);
@@ -799,12 +803,12 @@ namespace ADS
if (!d->m_workspaces.contains(original))
return false;
- QFile fi(workspaceNameToFileName(original).toString());
+ QFile fi(workspaceNameToFilePath(original).toString());
// If the file does not exist, we can still clone
- if (!fi.exists() || fi.copy(workspaceNameToFileName(clone).toString())) {
+ if (!fi.exists() || fi.copy(workspaceNameToFilePath(clone).toString())) {
d->m_workspaces.insert(1, clone);
d->m_workspaceDateTimes
- .insert(clone, workspaceNameToFileName(clone).toFileInfo().lastModified());
+ .insert(clone, workspaceNameToFilePath(clone).toFileInfo().lastModified());
emit workspaceListChanged();
return true;
}
@@ -825,17 +829,14 @@ namespace ADS
if (!isWorkspacePreset(workspace))
return false;
- Utils::FilePath filename = workspaceNameToFileName(workspace);
+ Utils::FilePath fileName = workspaceNameToFilePath(workspace);
- if (!QFile::remove(filename.toString()))
+ if (!QFile::remove(fileName.toString()))
return false;
QDir presetsDir(d->m_workspacePresetsPath);
- QString presetName = workspace;
- presetName.replace(" ", "_");
- presetName.append(".wrk");
-
- bool result = QFile::copy(presetsDir.filePath(presetName), filename.toString());
+ bool result = QFile::copy(presetsDir.filePath(workspaceNameToFileName(workspace)),
+ fileName.toString());
if (result)
d->m_workspaceDateTimes.insert(workspace, QDateTime::currentDateTime());
@@ -852,13 +853,89 @@ namespace ADS
return d->m_modeChangeState;
}
+ void DockManager::importWorkspace(const QString &workspace)
+ {
+ // Extract workspace name
+ QString workspaceName = fileNameToWorkspaceName(workspace);
+
+ // Check if the workspace is already contained in the list of workspaces. If that is the case
+ // add a counter to the workspace name.
+ if (workspaces().contains(workspaceName)) {
+ int i = 2;
+ QString copy;
+ do {
+ copy = workspaceName + QLatin1String(" (") + QString::number(i) + QLatin1Char(')');
+ ++i;
+ } while (workspaces().contains(copy));
+ workspaceName = copy;
+ }
+
+ QString fileName = workspaceNameToFileName(workspaceName);
+ QFile file(workspace);
+ if (!file.exists()) {
+ qCInfo(adsLog) << QString("File doesn't exist '%1'").arg(workspace);
+ return;
+ }
+
+ QDir workspaceDir(QFileInfo(d->m_settings->fileName()).path() + QLatin1Char('/') + m_dirName);
+
+ if (!file.copy(workspaceDir.filePath(fileName))) {
+ qCInfo(adsLog) << QString("Could not copy '%1' to '%2' error: %3").arg(
+ workspace, workspaceDir.filePath(fileName), file.errorString());
+ } else {
+ d->m_workspaces.insert(1, workspaceName);
+ d->m_workspaceDateTimes.insert(workspaceName,
+ workspaceNameToFilePath(workspaceName).toFileInfo().lastModified());
+ d->m_workspaceListDirty = true;
+ // After importing the workspace, update the workspace list
+ workspaces();
+ emit workspaceListChanged();
+ }
+ }
+
+ void DockManager::exportWorkspace(const QString &target, const QString &workspace)
+ {
+ // If we came this far the user decided that in case the target already exists to overwrite it.
+ // We first need to remove the existing file, otherwise QFile::copy() will fail.
+ QFileInfo targetFileInfo(target);
+
+ // Remove the file which supposed to be overwritten
+ if (targetFileInfo.exists()) {
+ QFile fi(targetFileInfo.absoluteFilePath());
+ if (!fi.remove()) {
+ qCInfo(adsLog) << QString("Couldn't remove '%1'").arg(targetFileInfo.absoluteFilePath());
+ return;
+ }
+ }
+
+ // Check if the target directory exists
+ if (!targetFileInfo.absoluteDir().exists()) {
+ qCInfo(adsLog) << QString("Directory doesn't exist '%1'").arg(targetFileInfo.dir().dirName());
+ return;
+ }
+
+ // Check if the workspace exists
+ Utils::FilePath workspaceFilePath = workspaceNameToFilePath(workspace);
+ if (!workspaceFilePath.exists()) {
+ qCInfo(adsLog) << QString("Workspace doesn't exist '%1'").arg(workspaceFilePath.toString());
+ return;
+ }
+
+ // Finally copy the workspace to the target
+ QFile workspaceFile(workspaceFilePath.toString());
+ if (!workspaceFile.copy(targetFileInfo.absoluteFilePath())) {
+ qCInfo(adsLog) << QString("Could not copy '%1' to '%2' error: %3").arg(
+ workspace, workspaceFilePath.toString(), workspaceFile.errorString());
+ }
+ }
+
bool DockManager::write(const QString &workspace, const QByteArray &data, QString *errorString) const
{
- Utils::FilePath filename = workspaceNameToFileName(workspace);
+ Utils::FilePath fileName = workspaceNameToFilePath(workspace);
QDir tmp;
- tmp.mkpath(filename.toFileInfo().path());
- Utils::FileSaver fileSaver(filename.toString(), QIODevice::Text);
+ tmp.mkpath(fileName.toFileInfo().path());
+ Utils::FileSaver fileSaver(fileName.toString(), QIODevice::Text);
if (!fileSaver.hasError())
fileSaver.write(data);
@@ -884,7 +961,7 @@ namespace ADS
QByteArray DockManager::loadWorkspace(const QString &workspace) const
{
QByteArray data;
- Utils::FilePath fileName = workspaceNameToFileName(workspace);
+ Utils::FilePath fileName = workspaceNameToFilePath(workspace);
if (fileName.exists()) {
QFile file(fileName.toString());
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
@@ -920,17 +997,14 @@ namespace ADS
}
for (const auto &preset : presets) {
- QString filename = preset;
- filename.replace(" ", "_");
- filename.append(".wrk");
-
- QString filePath = presetsDir.filePath(filename);
+ QString fileName = workspaceNameToFileName(preset);
+ QString filePath = presetsDir.filePath(fileName);
QFile file(filePath);
if (file.exists()) {
- if (!file.copy(workspaceDir.filePath(filename))) {
+ if (!file.copy(workspaceDir.filePath(fileName))) {
qCInfo(adsLog) << QString("Could not copy '%1' to '%2' error: %3").arg(
- filePath, workspaceDir.filePath(filename), file.errorString());
+ filePath, workspaceDir.filePath(fileName), file.errorString());
}
d->m_workspaceListDirty = true;
}
diff --git a/src/libs/advanceddockingsystem/dockmanager.h b/src/libs/advanceddockingsystem/dockmanager.h
index 506335714e..658c9a2d6c 100644
--- a/src/libs/advanceddockingsystem/dockmanager.h
+++ b/src/libs/advanceddockingsystem/dockmanager.h
@@ -232,7 +232,7 @@ public:
virtual ~DockManager() override;
/**
- * This function returns the global configuration flags
+ * This function returns the global configuration flags.
*/
static ConfigFlags configFlags();
@@ -244,13 +244,13 @@ public:
static void setConfigFlags(const ConfigFlags flags);
/**
- * Set a certain config flag
+ * Set a certain config flag.
* \see setConfigFlags()
*/
static void setConfigFlag(eConfigFlag flag, bool on = true);
/**
- * Returns true if the given config flag is set
+ * Returns true if the given config flag is set.
*/
static bool testConfigFlag(eConfigFlag flag);
@@ -263,7 +263,7 @@ public:
/**
* The distance the user needs to move the mouse with the left button
- * hold down before a dock widget start floating
+ * hold down before a dock widget start floating.
*/
static int startDragDistance();
@@ -319,35 +319,35 @@ public:
/**
* Searches for a registered doc widget with the given ObjectName
* \return Return the found dock widget or nullptr if a dock widget with the
- * given name is not registered
+ * given name is not registered.
*/
DockWidget *findDockWidget(const QString &objectName) const;
/**
- * Remove the given Dock from the dock manager
+ * Remove the given DockWidget from the dock manager.
*/
void removeDockWidget(DockWidget *dockWidget);
/**
* This function returns a readable reference to the internal dock
- * widgets map so that it is possible to iterate over all dock widgets
+ * widgets map so that it is possible to iterate over all dock widgets.
*/
QMap<QString, DockWidget *> dockWidgetsMap() const;
/**
* Returns the list of all active and visible dock containers
- * Dock containers are the main dock manager and all floating widgets
+ * Dock containers are the main dock manager and all floating widgets.
*/
const QList<DockContainerWidget *> dockContainers() const;
/**
- * Returns the list of all floating widgets
+ * Returns the list of all floating widgets.
*/
const QList<FloatingDockContainer *> floatingWidgets() const;
/**
* This function always return 0 because the main window is always behind
- * any floating widget
+ * any floating widget.
*/
virtual unsigned int zOrderIndex() const override;
@@ -378,33 +378,33 @@ public:
signals:
/**
- * This signal is emitted if the list of perspectives changed
+ * This signal is emitted if the list of workspaces changed.
*/
void workspaceListChanged();
/**
- * This signal is emitted if perspectives have been removed
+ * This signal is emitted if workspaces have been removed.
*/
void workspacesRemoved();
/**
* This signal is emitted, if the restore function is called, just before
* the dock manager starts restoring the state.
- * If this function is called, nothing has changed yet
+ * If this function is called, nothing has changed yet.
*/
void restoringState();
/**
* This signal is emitted if the state changed in restoreState.
* The signal is emitted if the restoreState() function is called or
- * if the openWorkspace() function is called
+ * if the openWorkspace() function is called.
*/
void stateRestored();
/**
* This signal is emitted, if the dock manager starts opening a
- * perspective.
- * Opening a perspective may take more than a second if there are
+ * workspace.
+ * Opening a workspace may take more than a second if there are
* many complex widgets. The application may use this signal
* to show some progress indicator or to change the mouse cursor
* into a busy cursor.
@@ -413,7 +413,7 @@ signals:
/**
* This signal is emitted if the dock manager finished opening a
- * perspective
+ * workspace.
*/
void workspaceOpened(const QString &workspaceName);
@@ -432,8 +432,7 @@ signals:
void dockAreaCreated(DockAreaWidget *dockArea);
/**
- * This signal is emitted just before the given dock widget is removed
- * from the
+ * This signal is emitted just before removal of the given DockWidget.
*/
void dockWidgetAboutToBeRemoved(DockWidget *dockWidget);
@@ -452,10 +451,13 @@ public:
QString activeWorkspace() const;
QString lastWorkspace() const;
bool autoRestorLastWorkspace() const;
+ QString workspaceFileExtension() const;
QStringList workspaces();
QSet<QString> workspacePresets() const;
QDateTime workspaceDateTime(const QString &workspace) const;
- Utils::FilePath workspaceNameToFileName(const QString &workspaceName) const;
+ Utils::FilePath workspaceNameToFilePath(const QString &workspaceName) const;
+ QString fileNameToWorkspaceName(const QString &fileName) const;
+ QString workspaceNameToFileName(const QString &workspaceName) const;
bool createWorkspace(const QString &workspace);
@@ -478,6 +480,9 @@ public:
void setModeChangeState(bool value);
bool isModeChangeState() const;
+ void importWorkspace(const QString &workspace);
+ void exportWorkspace(const QString &target, const QString &workspace);
+
signals:
void aboutToUnloadWorkspace(QString workspaceName);
void aboutToLoadWorkspace(QString workspaceName);
diff --git a/src/libs/advanceddockingsystem/dockwidgettab.cpp b/src/libs/advanceddockingsystem/dockwidgettab.cpp
index 611580d368..b46d172050 100644
--- a/src/libs/advanceddockingsystem/dockwidgettab.cpp
+++ b/src/libs/advanceddockingsystem/dockwidgettab.cpp
@@ -168,12 +168,18 @@ namespace ADS
m_titleLabel->setText(m_dockWidget->windowTitle());
m_titleLabel->setObjectName("dockWidgetTabLabel");
m_titleLabel->setAlignment(Qt::AlignCenter);
- QObject::connect(m_titleLabel, &ElidingLabel::elidedChanged, q, &DockWidgetTab::elidedChanged);
+ QObject::connect(m_titleLabel,
+ &ElidingLabel::elidedChanged,
+ q,
+ &DockWidgetTab::elidedChanged);
m_closeButton = createCloseButton();
m_closeButton->setObjectName("tabCloseButton");
- internal::setButtonIcon(m_closeButton, QStyle::SP_TitleBarCloseButton, TabCloseIcon);
+ internal::setButtonIcon(m_closeButton,
+ QStyle::SP_TitleBarCloseButton,
+ TabCloseIcon);
m_closeButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+ m_closeButton->setIconSize(QSize(14, 14));
q->onDockWidgetFeaturesChanged();
internal::setToolTip(m_closeButton, QObject::tr("Close Tab"));
QObject::connect(m_closeButton,
@@ -189,11 +195,11 @@ namespace ADS
boxLayout->setContentsMargins(2 * spacing, 0, 0, 0);
boxLayout->setSpacing(0);
q->setLayout(boxLayout);
- boxLayout->addWidget(m_titleLabel, 1);
+ boxLayout->addWidget(m_titleLabel, 1, Qt::AlignVCenter);
boxLayout->addSpacing(spacing);
- boxLayout->addWidget(m_closeButton);
+ boxLayout->addWidget(m_closeButton, 0, Qt::AlignVCenter);
boxLayout->addSpacing(qRound(spacing * 4.0 / 3.0));
- boxLayout->setAlignment(Qt::AlignCenter);
+ boxLayout->setAlignment(Qt::AlignCenter | Qt::AlignVCenter);
m_titleLabel->setVisible(true);
}
diff --git a/src/libs/advanceddockingsystem/iconprovider.cpp b/src/libs/advanceddockingsystem/iconprovider.cpp
index 6a6f46752b..f220418220 100644
--- a/src/libs/advanceddockingsystem/iconprovider.cpp
+++ b/src/libs/advanceddockingsystem/iconprovider.cpp
@@ -51,7 +51,7 @@ namespace ADS {
*/
IconProviderPrivate(IconProvider *parent);
};
- // struct LedArrayPanelPrivate
+ // struct IconProviderPrivate
IconProviderPrivate::IconProviderPrivate(IconProvider *parent)
: q(parent)
diff --git a/src/libs/advanceddockingsystem/linux/floatingwidgettitlebar.cpp b/src/libs/advanceddockingsystem/linux/floatingwidgettitlebar.cpp
index 64e71a3b1c..7d92952d70 100644
--- a/src/libs/advanceddockingsystem/linux/floatingwidgettitlebar.cpp
+++ b/src/libs/advanceddockingsystem/linux/floatingwidgettitlebar.cpp
@@ -41,7 +41,7 @@
namespace ADS {
using TabLabelType = ElidingLabel;
-using tCloseButton = QPushButton;
+using CloseButtonType = QPushButton;
/**
* @brief Private data class of public interface CFloatingWidgetTitleBar
@@ -52,7 +52,7 @@ public:
FloatingWidgetTitleBar *q; ///< public interface class
QLabel *m_iconLabel = nullptr;
TabLabelType *m_titleLabel = nullptr;
- tCloseButton *m_closeButton = nullptr;
+ CloseButtonType *m_closeButton = nullptr;
FloatingDockContainer *m_floatingWidget = nullptr;
eDragState m_dragState = DraggingInactive;
@@ -74,22 +74,20 @@ void FloatingWidgetTitleBarPrivate::createLayout()
m_titleLabel->setObjectName("floatingTitleLabel");
m_titleLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
- m_closeButton = new tCloseButton();
+ m_closeButton = new CloseButtonType();
m_closeButton->setObjectName("floatingTitleCloseButton");
m_closeButton->setFlat(true);
-
- // The standard icons do does not look good on high DPI screens
- QIcon closeIcon;
- QPixmap normalPixmap = q->style()->standardPixmap(QStyle::SP_TitleBarCloseButton,
- nullptr,
- m_closeButton);
- closeIcon.addPixmap(normalPixmap, QIcon::Normal);
- closeIcon.addPixmap(internal::createTransparentPixmap(normalPixmap, 0.25), QIcon::Disabled);
- m_closeButton->setIcon(q->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
+ internal::setButtonIcon(m_closeButton,
+ QStyle::SP_TitleBarCloseButton,
+ ADS::FloatingWidgetCloseIcon);
m_closeButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+ m_closeButton->setIconSize(QSize(14, 14));
m_closeButton->setVisible(true);
m_closeButton->setFocusPolicy(Qt::NoFocus);
- q->connect(m_closeButton, &QPushButton::clicked, q, &FloatingWidgetTitleBar::closeRequested);
+ QObject::connect(m_closeButton,
+ &QPushButton::clicked,
+ q,
+ &FloatingWidgetTitleBar::closeRequested);
QFontMetrics fontMetrics(m_titleLabel->font());
int spacing = qRound(fontMetrics.height() / 4.0);
diff --git a/src/libs/advanceddockingsystem/workspacedialog.cpp b/src/libs/advanceddockingsystem/workspacedialog.cpp
index a458940aa0..0226f4a597 100644
--- a/src/libs/advanceddockingsystem/workspacedialog.cpp
+++ b/src/libs/advanceddockingsystem/workspacedialog.cpp
@@ -170,6 +170,14 @@ WorkspaceDialog::WorkspaceDialog(DockManager *manager, QWidget *parent)
&WorkspaceView::selected,
this,
&WorkspaceDialog::updateActions);
+ connect(m_ui.btImport,
+ &QAbstractButton::clicked,
+ m_ui.workspaceView,
+ &WorkspaceView::importWorkspace);
+ connect(m_ui.btExport,
+ &QAbstractButton::clicked,
+ m_ui.workspaceView,
+ &WorkspaceView::exportCurrentWorkspace);
m_ui.whatsAWorkspaceLabel->setOpenExternalLinks(true);
@@ -199,6 +207,7 @@ void WorkspaceDialog::updateActions(const QStringList &workspaces)
m_ui.btClone->setEnabled(false);
m_ui.btReset->setEnabled(false);
m_ui.btSwitch->setEnabled(false);
+ m_ui.btExport->setEnabled(false);
return;
}
const bool presetIsSelected = Utils::anyOf(workspaces, [this](const QString &workspace) {
@@ -212,6 +221,7 @@ void WorkspaceDialog::updateActions(const QStringList &workspaces)
m_ui.btClone->setEnabled(workspaces.size() == 1);
m_ui.btReset->setEnabled(presetIsSelected);
m_ui.btSwitch->setEnabled(workspaces.size() == 1);
+ m_ui.btExport->setEnabled(workspaces.size() == 1);
}
} // namespace ADS
diff --git a/src/libs/advanceddockingsystem/workspacedialog.ui b/src/libs/advanceddockingsystem/workspacedialog.ui
index 93e40aeefc..ea494218aa 100644
--- a/src/libs/advanceddockingsystem/workspacedialog.ui
+++ b/src/libs/advanceddockingsystem/workspacedialog.ui
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
- <width>373</width>
- <height>282</height>
+ <width>400</width>
+ <height>300</height>
</rect>
</property>
<property name="windowTitle">
@@ -90,6 +90,20 @@
</property>
</spacer>
</item>
+ <item>
+ <widget class="QPushButton" name="btImport">
+ <property name="text">
+ <string>Import</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="btExport">
+ <property name="text">
+ <string>Export</string>
+ </property>
+ </widget>
+ </item>
</layout>
</item>
<item row="1" column="0">
diff --git a/src/libs/advanceddockingsystem/workspacemodel.cpp b/src/libs/advanceddockingsystem/workspacemodel.cpp
index badf263368..2fb1dc52be 100644
--- a/src/libs/advanceddockingsystem/workspacemodel.cpp
+++ b/src/libs/advanceddockingsystem/workspacemodel.cpp
@@ -260,6 +260,18 @@ void WorkspaceModel::switchToWorkspace(const QString &workspace)
emit workspaceSwitched();
}
+void WorkspaceModel::importWorkspace(const QString &workspace)
+{
+ m_manager->importWorkspace(workspace);
+ m_sortedWorkspaces = m_manager->workspaces();
+ sort(m_currentSortColumn, m_currentSortOrder);
+}
+
+void WorkspaceModel::exportWorkspace(const QString &target, const QString &workspace)
+{
+ m_manager->exportWorkspace(target, workspace);
+}
+
void WorkspaceModel::runWorkspaceNameInputDialog(WorkspaceNameInputDialog *workspaceInputDialog,
std::function<void(const QString &)> createWorkspace)
{
diff --git a/src/libs/advanceddockingsystem/workspacemodel.h b/src/libs/advanceddockingsystem/workspacemodel.h
index 3ccd70db92..9b4ce5fc48 100644
--- a/src/libs/advanceddockingsystem/workspacemodel.h
+++ b/src/libs/advanceddockingsystem/workspacemodel.h
@@ -77,6 +77,9 @@ public:
void resetWorkspace(const QString &workspace);
void switchToWorkspace(const QString &workspace);
+ void importWorkspace(const QString &workspace);
+ void exportWorkspace(const QString &target, const QString &workspace);
+
private:
void runWorkspaceNameInputDialog(WorkspaceNameInputDialog *workspaceInputDialog,
std::function<void(const QString &)> createWorkspace);
diff --git a/src/libs/advanceddockingsystem/workspaceview.cpp b/src/libs/advanceddockingsystem/workspaceview.cpp
index 383aa2d0a5..7c730443b4 100644
--- a/src/libs/advanceddockingsystem/workspaceview.cpp
+++ b/src/libs/advanceddockingsystem/workspaceview.cpp
@@ -40,6 +40,7 @@
#include <utils/algorithm.h>
+#include <QFileDialog>
#include <QHeaderView>
#include <QItemSelection>
#include <QStringList>
@@ -135,6 +136,38 @@ void WorkspaceView::deleteWorkspaces(const QStringList &workspaces)
m_workspaceModel.deleteWorkspaces(workspaces);
}
+void WorkspaceView::importWorkspace()
+{
+ static QString lastDir;
+ const QString currentDir = lastDir.isEmpty() ? "" : lastDir;
+ const auto fileName = QFileDialog::getOpenFileName(this,
+ tr("Import Workspace"),
+ currentDir,
+ "Workspaces (*" + m_manager->workspaceFileExtension() + ")");
+
+ if (!fileName.isEmpty())
+ lastDir = QFileInfo(fileName).absolutePath();
+
+ m_workspaceModel.importWorkspace(fileName);
+}
+
+void WorkspaceView::exportCurrentWorkspace()
+{
+ static QString lastDir;
+ const QString currentDir = lastDir.isEmpty() ? "" : lastDir;
+ QFileInfo fileInfo(currentDir, m_manager->workspaceNameToFileName(currentWorkspace()));
+
+ const auto fileName = QFileDialog::getSaveFileName(this,
+ tr("Export Workspace"),
+ fileInfo.absoluteFilePath(),
+ "Workspaces (*" + m_manager->workspaceFileExtension() + ")");
+
+ if (!fileName.isEmpty())
+ lastDir = QFileInfo(fileName).absolutePath();
+
+ m_workspaceModel.exportWorkspace(fileName, currentWorkspace());
+}
+
void WorkspaceView::cloneCurrentWorkspace()
{
m_workspaceModel.cloneWorkspace(this, currentWorkspace());
@@ -187,7 +220,7 @@ void WorkspaceView::showEvent(QShowEvent *event)
void WorkspaceView::keyPressEvent(QKeyEvent *event)
{
- if (event->key() != Qt::Key_Delete) {
+ if (event->key() != Qt::Key_Delete && event->key() != Qt::Key_Backspace) {
TreeView::keyPressEvent(event);
return;
}
diff --git a/src/libs/advanceddockingsystem/workspaceview.h b/src/libs/advanceddockingsystem/workspaceview.h
index 428c0cbd1d..3edd668cc2 100644
--- a/src/libs/advanceddockingsystem/workspaceview.h
+++ b/src/libs/advanceddockingsystem/workspaceview.h
@@ -60,6 +60,9 @@ public:
void resetCurrentWorkspace();
void switchToCurrentWorkspace();
+ void importWorkspace();
+ void exportCurrentWorkspace();
+
QString currentWorkspace();
WorkspaceModel *workspaceModel();
void selectActiveWorkspace();
diff --git a/src/libs/clangsupport/CMakeLists.txt b/src/libs/clangsupport/CMakeLists.txt
index 20af2c1b9d..d1f38507cb 100644
--- a/src/libs/clangsupport/CMakeLists.txt
+++ b/src/libs/clangsupport/CMakeLists.txt
@@ -147,32 +147,18 @@ if (NOT TARGET libclang)
return()
endif()
-add_custom_target(copy_clang_to_builddir ALL
- COMMENT Copy Clang files into build directory
-)
-
# For the developer build directory
-add_custom_command(TARGET copy_clang_to_builddir POST_BUILD
- COMMAND "${CMAKE_COMMAND}"
- -E copy_directory
- "${LLVM_LIBRARY_DIR}/clang/${CLANG_VERSION}/include"
- "${PROJECT_BINARY_DIR}/${IDE_LIBEXEC_PATH}/clang/lib/clang/${CLANG_VERSION}/include"
- VERBATIM
+qtc_copy_to_builddir(copy_clang_to_builddir
+ DIRECTORIES "${LLVM_LIBRARY_DIR}/clang/${CLANG_VERSION}/include"
+ DESTINATION "${IDE_LIBEXEC_PATH}/clang/lib/clang/${CLANG_VERSION}/include"
)
foreach(executable clang clang-cl clangd clang-tidy clazy-standalone)
if (EXISTS "${LLVM_TOOLS_BINARY_DIR}/${executable}${CMAKE_EXECUTABLE_SUFFIX}")
- add_custom_command(TARGET copy_clang_to_builddir PRE_BUILD
- COMMAND "${CMAKE_COMMAND}"
- -E make_directory
- "${PROJECT_BINARY_DIR}/${IDE_LIBEXEC_PATH}/clang/bin/"
- COMMAND "${CMAKE_COMMAND}"
- -E copy
- "${LLVM_TOOLS_BINARY_DIR}/${executable}${CMAKE_EXECUTABLE_SUFFIX}"
- "${PROJECT_BINARY_DIR}/${IDE_LIBEXEC_PATH}/clang/bin/"
- VERBATIM
+ qtc_copy_to_builddir(copy_clang_${executable}_to_builddir
+ FILES "${LLVM_TOOLS_BINARY_DIR}/${executable}${CMAKE_EXECUTABLE_SUFFIX}"
+ DESTINATION "${IDE_LIBEXEC_PATH}/clang/bin/"
)
-
# For the install directory
install(PROGRAMS
"${LLVM_TOOLS_BINARY_DIR}/${executable}${CMAKE_EXECUTABLE_SUFFIX}"
diff --git a/src/libs/clangsupport/tooltipinfo.h b/src/libs/clangsupport/tooltipinfo.h
index b8f828a52e..f50c93a53e 100644
--- a/src/libs/clangsupport/tooltipinfo.h
+++ b/src/libs/clangsupport/tooltipinfo.h
@@ -28,6 +28,8 @@
#include <utf8string.h>
#include <utf8stringvector.h>
+#include <QVariant>
+
namespace ClangBackEnd {
class ToolTipInfo
@@ -54,6 +56,7 @@ public:
out << message.qdocIdCandidates;
out << message.qdocMark;
out << static_cast<quint8>(message.qdocCategory);
+ out << message.value;
out << message.sizeInBytes;
return out;
@@ -68,6 +71,7 @@ public:
in >> message.qdocIdCandidates;
in >> message.qdocMark;
in >> qdocCategory;
+ in >> message.value;
in >> message.sizeInBytes;
message.qdocCategory = static_cast<QdocCategory>(qdocCategory);
@@ -82,6 +86,7 @@ public:
&& first.qdocIdCandidates == second.qdocIdCandidates
&& first.qdocMark == second.qdocMark
&& first.qdocCategory == second.qdocCategory
+ && first.value == second.value
&& first.sizeInBytes == second.sizeInBytes;
}
@@ -92,6 +97,7 @@ public:
Utf8StringVector qdocIdCandidates;
Utf8String qdocMark;
QdocCategory qdocCategory = Unknown;
+ QVariant value;
// For class definition and for class fields.
Utf8String sizeInBytes;
diff --git a/src/libs/languageserverprotocol/clientcapabilities.cpp b/src/libs/languageserverprotocol/clientcapabilities.cpp
index fac2d3f5d7..4ee6d74166 100644
--- a/src/libs/languageserverprotocol/clientcapabilities.cpp
+++ b/src/libs/languageserverprotocol/clientcapabilities.cpp
@@ -92,7 +92,7 @@ bool TextDocumentClientCapabilities::isValid(ErrorHierarchy *error) const
&& checkOptional<DynamicRegistrationCapabilities>(error, codeLensKey)
&& checkOptional<DynamicRegistrationCapabilities>(error, documentLinkKey)
&& checkOptional<DynamicRegistrationCapabilities>(error, colorProviderKey)
- && checkOptional<DynamicRegistrationCapabilities>(error, renameKey)
+ && checkOptional<RenameClientCapabilities>(error, renameKey)
&& checkOptional<SemanticHighlightingCapabilities>(error, semanticHighlightingCapabilitiesKey);
}
@@ -128,4 +128,10 @@ bool TextDocumentClientCapabilities::CodeActionCapabilities::isValid(ErrorHierar
&& checkOptional<CodeActionLiteralSupport>(errorHierarchy, codeActionLiteralSupportKey);
}
+bool TextDocumentClientCapabilities::RenameClientCapabilities::isValid(ErrorHierarchy *error) const
+{
+ return DynamicRegistrationCapabilities::isValid(error)
+ && checkOptional<bool>(error, prepareSupportKey);
+}
+
} // namespace LanguageServerProtocol
diff --git a/src/libs/languageserverprotocol/clientcapabilities.h b/src/libs/languageserverprotocol/clientcapabilities.h
index 76462fa15b..13cfb262cf 100644
--- a/src/libs/languageserverprotocol/clientcapabilities.h
+++ b/src/libs/languageserverprotocol/clientcapabilities.h
@@ -444,10 +444,28 @@ public:
{ insert(colorProviderKey, colorProvider); }
void clearColorProvider() { remove(colorProviderKey); }
+ class LANGUAGESERVERPROTOCOL_EXPORT RenameClientCapabilities : public DynamicRegistrationCapabilities
+ {
+ public:
+ using DynamicRegistrationCapabilities::DynamicRegistrationCapabilities;
+ /**
+ * Client supports testing for validity of rename operations
+ * before execution.
+ *
+ * @since version 3.12.0
+ */
+
+ Utils::optional<bool> prepareSupport() const { return optionalValue<bool>(prepareSupportKey); }
+ void setPrepareSupport(bool prepareSupport) { insert(prepareSupportKey, prepareSupport); }
+ void clearPrepareSupport() { remove(prepareSupportKey); }
+
+ bool isValid(ErrorHierarchy *error) const override;
+ };
+
// Whether rename supports dynamic registration.
- Utils::optional<DynamicRegistrationCapabilities> rename() const
- { return optionalValue<DynamicRegistrationCapabilities>(renameKey); }
- void setRename(const DynamicRegistrationCapabilities &rename)
+ Utils::optional<RenameClientCapabilities> rename() const
+ { return optionalValue<RenameClientCapabilities>(renameKey); }
+ void setRename(const RenameClientCapabilities &rename)
{ insert(renameKey, rename); }
void clearRename() { remove(renameKey); }
diff --git a/src/libs/languageserverprotocol/jsonkeys.h b/src/libs/languageserverprotocol/jsonkeys.h
index cccf0789b9..d8f2b13117 100644
--- a/src/libs/languageserverprotocol/jsonkeys.h
+++ b/src/libs/languageserverprotocol/jsonkeys.h
@@ -144,8 +144,10 @@ constexpr char openCloseKey[] = "openClose";
constexpr char optionsKey[] = "options";
constexpr char parametersKey[] = "params";
constexpr char patternKey[] = "pattern";
+constexpr char placeHolderKey[] = "placeHolder";
constexpr char positionKey[] = "position";
constexpr char prepareProviderKey[] = "prepareProvider";
+constexpr char prepareSupportKey[] = "prepareSupport";
constexpr char processIdKey[] = "processId";
constexpr char queryKey[] = "query";
constexpr char rangeFormattingKey[] = "rangeFormatting";
diff --git a/src/libs/languageserverprotocol/languagefeatures.cpp b/src/libs/languageserverprotocol/languagefeatures.cpp
index d76f03f0b6..e960296dc8 100644
--- a/src/libs/languageserverprotocol/languagefeatures.cpp
+++ b/src/libs/languageserverprotocol/languagefeatures.cpp
@@ -49,6 +49,7 @@ constexpr const char DocumentOnTypeFormattingRequest::methodName[];
constexpr const char RenameRequest::methodName[];
constexpr const char SignatureHelpRequest::methodName[];
constexpr const char SemanticHighlightNotification::methodName[];
+constexpr const char PrepareRenameRequest::methodName[];
HoverContent LanguageServerProtocol::Hover::content() const
{
@@ -245,6 +246,10 @@ DocumentOnTypeFormattingRequest::DocumentOnTypeFormattingRequest(
: Request(methodName, params)
{ }
+PrepareRenameRequest::PrepareRenameRequest(const TextDocumentPositionParams &params)
+ : Request(methodName, params)
+{ }
+
bool RenameParams::isValid(ErrorHierarchy *error) const
{
return check<TextDocumentIdentifier>(error, textDocumentKey)
@@ -491,10 +496,55 @@ void SemanticHighlightToken::appendToByteArray(QByteArray &byteArray) const
byteArray.append(char((scope & 0x00ff)));
}
+Utils::variant<VersionedTextDocumentIdentifier, TextDocumentIdentifier>
+SemanticHighlightingParams::textDocument() const
+{
+ VersionedTextDocumentIdentifier textDocument = fromJsonValue<VersionedTextDocumentIdentifier>(
+ value(textDocumentKey));
+ ErrorHierarchy error;
+ if (!textDocument.isValid(&error)) {
+ return TextDocumentIdentifier(textDocument);
+ } else {
+ return textDocument;
+ }
+}
+
bool SemanticHighlightingParams::isValid(ErrorHierarchy *error) const
{
- return check<VersionedTextDocumentIdentifier>(error, textDocumentKey)
- && checkArray<SemanticHighlightingInformation>(error, linesKey);
+ return checkVariant<VersionedTextDocumentIdentifier, TextDocumentIdentifier>(error,
+ textDocumentKey)
+ && checkArray<SemanticHighlightingInformation>(error, linesKey);
+}
+
+PrepareRenameResult::PrepareRenameResult()
+ : Utils::variant<PlaceHolderResult, Range, std::nullptr_t>(nullptr)
+{}
+
+PrepareRenameResult::PrepareRenameResult(
+ const Utils::variant<PlaceHolderResult, Range, std::nullptr_t> &val)
+ : Utils::variant<PlaceHolderResult, Range, std::nullptr_t>(val)
+{}
+
+PrepareRenameResult::PrepareRenameResult(const PlaceHolderResult &val)
+ : Utils::variant<PlaceHolderResult, Range, std::nullptr_t>(val)
+
+{}
+
+PrepareRenameResult::PrepareRenameResult(const Range &val)
+ : Utils::variant<PlaceHolderResult, Range, std::nullptr_t>(val)
+{}
+
+PrepareRenameResult::PrepareRenameResult(const QJsonValue &val)
+{
+ if (val.isNull()) {
+ emplace<std::nullptr_t>(nullptr);
+ } else if (val.isObject()) {
+ const QJsonObject object = val.toObject();
+ if (object.keys().contains(rangeKey))
+ emplace<PlaceHolderResult>(PlaceHolderResult(object));
+ else
+ emplace<Range>(Range(object));
+ }
}
} // namespace LanguageServerProtocol
diff --git a/src/libs/languageserverprotocol/languagefeatures.h b/src/libs/languageserverprotocol/languagefeatures.h
index bee7cbd04f..fd742391f3 100644
--- a/src/libs/languageserverprotocol/languagefeatures.h
+++ b/src/libs/languageserverprotocol/languagefeatures.h
@@ -778,6 +778,44 @@ public:
constexpr static const char methodName[] = "textDocument/onTypeFormatting";
};
+class PlaceHolderResult : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ Range range() const { return typedValue<Range>(rangeKey); }
+ void setRange(const Range &range) { insert(rangeKey, range); }
+
+ QString placeHolder() const { return typedValue<QString>(placeHolderKey); }
+ void setPlaceHolder(const QString &placeHolder) { insert(placeHolderKey, placeHolder); }
+
+ bool isValid(ErrorHierarchy *error) const override
+ {
+ return check<Range>(error, rangeKey) && checkOptional<QString>(error, placeHolderKey);
+ }
+};
+
+class PrepareRenameResult : public Utils::variant<PlaceHolderResult, Range, std::nullptr_t>
+{
+public:
+ PrepareRenameResult();
+ PrepareRenameResult(const Utils::variant<PlaceHolderResult, Range, std::nullptr_t> &val);
+ explicit PrepareRenameResult(const PlaceHolderResult &val);
+ explicit PrepareRenameResult(const Range &val);
+ PrepareRenameResult(const QJsonValue &val);
+
+ bool isValid(ErrorHierarchy *error) const;
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT PrepareRenameRequest
+ : public Request<PrepareRenameResult, std::nullptr_t, TextDocumentPositionParams>
+{
+public:
+ PrepareRenameRequest(const TextDocumentPositionParams &params = TextDocumentPositionParams());
+ using Request::Request;
+ constexpr static const char methodName[] = "textDocument/prepareRename";
+};
+
class LANGUAGESERVERPROTOCOL_EXPORT RenameParams : public JsonObject
{
public:
@@ -841,8 +879,9 @@ class LANGUAGESERVERPROTOCOL_EXPORT SemanticHighlightingParams : public JsonObje
public:
using JsonObject::JsonObject;
- VersionedTextDocumentIdentifier textDocument() const
- { return typedValue<VersionedTextDocumentIdentifier>(textDocumentKey); }
+ Utils::variant<VersionedTextDocumentIdentifier, TextDocumentIdentifier> textDocument() const;
+ void setTextDocument(const TextDocumentIdentifier &textDocument)
+ { insert(textDocumentKey, textDocument); }
void setTextDocument(const VersionedTextDocumentIdentifier &textDocument)
{ insert(textDocumentKey, textDocument); }
diff --git a/src/libs/languageserverprotocol/lsptypes.cpp b/src/libs/languageserverprotocol/lsptypes.cpp
index 2a34a53fc6..4aa9963f1a 100644
--- a/src/libs/languageserverprotocol/lsptypes.cpp
+++ b/src/libs/languageserverprotocol/lsptypes.cpp
@@ -399,12 +399,22 @@ Utils::Link Location::toLink() const
{
if (!isValid(nullptr))
return Utils::Link();
+
+ // QUrl::FullyDecoded is not supported by QUrl::toString.
+ // Ensure %xx like %20 are really decoded using fromPercentEncoding
+ // Else, a path with spaces would keep its %20 which would cause failure
+ // to open the file by the text editor. This is the cases with compilers in
+ // C:\Programs Files on Windows.
auto file = uri().toString(QUrl::FullyDecoded | QUrl::PreferLocalFile);
+
+ // fromPercentEncoding convert %xx encoding to raw values and then interpret
+ // the result as utf-8, so toUtf8() must be used here.
+ file = QUrl::fromPercentEncoding(file.toUtf8());
return Utils::Link(file, range().start().line() + 1, range().start().character());
}
DocumentUri::DocumentUri(const QString &other)
- : QUrl(QUrl::fromPercentEncoding(other.toLocal8Bit()))
+ : QUrl(QUrl::fromPercentEncoding(other.toUtf8()))
{ }
DocumentUri::DocumentUri(const Utils::FilePath &other)
diff --git a/src/libs/libs.pro b/src/libs/libs.pro
index 7213fa6631..013376911f 100644
--- a/src/libs/libs.pro
+++ b/src/libs/libs.pro
@@ -68,7 +68,7 @@ win32:SUBDIRS += utils/process_ctrlc_stub.pro
# Windows: Compile Qt Creator CDB extension if Debugging tools can be detected.
win32: isEmpty(QTC_SKIP_CDBEXT) {
include(qtcreatorcdbext/cdb_detect.pri)
- exists($$CDB_PATH) {
+ !isEmpty(CDB_PATH): exists($$CDB_PATH) {
SUBDIRS += qtcreatorcdbext
} else {
message("Compiling Qt Creator without a CDB extension.")
diff --git a/src/libs/modelinglib/qmt/config/stereotypedefinitionparser.cpp b/src/libs/modelinglib/qmt/config/stereotypedefinitionparser.cpp
index fe070fc08a..b11e34cf71 100644
--- a/src/libs/modelinglib/qmt/config/stereotypedefinitionparser.cpp
+++ b/src/libs/modelinglib/qmt/config/stereotypedefinitionparser.cpp
@@ -55,6 +55,7 @@ static const int KEYWORD_DISPLAY = 11;
static const int KEYWORD_TEXTALIGN = 12;
static const int KEYWORD_BASECOLOR = 13;
static const int KEYWORD_SHAPE = 14;
+static const int KEYWORD_OUTLINE = 15;
// Shape items
static const int KEYWORD_CIRCLE = 30;
@@ -166,16 +167,13 @@ public:
IconCommandParameter() = default;
- IconCommandParameter(int keyword, ShapeValueF::Unit unit, ShapeValueF::Origin origin = ShapeValueF::OriginSmart)
- : m_keyword(keyword),
- m_unit(unit),
+ IconCommandParameter(ShapeValueF::Unit unit, ShapeValueF::Origin origin = ShapeValueF::OriginSmart)
+ : m_unit(unit),
m_origin(origin)
{
}
- IconCommandParameter(int keyword, Type type)
- : m_keyword(keyword),
- m_type(type)
+ IconCommandParameter(Type type) : m_type(type)
{
}
@@ -190,7 +188,6 @@ public:
void setBoolean(bool boolean) { m_boolean = boolean; }
private:
- int m_keyword = -1;
Type m_type = ShapeValue;
ShapeValueF::Unit m_unit = ShapeValueF::UnitAbsolute;
ShapeValueF::Origin m_origin = ShapeValueF::OriginSmart;
@@ -245,6 +242,7 @@ void StereotypeDefinitionParser::parse(ITextSource *source)
<< qMakePair(QString("textalignment"), KEYWORD_TEXTALIGN)
<< qMakePair(QString("basecolor"), KEYWORD_BASECOLOR)
<< qMakePair(QString("shape"), KEYWORD_SHAPE)
+ << qMakePair(QString("outline"), KEYWORD_OUTLINE)
<< qMakePair(QString("circle"), KEYWORD_CIRCLE)
<< qMakePair(QString("ellipse"), KEYWORD_ELLIPSE)
<< qMakePair(QString("line"), KEYWORD_LINE)
@@ -436,6 +434,9 @@ void StereotypeDefinitionParser::parseIcon()
case KEYWORD_SHAPE:
stereotypeIcon.setIconShape(parseIconShape());
break;
+ case KEYWORD_OUTLINE:
+ stereotypeIcon.setOutlineShape(parseIconShape());
+ break;
case KEYWORD_NAME:
stereotypeIcon.setName(parseStringProperty());
stereotypeIcon.setHasName(true);
@@ -455,22 +456,22 @@ void StereotypeDefinitionParser::parseIcon()
QPair<int, StereotypeDefinitionParser::IconCommandParameter> StereotypeDefinitionParser::SCALED(int keyword)
{
- return qMakePair(keyword, IconCommandParameter(keyword, ShapeValueF::UnitScaled));
+ return qMakePair(keyword, IconCommandParameter(ShapeValueF::UnitScaled));
}
QPair<int, StereotypeDefinitionParser::IconCommandParameter> StereotypeDefinitionParser::FIX(int keyword)
{
- return qMakePair(keyword, IconCommandParameter(keyword, ShapeValueF::UnitRelative));
+ return qMakePair(keyword, IconCommandParameter(ShapeValueF::UnitRelative));
}
QPair<int, StereotypeDefinitionParser::IconCommandParameter> StereotypeDefinitionParser::ABSOLUTE(int keyword)
{
- return qMakePair(keyword, IconCommandParameter(keyword, ShapeValueF::UnitAbsolute));
+ return qMakePair(keyword, IconCommandParameter(ShapeValueF::UnitAbsolute));
}
QPair<int, StereotypeDefinitionParser::IconCommandParameter> StereotypeDefinitionParser::BOOLEAN(int keyword)
{
- return qMakePair(keyword, IconCommandParameter(keyword, IconCommandParameter::Boolean));
+ return qMakePair(keyword, IconCommandParameter(IconCommandParameter::Boolean));
}
IconShape StereotypeDefinitionParser::parseIconShape()
diff --git a/src/libs/modelinglib/qmt/controller/namecontroller.cpp b/src/libs/modelinglib/qmt/controller/namecontroller.cpp
index 25ebbc171f..b336688f04 100644
--- a/src/libs/modelinglib/qmt/controller/namecontroller.cpp
+++ b/src/libs/modelinglib/qmt/controller/namecontroller.cpp
@@ -138,7 +138,7 @@ QStringList NameController::buildElementsPath(const QString &filePath, bool igno
QStringList split = filePath.split("/");
QStringList::const_iterator splitEnd = split.constEnd();
if (ignoreLastFilePathPart || split.last().isEmpty())
- splitEnd = --splitEnd;
+ --splitEnd;
for (auto it = split.constBegin(); it != splitEnd; ++it) {
QString packageName = qmt::NameController::convertFileNameToElementName(*it);
relativeElements.append(packageName);
diff --git a/src/libs/modelinglib/qmt/diagram_scene/diagramscenemodel.cpp b/src/libs/modelinglib/qmt/diagram_scene/diagramscenemodel.cpp
index 34efac9f3d..6349b7db30 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/diagramscenemodel.cpp
+++ b/src/libs/modelinglib/qmt/diagram_scene/diagramscenemodel.cpp
@@ -88,7 +88,7 @@ public:
Q_UNUSED(option)
Q_UNUSED(widget)
- QPen pen(QBrush(Qt::gray), 1.0, Qt::DotLine);
+ QPen pen(QBrush(Qt::lightGray), 1.0, Qt::DotLine);
painter->setPen(pen);
painter->drawLine(QLineF(0.0, 0.0, 20.0, 0.0));
painter->drawLine(QLineF(0.0, 0.0, 0.0, 20.0));
diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/classitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/items/classitem.cpp
index 3e65c36dae..658b6bdb38 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/items/classitem.cpp
+++ b/src/libs/modelinglib/qmt/diagram_scene/items/classitem.cpp
@@ -287,8 +287,25 @@ void ClassItem::update()
bool ClassItem::intersectShapeWithLine(const QLineF &line, QPointF *intersectionPoint, QLineF *intersectionLine) const
{
+ if (m_customIcon) {
+ QList<QPolygonF> polygons = m_customIcon->outline();
+ for (int i = 0; i < polygons.size(); ++i)
+ polygons[i].translate(object()->pos() + object()->rect().topLeft());
+ if (shapeIcon().textAlignment() == qmt::StereotypeIcon::TextalignBelow) {
+ if (nameItem()) {
+ QPolygonF polygon(nameItem()->boundingRect());
+ polygon.translate(object()->pos() + nameItem()->pos());
+ polygons.append(polygon);
+ }
+ if (m_contextLabel) {
+ QPolygonF polygon(m_contextLabel->boundingRect());
+ polygon.translate(object()->pos() + m_contextLabel->pos());
+ polygons.append(polygon);
+ }
+ }
+ return GeometryUtilities::intersect(polygons, line, nullptr, intersectionPoint, intersectionLine);
+ }
QPolygonF polygon;
- // TODO if m_customIcon then use that shape + label's shape as intersection path
QRectF rect = object()->rect();
rect.translate(object()->pos());
polygon << rect.topLeft() << rect.topRight() << rect.bottomRight() << rect.bottomLeft() << rect.topLeft();
diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/componentitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/items/componentitem.cpp
index 96f0b8231c..55e70d9b1f 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/items/componentitem.cpp
+++ b/src/libs/modelinglib/qmt/diagram_scene/items/componentitem.cpp
@@ -160,13 +160,26 @@ void ComponentItem::update()
bool ComponentItem::intersectShapeWithLine(const QLineF &line, QPointF *intersectionPoint, QLineF *intersectionLine) const
{
- QPolygonF polygon;
if (m_customIcon) {
- // TODO use customIcon path as shape
- QRectF rect = object()->rect();
- rect.translate(object()->pos());
- polygon << rect.topLeft() << rect.topRight() << rect.bottomRight() << rect.bottomLeft() << rect.topLeft();
- } else if (hasPlainShape()) {
+ QList<QPolygonF> polygons = m_customIcon->outline();
+ for (int i = 0; i < polygons.size(); ++i)
+ polygons[i].translate(object()->pos() + object()->rect().topLeft());
+ if (shapeIcon().textAlignment() == qmt::StereotypeIcon::TextalignBelow) {
+ if (nameItem()) {
+ QPolygonF polygon(nameItem()->boundingRect());
+ polygon.translate(object()->pos() + nameItem()->pos());
+ polygons.append(polygon);
+ }
+ if (m_contextLabel) {
+ QPolygonF polygon(m_contextLabel->boundingRect());
+ polygon.translate(object()->pos() + m_contextLabel->pos());
+ polygons.append(polygon);
+ }
+ }
+ return GeometryUtilities::intersect(polygons, line, nullptr, intersectionPoint, intersectionLine);
+ }
+ QPolygonF polygon;
+ if (hasPlainShape()) {
QRectF rect = object()->rect();
rect.translate(object()->pos());
polygon << rect.topLeft() << rect.topRight() << rect.bottomRight() << rect.bottomLeft() << rect.topLeft();
@@ -177,10 +190,14 @@ bool ComponentItem::intersectShapeWithLine(const QLineF &line, QPointF *intersec
<< rect.topRight()
<< rect.bottomRight()
<< rect.bottomLeft()
- << rect.bottomLeft() + QPointF(0, UPPER_RECT_Y + RECT_HEIGHT + RECT_Y_DISTANCE + RECT_HEIGHT)
- << rect.bottomLeft() + QPointF(-RECT_WIDTH * 0.5, UPPER_RECT_Y + RECT_HEIGHT + RECT_Y_DISTANCE + RECT_HEIGHT)
- << rect.bottomLeft() + QPointF(-RECT_WIDTH * 0.5, UPPER_RECT_Y)
- << rect.bottomLeft() + QPointF(0, UPPER_RECT_Y)
+ << rect.topLeft() + QPointF(0, UPPER_RECT_Y + RECT_HEIGHT + RECT_Y_DISTANCE + RECT_HEIGHT)
+ << rect.topLeft() + QPointF(-RECT_WIDTH * 0.5, UPPER_RECT_Y + RECT_HEIGHT + RECT_Y_DISTANCE + RECT_HEIGHT)
+ << rect.topLeft() + QPointF(-RECT_WIDTH * 0.5, UPPER_RECT_Y + RECT_HEIGHT + RECT_Y_DISTANCE)
+ << rect.topLeft() + QPointF(0, UPPER_RECT_Y + RECT_HEIGHT + RECT_Y_DISTANCE)
+ << rect.topLeft() + QPointF(0, UPPER_RECT_Y + RECT_HEIGHT)
+ << rect.topLeft() + QPointF(-RECT_WIDTH * 0.5, UPPER_RECT_Y + RECT_HEIGHT)
+ << rect.topLeft() + QPointF(-RECT_WIDTH * 0.5, UPPER_RECT_Y)
+ << rect.topLeft() + QPointF(0, UPPER_RECT_Y)
<< rect.topLeft();
}
return GeometryUtilities::intersect(polygon, line, intersectionPoint, intersectionLine);
diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/diagramitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/items/diagramitem.cpp
index c3cce6a297..bdb1ab543f 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/items/diagramitem.cpp
+++ b/src/libs/modelinglib/qmt/diagram_scene/items/diagramitem.cpp
@@ -122,17 +122,24 @@ void DiagramItem::update()
bool DiagramItem::intersectShapeWithLine(const QLineF &line, QPointF *intersectionPoint, QLineF *intersectionLine) const
{
- QPolygonF polygon;
if (m_customIcon) {
- // TODO use customIcon path as shape
- QRectF rect = object()->rect();
- rect.translate(object()->pos());
- polygon << rect.topLeft() << rect.topRight() << rect.bottomRight() << rect.bottomLeft() << rect.topLeft();
- } else {
- QRectF rect = object()->rect();
- rect.translate(object()->pos());
- polygon << rect.topLeft() << rect.topRight() << rect.bottomRight() << rect.bottomLeft() << rect.topLeft();
+ QList<QPolygonF> polygons = m_customIcon->outline();
+ for (int i = 0; i < polygons.size(); ++i)
+ polygons[i].translate(object()->pos() + object()->rect().topLeft());
+ if (shapeIcon().textAlignment() == qmt::StereotypeIcon::TextalignBelow) {
+ if (nameItem()) {
+ QPolygonF polygon(nameItem()->boundingRect());
+ polygon.translate(object()->pos() + nameItem()->pos());
+ polygons.append(polygon);
+ }
+ }
+ return GeometryUtilities::intersect(polygons, line, nullptr, intersectionPoint, intersectionLine);
}
+ QPolygonF polygon;
+ QRectF rect = object()->rect();
+ rect.translate(object()->pos());
+ // TODO use real outline
+ polygon << rect.topLeft() << rect.topRight() << rect.bottomRight() << rect.bottomLeft() << rect.topLeft();
return GeometryUtilities::intersect(polygon, line, intersectionPoint, intersectionLine);
}
diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/itemitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/items/itemitem.cpp
index e3b50bab1b..cac585efa4 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/items/itemitem.cpp
+++ b/src/libs/modelinglib/qmt/diagram_scene/items/itemitem.cpp
@@ -130,17 +130,28 @@ void ItemItem::update()
bool ItemItem::intersectShapeWithLine(const QLineF &line, QPointF *intersectionPoint, QLineF *intersectionLine) const
{
- QPolygonF polygon;
if (m_customIcon) {
- // TODO use customIcon path as shape
- QRectF rect = object()->rect();
- rect.translate(object()->pos());
- polygon << rect.topLeft() << rect.topRight() << rect.bottomRight() << rect.bottomLeft() << rect.topLeft();
- } else {
- QRectF rect = object()->rect();
- rect.translate(object()->pos());
- polygon << rect.topLeft() << rect.topRight() << rect.bottomRight() << rect.bottomLeft() << rect.topLeft();
+ QList<QPolygonF> polygons = m_customIcon->outline();
+ for (int i = 0; i < polygons.size(); ++i)
+ polygons[i].translate(object()->pos() + object()->rect().topLeft());
+ if (shapeIcon().textAlignment() == qmt::StereotypeIcon::TextalignBelow) {
+ if (nameItem()) {
+ QPolygonF polygon(nameItem()->boundingRect());
+ polygon.translate(object()->pos() + nameItem()->pos());
+ polygons.append(polygon);
+ }
+ if (m_contextLabel) {
+ QPolygonF polygon(m_contextLabel->boundingRect());
+ polygon.translate(object()->pos() + m_contextLabel->pos());
+ polygons.append(polygon);
+ }
+ }
+ return GeometryUtilities::intersect(polygons, line, nullptr, intersectionPoint, intersectionLine);
}
+ QRectF rect = object()->rect();
+ rect.translate(object()->pos());
+ QPolygonF polygon;
+ polygon << rect.topLeft() << rect.topRight() << rect.bottomRight() << rect.bottomLeft() << rect.topLeft();
return GeometryUtilities::intersect(polygon, line, intersectionPoint, intersectionLine);
}
diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/packageitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/items/packageitem.cpp
index 8cc4f7ed92..7514d58203 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/items/packageitem.cpp
+++ b/src/libs/modelinglib/qmt/diagram_scene/items/packageitem.cpp
@@ -141,21 +141,32 @@ void PackageItem::update()
bool PackageItem::intersectShapeWithLine(const QLineF &line, QPointF *intersectionPoint, QLineF *intersectionLine) const
{
- QPolygonF polygon;
if (m_customIcon) {
- // TODO use customIcon path as shape
- QRectF rect = object()->rect();
- rect.translate(object()->pos());
- polygon << rect.topLeft() << rect.topRight() << rect.bottomRight() << rect.bottomLeft() << rect.topLeft();
- } else {
- QRectF rect = object()->rect();
- rect.translate(object()->pos());
- ShapeGeometry shape = calcMinimumGeometry();
- polygon << rect.topLeft() << (rect.topLeft() + QPointF(shape.m_minimumTabSize.width(), 0.0))
- << (rect.topLeft() + QPointF(shape.m_minimumTabSize.width(), shape.m_minimumTabSize.height()))
- << rect.topRight() + QPointF(0.0, shape.m_minimumTabSize.height())
- << rect.bottomRight() << rect.bottomLeft() << rect.topLeft();
+ QList<QPolygonF> polygons = m_customIcon->outline();
+ for (int i = 0; i < polygons.size(); ++i)
+ polygons[i].translate(object()->pos() + object()->rect().topLeft());
+ if (shapeIcon().textAlignment() == qmt::StereotypeIcon::TextalignBelow) {
+ if (nameItem()) {
+ QPolygonF polygon(nameItem()->boundingRect());
+ polygon.translate(object()->pos() + nameItem()->pos());
+ polygons.append(polygon);
+ }
+ if (m_contextLabel) {
+ QPolygonF polygon(m_contextLabel->boundingRect());
+ polygon.translate(object()->pos() + m_contextLabel->pos());
+ polygons.append(polygon);
+ }
+ }
+ return GeometryUtilities::intersect(polygons, line, nullptr, intersectionPoint, intersectionLine);
}
+ QPolygonF polygon;
+ QRectF rect = object()->rect();
+ rect.translate(object()->pos());
+ ShapeGeometry shape = calcMinimumGeometry();
+ polygon << rect.topLeft() << (rect.topLeft() + QPointF(shape.m_minimumTabSize.width(), 0.0))
+ << (rect.topLeft() + QPointF(shape.m_minimumTabSize.width(), shape.m_minimumTabSize.height()))
+ << rect.topRight() + QPointF(0.0, shape.m_minimumTabSize.height())
+ << rect.bottomRight() << rect.bottomLeft() << rect.topLeft();
return GeometryUtilities::intersect(polygon, line, intersectionPoint, intersectionLine);
}
diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/stereotypedisplayvisitor.cpp b/src/libs/modelinglib/qmt/diagram_scene/items/stereotypedisplayvisitor.cpp
index 0fdb273c0b..7c25863417 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/items/stereotypedisplayvisitor.cpp
+++ b/src/libs/modelinglib/qmt/diagram_scene/items/stereotypedisplayvisitor.cpp
@@ -151,9 +151,9 @@ void StereotypeDisplayVisitor::visitDItem(const DItem *item)
m_stereotypeSmartDisplay = DObject::StereotypeIcon;
visitDObject(item);
if (m_stereotypeIconId.isEmpty() && !item->shape().isEmpty())
- m_stereotypeIconId = m_stereotypeController->findStereotypeIconId(StereotypeIcon::ElementItem, QStringList(item->shape()));
+ m_stereotypeIconId = m_stereotypeController->findStereotypeIconId(StereotypeIcon::ElementItem, {item->shape()});
if (m_shapeIconId.isEmpty() && !item->variety().isEmpty())
- m_shapeIconId = m_stereotypeController->findStereotypeIconId(StereotypeIcon::ElementItem, QStringList(item->variety()));
+ m_shapeIconId = m_stereotypeController->findStereotypeIconId(StereotypeIcon::ElementItem, {item->variety()});
updateShapeIcon();
}
diff --git a/src/libs/modelinglib/qmt/diagram_scene/parts/customiconitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/parts/customiconitem.cpp
index 374f1e786a..13a8e4cbce 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/parts/customiconitem.cpp
+++ b/src/libs/modelinglib/qmt/diagram_scene/parts/customiconitem.cpp
@@ -33,6 +33,8 @@
#include <QPainter>
+//#define DEBUG_OUTLINE
+
namespace qmt {
CustomIconItem::CustomIconItem(DiagramSceneModel *diagramSceneModel, QGraphicsItem *parent)
@@ -102,9 +104,30 @@ void CustomIconItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *op
painter->save();
painter->setBrush(m_brush);
painter->setPen(m_pen);
+#ifdef DEBUG_OUTLINE
+ ShapePolygonVisitor visitor(QPointF(0.0, 0.0), QSizeF(m_stereotypeIcon.width(), m_stereotypeIcon.height()), m_baseSize, m_actualSize);
+ IconShape shape = m_stereotypeIcon.outlineShape();
+ if (shape.isEmpty())
+ shape = m_stereotypeIcon.iconShape();
+ shape.visitShapes(&visitor);
+ painter->drawPath(visitor.path());
+ ShapePaintVisitor visitor1(painter, QPointF(0.0, 0.0), QSizeF(m_stereotypeIcon.width(), m_stereotypeIcon.height()), m_baseSize, m_actualSize);
+ m_stereotypeIcon.iconShape().visitShapes(&visitor1);
+#else
ShapePaintVisitor visitor(painter, QPointF(0.0, 0.0), QSizeF(m_stereotypeIcon.width(), m_stereotypeIcon.height()), m_baseSize, m_actualSize);
m_stereotypeIcon.iconShape().visitShapes(&visitor);
+#endif
painter->restore();
}
+QList<QPolygonF> CustomIconItem::outline() const
+{
+ ShapePolygonVisitor visitor(QPointF(0.0, 0.0), QSizeF(m_stereotypeIcon.width(), m_stereotypeIcon.height()), m_baseSize, m_actualSize);
+ IconShape shape = m_stereotypeIcon.outlineShape();
+ if (shape.isEmpty())
+ shape = m_stereotypeIcon.iconShape();
+ shape.visitShapes(&visitor);
+ return visitor.toPolygons();
+}
+
} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/diagram_scene/parts/customiconitem.h b/src/libs/modelinglib/qmt/diagram_scene/parts/customiconitem.h
index 93e083b962..ce4ea97260 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/parts/customiconitem.h
+++ b/src/libs/modelinglib/qmt/diagram_scene/parts/customiconitem.h
@@ -55,6 +55,8 @@ public:
QRectF boundingRect() const override;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
+ QList<QPolygonF> outline() const;
+
private:
DiagramSceneModel *m_diagramSceneModel = nullptr;
QString m_stereotypeIconId;
diff --git a/src/libs/modelinglib/qmt/diagram_widgets_ui/diagramview.cpp b/src/libs/modelinglib/qmt/diagram_widgets_ui/diagramview.cpp
index ecc7fb327c..2d23871f0b 100644
--- a/src/libs/modelinglib/qmt/diagram_widgets_ui/diagramview.cpp
+++ b/src/libs/modelinglib/qmt/diagram_widgets_ui/diagramview.cpp
@@ -151,8 +151,10 @@ void DiagramView::dropEvent(QDropEvent *event)
void DiagramView::onSceneRectChanged(const QRectF &sceneRect)
{
- // TODO add some adjustment to all 4 sides?
- setSceneRect(sceneRect);
+ // add some adjustment to all 4 sides
+ static const qreal ADJUSTMENT = 80;
+ QRectF rect = sceneRect.adjusted(-ADJUSTMENT, -ADJUSTMENT, ADJUSTMENT, ADJUSTMENT);
+ setSceneRect(rect);
}
} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/infrastructure/geometryutilities.cpp b/src/libs/modelinglib/qmt/infrastructure/geometryutilities.cpp
index 5a42bf1f33..91886cf49e 100644
--- a/src/libs/modelinglib/qmt/infrastructure/geometryutilities.cpp
+++ b/src/libs/modelinglib/qmt/infrastructure/geometryutilities.cpp
@@ -54,24 +54,83 @@ QLineF GeometryUtilities::stretch(const QLineF &line, double p1Extension, double
}
bool GeometryUtilities::intersect(const QPolygonF &polygon, const QLineF &line,
- QPointF *intersectionPoint, QLineF *intersectionLine)
+ QPointF *intersectionPoint, QLineF *intersectionLine,
+ int nearestPoint)
{
+ bool found = false;
+ qreal mindist = 0;
+ QPointF ipoint;
+ QLineF iline;
for (int i = 0; i <= polygon.size() - 2; ++i) {
QLineF polygonLine(polygon.at(i), polygon.at(i+1));
+ QPointF point;
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
- QLineF::IntersectType intersectionType = polygonLine.intersect(line, intersectionPoint);
+ QLineF::IntersectType intersectionType = polygonLine.intersect(line, &point);
#else
- QLineF::IntersectType intersectionType = polygonLine.intersects(line, intersectionPoint);
+ QLineF::IntersectType intersectionType = polygonLine.intersects(line, &point);
#endif
if (intersectionType == QLineF::BoundedIntersection) {
- if (intersectionLine)
- *intersectionLine = polygonLine;
- return true;
+ qreal dist = QLineF(point, nearestPoint <= 0 ? line.p1() : line.p2()).length();
+ if (!found || dist < mindist) {
+ mindist = dist;
+ ipoint = point;
+ iline = polygonLine;
+ found = true;
+ }
+ }
+ }
+ if (found) {
+ if (intersectionPoint)
+ *intersectionPoint = ipoint;
+ if (intersectionLine)
+ *intersectionLine = iline;
+ }
+ return found;
+}
+
+bool GeometryUtilities::intersect(const QList<QPolygonF> &polygons, const QLineF &line,
+ int *intersectionPolygon, QPointF *intersectionPoint,
+ QLineF *intersectionLine, int nearestPoint)
+{
+ bool found = false;
+ qreal mindist = 0;
+ int ipolygon = -1;
+ QPointF ipoint;
+ QLineF iline;
+ for (int p = 0; p < polygons.size(); ++p) {
+ const QPolygonF polygon = polygons.at(p);
+ for (int i = 0; i <= polygon.size() - 2; ++i) {
+ const QLineF polygonLine(polygon.at(i), polygon.at(i + 1));
+ QPointF point;
+#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
+ QLineF::IntersectType intersectionType = polygonLine.intersect(line, &point);
+#else
+ QLineF::IntersectType intersectionType = polygonLine.intersects(line, &point);
+#endif
+ if (intersectionType == QLineF::BoundedIntersection) {
+ qreal dist = QLineF(point, nearestPoint <= 0 ? line.p1() : line.p2()).length();
+ if (!found || dist < mindist) {
+ mindist = dist;
+ ipolygon = p;
+ ipoint = point;
+ iline = polygonLine;
+ found = true;
+ }
+ }
}
}
- return false;
+ if (found) {
+ if (intersectionPolygon)
+ *intersectionPolygon = ipolygon;
+ if (intersectionPoint)
+ *intersectionPoint = ipoint;
+ if (intersectionLine)
+ *intersectionLine = iline;
+ }
+ return found;
}
+
namespace {
class Candidate
diff --git a/src/libs/modelinglib/qmt/infrastructure/geometryutilities.h b/src/libs/modelinglib/qmt/infrastructure/geometryutilities.h
index f0b4f697b0..6f39352f3f 100644
--- a/src/libs/modelinglib/qmt/infrastructure/geometryutilities.h
+++ b/src/libs/modelinglib/qmt/infrastructure/geometryutilities.h
@@ -52,7 +52,11 @@ public:
static QLineF stretch(const QLineF &line, double p1Extension, double p2Extension);
static bool intersect(const QPolygonF &polygon, const QLineF &line,
- QPointF *intersectionPoint, QLineF *intersectionLine = nullptr);
+ QPointF *intersectionPoint = nullptr, QLineF *intersectionLine = nullptr,
+ int nearestPoint = 1);
+ static bool intersect(const QList<QPolygonF> &polygons, const QLineF &line,
+ int *intersectionPolygon, QPointF *intersectionPoint = nullptr, QLineF *intersectionLine = nullptr,
+ int nearestPoint = 1);
static bool placeRectAtLine(const QRectF &rect, const QLineF &line, double lineOffset,
double distance, const QLineF &intersectionLine, QPointF *placement,
Side *horizontalAlignedSide);
diff --git a/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.cpp b/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.cpp
index 4af7b78285..fbb0f2520d 100644
--- a/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.cpp
+++ b/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.cpp
@@ -1518,7 +1518,7 @@ void PropertiesView::MView::setTitle(const MItem *item, const QList<V *> &elemen
if (elements.size() == 1) {
if (item && !item->isVarietyEditable()) {
QString stereotypeIconId = m_propertiesView->stereotypeController()
- ->findStereotypeIconId(StereotypeIcon::ElementItem, QStringList(item->variety()));
+ ->findStereotypeIconId(StereotypeIcon::ElementItem, {item->variety()});
if (!stereotypeIconId.isEmpty()) {
StereotypeIcon stereotypeIcon = m_propertiesView->stereotypeController()->findStereotypeIcon(stereotypeIconId);
m_propertiesTitle = stereotypeIcon.title();
diff --git a/src/libs/modelinglib/qmt/stereotype/iconshape.cpp b/src/libs/modelinglib/qmt/stereotype/iconshape.cpp
index 172bb36984..fc8e076ac8 100644
--- a/src/libs/modelinglib/qmt/stereotype/iconshape.cpp
+++ b/src/libs/modelinglib/qmt/stereotype/iconshape.cpp
@@ -107,6 +107,11 @@ IconShape &IconShape::operator=(const IconShape &rhs)
return *this;
}
+bool IconShape::isEmpty() const
+{
+ return d->m_shapes.isEmpty();
+}
+
void IconShape::addLine(const ShapePointF &pos1, const ShapePointF &pos2)
{
d->m_shapes.append(new LineShape(pos1, pos2));
diff --git a/src/libs/modelinglib/qmt/stereotype/iconshape.h b/src/libs/modelinglib/qmt/stereotype/iconshape.h
index 215dc8adec..87880f2c5c 100644
--- a/src/libs/modelinglib/qmt/stereotype/iconshape.h
+++ b/src/libs/modelinglib/qmt/stereotype/iconshape.h
@@ -46,6 +46,7 @@ public:
IconShape &operator=(const IconShape &rhs);
+ bool isEmpty() const;
QSizeF size() const;
void setSize(const QSizeF &size);
diff --git a/src/libs/modelinglib/qmt/stereotype/shapepaintvisitor.cpp b/src/libs/modelinglib/qmt/stereotype/shapepaintvisitor.cpp
index 930f8450ad..13ce2b1317 100644
--- a/src/libs/modelinglib/qmt/stereotype/shapepaintvisitor.cpp
+++ b/src/libs/modelinglib/qmt/stereotype/shapepaintvisitor.cpp
@@ -263,4 +263,152 @@ void ShapeSizeVisitor::visitPath(const PathShape *shapePath)
m_boundingRect |= path.boundingRect();
}
+ShapePolygonVisitor::ShapePolygonVisitor(const QPointF &scaledOrigin, const QSizeF &originalSize,
+ const QSizeF &baseSize, const QSizeF &size)
+ : m_scaledOrigin(scaledOrigin),
+ m_originalSize(originalSize),
+ m_baseSize(baseSize),
+ m_size(size)
+{
+ m_path.setFillRule(Qt::WindingFill);
+}
+
+QList<QPolygonF> ShapePolygonVisitor::toPolygons() const
+{
+ return m_path.toSubpathPolygons();
+}
+
+void ShapePolygonVisitor::visitLine(const LineShape *shapeLine)
+{
+ QPointF p1 = shapeLine->pos1().mapScaledTo(m_scaledOrigin, m_originalSize, m_baseSize, m_size);
+ QPointF p2 = shapeLine->pos2().mapScaledTo(m_scaledOrigin, m_originalSize, m_baseSize, m_size);
+ m_path.moveTo(p1);
+ m_path.lineTo(p2);
+}
+
+void ShapePolygonVisitor::visitRect(const RectShape *shapeRect)
+{
+ m_path.addRect(QRectF(shapeRect->pos().mapScaledTo(m_scaledOrigin, m_originalSize,
+ m_baseSize, m_size),
+ shapeRect->size().mapScaledTo(m_scaledOrigin, m_originalSize,
+ m_baseSize, m_size)));
+}
+
+void ShapePolygonVisitor::visitRoundedRect(const RoundedRectShape *shapeRoundedRect)
+{
+ qreal radiusX = shapeRoundedRect->radius().mapScaledTo(0, m_originalSize.width(),
+ m_baseSize.width(), m_size.width());
+ qreal radiusY = shapeRoundedRect->radius().mapScaledTo(0, m_originalSize.height(),
+ m_baseSize.height(), m_size.height());
+ m_path.addRoundedRect(QRectF(shapeRoundedRect->pos().mapScaledTo(m_scaledOrigin, m_originalSize,
+ m_baseSize, m_size),
+ shapeRoundedRect->size().mapScaledTo(m_scaledOrigin, m_originalSize,
+ m_baseSize, m_size)),
+ radiusX, radiusY);
+}
+
+void ShapePolygonVisitor::visitCircle(const CircleShape *shapeCircle)
+{
+ m_path.addEllipse(shapeCircle->center().mapScaledTo(m_scaledOrigin, m_originalSize,
+ m_baseSize, m_size),
+ shapeCircle->radius().mapScaledTo(m_scaledOrigin.x(), m_originalSize.width(),
+ m_baseSize.width(), m_size.width()),
+ shapeCircle->radius().mapScaledTo(m_scaledOrigin.y(), m_originalSize.height(),
+ m_baseSize.height(), m_size.height()));
+}
+
+void ShapePolygonVisitor::visitEllipse(const EllipseShape *shapeEllipse)
+{
+ QSizeF radius = shapeEllipse->radius().mapScaledTo(m_scaledOrigin, m_originalSize,
+ m_baseSize, m_size);
+ m_path.addEllipse(shapeEllipse->center().mapScaledTo(m_scaledOrigin, m_originalSize,
+ m_baseSize, m_size),
+ radius.width(), radius.height());
+}
+
+void ShapePolygonVisitor::visitDiamond(const DiamondShape *shapeDiamond)
+{
+ QPainterPath path;
+ QPointF center = shapeDiamond->center().mapScaledTo(m_scaledOrigin, m_originalSize,
+ m_baseSize, m_size);
+ QSizeF size = shapeDiamond->size().mapScaledTo(m_scaledOrigin, m_originalSize,
+ m_baseSize, m_size);
+ path.moveTo(center + QPointF(0.0, size.height() / 2.0));
+ path.lineTo(center + QPointF(-size.width() / 2.0, 0.0));
+ path.lineTo(center + QPointF(0.0, -size.height() / 2.0));
+ path.lineTo(center + QPointF(size.width() / 2.0, 0.0));
+ path.closeSubpath();
+ m_path.addPath(path);
+}
+
+void ShapePolygonVisitor::visitTriangle(const TriangleShape *shapeTriangle)
+{
+ QPainterPath path;
+ QPointF center = shapeTriangle->center().mapScaledTo(m_scaledOrigin, m_originalSize,
+ m_baseSize, m_size);
+ QSizeF size = shapeTriangle->size().mapScaledTo(m_scaledOrigin, m_originalSize,
+ m_baseSize, m_size);
+ path.moveTo(center + QPointF(size.width() / 2.0, size.height() / 2.0));
+ path.lineTo(center + QPointF(-size.width() / 2.0, size.height() / 2.0));
+ path.lineTo(center + QPointF(0.0, -size.height() / 2.0));
+ path.closeSubpath();
+ m_path.addPath(path);
+}
+
+void ShapePolygonVisitor::visitArc(const ArcShape *shapeArc)
+{
+ QSizeF radius = shapeArc->radius().mapScaledTo(m_scaledOrigin, m_originalSize,
+ m_baseSize, m_size);
+ QRectF rect(shapeArc->center().mapScaledTo(m_scaledOrigin, m_originalSize, m_baseSize, m_size)
+ - QPointF(radius.width(), radius.height()), radius * 2.0);
+ m_path.arcMoveTo(rect, shapeArc->startAngle());
+ m_path.arcTo(rect, shapeArc->startAngle(), shapeArc->spanAngle());
+}
+
+void ShapePolygonVisitor::visitPath(const PathShape *shapePath)
+{
+ QPainterPath path;
+ for (const PathShape::Element &element: shapePath->elements()) {
+ switch (element.m_elementType) {
+ case PathShape::TypeNone:
+ // nothing to do
+ break;
+ case PathShape::TypeMoveto:
+ path.moveTo(element.m_position.mapScaledTo(m_scaledOrigin, m_originalSize,
+ m_baseSize, m_size));
+ break;
+ case PathShape::TypeLineto:
+ path.lineTo(element.m_position.mapScaledTo(m_scaledOrigin, m_originalSize,
+ m_baseSize, m_size));
+ break;
+ case PathShape::TypeArcmoveto:
+ {
+ QSizeF radius = element.m_size.mapScaledTo(m_scaledOrigin, m_originalSize,
+ m_baseSize, m_size);
+ path.arcMoveTo(QRectF(element.m_position.mapScaledTo(m_scaledOrigin, m_originalSize,
+ m_baseSize, m_size)
+ - QPointF(radius.width(), radius.height()),
+ radius * 2.0),
+ element.m_angle1);
+ break;
+ }
+ case PathShape::TypeArcto:
+ {
+ QSizeF radius = element.m_size.mapScaledTo(m_scaledOrigin, m_originalSize,
+ m_baseSize, m_size);
+ path.arcTo(QRectF(element.m_position.mapScaledTo(m_scaledOrigin, m_originalSize,
+ m_baseSize, m_size)
+ - QPointF(radius.width(), radius.height()),
+ radius * 2.0),
+ element.m_angle1, element.m_angle2);
+ break;
+ }
+ case PathShape::TypeClose:
+ path.closeSubpath();
+ break;
+ }
+ }
+ m_path.addPath(path);
+}
+
} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/stereotype/shapepaintvisitor.h b/src/libs/modelinglib/qmt/stereotype/shapepaintvisitor.h
index 92e340e3e9..8ad4074764 100644
--- a/src/libs/modelinglib/qmt/stereotype/shapepaintvisitor.h
+++ b/src/libs/modelinglib/qmt/stereotype/shapepaintvisitor.h
@@ -31,6 +31,8 @@
#include <QPainter>
#include <QPointF>
#include <QSizeF>
+#include <QPolygonF>
+#include <QPainterPath>
namespace qmt {
@@ -84,4 +86,31 @@ private:
QRectF m_boundingRect;
};
+class QMT_EXPORT ShapePolygonVisitor : public ShapeConstVisitor
+{
+public:
+ ShapePolygonVisitor(const QPointF &scaledOrigin, const QSizeF &originalSize,
+ const QSizeF &baseSize, const QSizeF &size);
+
+ QPainterPath path() const { return m_path; }
+ QList<QPolygonF> toPolygons() const;
+
+ void visitLine(const LineShape *shapeLine) override;
+ void visitRect(const RectShape *shapeRect) override;
+ void visitRoundedRect(const RoundedRectShape *shapeRoundedRect) override;
+ void visitCircle(const CircleShape *shapeCircle) override;
+ void visitEllipse(const EllipseShape *shapeEllipse) override;
+ void visitDiamond(const DiamondShape *shapeDiamond) override;
+ void visitTriangle(const TriangleShape *shapeTriangle) override;
+ void visitArc(const ArcShape *shapeArc) override;
+ void visitPath(const PathShape *shapePath) override;
+
+private:
+ QPointF m_scaledOrigin;
+ QSizeF m_originalSize;
+ QSizeF m_baseSize;
+ QSizeF m_size;
+ QPainterPath m_path;
+};
+
} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/stereotype/stereotypeicon.cpp b/src/libs/modelinglib/qmt/stereotype/stereotypeicon.cpp
index d11cace46b..f9610851f3 100644
--- a/src/libs/modelinglib/qmt/stereotype/stereotypeicon.cpp
+++ b/src/libs/modelinglib/qmt/stereotype/stereotypeicon.cpp
@@ -109,4 +109,9 @@ void StereotypeIcon::setIconShape(const IconShape &iconShape)
m_iconShape = iconShape;
}
+void StereotypeIcon::setOutlineShape(const IconShape &outlineShape)
+{
+ m_outlineShape = outlineShape;
+}
+
} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/stereotype/stereotypeicon.h b/src/libs/modelinglib/qmt/stereotype/stereotypeicon.h
index 4465734cfd..ab837bd333 100644
--- a/src/libs/modelinglib/qmt/stereotype/stereotypeicon.h
+++ b/src/libs/modelinglib/qmt/stereotype/stereotypeicon.h
@@ -100,6 +100,8 @@ public:
void setBaseColor(const QColor &baseColor);
IconShape iconShape() const { return m_iconShape; }
void setIconShape(const IconShape &iconShape);
+ IconShape outlineShape() const { return m_outlineShape; }
+ void setOutlineShape(const IconShape &outlineShape);
private:
QString m_id;
@@ -117,6 +119,7 @@ private:
TextAlignment m_textAlignment = TextalignBelow;
QColor m_baseColor;
IconShape m_iconShape;
+ IconShape m_outlineShape;
};
} // namespace qmt
diff --git a/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.cpp b/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.cpp
index ec15b0f7d8..9995cd3041 100644
--- a/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.cpp
+++ b/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.cpp
@@ -101,7 +101,7 @@ public:
endItems = customRelation.endItems();
QString stereotypeIconId = m_stereotypeController->findStereotypeIconId(StereotypeIcon::ElementItem, object->stereotypes());
if (stereotypeIconId.isEmpty() && !m_variety.isEmpty())
- stereotypeIconId = m_stereotypeController->findStereotypeIconId(StereotypeIcon::ElementItem, QStringList(m_variety));
+ stereotypeIconId = m_stereotypeController->findStereotypeIconId(StereotypeIcon::ElementItem, {m_variety});
m_accepted = endItems.contains(stereotypeIconId);
}
}
diff --git a/src/libs/qmleditorwidgets/fontsizespinbox.cpp b/src/libs/qmleditorwidgets/fontsizespinbox.cpp
index f127b5a677..8dd86959dc 100644
--- a/src/libs/qmleditorwidgets/fontsizespinbox.cpp
+++ b/src/libs/qmleditorwidgets/fontsizespinbox.cpp
@@ -26,7 +26,7 @@
#include "fontsizespinbox.h"
#include <QLineEdit>
-#include <QRegExpValidator>
+#include <QRegularExpressionValidator>
namespace QmlEditorWidgets {
@@ -91,8 +91,7 @@ void FontSizeSpinBox::onEditingFinished()
QValidator::State FontSizeSpinBox::validate (QString &input, int &p) const
{
- QRegExp rx(QLatin1String("\\d+\\s*(px|pt)"));
- QRegExpValidator v(rx, nullptr);
+ QRegularExpressionValidator v(QRegularExpression(QLatin1String("\\d+\\s*(px|pt)")), nullptr);
return v.validate(input, p);
}
diff --git a/src/libs/qmljs/qmljsdocument.cpp b/src/libs/qmljs/qmljsdocument.cpp
index dfa7414438..25e505e584 100644
--- a/src/libs/qmljs/qmljsdocument.cpp
+++ b/src/libs/qmljs/qmljsdocument.cpp
@@ -382,6 +382,7 @@ LibraryInfo::LibraryInfo(const QmlDirParser &parser, const QByteArray &fingerpri
, _components(parser.components().values())
, _plugins(parser.plugins())
, _typeinfos(parser.typeInfos())
+ , _imports(parser.imports())
, _fingerprint(fingerprint)
{
if (_fingerprint.isEmpty())
@@ -444,6 +445,11 @@ QByteArray LibraryInfo::calculateFingerprint() const
foreach (const ModuleApiInfo &moduleInfo, _moduleApis)
moduleInfo.addToHash(hash); // make it order independent?
+ len = _imports.size();
+ hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
+ foreach (const QString &import, _imports)
+ hash.addData(import.toUtf8()); // import order matters, keep order-dependent
+
QByteArray res(hash.result());
res.append('L');
return res;
diff --git a/src/libs/qmljs/qmljsdocument.h b/src/libs/qmljs/qmljsdocument.h
index 7565ab5fab..7a6b0624ff 100644
--- a/src/libs/qmljs/qmljsdocument.h
+++ b/src/libs/qmljs/qmljsdocument.h
@@ -157,7 +157,8 @@ private:
typedef QList<LanguageUtils::FakeMetaObject::ConstPtr> FakeMetaObjectList;
FakeMetaObjectList _metaObjects;
QList<ModuleApiInfo> _moduleApis;
- QStringList _dependencies;
+ QStringList _dependencies; // from qmltypes "dependencies: [...]"
+ QStringList _imports; // from qmldir "import" commands
QByteArray _fingerprint;
PluginTypeInfoStatus _dumpStatus = NoTypeInfo;
@@ -203,6 +204,12 @@ public:
void setDependencies(const QStringList &deps)
{ _dependencies = deps; }
+ QStringList imports() const
+ { return _imports; }
+
+ void setImports(const QStringList &imports)
+ { _imports = imports; }
+
bool isValid() const
{ return _status == Found; }
diff --git a/src/libs/qmljs/qmljslink.cpp b/src/libs/qmljs/qmljslink.cpp
index e505a9e4c5..dd372d62bb 100644
--- a/src/libs/qmljs/qmljslink.cpp
+++ b/src/libs/qmljs/qmljslink.cpp
@@ -93,7 +93,7 @@ public:
bool importLibrary(const Document::Ptr &doc,
const QString &libraryPath,
- Import *import,
+ Import *import, ObjectValue *targetObject,
const QString &importPath = QString());
void loadQmldirComponents(ObjectValue *import,
LanguageUtils::ComponentVersion version,
@@ -312,7 +312,7 @@ Import LinkPrivate::importFileOrDirectory(const Document::Ptr &doc, const Import
|| importInfo.type() == ImportType::ImplicitDirectory) {
import.object = new ObjectValue(m_valueOwner);
- importLibrary(doc, path, &import);
+ importLibrary(doc, path, &import, import.object);
const QList<Document::Ptr> documentsInDirectory = m_snapshot.documentsInDirectory(path);
for (const Document::Ptr &importedDoc : documentsInDirectory) {
@@ -337,7 +337,7 @@ Import LinkPrivate::importFileOrDirectory(const Document::Ptr &doc, const Import
} else if (importInfo.type() == ImportType::QrcDirectory){
import.object = new ObjectValue(m_valueOwner);
- importLibrary(doc, path, &import);
+ importLibrary(doc, path, &import, import.object);
const QMap<QString, QStringList> paths
= ModelManagerInterface::instance()->filesInQrcPath(path);
@@ -382,7 +382,7 @@ Import LinkPrivate::importNonFile(const Document::Ptr &doc, const ImportInfo &im
const ComponentVersion version = importInfo.version();
QString libraryPath = modulePath(packageName, version.toString(), m_importPaths);
- bool importFound = !libraryPath.isEmpty() && importLibrary(doc, libraryPath, &import);
+ bool importFound = !libraryPath.isEmpty() && importLibrary(doc, libraryPath, &import, import.object);
if (!importFound) {
for (const QString &dir : qAsConst(m_applicationDirectories)) {
@@ -390,7 +390,7 @@ Import LinkPrivate::importNonFile(const Document::Ptr &doc, const ImportInfo &im
// This adds the types to the C++ types, to be found below if applicable.
if (it.hasNext())
- importLibrary(doc, dir, &import);
+ importLibrary(doc, dir, &import, import.object);
}
}
@@ -436,6 +436,7 @@ Import LinkPrivate::importNonFile(const Document::Ptr &doc, const ImportInfo &im
bool LinkPrivate::importLibrary(const Document::Ptr &doc,
const QString &libraryPath,
Import *import,
+ ObjectValue *targetObject,
const QString &importPath)
{
const ImportInfo &importInfo = import->info;
@@ -451,6 +452,38 @@ bool LinkPrivate::importLibrary(const Document::Ptr &doc,
if (const UiImport *ast = importInfo.ast())
errorLoc = locationFromRange(ast->firstSourceLocation(), ast->lastSourceLocation());
+ // Load imports that are mentioned by the "import" command in a qmldir
+ // file into the same targetObject, using the same version and "as".
+ //
+ // Note: Since this works on the same targetObject, the ModuleApi setPrototype()
+ // logic will not work. But ModuleApi isn't used in Qt versions that use import
+ // commands in qmldir files, and is pending removal in Qt 6.
+ for (const auto &importName : libraryInfo.imports()) {
+ Import subImport;
+ subImport.valid = true;
+ subImport.info = ImportInfo::moduleImport(importName, version, importInfo.as(), importInfo.ast());
+ subImport.libraryPath = modulePath(importName, version.toString(), m_importPaths);
+ bool subImportFound = importLibrary(doc, subImport.libraryPath, &subImport, targetObject, importPath);
+
+ if (!subImportFound && errorLoc.isValid()) {
+ import->valid = false;
+ error(doc, errorLoc,
+ Link::tr(
+ "Implicit import '%1' of QML module '%2' not found.\n\n"
+ "Import paths:\n"
+ "%3\n\n"
+ "For qmake projects, use the QML_IMPORT_PATH variable to add import paths.\n"
+ "For Qbs projects, declare and set a qmlImportPaths property in your product "
+ "to add import paths.\n"
+ "For qmlproject projects, use the importPaths property to add import paths.\n"
+ "For CMake projects, make sure QML_IMPORT_PATH variable is in CMakeCache.txt.\n")
+ .arg(importName, importInfo.name(), m_importPaths.join(QLatin1Char('\n'))));
+ } else if (!subImport.valid) {
+ import->valid = false;
+ }
+ }
+
+ // Load types from qmltypes or plugins
if (!libraryInfo.plugins().isEmpty() || !libraryInfo.typeInfos().isEmpty()) {
if (libraryInfo.pluginTypeInfoStatus() == LibraryInfo::NoTypeInfo) {
ModelManagerInterface *modelManager = ModelManagerInterface::instance();
@@ -493,7 +526,7 @@ bool LinkPrivate::importLibrary(const Document::Ptr &doc,
const auto objects = m_valueOwner->cppQmlTypes().createObjectsForImport(packageName,
version);
for (const CppComponentValue *object : objects)
- import->object->setMember(object->className(), object);
+ targetObject->setMember(object->className(), object);
// all but no-uri module apis become available for import
QList<ModuleApiInfo> noUriModuleApis;
@@ -508,13 +541,14 @@ bool LinkPrivate::importLibrary(const Document::Ptr &doc,
// if a module api has no uri, it shares the same name
ModuleApiInfo sameUriModuleApi = findBestModuleApi(noUriModuleApis, version);
if (sameUriModuleApi.version.isValid()) {
- import->object->setPrototype(m_valueOwner->cppQmlTypes()
+ targetObject->setPrototype(m_valueOwner->cppQmlTypes()
.objectByCppName(sameUriModuleApi.cppName));
}
}
}
- loadQmldirComponents(import->object, version, libraryInfo, libraryPath);
+ // Load types that are mentioned explicitly in the qmldir
+ loadQmldirComponents(targetObject, version, libraryInfo, libraryPath);
return true;
}
diff --git a/src/libs/qmljs/qmljsmodelmanagerinterface.cpp b/src/libs/qmljs/qmljsmodelmanagerinterface.cpp
index 25cd5f02d0..1eb54f7303 100644
--- a/src/libs/qmljs/qmljsmodelmanagerinterface.cpp
+++ b/src/libs/qmljs/qmljsmodelmanagerinterface.cpp
@@ -306,6 +306,7 @@ void ModelManagerInterface::updateSourceFiles(const QStringList &files,
void ModelManagerInterface::cleanupFutures()
{
+ QMutexLocker lock(&m_futuresMutex);
const int maxFutures = 10;
if (m_futures.size() > maxFutures) {
const QList<QFuture<void>> futures = m_futures;
@@ -327,8 +328,7 @@ QFuture<void> ModelManagerInterface::refreshSourceFiles(const QStringList &sourc
workingCopyInternal(), sourceFiles,
this, Dialect(Dialect::Qml),
emitDocumentOnDiskChanged);
- cleanupFutures();
- m_futures.append(result);
+ addFuture(result);
if (sourceFiles.count() > 1)
addTaskInternal(result, tr("Parsing QML Files"), Constants::TASK_INDEX);
@@ -1133,13 +1133,11 @@ void ModelManagerInterface::maybeScan(const PathsAndLanguages &importPaths)
pathToScan.maybeInsert(importPath);
}
- if (pathToScan.length() > 1) {
+ if (pathToScan.length() >= 1) {
QFuture<void> result = Utils::runAsync(&ModelManagerInterface::importScan,
workingCopyInternal(), pathToScan,
this, true, true, false);
- cleanupFutures();
- m_futures.append(result);
-
+ addFuture(result);
addTaskInternal(result, tr("Scanning QML Imports"), Constants::TASK_IMPORT_SCAN);
}
}
@@ -1401,7 +1399,7 @@ ModelManagerInterface::CppDataHash ModelManagerInterface::cppData() const
LibraryInfo ModelManagerInterface::builtins(const Document::Ptr &doc) const
{
const ProjectInfo info = projectInfoForPath(doc->fileName());
- if (!info.project.isNull() && !info.qtQmlPath.isEmpty())
+ if (!info.qtQmlPath.isEmpty())
return m_validSnapshot.libraryInfo(info.qtQmlPath);
return LibraryInfo();
}
@@ -1536,13 +1534,43 @@ void ModelManagerInterface::setDefaultVContext(const ViewerContext &vContext)
m_defaultVContexts[vContext.language] = vContext;
}
-void ModelManagerInterface::joinAllThreads()
+void ModelManagerInterface::test_joinAllThreads()
{
- for (QFuture<void> &future : m_futures)
- future.waitForFinished();
+ // Loop since futures can spawn more futures as they finish.
+ while (true) {
+ QFuture<void> f;
+ // get one future
+ {
+ QMutexLocker lock(&m_futuresMutex);
+ for (QFuture<void> &future : m_futures) {
+ if (!future.isFinished() && !future.isCanceled()) {
+ f = future;
+ break;
+ }
+ }
+ }
+ if (!f.isFinished() && !f.isCanceled()) {
+ f.waitForFinished();
+
+ // Some futures trigger more futures from connected signals
+ // and in tests, we care about finishing all of these too.
+ QEventLoop().processEvents();
+ } else {
+ break;
+ }
+ }
m_futures.clear();
}
+void ModelManagerInterface::addFuture(const QFuture<void> &future)
+{
+ {
+ QMutexLocker lock(&m_futuresMutex);
+ m_futures.append(future);
+ }
+ cleanupFutures();
+}
+
Document::Ptr ModelManagerInterface::ensuredGetDocumentForPath(const QString &filePath)
{
QmlJS::Document::Ptr document = newestSnapshot().document(filePath);
diff --git a/src/libs/qmljs/qmljsmodelmanagerinterface.h b/src/libs/qmljs/qmljsmodelmanagerinterface.h
index 4337adcb79..8e8b9d2a24 100644
--- a/src/libs/qmljs/qmljsmodelmanagerinterface.h
+++ b/src/libs/qmljs/qmljsmodelmanagerinterface.h
@@ -179,8 +179,9 @@ public:
virtual ProjectInfo defaultProjectInfoForProject(ProjectExplorer::Project *project) const;
- // Blocks until all parsing threads are done. Used for testing.
- void joinAllThreads();
+ // Blocks until all parsing threads are done. Use for testing only!
+ void test_joinAllThreads();
+ void addFuture(const QFuture<void> &future);
QmlJS::Document::Ptr ensuredGetDocumentForPath(const QString &filePath);
static void importScan(QFutureInterface<void> &future, const WorkingCopy& workingCopyInternal,
@@ -271,7 +272,9 @@ private:
PluginDumper *m_pluginDumper = nullptr;
+ mutable QMutex m_futuresMutex;
QList<QFuture<void>> m_futures;
+
bool m_indexerDisabled = false;
};
diff --git a/src/libs/qmljs/qmljsplugindumper.cpp b/src/libs/qmljs/qmljsplugindumper.cpp
index 7ba665dc94..8b7604809b 100644
--- a/src/libs/qmljs/qmljsplugindumper.cpp
+++ b/src/libs/qmljs/qmljsplugindumper.cpp
@@ -34,6 +34,7 @@
#include <utils/filesystemwatcher.h>
#include <utils/fileutils.h>
#include <utils/hostosinfo.h>
+#include <utils/runextensions.h>
#include <QDir>
#include <QDirIterator>
@@ -283,35 +284,57 @@ void PluginDumper::qmlPluginTypeDumpDone(int exitCode)
if (!privatePlugin)
ModelManagerInterface::writeWarning(qmldumpErrorMessage(libraryPath, errorMessages));
libraryInfo.setPluginTypeInfoStatus(LibraryInfo::DumpError, qmldumpFailedMessage(libraryPath, errorMessages));
- }
-
- const QByteArray output = process->readAllStandardOutput();
- QString error;
- QString warning;
- CppQmlTypesLoader::BuiltinObjects objectsList;
- QList<ModuleApiInfo> moduleApis;
- QStringList dependencies;
- CppQmlTypesLoader::parseQmlTypeDescriptions(output, &objectsList, &moduleApis, &dependencies,
- &error, &warning,
- QLatin1String("<dump of ") + libraryPath + QLatin1Char('>'));
- if (exitCode == 0) {
- if (!error.isEmpty()) {
- libraryInfo.setPluginTypeInfoStatus(LibraryInfo::DumpError,
- qmldumpErrorMessage(libraryPath, error));
- if (!privatePlugin)
- printParseWarnings(libraryPath, libraryInfo.pluginTypeInfoError());
- } else {
- libraryInfo.setMetaObjects(objectsList.values());
- libraryInfo.setModuleApis(moduleApis);
- libraryInfo.setPluginTypeInfoStatus(LibraryInfo::DumpDone);
- }
- if (!warning.isEmpty())
- printParseWarnings(libraryPath, warning);
+ const QByteArray output = process->readAllStandardOutput();
+
+ class CppQmlTypesInfo {
+ public:
+ QString error;
+ QString warning;
+ CppQmlTypesLoader::BuiltinObjects objectsList;
+ QList<ModuleApiInfo> moduleApis;
+ QStringList dependencies;
+ };
+
+ auto future = Utils::runAsync([output, libraryPath](QFutureInterface<CppQmlTypesInfo>& future)
+ {
+ CppQmlTypesInfo infos;
+ CppQmlTypesLoader::parseQmlTypeDescriptions(output, &infos.objectsList, &infos.moduleApis, &infos.dependencies,
+ &infos.error, &infos.warning,
+ QLatin1String("<dump of ") + libraryPath + QLatin1Char('>'));
+ future.reportFinished(&infos);
+ });
+
+ auto finalFuture = Utils::onFinished(future, this,
+ [this, libraryInfo, privatePlugin, libraryPath] (const QFuture<CppQmlTypesInfo>& future) {
+ CppQmlTypesInfo infos = future.result();
+
+ LibraryInfo libInfo = libraryInfo;
+
+ if (!infos.error.isEmpty()) {
+ libInfo.setPluginTypeInfoStatus(LibraryInfo::DumpError,
+ qmldumpErrorMessage(libraryPath, infos.error));
+ if (!privatePlugin)
+ printParseWarnings(libraryPath, libInfo.pluginTypeInfoError());
+ } else {
+ libInfo.setMetaObjects(infos.objectsList.values());
+ libInfo.setModuleApis(infos.moduleApis);
+ libInfo.setPluginTypeInfoStatus(LibraryInfo::DumpDone);
+ }
+
+ if (!infos.warning.isEmpty())
+ printParseWarnings(libraryPath, infos.warning);
+
+ libInfo.updateFingerprint();
+
+ m_modelManager->updateLibraryInfo(libraryPath, libInfo);
+ });
+ m_modelManager->addFuture(finalFuture);
+ } else {
+ libraryInfo.setPluginTypeInfoStatus(LibraryInfo::DumpDone);
+ libraryInfo.updateFingerprint();
+ m_modelManager->updateLibraryInfo(libraryPath, libraryInfo);
}
- libraryInfo.updateFingerprint();
-
- m_modelManager->updateLibraryInfo(libraryPath, libraryInfo);
}
void PluginDumper::qmlPluginTypeDumpError(QProcess::ProcessError)
@@ -344,38 +367,42 @@ void PluginDumper::pluginChanged(const QString &pluginLibrary)
dump(plugin);
}
-void PluginDumper::loadQmlTypeDescription(const QStringList &paths,
- QStringList &errors,
- QStringList &warnings,
- QList<FakeMetaObject::ConstPtr> &objects,
- QList<ModuleApiInfo> *moduleApi,
- QStringList *dependencies) const {
- for (const QString &p: paths) {
- Utils::FileReader reader;
- if (!reader.fetch(p, QFile::Text)) {
- errors += reader.errorString();
- continue;
- }
- QString error;
- QString warning;
- CppQmlTypesLoader::BuiltinObjects objs;
- QList<ModuleApiInfo> apis;
- QStringList deps;
- CppQmlTypesLoader::parseQmlTypeDescriptions(reader.data(), &objs, &apis, &deps,
- &error, &warning, p);
- if (!error.isEmpty()) {
- errors += tr("Failed to parse \"%1\".\nError: %2").arg(p, error);
- } else {
- objects += objs.values();
- if (moduleApi)
- *moduleApi += apis;
- if (!deps.isEmpty())
- *dependencies += deps;
+QFuture<PluginDumper::QmlTypeDescription> PluginDumper::loadQmlTypeDescription(const QStringList &paths) const {
+ auto future = Utils::runAsync([=](QFutureInterface<PluginDumper::QmlTypeDescription> &future)
+ {
+ PluginDumper::QmlTypeDescription result;
+
+ for (const QString &p: paths) {
+ Utils::FileReader reader;
+ if (!reader.fetch(p, QFile::Text)) {
+ result.errors += reader.errorString();
+ continue;
+ }
+ QString error;
+ QString warning;
+ CppQmlTypesLoader::BuiltinObjects objs;
+ QList<ModuleApiInfo> apis;
+ QStringList deps;
+ CppQmlTypesLoader::parseQmlTypeDescriptions(reader.data(), &objs, &apis, &deps,
+ &error, &warning, p);
+ if (!error.isEmpty()) {
+ result.errors += tr("Failed to parse \"%1\".\nError: %2").arg(p, error);
+ } else {
+ result.objects += objs.values();
+ result.moduleApis += apis;
+ if (!deps.isEmpty())
+ result.dependencies += deps;
+ }
+ if (!warning.isEmpty())
+ result.warnings += warning;
}
- if (!warning.isEmpty())
- warnings += warning;
- }
+
+ future.reportFinished(&result);
+ });
+
+ return future;
}
+
/*!
* \brief Build the path of an existing qmltypes file from a module name.
* \param name
@@ -421,16 +448,14 @@ QString PluginDumper::buildQmltypesPath(const QString &name) const
* Recursively load type descriptions of dependencies, collecting results
* in \a objects.
*/
-void PluginDumper::loadDependencies(const QStringList &dependencies,
- QStringList &errors,
- QStringList &warnings,
- QList<FakeMetaObject::ConstPtr> &objects,
- QSet<QString> *visited) const
+QFuture<PluginDumper::DependencyInfo> PluginDumper::loadDependencies(const QStringList &dependencies,
+ QSharedPointer<QSet<QString>> visited) const
{
- if (dependencies.isEmpty())
- return;
+ auto iface = QSharedPointer<QFutureInterface<PluginDumper::DependencyInfo>>(new QFutureInterface<PluginDumper::DependencyInfo>);
- QScopedPointer<QSet<QString>> visitedPtr(visited ? visited : new QSet<QString>());
+ if (visited.isNull()) {
+ visited = QSharedPointer<QSet<QString>>(new QSet<QString>());
+ }
QStringList dependenciesPaths;
QString path;
@@ -438,44 +463,176 @@ void PluginDumper::loadDependencies(const QStringList &dependencies,
path = buildQmltypesPath(name);
if (!path.isNull())
dependenciesPaths << path;
- visitedPtr->insert(name);
+ visited->insert(name);
}
- QStringList newDependencies;
- loadQmlTypeDescription(dependenciesPaths, errors, warnings, objects, nullptr, &newDependencies);
- newDependencies = Utils::toList(Utils::toSet(newDependencies) - *visitedPtr);
- if (!newDependencies.isEmpty())
- loadDependencies(newDependencies, errors, warnings, objects, visitedPtr.take());
+
+ Utils::onFinished(loadQmlTypeDescription(dependenciesPaths), const_cast<PluginDumper*>(this), [=] (const QFuture<PluginDumper::QmlTypeDescription> &typesFuture) {
+ PluginDumper::QmlTypeDescription typesResult = typesFuture.result();
+ QStringList newDependencies = typesResult.dependencies;
+ newDependencies = Utils::toList(Utils::toSet(newDependencies) - *visited.data());
+ if (!newDependencies.isEmpty()) {
+ Utils::onFinished(loadDependencies(newDependencies, visited),
+ const_cast<PluginDumper*>(this), [typesResult, iface] (const QFuture<PluginDumper::DependencyInfo> &future) {
+ PluginDumper::DependencyInfo result = future.result();
+
+ result.errors += typesResult.errors;
+ result.objects += typesResult.objects;
+ result.warnings+= typesResult.warnings;
+
+ iface->reportFinished(&result);
+ });
+
+ } else {
+ PluginDumper::DependencyInfo result;
+ result.errors += typesResult.errors;
+ result.objects += typesResult.objects;
+ result.warnings+= typesResult.warnings;
+ iface->reportFinished(&result);
+ }
+ });
+
+ return iface->future();
}
-void PluginDumper::loadQmltypesFile(const QStringList &qmltypesFilePaths,
- const QString &libraryPath,
- QmlJS::LibraryInfo libraryInfo)
+// Fills \a highestVersion with the largest export version for \a package
+// and sets \a hasExportName to true if a type called \a exportName is found.
+static void getHighestExportVersion(
+ const QList<LanguageUtils::FakeMetaObject::ConstPtr> &objects,
+ const QString &package,
+ const QString &exportName,
+ bool *hasExportName,
+ ComponentVersion *highestVersion)
+{
+ *highestVersion = ComponentVersion();
+ *hasExportName = false;
+ for (const auto &object : objects) {
+ for (const auto &e : object->exports()) {
+ if (e.package == package) {
+ if (e.version > *highestVersion)
+ *highestVersion = e.version;
+ if (e.type == exportName)
+ *hasExportName = true;
+ }
+ }
+ }
+
+}
+
+/*** Workaround for implicit dependencies in >= 5.15.0.
+ *
+ * When "QtQuick" is imported, "QtQml" is implicitly loaded as well.
+ * When "QtQml" is imported, "QtQml.Models" and "QtQml.WorkerScript" are implicitly loaded.
+ * Add these imports as if they were "import" commands in the qmldir file.
+ *
+ * Qt 6 is planned to have these included in the qmldir file.
+ */
+static void applyQt515MissingImportWorkaround(const QString &path, LibraryInfo &info)
{
- QStringList errors;
- QStringList warnings;
- QList<FakeMetaObject::ConstPtr> objects;
- QList<ModuleApiInfo> moduleApis;
- QStringList dependencies;
-
- loadQmlTypeDescription(qmltypesFilePaths, errors, warnings, objects, &moduleApis, &dependencies);
- loadDependencies(dependencies, errors, warnings, objects);
-
- libraryInfo.setMetaObjects(objects);
- libraryInfo.setModuleApis(moduleApis);
- libraryInfo.setDependencies(dependencies);
- if (errors.isEmpty()) {
- libraryInfo.setPluginTypeInfoStatus(LibraryInfo::TypeInfoFileDone);
+ if (!info.imports().isEmpty())
+ return;
+
+ const bool isQtQuick = path.endsWith(QStringLiteral("/QtQuick"))
+ || path.endsWith(QStringLiteral("/QtQuick.2"));
+ const bool isQtQml = path.endsWith(QStringLiteral("/QtQml"))
+ || path.endsWith(QStringLiteral("/QtQml.2"));
+ if (!isQtQuick && !isQtQml)
+ return;
+
+ ComponentVersion highestVersion;
+ const auto package = isQtQuick ? QStringLiteral("QtQuick") : QStringLiteral("QtQml");
+ const auto missingTypeName = isQtQuick ? QStringLiteral("QtObject") : QStringLiteral("ListElement");
+ bool hasMissingType = false;
+ getHighestExportVersion(
+ info.metaObjects(),
+ package,
+ missingTypeName,
+ &hasMissingType,
+ &highestVersion);
+
+ // If the highest export version is < 2.15, we expect Qt <5.15
+ if (highestVersion.majorVersion() != 2 || highestVersion.minorVersion() < 15)
+ return;
+ // As an extra sanity check: if the type from the dependent module already exists,
+ // don't proceeed either.
+ if (hasMissingType)
+ return;
+
+ if (isQtQuick) {
+ info.setImports(QStringList(QStringLiteral("QtQml")));
+ } else if (isQtQml) {
+ info.setImports(QStringList(
+ { QStringLiteral("QtQml.Models"),
+ QStringLiteral("QtQml.WorkerScript") }));
+ }
+}
+
+void PluginDumper::prepareLibraryInfo(LibraryInfo &libInfo,
+ const QString &libraryPath,
+ const QStringList &deps,
+ const QStringList &errors,
+ const QStringList &warnings,
+ const QList<ModuleApiInfo> &moduleApis,
+ QList<FakeMetaObject::ConstPtr> &objects)
+{
+ QStringList errs = errors;
+
+ libInfo.setMetaObjects(objects);
+ libInfo.setModuleApis(moduleApis);
+ libInfo.setDependencies(deps);
+
+ if (errs.isEmpty()) {
+ libInfo.setPluginTypeInfoStatus(LibraryInfo::TypeInfoFileDone);
} else {
printParseWarnings(libraryPath, errors.join(QLatin1Char('\n')));
- errors.prepend(tr("Errors while reading typeinfo files:"));
- libraryInfo.setPluginTypeInfoStatus(LibraryInfo::TypeInfoFileError, errors.join(QLatin1Char('\n')));
+ errs.prepend(tr("Errors while reading typeinfo files:"));
+ libInfo.setPluginTypeInfoStatus(LibraryInfo::TypeInfoFileError, errs.join(QLatin1Char('\n')));
}
if (!warnings.isEmpty())
printParseWarnings(libraryPath, warnings.join(QLatin1String("\n")));
- libraryInfo.updateFingerprint();
- m_modelManager->updateLibraryInfo(libraryPath, libraryInfo);
+ applyQt515MissingImportWorkaround(libraryPath, libInfo);
+
+ libInfo.updateFingerprint();
+}
+
+void PluginDumper::loadQmltypesFile(const QStringList &qmltypesFilePaths,
+ const QString &libraryPath,
+ QmlJS::LibraryInfo libraryInfo)
+{
+ auto future = Utils::onFinished(loadQmlTypeDescription(qmltypesFilePaths), this, [=](const QFuture<PluginDumper::QmlTypeDescription> &typesFuture)
+ {
+ PluginDumper::QmlTypeDescription typesResult = typesFuture.result();
+ if (!typesResult.dependencies.isEmpty())
+ {
+ auto depFuture = Utils::onFinished(loadDependencies(typesResult.dependencies, QSharedPointer<QSet<QString>>()), this,
+ [typesResult, libraryInfo, libraryPath, this] (const QFuture<PluginDumper::DependencyInfo> &loadFuture)
+ {
+ PluginDumper::DependencyInfo loadResult = loadFuture.result();
+ QStringList errors = typesResult.errors;
+ QStringList warnings = typesResult.errors;
+ QList<FakeMetaObject::ConstPtr> objects = typesResult.objects;
+
+ errors += loadResult.errors;
+ warnings += loadResult.warnings;
+ objects += loadResult.objects;
+
+ QmlJS::LibraryInfo libInfo = libraryInfo;
+ prepareLibraryInfo(libInfo, libraryPath, typesResult.dependencies,
+ errors, warnings,
+ typesResult.moduleApis, objects);
+ m_modelManager->updateLibraryInfo(libraryPath, libInfo);
+ });
+ m_modelManager->addFuture(depFuture);
+ } else {
+ QmlJS::LibraryInfo libInfo = libraryInfo;
+ prepareLibraryInfo(libInfo, libraryPath, typesResult.dependencies,
+ typesResult.errors, typesResult.warnings,
+ typesResult.moduleApis, typesResult.objects);
+ m_modelManager->updateLibraryInfo(libraryPath, libInfo);
+ }
+ });
+ m_modelManager->addFuture(future);
}
void PluginDumper::runQmlDump(const QmlJS::ModelManagerInterface::ProjectInfo &info,
diff --git a/src/libs/qmljs/qmljsplugindumper.h b/src/libs/qmljs/qmljsplugindumper.h
index d38b09bea4..3b664d507b 100644
--- a/src/libs/qmljs/qmljsplugindumper.h
+++ b/src/libs/qmljs/qmljsplugindumper.h
@@ -71,18 +71,30 @@ private:
QStringList typeInfoPaths;
};
+ class QmlTypeDescription {
+ public:
+ QStringList errors;
+ QStringList warnings;
+ QList<LanguageUtils::FakeMetaObject::ConstPtr> objects;
+ QList<ModuleApiInfo> moduleApis;
+ QStringList dependencies;
+ };
+
+ class DependencyInfo {
+ public:
+ QStringList errors;
+ QStringList warnings;
+ QList<LanguageUtils::FakeMetaObject::ConstPtr> objects;
+ };
+
void runQmlDump(const QmlJS::ModelManagerInterface::ProjectInfo &info, const QStringList &arguments, const QString &importPath);
void dump(const Plugin &plugin);
- void loadQmlTypeDescription(const QStringList &path, QStringList &errors, QStringList &warnings,
- QList<LanguageUtils::FakeMetaObject::ConstPtr> &objects,
- QList<ModuleApiInfo> *moduleApi,
- QStringList *dependencies) const;
+ QFuture<QmlTypeDescription> loadQmlTypeDescription(const QStringList &path) const;
QString buildQmltypesPath(const QString &name) const;
- void loadDependencies(const QStringList &dependencies,
- QStringList &errors,
- QStringList &warnings,
- QList<LanguageUtils::FakeMetaObject::ConstPtr> &objects,
- QSet<QString> *visited = nullptr) const;
+
+ QFuture<PluginDumper::DependencyInfo> loadDependencies(const QStringList &dependencies,
+ QSharedPointer<QSet<QString>> visited) const;
+
void loadQmltypesFile(const QStringList &qmltypesFilePaths,
const QString &libraryPath,
QmlJS::LibraryInfo libraryInfo);
@@ -94,6 +106,13 @@ private:
private:
Utils::FileSystemWatcher *pluginWatcher();
+ void prepareLibraryInfo(LibraryInfo &libInfo,
+ const QString &libraryPath,
+ const QStringList &deps,
+ const QStringList &errors,
+ const QStringList &warnings,
+ const QList<ModuleApiInfo> &moduleApis,
+ QList<LanguageUtils::FakeMetaObject::ConstPtr> &objects);
ModelManagerInterface *m_modelManager;
Utils::FileSystemWatcher *m_pluginWatcher;
diff --git a/src/libs/qtcreatorcdbext/CMakeLists.txt b/src/libs/qtcreatorcdbext/CMakeLists.txt
index b08a833b7a..331dc80937 100644
--- a/src/libs/qtcreatorcdbext/CMakeLists.txt
+++ b/src/libs/qtcreatorcdbext/CMakeLists.txt
@@ -83,7 +83,7 @@ if (_library_enabled)
return()
endif()
- extend_qtc_target(qtcreatorcdbext
+ extend_qtc_library(qtcreatorcdbext
DEPENDS "${PYTHON_LIBRARIES}"
INCLUDES "${PYTHON_INCLUDE_DIR}"
DEFINES WITH_PYTHON=1
diff --git a/src/libs/qtcreatorcdbext/extensioncontext.h b/src/libs/qtcreatorcdbext/extensioncontext.h
index e1a27f3a9a..db099c17ca 100644
--- a/src/libs/qtcreatorcdbext/extensioncontext.h
+++ b/src/libs/qtcreatorcdbext/extensioncontext.h
@@ -137,8 +137,8 @@ private:
bool isInitialized() const;
IInterfacePointer<CIDebugControl> m_control;
- std::auto_ptr<LocalsSymbolGroup> m_symbolGroup;
- std::auto_ptr<WatchesSymbolGroup> m_watchesSymbolGroup;
+ std::unique_ptr<LocalsSymbolGroup> m_symbolGroup;
+ std::unique_ptr<WatchesSymbolGroup> m_watchesSymbolGroup;
CIDebugClient *m_hookedClient = nullptr;
IDebugEventCallbacks *m_oldEventCallback = nullptr;
diff --git a/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp b/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp
index 77e537c275..f60ad90cc9 100644
--- a/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp
+++ b/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp
@@ -191,6 +191,12 @@ static inline bool isOption(const std::string &opt)
return opt.size() == 2 && opt.at(0) == '-' && opt != "--";
}
+struct CommandToken
+{
+ int majorPart = 0;
+ int minorPart = 0;
+};
+
// Helper for commandTokens() below:
// Simple splitting of command lines allowing for '"'-quoted tokens
// 'typecast local.i "class QString *"' -> ('typecast','local.i','class QString *')
@@ -251,6 +257,38 @@ static inline void splitCommand(PCSTR args, Inserter it)
}
}
+// check whether arguments start with a "-t 23.1" or "-t 3" token identifier
+CommandToken extractToken(PCSTR args, PCSTR *afterToken)
+{
+ CommandToken token;
+ while (*args == ' ') // skip whitespace
+ ++args;
+ if (*args != '-')
+ return {};
+ if (*(++args) != 't')
+ return {};
+ ++args;
+ while (*args == ' ') // skip whitespace
+ ++args;
+ PSTR end = nullptr;
+ token.majorPart = strtol(args, &end, 10);
+ if (args >= end)
+ return {};
+ args = end;
+ if (*args == '.') {
+ ++args;
+ end = nullptr;
+ token.minorPart = strtol(args, &end, 10);
+ if (args >= end)
+ return {};
+ args = end;
+ }
+ while (*args == ' ') // skip whitespace
+ ++args;
+ *afterToken = args;
+ return token;
+}
+
// Split & Parse the arguments of a command and extract the
// optional first integer token argument ('command -t <number> remaining arguments')
// Each command takes the 'token' argument and includes it in its output
@@ -259,18 +297,25 @@ static inline void splitCommand(PCSTR args, Inserter it)
template<class StringContainer>
static inline StringContainer commandTokens(PCSTR args, int *token = 0)
{
- typedef typename StringContainer::iterator ContainerIterator;
+ static std::map<int, std::string> s_commandBuffer;
if (token)
*token = -1; // Handled as 'display' in engine, so that user can type commands
+
StringContainer tokens;
- splitCommand(args, std::back_inserter(tokens));
- // Check for token
- ContainerIterator it = tokens.begin();
- if (it != tokens.end() && *it == "-t" && ++it != tokens.end()) {
- if (token)
- std::istringstream(*it) >> *token;
- tokens.erase(tokens.begin(), ++it);
+ CommandToken commandToken = extractToken(args, &args);
+ if (commandToken.majorPart != 0) {
+ s_commandBuffer[commandToken.majorPart].append(args);
+ if (commandToken.minorPart == 0) {
+ DebugPrint() << commandToken.majorPart << ':' << s_commandBuffer[commandToken.majorPart];
+ splitCommand(s_commandBuffer[commandToken.majorPart].data(), std::back_inserter(tokens));
+ if (token)
+ *token = commandToken.majorPart;
+ } else if (token) {
+ *token = 0;
+ }
+ } else {
+ splitCommand(args, std::back_inserter(tokens));
}
return tokens;
}
@@ -283,6 +328,8 @@ extern "C" HRESULT CALLBACK pid(CIDebugClient *client, PCSTR args)
int token;
commandTokens<StringList>(args, &token);
+ if (token == 0) // partial message
+ return S_OK;
dprintf("Qt Creator CDB extension version 4.3 %d bit.\n",
sizeof(void *) * 8);
if (const ULONG pid = currentProcessId(client))
@@ -304,6 +351,9 @@ extern "C" HRESULT CALLBACK expandlocals(CIDebugClient *client, PCSTR args)
int token;
StringList tokens = commandTokens<StringList>(args, &token);
+ if (token == 0) // partial message
+ return S_OK;
+
StringVector inames;
bool runComplexDumpers = false;
do {
@@ -423,10 +473,12 @@ static std::string commandLocals(ExtensionCommandContext &commandExtCtx,PCSTR ar
typedef InameExpressionMap::value_type InameExpressionMapEntry;
// Parse the command
+ StringList tokens = commandTokens<StringList>(args, token);
+ if (token == 0) // partial arguments
+ return {};
ExtensionContext &extCtx = ExtensionContext::instance();
DumpCommandParameters parameters;
std::string iname;
- StringList tokens = commandTokens<StringList>(args, token);
StringVector expandedInames;
StringVector uninitializedInames;
InameExpressionMap watcherInameExpressionMap;
@@ -577,8 +629,11 @@ extern "C" HRESULT CALLBACK script(CIDebugClient *client, PCSTR argsIn)
ExtensionCommandContext exc(client);
int token;
#ifdef WITH_PYTHON
+ const StringList args = commandTokens<StringList>(argsIn, &token);
+ if (token == 0) // partial arguments
+ return {};
std::stringstream command;
- for (std::string arg : commandTokens<StringList>(argsIn, &token))
+ for (std::string arg : args)
command << arg << ' ';
PyObject *ptype = NULL;
@@ -594,6 +649,8 @@ extern "C" HRESULT CALLBACK script(CIDebugClient *client, PCSTR argsIn)
PyErr_Restore(ptype, pvalue, ptraceback);
#else
commandTokens<StringList>(argsIn, &token);
+ if (token == 0) // partial arguments
+ return {};
ExtensionContext::instance().report('N', token, 0, "script",
"Python is not supported in this CDB extension.\n"
"You need to define PYTHON_INSTALL_DIR in your creator build environment "
@@ -608,6 +665,8 @@ extern "C" HRESULT CALLBACK locals(CIDebugClient *client, PCSTR args)
std::string errorMessage;
int token;
const std::string output = commandLocals(exc, args, &token, &errorMessage);
+ if (token == 0) // partial message
+ return S_OK;
SymbolGroupValue::verbose = 0;
if (output.empty())
ExtensionContext::instance().report('N', token, 0, "locals", errorMessage.c_str());
@@ -625,6 +684,9 @@ static std::string commmandWatches(ExtensionCommandContext &exc, PCSTR args, int
// Parse the command
DumpCommandParameters parameters;
StringList tokens = commandTokens<StringList>(args, token);
+ if (token == 0) // partial message
+ return {};
+
// Parse away options
for (bool optionLeft = true; optionLeft && !tokens.empty(); ) {
switch (parameters.parseOption(&tokens)) {
@@ -662,6 +724,9 @@ extern "C" HRESULT CALLBACK watches(CIDebugClient *client, PCSTR args)
std::string errorMessage = "e";
int token = 0;
const std::string output = commmandWatches(exc, args, &token, &errorMessage);
+ if (token == 0) // partial message
+ return S_OK;
+
SymbolGroupValue::verbose = 0;
if (output.empty())
ExtensionContext::instance().report('N', token, 0, "locals", errorMessage.c_str());
@@ -677,6 +742,9 @@ static std::string dumplocalHelper(ExtensionCommandContext &exc,PCSTR args, int
{
// Parse the command
StringList tokens = commandTokens<StringList>(args, token);
+ if (token == 0) // partial message
+ return {};
+
// Frame and iname
unsigned frame;
if (tokens.empty() || integerFromString(tokens.front(), &frame)) {
@@ -714,6 +782,9 @@ extern "C" HRESULT CALLBACK dumplocal(CIDebugClient *client, PCSTR argsIn)
std::string errorMessage;
int token = 0;
const std::string value = dumplocalHelper(exc,argsIn, &token, &errorMessage);
+ if (token == 0) // partial message
+ return S_OK;
+
if (value.empty())
ExtensionContext::instance().report('N', token, 0, "dumplocal", errorMessage.c_str());
else
@@ -733,6 +804,9 @@ extern "C" HRESULT CALLBACK typecast(CIDebugClient *client, PCSTR args)
int token;
const StringVector tokens = commandTokens<StringVector>(args, &token);
+ if (token == 0) // partial message
+ return S_OK;
+
std::string iname;
std::string desiredType;
if (tokens.size() == 3u && integerFromString(tokens.front(), &frame)) {
@@ -761,6 +835,9 @@ extern "C" HRESULT CALLBACK addsymbol(CIDebugClient *client, PCSTR args)
int token;
const StringVector tokens = commandTokens<StringVector>(args, &token);
+ if (token == 0) // partial message
+ return S_OK;
+
std::string name;
std::string iname;
if (tokens.size() >= 2u && integerFromString(tokens.front(), &frame)) {
@@ -790,6 +867,9 @@ extern "C" HRESULT CALLBACK addwatch(CIDebugClient *client, PCSTR argsIn)
bool success = false;
do {
StringList tokens = commandTokens<StringList>(argsIn, &token);
+ if (token == 0) // partial message
+ return S_OK;
+
if (tokens.size() != 2) {
errorMessage = singleLineUsage(commandDescriptions[CmdAddWatch]);
break;
@@ -903,6 +983,8 @@ extern "C" HRESULT CALLBACK threads(CIDebugClient *client, PCSTR argsIn)
int token;
commandTokens<StringList>(argsIn, &token);
+ if (token == 0) // partial message
+ return S_OK;
const std::string gdbmi = gdbmiThreadList(exc.systemObjects(),
exc.symbols(),
@@ -926,6 +1008,9 @@ extern "C" HRESULT CALLBACK registers(CIDebugClient *Client, PCSTR argsIn)
int token;
const StringList tokens = commandTokens<StringList>(argsIn, &token);
+ if (token == 0) // partial message
+ return S_OK;
+
const bool humanReadable = !tokens.empty() && tokens.front() == "-h";
const std::string regs = gdbmiRegisters(exc.registers(), exc.control(), humanReadable, IncludePseudoRegisters, &errorMessage);
if (regs.empty())
@@ -945,6 +1030,9 @@ extern "C" HRESULT CALLBACK modules(CIDebugClient *Client, PCSTR argsIn)
int token;
const StringList tokens = commandTokens<StringList>(argsIn, &token);
+ if (token == 0) // partial message
+ return S_OK;
+
const bool humanReadable = !tokens.empty() && tokens.front() == "-h";
const std::string modules = gdbmiModules(exc.symbols(), humanReadable, &errorMessage);
if (modules.empty())
@@ -969,6 +1057,9 @@ extern "C" HRESULT CALLBACK setparameter(CIDebugClient *, PCSTR args)
{
int token;
StringVector tokens = commandTokens<StringVector>(args, &token);
+ if (token == 0) // partial message
+ return S_OK;
+
const size_t count = tokens.size();
size_t success = 0;
for (size_t i = 0; i < count; ++i) {
@@ -1034,6 +1125,9 @@ extern "C" HRESULT CALLBACK memory(CIDebugClient *Client, PCSTR argsIn)
ULONG length = 0;
const StringVector tokens = commandTokens<StringVector>(argsIn, &token);
+ if (token == 0) // partial message
+ return S_OK;
+
if (tokens.size() == 2
&& integerFromString(tokens.front(), &address)
&& integerFromString(tokens.at(1), &length)) {
@@ -1061,6 +1155,9 @@ extern "C" HRESULT CALLBACK expression(CIDebugClient *Client, PCSTR argsIn)
do {
const StringVector tokens = commandTokens<StringVector>(argsIn, &token);
+ if (token == 0) // partial message
+ return S_OK;
+
if (tokens.size() != 1) {
errorMessage = singleLineUsage(commandDescriptions[CmdExpression]);
@@ -1090,6 +1187,9 @@ extern "C" HRESULT CALLBACK stack(CIDebugClient *Client, PCSTR argsIn)
unsigned maxFrames = ExtensionContext::instance().parameters().maxStackDepth;
StringList tokens = commandTokens<StringList>(argsIn, &token);
+ if (token == 0) // partial message
+ return S_OK;
+
if (!tokens.empty() && tokens.front() == "-h") {
humanReadable = true;
tokens.pop_front();
@@ -1126,6 +1226,9 @@ extern "C" HRESULT CALLBACK qmlstack(CIDebugClient *client, PCSTR argsIn)
do {
StringList tokens = commandTokens<StringList>(argsIn, &token);
+ if (token == 0) // partial message
+ return S_OK;
+
if (!tokens.empty() && tokens.front() == "-h") {
humanReadable = true;
tokens.pop_front();
@@ -1190,6 +1293,9 @@ extern "C" HRESULT CALLBACK widgetat(CIDebugClient *client, PCSTR argsIn)
int y = -1;
const StringVector tokens = commandTokens<StringVector>(argsIn, &token);
+ if (token == 0) // partial message
+ return S_OK;
+
if (tokens.size() != 2) {
errorMessage = singleLineUsage(commandDescriptions[CmdWidgetAt]);
break;
@@ -1217,6 +1323,9 @@ extern "C" HRESULT CALLBACK breakpoints(CIDebugClient *client, PCSTR argsIn)
bool humanReadable = false;
unsigned verbose = 0;
StringList tokens = commandTokens<StringList>(argsIn, &token);
+ if (token == 0) // partial message
+ return S_OK;
+
while (!tokens.empty() && tokens.front().size() == 2 && tokens.front().at(0) == '-') {
switch (tokens.front().at(1)) {
case 'h':
@@ -1246,6 +1355,9 @@ extern "C" HRESULT CALLBACK test(CIDebugClient *client, PCSTR argsIn)
Mode mode = Invalid;
int token = 0;
StringList tokens = commandTokens<StringList>(argsIn, &token);
+ if (token == 0) // partial message
+ return S_OK;
+
// Parse away options
while (!tokens.empty() && tokens.front().size() == 2 && tokens.front().at(0) == '-') {
const char option = tokens.front().at(1);
diff --git a/src/libs/qtcreatorcdbext/symbolgroup.cpp b/src/libs/qtcreatorcdbext/symbolgroup.cpp
index 0d55fb6a39..6bc08506b4 100644
--- a/src/libs/qtcreatorcdbext/symbolgroup.cpp
+++ b/src/libs/qtcreatorcdbext/symbolgroup.cpp
@@ -227,7 +227,7 @@ std::string SymbolGroup::debug(const std::string &iname,
{
std::ostringstream str;
str << '\n';
- std::auto_ptr<DebugSymbolGroupNodeVisitor>
+ std::unique_ptr<DebugSymbolGroupNodeVisitor>
visitor(filter.empty() ?
new DebugSymbolGroupNodeVisitor(str, verbosity) :
new DebugFilterSymbolGroupNodeVisitor(str, filter, verbosity));
diff --git a/src/libs/sqlite/CMakeLists.txt b/src/libs/sqlite/CMakeLists.txt
index 36737ca1a2..36a92a7099 100644
--- a/src/libs/sqlite/CMakeLists.txt
+++ b/src/libs/sqlite/CMakeLists.txt
@@ -22,6 +22,7 @@ add_qtc_library(Sqlite
sqlitetable.h
sqlitetransaction.h
sqlitewritestatement.cpp sqlitewritestatement.h
+ sqlitevalue.h
sqlstatementbuilder.cpp sqlstatementbuilder.h
sqlstatementbuilderexception.h
utf8string.cpp utf8string.h
diff --git a/src/libs/sqlite/sqlite-lib.pri b/src/libs/sqlite/sqlite-lib.pri
index 4d7f906a19..1ce343b624 100644
--- a/src/libs/sqlite/sqlite-lib.pri
+++ b/src/libs/sqlite/sqlite-lib.pri
@@ -32,6 +32,7 @@ HEADERS += \
$$PWD/sqlitereadstatement.h \
$$PWD/sqlitereadwritestatement.h \
$$PWD/sqlitetransaction.h \
+ $$PWD/sqlitevalue.h \
$$PWD/sqlitewritestatement.h \
$$PWD/sqlstatementbuilder.h \
$$PWD/sqlstatementbuilderexception.h \
diff --git a/src/libs/sqlite/sqlitebasestatement.cpp b/src/libs/sqlite/sqlitebasestatement.cpp
index 87aa3f68b3..85a6db2ddc 100644
--- a/src/libs/sqlite/sqlitebasestatement.cpp
+++ b/src/libs/sqlite/sqlitebasestatement.cpp
@@ -190,6 +190,21 @@ void BaseStatement::bind(int index, Utils::SmallStringView text)
checkForBindingError(resultCode);
}
+void BaseStatement::bind(int index, const Value &value)
+{
+ switch (value.type()) {
+ case ValueType::Integer:
+ bind(index, value.toInteger());
+ break;
+ case ValueType::Float:
+ bind(index, value.toFloat());
+ break;
+ case ValueType::String:
+ bind(index, value.toStringView());
+ break;
+ }
+}
+
template <typename Type>
void BaseStatement::bind(Utils::SmallStringView name, Type value)
{
@@ -498,12 +513,34 @@ StringType BaseStatement::fetchValue(int column) const
return convertToTextForColumn<StringType>(m_compiledStatement.get(), column);
}
+template SQLITE_EXPORT Utils::SmallStringView BaseStatement::fetchValue<Utils::SmallStringView>(
+ int column) const;
+template SQLITE_EXPORT Utils::SmallString BaseStatement::fetchValue<Utils::SmallString>(
+ int column) const;
+template SQLITE_EXPORT Utils::PathString BaseStatement::fetchValue<Utils::PathString>(
+ int column) const;
+
Utils::SmallStringView BaseStatement::fetchSmallStringViewValue(int column) const
{
return fetchValue<Utils::SmallStringView>(column);
}
-template SQLITE_EXPORT Utils::SmallStringView BaseStatement::fetchValue<Utils::SmallStringView>(int column) const;
-template SQLITE_EXPORT Utils::SmallString BaseStatement::fetchValue<Utils::SmallString>(int column) const;
-template SQLITE_EXPORT Utils::PathString BaseStatement::fetchValue<Utils::PathString>(int column) const;
+ValueView BaseStatement::fetchValueView(int column) const
+{
+ int dataType = sqlite3_column_type(m_compiledStatement.get(), column);
+ switch (dataType) {
+ case SQLITE_INTEGER:
+ return ValueView::create(fetchLongLongValue(column));
+ case SQLITE_FLOAT:
+ return ValueView::create(fetchDoubleValue(column));
+ case SQLITE3_TEXT:
+ return ValueView::create(fetchValue<Utils::SmallStringView>(column));
+ case SQLITE_BLOB:
+ case SQLITE_NULL:
+ break;
+ }
+
+ return ValueView::create(0LL);
+}
+
} // namespace Sqlite
diff --git a/src/libs/sqlite/sqlitebasestatement.h b/src/libs/sqlite/sqlitebasestatement.h
index 86d03fd855..aa40e0c6ea 100644
--- a/src/libs/sqlite/sqlitebasestatement.h
+++ b/src/libs/sqlite/sqlitebasestatement.h
@@ -28,6 +28,7 @@
#include "sqliteglobal.h"
#include "sqliteexception.h"
+#include "sqlitevalue.h"
#include <utils/smallstringvector.h>
@@ -67,6 +68,7 @@ public:
long long fetchLongLongValue(int column) const;
double fetchDoubleValue(int column) const;
Utils::SmallStringView fetchSmallStringViewValue(int column) const;
+ ValueView fetchValueView(int column) const;
template<typename Type>
Type fetchValue(int column) const;
int columnCount() const;
@@ -76,11 +78,9 @@ public:
void bind(int index, long long fetchValue);
void bind(int index, double fetchValue);
void bind(int index, Utils::SmallStringView fetchValue);
+ void bind(int index, const Value &fetchValue);
- void bind(int index, uint value)
- {
- bind(index, static_cast<long long>(value));
- }
+ void bind(int index, uint value) { bind(index, static_cast<long long>(value)); }
void bind(int index, long value)
{
@@ -345,34 +345,16 @@ private:
struct ValueGetter
{
ValueGetter(StatementImplementation &statement, int column)
- : statement(statement),
- column(column)
+ : statement(statement)
+ , column(column)
{}
- operator int()
- {
- return statement.fetchIntValue(column);
- }
-
- operator long()
- {
- return statement.fetchLongValue(column);
- }
-
- operator long long()
- {
- return statement.fetchLongLongValue(column);
- }
-
- operator double()
- {
- return statement.fetchDoubleValue(column);
- }
-
- operator Utils::SmallStringView()
- {
- return statement.fetchSmallStringViewValue(column);
- }
+ operator int() { return statement.fetchIntValue(column); }
+ operator long() { return statement.fetchLongValue(column); }
+ operator long long() { return statement.fetchLongLongValue(column); }
+ operator double() { return statement.fetchDoubleValue(column); }
+ operator Utils::SmallStringView() { return statement.fetchSmallStringViewValue(column); }
+ operator ValueView() { return statement.fetchValueView(column); }
StatementImplementation &statement;
int column;
diff --git a/src/libs/sqlite/sqliteexception.h b/src/libs/sqlite/sqliteexception.h
index 8edfd984ef..6f898504a4 100644
--- a/src/libs/sqlite/sqliteexception.h
+++ b/src/libs/sqlite/sqliteexception.h
@@ -264,4 +264,12 @@ public:
}
};
+class CannotConvert : public Exception
+{
+public:
+ CannotConvert(const char *whatErrorHasHappen)
+ : Exception(whatErrorHasHappen)
+ {}
+};
+
} // namespace Sqlite
diff --git a/src/libs/sqlite/sqlitevalue.h b/src/libs/sqlite/sqlitevalue.h
new file mode 100644
index 0000000000..ca57642177
--- /dev/null
+++ b/src/libs/sqlite/sqlitevalue.h
@@ -0,0 +1,300 @@
+/****************************************************************************
+**
+** 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 "sqliteexception.h"
+
+#include <utils/smallstring.h>
+#include <utils/variant.h>
+
+#include <QVariant>
+
+#pragma once
+
+namespace Sqlite {
+
+enum class ValueType : unsigned char { Integer, Float, String };
+
+template<typename StringType>
+class ValueBase
+{
+public:
+ using VariantType = Utils::variant<long long, double, StringType>;
+
+ explicit ValueBase(VariantType &&value)
+ : value(value)
+ {}
+
+ explicit ValueBase(const char *value)
+ : value(Utils::SmallStringView{value})
+ {}
+
+ explicit ValueBase(long long value)
+ : value(value)
+ {}
+ explicit ValueBase(int value)
+ : value(static_cast<long long>(value))
+ {}
+
+ explicit ValueBase(uint value)
+ : value(static_cast<long long>(value))
+ {}
+
+ explicit ValueBase(double value)
+ : value(value)
+ {}
+
+ explicit ValueBase(Utils::SmallStringView value)
+ : value(value)
+
+ {}
+
+ long long toInteger() const { return Utils::get<int(ValueType::Integer)>(value); }
+
+ double toFloat() const { return Utils::get<int(ValueType::Float)>(value); }
+
+ Utils::SmallStringView toStringView() const
+ {
+ return Utils::get<int(ValueType::String)>(value);
+ }
+
+ explicit operator QVariant() const
+ {
+ switch (type()) {
+ case ValueType::Integer:
+ return QVariant(toInteger());
+ case ValueType::Float:
+ return QVariant(toFloat());
+ case ValueType::String:
+ return QVariant(QString(toStringView()));
+ }
+
+ return {};
+ }
+
+ friend bool operator==(const ValueBase &first, long long second)
+ {
+ auto maybeInteger = Utils::get_if<int(ValueType::Integer)>(&first.value);
+
+ return maybeInteger && *maybeInteger == second;
+ }
+
+ friend bool operator==(long long first, const ValueBase &second) { return second == first; }
+
+ friend bool operator==(const ValueBase &first, double second)
+ {
+ auto maybeInteger = Utils::get_if<int(ValueType::Float)>(&first.value);
+
+ return maybeInteger && *maybeInteger == second;
+ }
+
+ friend bool operator==(const ValueBase &first, int second)
+ {
+ return first == static_cast<long long>(second);
+ }
+
+ friend bool operator==(int first, const ValueBase &second) { return second == first; }
+
+ friend bool operator==(const ValueBase &first, uint second)
+ {
+ return first == static_cast<long long>(second);
+ }
+
+ friend bool operator==(uint first, const ValueBase &second) { return second == first; }
+
+ friend bool operator==(double first, const ValueBase &second) { return second == first; }
+
+ friend bool operator==(const ValueBase &first, Utils::SmallStringView second)
+ {
+ auto maybeInteger = Utils::get_if<int(ValueType::String)>(&first.value);
+
+ return maybeInteger && *maybeInteger == second;
+ }
+
+ friend bool operator==(Utils::SmallStringView first, const ValueBase &second)
+ {
+ return second == first;
+ }
+
+ friend bool operator==(const ValueBase &first, const QString &second)
+ {
+ auto maybeInteger = Utils::get_if<int(ValueType::String)>(&first.value);
+
+ return maybeInteger
+ && second == QLatin1String{maybeInteger->data(), int(maybeInteger->size())};
+ }
+
+ friend bool operator==(const QString &first, const ValueBase &second)
+ {
+ return second == first;
+ }
+
+ friend bool operator==(const ValueBase &first, const char *second)
+ {
+ return first == Utils::SmallStringView{second};
+ }
+
+ friend bool operator==(const char *first, const ValueBase &second) { return second == first; }
+
+ friend bool operator==(const ValueBase &first, const ValueBase &second)
+ {
+ return first.value == second.value;
+ }
+
+ friend bool operator!=(const ValueBase &first, const ValueBase &second)
+ {
+ return !(first.value == second.value);
+ }
+
+ ValueType type() const
+ {
+ switch (value.index()) {
+ case 0:
+ return ValueType::Integer;
+ case 1:
+ return ValueType::Float;
+ case 2:
+ return ValueType::String;
+ }
+
+ return {};
+ }
+
+public:
+ VariantType value;
+};
+
+class ValueView : public ValueBase<Utils::SmallStringView>
+{
+public:
+ explicit ValueView(ValueBase &&base)
+ : ValueBase(std::move(base))
+ {}
+
+ template<typename Type>
+ static ValueView create(Type &&value)
+ {
+ return ValueView{ValueBase{value}};
+ }
+};
+
+class Value : public ValueBase<Utils::SmallString>
+{
+ using Base = ValueBase<Utils::SmallString>;
+
+public:
+ using Base::Base;
+
+ explicit Value(ValueView view)
+ : ValueBase(convert(view))
+ {}
+
+ explicit Value(const QVariant &value)
+ : ValueBase(convert(value))
+ {}
+
+ explicit Value(Utils::SmallString &&value)
+ : ValueBase(VariantType{std::move(value)})
+ {}
+
+ explicit Value(const Utils::SmallString &value)
+ : ValueBase(Utils::SmallStringView(value))
+ {}
+
+ explicit Value(const QString &value)
+ : ValueBase(VariantType{Utils::SmallString(value)})
+ {}
+
+ friend bool operator!=(const Value &first, const Value &second)
+ {
+ return !(first.value == second.value);
+ }
+
+ template<typename Type>
+ friend bool operator!=(const Value &first, const Type &second)
+ {
+ return !(first == second);
+ }
+
+ template<typename Type>
+ friend bool operator!=(const Type &first, const Value &second)
+ {
+ return !(first == second);
+ }
+
+ friend bool operator==(const Value &first, const ValueView &second)
+ {
+ if (first.type() != second.type())
+ return false;
+
+ switch (first.type()) {
+ case ValueType::Integer:
+ return first.toInteger() == second.toInteger();
+ case ValueType::Float:
+ return first.toFloat() == second.toFloat();
+ case ValueType::String:
+ return first.toStringView() == second.toStringView();
+ }
+
+ return false;
+ }
+
+ friend bool operator==(const ValueView &first, const Value &second) { return second == first; }
+
+private:
+ static Base::VariantType convert(const QVariant &value)
+ {
+ switch (value.type()) {
+ case QVariant::Int:
+ return VariantType{static_cast<long long>(value.toInt())};
+ case QVariant::LongLong:
+ return VariantType{value.toLongLong()};
+ case QVariant::UInt:
+ return VariantType{static_cast<long long>(value.toUInt())};
+ case QVariant::Double:
+ return VariantType{value.toFloat()};
+ case QVariant::String:
+ return VariantType{value.toString()};
+ default:
+ throw CannotConvert("Cannot convert this QVariant to a ValueBase");
+ }
+ }
+
+ static Base::VariantType convert(ValueView view)
+ {
+ switch (view.type()) {
+ case ValueType::Integer:
+ return VariantType{view.toInteger()};
+ case ValueType::Float:
+ return VariantType{view.toFloat()};
+ case ValueType::String:
+ return VariantType{view.toStringView()};
+ default:
+ throw CannotConvert("Cannot convert this QVariant to a ValueBase");
+ }
+ }
+};
+
+using Values = std::vector<Value>;
+} // namespace Sqlite
diff --git a/src/libs/ssh/sshprocess.cpp b/src/libs/ssh/sshprocess.cpp
index c17a6cbfb8..d29b196beb 100644
--- a/src/libs/ssh/sshprocess.cpp
+++ b/src/libs/ssh/sshprocess.cpp
@@ -47,6 +47,12 @@ SshProcess::SshProcess()
env.set("DISPLAY", ":0");
}
setProcessEnvironment(env.toProcessEnvironment());
+
+#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) && defined(Q_OS_UNIX)
+ setChildProcessModifier([]() {
+ setsid(); // Otherwise, ssh will ignore SSH_ASKPASS and read from /dev/tty directly.
+ });
+#endif
}
SshProcess::~SshProcess()
@@ -62,11 +68,13 @@ SshProcess::~SshProcess()
waitForFinished(1000);
}
+#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
void SshProcess::setupChildProcess()
{
#ifdef Q_OS_UNIX
setsid(); // Otherwise, ssh will ignore SSH_ASKPASS and read from /dev/tty directly.
#endif
}
+#endif
} // namespace QSsh
diff --git a/src/libs/ssh/sshprocess.h b/src/libs/ssh/sshprocess.h
index af20bd71cd..123cb31842 100644
--- a/src/libs/ssh/sshprocess.h
+++ b/src/libs/ssh/sshprocess.h
@@ -38,7 +38,9 @@ public:
~SshProcess() override;
private:
+#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
void setupChildProcess() override;
+#endif
};
} // namespace QSsh
diff --git a/src/libs/utils/CMakeLists.txt b/src/libs/utils/CMakeLists.txt
index ff7bbe6286..ee001a311d 100644
--- a/src/libs/utils/CMakeLists.txt
+++ b/src/libs/utils/CMakeLists.txt
@@ -96,6 +96,7 @@ add_qtc_library(Utils
osspecificaspects.h
outputformat.h
outputformatter.cpp outputformatter.h
+ overlaywidget.cpp overlaywidget.h
overridecursor.cpp overridecursor.h
parameteraction.cpp parameteraction.h
pathchooser.cpp pathchooser.h
@@ -166,7 +167,7 @@ add_qtc_library(Utils
wizardpage.cpp wizardpage.h
)
-extend_qtc_target(Utils CONDITION WIN32
+extend_qtc_library(Utils CONDITION WIN32
SOURCES
process_ctrlc_stub.cpp
touchbar/touchbar.cpp
@@ -178,7 +179,7 @@ extend_qtc_target(Utils CONDITION WIN32
_CRT_SECURE_NO_WARNINGS _SCL_SECURE_NO_WARNINGS
)
-extend_qtc_target(Utils CONDITION APPLE
+extend_qtc_library(Utils CONDITION APPLE
SOURCES
fileutils_mac.mm fileutils_mac.h
processhandle_mac.mm
@@ -189,7 +190,7 @@ extend_qtc_target(Utils CONDITION APPLE
${FWFoundation} ${FWAppKit}
)
-extend_qtc_target(Utils CONDITION UNIX AND NOT APPLE
+extend_qtc_library(Utils CONDITION UNIX AND NOT APPLE
SOURCES
touchbar/touchbar.cpp
)
diff --git a/src/libs/utils/ansiescapecodehandler.cpp b/src/libs/utils/ansiescapecodehandler.cpp
index 24f66af0d7..510eb03f73 100644
--- a/src/libs/utils/ansiescapecodehandler.cpp
+++ b/src/libs/utils/ansiescapecodehandler.cpp
@@ -93,6 +93,24 @@ QList<FormattedText> AnsiEscapeCodeHandler::parseText(const FormattedText &input
while (!strippedText.isEmpty()) {
QTC_ASSERT(m_pendingText.isEmpty(), break);
+ if (m_waitingForTerminator) {
+ // We ignore all escape codes taking string arguments.
+ QString terminator = "\x1b\\";
+ int terminatorPos = strippedText.indexOf(terminator);
+ if (terminatorPos == -1 && !m_alternateTerminator.isEmpty()) {
+ terminator = m_alternateTerminator;
+ terminatorPos = strippedText.indexOf(terminator);
+ }
+ if (terminatorPos == -1) {
+ m_pendingText = strippedText;
+ break;
+ }
+ m_waitingForTerminator = false;
+ m_alternateTerminator.clear();
+ strippedText.remove(0, terminatorPos + terminator.length());
+ if (strippedText.isEmpty())
+ break;
+ }
const int escapePos = strippedText.indexOf(escape.at(0));
if (escapePos < 0) {
outputData << FormattedText(strippedText, charFormat);
@@ -111,11 +129,28 @@ QList<FormattedText> AnsiEscapeCodeHandler::parseText(const FormattedText &input
break;
}
if (!strippedText.startsWith(escape)) {
- // not a control sequence
- m_pendingText.clear();
- outputData << FormattedText(strippedText.left(1), charFormat);
- strippedText.remove(0, 1);
- continue;
+ switch (strippedText.at(1).toLatin1()) {
+ case '\\': // Unexpected terminator sequence.
+ QTC_CHECK(false);
+ Q_FALLTHROUGH();
+ case 'N': case 'O': // Ignore unsupported single-character sequences.
+ strippedText.remove(0, 2);
+ break;
+ case ']':
+ m_alternateTerminator = QChar(7);
+ Q_FALLTHROUGH();
+ case 'P': case 'X': case '^': case '_':
+ strippedText.remove(0, 2);
+ m_waitingForTerminator = true;
+ break;
+ default:
+ // not a control sequence
+ m_pendingText.clear();
+ outputData << FormattedText(strippedText.left(1), charFormat);
+ strippedText.remove(0, 1);
+ continue;
+ }
+ break;
}
m_pendingText += strippedText.midRef(0, escape.length());
strippedText.remove(0, escape.length());
diff --git a/src/libs/utils/ansiescapecodehandler.h b/src/libs/utils/ansiescapecodehandler.h
index dec9cd39af..4870d59337 100644
--- a/src/libs/utils/ansiescapecodehandler.h
+++ b/src/libs/utils/ansiescapecodehandler.h
@@ -53,6 +53,8 @@ private:
void setFormatScope(const QTextCharFormat &charFormat);
bool m_previousFormatClosed = true;
+ bool m_waitingForTerminator = false;
+ QString m_alternateTerminator;
QTextCharFormat m_previousFormat;
QString m_pendingText;
};
diff --git a/src/libs/utils/categorysortfiltermodel.cpp b/src/libs/utils/categorysortfiltermodel.cpp
index ab1769f8bd..c53216dabf 100644
--- a/src/libs/utils/categorysortfiltermodel.cpp
+++ b/src/libs/utils/categorysortfiltermodel.cpp
@@ -25,6 +25,8 @@
#include "categorysortfiltermodel.h"
+#include <QRegularExpression>
+
namespace Utils {
CategorySortFilterModel::CategorySortFilterModel(QObject *parent)
@@ -37,9 +39,9 @@ bool CategorySortFilterModel::filterAcceptsRow(int source_row,
{
if (!source_parent.isValid()) {
// category items should be visible if any of its children match
- const QRegExp &regexp = filterRegExp();
+ const QRegularExpression &regexp = filterRegularExpression();
const QModelIndex &categoryIndex = sourceModel()->index(source_row, 0, source_parent);
- if (regexp.indexIn(sourceModel()->data(categoryIndex, filterRole()).toString()) != -1)
+ if (regexp.match(sourceModel()->data(categoryIndex, filterRole()).toString()).hasMatch())
return true;
const int rowCount = sourceModel()->rowCount(categoryIndex);
for (int row = 0; row < rowCount; ++row) {
diff --git a/src/libs/utils/checkablemessagebox.cpp b/src/libs/utils/checkablemessagebox.cpp
index 0cded34acd..b2109ccbb7 100644
--- a/src/libs/utils/checkablemessagebox.cpp
+++ b/src/libs/utils/checkablemessagebox.cpp
@@ -33,6 +33,7 @@
#include <QPushButton>
#include <QSettings>
#include <QStyle>
+#include <QTextEdit>
/*!
\class Utils::CheckableMessageBox
@@ -73,15 +74,23 @@ public:
messageLabel->setOpenExternalLinks(true);
messageLabel->setTextInteractionFlags(Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse);
messageLabel->setFocusPolicy(Qt::NoFocus);
-
- auto checkBoxRightSpacer =
- new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Minimum);
- auto buttonSpacer =
- new QSpacerItem(0, 1, QSizePolicy::Minimum, QSizePolicy::Minimum);
+ messageLabel->setAlignment(Qt::AlignLeft | Qt::AlignTop);
checkBox = new QCheckBox(q);
checkBox->setText(CheckableMessageBox::tr("Do not ask again"));
+ const QString showText = CheckableMessageBox::tr("Show Details...");
+ detailsButton = new QPushButton(showText, q);
+ detailsButton->setAutoDefault(false);
+ detailsButton->hide();
+ detailsText = new QTextEdit(q);
+ detailsText->hide();
+ QObject::connect(detailsButton, &QPushButton::clicked, detailsText, [this, showText] {
+ detailsText->setVisible(!detailsText->isVisible());
+ detailsButton->setText(
+ detailsText->isVisible() ? CheckableMessageBox::tr("Hide Details...") : showText);
+ });
+
buttonBox = new QDialogButtonBox(q);
buttonBox->setOrientation(Qt::Horizontal);
buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
@@ -92,16 +101,22 @@ public:
auto horizontalLayout_2 = new QHBoxLayout();
horizontalLayout_2->addLayout(verticalLayout);
- horizontalLayout_2->addWidget(messageLabel);
+ horizontalLayout_2->addWidget(messageLabel, 10);
auto horizontalLayout = new QHBoxLayout();
horizontalLayout->addWidget(checkBox);
- horizontalLayout->addItem(checkBoxRightSpacer);
+ horizontalLayout->addStretch(10);
+
+ auto detailsButtonLayout = new QHBoxLayout;
+ detailsButtonLayout->addWidget(detailsButton);
+ detailsButtonLayout->addStretch(10);
auto verticalLayout_2 = new QVBoxLayout(q);
verticalLayout_2->addLayout(horizontalLayout_2);
verticalLayout_2->addLayout(horizontalLayout);
- verticalLayout_2->addItem(buttonSpacer);
+ verticalLayout_2->addLayout(detailsButtonLayout);
+ verticalLayout_2->addWidget(detailsText, 10);
+ verticalLayout_2->addStretch(1);
verticalLayout_2->addWidget(buttonBox);
}
@@ -110,6 +125,8 @@ public:
QCheckBox *checkBox = nullptr;
QDialogButtonBox *buttonBox = nullptr;
QAbstractButton *clickedButton = nullptr;
+ QPushButton *detailsButton = nullptr;
+ QTextEdit *detailsText = nullptr;
QMessageBox::Icon icon = QMessageBox::NoIcon;
};
@@ -230,6 +247,18 @@ void CheckableMessageBox::setCheckBoxVisible(bool v)
d->checkBox->setVisible(v);
}
+QString CheckableMessageBox::detailedText() const
+{
+ return d->detailsText->toPlainText();
+}
+
+void CheckableMessageBox::setDetailedText(const QString &text)
+{
+ d->detailsText->setText(text);
+ if (!text.isEmpty())
+ d->detailsButton->setVisible(true);
+}
+
QDialogButtonBox::StandardButtons CheckableMessageBox::standardButtons() const
{
return d->buttonBox->standardButtons();
diff --git a/src/libs/utils/checkablemessagebox.h b/src/libs/utils/checkablemessagebox.h
index 042e88aa96..7f16449da7 100644
--- a/src/libs/utils/checkablemessagebox.h
+++ b/src/libs/utils/checkablemessagebox.h
@@ -101,6 +101,9 @@ public:
bool isCheckBoxVisible() const;
void setCheckBoxVisible(bool);
+ QString detailedText() const;
+ void setDetailedText(const QString &text);
+
QDialogButtonBox::StandardButtons standardButtons() const;
void setStandardButtons(QDialogButtonBox::StandardButtons s);
QPushButton *button(QDialogButtonBox::StandardButton b) const;
diff --git a/src/libs/utils/consoleprocess.cpp b/src/libs/utils/consoleprocess.cpp
index f4cde33a87..3095c5ee9d 100644
--- a/src/libs/utils/consoleprocess.cpp
+++ b/src/libs/utils/consoleprocess.cpp
@@ -136,6 +136,11 @@ void ConsoleProcess::setCommand(const CommandLine &command)
d->m_commandLine = command;
}
+CommandLine ConsoleProcess::command() const
+{
+ return d->m_commandLine;
+}
+
void ConsoleProcess::setSettings(QSettings *settings)
{
d->m_settings = settings;
diff --git a/src/libs/utils/consoleprocess.h b/src/libs/utils/consoleprocess.h
index af1ce1017c..6af30c1f84 100644
--- a/src/libs/utils/consoleprocess.h
+++ b/src/libs/utils/consoleprocess.h
@@ -65,6 +65,7 @@ public:
~ConsoleProcess() override;
void setCommand(const Utils::CommandLine &command);
+ Utils::CommandLine command() const;
void setAbortOnMetaChars(bool abort);
void setWorkingDirectory(const QString &dir);
diff --git a/src/libs/utils/delegates.cpp b/src/libs/utils/delegates.cpp
index 1eb281e3af..240b20fe0c 100644
--- a/src/libs/utils/delegates.cpp
+++ b/src/libs/utils/delegates.cpp
@@ -162,7 +162,7 @@ void PathChooserDelegate::setModelData(QWidget *editor, QAbstractItemModel *mode
if (!pathChooser)
return;
- model->setData(index, pathChooser->path(), Qt::EditRole);
+ model->setData(index, pathChooser->filePath().toString(), Qt::EditRole);
}
void PathChooserDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
diff --git a/src/libs/utils/environmentdialog.cpp b/src/libs/utils/environmentdialog.cpp
index 88311854ec..123a571646 100644
--- a/src/libs/utils/environmentdialog.cpp
+++ b/src/libs/utils/environmentdialog.cpp
@@ -48,7 +48,7 @@ Utils::optional<EnvironmentItems> EnvironmentDialog::getEnvironmentItems(
"To set or change a variable, use VARIABLE=VALUE.\n"
"Existing variables can be referenced in a VALUE with ${OTHER}.\n"
"To clear a variable, put its name on a line with nothing else on it.\n"
- "To disable a variable, prefix the line with \"#\""));
+ "To disable a variable, prefix the line with \"#\"."));
}
} // namespace Utils
diff --git a/src/libs/utils/fileutils.cpp b/src/libs/utils/fileutils.cpp
index 5901a60803..980ee4c0d6 100644
--- a/src/libs/utils/fileutils.cpp
+++ b/src/libs/utils/fileutils.cpp
@@ -163,7 +163,7 @@ bool FileUtils::removeRecursively(const FilePath &filePath, QString *error)
QStringList fileNames = dir.entryList(QDir::Files | QDir::Hidden
| QDir::System | QDir::Dirs | QDir::NoDotAndDotDot);
foreach (const QString &fileName, fileNames) {
- if (!removeRecursively(filePath.pathAppended(fileName), error))
+ if (!removeRecursively(filePath / fileName, error))
return false;
}
if (!QDir::root().rmdir(dir.path())) {
@@ -222,8 +222,8 @@ bool FileUtils::copyRecursively(const FilePath &srcFilePath, const FilePath &tgt
QStringList fileNames = sourceDir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot
| QDir::Hidden | QDir::System);
foreach (const QString &fileName, fileNames) {
- const FilePath newSrcFilePath = srcFilePath.pathAppended(fileName);
- const FilePath newTgtFilePath = tgtFilePath.pathAppended(fileName);
+ const FilePath newSrcFilePath = srcFilePath / fileName;
+ const FilePath newTgtFilePath = tgtFilePath / fileName;
if (!copyRecursively(newSrcFilePath, newTgtFilePath, error, copyHelper))
return false;
}
@@ -304,6 +304,11 @@ FilePath FilePath::canonicalPath() const
return FilePath::fromString(result);
}
+FilePath FilePath::operator/(const QString &str) const
+{
+ return pathAppended(str);
+}
+
/*!
Like QDir::toNativeSeparators(), but use prefix '~' instead of $HOME on unix systems when an
absolute path is given.
diff --git a/src/libs/utils/fileutils.h b/src/libs/utils/fileutils.h
index 7438a19e17..4a5e3fa8bb 100644
--- a/src/libs/utils/fileutils.h
+++ b/src/libs/utils/fileutils.h
@@ -111,6 +111,8 @@ public:
FilePath canonicalPath() const;
+ FilePath operator/(const QString &str) const;
+
void clear() { m_data.clear(); }
bool isEmpty() const { return m_data.isEmpty(); }
diff --git a/src/libs/utils/filewizardpage.cpp b/src/libs/utils/filewizardpage.cpp
index cd9f3b345b..d280cf2dbb 100644
--- a/src/libs/utils/filewizardpage.cpp
+++ b/src/libs/utils/filewizardpage.cpp
@@ -82,7 +82,7 @@ QString FileWizardPage::fileName() const
QString FileWizardPage::path() const
{
- return d->m_ui.pathChooser->path();
+ return d->m_ui.pathChooser->filePath().toString();
}
void FileWizardPage::setPath(const QString &path)
@@ -110,6 +110,19 @@ void FileWizardPage::setPathLabel(const QString &label)
d->m_ui.pathLabel->setText(label);
}
+void FileWizardPage::setDefaultSuffix(const QString &suffix)
+{
+ if (suffix.isEmpty()) {
+ const auto layout = qobject_cast<QFormLayout *>(this->layout());
+ if (layout->rowCount() == 3)
+ layout->removeRow(0);
+ } else {
+ d->m_ui.defaultSuffixLabel->setText(
+ tr("The default suffix if you do not explicitly specify a file extension is \".%1\".")
+ .arg(suffix));
+ }
+}
+
bool FileWizardPage::forceFirstCapitalLetterForFileName() const
{
return d->m_ui.nameLineEdit->forceFirstCapitalLetter();
diff --git a/src/libs/utils/filewizardpage.h b/src/libs/utils/filewizardpage.h
index ede6c4d3ab..0ce3287bef 100644
--- a/src/libs/utils/filewizardpage.h
+++ b/src/libs/utils/filewizardpage.h
@@ -50,6 +50,7 @@ public:
void setFileNameLabel(const QString &label);
void setPathLabel(const QString &label);
+ void setDefaultSuffix(const QString &suffix);
bool forceFirstCapitalLetterForFileName() const;
void setForceFirstCapitalLetterForFileName(bool b);
diff --git a/src/libs/utils/filewizardpage.ui b/src/libs/utils/filewizardpage.ui
index e8b3ca1b4b..9d3f09abe4 100644
--- a/src/libs/utils/filewizardpage.ui
+++ b/src/libs/utils/filewizardpage.ui
@@ -6,34 +6,41 @@
<rect>
<x>0</x>
<y>0</y>
- <width>196</width>
- <height>68</height>
+ <width>368</width>
+ <height>102</height>
</rect>
</property>
<property name="title">
<string>Choose the Location</string>
</property>
<layout class="QFormLayout" name="formLayout">
- <item row="0" column="0">
+ <item row="1" column="0">
<widget class="QLabel" name="nameLabel">
<property name="text">
- <string>Name:</string>
+ <string>File name:</string>
</property>
</widget>
</item>
- <item row="0" column="1">
+ <item row="1" column="1">
<widget class="Utils::FileNameValidatingLineEdit" name="nameLineEdit"/>
</item>
- <item row="1" column="0">
+ <item row="3" column="0">
<widget class="QLabel" name="pathLabel">
<property name="text">
<string>Path:</string>
</property>
</widget>
</item>
- <item row="1" column="1">
+ <item row="3" column="1">
<widget class="Utils::PathChooser" name="pathChooser" native="true"/>
</item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="defaultSuffixLabel">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
</layout>
</widget>
<customwidgets>
diff --git a/src/libs/utils/listmodel.h b/src/libs/utils/listmodel.h
index 4a28041b66..3497b84bcb 100644
--- a/src/libs/utils/listmodel.h
+++ b/src/libs/utils/listmodel.h
@@ -120,7 +120,29 @@ public:
return item ? &item->itemData : nullptr;
}
- void forItems(const std::function<void(ItemData &)> &func) const
+ QModelIndex findIndex(const std::function<bool(const ItemData &)> &pred) const
+ {
+ ChildType *item = findItemByData(pred);
+ return item ? BaseTreeModel::indexForItem(item) : QModelIndex();
+ }
+
+ QList<ItemData> allData() const
+ {
+ QList<ItemData> res;
+ BaseModel::rootItem()->forFirstLevelChildren([&res](ChildType *child) {
+ res.append(child->itemData);
+ });
+ return res;
+ }
+
+ void setAllData(const QList<ItemData> &items)
+ {
+ BaseModel::rootItem()->removeChildren();
+ for (const ItemData &data : items)
+ appendItem(data);
+ }
+
+ void forAllData(const std::function<void(ItemData &)> &func) const
{
BaseModel::rootItem()->forFirstLevelChildren([func](ChildType *child) {
func(child->itemData);
@@ -151,6 +173,7 @@ public:
return {};
}
+ using QAbstractItemModel::itemData;
virtual QVariant itemData(const ItemData &idata, int column, int role) const
{
if (m_dataAccessor)
diff --git a/src/libs/utils/outputformat.h b/src/libs/utils/outputformat.h
index 12b14d5b80..1e959d05d4 100644
--- a/src/libs/utils/outputformat.h
+++ b/src/libs/utils/outputformat.h
@@ -35,8 +35,6 @@ enum OutputFormat
DebugFormat,
StdOutFormat,
StdErrFormat,
- StdOutFormatSameLine,
- StdErrFormatSameLine,
NumberOfFormats // Keep this entry last.
};
diff --git a/src/libs/utils/outputformatter.cpp b/src/libs/utils/outputformatter.cpp
index ad077755ca..7d8ac409ed 100644
--- a/src/libs/utils/outputformatter.cpp
+++ b/src/libs/utils/outputformatter.cpp
@@ -23,36 +23,211 @@
**
****************************************************************************/
-#include "ansiescapecodehandler.h"
#include "outputformatter.h"
+
+#include "algorithm.h"
+#include "ansiescapecodehandler.h"
+#include "fileinprojectfinder.h"
+#include "qtcassert.h"
+#include "synchronousprocess.h"
#include "theme/theme.h"
+#include <QDir>
+#include <QFileInfo>
+#include <QPair>
#include <QPlainTextEdit>
+#include <QPointer>
+#include <QRegExp>
+#include <QRegularExpressionMatch>
#include <QTextCursor>
+#include <numeric>
+
namespace Utils {
-namespace Internal {
+class OutputLineParser::Private
+{
+public:
+ FilePaths searchDirs;
+ QPointer<const OutputLineParser> redirectionDetector;
+ bool skipFileExistsCheck = false;
+ bool demoteErrorsToWarnings = false;
+ FileInProjectFinder *fileFinder = nullptr;
+};
+
+OutputLineParser::OutputLineParser() : d(new Private) { }
+
+OutputLineParser::~OutputLineParser() { delete d; }
+
+Q_GLOBAL_STATIC_WITH_ARGS(QString, linkPrefix, {"olpfile://"})
+Q_GLOBAL_STATIC_WITH_ARGS(QString, linkSep, {"::"})
+
+QString OutputLineParser::createLinkTarget(const FilePath &filePath, int line = -1, int column = -1)
+{
+ return *linkPrefix() + filePath.toString() + *linkSep() + QString::number(line)
+ + *linkSep() + QString::number(column);
+}
+
+bool OutputLineParser::isLinkTarget(const QString &target)
+{
+ return target.startsWith(*linkPrefix());
+}
+
+void OutputLineParser::parseLinkTarget(const QString &target, FilePath &filePath, int &line,
+ int &column)
+{
+ const QStringList parts = target.mid(linkPrefix()->length()).split(*linkSep());
+ if (parts.isEmpty())
+ return;
+ filePath = FilePath::fromString(parts.first());
+ line = parts.length() > 1 ? parts.at(1).toInt() : 0;
+ column = parts.length() > 2 ? parts.at(2).toInt() : 0;
+}
+
+// The redirection mechanism is needed for broken build tools (e.g. xcodebuild) that get invoked
+// indirectly as part of the build process and redirect their child processes' stderr output
+// to stdout. A parser might be able to detect this condition and inform interested
+// other parsers that they need to interpret stdout data as stderr.
+void OutputLineParser::setRedirectionDetector(const OutputLineParser *detector)
+{
+ d->redirectionDetector = detector;
+}
+
+bool OutputLineParser::needsRedirection() const
+{
+ return d->redirectionDetector && (d->redirectionDetector->hasDetectedRedirection()
+ || d->redirectionDetector->needsRedirection());
+}
+
+void OutputLineParser::addSearchDir(const FilePath &dir)
+{
+ d->searchDirs << dir;
+}
+
+void OutputLineParser::dropSearchDir(const FilePath &dir)
+{
+ const int idx = d->searchDirs.lastIndexOf(dir);
+
+ // TODO: This apparently triggers. Find out why and either remove the assertion (if it's legit)
+ // or fix the culprit.
+ QTC_ASSERT(idx != -1, return);
+
+ d->searchDirs.removeAt(idx);
+}
+
+const FilePaths OutputLineParser::searchDirectories() const
+{
+ return d->searchDirs;
+}
+
+void OutputLineParser::setFileFinder(FileInProjectFinder *finder)
+{
+ d->fileFinder = finder;
+}
+
+void OutputLineParser::setDemoteErrorsToWarnings(bool demote)
+{
+ d->demoteErrorsToWarnings = demote;
+}
+
+bool OutputLineParser::demoteErrorsToWarnings() const
+{
+ return d->demoteErrorsToWarnings;
+}
-class OutputFormatterPrivate
+FilePath OutputLineParser::absoluteFilePath(const FilePath &filePath)
+{
+ if (filePath.isEmpty() || filePath.toFileInfo().isAbsolute())
+ return filePath;
+ FilePaths candidates;
+ for (const FilePath &dir : searchDirectories()) {
+ const FilePath candidate = dir.pathAppended(filePath.toString());
+ if (candidate.exists() || d->skipFileExistsCheck)
+ candidates << candidate;
+ }
+ if (candidates.count() == 1)
+ return FilePath::fromString(QDir::cleanPath(candidates.first().toString()));
+
+ QString fp = filePath.toString();
+ while (fp.startsWith("../"))
+ fp.remove(0, 3);
+ bool found = false;
+ candidates = d->fileFinder->findFile(QUrl::fromLocalFile(fp), &found);
+ if (found && candidates.size() == 1)
+ return candidates.first();
+
+ return filePath;
+}
+
+void OutputLineParser::addLinkSpecForAbsoluteFilePath(OutputLineParser::LinkSpecs &linkSpecs,
+ const FilePath &filePath, int lineNo, int pos, int len)
+{
+ if (filePath.toFileInfo().isAbsolute())
+ linkSpecs.append({pos, len, createLinkTarget(filePath, lineNo)});
+}
+
+void OutputLineParser::addLinkSpecForAbsoluteFilePath(OutputLineParser::LinkSpecs &linkSpecs,
+ const FilePath &filePath, int lineNo, const QRegExp &regex, int capIndex)
+{
+ addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, lineNo, regex.pos(capIndex),
+ regex.cap(capIndex).length());
+}
+
+void OutputLineParser::addLinkSpecForAbsoluteFilePath(OutputLineParser::LinkSpecs &linkSpecs,
+ const FilePath &filePath, int lineNo, const QRegularExpressionMatch &match,
+ int capIndex)
+{
+ addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, lineNo, match.capturedStart(capIndex),
+ match.capturedLength(capIndex));
+}
+void OutputLineParser::addLinkSpecForAbsoluteFilePath(OutputLineParser::LinkSpecs &linkSpecs,
+ const FilePath &filePath, int lineNo, const QRegularExpressionMatch &match,
+ const QString &capName)
+{
+ addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, lineNo, match.capturedStart(capName),
+ match.capturedLength(capName));
+}
+
+QString OutputLineParser::rightTrimmed(const QString &in)
+{
+ int pos = in.length();
+ for (; pos > 0; --pos) {
+ if (!in.at(pos - 1).isSpace())
+ break;
+ }
+ return in.mid(0, pos);
+}
+
+#ifdef WITH_TESTS
+void OutputLineParser::skipFileExistsCheck()
+{
+ d->skipFileExistsCheck = true;
+}
+#endif
+
+
+class OutputFormatter::Private
{
public:
QPlainTextEdit *plainTextEdit = nullptr;
QTextCharFormat formats[NumberOfFormats];
QTextCursor cursor;
AnsiEscapeCodeHandler escapeCodeHandler;
+ QPair<QString, OutputFormat> incompleteLine;
+ optional<QTextCharFormat> formatOverride;
+ QList<OutputLineParser *> lineParsers;
+ OutputLineParser *nextParser = nullptr;
+ FileInProjectFinder fileFinder;
+ PostPrintAction postPrintAction;
bool boldFontEnabled = true;
+ bool prependCarriageReturn = false;
};
-} // namespace Internal
-
-OutputFormatter::OutputFormatter()
- : d(new Internal::OutputFormatterPrivate)
-{
-}
+OutputFormatter::OutputFormatter() : d(new Private) { }
OutputFormatter::~OutputFormatter()
{
+ qDeleteAll(d->lineParsers);
delete d;
}
@@ -69,23 +244,118 @@ void OutputFormatter::setPlainTextEdit(QPlainTextEdit *plainText)
initFormats();
}
-void OutputFormatter::appendMessage(const QString &text, OutputFormat format)
+void OutputFormatter::setLineParsers(const QList<OutputLineParser *> &parsers)
{
- if (!d->cursor.atEnd() && text.startsWith('\n'))
- d->cursor.movePosition(QTextCursor::End);
- appendMessage(text, d->formats[format]);
+ flush();
+ qDeleteAll(d->lineParsers);
+ d->lineParsers.clear();
+ d->nextParser = nullptr;
+ addLineParsers(parsers);
+}
+
+void OutputFormatter::addLineParsers(const QList<OutputLineParser *> &parsers)
+{
+ for (OutputLineParser * const p : qAsConst(parsers))
+ addLineParser(p);
+}
+
+void OutputFormatter::addLineParser(OutputLineParser *parser)
+{
+ setupLineParser(parser);
+ d->lineParsers << parser;
+}
+
+void OutputFormatter::setupLineParser(OutputLineParser *parser)
+{
+ parser->setFileFinder(&d->fileFinder);
+ connect(parser, &OutputLineParser::newSearchDir, this, &OutputFormatter::addSearchDir);
+ connect(parser, &OutputLineParser::searchDirExpired, this, &OutputFormatter::dropSearchDir);
+}
+
+void OutputFormatter::setFileFinder(const FileInProjectFinder &finder)
+{
+ d->fileFinder = finder;
+}
+
+void OutputFormatter::setDemoteErrorsToWarnings(bool demote)
+{
+ for (OutputLineParser * const p : qAsConst(d->lineParsers))
+ p->setDemoteErrorsToWarnings(demote);
}
-void OutputFormatter::appendMessage(const QString &text, const QTextCharFormat &format)
+void OutputFormatter::overridePostPrintAction(const PostPrintAction &postPrintAction)
{
- const QList<FormattedText> formattedTextList = parseAnsi(text, format);
- for (const FormattedText &output : formattedTextList)
+ d->postPrintAction = postPrintAction;
+}
+
+void OutputFormatter::doAppendMessage(const QString &text, OutputFormat format)
+{
+ const QTextCharFormat charFmt = charFormat(format);
+ const QList<FormattedText> formattedText = parseAnsi(text, charFmt);
+ const QString cleanLine = std::accumulate(formattedText.begin(), formattedText.end(), QString(),
+ [](const FormattedText &t1, const FormattedText &t2) { return t1.text + t2.text; });
+ QList<OutputLineParser *> involvedParsers;
+ const OutputLineParser::Result res = handleMessage(cleanLine, format, involvedParsers);
+ if (res.newContent) {
+ append(res.newContent.value(), charFmt);
+ return;
+ }
+ for (const FormattedText &output : linkifiedText(formattedText, res.linkSpecs))
append(output.text, output.format);
+ for (OutputLineParser * const p : qAsConst(involvedParsers)) {
+ if (d->postPrintAction)
+ d->postPrintAction(p);
+ else
+ p->runPostPrintActions();
+ }
+}
+
+OutputLineParser::Result OutputFormatter::handleMessage(const QString &text, OutputFormat format,
+ QList<OutputLineParser *> &involvedParsers)
+{
+ // We only invoke the line parsers for stdout and stderr
+ if (format != StdOutFormat && format != StdErrFormat)
+ return OutputLineParser::Status::NotHandled;
+ const OutputLineParser * const oldNextParser = d->nextParser;
+ if (d->nextParser) {
+ involvedParsers << d->nextParser;
+ const OutputLineParser::Result res
+ = d->nextParser->handleLine(text, outputTypeForParser(d->nextParser, format));
+ switch (res.status) {
+ case OutputLineParser::Status::Done:
+ d->nextParser = nullptr;
+ return res;
+ case OutputLineParser::Status::InProgress:
+ return res;
+ case OutputLineParser::Status::NotHandled:
+ d->nextParser = nullptr;
+ break;
+ }
+ }
+ QTC_CHECK(!d->nextParser);
+ for (OutputLineParser * const parser : qAsConst(d->lineParsers)) {
+ if (parser == oldNextParser) // We tried that one already.
+ continue;
+ const OutputLineParser::Result res
+ = parser->handleLine(text, outputTypeForParser(parser, format));
+ switch (res.status) {
+ case OutputLineParser::Status::Done:
+ involvedParsers << parser;
+ return res;
+ case OutputLineParser::Status::InProgress:
+ involvedParsers << parser;
+ d->nextParser = parser;
+ return res;
+ case OutputLineParser::Status::NotHandled:
+ break;
+ }
+ }
+ return OutputLineParser::Status::NotHandled;
}
QTextCharFormat OutputFormatter::charFormat(OutputFormat format) const
{
- return d->formats[format];
+ return d->formatOverride ? d->formatOverride.value() : d->formats[format];
}
QList<FormattedText> OutputFormatter::parseAnsi(const QString &text, const QTextCharFormat &format)
@@ -93,16 +363,67 @@ QList<FormattedText> OutputFormatter::parseAnsi(const QString &text, const QText
return d->escapeCodeHandler.parseText(FormattedText(text, format));
}
+const QList<FormattedText> OutputFormatter::linkifiedText(
+ const QList<FormattedText> &text, const OutputLineParser::LinkSpecs &linkSpecs)
+{
+ if (linkSpecs.isEmpty())
+ return text;
+
+ QList<FormattedText> linkified;
+ int totalTextLengthSoFar = 0;
+ int nextLinkSpecIndex = 0;
+
+ for (const FormattedText &t : text) {
+ const int totalPreviousTextLength = totalTextLengthSoFar;
+
+ // There is no more linkification work to be done. Just copy the text as-is.
+ if (nextLinkSpecIndex >= linkSpecs.size()) {
+ linkified << t;
+ continue;
+ }
+
+ for (int nextLocalTextPos = 0; nextLocalTextPos < t.text.size(); ) {
+
+ // There are no more links in this part, so copy the rest of the text as-is.
+ if (nextLinkSpecIndex >= linkSpecs.size()) {
+ linkified << FormattedText(t.text.mid(nextLocalTextPos), t.format);
+ totalTextLengthSoFar += t.text.length() - nextLocalTextPos;
+ break;
+ }
+
+ const OutputLineParser::LinkSpec &linkSpec = linkSpecs.at(nextLinkSpecIndex);
+ const int localLinkStartPos = linkSpec.startPos - totalPreviousTextLength;
+ ++nextLinkSpecIndex;
+
+ // We ignore links that would cross format boundaries.
+ if (localLinkStartPos < nextLocalTextPos
+ || localLinkStartPos + linkSpec.length > t.text.length()) {
+ linkified << FormattedText(t.text.mid(nextLocalTextPos), t.format);
+ totalTextLengthSoFar += t.text.length() - nextLocalTextPos;
+ break;
+ }
+
+ // Now we know we have a link that is fully inside this part of the text.
+ // Split the text so that the link part gets the appropriate format.
+ const int prefixLength = localLinkStartPos - nextLocalTextPos;
+ const QString textBeforeLink = t.text.mid(nextLocalTextPos, prefixLength);
+ linkified << FormattedText(textBeforeLink, t.format);
+ const QString linkedText = t.text.mid(localLinkStartPos, linkSpec.length);
+ linkified << FormattedText(linkedText, linkFormat(t.format, linkSpec.target));
+ nextLocalTextPos = localLinkStartPos + linkSpec.length;
+ totalTextLengthSoFar += prefixLength + linkSpec.length;
+ }
+ }
+ return linkified;
+}
+
void OutputFormatter::append(const QString &text, const QTextCharFormat &format)
{
+ if (!plainTextEdit())
+ return;
int startPos = 0;
int crPos = -1;
while ((crPos = text.indexOf('\r', startPos)) >= 0) {
- if (text.size() > crPos + 1 && text.at(crPos + 1) == '\n') {
- d->cursor.insertText(text.mid(startPos, crPos - startPos) + '\n', format);
- startPos = crPos + 2;
- continue;
- }
d->cursor.insertText(text.mid(startPos, crPos - startPos), format);
d->cursor.clearSelection();
d->cursor.movePosition(QTextCursor::StartOfBlock, QTextCursor::KeepAnchor);
@@ -122,8 +443,23 @@ QTextCharFormat OutputFormatter::linkFormat(const QTextCharFormat &inputFormat,
return result;
}
+#ifdef WITH_TESTS
+void OutputFormatter::overrideTextCharFormat(const QTextCharFormat &fmt)
+{
+ d->formatOverride = fmt;
+}
+
+QList<OutputLineParser *> OutputFormatter::lineParsers() const
+{
+ return d->lineParsers;
+}
+#endif // WITH_TESTS
+
void OutputFormatter::clearLastLine()
{
+ // Note that this approach will fail if the text edit is not read-only and users
+ // have messed with the last line between programmatic inputs.
+ // We live with this risk, as all the alternatives are worse.
if (!d->cursor.atEnd())
d->cursor.movePosition(QTextCursor::End);
d->cursor.movePosition(QTextCursor::StartOfBlock, QTextCursor::KeepAnchor);
@@ -136,32 +472,66 @@ void OutputFormatter::initFormats()
return;
Theme *theme = creatorTheme();
-
- // NormalMessageFormat
d->formats[NormalMessageFormat].setForeground(theme->color(Theme::OutputPanes_NormalMessageTextColor));
-
- // ErrorMessageFormat
d->formats[ErrorMessageFormat].setForeground(theme->color(Theme::OutputPanes_ErrorMessageTextColor));
-
- // LogMessageFormat
d->formats[LogMessageFormat].setForeground(theme->color(Theme::OutputPanes_WarningMessageTextColor));
-
- // StdOutFormat
d->formats[StdOutFormat].setForeground(theme->color(Theme::OutputPanes_StdOutTextColor));
- d->formats[StdOutFormatSameLine] = d->formats[StdOutFormat];
-
- // StdErrFormat
d->formats[StdErrFormat].setForeground(theme->color(Theme::OutputPanes_StdErrTextColor));
- d->formats[StdErrFormatSameLine] = d->formats[StdErrFormat];
-
d->formats[DebugFormat].setForeground(theme->color(Theme::OutputPanes_DebugTextColor));
-
setBoldFontEnabled(d->boldFontEnabled);
}
+void OutputFormatter::flushIncompleteLine()
+{
+ clearLastLine();
+ doAppendMessage(d->incompleteLine.first, d->incompleteLine.second);
+ d->incompleteLine.first.clear();
+}
+
+void OutputFormatter::dumpIncompleteLine(const QString &line, OutputFormat format)
+{
+ if (line.isEmpty())
+ return;
+ append(line, charFormat(format));
+ d->incompleteLine.first.append(line);
+ d->incompleteLine.second = format;
+}
+
void OutputFormatter::handleLink(const QString &href)
{
- Q_UNUSED(href)
+ // We can handle absolute file paths ourselves. Other types of references are forwarded
+ // to the line parsers.
+ if (OutputLineParser::isLinkTarget(href)) {
+ FilePath filePath;
+ int line;
+ int column;
+ OutputLineParser::parseLinkTarget(href, filePath, line, column);
+ QTC_ASSERT(!filePath.isEmpty(), return);
+ emit openInEditorRequested(filePath, line, column);
+ return;
+ }
+ for (OutputLineParser * const f : qAsConst(d->lineParsers)) {
+ if (f->handleLink(href))
+ return;
+ }
+}
+
+void OutputFormatter::clear()
+{
+ if (plainTextEdit())
+ plainTextEdit()->clear();
+}
+
+void OutputFormatter::reset()
+{
+ d->prependCarriageReturn = false;
+ d->incompleteLine.first.clear();
+ d->nextParser = nullptr;
+ qDeleteAll(d->lineParsers);
+ d->lineParsers.clear();
+ d->fileFinder = FileInProjectFinder();
+ d->formatOverride.reset();
+ d->escapeCodeHandler = AnsiEscapeCodeHandler();
}
void OutputFormatter::setBoldFontEnabled(bool enabled)
@@ -174,7 +544,92 @@ void OutputFormatter::setBoldFontEnabled(bool enabled)
void OutputFormatter::flush()
{
+ if (!d->incompleteLine.first.isEmpty())
+ flushIncompleteLine();
d->escapeCodeHandler.endFormatScope();
+ for (OutputLineParser * const p : qAsConst(d->lineParsers))
+ p->flush();
+ if (d->nextParser)
+ d->nextParser->runPostPrintActions();
+}
+
+bool OutputFormatter::hasFatalErrors() const
+{
+ return anyOf(d->lineParsers, [](const OutputLineParser *p) {
+ return p->hasFatalErrors();
+ });
+}
+
+void OutputFormatter::addSearchDir(const FilePath &dir)
+{
+ for (OutputLineParser * const p : qAsConst(d->lineParsers))
+ p->addSearchDir(dir);
+}
+
+void OutputFormatter::dropSearchDir(const FilePath &dir)
+{
+ for (OutputLineParser * const p : qAsConst(d->lineParsers))
+ p->dropSearchDir(dir);
+}
+
+OutputFormat OutputFormatter::outputTypeForParser(const OutputLineParser *parser,
+ OutputFormat type) const
+{
+ if (type == StdOutFormat && parser->needsRedirection())
+ return StdErrFormat;
+ return type;
+}
+
+void OutputFormatter::appendMessage(const QString &text, OutputFormat format)
+{
+ if (text.isEmpty())
+ return;
+
+ // If we have an existing incomplete line and its format is different from this one,
+ // then we consider the two messages unrelated. We re-insert the previous incomplete line,
+ // possibly formatted now, and start from scratch with the new input.
+ if (!d->incompleteLine.first.isEmpty() && d->incompleteLine.second != format)
+ flushIncompleteLine();
+
+ QString out = text;
+ if (d->prependCarriageReturn) {
+ d->prependCarriageReturn = false;
+ out.prepend('\r');
+ }
+ out = SynchronousProcess::normalizeNewlines(out);
+ if (out.endsWith('\r')) {
+ d->prependCarriageReturn = true;
+ out.chop(1);
+ }
+
+ // If the input is a single incomplete line, we do not forward it to the specialized
+ // formatting code, but simply dump it as-is. Once it becomes complete or it needs to
+ // be flushed for other reasons, we remove the unformatted part and re-insert it, this
+ // time with proper formatting.
+ if (!out.contains('\n')) {
+ dumpIncompleteLine(out, format);
+ return;
+ }
+
+ // We have at least one complete line, so let's remove the previously dumped
+ // incomplete line and prepend it to the first line of our new input.
+ if (!d->incompleteLine.first.isEmpty()) {
+ clearLastLine();
+ out.prepend(d->incompleteLine.first);
+ d->incompleteLine.first.clear();
+ }
+
+ // Forward all complete lines to the specialized formatting code, and handle a
+ // potential trailing incomplete line the same way as above.
+ for (int startPos = 0; ;) {
+ const int eolPos = out.indexOf('\n', startPos);
+ if (eolPos == -1) {
+ dumpIncompleteLine(out.mid(startPos), format);
+ break;
+ }
+ doAppendMessage(out.mid(startPos, eolPos - startPos + 1), format);
+ startPos = eolPos + 1;
+ }
}
} // namespace Utils
diff --git a/src/libs/utils/outputformatter.h b/src/libs/utils/outputformatter.h
index 5b7acb0337..d91f96fa13 100644
--- a/src/libs/utils/outputformatter.h
+++ b/src/libs/utils/outputformatter.h
@@ -26,56 +26,174 @@
#pragma once
#include "utils_global.h"
+#include "fileutils.h"
+#include "optional.h"
#include "outputformat.h"
#include <QObject>
-#include <QFont>
+
+#include <functional>
QT_BEGIN_NAMESPACE
class QPlainTextEdit;
+class QRegExp;
+class QRegularExpressionMatch;
class QTextCharFormat;
class QTextCursor;
QT_END_NAMESPACE
namespace Utils {
-
+class FileInProjectFinder;
class FormattedText;
-namespace Internal { class OutputFormatterPrivate; }
+class QTCREATOR_UTILS_EXPORT OutputLineParser : public QObject
+{
+ Q_OBJECT
+public:
+ OutputLineParser();
+ ~OutputLineParser() override;
+
+ enum class Status { Done, InProgress, NotHandled };
+ class LinkSpec {
+ public:
+ LinkSpec() = default;
+ LinkSpec(int sp, int l, const QString &t) : startPos(sp), length(l), target(t) {}
+ int startPos = -1;
+ int length = -1;
+ QString target;
+ };
+ using LinkSpecs = QList<LinkSpec>;
+ class Result {
+ public:
+ Result(Status s, const LinkSpecs &l = {}, const optional<QString> &c = {})
+ : status(s), linkSpecs(l), newContent(c) {}
+ Status status;
+ LinkSpecs linkSpecs;
+ optional<QString> newContent; // Hard content override. Only to be used in extreme cases.
+ };
+
+ static bool isLinkTarget(const QString &target);
+ static void parseLinkTarget(const QString &target, FilePath &filePath, int &line, int &column);
+
+ void addSearchDir(const Utils::FilePath &dir);
+ void dropSearchDir(const Utils::FilePath &dir);
+ const FilePaths searchDirectories() const;
+
+ void setFileFinder(Utils::FileInProjectFinder *finder);
+
+ void setDemoteErrorsToWarnings(bool demote);
+ bool demoteErrorsToWarnings() const;
+
+ // line contains at most one line feed character, and if it does occur, it's the last character.
+ // Either way, the input is to be considered "complete" for parsing purposes.
+ virtual Result handleLine(const QString &line, OutputFormat format) = 0;
+
+ virtual bool handleLink(const QString &href) { Q_UNUSED(href); return false; }
+ virtual bool hasFatalErrors() const { return false; }
+ virtual void flush() {}
+ virtual void runPostPrintActions() {}
+
+ void setRedirectionDetector(const OutputLineParser *detector);
+ bool needsRedirection() const;
+ virtual bool hasDetectedRedirection() const { return false; }
+
+#ifdef WITH_TESTS
+ void skipFileExistsCheck();
+#endif
+
+protected:
+ static QString rightTrimmed(const QString &in);
+ Utils::FilePath absoluteFilePath(const Utils::FilePath &filePath);
+ static QString createLinkTarget(const FilePath &filePath, int line, int column);
+ void addLinkSpecForAbsoluteFilePath(LinkSpecs &linkSpecs, const FilePath &filePath,
+ int lineNo, int pos, int len);
+ void addLinkSpecForAbsoluteFilePath(LinkSpecs &linkSpecs, const FilePath &filePath,
+ int lineNo, const QRegExp &regex, int capIndex);
+ void addLinkSpecForAbsoluteFilePath(LinkSpecs &linkSpecs, const FilePath &filePath,
+ int lineNo, const QRegularExpressionMatch &match,
+ int capIndex);
+ void addLinkSpecForAbsoluteFilePath(LinkSpecs &linkSpecs, const FilePath &filePath,
+ int lineNo, const QRegularExpressionMatch &match,
+ const QString &capName);
+
+signals:
+ void newSearchDir(const Utils::FilePath &dir);
+ void searchDirExpired(const Utils::FilePath &dir);
+
+private:
+ class Private;
+ Private * const d;
+};
class QTCREATOR_UTILS_EXPORT OutputFormatter : public QObject
{
Q_OBJECT
-
public:
OutputFormatter();
~OutputFormatter() override;
QPlainTextEdit *plainTextEdit() const;
- virtual void setPlainTextEdit(QPlainTextEdit *plainText);
+ void setPlainTextEdit(QPlainTextEdit *plainText);
+
+ // Forwards to line parsers. Add those before.
+ void addSearchDir(const FilePath &dir);
+ void dropSearchDir(const FilePath &dir);
+
+ void setLineParsers(const QList<OutputLineParser *> &parsers); // Takes ownership
+ void addLineParsers(const QList<OutputLineParser *> &parsers);
+ void addLineParser(OutputLineParser *parser);
+
+ void setFileFinder(const FileInProjectFinder &finder);
+ void setDemoteErrorsToWarnings(bool demote);
- void flush();
+ using PostPrintAction = std::function<void(OutputLineParser *)>;
+ void overridePostPrintAction(const PostPrintAction &postPrintAction);
- virtual void appendMessage(const QString &text, OutputFormat format);
- virtual void handleLink(const QString &href);
- virtual QList<QWidget *> toolbarWidgets() const { return {}; }
- virtual void clear() {}
+ void appendMessage(const QString &text, OutputFormat format);
+ void flush(); // Flushes in-flight data.
+ void clear(); // Clears the text edit, if there is one.
+ void reset(); // Wipes everything except the text edit.
+
+ void handleLink(const QString &href);
void setBoldFontEnabled(bool enabled);
+
+ bool hasFatalErrors() const;
+
+ static const QList<Utils::FormattedText> linkifiedText(const QList<FormattedText> &text,
+ const OutputLineParser::LinkSpecs &linkSpecs);
+
+#ifdef WITH_TESTS
+ void overrideTextCharFormat(const QTextCharFormat &fmt);
+ QList<OutputLineParser *> lineParsers() const;
+#endif
+
+#ifndef WITH_TESTS
+private:
+#endif
+ QTextCharFormat charFormat(OutputFormat format) const;
static QTextCharFormat linkFormat(const QTextCharFormat &inputFormat, const QString &href);
signals:
- void contentChanged();
+ void openInEditorRequested(const FilePath &filePath, int line, int column);
-protected:
+private:
+ void doAppendMessage(const QString &text, OutputFormat format);
+
+ OutputLineParser::Result handleMessage(const QString &text, OutputFormat format,
+ QList<OutputLineParser *> &involvedParsers);
+
+ void append(const QString &text, const QTextCharFormat &format);
void initFormats();
- virtual void clearLastLine();
- QTextCharFormat charFormat(OutputFormat format) const;
+ void flushIncompleteLine();
+ void dumpIncompleteLine(const QString &line, OutputFormat format);
+ void clearLastLine();
QList<FormattedText> parseAnsi(const QString &text, const QTextCharFormat &format);
- void append(const QString &text, const QTextCharFormat &format);
+ OutputFormat outputTypeForParser(const OutputLineParser *parser, OutputFormat type) const;
+ void setupLineParser(OutputLineParser *parser);
-private:
- virtual void appendMessage(const QString &text, const QTextCharFormat &format);
- Internal::OutputFormatterPrivate *d;
+ class Private;
+ Private * const d;
};
+
} // namespace Utils
diff --git a/src/plugins/boot2qt/qdbdeploystepfactory.cpp b/src/libs/utils/overlaywidget.cpp
index a39b3e5b86..d1a5f6e3d3 100644
--- a/src/plugins/boot2qt/qdbdeploystepfactory.cpp
+++ b/src/libs/utils/overlaywidget.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2019 The Qt Company Ltd.
+** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -23,34 +23,54 @@
**
****************************************************************************/
-#include "qdbdeploystepfactory.h"
+#include "overlaywidget.h"
-#include "qdbconstants.h"
-#include "qdbmakedefaultappstep.h"
-#include "qdbstopapplicationstep.h"
+#include "qtcassert.h"
-#include <projectexplorer/buildsteplist.h>
-#include <projectexplorer/projectexplorerconstants.h>
-#include <projectexplorer/target.h>
+#include <QEvent>
+#include <QPainter>
-namespace Qdb {
-namespace Internal {
+Utils::OverlayWidget::OverlayWidget(QWidget *parent)
+{
+ setAttribute(Qt::WA_TransparentForMouseEvents);
+ if (parent)
+ attachToWidget(parent);
+}
+
+void Utils::OverlayWidget::setPaintFunction(const Utils::OverlayWidget::PaintFunction &paint)
+{
+ m_paint = paint;
+}
-QdbMakeDefaultAppStepFactory::QdbMakeDefaultAppStepFactory()
+bool Utils::OverlayWidget::eventFilter(QObject *obj, QEvent *ev)
{
- registerStep<QdbMakeDefaultAppStep>(QdbMakeDefaultAppStep::stepId());
- setDisplayName(QdbMakeDefaultAppStep::stepDisplayName());
- setSupportedDeviceType(Constants::QdbLinuxOsType);
- setSupportedStepList(ProjectExplorer::Constants::BUILDSTEPS_DEPLOY);
+ if (obj == parent() && ev->type() == QEvent::Resize)
+ resizeToParent();
+ return QWidget::eventFilter(obj, ev);
}
-QdbStopApplicationStepFactory::QdbStopApplicationStepFactory()
+void Utils::OverlayWidget::paintEvent(QPaintEvent *ev)
{
- registerStep<QdbStopApplicationStep>(QdbStopApplicationStep::stepId());
- setDisplayName(QdbStopApplicationStep::stepDisplayName());
- setSupportedDeviceType(Constants::QdbLinuxOsType);
- setSupportedStepList(ProjectExplorer::Constants::BUILDSTEPS_DEPLOY);
+ if (m_paint) {
+ QPainter p(this);
+ m_paint(this, p, ev);
+ }
}
-} // namespace Internal
-} // namespace Qdb
+void Utils::OverlayWidget::attachToWidget(QWidget *parent)
+{
+ if (parentWidget())
+ parentWidget()->removeEventFilter(this);
+ setParent(parent);
+ if (parent) {
+ parent->installEventFilter(this);
+ resizeToParent();
+ raise();
+ }
+}
+
+void Utils::OverlayWidget::resizeToParent()
+{
+ QTC_ASSERT(parentWidget(), return );
+ setGeometry(QRect(QPoint(0, 0), parentWidget()->size()));
+}
diff --git a/src/plugins/projectexplorer/buildenvironmentwidget.h b/src/libs/utils/overlaywidget.h
index 7c45bd8f89..3470166c73 100644
--- a/src/plugins/projectexplorer/buildenvironmentwidget.h
+++ b/src/libs/utils/overlaywidget.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -25,32 +25,33 @@
#pragma once
-#include <projectexplorer/namedwidget.h>
+#include "utils_global.h"
-QT_BEGIN_NAMESPACE
-class QCheckBox;
-QT_END_NAMESPACE
+#include <QWidget>
-namespace ProjectExplorer {
+#include <functional>
-class EnvironmentWidget;
-class BuildConfiguration;
+namespace Utils {
-class PROJECTEXPLORER_EXPORT BuildEnvironmentWidget : public NamedWidget
+class QTCREATOR_UTILS_EXPORT OverlayWidget : public QWidget
{
Q_OBJECT
-
public:
- explicit BuildEnvironmentWidget(BuildConfiguration *bc);
+ using PaintFunction = std::function<void(QWidget *, QPainter &, QPaintEvent *)>;
+
+ explicit OverlayWidget(QWidget *parent = nullptr);
+
+ void attachToWidget(QWidget *parent);
+ void setPaintFunction(const PaintFunction &paint);
+
+protected:
+ bool eventFilter(QObject *obj, QEvent *ev) override;
+ void paintEvent(QPaintEvent *ev) override;
private:
- void environmentModelUserChangesChanged();
- void clearSystemEnvironmentCheckBoxClicked(bool checked);
- void environmentChanged();
+ void resizeToParent();
- EnvironmentWidget *m_buildEnvironmentWidget;
- QCheckBox *m_clearSystemEnvironmentCheckBox;
- BuildConfiguration *m_buildConfiguration;
+ PaintFunction m_paint;
};
-} // namespace ProjectExplorer
+} // namespace Utils
diff --git a/src/libs/utils/pathchooser.cpp b/src/libs/utils/pathchooser.cpp
index bc874241a3..01e2fa3e5f 100644
--- a/src/libs/utils/pathchooser.cpp
+++ b/src/libs/utils/pathchooser.cpp
@@ -175,13 +175,15 @@ public:
Environment m_environment;
BinaryVersionToolTipEventFilter *m_binaryVersionToolTipEventFilter = nullptr;
QList<QAbstractButton *> m_buttons;
- MacroExpander *m_macroExpander;
+ MacroExpander *m_macroExpander = globalMacroExpander();
+
+ bool m_isReadOnly = false;
+ bool m_isFileDialogOnly = false;
};
-PathChooserPrivate::PathChooserPrivate() :
- m_hLayout(new QHBoxLayout),
- m_lineEdit(new FancyLineEdit),
- m_macroExpander(globalMacroExpander())
+PathChooserPrivate::PathChooserPrivate()
+ : m_hLayout(new QHBoxLayout)
+ , m_lineEdit(new FancyLineEdit)
{
}
@@ -223,9 +225,13 @@ PathChooser::PathChooser(QWidget *parent) :
{
d->m_hLayout->setContentsMargins(0, 0, 0, 0);
- d->m_lineEdit->setContextMenuPolicy(Qt::CustomContextMenu);
+ setContextMenuPolicy(Qt::CustomContextMenu);
+ d->m_lineEdit->setContextMenuPolicy(Qt::NoContextMenu);
- connect(d->m_lineEdit, &FancyLineEdit::customContextMenuRequested, this, &PathChooser::contextMenuRequested);
+ connect(this,
+ &FancyLineEdit::customContextMenuRequested,
+ this,
+ &PathChooser::contextMenuRequested);
connect(d->m_lineEdit, &FancyLineEdit::validReturnPressed, this, &PathChooser::returnPressed);
connect(d->m_lineEdit, &QLineEdit::textChanged, this,
[this] { emit rawPathChanged(rawPath()); });
@@ -268,6 +274,7 @@ void PathChooser::insertButton(int index, const QString &text, QObject *context,
connect(button, &QAbstractButton::clicked, context, callback);
d->m_hLayout->insertWidget(index + 1/*line edit*/, button);
d->m_buttons.insert(index, button);
+ updateReadOnlyStateOfSubwidgets();
}
QString PathChooser::browseButtonLabel()
@@ -295,9 +302,9 @@ FilePath PathChooser::baseDirectory() const
void PathChooser::setEnvironment(const Environment &env)
{
- QString oldExpand = path();
+ QString oldExpand = filePath().toString();
d->m_environment = env;
- if (path() != oldExpand) {
+ if (filePath().toString() != oldExpand) {
triggerChanged();
emit rawPathChanged(rawPath());
}
@@ -305,22 +312,17 @@ void PathChooser::setEnvironment(const Environment &env)
QString PathChooser::rawPath() const
{
- return rawFileName().toString();
+ return rawFilePath().toString();
}
-QString PathChooser::path() const
-{
- return fileName().toString();
-}
-
-FilePath PathChooser::rawFileName() const
+FilePath PathChooser::rawFilePath() const
{
return FilePath::fromString(QDir::fromNativeSeparators(d->m_lineEdit->text()));
}
-FilePath PathChooser::fileName() const
+FilePath PathChooser::filePath() const
{
- return FilePath::fromUserInput(d->expandedPath(rawFileName().toString()));
+ return FilePath::fromUserInput(d->expandedPath(rawFilePath().toString()));
}
// FIXME: try to remove again
@@ -342,29 +344,38 @@ void PathChooser::setPath(const QString &path)
d->m_lineEdit->setTextKeepingActiveCursor(QDir::toNativeSeparators(path));
}
-void PathChooser::setFileName(const FilePath &fn)
+void PathChooser::setFilePath(const FilePath &fn)
{
d->m_lineEdit->setTextKeepingActiveCursor(fn.toUserOutput());
}
bool PathChooser::isReadOnly() const
{
- return d->m_lineEdit->isReadOnly();
+ return d->m_isReadOnly;
}
void PathChooser::setReadOnly(bool b)
{
- d->m_lineEdit->setReadOnly(b);
- const auto buttons = d->m_buttons;
- for (QAbstractButton *button : buttons)
- button->setEnabled(!b);
+ d->m_isReadOnly = b;
+ updateReadOnlyStateOfSubwidgets();
+}
+
+bool PathChooser::isFileDialogOnly() const
+{
+ return d->m_isFileDialogOnly;
+}
+
+void PathChooser::setFileDialogOnly(bool b)
+{
+ d->m_isFileDialogOnly = b;
+ updateReadOnlyStateOfSubwidgets();
}
void PathChooser::slotBrowse()
{
emit beforeBrowsing();
- QString predefined = path();
+ QString predefined = filePath().toString();
QFileInfo fi(predefined);
if (!predefined.isEmpty() && !fi.isDir()) {
@@ -447,16 +458,31 @@ void PathChooser::slotBrowse()
void PathChooser::contextMenuRequested(const QPoint &pos)
{
- if (QMenu *menu = d->m_lineEdit->createStandardContextMenu()) {
+ if (!d->m_lineEdit->rect().contains(pos))
+ return;
+ QMenu *menu = d->m_lineEdit->createStandardContextMenu();
+ if (!menu)
+ menu = new QMenu;
+ if (s_aboutToShowContextMenuHandler)
+ s_aboutToShowContextMenuHandler(this, menu);
+ if (!menu->actions().isEmpty()) {
menu->setAttribute(Qt::WA_DeleteOnClose);
-
- if (s_aboutToShowContextMenuHandler)
- s_aboutToShowContextMenuHandler(this, menu);
-
- menu->popup(d->m_lineEdit->mapToGlobal(pos));
+ menu->popup(mapToGlobal(pos));
+ } else {
+ delete menu;
}
}
+void PathChooser::updateReadOnlyStateOfSubwidgets()
+{
+ const bool readOnlyLineEdit = d->m_isReadOnly || d->m_isFileDialogOnly;
+ d->m_lineEdit->setEnabled(!readOnlyLineEdit);
+ d->m_lineEdit->setReadOnly(readOnlyLineEdit);
+ setFocusPolicy(d->m_lineEdit->focusPolicy());
+ for (QAbstractButton *button : qAsConst(d->m_buttons))
+ button->setEnabled(!d->m_isReadOnly);
+}
+
bool PathChooser::isValid() const
{
return d->m_lineEdit->isValid();
diff --git a/src/libs/utils/pathchooser.h b/src/libs/utils/pathchooser.h
index 016f088f2d..cc864b48be 100644
--- a/src/libs/utils/pathchooser.h
+++ b/src/libs/utils/pathchooser.h
@@ -55,7 +55,7 @@ class QTCREATOR_UTILS_EXPORT PathChooser : public QWidget
Q_PROPERTY(QStringList commandVersionArguments READ commandVersionArguments WRITE setCommandVersionArguments)
Q_PROPERTY(bool readOnly READ isReadOnly WRITE setReadOnly DESIGNABLE true)
// Designer does not know this type, so force designable to false:
- Q_PROPERTY(Utils::FilePath fileName READ fileName WRITE setFileName DESIGNABLE false)
+ Q_PROPERTY(Utils::FilePath filePath READ filePath WRITE setFilePath DESIGNABLE false)
public:
static QString browseButtonLabel();
@@ -88,10 +88,10 @@ public:
bool isValid() const;
QString errorMessage() const;
- QString path() const;
+ FilePath filePath() const;
+
QString rawPath() const; // The raw unexpanded input.
- FilePath rawFileName() const; // The raw unexpanded input.
- FilePath fileName() const;
+ FilePath rawFilePath() const; // The raw unexpanded input as FilePath.
static QString expandedDirectory(const QString &input, const Environment &env,
const QString &baseDir);
@@ -138,6 +138,9 @@ public:
bool isReadOnly() const;
void setReadOnly(bool b);
+ bool isFileDialogOnly() const;
+ void setFileDialogOnly(bool b);
+
void triggerChanged();
// global handler for adding context menus to ALL pathchooser
@@ -145,12 +148,18 @@ public:
using AboutToShowContextMenuHandler = std::function<void (PathChooser *, QMenu *)>;
static void setAboutToShowContextMenuHandler(AboutToShowContextMenuHandler handler);
+ // Deprecated. Use filePath().toString() or better suitable conversions.
+ QString path() const { return filePath().toString(); }
+ // Deprecated. Use filePath()
+ FilePath fileName() const { return filePath(); }
+
private:
bool validatePath(FancyLineEdit *edit, QString *errorMessage) const;
// Returns overridden title or the one from <title>
QString makeDialogTitle(const QString &title);
void slotBrowse();
void contextMenuRequested(const QPoint &pos);
+ void updateReadOnlyStateOfSubwidgets();
signals:
void validChanged(bool validState);
@@ -163,7 +172,9 @@ signals:
public slots:
void setPath(const QString &);
- void setFileName(const FilePath &);
+ // Deprecated: Use setFilePath()
+ void setFileName(const FilePath &path) { setFilePath(path); }
+ void setFilePath(const FilePath &);
private:
PathChooserPrivate *d = nullptr;
diff --git a/src/libs/utils/progressindicator.cpp b/src/libs/utils/progressindicator.cpp
index dc2d8bb626..7bc016f8ee 100644
--- a/src/libs/utils/progressindicator.cpp
+++ b/src/libs/utils/progressindicator.cpp
@@ -220,9 +220,11 @@ void ProgressIndicatorPainter::nextAnimationStep()
\sa setIndicatorSize
*/
ProgressIndicator::ProgressIndicator(ProgressIndicatorSize size, QWidget *parent)
- : QWidget(parent), m_paint(size)
+ : OverlayWidget(parent)
+ , m_paint(size)
{
- setAttribute(Qt::WA_TransparentForMouseEvents);
+ setPaintFunction(
+ [this](QWidget *w, QPainter &p, QPaintEvent *) { m_paint.paint(p, w->rect()); });
m_paint.setUpdateCallback([this]() { update(); });
updateGeometry();
}
@@ -249,29 +251,6 @@ QSize ProgressIndicator::sizeHint() const
}
/*!
- Makes the indicator a child of \a parent, automatically centering on it,
- and adapting to size changes.
-*/
-void ProgressIndicator::attachToWidget(QWidget *parent)
-{
- if (parentWidget())
- parentWidget()->removeEventFilter(this);
- setParent(parent);
- parent->installEventFilter(this);
- resizeToParent();
- raise();
-}
-
-/*!
- \internal
-*/
-void ProgressIndicator::paintEvent(QPaintEvent *)
-{
- QPainter p(this);
- m_paint.paint(p, rect());
-}
-
-/*!
\internal
*/
void ProgressIndicator::showEvent(QShowEvent *)
@@ -287,24 +266,4 @@ void ProgressIndicator::hideEvent(QHideEvent *)
m_paint.stopAnimation();
}
-/*!
- \internal
-*/
-bool ProgressIndicator::eventFilter(QObject *obj, QEvent *ev)
-{
- if (obj == parent() && ev->type() == QEvent::Resize) {
- resizeToParent();
- }
- return QWidget::eventFilter(obj, ev);
-}
-
-/*!
- \internal
-*/
-void ProgressIndicator::resizeToParent()
-{
- QTC_ASSERT(parentWidget(), return);
- setGeometry(QRect(QPoint(0, 0), parentWidget()->size()));
-}
-
} // namespace Utils
diff --git a/src/libs/utils/progressindicator.h b/src/libs/utils/progressindicator.h
index 6713709c1b..0d13cf8952 100644
--- a/src/libs/utils/progressindicator.h
+++ b/src/libs/utils/progressindicator.h
@@ -25,6 +25,7 @@
#pragma once
+#include "overlaywidget.h"
#include "utils_global.h"
#include <QTimer>
@@ -76,7 +77,7 @@ private:
UpdateCallback m_callback;
};
-class QTCREATOR_UTILS_EXPORT ProgressIndicator : public QWidget
+class QTCREATOR_UTILS_EXPORT ProgressIndicator : public OverlayWidget
{
Q_OBJECT
public:
@@ -86,17 +87,11 @@ public:
QSize sizeHint() const final;
- void attachToWidget(QWidget *parent);
-
protected:
- void paintEvent(QPaintEvent *) final;
void showEvent(QShowEvent *) final;
void hideEvent(QHideEvent *) final;
- bool eventFilter(QObject *obj, QEvent *ev) final;
private:
- void resizeToParent();
-
ProgressIndicatorPainter m_paint;
};
diff --git a/src/libs/utils/projectintropage.cpp b/src/libs/utils/projectintropage.cpp
index a98095b3d9..ac172f4078 100644
--- a/src/libs/utils/projectintropage.cpp
+++ b/src/libs/utils/projectintropage.cpp
@@ -116,7 +116,7 @@ QString ProjectIntroPage::projectName() const
QString ProjectIntroPage::path() const
{
- return d->m_ui.pathChooser->path();
+ return d->m_ui.pathChooser->filePath().toString();
}
void ProjectIntroPage::setPath(const QString &path)
diff --git a/src/libs/utils/qtcprocess.cpp b/src/libs/utils/qtcprocess.cpp
index 2088ae408f..1b0c1e3866 100644
--- a/src/libs/utils/qtcprocess.cpp
+++ b/src/libs/utils/qtcprocess.cpp
@@ -678,6 +678,10 @@ QtcProcess::QtcProcess(QObject *parent)
static int qProcessProcessErrorMeta = qRegisterMetaType<QProcess::ProcessError>();
Q_UNUSED(qProcessExitStatusMeta)
Q_UNUSED(qProcessProcessErrorMeta)
+
+#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) && defined(Q_OS_UNIX)
+ setChildProcessModifier([this]() { niceChildProcess(); });
+#endif
}
void QtcProcess::setUseCtrlCStub(bool enabled)
@@ -1220,18 +1224,25 @@ QString QtcProcess::expandMacros(const QString &str, AbstractMacroExpander *mx,
return ret;
}
-void QtcProcess::setupChildProcess()
-{
#if defined Q_OS_UNIX
+void QtcProcess::niceChildProcess()
+{
// nice value range is -20 to +19 where -20 is highest, 0 default and +19 is lowest
if (m_lowPriority) {
errno = 0;
if (::nice(5) == -1 && errno != 0)
perror("Failed to set nice value");
}
-#endif
+}
+
+# if QT_VERSION < QT_VERSION_CHECK(6,0,0)
+void QtcProcess::setupChildProcess()
+{
+ niceChildProcess();
QProcess::setupChildProcess();
}
+# endif
+#endif
bool QtcProcess::ArgIterator::next()
{
diff --git a/src/libs/utils/qtcprocess.h b/src/libs/utils/qtcprocess.h
index ca3f9a5a86..5a6bf0f944 100644
--- a/src/libs/utils/qtcprocess.h
+++ b/src/libs/utils/qtcprocess.h
@@ -142,7 +142,12 @@ public:
};
private:
+#ifdef Q_OS_UNIX
+# if QT_VERSION < QT_VERSION_CHECK(6,0,0)
void setupChildProcess() override;
+# endif
+ void niceChildProcess();
+#endif
CommandLine m_commandLine;
Environment m_environment;
diff --git a/src/libs/utils/stylehelper.cpp b/src/libs/utils/stylehelper.cpp
index f91c24b52a..68d40accbc 100644
--- a/src/libs/utils/stylehelper.cpp
+++ b/src/libs/utils/stylehelper.cpp
@@ -28,6 +28,8 @@
#include "theme/theme.h"
#include "hostosinfo.h"
+#include <utils/qtcassert.h>
+
#include <QPixmapCache>
#include <QPainter>
#include <QApplication>
@@ -35,6 +37,7 @@
#include <QCommonStyle>
#include <QStyleOption>
#include <QWindow>
+#include <QFontDatabase>
#include <qmath.h>
// Clamps float color values within (0, 255)
@@ -542,6 +545,48 @@ QLinearGradient StyleHelper::statusBarGradient(const QRect &statusBarRect)
return grad;
}
+QIcon StyleHelper::getIconFromIconFont(const QString &fontName, const QString &iconSymbol, int fontSize, int iconSize, QColor color)
+{
+ QFontDatabase a;
+
+ QTC_ASSERT(a.hasFamily(fontName), {});
+
+ if (a.hasFamily(fontName)) {
+
+ QIcon icon;
+ QSize size(iconSize, iconSize);
+
+ const int maxDpr = qRound(qApp->devicePixelRatio());
+ for (int dpr = 1; dpr <= maxDpr; dpr++) {
+ QPixmap pixmap(size * dpr);
+ pixmap.setDevicePixelRatio(dpr);
+ pixmap.fill(Qt::transparent);
+
+ QFont font(fontName);
+ font.setPixelSize(fontSize * dpr);
+
+ QPainter painter(&pixmap);
+ painter.save();
+ painter.setPen(color);
+ painter.setFont(font);
+ painter.drawText(QRectF(QPoint(0, 0), size), iconSymbol);
+ painter.restore();
+
+ icon.addPixmap(pixmap);
+ }
+
+ return icon;
+ }
+
+ return {};
+}
+
+QIcon StyleHelper::getIconFromIconFont(const QString &fontName, const QString &iconSymbol, int fontSize, int iconSize)
+{
+ QColor penColor = QApplication::palette("QWidget").color(QPalette::Normal, QPalette::ButtonText);
+ return getIconFromIconFont(fontName, iconSymbol, fontSize, iconSize, penColor);
+}
+
QString StyleHelper::dpiSpecificImageFile(const QString &fileName)
{
// See QIcon::addFile()
diff --git a/src/libs/utils/stylehelper.h b/src/libs/utils/stylehelper.h
index 4bcec960ad..09f3253435 100644
--- a/src/libs/utils/stylehelper.h
+++ b/src/libs/utils/stylehelper.h
@@ -93,6 +93,9 @@ public:
static void tintImage(QImage &img, const QColor &tintColor);
static QLinearGradient statusBarGradient(const QRect &statusBarRect);
+ static QIcon getIconFromIconFont(const QString &fontName, const QString &iconSymbol, int fontSize, int iconSize, QColor color);
+ static QIcon getIconFromIconFont(const QString &fontName, const QString &iconSymbol, int fontSize, int iconSize);
+
static QString dpiSpecificImageFile(const QString &fileName);
static QString imageFileWithResolution(const QString &fileName, int dpr);
static QList<int> availableImageResolutions(const QString &fileName);
diff --git a/src/libs/utils/synchronousprocess.cpp b/src/libs/utils/synchronousprocess.cpp
index 43a00ef1ee..2d73283695 100644
--- a/src/libs/utils/synchronousprocess.cpp
+++ b/src/libs/utils/synchronousprocess.cpp
@@ -89,19 +89,27 @@ static Q_LOGGING_CATEGORY(processLog, "qtc.utils.synchronousprocess", QtWarningM
// A special QProcess derivative allowing for terminal control.
class TerminalControllingProcess : public QProcess {
public:
- TerminalControllingProcess() = default;
+ TerminalControllingProcess()
+ {
+#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) && defined(Q_OS_UNIX)
+ setChildProcessModifier([this]() { maybeSetsid(); });
+#endif
+ }
unsigned flags() const { return m_flags; }
void setFlags(unsigned tc) { m_flags = tc; }
protected:
- void setupChildProcess() override;
+ inline void maybeSetsid();
+#if QT_VERSION < QT_VERSION_CHECK(6,0,0) && defined(Q_OS_UNIX)
+ void setupChildProcess() override { maybeSetsid(); }
+#endif
private:
unsigned m_flags = 0;
};
-void TerminalControllingProcess::setupChildProcess()
+inline void TerminalControllingProcess::maybeSetsid()
{
#ifdef Q_OS_UNIX
// Disable terminal by becoming a session leader.
diff --git a/src/libs/utils/textfileformat.cpp b/src/libs/utils/textfileformat.cpp
index 8b8a549c35..814cb0256f 100644
--- a/src/libs/utils/textfileformat.cpp
+++ b/src/libs/utils/textfileformat.cpp
@@ -304,7 +304,7 @@ bool TextFileFormat::writeFile(const QString &fileName, QString plainText, QStri
QTC_ASSERT(codec, return false);
// Does the user want CRLF? If that is native,
- // do net let QFile do the work, because it replaces the line ending after the text was encoded,
+ // do not let QFile do the work, because it replaces the line ending after the text was encoded,
// and this could lead to undecodable file contents.
QIODevice::OpenMode fileMode = QIODevice::NotOpen;
if (lineTerminationMode == CRLFLineTerminator)
diff --git a/src/libs/utils/theme/theme.h b/src/libs/utils/theme/theme.h
index e0f6e9cdb9..8abf2d3992 100644
--- a/src/libs/utils/theme/theme.h
+++ b/src/libs/utils/theme/theme.h
@@ -279,6 +279,13 @@ public:
VcsBase_FileRenamed_TextColor,
VcsBase_FileUnmerged_TextColor,
+ /* Git Plugin */
+ Git_AuthorName_TextColor,
+ Git_CommitDate_TextColor,
+ Git_CommitHash_TextColor,
+ Git_CommitSubject_TextColor,
+ Git_Decoration_TextColor,
+
/* Bookmarks Plugin */
Bookmarks_TextMarkColor,
diff --git a/src/libs/utils/touchbar/touchbar_appdelegate_mac.mm b/src/libs/utils/touchbar/touchbar_appdelegate_mac.mm
index e921695fdc..128679dfb7 100644
--- a/src/libs/utils/touchbar/touchbar_appdelegate_mac.mm
+++ b/src/libs/utils/touchbar/touchbar_appdelegate_mac.mm
@@ -29,6 +29,7 @@
#include <stack>
#import <AppKit/NSTouchBar.h>
+#import <AppKit/NSWindow.h>
Q_GLOBAL_STATIC(Utils::Internal::ApplicationDelegate, staticApplicationDelegate);
@@ -148,4 +149,11 @@ using namespace Utils::Internal;
[anInvocation invokeWithTarget:self.qtDelegate];
}
+// Work around QTBUG-61707
+- (void)applicationWillFinishLaunching:(NSNotification*)notify
+{
+ Q_UNUSED(notify)
+ [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"NSFullScreenMenuItemEverywhere"];
+ NSWindow.allowsAutomaticWindowTabbing = NO;
+}
@end
diff --git a/src/libs/utils/touchbar/touchbar_appdelegate_mac_p.h b/src/libs/utils/touchbar/touchbar_appdelegate_mac_p.h
index da2f8e4e07..e97e49691d 100644
--- a/src/libs/utils/touchbar/touchbar_appdelegate_mac_p.h
+++ b/src/libs/utils/touchbar/touchbar_appdelegate_mac_p.h
@@ -37,6 +37,7 @@
- (void)setApplicationTouchBar:(Utils::Internal::TouchBarPrivate *)bar;
- (void)pushTouchBar:(Utils::Internal::TouchBarPrivate *)bar;
- (void)popTouchBar;
+- (void)applicationWillFinishLaunching:(NSNotification*)notify;
@end
diff --git a/src/libs/utils/utils-lib.pri b/src/libs/utils/utils-lib.pri
index 55dd718a72..69db3b63a0 100644
--- a/src/libs/utils/utils-lib.pri
+++ b/src/libs/utils/utils-lib.pri
@@ -132,7 +132,8 @@ SOURCES += \
$$PWD/jsontreeitem.cpp \
$$PWD/namevaluevalidator.cpp \
$$PWD/camelcasecursor.cpp \
- $$PWD/infolabel.cpp
+ $$PWD/infolabel.cpp \
+ $$PWD/overlaywidget.cpp
HEADERS += \
$$PWD/environmentfwd.h \
@@ -279,7 +280,8 @@ HEADERS += \
$$PWD/listmodel.h \
$$PWD/namevaluevalidator.h \
$$PWD/camelcasecursor.h \
- $$PWD/infolabel.h
+ $$PWD/infolabel.h \
+ $$PWD/overlaywidget.h
FORMS += $$PWD/filewizardpage.ui \
$$PWD/projectintropage.ui \
diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs
index ed15c78d8e..2c1b098c9e 100644
--- a/src/libs/utils/utils.qbs
+++ b/src/libs/utils/utils.qbs
@@ -176,6 +176,8 @@ Project {
"outputformat.h",
"outputformatter.cpp",
"outputformatter.h",
+ "overlaywidget.cpp",
+ "overlaywidget.h",
"overridecursor.cpp",
"overridecursor.h",
"parameteraction.cpp",
diff --git a/src/plugins/android/CMakeLists.txt b/src/plugins/android/CMakeLists.txt
index 0f2eb17d7b..c19da7c15a 100644
--- a/src/plugins/android/CMakeLists.txt
+++ b/src/plugins/android/CMakeLists.txt
@@ -24,6 +24,8 @@ add_qtc_plugin(Android
androidmanifesteditor.cpp androidmanifesteditor.h
androidmanifesteditorfactory.cpp androidmanifesteditorfactory.h
androidmanifesteditorwidget.cpp androidmanifesteditorwidget.h
+ androidmanifesteditoriconwidget.cpp androidmanifesteditoriconwidget.h
+ androidmanifesteditoriconcontainerwidget.cpp androidmanifesteditoriconcontainerwidget.h
androidpackageinstallationstep.cpp androidpackageinstallationstep.h
androidplugin.cpp androidplugin.h
androidpotentialkit.cpp androidpotentialkit.h
@@ -38,6 +40,7 @@ add_qtc_plugin(Android
androidsdkmanagerwidget.cpp androidsdkmanagerwidget.h androidsdkmanagerwidget.ui
androidsdkmodel.cpp androidsdkmodel.h
androidsdkpackage.cpp androidsdkpackage.h
+ androidservicewidget.cpp androidservicewidget.h androidservicewidget_p.h
androidsettingswidget.cpp androidsettingswidget.h androidsettingswidget.ui
androidsignaloperation.cpp androidsignaloperation.h
androidtoolchain.cpp androidtoolchain.h
diff --git a/src/plugins/android/android.pro b/src/plugins/android/android.pro
index f3745d18c0..529e4d090c 100644
--- a/src/plugins/android/android.pro
+++ b/src/plugins/android/android.pro
@@ -9,8 +9,12 @@ HEADERS += \
androidconstants.h \
androidconfigurations.h \
androidmanager.h \
+ androidmanifesteditoriconcontainerwidget.h \
+ androidmanifesteditoriconwidget.h \
androidrunconfiguration.h \
androidruncontrol.h \
+ androidservicewidget.h \
+ androidservicewidget_p.h \
androidsettingswidget.h \
androidtoolchain.h \
androiderrormessage.h \
@@ -54,8 +58,11 @@ HEADERS += \
SOURCES += \
androidconfigurations.cpp \
androidmanager.cpp \
+ androidmanifesteditoriconcontainerwidget.cpp \
+ androidmanifesteditoriconwidget.cpp \
androidrunconfiguration.cpp \
androidruncontrol.cpp \
+ androidservicewidget.cpp \
androidsettingswidget.cpp \
androidtoolchain.cpp \
androiderrormessage.cpp \
diff --git a/src/plugins/android/android.qbs b/src/plugins/android/android.qbs
index 0162ed096d..0edfce86a5 100644
--- a/src/plugins/android/android.qbs
+++ b/src/plugins/android/android.qbs
@@ -56,6 +56,10 @@ Project {
"androidmanifestdocument.h",
"androidmanifesteditor.cpp",
"androidmanifesteditor.h",
+ "androidmanifesteditoriconwidget.cpp",
+ "androidmanifesteditoriconwidget.h",
+ "androidmanifesteditoriconcontainerwidget.cpp",
+ "androidmanifesteditoriconcontainerwidget.h",
"androidmanifesteditorfactory.cpp",
"androidmanifesteditorfactory.h",
"androidmanifesteditorwidget.cpp",
@@ -89,6 +93,9 @@ Project {
"androidsdkmodel.h",
"androidsdkpackage.cpp",
"androidsdkpackage.h",
+ "androidservicewidget.cpp",
+ "androidservicewidget.h",
+ "androidservicewidget_p.h",
"androidsettingswidget.cpp",
"androidsettingswidget.h",
"androidsettingswidget.ui",
diff --git a/src/plugins/android/androidavdmanager.cpp b/src/plugins/android/androidavdmanager.cpp
index 7e91db6ef8..19cdd50502 100644
--- a/src/plugins/android/androidavdmanager.cpp
+++ b/src/plugins/android/androidavdmanager.cpp
@@ -62,7 +62,6 @@ const char avdInfoSdcardKey[] = "Sdcard";
const char avdInfoTargetTypeKey[] = "Target";
const char avdInfoDeviceKey[] = "Device";
const char avdInfoSkinKey[] = "Skin";
-const char googleApiTag[] = "google_apis";
const int avdCreateTimeoutMs = 30000;
diff --git a/src/plugins/android/androidbuildapkstep.cpp b/src/plugins/android/androidbuildapkstep.cpp
index 94cb986b19..7bb6bbc464 100644
--- a/src/plugins/android/androidbuildapkstep.cpp
+++ b/src/plugins/android/androidbuildapkstep.cpp
@@ -40,11 +40,11 @@
#include <projectexplorer/buildconfiguration.h>
#include <projectexplorer/buildsteplist.h>
+#include <projectexplorer/buildsystem.h>
#include <projectexplorer/processparameters.h>
#include <projectexplorer/project.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/projectnodes.h>
-#include <projectexplorer/runconfiguration.h>
#include <projectexplorer/target.h>
#include <qtsupport/qtkitinformation.h>
@@ -65,6 +65,7 @@
#include <QMessageBox>
#include <QProcess>
#include <QPushButton>
+#include <QTimer>
#include <QVBoxLayout>
#include <memory>
@@ -86,13 +87,13 @@ const char VerboseOutputKey[] = "VerboseOutput";
const char UseMinistroKey[] = "UseMinistro";
static void setupProcessParameters(ProcessParameters *pp,
- BuildConfiguration *bc,
+ BuildStep *step,
const QStringList &arguments,
const QString &command)
{
- pp->setMacroExpander(bc->macroExpander());
- pp->setWorkingDirectory(bc->buildDirectory());
- Utils::Environment env = bc->environment();
+ pp->setMacroExpander(step->macroExpander());
+ pp->setWorkingDirectory(step->buildDirectory());
+ Utils::Environment env = step->buildEnvironment();
pp->setEnvironment(env);
pp->setCommandLine({command, arguments});
}
@@ -124,22 +125,6 @@ private:
this);
};
-static FilePath aabPath(const BuildConfiguration *bc)
-{
- if (!bc)
- return {};
-
- QString buildType;
- if (bc->buildType() == BuildConfiguration::Release)
- buildType = "release";
- else
- buildType = "debug";
-
- return bc->buildDirectory()
- .pathAppended(Constants::ANDROID_BUILDDIRECTORY)
- .pathAppended(QString("build/outputs/bundle/%1/android-build-%1.aab").arg(buildType));
-}
-
AndroidBuildApkStep::AndroidBuildApkStep(BuildStepList *parent, Core::Id id)
: AbstractProcessStep(parent, id),
m_buildTargetSdk(AndroidConfig::apiLevelNameFor(AndroidConfigurations::
@@ -152,8 +137,6 @@ AndroidBuildApkStep::AndroidBuildApkStep(BuildStepList *parent, Core::Id id)
bool AndroidBuildApkStep::init()
{
- ProjectExplorer::BuildConfiguration *bc = buildConfiguration();
-
if (m_signPackage) {
qCDebug(buildapkstepLog) << "Signing enabled";
// check keystore and certificate passwords
@@ -162,7 +145,7 @@ bool AndroidBuildApkStep::init()
return false;
}
- if (bc->buildType() != ProjectExplorer::BuildConfiguration::Release)
+ if (buildType() != BuildConfiguration::Release)
emit addOutput(tr("Warning: Signing a debug or profile package."),
OutputFormat::ErrorMessage);
}
@@ -195,26 +178,18 @@ bool AndroidBuildApkStep::init()
return false;
}
- auto parser = new JavaParser;
- parser->setProjectFileList(Utils::transform(target()->project()->files(ProjectExplorer::Project::AllFiles),
- &Utils::FilePath::toString));
-
- RunConfiguration *rc = target()->activeRunConfiguration();
- const QString buildKey = rc ? rc->buildKey() : QString();
- const ProjectNode *node = rc ? target()->project()->findNodeForBuildKey(buildKey) : nullptr;
-
- QString sourceDirName;
- if (node)
- sourceDirName = node->data(Constants::AndroidPackageSourceDir).toString();
+ m_openPackageLocationForRun = m_openPackageLocation;
- QFileInfo sourceDirInfo(sourceDirName);
- parser->setSourceDirectory(Utils::FilePath::fromString(sourceDirInfo.canonicalFilePath()));
- parser->setBuildDirectory(bc->buildDirectory().pathAppended(Constants::ANDROID_BUILDDIRECTORY));
- setOutputParser(parser);
+ if (m_buildAAB) {
+ const QString bt = buildType() == BuildConfiguration::Release ? QLatin1String("release")
+ : QLatin1String("debug");
+ m_packagePath = buildDirectory()
+ .pathAppended(Constants::ANDROID_BUILDDIRECTORY)
+ .pathAppended(QString("build/outputs/bundle/%1/android-build-%1.aab").arg(bt)).toString();
+ } else {
+ m_packagePath = AndroidManager::apkPath(target()).toString();
+ }
- m_openPackageLocationForRun = m_openPackageLocation;
- m_packagePath = m_buildAAB ? aabPath(buildConfiguration()).toString()
- : AndroidManager::apkPath(target()).toString();
qCDebug(buildapkstepLog) << "Package path:" << m_packagePath;
if (!AbstractProcessStep::init())
@@ -225,13 +200,15 @@ bool AndroidBuildApkStep::init()
command += '/';
command += Utils::HostOsInfo::withExecutableSuffix("androiddeployqt");
- QString outputDir = bc->buildDirectory().pathAppended(Constants::ANDROID_BUILDDIRECTORY).toString();
+ QString outputDir = buildDirectory().pathAppended(Constants::ANDROID_BUILDDIRECTORY).toString();
+ const QString buildKey = target()->activeBuildKey();
+ const ProjectNode *node = project()->findNodeForBuildKey(buildKey);
if (node)
m_inputFile = node->data(Constants::AndroidDeploySettingsFile).toString();
if (m_inputFile.isEmpty()) {
- qCDebug(buildapkstepLog) << "no input file" << rc << node << buildKey;
+ qCDebug(buildapkstepLog) << "no input file" << node << buildKey;
m_skipBuilding = true;
return true;
}
@@ -276,24 +253,41 @@ bool AndroidBuildApkStep::init()
// Must be the last option, otherwise androiddeployqt might use the other
// params (e.g. --sign) to choose not to add gdbserver
if (version->qtVersion() >= QtSupport::QtVersionNumber(5, 6, 0)) {
- if (m_addDebugger || bc->buildType() == ProjectExplorer::BuildConfiguration::Debug)
+ if (m_addDebugger || buildType() == ProjectExplorer::BuildConfiguration::Debug)
arguments << "--gdbserver";
else
arguments << "--no-gdbserver";
}
ProjectExplorer::ProcessParameters *pp = processParameters();
- setupProcessParameters(pp, bc, arguments, command);
+ setupProcessParameters(pp, this, arguments, command);
// Generate arguments with keystore password concealed
ProjectExplorer::ProcessParameters pp2;
- setupProcessParameters(&pp2, bc, argumentsPasswordConcealed, command);
+ setupProcessParameters(&pp2, this, argumentsPasswordConcealed, command);
m_command = pp2.effectiveCommand().toString();
m_argumentsPasswordConcealed = pp2.prettyArguments();
return true;
}
+void AndroidBuildApkStep::setupOutputFormatter(OutputFormatter *formatter)
+{
+ const auto parser = new JavaParser;
+ parser->setProjectFileList(Utils::transform(project()->files(ProjectExplorer::Project::AllFiles),
+ &Utils::FilePath::toString));
+ const QString buildKey = target()->activeBuildKey();
+ const ProjectNode *node = project()->findNodeForBuildKey(buildKey);
+ QString sourceDirName;
+ if (node)
+ sourceDirName = node->data(Constants::AndroidPackageSourceDir).toString();
+ QFileInfo sourceDirInfo(sourceDirName);
+ parser->setSourceDirectory(Utils::FilePath::fromString(sourceDirInfo.canonicalFilePath()));
+ parser->setBuildDirectory(buildDirectory().pathAppended(Constants::ANDROID_BUILDDIRECTORY));
+ formatter->addLineParser(parser);
+ AbstractProcessStep::setupOutputFormatter(formatter);
+}
+
void AndroidBuildApkStep::showInGraphicalShell()
{
Core::FileUtils::showInGraphicalShell(Core::ICore::mainWindow(), m_packagePath);
@@ -308,7 +302,7 @@ void AndroidBuildApkStep::processFinished(int exitCode, QProcess::ExitStatus sta
{
AbstractProcessStep::processFinished(exitCode, status);
if (m_openPackageLocationForRun && status == QProcess::NormalExit && exitCode == 0)
- QMetaObject::invokeMethod(this, "showInGraphicalShell", Qt::QueuedConnection);
+ QTimer::singleShot(0, this, &AndroidBuildApkStep::showInGraphicalShell);
}
bool AndroidBuildApkStep::verifyKeystorePassword()
@@ -384,28 +378,21 @@ void AndroidBuildApkStep::doRun()
}
auto setup = [this] {
- auto bc = buildConfiguration();
const auto androidAbis = AndroidManager::applicationAbis(target());
for (const auto &abi : androidAbis) {
- Utils::FilePath androidLibsDir = bc->buildDirectory()
- .pathAppended("android-build/libs")
- .pathAppended(abi);
- if (!androidLibsDir.exists() && !QDir{bc->buildDirectory().toString()}.mkpath(androidLibsDir.toString()))
+ FilePath androidLibsDir = buildDirectory() / "android-build/libs" / abi;
+ if (!androidLibsDir.exists() && !QDir{buildDirectory().toString()}.mkpath(androidLibsDir.toString()))
return false;
}
- RunConfiguration *rc = target()->activeRunConfiguration();
- const QString buildKey = rc ? rc->buildKey() : QString();
- const ProjectNode *node = rc ? target()->project()->findNodeForBuildKey(buildKey) : nullptr;
-
- if (!node)
- return false;
+ const QString buildKey = target()->activeBuildKey();
+ BuildSystem *bs = buildSystem();
bool inputExists = QFile::exists(m_inputFile);
if (inputExists && !AndroidManager::isQtCreatorGenerated(FilePath::fromString(m_inputFile)))
return true; // use the generated file if it was not generated by qtcreator
- auto targets = node->data(Android::Constants::AndroidTargets).toStringList();
+ auto targets = bs->extraData(buildKey, Android::Constants::AndroidTargets).toStringList();
if (targets.isEmpty())
return inputExists; // qmake does this job for us
@@ -418,15 +405,15 @@ void AndroidBuildApkStep::doRun()
QString applicationBinary;
if (version->qtVersion() < QtSupport::QtVersionNumber(5, 14, 0)) {
QTC_ASSERT(androidAbis.size() == 1, return false);
- applicationBinary = target()->activeRunConfiguration()->buildTargetInfo().targetFilePath.toString();
- Utils::FilePath androidLibsDir = bc->buildDirectory().pathAppended("android-build/libs").pathAppended(androidAbis.first());
+ applicationBinary = buildSystem()->buildTarget(buildKey).targetFilePath.toString();
+ FilePath androidLibsDir = buildDirectory() / "android-build/libs" / androidAbis.first();
for (const auto &target : targets) {
if (!copyFileIfNewer(target, androidLibsDir.pathAppended(QFileInfo{target}.fileName()).toString()))
return false;
}
deploySettings["target-architecture"] = androidAbis.first();
} else {
- applicationBinary = target()->activeRunConfiguration()->buildTargetInfo().targetFilePath.toFileInfo().fileName();
+ applicationBinary = buildSystem()->buildTarget(buildKey).targetFilePath.toFileInfo().fileName();
QJsonObject architectures;
// Copy targets to android build folder
@@ -437,9 +424,7 @@ void AndroidBuildApkStep::doRun()
applicationBinary.remove(0, 3).chop(targetSuffix.size());
}
- Utils::FilePath androidLibsDir = bc->buildDirectory()
- .pathAppended("android-build/libs")
- .pathAppended(abi);
+ FilePath androidLibsDir = buildDirectory() / "android-build/libs" / abi;
for (const auto &target : targets) {
if (target.endsWith(targetSuffix)) {
if (!copyFileIfNewer(target, androidLibsDir.pathAppended(QFileInfo{target}.fileName()).toString()))
@@ -452,19 +437,19 @@ void AndroidBuildApkStep::doRun()
}
deploySettings["application-binary"] = applicationBinary;
- QString extraLibs = node->data(Android::Constants::AndroidExtraLibs).toString();
+ QString extraLibs = bs->extraData(buildKey, Android::Constants::AndroidExtraLibs).toString();
if (!extraLibs.isEmpty())
deploySettings["android-extra-libs"] = extraLibs;
- QString androidSrcs = node->data(Android::Constants::AndroidPackageSourceDir).toString();
+ QString androidSrcs = bs->extraData(buildKey, Android::Constants::AndroidPackageSourceDir).toString();
if (!androidSrcs.isEmpty())
deploySettings["android-package-source-directory"] = androidSrcs;
- QString qmlImportPath = node->data("QML_IMPORT_PATH").toString();
+ QString qmlImportPath = bs->extraData(buildKey, "QML_IMPORT_PATH").toString();
if (!qmlImportPath.isEmpty())
deploySettings["qml-import-paths"] = qmlImportPath;
- QString qmlRootPath = node->data("QML_ROOT_PATH").toString();
+ QString qmlRootPath = bs->extraData(buildKey, "QML_ROOT_PATH").toString();
if (qmlRootPath.isEmpty())
qmlRootPath = target()->project()->rootProjectDirectory().toString();
deploySettings["qml-root-path"] = qmlRootPath;
diff --git a/src/plugins/android/androidbuildapkstep.h b/src/plugins/android/androidbuildapkstep.h
index 49ef9dc94e..ab65a2d7f5 100644
--- a/src/plugins/android/androidbuildapkstep.h
+++ b/src/plugins/android/androidbuildapkstep.h
@@ -79,9 +79,10 @@ public:
QVariant data(Core::Id id) const override;
private:
- Q_INVOKABLE void showInGraphicalShell();
+ void showInGraphicalShell();
bool init() override;
+ void setupOutputFormatter(Utils::OutputFormatter *formatter) override;
ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override;
void processStarted() override;
void processFinished(int exitCode, QProcess::ExitStatus status) override;
diff --git a/src/plugins/android/androidbuildapkwidget.cpp b/src/plugins/android/androidbuildapkwidget.cpp
index 66be50dca7..a7d90e5cad 100644
--- a/src/plugins/android/androidbuildapkwidget.cpp
+++ b/src/plugins/android/androidbuildapkwidget.cpp
@@ -38,7 +38,6 @@
#include <projectexplorer/buildsystem.h>
#include <projectexplorer/project.h>
#include <projectexplorer/projectnodes.h>
-#include <projectexplorer/runconfiguration.h>
#include <projectexplorer/target.h>
#include <qtsupport/qtkitinformation.h>
@@ -257,7 +256,7 @@ QWidget *AndroidBuildApkWidget::createCreateTemplatesGroup()
auto createAndroidTemplatesButton = new QPushButton(tr("Create Templates"));
connect(createAndroidTemplatesButton, &QAbstractButton::clicked, this, [this] {
- CreateAndroidManifestWizard wizard(m_step->buildConfiguration()->buildSystem());
+ CreateAndroidManifestWizard wizard(m_step->buildSystem());
wizard.exec();
});
@@ -273,7 +272,7 @@ QWidget *AndroidBuildApkWidget::createAdditionalLibrariesGroup()
auto group = new QGroupBox(tr("Additional Libraries"));
group->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
- auto libsModel = new AndroidExtraLibraryListModel(m_step->target(), this);
+ auto libsModel = new AndroidExtraLibraryListModel(m_step->buildSystem(), this);
connect(libsModel, &AndroidExtraLibraryListModel::enabledChanged, this,
[this, group](const bool enabled) {
group->setEnabled(enabled);
@@ -329,8 +328,8 @@ QWidget *AndroidBuildApkWidget::createAdditionalLibrariesGroup()
});
Target *target = m_step->target();
- RunConfiguration *rc = target->activeRunConfiguration();
- const ProjectNode *node = rc ? target->project()->findNodeForBuildKey(rc->buildKey()) : nullptr;
+ const QString buildKey = target->activeBuildKey();
+ const ProjectNode *node = target->project()->findNodeForBuildKey(buildKey);
group->setEnabled(node && !node->parseInProgress());
return group;
@@ -406,7 +405,7 @@ void AndroidBuildApkWidget::setCertificates()
void AndroidBuildApkWidget::updateSigningWarning()
{
- bool nonRelease = m_step->buildConfiguration()->buildType() != BuildConfiguration::Release;
+ bool nonRelease = m_step->buildType() != BuildConfiguration::Release;
bool visible = m_step->signPackage() && nonRelease;
m_signingDebugWarningLabel->setVisible(visible);
}
diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp
index 000cc35399..4ea7fc6bd8 100644
--- a/src/plugins/android/androidconfigurations.cpp
+++ b/src/plugins/android/androidconfigurations.cpp
@@ -112,7 +112,6 @@ namespace {
const QLatin1String KeystoreLocationKey("KeystoreLocation");
const QLatin1String AutomaticKitCreationKey("AutomatiKitCreation");
const QLatin1String PartitionSizeKey("PartitionSize");
- const QLatin1String ToolchainHostKey("ToolchainHost");
const QLatin1String ArmToolchainPrefix("arm-linux-androideabi");
const QLatin1String X86ToolchainPrefix("x86");
@@ -439,7 +438,7 @@ bool AndroidConfig::isCmdlineSdkToolsInstalled() const
FilePath AndroidConfig::adbToolPath() const
{
- return m_sdkLocation.pathAppended("platform-tools/adb" QTC_HOST_EXE_SUFFIX);
+ return m_sdkLocation / "platform-tools/adb" QTC_HOST_EXE_SUFFIX;
}
FilePath AndroidConfig::androidToolPath() const
@@ -447,12 +446,12 @@ FilePath AndroidConfig::androidToolPath() const
if (HostOsInfo::isWindowsHost()) {
// I want to switch from using android.bat to using an executable. All it really does is call
// Java and I've made some progress on it. So if android.exe exists, return that instead.
- const FilePath path = m_sdkLocation.pathAppended("tools/android" QTC_HOST_EXE_SUFFIX);
+ const FilePath path = m_sdkLocation / "tools/android" QTC_HOST_EXE_SUFFIX;
if (path.exists())
return path;
- return m_sdkLocation.pathAppended("tools/android" ANDROID_BAT_SUFFIX);
+ return m_sdkLocation / "tools/android" ANDROID_BAT_SUFFIX;
}
- return m_sdkLocation.pathAppended("tools/android");
+ return m_sdkLocation / "tools/android";
}
FilePath AndroidConfig::emulatorToolPath() const
@@ -460,7 +459,7 @@ FilePath AndroidConfig::emulatorToolPath() const
QString relativePath = "emulator/emulator";
if (sdkToolsVersion() < QVersionNumber(25, 3, 0) && !isCmdlineSdkToolsInstalled())
relativePath = "tools/emulator";
- return m_sdkLocation.pathAppended(relativePath + QTC_HOST_EXE_SUFFIX);
+ return m_sdkLocation / (relativePath + QTC_HOST_EXE_SUFFIX);
}
FilePath AndroidConfig::sdkManagerToolPath() const
@@ -472,7 +471,7 @@ FilePath AndroidConfig::sdkManagerToolPath() const
if (HostOsInfo::isWindowsHost())
toolPath += ANDROID_BAT_SUFFIX;
- const FilePath sdkmanagerPath = m_sdkLocation.pathAppended(toolPath);
+ const FilePath sdkmanagerPath = m_sdkLocation / toolPath;
if (sdkmanagerPath.exists())
return sdkmanagerPath;
}
@@ -489,7 +488,7 @@ FilePath AndroidConfig::avdManagerToolPath() const
if (HostOsInfo::isWindowsHost())
toolPath += ANDROID_BAT_SUFFIX;
- const FilePath sdkmanagerPath = m_sdkLocation.pathAppended(toolPath);
+ const FilePath sdkmanagerPath = m_sdkLocation / toolPath;
if (sdkmanagerPath.exists())
return sdkmanagerPath;
}
@@ -499,16 +498,16 @@ FilePath AndroidConfig::avdManagerToolPath() const
FilePath AndroidConfig::aaptToolPath() const
{
- const Utils::FilePath aaptToolPath = m_sdkLocation.pathAppended("build-tools");
+ const FilePath aaptToolPath = m_sdkLocation / "build-tools";
QString toolPath = QString("%1/aapt").arg(buildToolsVersion().toString());
if (HostOsInfo::isWindowsHost())
toolPath += QTC_HOST_EXE_SUFFIX;
- return aaptToolPath.pathAppended(toolPath);
+ return aaptToolPath / toolPath;
}
FilePath AndroidConfig::toolchainPathFromNdk(const Utils::FilePath &ndkLocation) const
{
- const FilePath toolchainPath = ndkLocation.pathAppended("toolchains/llvm/prebuilt/");
+ const FilePath toolchainPath = ndkLocation / "toolchains/llvm/prebuilt/";
// detect toolchain host
QStringList hostPatterns;
@@ -528,7 +527,7 @@ FilePath AndroidConfig::toolchainPathFromNdk(const Utils::FilePath &ndkLocation)
QDirIterator iter(toolchainPath.toString(), hostPatterns, QDir::Dirs);
if (iter.hasNext()) {
iter.next();
- return toolchainPath.pathAppended(iter.fileName());
+ return toolchainPath / iter.fileName();
}
return {};
@@ -544,7 +543,7 @@ FilePath AndroidConfig::clangPathFromNdk(const Utils::FilePath &ndkLocation) con
const FilePath path = toolchainPathFromNdk(ndkLocation);
if (path.isEmpty())
return {};
- return path.pathAppended(HostOsInfo::withExecutableSuffix("bin/clang"));
+ return path / HostOsInfo::withExecutableSuffix("bin/clang");
}
FilePath AndroidConfig::clangPath(const BaseQtVersion *qtVersion) const
@@ -879,9 +878,9 @@ QVersionNumber AndroidConfig::sdkToolsVersion() const
if (m_sdkLocation.exists()) {
FilePath sdkToolsPropertiesPath;
if (isCmdlineSdkToolsInstalled())
- sdkToolsPropertiesPath = m_sdkLocation.pathAppended("cmdline-tools/latest/source.properties");
+ sdkToolsPropertiesPath = m_sdkLocation / "cmdline-tools/latest/source.properties";
else
- sdkToolsPropertiesPath = m_sdkLocation.pathAppended("tools/source.properties");
+ sdkToolsPropertiesPath = m_sdkLocation / "tools/source.properties";
QSettings settings(sdkToolsPropertiesPath.toString(), QSettings::IniFormat);
auto versionStr = settings.value(sdkToolsVersionKey).toString();
version = QVersionNumber::fromString(versionStr);
@@ -894,7 +893,7 @@ QVersionNumber AndroidConfig::buildToolsVersion() const
//TODO: return version according to qt version
QVersionNumber maxVersion;
QDir buildToolsDir(m_sdkLocation.pathAppended("build-tools").toString());
- for (const QFileInfo &file: buildToolsDir.entryList(QDir::Dirs|QDir::NoDotAndDotDot))
+ for (const QFileInfo &file: buildToolsDir.entryInfoList(QDir::Dirs|QDir::NoDotAndDotDot))
maxVersion = qMax(maxVersion, QVersionNumber::fromString(file.fileName()));
return maxVersion;
}
@@ -919,31 +918,6 @@ FilePath AndroidConfig::defaultNdkLocation() const
return sdkLocation().pathAppended(m_defaultSdkDepends.ndkPath);
}
-static inline QString gdbServerArch(const QString &androidAbi)
-{
- if (androidAbi == "arm64-v8a") {
- return QString("arm64");
- } else if (androidAbi == "armeabi-v7a") {
- return QString("arm");
- } else if (androidAbi == "x86_64") {
- return QString("x86_64");
- } else if (androidAbi == "x86") {
- return QString("x86");
- } else {
- return {};
- }
-}
-
-FilePath AndroidConfig::gdbServer(const QString &androidAbi, const BaseQtVersion *qtVersion) const
-{
- const FilePath path = AndroidConfigurations::currentConfig().ndkLocation(qtVersion)
- .pathAppended(QString("prebuilt/android-%1/gdbserver/gdbserver")
- .arg(gdbServerArch(androidAbi)));
- if (path.exists())
- return path;
- return {};
-}
-
QVersionNumber AndroidConfig::ndkVersion(const BaseQtVersion *qtVersion) const
{
return ndkVersion(ndkLocation(qtVersion));
@@ -1400,9 +1374,9 @@ void AndroidConfigurations::updateAutomaticKitList()
if (qt != QtSupport::QtKitAspect::qtVersion(b))
return false;
return matchToolChain(toolChainForLanguage[ProjectExplorer::Constants::CXX_LANGUAGE_ID],
- ToolChainKitAspect::toolChain(b, ProjectExplorer::Constants::CXX_LANGUAGE_ID))
+ ToolChainKitAspect::cxxToolChain(b))
&& matchToolChain(toolChainForLanguage[ProjectExplorer::Constants::C_LANGUAGE_ID],
- ToolChainKitAspect::toolChain(b, ProjectExplorer::Constants::C_LANGUAGE_ID));
+ ToolChainKitAspect::cToolChain(b));
});
const auto initializeKit = [allLanguages, device, tc, qt](Kit *k) {
diff --git a/src/plugins/android/androidconfigurations.h b/src/plugins/android/androidconfigurations.h
index a6f6c5d4a2..93a037cd0a 100644
--- a/src/plugins/android/androidconfigurations.h
+++ b/src/plugins/android/androidconfigurations.h
@@ -124,7 +124,6 @@ public:
Utils::FilePath ndkLocation(const QtSupport::BaseQtVersion *qtVersion) const;
Utils::FilePath defaultNdkLocation() const;
- Utils::FilePath gdbServer(const QString &androidAbi, const QtSupport::BaseQtVersion *qtVersion) const;
QVersionNumber ndkVersion(const QtSupport::BaseQtVersion *qtVersion) const;
QVersionNumber ndkVersion(const Utils::FilePath &ndkPath) const;
diff --git a/src/plugins/android/androiddebugsupport.cpp b/src/plugins/android/androiddebugsupport.cpp
index 3ffed5e7ec..dc58202daa 100644
--- a/src/plugins/android/androiddebugsupport.cpp
+++ b/src/plugins/android/androiddebugsupport.cpp
@@ -55,6 +55,7 @@ static Q_LOGGING_CATEGORY(androidDebugSupportLog, "qtc.android.run.androiddebugs
using namespace Debugger;
using namespace ProjectExplorer;
+using namespace Utils;
namespace Android {
namespace Internal {
@@ -105,6 +106,7 @@ AndroidDebugSupport::AndroidDebugSupport(RunControl *runControl, const QString &
: Debugger::DebuggerRunTool(runControl)
{
setId("AndroidDebugger");
+ setLldbPlatform("remote-android");
m_runner = new AndroidRunner(runControl, intentName);
addStartDependency(m_runner);
}
@@ -123,8 +125,10 @@ void AndroidDebugSupport::start()
qCDebug(androidDebugSupportLog) << "Start. Package name: " << packageName
<< "PID: " << m_runner->pid().pid();
QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitAspect::qtVersion(kit);
- if (!Utils::HostOsInfo::isWindowsHost() &&
- AndroidConfigurations::currentConfig().ndkVersion(qtVersion) >= QVersionNumber(11, 0, 0)) {
+ if (!Utils::HostOsInfo::isWindowsHost()
+ && (qtVersion
+ && AndroidConfigurations::currentConfig().ndkVersion(qtVersion)
+ >= QVersionNumber(11, 0, 0))) {
qCDebug(androidDebugSupportLog) << "UseTargetAsync: " << true;
setUseTargetAsync(true);
}
@@ -146,25 +150,33 @@ void AndroidDebugSupport::start()
setUseExtendedRemote(true);
QString devicePreferredAbi = AndroidManager::apkDevicePreferredAbi(target);
setAbi(AndroidManager::androidAbi2Abi(devicePreferredAbi));
- QUrl gdbServer;
- gdbServer.setHost(QHostAddress(QHostAddress::LocalHost).toString());
- gdbServer.setPort(m_runner->gdbServerPort().number());
- setRemoteChannel(gdbServer);
+
+ QUrl debugServer;
+ debugServer.setPort(m_runner->debugServerPort().number());
+ if (cppEngineType() == LldbEngineType) {
+ debugServer.setScheme("adb");
+ debugServer.setHost(AndroidManager::deviceSerialNumber(target));
+ setRemoteChannel(debugServer.toString());
+ } else {
+ debugServer.setHost(QHostAddress(QHostAddress::LocalHost).toString());
+ setRemoteChannel(debugServer);
+ }
auto qt = static_cast<AndroidQtVersion *>(qtVersion);
- QTC_CHECK(qt);
const int minimumNdk = qt ? qt->minimumNDK() : 0;
int sdkVersion = qMax(AndroidManager::minimumSDK(kit), minimumNdk);
// TODO find a way to use the new sysroot layout
// instead ~/android/ndk-bundle/platforms/android-29/arch-arm64
// use ~/android/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64/sysroot
- Utils::FilePath sysRoot = AndroidConfigurations::currentConfig().ndkLocation(qtVersion)
- .pathAppended("platforms")
- .pathAppended(QString("android-%1").arg(sdkVersion))
- .pathAppended(devicePreferredAbi);
- setSysRoot(sysRoot);
- qCDebug(androidDebugSupportLog) << "Sysroot: " << sysRoot;
+ if (qtVersion) {
+ Utils::FilePath sysRoot = AndroidConfigurations::currentConfig().ndkLocation(qtVersion)
+ / "platforms"
+ / QString("android-%1").arg(sdkVersion)
+ / devicePreferredAbi;
+ setSysRoot(sysRoot);
+ qCDebug(androidDebugSupportLog) << "Sysroot: " << sysRoot;
+ }
}
if (isQmlDebugging()) {
qCDebug(androidDebugSupportLog) << "QML debugging enabled. QML server: "
diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp
index f3863ca998..bac9e4ff49 100644
--- a/src/plugins/android/androiddeployqtstep.cpp
+++ b/src/plugins/android/androiddeployqtstep.cpp
@@ -178,7 +178,7 @@ bool AndroidDeployQtStep::init()
RunConfiguration *rc = target()->activeRunConfiguration();
QTC_ASSERT(rc, return false);
- ProjectExplorer::BuildConfiguration *bc = buildConfiguration();
+ BuildConfiguration *bc = target()->activeBuildConfiguration();
QTC_ASSERT(bc, return false);
auto androidBuildApkStep = bc->buildSteps()->firstOfType<AndroidBuildApkStep>();
@@ -222,7 +222,8 @@ bool AndroidDeployQtStep::init()
m_useAndroiddeployqt = version->qtVersion() >= QtSupport::QtVersionNumber(5, 4, 0);
if (m_useAndroiddeployqt) {
- const ProjectNode *node = target()->project()->findNodeForBuildKey(rc->buildKey());
+ const QString buildKey = target()->activeBuildKey();
+ const ProjectNode *node = target()->project()->findNodeForBuildKey(buildKey);
if (!node)
return false;
m_apkPath = Utils::FilePath::fromString(node->data(Constants::AndroidApk).toString());
@@ -469,7 +470,7 @@ bool AndroidDeployQtStep::runImpl()
void AndroidDeployQtStep::gatherFilesToPull()
{
m_filesToPull.clear();
- ProjectExplorer::BuildConfiguration *bc = buildConfiguration();
+ BuildConfiguration *bc = target()->activeBuildConfiguration();
QString buildDir = bc ? bc->buildDirectory().toString() : QString();
if (bc && !buildDir.endsWith("/")) {
buildDir += "/";
diff --git a/src/plugins/android/androidextralibrarylistmodel.cpp b/src/plugins/android/androidextralibrarylistmodel.cpp
index 3a168eca4a..7ade7405a8 100644
--- a/src/plugins/android/androidextralibrarylistmodel.cpp
+++ b/src/plugins/android/androidextralibrarylistmodel.cpp
@@ -29,27 +29,32 @@
#include <android/androidconstants.h>
#include <android/androidmanager.h>
+#include <projectexplorer/buildsystem.h>
#include <projectexplorer/project.h>
#include <projectexplorer/projectnodes.h>
#include <projectexplorer/runconfiguration.h>
#include <projectexplorer/target.h>
+#include <utils/qtcassert.h>
+
using namespace ProjectExplorer;
namespace Android {
-AndroidExtraLibraryListModel::AndroidExtraLibraryListModel(ProjectExplorer::Target *target,
+AndroidExtraLibraryListModel::AndroidExtraLibraryListModel(BuildSystem *buildSystem,
QObject *parent)
: QAbstractItemModel(parent),
- m_target(target)
+ m_buildSystem(buildSystem)
{
updateModel();
- connect(target, &Target::parsingStarted,
+ connect(buildSystem, &BuildSystem::parsingStarted,
this, &AndroidExtraLibraryListModel::updateModel);
- connect(target, &Target::parsingFinished,
+ connect(buildSystem, &BuildSystem::parsingFinished,
this, &AndroidExtraLibraryListModel::updateModel);
- connect(target, &Target::activeRunConfigurationChanged,
+ // Causes target()->activeBuildKey() result and consequently the node data
+ // extracted below to change.
+ connect(buildSystem->target(), &Target::activeRunConfigurationChanged,
this, &AndroidExtraLibraryListModel::updateModel);
}
@@ -83,10 +88,8 @@ QVariant AndroidExtraLibraryListModel::data(const QModelIndex &index, int role)
void AndroidExtraLibraryListModel::updateModel()
{
- RunConfiguration *rc = m_target->activeRunConfiguration();
- QTC_ASSERT(rc, return);
-
- const ProjectNode *node = m_target->project()->findNodeForBuildKey(rc->buildKey());
+ const QString buildKey = m_buildSystem->target()->activeBuildKey();
+ const ProjectNode *node = m_buildSystem->target()->project()->findNodeForBuildKey(buildKey);
if (!node)
return;
@@ -112,10 +115,8 @@ void AndroidExtraLibraryListModel::updateModel()
void AndroidExtraLibraryListModel::addEntries(const QStringList &list)
{
- RunConfiguration *rc = m_target->activeRunConfiguration();
- QTC_ASSERT(rc, return);
-
- const ProjectNode *node = m_target->project()->findNodeForBuildKey(rc->buildKey());
+ const QString buildKey = m_buildSystem->target()->activeBuildKey();
+ const ProjectNode *node = m_buildSystem->target()->project()->findNodeForBuildKey(buildKey);
QTC_ASSERT(node, return);
beginInsertRows(QModelIndex(), m_entries.size(), m_entries.size() + list.size());
@@ -124,7 +125,7 @@ void AndroidExtraLibraryListModel::addEntries(const QStringList &list)
for (const QString &path : list)
m_entries += "$$PWD/" + dir.relativeFilePath(path);
- node->setData(Constants::AndroidExtraLibs, m_entries);
+ m_buildSystem->setExtraData(buildKey, Constants::AndroidExtraLibs, m_entries);
endInsertRows();
}
@@ -154,11 +155,8 @@ void AndroidExtraLibraryListModel::removeEntries(QModelIndexList list)
endRemoveRows();
}
- RunConfiguration *rc = m_target->activeRunConfiguration();
- QTC_ASSERT(rc, return);
- const ProjectNode *node = m_target->project()->findNodeForBuildKey(rc->buildKey());
- QTC_ASSERT(node, return);
- node->setData(Constants::AndroidExtraLibs, m_entries);
+ const QString buildKey = m_buildSystem->target()->activeBuildKey();
+ m_buildSystem->setExtraData(buildKey, Constants::AndroidExtraLibs, m_entries);
}
} // Android
diff --git a/src/plugins/android/androidextralibrarylistmodel.h b/src/plugins/android/androidextralibrarylistmodel.h
index bbd21ce815..0856b32ce7 100644
--- a/src/plugins/android/androidextralibrarylistmodel.h
+++ b/src/plugins/android/androidextralibrarylistmodel.h
@@ -31,19 +31,16 @@
#include <QAbstractItemModel>
#include <QStringList>
-namespace ProjectExplorer {
-class RunConfiguration;
-class Target;
-}
+namespace ProjectExplorer { class BuildSystem; }
namespace Android {
class ANDROID_EXPORT AndroidExtraLibraryListModel : public QAbstractItemModel
{
Q_OBJECT
+
public:
- explicit AndroidExtraLibraryListModel(ProjectExplorer::Target *target,
- QObject *parent = nullptr);
+ AndroidExtraLibraryListModel(ProjectExplorer::BuildSystem *buildSystem, QObject *parent);
QModelIndex index(int row, int column, const QModelIndex &parent) const override;
QModelIndex parent(const QModelIndex &child) const override;
@@ -60,7 +57,7 @@ signals:
private:
void updateModel();
- ProjectExplorer::Target *m_target;
+ ProjectExplorer::BuildSystem *m_buildSystem;
QStringList m_entries;
};
diff --git a/src/plugins/android/androidmanager.cpp b/src/plugins/android/androidmanager.cpp
index 4fd6c7504b..04b85d2beb 100644
--- a/src/plugins/android/androidmanager.cpp
+++ b/src/plugins/android/androidmanager.cpp
@@ -68,63 +68,59 @@
#include <QRegularExpression>
#include <QVersionNumber>
-namespace {
- const QLatin1String AndroidManifestName("AndroidManifest.xml");
- const QLatin1String AndroidDefaultPropertiesName("project.properties");
- const QLatin1String AndroidDeviceSn("AndroidDeviceSerialNumber");
- const QLatin1String AndroidDeviceAbis("AndroidDeviceAbis");
- const QLatin1String ApiLevelKey("AndroidVersion.ApiLevel");
- const QString packageNameRegEx("(?<token>package: )(.*?)(name=)'(?<target>.*?)'");
- const QString activityRegEx("(?<token>launchable-activity: )(.*?)(name=)'(?<target>.*?)'");
- const QString apkVersionRegEx("(?<token>package: )(.*?)(versionCode=)'(?<target>.*?)'");
- const QString versionCodeRegEx("(?<token>versionCode=)(?<version>\\d*)");
- const QString qtcSignature("This file is generated by QtCreator to be read by androiddeployqt and should not be modified by hand.");
-
- static Q_LOGGING_CATEGORY(androidManagerLog, "qtc.android.androidManager", QtWarningMsg)
-
- QString parseAaptOutput(const QString &output, const QString &regEx) {
- const QRegularExpression regRx(regEx,
- QRegularExpression::CaseInsensitiveOption |
- QRegularExpression::MultilineOption);
- QRegularExpressionMatch match = regRx.match(output);
- if (match.hasMatch())
- return match.captured("target");
- return QString();
- };
-} // anonymous namespace
-
-
using namespace ProjectExplorer;
using namespace Utils;
+using namespace Android::Internal;
+
namespace Android {
-using namespace Internal;
+const QLatin1String AndroidManifestName("AndroidManifest.xml");
+const QLatin1String AndroidDefaultPropertiesName("project.properties");
+const QLatin1String AndroidDeviceSn("AndroidDeviceSerialNumber");
+const QLatin1String AndroidDeviceAbis("AndroidDeviceAbis");
+const QLatin1String ApiLevelKey("AndroidVersion.ApiLevel");
+const QString packageNameRegEx("(?<token>package: )(.*?)(name=)'(?<target>.*?)'");
+const QString activityRegEx("(?<token>launchable-activity: )(.*?)(name=)'(?<target>.*?)'");
+const QString apkVersionRegEx("(?<token>package: )(.*?)(versionCode=)'(?<target>.*?)'");
+const QString versionCodeRegEx("(?<token>versionCode=)(?<version>\\d*)");
+const QString qtcSignature("This file is generated by QtCreator to be read by androiddeployqt and should not be modified by hand.");
+
+static Q_LOGGING_CATEGORY(androidManagerLog, "qtc.android.androidManager", QtWarningMsg)
+
+static QString parseAaptOutput(const QString &output, const QString &regEx)
+{
+ const QRegularExpression regRx(regEx,
+ QRegularExpression::CaseInsensitiveOption |
+ QRegularExpression::MultilineOption);
+ QRegularExpressionMatch match = regRx.match(output);
+ if (match.hasMatch())
+ return match.captured("target");
+ return QString();
+}
class Library
{
public:
- Library()
- { level = -1; }
- int level;
+ int level = -1;
QStringList dependencies;
QString name;
};
using LibrariesMap = QMap<QString, Library>;
-static bool openXmlFile(QDomDocument &doc, const Utils::FilePath &fileName);
-static bool openManifest(ProjectExplorer::Target *target, QDomDocument &doc);
+static bool openXmlFile(QDomDocument &doc, const FilePath &fileName);
+static bool openManifest(const Target *target, QDomDocument &doc);
static int parseMinSdk(const QDomElement &manifestElem);
-static const ProjectNode *currentProjectNode(Target *target)
+static const ProjectNode *currentProjectNode(const Target *target)
{
if (RunConfiguration *rc = target->activeRunConfiguration())
return target->project()->findNodeForBuildKey(rc->buildKey());
return nullptr;
}
-QString AndroidManager::packageName(ProjectExplorer::Target *target)
+QString AndroidManager::packageName(const Target *target)
{
QDomDocument doc;
if (!openManifest(target, doc))
@@ -133,7 +129,7 @@ QString AndroidManager::packageName(ProjectExplorer::Target *target)
return manifestElem.attribute(QLatin1String("package"));
}
-QString AndroidManager::packageName(const Utils::FilePath &manifestFile)
+QString AndroidManager::packageName(const FilePath &manifestFile)
{
QDomDocument doc;
if (!openXmlFile(doc, manifestFile))
@@ -178,10 +174,10 @@ int AndroidManager::packageVersionCode(const QString &deviceSerial,
return -1;
}
-void AndroidManager::apkInfo(const Utils::FilePath &apkPath,
- QString *packageName,
- int *version,
- QString *activityPath)
+void AndroidManager::apkInfo(const FilePath &apkPath,
+ QString *packageName,
+ int *version,
+ QString *activityPath)
{
SdkToolResult result;
result = runAaptCommand({"dump", "badging", apkPath.toString()});
@@ -205,12 +201,7 @@ void AndroidManager::apkInfo(const Utils::FilePath &apkPath,
}
}
-QString AndroidManager::intentName(ProjectExplorer::Target *target)
-{
- return packageName(target) + QLatin1Char('/') + activityName(target);
-}
-
-QString AndroidManager::activityName(ProjectExplorer::Target *target)
+QString AndroidManager::activityName(const Target *target)
{
QDomDocument doc;
if (!openManifest(target, doc))
@@ -224,7 +215,7 @@ QString AndroidManager::activityName(ProjectExplorer::Target *target)
of the kit is returned if the manifest file of the APK cannot be found
or parsed.
*/
-int AndroidManager::minimumSDK(ProjectExplorer::Target *target)
+int AndroidManager::minimumSDK(const Target *target)
{
QDomDocument doc;
if (!openXmlFile(doc, AndroidManager::manifestSourcePath(target)))
@@ -236,12 +227,12 @@ int AndroidManager::minimumSDK(ProjectExplorer::Target *target)
Returns the minimum Android API level required by the kit to compile. -1 is
returned if the kit does not support Android.
*/
-int AndroidManager::minimumSDK(const ProjectExplorer::Kit *kit)
+int AndroidManager::minimumSDK(const Kit *kit)
{
int minSDKVersion = -1;
QtSupport::BaseQtVersion *version = QtSupport::QtKitAspect::qtVersion(kit);
if (version && version->targetDeviceTypes().contains(Constants::ANDROID_DEVICE_TYPE)) {
- Utils::FilePath stockManifestFilePath = Utils::FilePath::fromUserInput(
+ FilePath stockManifestFilePath = FilePath::fromUserInput(
version->prefix().toString() + "/src/android/templates/AndroidManifest.xml");
QDomDocument doc;
if (openXmlFile(doc, stockManifestFilePath)) {
@@ -251,7 +242,7 @@ int AndroidManager::minimumSDK(const ProjectExplorer::Kit *kit)
return minSDKVersion;
}
-QString AndroidManager::buildTargetSDK(ProjectExplorer::Target *target)
+QString AndroidManager::buildTargetSDK(const Target *target)
{
if (auto bc = target->activeBuildConfiguration()) {
if (auto androidBuildApkStep = bc->buildSteps()->firstOfType<AndroidBuildApkStep>())
@@ -287,7 +278,7 @@ QJsonObject AndroidManager::deploymentSettings(const Target *target)
if (!qt)
return {};
- auto tc = ProjectExplorer::ToolChainKitAspect::toolChain(target->kit(), ProjectExplorer::Constants::CXX_LANGUAGE_ID);
+ auto tc = ToolChainKitAspect::cxxToolChain(target->kit());
if (!tc || tc->typeId() != Constants::ANDROID_TOOLCHAIN_TYPEID)
return {};
QJsonObject settings;
@@ -298,10 +289,10 @@ QJsonObject AndroidManager::deploymentSettings(const Target *target)
if (qt->qtVersion() < QtSupport::QtVersionNumber(5, 14, 0)) {
const QStringList abis = applicationAbis(target);
QTC_ASSERT(abis.size() == 1, return {});
- settings["stdcpp-path"] = AndroidConfigurations::currentConfig().toolchainPath(qt)
- .pathAppended("sysroot/usr/lib/")
- .pathAppended(archTriplet(abis.first()))
- .pathAppended("libc++_shared.so").toString();
+ settings["stdcpp-path"] = (AndroidConfigurations::currentConfig().toolchainPath(qt)
+ / "sysroot/usr/lib/"
+ / archTriplet(abis.first())
+ / "libc++_shared.so").toString();
} else {
settings["stdcpp-path"] = AndroidConfigurations::currentConfig()
.toolchainPath(qt)
@@ -323,23 +314,23 @@ bool AndroidManager::isQtCreatorGenerated(const FilePath &deploymentFile)
return QJsonDocument::fromJson(f.readAll()).object()["_description"].toString() == qtcSignature;
}
-Utils::FilePath AndroidManager::dirPath(const ProjectExplorer::Target *target)
+FilePath AndroidManager::dirPath(const Target *target)
{
if (auto *bc = target->activeBuildConfiguration())
- return bc->buildDirectory().pathAppended(Constants::ANDROID_BUILDDIRECTORY);
- return Utils::FilePath();
+ return bc->buildDirectory() / Constants::ANDROID_BUILDDIRECTORY;
+ return {};
}
-Utils::FilePath AndroidManager::apkPath(const ProjectExplorer::Target *target)
+FilePath AndroidManager::apkPath(const Target *target)
{
- QTC_ASSERT(target, return Utils::FilePath());
+ QTC_ASSERT(target, return {});
auto bc = target->activeBuildConfiguration();
if (!bc)
return {};
auto buildApkStep = bc->buildSteps()->firstOfType<AndroidBuildApkStep>();
if (!buildApkStep)
- return Utils::FilePath();
+ return {};
QString apkPath("build/outputs/apk/android-build-");
if (buildApkStep->signPackage())
@@ -347,7 +338,7 @@ Utils::FilePath AndroidManager::apkPath(const ProjectExplorer::Target *target)
else
apkPath += QLatin1String("debug.apk");
- return dirPath(target).pathAppended(apkPath);
+ return dirPath(target) / apkPath;
}
bool AndroidManager::matchedAbis(const QStringList &deviceAbis, const QStringList &appAbis)
@@ -403,7 +394,7 @@ Abi AndroidManager::androidAbi2Abi(const QString &androidAbi)
}
}
-Utils::FilePath AndroidManager::manifestSourcePath(ProjectExplorer::Target *target)
+FilePath AndroidManager::manifestSourcePath(const Target *target)
{
if (const ProjectNode *node = currentProjectNode(target)) {
const QString packageSource
@@ -417,7 +408,7 @@ Utils::FilePath AndroidManager::manifestSourcePath(ProjectExplorer::Target *targ
return manifestPath(target);
}
-Utils::FilePath AndroidManager::manifestPath(ProjectExplorer::Target *target)
+FilePath AndroidManager::manifestPath(const Target *target)
{
QVariant manifest = target->namedSettings(AndroidManifestName);
if (manifest.isValid())
@@ -430,24 +421,24 @@ void AndroidManager::setManifestPath(Target *target, const FilePath &path)
target->setNamedSettings(AndroidManifestName, QVariant::fromValue(path));
}
-Utils::FilePath AndroidManager::defaultPropertiesPath(ProjectExplorer::Target *target)
+FilePath AndroidManager::defaultPropertiesPath(const Target *target)
{
return dirPath(target).pathAppended(AndroidDefaultPropertiesName);
}
-QString AndroidManager::deviceSerialNumber(ProjectExplorer::Target *target)
+QString AndroidManager::deviceSerialNumber(const Target *target)
{
return target->namedSettings(AndroidDeviceSn).toString();
}
-void AndroidManager::setDeviceSerialNumber(ProjectExplorer::Target *target, const QString &deviceSerialNumber)
+void AndroidManager::setDeviceSerialNumber(Target *target, const QString &deviceSerialNumber)
{
qCDebug(androidManagerLog) << "Device serial for the target changed"
<< target->displayName() << deviceSerialNumber;
target->setNamedSettings(AndroidDeviceSn, deviceSerialNumber);
}
-static QString preferredAbi(const QStringList &appAbis, Target *target)
+static QString preferredAbi(const QStringList &appAbis, const Target *target)
{
const auto deviceAbis = target->namedSettings(AndroidDeviceAbis).toStringList();
for (const auto &abi : deviceAbis) {
@@ -457,7 +448,7 @@ static QString preferredAbi(const QStringList &appAbis, Target *target)
return {};
}
-QString AndroidManager::apkDevicePreferredAbi(Target *target)
+QString AndroidManager::apkDevicePreferredAbi(const Target *target)
{
auto libsPath = dirPath(target).pathAppended("libs");
QStringList apkAbis;
@@ -467,17 +458,17 @@ QString AndroidManager::apkDevicePreferredAbi(Target *target)
return preferredAbi(apkAbis, target);
}
-void AndroidManager::setDeviceAbis(ProjectExplorer::Target *target, const QStringList &deviceAbis)
+void AndroidManager::setDeviceAbis(Target *target, const QStringList &deviceAbis)
{
target->setNamedSettings(AndroidDeviceAbis, deviceAbis);
}
-int AndroidManager::deviceApiLevel(ProjectExplorer::Target *target)
+int AndroidManager::deviceApiLevel(const Target *target)
{
return target->namedSettings(ApiLevelKey).toInt();
}
-void AndroidManager::setDeviceApiLevel(ProjectExplorer::Target *target, int level)
+void AndroidManager::setDeviceApiLevel(Target *target, int level)
{
qCDebug(androidManagerLog) << "Device API level for the target changed"
<< target->displayName() << level;
@@ -547,7 +538,7 @@ QString AndroidManager::androidNameForApiLevel(int x)
case 30:
return QLatin1String("Android 11");
default:
- return tr("Unknown Android version. API Level: %1").arg(QString::number(x));
+ return tr("Unknown Android version. API Level: %1").arg(x);
}
}
@@ -556,7 +547,7 @@ static void raiseError(const QString &reason)
QMessageBox::critical(nullptr, AndroidManager::tr("Error creating Android templates."), reason);
}
-static bool openXmlFile(QDomDocument &doc, const Utils::FilePath &fileName)
+static bool openXmlFile(QDomDocument &doc, const FilePath &fileName)
{
QFile f(fileName.toString());
if (!f.open(QIODevice::ReadOnly))
@@ -569,7 +560,7 @@ static bool openXmlFile(QDomDocument &doc, const Utils::FilePath &fileName)
return true;
}
-static bool openManifest(ProjectExplorer::Target *target, QDomDocument &doc)
+static bool openManifest(const Target *target, QDomDocument &doc)
{
return openXmlFile(doc, AndroidManager::manifestPath(target));
}
@@ -588,7 +579,7 @@ static int parseMinSdk(const QDomElement &manifestElem)
return 0;
}
-void AndroidManager::installQASIPackage(ProjectExplorer::Target *target, const QString &packagePath)
+void AndroidManager::installQASIPackage(Target *target, const QString &packagePath)
{
const QStringList appAbis = AndroidManager::applicationAbis(target);
if (appAbis.isEmpty())
@@ -621,7 +612,7 @@ bool AndroidManager::checkKeystorePassword(const QString &keystorePath, const QS
SynchronousProcess proc;
proc.setTimeoutS(10);
SynchronousProcessResponse response = proc.run(cmd);
- return (response.result == Utils::SynchronousProcessResponse::Finished && response.exitCode == 0);
+ return (response.result == SynchronousProcessResponse::Finished && response.exitCode == 0);
}
bool AndroidManager::checkCertificatePassword(const QString &keystorePath, const QString &keystorePasswd, const QString &alias, const QString &certificatePasswd)
@@ -717,7 +708,7 @@ static bool mergeGradleProperties(const QString &path, GradleProperties properti
}
-bool AndroidManager::updateGradleProperties(ProjectExplorer::Target *target, const QString &buildKey)
+bool AndroidManager::updateGradleProperties(Target *target, const QString &buildKey)
{
QtSupport::BaseQtVersion *version = QtSupport::QtKitAspect::qtVersion(target->kit());
if (!version)
@@ -743,7 +734,7 @@ bool AndroidManager::updateGradleProperties(ProjectExplorer::Target *target, con
if (!packageSourceDir.exists())
return false;
- const FilePath wrapperProps = packageSourceDir.pathAppended("gradle/wrapper/gradle-wrapper.properties");
+ const FilePath wrapperProps = packageSourceDir / "gradle/wrapper/gradle-wrapper.properties";
if (wrapperProps.exists()) {
GradleProperties wrapperProperties = readGradleProperties(wrapperProps.toString());
QString distributionUrl = QString::fromLocal8Bit(wrapperProperties["distributionUrl"]);
@@ -756,7 +747,7 @@ bool AndroidManager::updateGradleProperties(ProjectExplorer::Target *target, con
GradleProperties localProperties;
localProperties["sdk.dir"] = AndroidConfigurations::currentConfig().sdkLocation().toString().toLocal8Bit();
- const FilePath localPropertiesFile = packageSourceDir.pathAppended("local.properties");
+ const FilePath localPropertiesFile = packageSourceDir / "local.properties";
if (!mergeGradleProperties(localPropertiesFile.toString(), localProperties))
return false;
@@ -775,10 +766,10 @@ bool AndroidManager::updateGradleProperties(ProjectExplorer::Target *target, con
return mergeGradleProperties(gradlePropertiesPath, gradleProperties);
}
-int AndroidManager::findApiLevel(const Utils::FilePath &platformPath)
+int AndroidManager::findApiLevel(const FilePath &platformPath)
{
int apiLevel = -1;
- const Utils::FilePath propertiesPath = platformPath.pathAppended("/source.properties");
+ const FilePath propertiesPath = platformPath / "/source.properties";
if (propertiesPath.exists()) {
QSettings sdkProperties(propertiesPath.toString(), QSettings::IniFormat);
bool validInt = false;
@@ -817,13 +808,13 @@ SdkToolResult AndroidManager::runCommand(const CommandLine &command,
const QByteArray &writeData, int timeoutS)
{
Android::SdkToolResult cmdResult;
- Utils::SynchronousProcess cmdProc;
+ SynchronousProcess cmdProc;
cmdProc.setTimeoutS(timeoutS);
qCDebug(androidManagerLog) << "Running command (sync):" << command.toUserOutput();
SynchronousProcessResponse response = cmdProc.run(command, writeData);
cmdResult.m_stdOut = response.stdOut().trimmed();
cmdResult.m_stdErr = response.stdErr().trimmed();
- cmdResult.m_success = response.result == Utils::SynchronousProcessResponse::Finished;
+ cmdResult.m_success = response.result == SynchronousProcessResponse::Finished;
qCDebug(androidManagerLog) << "Running command (sync) finshed:" << command.toUserOutput()
<< "Success:" << cmdResult.m_success
<< "Output:" << response.allRawOutput();
diff --git a/src/plugins/android/androidmanager.h b/src/plugins/android/androidmanager.h
index e141636c17..f38469a3c7 100644
--- a/src/plugins/android/androidmanager.h
+++ b/src/plugins/android/androidmanager.h
@@ -70,7 +70,7 @@ class ANDROID_EXPORT AndroidManager : public QObject
Q_OBJECT
public:
- static QString packageName(ProjectExplorer::Target *target);
+ static QString packageName(const ProjectExplorer::Target *target);
static QString packageName(const Utils::FilePath &manifestFile);
static bool packageInstalled(const QString &deviceSerial, const QString &packageName);
static int packageVersionCode(const QString &deviceSerial, const QString &packageName);
@@ -78,31 +78,30 @@ public:
QString *packageName = nullptr,
int *version = nullptr,
QString *activityPath = nullptr);
- static QString intentName(ProjectExplorer::Target *target);
- static QString activityName(ProjectExplorer::Target *target);
+ static QString activityName(const ProjectExplorer::Target *target);
- static QString deviceSerialNumber(ProjectExplorer::Target *target);
+ static QString deviceSerialNumber(const ProjectExplorer::Target *target);
static void setDeviceSerialNumber(ProjectExplorer::Target *target, const QString &deviceSerialNumber);
- static QString apkDevicePreferredAbi(ProjectExplorer::Target *target);
+ static QString apkDevicePreferredAbi(const ProjectExplorer::Target *target);
static void setDeviceAbis(ProjectExplorer::Target *target, const QStringList &deviceAbis);
- static int deviceApiLevel(ProjectExplorer::Target *target);
+ static int deviceApiLevel(const ProjectExplorer::Target *target);
static void setDeviceApiLevel(ProjectExplorer::Target *target, int level);
- static QString buildTargetSDK(ProjectExplorer::Target *target);
+ static QString buildTargetSDK(const ProjectExplorer::Target *target);
- static int minimumSDK(ProjectExplorer::Target *target);
+ static int minimumSDK(const ProjectExplorer::Target *target);
static int minimumSDK(const ProjectExplorer::Kit *kit);
static QStringList applicationAbis(const ProjectExplorer::Target *target);
static QString archTriplet(const QString &abi);
static Utils::FilePath dirPath(const ProjectExplorer::Target *target);
- static Utils::FilePath manifestPath(ProjectExplorer::Target *target);
+ static Utils::FilePath manifestPath(const ProjectExplorer::Target *target);
static void setManifestPath(ProjectExplorer::Target *target, const Utils::FilePath &path);
- static Utils::FilePath manifestSourcePath(ProjectExplorer::Target *target);
- static Utils::FilePath defaultPropertiesPath(ProjectExplorer::Target *target);
+ static Utils::FilePath manifestSourcePath(const ProjectExplorer::Target *target);
+ static Utils::FilePath defaultPropertiesPath(const ProjectExplorer::Target *target);
static Utils::FilePath apkPath(const ProjectExplorer::Target *target);
static bool matchedAbis(const QStringList &deviceAbis, const QStringList &appAbis);
static QString devicePreferredAbi(const QStringList &deviceAbis, const QStringList &appAbis);
@@ -114,7 +113,8 @@ public:
static void installQASIPackage(ProjectExplorer::Target *target, const QString &packagePath);
static bool checkKeystorePassword(const QString &keystorePath, const QString &keystorePasswd);
- static bool checkCertificatePassword(const QString &keystorePath, const QString &keystorePasswd, const QString &alias, const QString &certificatePasswd);
+ static bool checkCertificatePassword(const QString &keystorePath, const QString &keystorePasswd,
+ const QString &alias, const QString &certificatePasswd);
static bool checkCertificateExists(const QString &keystorePath, const QString &keystorePasswd,
const QString &alias);
static bool updateGradleProperties(ProjectExplorer::Target *target, const QString &buildKey);
diff --git a/src/plugins/android/androidmanifesteditoriconcontainerwidget.cpp b/src/plugins/android/androidmanifesteditoriconcontainerwidget.cpp
new file mode 100644
index 0000000000..9a9c01da3e
--- /dev/null
+++ b/src/plugins/android/androidmanifesteditoriconcontainerwidget.cpp
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** 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 "androidmanifesteditoriconcontainerwidget.h"
+#include "androidmanifesteditoriconwidget.h"
+
+#include <utils/utilsicons.h>
+
+#include <QFrame>
+#include <QHBoxLayout>
+
+namespace Android {
+namespace Internal {
+
+namespace {
+const QString highDpiIconPath = "/res/drawable-hdpi/icon.png";
+const QString mediumDpiIconPath = "/res/drawable-mdpi/icon.png";
+const QString lowDpiIconPath = "/res/drawable-ldpi/icon.png";
+const QSize lowDpiIconSize{32, 32};
+const QSize mediumDpiIconSize{48, 48};
+const QSize highDpiIconSize{72, 72};
+}
+
+AndroidManifestEditorIconContainerWidget::AndroidManifestEditorIconContainerWidget(
+ QWidget *parent,
+ TextEditor::TextEditorWidget *textEditorWidget)
+ : QWidget(parent)
+{
+ auto iconLayout = new QHBoxLayout(this);
+ auto masterIconButton = new AndroidManifestEditorIconWidget(this,
+ lowDpiIconSize,
+ tr("Master icon"), tr("Select master icon"));
+ masterIconButton->setIcon(QIcon::fromTheme(QLatin1String("document-open"), Utils::Icons::OPENFILE.icon()));
+ iconLayout->addWidget(masterIconButton);
+ iconLayout->addStretch(1);
+
+ QFrame *line = new QFrame(this);
+ line->setFrameShape(QFrame::VLine);
+ line->setFrameShadow(QFrame::Sunken);
+ iconLayout->addWidget(line);
+ iconLayout->addStretch(1);
+
+ auto lIconButton = new AndroidManifestEditorIconWidget(this,
+ lowDpiIconSize,
+ tr("Low DPI icon"), tr("Select low DPI icon"),
+ textEditorWidget, lowDpiIconPath);
+ iconLayout->addWidget(lIconButton);
+ m_iconButtons.push_back(lIconButton);
+ iconLayout->addStretch(1);
+
+ auto mIconButton = new AndroidManifestEditorIconWidget(this,
+ mediumDpiIconSize,
+ tr("Medium DPI icon"), tr("Select medium DPI icon"),
+ textEditorWidget, mediumDpiIconPath);
+ iconLayout->addWidget(mIconButton);
+ m_iconButtons.push_back(mIconButton);
+ iconLayout->addStretch(1);
+
+ auto hIconButton = new AndroidManifestEditorIconWidget(this,
+ highDpiIconSize,
+ tr("High DPI icon"), tr("Select high DPI icon"),
+ textEditorWidget, highDpiIconPath);
+ iconLayout->addWidget(hIconButton);
+ m_iconButtons.push_back(hIconButton);
+ iconLayout->addStretch(6);
+
+ for (auto &&iconButton : m_iconButtons) {
+ connect(masterIconButton, &AndroidManifestEditorIconWidget::iconSelected,
+ iconButton, &AndroidManifestEditorIconWidget::setIconFromPath);
+ }
+}
+
+void AndroidManifestEditorIconContainerWidget::loadIcons()
+{
+ for (auto &&iconButton : m_iconButtons)
+ iconButton->loadIcon();
+}
+
+bool AndroidManifestEditorIconContainerWidget::hasIcons()
+{
+ for (auto &&iconButton : m_iconButtons) {
+ if (iconButton->hasIcon())
+ return true;
+ }
+ return false;
+}
+
+} // namespace Internal
+} // namespace Android
diff --git a/src/plugins/android/androidmanifesteditoriconcontainerwidget.h b/src/plugins/android/androidmanifesteditoriconcontainerwidget.h
new file mode 100644
index 0000000000..b1d0415e9b
--- /dev/null
+++ b/src/plugins/android/androidmanifesteditoriconcontainerwidget.h
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** 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 <QVector>
+#include <QWidget>
+
+namespace TextEditor {
+ class TextEditorWidget;
+}
+
+namespace Android {
+namespace Internal {
+
+class AndroidManifestEditorIconWidget;
+
+class AndroidManifestEditorIconContainerWidget : public QWidget
+{
+public:
+ explicit AndroidManifestEditorIconContainerWidget(QWidget *parent,
+ TextEditor::TextEditorWidget *textEditorWidget);
+ void loadIcons();
+ bool hasIcons();
+private:
+ QVector<AndroidManifestEditorIconWidget *> m_iconButtons;
+};
+
+} // namespace Internal
+} // namespace Android
diff --git a/src/plugins/android/androidmanifesteditoriconwidget.cpp b/src/plugins/android/androidmanifesteditoriconwidget.cpp
new file mode 100644
index 0000000000..e609b17491
--- /dev/null
+++ b/src/plugins/android/androidmanifesteditoriconwidget.cpp
@@ -0,0 +1,213 @@
+/****************************************************************************
+**
+** 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 "androidmanifesteditoriconwidget.h"
+
+#include <texteditor/textdocument.h>
+#include <texteditor/texteditor.h>
+#include <utils/utilsicons.h>
+
+#include <QFileDialog>
+#include <QFileInfo>
+#include <QGridLayout>
+#include <QLabel>
+#include <QLoggingCategory>
+#include <QToolButton>
+#include <QVBoxLayout>
+
+namespace Android {
+namespace Internal {
+
+namespace {
+static Q_LOGGING_CATEGORY(androidManifestEditorLog, "qtc.android.manifestEditor", QtWarningMsg)
+const auto fileDialogIconFiles = QWidget::tr("Images (*.png *.jpg *.webp *.svg)");
+QString manifestDir(TextEditor::TextEditorWidget *textEditorWidget)
+{
+ // Get the manifest file's directory from its filepath.
+ return textEditorWidget->textDocument()->filePath().toFileInfo().absolutePath();
+}
+}
+
+AndroidManifestEditorIconWidget::AndroidManifestEditorIconWidget(QWidget *parent) : QWidget(parent)
+{
+
+}
+
+AndroidManifestEditorIconWidget::AndroidManifestEditorIconWidget(
+ QWidget *parent, const QSize &buttonSize, const QString &title,
+ const QString &tooltip,
+ TextEditor::TextEditorWidget *textEditorWidget,
+ const QString &targetIconPath)
+ : QWidget(parent), m_buttonSize(buttonSize),
+ m_textEditorWidget(textEditorWidget), m_targetIconPath(targetIconPath)
+{
+ auto iconLayout = new QVBoxLayout(this);
+ auto iconTitle = new QLabel(title, this);
+ auto iconButtonLayout = new QGridLayout();
+ m_button = new QToolButton(this);
+ m_button->setMinimumSize(buttonSize);
+ m_button->setMaximumSize(buttonSize);
+ m_button->setToolTip(tooltip);
+ m_button->setIconSize(buttonSize);
+ QSize clearAndWarningSize(16, 16);
+ QToolButton *clearButton = nullptr;
+ if (textEditorWidget) {
+ clearButton = new QToolButton(this);
+ clearButton->setMinimumSize(clearAndWarningSize);
+ clearButton->setMaximumSize(clearAndWarningSize);
+ clearButton->setIcon(Utils::Icons::CLOSE_FOREGROUND.icon());
+ }
+ if (textEditorWidget) {
+ m_scaleWarningLabel = new QLabel(this);
+ m_scaleWarningLabel->setMinimumSize(clearAndWarningSize);
+ m_scaleWarningLabel->setMaximumSize(clearAndWarningSize);
+ m_scaleWarningLabel->setPixmap(Utils::Icons::WARNING.icon().pixmap(clearAndWarningSize));
+ m_scaleWarningLabel->setToolTip(tr("Icon scaled up"));
+ m_scaleWarningLabel->setVisible(false);
+ }
+ auto label = new QLabel(tr("Click to select..."), parent);
+ iconLayout->addWidget(iconTitle);
+ iconLayout->setAlignment(iconTitle, Qt::AlignHCenter);
+ iconButtonLayout->setColumnMinimumWidth(0, 16);
+ iconButtonLayout->addWidget(m_button, 0, 1, 1, 3);
+ iconButtonLayout->setAlignment(m_button, Qt::AlignVCenter);
+ if (textEditorWidget) {
+ iconButtonLayout->addWidget(clearButton, 0, 4, 1, 1);
+ iconButtonLayout->setAlignment(clearButton, Qt::AlignTop);
+ }
+ if (textEditorWidget) {
+ iconButtonLayout->addWidget(m_scaleWarningLabel, 0, 0, 1, 1);
+ iconButtonLayout->setAlignment(m_scaleWarningLabel, Qt::AlignTop);
+ }
+ iconLayout->addLayout(iconButtonLayout);
+ iconLayout->setAlignment(iconButtonLayout, Qt::AlignHCenter);
+ iconLayout->addWidget(label);
+ iconLayout->setAlignment(label, Qt::AlignHCenter);
+ this->setLayout(iconLayout);
+ connect(m_button, &QAbstractButton::clicked,
+ this, &AndroidManifestEditorIconWidget::selectIcon);
+ if (clearButton)
+ connect(clearButton, &QAbstractButton::clicked,
+ this, &AndroidManifestEditorIconWidget::removeIcon);
+ m_iconSelectionText = tooltip;
+}
+
+void AndroidManifestEditorIconWidget::setIcon(const QIcon &icon)
+{
+ m_button->setIcon(icon);
+}
+
+void AndroidManifestEditorIconWidget::loadIcon()
+{
+ QString baseDir = manifestDir(m_textEditorWidget);
+ QString iconFile = baseDir + m_targetIconPath;
+ setIconFromPath(iconFile);
+}
+
+void AndroidManifestEditorIconWidget::setIconFromPath(const QString &iconPath)
+{
+ if (!m_textEditorWidget) {
+ iconSelected(iconPath);
+ return;
+ }
+ m_iconPath = iconPath;
+ QString baseDir = manifestDir(m_textEditorWidget);
+ copyIcon();
+ QString iconFile = baseDir + m_targetIconPath;
+ m_button->setIcon(QIcon(iconFile));
+}
+
+void AndroidManifestEditorIconWidget::selectIcon()
+{
+ QString file = QFileDialog::getOpenFileName(this, m_iconSelectionText,
+ QDir::homePath(), fileDialogIconFiles);
+ if (file.isEmpty())
+ return;
+ setIconFromPath(file);
+}
+
+void AndroidManifestEditorIconWidget::removeIcon()
+{
+ QString baseDir = manifestDir(m_textEditorWidget);
+ const QString targetPath = baseDir + m_targetIconPath;
+ if (targetPath.isEmpty()) {
+ qCDebug(androidManifestEditorLog) << "Icon target path empty, cannot remove icon.";
+ return;
+ }
+ QFileInfo targetFile(targetPath);
+ if (targetFile.exists()) {
+ QDir rmRf(targetFile.absoluteDir());
+ rmRf.removeRecursively();
+ }
+ setScaleWarningLabelVisible(false);
+ m_button->setIcon(QIcon());
+}
+
+bool AndroidManifestEditorIconWidget::hasIcon()
+{
+ return !m_iconPath.isEmpty();
+}
+
+void AndroidManifestEditorIconWidget::setScaleWarningLabelVisible(bool visible)
+{
+ if (m_scaleWarningLabel)
+ m_scaleWarningLabel->setVisible(visible);
+}
+
+void AndroidManifestEditorIconWidget::copyIcon()
+{
+ if (m_targetIconPath.isEmpty())
+ return;
+ QString baseDir = manifestDir(m_textEditorWidget);
+ const QString targetPath = baseDir + m_targetIconPath;
+ if (targetPath.isEmpty()) {
+ qCDebug(androidManifestEditorLog) << "Icon target path empty, cannot copy icon.";
+ return;
+ }
+ QFileInfo targetFile(targetPath);
+ if (m_iconPath == targetPath)
+ return;
+ removeIcon();
+ QImage original(m_iconPath);
+ if (!targetPath.isEmpty() && !original.isNull()) {
+ QDir dir;
+ if (!dir.mkpath(QFileInfo(targetPath).absolutePath())) {
+ qCDebug(androidManifestEditorLog) << "Cannot create icon target path.";
+ m_iconPath.clear();
+ return;
+ }
+ QSize targetSize = m_buttonSize;
+ QImage scaled = original.scaled(targetSize.width(), targetSize.height(),
+ Qt::KeepAspectRatio, Qt::SmoothTransformation);
+ setScaleWarningLabelVisible(scaled.width() > original.width() || scaled.height() > original.height());
+ scaled.save(targetPath);
+ m_iconPath = m_targetIconPath;
+ } else {
+ m_iconPath.clear();
+ }
+}
+
+} // namespace Internal
+} // namespace Android
diff --git a/src/plugins/android/androidmanifesteditoriconwidget.h b/src/plugins/android/androidmanifesteditoriconwidget.h
new file mode 100644
index 0000000000..955ac11b8e
--- /dev/null
+++ b/src/plugins/android/androidmanifesteditoriconwidget.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** 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 <QWidget>
+
+namespace TextEditor {
+ class TextEditorWidget;
+}
+
+QT_BEGIN_NAMESPACE
+class QLabel;
+class QToolButton;
+QT_END_NAMESPACE
+
+namespace Android {
+namespace Internal {
+
+class AndroidManifestEditorIconWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ explicit AndroidManifestEditorIconWidget(QWidget *parent);
+ AndroidManifestEditorIconWidget(QWidget *parent,
+ const QSize &buttonSize,
+ const QString &title,
+ const QString &tooltip,
+ TextEditor::TextEditorWidget *textEditorWidget = nullptr,
+ const QString &targetIconPath = {});
+ void setIcon(const QIcon &icon);
+ void loadIcon();
+ void setIconFromPath(const QString &iconPath);
+ bool hasIcon();
+
+signals:
+ void iconSelected(const QString &path);
+
+private:
+ void selectIcon();
+ void removeIcon();
+ void copyIcon();
+ void setScaleWarningLabelVisible(bool visible);
+private:
+ QToolButton *m_button = nullptr;
+ QSize m_buttonSize;
+ QLabel *m_scaleWarningLabel = nullptr;
+ TextEditor::TextEditorWidget *m_textEditorWidget = nullptr;
+ QString m_iconPath;
+ QString m_targetIconPath;
+ QString m_iconSelectionText;
+};
+
+} // namespace Internal
+} // namespace Android
diff --git a/src/plugins/android/androidmanifesteditorwidget.cpp b/src/plugins/android/androidmanifesteditorwidget.cpp
index 87c2218cfe..3a7296b508 100644
--- a/src/plugins/android/androidmanifesteditorwidget.cpp
+++ b/src/plugins/android/androidmanifesteditorwidget.cpp
@@ -24,11 +24,13 @@
****************************************************************************/
#include "androidmanifesteditorwidget.h"
+#include "androidmanifesteditoriconcontainerwidget.h"
#include "androidmanifesteditor.h"
#include "androidconfigurations.h"
#include "androidconstants.h"
#include "androidmanifestdocument.h"
#include "androidmanager.h"
+#include "androidservicewidget.h"
#include <coreplugin/icore.h>
#include <coreplugin/infobar.h>
@@ -67,7 +69,7 @@
#include <QLabel>
#include <QLineEdit>
#include <QListView>
-#include <QLoggingCategory>
+#include <QMessageBox>
#include <QPushButton>
#include <QScrollArea>
#include <QSpinBox>
@@ -77,11 +79,6 @@
#include <algorithm>
#include <limits>
-
-namespace {
-static Q_LOGGING_CATEGORY(androidManifestEditorLog, "qtc.android.manifestEditor", QtWarningMsg)
-}
-
using namespace ProjectExplorer;
using namespace Android;
using namespace Android::Internal;
@@ -252,54 +249,14 @@ void AndroidManifestEditorWidget::initializePage()
m_styleExtractMethod->setItemData(i, styleMethodsMap.at(i).at(1), Qt::ToolTipRole);
}
- auto iconLayout = new QHBoxLayout();
-
- createDPIButton(iconLayout,
- applicationGroupBox,
- m_masterIconButton, iconSize(LowDPI),
- tr("Master icon"), tr("Select master icon."));
-
- m_masterIconButton->setIcon(QIcon::fromTheme(QLatin1String("document-open"), Utils::Icons::OPENFILE.icon()));
-
- iconLayout->addStretch(1);
-
- QFrame* line = new QFrame();
- line->setFrameShape(QFrame::VLine);
- line->setFrameShadow(QFrame::Sunken);
- iconLayout->addWidget(line);
-
- iconLayout->addStretch(1);
-
- createDPIButton(iconLayout,
- applicationGroupBox,
- m_lIconButton, iconSize(LowDPI),
- tr("Low DPI icon"), tr("Select low DPI icon."),
- &m_lIconClearButton,
- &m_lIconScaleWarningLabel);
-
- iconLayout->addStretch(1);
-
- createDPIButton(iconLayout,
- applicationGroupBox,
- m_mIconButton, iconSize(MediumDPI),
- tr("Medium DPI icon"), tr("Select medium DPI icon."),
- &m_mIconClearButton,
- &m_mIconScaleWarningLabel);
-
- iconLayout->addStretch(1);
-
- createDPIButton(iconLayout,
- applicationGroupBox,
- m_hIconButton, iconSize(HighDPI),
- tr("High DPI icon"), tr("Select high DPI icon."),
- &m_hIconClearButton,
- &m_hIconScaleWarningLabel);
-
- iconLayout->addStretch(6);
+ m_iconButtons = new AndroidManifestEditorIconContainerWidget(applicationGroupBox, m_textEditorWidget);
formLayout->addRow(tr("Application icon:"), new QLabel());
- formLayout->addRow(QString(), iconLayout);
+ formLayout->addRow(QString(), m_iconButtons);
+
+ m_services = new AndroidServiceWidget(this);
+ formLayout->addRow(tr("Android services:"), m_services);
applicationGroupBox->setLayout(formLayout);
@@ -312,21 +269,12 @@ void AndroidManifestEditorWidget::initializePage()
connect(m_styleExtractMethod,
QOverload<int>::of(&QComboBox::currentIndexChanged),
this, setDirtyFunc);
-
- connect(m_masterIconButton, &QAbstractButton::clicked,
- this, &AndroidManifestEditorWidget::setMasterIcon);
- connect(m_lIconButton, &QAbstractButton::clicked,
- this, &AndroidManifestEditorWidget::setLDPIIcon);
- connect(m_mIconButton, &QAbstractButton::clicked,
- this, &AndroidManifestEditorWidget::setMDPIIcon);
- connect(m_hIconButton, &QAbstractButton::clicked,
- this, &AndroidManifestEditorWidget::setHDPIIcon);
- connect(m_lIconClearButton, &QAbstractButton::clicked,
- this, &AndroidManifestEditorWidget::clearLDPIIcon);
- connect(m_mIconClearButton, &QAbstractButton::clicked,
- this, &AndroidManifestEditorWidget::clearMDPIIcon);
- connect(m_hIconClearButton, &QAbstractButton::clicked,
- this, &AndroidManifestEditorWidget::clearHDPIIcon);
+ connect(m_services, &AndroidServiceWidget::servicesModified,
+ this, setDirtyFunc);
+ connect(m_services, &AndroidServiceWidget::servicesModified,
+ this, &AndroidManifestEditorWidget::clearInvalidServiceInfo);
+ connect(m_services, &AndroidServiceWidget::servicesInvalid,
+ this, &AndroidManifestEditorWidget::setInvalidServiceInfo);
}
@@ -602,6 +550,14 @@ AndroidManifestEditorWidget::EditorPage AndroidManifestEditorWidget::activePage(
return AndroidManifestEditorWidget::EditorPage(currentIndex());
}
+bool servicesValid(const QList<AndroidServiceData> &services)
+{
+ for (auto &&x : services)
+ if (!x.isValid())
+ return false;
+ return true;
+}
+
bool AndroidManifestEditorWidget::setActivePage(EditorPage page)
{
EditorPage prevPage = activePage();
@@ -610,6 +566,11 @@ bool AndroidManifestEditorWidget::setActivePage(EditorPage page)
return true;
if (page == Source) {
+ if (!servicesValid(m_services->services())) {
+ QMessageBox::critical(nullptr, tr("Service Definition Invalid"),
+ tr("Cannot switch to source when there are invalid services."));
+ return false;
+ }
syncToEditor();
} else {
if (!syncToWidgets())
@@ -630,16 +591,16 @@ bool AndroidManifestEditorWidget::setActivePage(EditorPage page)
void AndroidManifestEditorWidget::preSave()
{
- if (activePage() != Source)
+ if (activePage() != Source) {
+ if (!servicesValid(m_services->services())) {
+ QMessageBox::critical(nullptr, tr("Service Definition Invalid"),
+ tr("Cannot save when there are invalid services."));
+ return;
+ }
syncToEditor();
-
- QString baseDir = m_textEditorWidget->textDocument()->filePath().toFileInfo().absolutePath();
- copyIcon(LowDPI, baseDir, m_lIconPath);
- copyIcon(MediumDPI, baseDir, m_mIconPath);
- copyIcon(HighDPI, baseDir, m_hIconPath);
+ }
// no need to emit changed() since this is called as part of saving
-
updateInfoBar();
}
@@ -776,7 +737,26 @@ void AndroidManifestEditorWidget::hideInfoBar()
{
Core::InfoBar *infoBar = m_textEditorWidget->textDocument()->infoBar();
infoBar->removeInfo(infoBarId);
- m_timerParseCheck.stop();
+ m_timerParseCheck.stop();
+}
+
+static const char kServicesInvalid[] = "AndroidServiceDefinitionInvalid";
+
+void AndroidManifestEditorWidget::setInvalidServiceInfo()
+{
+ Core::Id id(kServicesInvalid);
+ if (m_textEditorWidget->textDocument()->infoBar()->containsInfo(id))
+ return;
+ Core::InfoBarEntry info(id,
+ tr("Services invalid. "
+ "Manifest cannot be saved. Correct the service definitions before saving."));
+ m_textEditorWidget->textDocument()->infoBar()->addInfo(info);
+
+}
+
+void AndroidManifestEditorWidget::clearInvalidServiceInfo()
+{
+ m_textEditorWidget->textDocument()->infoBar()->removeInfo(Core::Id(kServicesInvalid));
}
void setApiLevel(QComboBox *box, const QDomElement &element, const QString &attribute)
@@ -840,13 +820,6 @@ void AndroidManifestEditorWidget::syncToWidgets(const QDomDocument &doc)
metadataElem = metadataElem.nextSiblingElement(QLatin1String("meta-data"));
}
- copyIcon(LowDPI, baseDir, baseDir + iconPath(LowDPI));
- copyIcon(MediumDPI, baseDir, baseDir + iconPath(MediumDPI));
- copyIcon(HighDPI, baseDir, baseDir + iconPath(HighDPI));
- m_lIconButton->setIcon(icon(baseDir, LowDPI));
- m_mIconButton->setIcon(icon(baseDir, MediumDPI));
- m_hIconButton->setIcon(icon(baseDir, HighDPI));
-
disconnect(m_defaultPermissonsCheckBox, &QCheckBox::stateChanged,
this, &AndroidManifestEditorWidget::defaultPermissionOrFeatureCheckBoxClicked);
disconnect(m_defaultFeaturesCheckBox, &QCheckBox::stateChanged,
@@ -886,6 +859,35 @@ void AndroidManifestEditorWidget::syncToWidgets(const QDomDocument &doc)
m_permissionsModel->setPermissions(permissions);
updateAddRemovePermissionButtons();
+ QList<AndroidServiceData> services;
+ QDomElement serviceElem = applicationElement.firstChildElement(QLatin1String("service"));
+ while (!serviceElem.isNull()) {
+ AndroidServiceData service;
+ service.setClassName(serviceElem.attribute(QLatin1String("android:name")));
+ QString process = serviceElem.attribute(QLatin1String("android:process"));
+ service.setRunInExternalProcess(!process.isEmpty());
+ service.setExternalProcessName(process);
+ QDomElement serviceMetadataElem = serviceElem.firstChildElement(QLatin1String("meta-data"));
+ while (!serviceMetadataElem.isNull()) {
+ QString metadataName = serviceMetadataElem.attribute(QLatin1String("android:name"));
+ if (metadataName == QLatin1String("android.app.lib_name")) {
+ QString metadataValue = serviceMetadataElem.attribute(QLatin1String("android:value"));
+ service.setRunInExternalLibrary(metadataValue != QLatin1String("-- %%INSERT_APP_LIB_NAME%% --"));
+ service.setExternalLibraryName(metadataValue);
+ }
+ else if (metadataName == QLatin1String("android.app.arguments")) {
+ QString metadataValue = serviceMetadataElem.attribute(QLatin1String("android:value"));
+ service.setServiceArguments(metadataValue);
+ }
+ serviceMetadataElem = serviceMetadataElem.nextSiblingElement(QLatin1String("meta-data"));
+ }
+ services << service;
+ serviceElem = serviceElem.nextSiblingElement(QLatin1String("service"));
+ }
+ m_services->setServices(services);
+
+ m_iconButtons->loadIcons();
+
m_stayClean = false;
m_dirty = false;
}
@@ -1048,9 +1050,7 @@ void AndroidManifestEditorWidget::parseApplication(QXmlStreamReader &reader, QXm
QStringList keys = {QLatin1String("android:label")};
QStringList values = {m_appNameLineEdit->text()};
QStringList remove;
- bool ensureIconAttribute = !m_lIconPath.isEmpty()
- || !m_mIconPath.isEmpty()
- || !m_hIconPath.isEmpty();
+ bool ensureIconAttribute = m_iconButtons->hasIcons();
if (ensureIconAttribute) {
keys << QLatin1String("android:icon");
values << QLatin1String("@drawable/icon");
@@ -1064,13 +1064,19 @@ void AndroidManifestEditorWidget::parseApplication(QXmlStreamReader &reader, QXm
while (!reader.atEnd()) {
if (reader.isEndElement()) {
+ parseNewServices(writer);
writer.writeCurrentToken(reader);
+ m_services->servicesSaved();
return;
} else if (reader.isStartElement()) {
if (reader.name() == QLatin1String("activity"))
parseActivity(reader, writer);
+ else if (reader.name() == QLatin1String("service"))
+ parseService(reader, writer);
else
parseUnknownElement(reader, writer);
+ } else if (reader.isWhitespace()) {
+ /* no copying of whitespace */
} else {
writer.writeCurrentToken(reader);
}
@@ -1079,6 +1085,144 @@ void AndroidManifestEditorWidget::parseApplication(QXmlStreamReader &reader, QXm
}
}
+static int findService(const QString &name, const QList<AndroidServiceData> &data)
+{
+ for (int i = 0; i < data.size(); ++i) {
+ if (data[i].className() == name)
+ return i;
+ }
+ return -1;
+}
+
+static void writeServiceMetadataElement(const char *name,
+ const char *attributeName,
+ const char *value,
+ QXmlStreamWriter &writer)
+{
+ writer.writeStartElement(QLatin1String("meta-data"));
+ writer.writeAttribute(QLatin1String("android:name"), QLatin1String(name));
+ writer.writeAttribute(QLatin1String(attributeName), QLatin1String(value));
+ writer.writeEndElement();
+
+}
+
+static void writeServiceMetadataElement(const char *name,
+ const char *attributeName,
+ const QString &value,
+ QXmlStreamWriter &writer)
+{
+ writer.writeStartElement(QLatin1String("meta-data"));
+ writer.writeAttribute(QLatin1String("android:name"), QLatin1String(name));
+ writer.writeAttribute(QLatin1String(attributeName), value);
+ writer.writeEndElement();
+
+}
+
+static void addServiceArgumentsAndLibName(const AndroidServiceData &service, QXmlStreamWriter &writer)
+{
+ if (!service.isRunInExternalLibrary() && !service.serviceArguments().isEmpty())
+ writeServiceMetadataElement("android.app.arguments", "android:value", service.serviceArguments(), writer);
+ if (service.isRunInExternalLibrary() && !service.externalLibraryName().isEmpty())
+ writeServiceMetadataElement("android.app.lib_name", "android:value", service.externalLibraryName(), writer);
+ else
+ writeServiceMetadataElement("android.app.lib_name", "android:value", "-- %%INSERT_APP_LIB_NAME%% --", writer);
+}
+
+static void addServiceMetadata(QXmlStreamWriter &writer)
+{
+ writeServiceMetadataElement("android.app.qt_sources_resource_id", "android:resource", "@array/qt_sources", writer);
+ writeServiceMetadataElement("android.app.repository", "android:value", "default", writer);
+ writeServiceMetadataElement("android.app.qt_libs_resource_id", "android:resource", "@array/qt_libs", writer);
+ writeServiceMetadataElement("android.app.bundled_libs_resource_id", "android:resource", "@array/bundled_libs", writer);
+ writeServiceMetadataElement("android.app.bundle_local_qt_libs", "android:value", "-- %%BUNDLE_LOCAL_QT_LIBS%% --", writer);
+ writeServiceMetadataElement("android.app.use_local_qt_libs", "android:value", "-- %%USE_LOCAL_QT_LIBS%% --", writer);
+ writeServiceMetadataElement("android.app.libs_prefix", "android:value", "/data/local/tmp/qt/", writer);
+ writeServiceMetadataElement("android.app.load_local_libs_resource_id", "android:resource", "@array/load_local_libs", writer);
+ writeServiceMetadataElement("android.app.load_local_jars", "android:value", "-- %%INSERT_LOCAL_JARS%% --", writer);
+ writeServiceMetadataElement("android.app.static_init_classes", "android:value", "-- %%INSERT_INIT_CLASSES%% --", writer);
+}
+
+void AndroidManifestEditorWidget::parseService(QXmlStreamReader &reader, QXmlStreamWriter &writer)
+{
+ Q_ASSERT(reader.isStartElement());
+ const auto &services = m_services->services();
+ QString serviceName = reader.attributes().value(QLatin1String("android:name")).toString();
+ int serviceIndex = findService(serviceName, services);
+ const AndroidServiceData* serviceFound = (serviceIndex >= 0) ? &services[serviceIndex] : nullptr;
+ if (serviceFound && serviceFound->isValid()) {
+ writer.writeStartElement(reader.name().toString());
+ writer.writeAttribute(QLatin1String("android:name"), serviceFound->className());
+ if (serviceFound->isRunInExternalProcess())
+ writer.writeAttribute(QLatin1String("android:process"), serviceFound->externalProcessName());
+ }
+
+ reader.readNext();
+
+ bool bundleTagFound = false;
+
+ while (!reader.atEnd()) {
+ if (reader.isEndElement()) {
+ if (serviceFound && serviceFound->isValid()) {
+ addServiceArgumentsAndLibName(*serviceFound, writer);
+ if (serviceFound->isRunInExternalProcess() && !bundleTagFound)
+ addServiceMetadata(writer);
+ writer.writeCurrentToken(reader);
+ }
+ return;
+ } else if (reader.isStartElement()) {
+ if (serviceFound && !serviceFound->isValid())
+ parseUnknownElement(reader, writer, true);
+ else if (reader.name() == QLatin1String("meta-data")) {
+ QString metaTagName = reader.attributes().value(QLatin1String("android:name")).toString();
+ if (serviceFound) {
+ if (metaTagName == QLatin1String("android.app.bundle_local_qt_libs"))
+ bundleTagFound = true;
+ if (metaTagName == QLatin1String("android.app.arguments"))
+ parseUnknownElement(reader, writer, true);
+ else if (metaTagName == QLatin1String("android.app.lib_name"))
+ parseUnknownElement(reader, writer, true);
+ else if (serviceFound->isRunInExternalProcess()
+ || metaTagName == QLatin1String("android.app.background_running"))
+ parseUnknownElement(reader, writer);
+ else
+ parseUnknownElement(reader, writer, true);
+ } else
+ parseUnknownElement(reader, writer, true);
+ } else
+ parseUnknownElement(reader, writer, true);
+ } else if (reader.isWhitespace()) {
+ /* no copying of whitespace */
+ } else {
+ if (serviceFound)
+ writer.writeCurrentToken(reader);
+ }
+ reader.readNext();
+ }
+}
+
+void AndroidManifestEditorWidget::parseNewServices(QXmlStreamWriter &writer)
+{
+ const auto &services = m_services->services();
+ for (const auto &x : services) {
+ if (x.isNewService() && x.isValid()) {
+ writer.writeStartElement(QLatin1String("service"));
+ writer.writeAttribute(QLatin1String("android:name"), x.className());
+ if (x.isRunInExternalProcess()) {
+ writer.writeAttribute(QLatin1String("android:process"),
+ x.externalProcessName());
+ }
+ addServiceArgumentsAndLibName(x, writer);
+ if (x.isRunInExternalProcess())
+ addServiceMetadata(writer);
+ writer.writeStartElement(QLatin1String("meta-data"));
+ writer.writeAttribute(QLatin1String("android:name"), QLatin1String("android.app.background_running"));
+ writer.writeAttribute(QLatin1String("android:value"), QLatin1String("true"));
+ writer.writeEndElement();
+ writer.writeEndElement();
+ }
+ }
+}
+
void AndroidManifestEditorWidget::parseActivity(QXmlStreamReader &reader, QXmlStreamWriter &writer)
{
Q_ASSERT(reader.isStartElement());
@@ -1256,273 +1400,29 @@ QString AndroidManifestEditorWidget::parseComment(QXmlStreamReader &reader, QXml
return commentText;
}
-void AndroidManifestEditorWidget::parseUnknownElement(QXmlStreamReader &reader, QXmlStreamWriter &writer)
+void AndroidManifestEditorWidget::parseUnknownElement(QXmlStreamReader &reader, QXmlStreamWriter &writer,
+ bool ignore)
{
Q_ASSERT(reader.isStartElement());
- writer.writeCurrentToken(reader);
+ if (!ignore)
+ writer.writeCurrentToken(reader);
reader.readNext();
while (!reader.atEnd()) {
if (reader.isEndElement()) {
- writer.writeCurrentToken(reader);
+ if (!ignore)
+ writer.writeCurrentToken(reader);
return;
} else if (reader.isStartElement()) {
- parseUnknownElement(reader, writer);
+ parseUnknownElement(reader, writer, ignore);
} else {
- writer.writeCurrentToken(reader);
+ if (!ignore)
+ writer.writeCurrentToken(reader);
}
reader.readNext();
}
}
-QString AndroidManifestEditorWidget::iconPath(IconDPI dpi)
-{
- switch (dpi) {
- case HighDPI:
- return QString("/res/drawable-hdpi/icon.png");
- case MediumDPI:
- return QString("/res/drawable-mdpi/icon.png");
- case LowDPI:
- return QString("/res/drawable-ldpi/icon.png");
- }
- return {};
-}
-
-QSize AndroidManifestEditorWidget::iconSize(IconDPI dpi)
-{
- switch (dpi) {
- case HighDPI:
- return QSize(72, 72);
- case MediumDPI:
- return QSize(48, 48);
- case LowDPI:
- return QSize(32, 32);
- }
- return QSize(72, 72);
-}
-
-void AndroidManifestEditorWidget::updateIconPath(const QString &newPath, IconDPI dpi)
-{
- switch (dpi) {
- case HighDPI:
- m_hIconPath = newPath;
- break;
- case MediumDPI:
- m_mIconPath = newPath;
- break;
- case LowDPI:
- m_lIconPath = newPath;
- break;
- }
-}
-
-QIcon AndroidManifestEditorWidget::icon(const QString &baseDir, IconDPI dpi)
-{
-
- if (dpi == HighDPI && !m_hIconPath.isEmpty())
- return QIcon(m_hIconPath);
-
- if (dpi == MediumDPI && !m_mIconPath.isEmpty())
- return QIcon(m_mIconPath);
-
- if (dpi == LowDPI && !m_lIconPath.isEmpty())
- return QIcon(m_lIconPath);
-
- QString fileName = baseDir + iconPath(dpi);
- if (fileName.isEmpty())
- return QIcon();
- return QIcon(fileName);
-}
-
-void AndroidManifestEditorWidget::copyIcon(IconDPI dpi, const QString &baseDir, const QString &filePath)
-{
- const QString targetPath = baseDir + iconPath(dpi);
- if (targetPath.isEmpty()) {
- qCDebug(androidManifestEditorLog) << "Icon target path empty, cannot copy icon.";
- return;
- }
- QFileInfo targetFile(targetPath);
- if (filePath != targetPath)
- removeIcon(dpi, baseDir);
- QImage original(filePath);
- if (!targetPath.isEmpty() && !original.isNull()) {
- if (filePath != targetPath) {
- QDir dir;
- dir.mkpath(QFileInfo(targetPath).absolutePath());
- QSize targetSize = iconSize(dpi);
- QImage scaled = original.scaled(targetSize.width(), targetSize.height(),
- Qt::KeepAspectRatio, Qt::SmoothTransformation);
- toggleIconScaleWarning(dpi, scaled.width() > original.width() || scaled.height() > original.height());
- scaled.save(targetPath);
- }
- updateIconPath(targetPath, dpi);
- }
-}
-
-void AndroidManifestEditorWidget::removeIcon(IconDPI dpi, const QString &baseDir)
-{
- const QString targetPath = baseDir + iconPath(dpi);
- if (targetPath.isEmpty()) {
- qCDebug(androidManifestEditorLog) << "Icon target path empty, cannot remove icon.";
- return;
- }
- QFileInfo targetFile(targetPath);
- if (targetFile.exists()) {
- QDir rmRf(targetFile.absoluteDir());
- rmRf.removeRecursively();
- }
- toggleIconScaleWarning(dpi, false);
-}
-
-void AndroidManifestEditorWidget::toggleIconScaleWarning(IconDPI dpi, bool visible)
-{
- switch (dpi) {
- case HighDPI:
- m_hIconScaleWarningLabel->setVisible(visible);
- break;
- case MediumDPI:
- m_mIconScaleWarningLabel->setVisible(visible);
- break;
- case LowDPI:
- m_lIconScaleWarningLabel->setVisible(visible);
- break;
- }
-}
-
-const auto fileDialogIconFiles = QWidget::tr("Images (*.png *.jpg *.webp *.svg)");
-
-void AndroidManifestEditorWidget::setMasterIcon()
-{
- QString file = QFileDialog::getOpenFileName(this, tr("Choose Master Icon"), QDir::homePath(), fileDialogIconFiles);
- if (file.isEmpty())
- return;
- QString baseDir = m_textEditorWidget->textDocument()->filePath().toFileInfo().absolutePath();
- copyIcon(LowDPI, baseDir, file);
- copyIcon(MediumDPI, baseDir, file);
- copyIcon(HighDPI, baseDir, file);
- m_lIconButton->setIcon(icon(baseDir, LowDPI));
- m_mIconButton->setIcon(icon(baseDir, MediumDPI));
- m_hIconButton->setIcon(icon(baseDir, HighDPI));
- syncToEditor();
-}
-
-void AndroidManifestEditorWidget::setLDPIIcon()
-{
- QString file = QFileDialog::getOpenFileName(this, tr("Choose Low DPI Icon"), QDir::homePath(), fileDialogIconFiles);
- if (file.isEmpty())
- return;
- m_lIconPath = file;
- QString baseDir = m_textEditorWidget->textDocument()->filePath().toFileInfo().absolutePath();
- copyIcon(LowDPI, baseDir, m_lIconPath);
- m_lIconButton->setIcon(icon(baseDir, LowDPI));
- syncToEditor();
-}
-
-void AndroidManifestEditorWidget::setMDPIIcon()
-{
- QString file = QFileDialog::getOpenFileName(this, tr("Choose Medium DPI Icon"), QDir::homePath(), fileDialogIconFiles);
- if (file.isEmpty())
- return;
- m_mIconPath = file;
- QString baseDir = m_textEditorWidget->textDocument()->filePath().toFileInfo().absolutePath();
- copyIcon(MediumDPI, baseDir, m_mIconPath);
- m_mIconButton->setIcon(icon(baseDir, MediumDPI));
- syncToEditor();
-}
-
-void AndroidManifestEditorWidget::setHDPIIcon()
-{
- QString file = QFileDialog::getOpenFileName(this, tr("Choose High DPI Icon"), QDir::homePath(), fileDialogIconFiles);
- if (file.isEmpty())
- return;
- m_hIconPath = file;
- QString baseDir = m_textEditorWidget->textDocument()->filePath().toFileInfo().absolutePath();
- copyIcon(HighDPI, baseDir, m_hIconPath);
- m_hIconButton->setIcon(icon(baseDir, HighDPI));
- syncToEditor();
-}
-
-void AndroidManifestEditorWidget::clearLDPIIcon()
-{
- m_lIconPath.clear();
- m_lIconButton->setIcon(QIcon());
- QString baseDir = m_textEditorWidget->textDocument()->filePath().toFileInfo().absolutePath();
- removeIcon(LowDPI, baseDir);
- syncToEditor();
-}
-
-void AndroidManifestEditorWidget::clearMDPIIcon()
-{
- m_mIconPath.clear();
- m_mIconButton->setIcon(QIcon());
- QString baseDir = m_textEditorWidget->textDocument()->filePath().toFileInfo().absolutePath();
- removeIcon(MediumDPI, baseDir);
- syncToEditor();
-}
-
-void AndroidManifestEditorWidget::clearHDPIIcon()
-{
- m_hIconPath.clear();
- m_hIconButton->setIcon(QIcon());
- QString baseDir = m_textEditorWidget->textDocument()->filePath().toFileInfo().absolutePath();
- removeIcon(HighDPI, baseDir);
- syncToEditor();
-}
-
-void AndroidManifestEditorWidget::createDPIButton(QHBoxLayout *layout,
- QWidget *parent,
- QToolButton *&button,
- const QSize &buttonSize,
- const QString &title,
- const QString &tooltip,
- QToolButton **clearButton,
- QLabel **scaleWarningLabel)
-{
- auto iconLayout = new QVBoxLayout();
- auto iconTitle = new QLabel(title, parent);
- auto iconButtonLayout = new QGridLayout();
- button = new QToolButton(parent);
- button->setMinimumSize(buttonSize);
- button->setMaximumSize(buttonSize);
- button->setToolTip(tooltip);
- button->setIconSize(buttonSize);
- QSize clearAndWarningSize(16, 16);
- if (clearButton) {
- *clearButton = new QToolButton(parent);
- (*clearButton)->setMinimumSize(clearAndWarningSize);
- (*clearButton)->setMaximumSize(clearAndWarningSize);
- (*clearButton)->setIcon(Utils::Icons::CLOSE_FOREGROUND.icon());
- }
- if (scaleWarningLabel) {
- *scaleWarningLabel = new QLabel(parent);
- (*scaleWarningLabel)->setMinimumSize(clearAndWarningSize);
- (*scaleWarningLabel)->setMaximumSize(clearAndWarningSize);
- (*scaleWarningLabel)->setPixmap(Utils::Icons::WARNING.icon().pixmap(clearAndWarningSize));
- (*scaleWarningLabel)->setToolTip(tr("Icon scaled up"));
- (*scaleWarningLabel)->setVisible(false);
- }
- auto label = new QLabel(tr("Click to select"), parent);
- iconLayout->addWidget(iconTitle);
- iconLayout->setAlignment(iconTitle, Qt::AlignHCenter);
- iconButtonLayout->setColumnMinimumWidth(0, 16);
- iconButtonLayout->addWidget(button, 0, 1, 1, 3);
- iconButtonLayout->setAlignment(button, Qt::AlignVCenter);
- if (clearButton) {
- iconButtonLayout->addWidget(*clearButton, 0, 4, 1, 1);
- iconButtonLayout->setAlignment(*clearButton, Qt::AlignTop);
- }
- if (scaleWarningLabel) {
- iconButtonLayout->addWidget(*scaleWarningLabel, 0, 0, 1, 1);
- iconButtonLayout->setAlignment(*scaleWarningLabel, Qt::AlignTop);
- }
- iconLayout->addLayout(iconButtonLayout);
- iconLayout->setAlignment(iconButtonLayout, Qt::AlignHCenter);
- iconLayout->addWidget(label);
- iconLayout->setAlignment(label, Qt::AlignHCenter);
-
- layout->addLayout(iconLayout);
-}
-
void AndroidManifestEditorWidget::defaultPermissionOrFeatureCheckBoxClicked()
{
setDirty(true);
diff --git a/src/plugins/android/androidmanifesteditorwidget.h b/src/plugins/android/androidmanifesteditorwidget.h
index 8e38773cd6..6d49cf7f42 100644
--- a/src/plugins/android/androidmanifesteditorwidget.h
+++ b/src/plugins/android/androidmanifesteditorwidget.h
@@ -52,8 +52,9 @@ namespace Core { class IEditor; }
namespace Android {
namespace Internal {
class AndroidManifestEditor;
+class AndroidManifestEditorIconContainerWidget;
class AndroidManifestEditorWidget;
-
+class AndroidServiceWidget;
class PermissionsModel: public QAbstractListModel
{
@@ -116,21 +117,6 @@ protected:
void focusInEvent(QFocusEvent *event) override;
private:
- void setMasterIcon();
- void clearMasterIcon();
- void setLDPIIcon();
- void setMDPIIcon();
- void setHDPIIcon();
- void clearLDPIIcon();
- void clearMDPIIcon();
- void clearHDPIIcon();
- void createDPIButton(QHBoxLayout *layout,
- QWidget *parent,
- QToolButton *&button, const QSize &buttonSize,
- const QString &title, const QString &tooltip,
- QToolButton **clearButton = nullptr,
- QLabel **scaleWarningLabel = nullptr
- );
void defaultPermissionOrFeatureCheckBoxClicked();
void addPermission();
void removePermission();
@@ -148,21 +134,18 @@ private:
bool checkDocument(const QDomDocument &doc, QString *errorMessage,
int *errorLine, int *errorColumn);
- enum IconDPI { LowDPI, MediumDPI, HighDPI };
- QIcon icon(const QString &baseDir, IconDPI dpi);
- QString iconPath(IconDPI dpi);
- QSize iconSize(IconDPI dpi);
- void updateIconPath(const QString &newPath, IconDPI dpi);
- void copyIcon(IconDPI dpi, const QString &baseDir, const QString &filePath);
- void removeIcon(IconDPI dpi, const QString &baseDir);
- void toggleIconScaleWarning(IconDPI dpi, bool visible);
void updateInfoBar(const QString &errorMessage, int line, int column);
void hideInfoBar();
+ void setInvalidServiceInfo();
+ void clearInvalidServiceInfo();
+
void updateTargetComboBox();
void parseManifest(QXmlStreamReader &reader, QXmlStreamWriter &writer);
void parseApplication(QXmlStreamReader &reader, QXmlStreamWriter &writer);
+ void parseService(QXmlStreamReader &reader, QXmlStreamWriter &writer);
+ void parseNewServices(QXmlStreamWriter &writer);
void parseActivity(QXmlStreamReader &reader, QXmlStreamWriter &writer);
bool parseMetaData(QXmlStreamReader &reader, QXmlStreamWriter &writer);
void parseUsesSdk(QXmlStreamReader &reader, QXmlStreamWriter &writer);
@@ -170,7 +153,7 @@ private:
QXmlStreamWriter &writer,
const QSet<QString> &permissions);
QString parseComment(QXmlStreamReader &reader, QXmlStreamWriter &writer);
- void parseUnknownElement(QXmlStreamReader &reader, QXmlStreamWriter &writer);
+ void parseUnknownElement(QXmlStreamReader &reader, QXmlStreamWriter &writer, bool ignore=false);
bool m_dirty; // indicates that we need to call syncToEditor()
bool m_stayClean;
@@ -190,19 +173,7 @@ private:
QLineEdit *m_activityNameLineEdit;
QComboBox *m_targetLineEdit;
QComboBox *m_styleExtractMethod;
- QToolButton *m_masterIconButton;
- QToolButton *m_lIconButton;
- QToolButton *m_lIconClearButton;
- QLabel *m_lIconScaleWarningLabel;
- QToolButton *m_mIconButton;
- QToolButton *m_mIconClearButton;
- QLabel *m_mIconScaleWarningLabel;
- QToolButton *m_hIconButton;
- QToolButton *m_hIconClearButton;
- QLabel *m_hIconScaleWarningLabel;
- QString m_lIconPath;
- QString m_mIconPath;
- QString m_hIconPath;
+ AndroidManifestEditorIconContainerWidget *m_iconButtons;
// Permissions
QCheckBox *m_defaultPermissonsCheckBox;
@@ -213,6 +184,8 @@ private:
QPushButton *m_removePermissionButton;
QComboBox *m_permissionsComboBox;
+ // Services
+ AndroidServiceWidget *m_services;
QTimer m_timerParseCheck;
TextEditor::TextEditorWidget *m_textEditorWidget;
AndroidManifestEditor *m_editor;
diff --git a/src/plugins/android/androidpackageinstallationstep.cpp b/src/plugins/android/androidpackageinstallationstep.cpp
index 9017513974..b16a8e864e 100644
--- a/src/plugins/android/androidpackageinstallationstep.cpp
+++ b/src/plugins/android/androidpackageinstallationstep.cpp
@@ -28,13 +28,14 @@
#include "androidconstants.h"
#include "androidmanager.h"
-#include <projectexplorer/buildsteplist.h>
-#include <projectexplorer/target.h>
+#include <projectexplorer/abstractprocessstep.h>
#include <projectexplorer/buildconfiguration.h>
+#include <projectexplorer/buildsteplist.h>
#include <projectexplorer/gnumakeparser.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/processparameters.h>
#include <projectexplorer/projectexplorerconstants.h>
+#include <projectexplorer/target.h>
#include <projectexplorer/toolchain.h>
#include <utils/hostosinfo.h>
@@ -44,9 +45,39 @@
using namespace ProjectExplorer;
using namespace Utils;
-using namespace Android::Internal;
namespace Android {
+namespace Internal {
+
+class AndroidPackageInstallationStep final : public AbstractProcessStep
+{
+ Q_DECLARE_TR_FUNCTIONS(Android::AndroidPackageInstallationStep)
+
+public:
+ AndroidPackageInstallationStep(BuildStepList *bsl, Core::Id id);
+
+ BuildStepConfigWidget *createConfigWidget() final;
+
+private:
+ bool init() final;
+ void setupOutputFormatter(Utils::OutputFormatter *formatter) override;
+ void doRun() final;
+
+ QStringList m_androidDirsToClean;
+};
+
+class AndroidPackageInstallationStepWidget final : public BuildStepConfigWidget
+{
+ Q_DECLARE_TR_FUNCTIONS(Android::AndroidPackageInstallationStepWidget)
+
+public:
+ AndroidPackageInstallationStepWidget(BuildStep *step)
+ : BuildStepConfigWidget(step)
+ {
+ setDisplayName(tr("Make install"));
+ setSummaryText("<b>" + tr("Make install") + "</b>");
+ }
+};
AndroidPackageInstallationStep::AndroidPackageInstallationStep(BuildStepList *bsl, Core::Id id)
: AbstractProcessStep(bsl, id)
@@ -60,35 +91,27 @@ AndroidPackageInstallationStep::AndroidPackageInstallationStep(BuildStepList *bs
bool AndroidPackageInstallationStep::init()
{
- BuildConfiguration *bc = buildConfiguration();
- QString dirPath = bc->buildDirectory().pathAppended(Constants::ANDROID_BUILDDIRECTORY).toString();
+ QString dirPath = buildDirectory().pathAppended(Constants::ANDROID_BUILDDIRECTORY).toString();
if (HostOsInfo::isWindowsHost())
- if (bc->environment().searchInPath("sh.exe").isEmpty())
+ if (buildEnvironment().searchInPath("sh.exe").isEmpty())
dirPath = QDir::toNativeSeparators(dirPath);
- ToolChain *tc = ToolChainKitAspect::toolChain(target()->kit(),
- ProjectExplorer::Constants::CXX_LANGUAGE_ID);
+ ToolChain *tc = ToolChainKitAspect::cxxToolChain(target()->kit());
QTC_ASSERT(tc, return false);
- CommandLine cmd{tc->makeCommand(bc->environment())};
+ CommandLine cmd{tc->makeCommand(buildEnvironment())};
const QString innerQuoted = QtcProcess::quoteArg(dirPath);
const QString outerQuoted = QtcProcess::quoteArg("INSTALL_ROOT=" + innerQuoted);
cmd.addArgs(outerQuoted + " install", CommandLine::Raw);
ProcessParameters *pp = processParameters();
- pp->setMacroExpander(bc->macroExpander());
- pp->setWorkingDirectory(bc->buildDirectory());
- Environment env = bc->environment();
+ pp->setMacroExpander(macroExpander());
+ pp->setWorkingDirectory(buildDirectory());
+ Environment env = buildEnvironment();
Environment::setupEnglishOutput(&env);
pp->setEnvironment(env);
pp->setCommandLine(cmd);
- setOutputParser(new GnuMakeParser());
- IOutputParser *parser = target()->kit()->createOutputParser();
- if (parser)
- appendOutputParser(parser);
- outputParser()->setWorkingDirectory(pp->effectiveWorkingDirectory());
-
m_androidDirsToClean.clear();
// don't remove gradle's cache, it takes ages to rebuild it.
m_androidDirsToClean << dirPath + "/assets";
@@ -97,6 +120,14 @@ bool AndroidPackageInstallationStep::init()
return AbstractProcessStep::init();
}
+void AndroidPackageInstallationStep::setupOutputFormatter(OutputFormatter *formatter)
+{
+ formatter->addLineParser(new GnuMakeParser);
+ formatter->addLineParsers(target()->kit()->createOutputParsers());
+ formatter->addSearchDir(processParameters()->effectiveWorkingDirectory());
+ AbstractProcessStep::setupOutputFormatter(formatter);
+}
+
void AndroidPackageInstallationStep::doRun()
{
QString error;
@@ -119,20 +150,6 @@ BuildStepConfigWidget *AndroidPackageInstallationStep::createConfigWidget()
return new AndroidPackageInstallationStepWidget(this);
}
-
-//
-// AndroidPackageInstallationStepWidget
-//
-
-namespace Internal {
-
-AndroidPackageInstallationStepWidget::AndroidPackageInstallationStepWidget(AndroidPackageInstallationStep *step)
- : BuildStepConfigWidget(step)
-{
- setDisplayName(tr("Make install"));
- setSummaryText("<b>" + tr("Make install") + "</b>");
-}
-
//
// AndroidPackageInstallationStepFactory
//
diff --git a/src/plugins/android/androidpackageinstallationstep.h b/src/plugins/android/androidpackageinstallationstep.h
index f9e2c7d493..80300f2997 100644
--- a/src/plugins/android/androidpackageinstallationstep.h
+++ b/src/plugins/android/androidpackageinstallationstep.h
@@ -25,39 +25,12 @@
#pragma once
-#include "android_global.h"
-
#include <projectexplorer/buildstep.h>
-#include <projectexplorer/abstractprocessstep.h>
namespace Android {
-
-class ANDROID_EXPORT AndroidPackageInstallationStep : public ProjectExplorer::AbstractProcessStep
-{
- Q_OBJECT
-
-public:
- AndroidPackageInstallationStep(ProjectExplorer::BuildStepList *bsl, Core::Id id);
-
- ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override;
-
-private:
- bool init() override;
- void doRun() override;
-
- QStringList m_androidDirsToClean;
-};
-
namespace Internal {
-class AndroidPackageInstallationStepWidget : public ProjectExplorer::BuildStepConfigWidget
-{
- Q_OBJECT
-public:
- AndroidPackageInstallationStepWidget(AndroidPackageInstallationStep *step);
-};
-
-class AndroidPackageInstallationFactory: public ProjectExplorer::BuildStepFactory
+class AndroidPackageInstallationFactory final : public ProjectExplorer::BuildStepFactory
{
public:
AndroidPackageInstallationFactory();
diff --git a/src/plugins/android/androidqtversion.cpp b/src/plugins/android/androidqtversion.cpp
index 9b6a2df57c..b3b602830a 100644
--- a/src/plugins/android/androidqtversion.cpp
+++ b/src/plugins/android/androidqtversion.cpp
@@ -124,7 +124,9 @@ Abis AndroidQtVersion::detectQtAbis() const
void AndroidQtVersion::addToEnvironment(const Kit *k, Utils::Environment &env) const
{
- const AndroidConfig &config =AndroidConfigurations::currentConfig();
+ BaseQtVersion::addToEnvironment(k, env);
+
+ const AndroidConfig &config = AndroidConfigurations::currentConfig();
// this env vars are used by qmake mkspecs to generate makefiles (check QTDIR/mkspecs/android-g++/qmake.conf for more info)
env.set(QLatin1String("ANDROID_NDK_HOST"), config.toolchainHost(this));
env.set(QLatin1String("ANDROID_NDK_ROOT"), config.ndkLocation(this).toUserOutput());
diff --git a/src/plugins/android/androidrunner.cpp b/src/plugins/android/androidrunner.cpp
index 62328589b5..566bfbc820 100644
--- a/src/plugins/android/androidrunner.cpp
+++ b/src/plugins/android/androidrunner.cpp
@@ -34,7 +34,6 @@
#include "androidavdmanager.h"
#include "androidrunnerworker.h"
-#include <QHostAddress>
#include <coreplugin/messagemanager.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projectexplorersettings.h>
@@ -42,6 +41,7 @@
#include <projectexplorer/target.h>
#include <utils/url.h>
+#include <QHostAddress>
#include <QLoggingCategory>
namespace {
@@ -51,70 +51,6 @@ static Q_LOGGING_CATEGORY(androidRunnerLog, "qtc.android.run.androidrunner", QtW
using namespace ProjectExplorer;
using namespace Utils;
-/*
- This uses explicit handshakes between the application and the
- gdbserver start and the host side by using the gdbserver socket.
-
- For the handshake there are two mechanisms. Only the first method works
- on Android 5.x devices and is chosen as default option. The second
- method can be enabled by setting the QTC_ANDROID_USE_FILE_HANDSHAKE
- environment variable before starting Qt Creator.
-
- 1.) This method uses a TCP server on the Android device which starts
- listening for incoming connections. The socket is forwarded by adb
- and creator connects to it. This is the only method that works
- on Android 5.x devices.
-
- 2.) This method uses two files ("ping" file in the application dir,
- "pong" file in /data/local/tmp/qt).
-
- The sequence is as follows:
-
- host: adb forward debugsocket :5039
-
- host: adb shell rm pong file
- host: adb shell am start
- host: loop until ping file appears
-
- app start up: launch gdbserver --multi +debug-socket
- app start up: loop until debug socket appear
-
- gdbserver: normal start up including opening debug-socket,
- not yet attached to any process
-
- app start up: 1.) set up ping connection or 2.) touch ping file
- app start up: 1.) accept() or 2.) loop until pong file appears
-
- host: start gdb
- host: gdb: set up binary, breakpoints, path etc
- host: gdb: target extended-remote :5039
-
- gdbserver: accepts connection from gdb
-
- host: gdb: attach <application-pid>
-
- gdbserver: attaches to the application
- and stops it
-
- app start up: stopped now (it is still waiting for
- the pong anyway)
-
- host: gdb: continue
-
- gdbserver: resumes application
-
- app start up: resumed (still waiting for the pong)
-
- host: 1) write "ok" to ping pong connection or 2.) write pong file
-
- app start up: java code continues now, the process
- is already fully under control
- of gdbserver. Breakpoints are set etc,
- we are before main.
- app start up: native code launches
-
-*/
-
namespace Android {
namespace Internal {
@@ -132,7 +68,10 @@ AndroidRunner::AndroidRunner(RunControl *runControl, const QString &intentName)
m_checkAVDTimer.setInterval(2000);
connect(&m_checkAVDTimer, &QTimer::timeout, this, &AndroidRunner::checkAVD);
- QString intent = intentName.isEmpty() ? AndroidManager::intentName(m_target) : intentName;
+ QString intent = intentName;
+ if (intent.isEmpty())
+ intent = AndroidManager::packageName(m_target) + '/' + AndroidManager::activityName(m_target);
+
m_packageName = intent.left(intent.indexOf('/'));
qCDebug(androidRunnerLog) << "Intent name:" << intent << "Package name" << m_packageName;
@@ -212,22 +151,22 @@ void AndroidRunner::qmlServerPortReady(Port port)
void AndroidRunner::remoteOutput(const QString &output)
{
Core::MessageManager::write("LOGCAT: " + output, Core::MessageManager::Silent);
- appendMessage(output, Utils::StdOutFormatSameLine);
+ appendMessage(output, Utils::StdOutFormat);
m_outputParser.processOutput(output);
}
void AndroidRunner::remoteErrorOutput(const QString &output)
{
Core::MessageManager::write("LOGCAT: " + output, Core::MessageManager::Silent);
- appendMessage(output, Utils::StdErrFormatSameLine);
+ appendMessage(output, Utils::StdErrFormat);
m_outputParser.processOutput(output);
}
-void AndroidRunner::handleRemoteProcessStarted(Utils::Port gdbServerPort,
+void AndroidRunner::handleRemoteProcessStarted(Utils::Port debugServerPort,
const QUrl &qmlServer, qint64 pid)
{
m_pid = ProcessHandle(pid);
- m_gdbServerPort = gdbServerPort;
+ m_debugServerPort = debugServerPort;
m_qmlServer = qmlServer;
reportStarted();
}
diff --git a/src/plugins/android/androidrunner.h b/src/plugins/android/androidrunner.h
index 86defe19ce..e745305d32 100644
--- a/src/plugins/android/androidrunner.h
+++ b/src/plugins/android/androidrunner.h
@@ -53,7 +53,7 @@ public:
const QString &intentName = QString());
~AndroidRunner() override;
- Utils::Port gdbServerPort() const { return m_gdbServerPort; }
+ Utils::Port debugServerPort() const { return m_debugServerPort; } // GDB or LLDB
QUrl qmlServer() const { return m_qmlServer; }
Utils::ProcessHandle pid() const { return m_pid; }
@@ -72,7 +72,7 @@ private:
void remoteOutput(const QString &output);
void remoteErrorOutput(const QString &output);
void gotRemoteOutput(const QString &output);
- void handleRemoteProcessStarted(Utils::Port gdbServerPort, const QUrl &qmlServer, qint64 pid);
+ void handleRemoteProcessStarted(Utils::Port debugServerPort, const QUrl &qmlServer, qint64 pid);
void handleRemoteProcessFinished(const QString &errString = QString());
void checkAVD();
void launchAVD();
@@ -83,7 +83,7 @@ private:
QTimer m_checkAVDTimer;
QScopedPointer<AndroidRunnerWorker> m_worker;
QPointer<ProjectExplorer::Target> m_target;
- Utils::Port m_gdbServerPort;
+ Utils::Port m_debugServerPort;
QUrl m_qmlServer;
Utils::ProcessHandle m_pid;
QmlDebug::QmlOutputParser m_outputParser;
diff --git a/src/plugins/android/androidrunnerworker.cpp b/src/plugins/android/androidrunnerworker.cpp
index 1fb878109f..1b026bc615 100644
--- a/src/plugins/android/androidrunnerworker.cpp
+++ b/src/plugins/android/androidrunnerworker.cpp
@@ -30,6 +30,7 @@
#include "androidmanager.h"
#include "androidrunconfiguration.h"
+#include <debugger/debuggerkitinformation.h>
#include <debugger/debuggerrunconfigurationaspect.h>
#include <projectexplorer/environmentaspect.h>
@@ -48,7 +49,11 @@
#include <utils/url.h>
#include <utils/fileutils.h>
+#include <QDir>
+#include <QDirIterator>
+#include <QFileInfo>
#include <QLoggingCategory>
+#include <QScopeGuard>
#include <QTcpServer>
#include <QThread>
@@ -156,16 +161,95 @@ static void deleter(QProcess *p)
p->deleteLater();
}
+static QString gdbServerArch(const QString &androidAbi)
+{
+ if (androidAbi == "arm64-v8a")
+ return QString("arm64");
+ if (androidAbi == "armeabi-v7a")
+ return QString("arm");
+ // That's correct for "x86_64" and "x86", and best guess at anything that will evolve:
+ return androidAbi;
+}
+
+static QString lldbServerArch(const QString &androidAbi)
+{
+ if (androidAbi == "armeabi-v7a")
+ return QString("armeabi");
+ // Correct for arm64-v8a "x86_64" and "x86", and best guess at anything that will evolve:
+ return androidAbi; // arm64-v8a, x86, x86_64
+}
+
+static QString lldbServerArch2(const QString &androidAbi)
+{
+ if (androidAbi == "armeabi-v7a")
+ return {"arm"};
+ if (androidAbi == "x86")
+ return {"i386"};
+ if (androidAbi == "arm64-v8a")
+ return {"aarch64"};
+ // Correct for "x86_64" a and best guess at anything that will evolve:
+ return androidAbi; // arm64-v8a
+}
+
+static FilePath debugServer(bool useLldb, const Target *target)
+{
+ QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitAspect::qtVersion(target->kit());
+ QString preferredAbi = AndroidManager::apkDevicePreferredAbi(target);
+
+ const AndroidConfig &config = AndroidConfigurations::currentConfig();
+
+ if (useLldb) {
+ // Search suitable lldb-server binary.
+ const FilePath prebuilt = config.ndkLocation(qtVersion) / "toolchains/llvm/prebuilt";
+ const QString abiNeedle = lldbServerArch2(preferredAbi);
+
+ // The new, built-in LLDB.
+ QDirIterator it(prebuilt.toString(), QDir::Files|QDir::Executable, QDirIterator::Subdirectories);
+ while (it.hasNext()) {
+ it.next();
+ const QString filePath = it.filePath();
+ if (filePath.endsWith(abiNeedle + "/lldb-server")) {
+ return FilePath::fromString(filePath);
+ }
+ }
+
+ // Older: Find LLDB version. sdk_definitions.json contains something like "lldb;3.1". Use that.
+ const QStringList packages = config.defaultEssentials();
+ for (const QString &package : packages) {
+ if (package.startsWith("lldb;")) {
+ const QString lldbVersion = package.mid(5);
+ const FilePath path = config.sdkLocation()
+ / QString("lldb/%1/android/%2/lldb-server")
+ .arg(lldbVersion, lldbServerArch(preferredAbi));
+ if (path.exists())
+ return path;
+ }
+ }
+ } else {
+ // Search suitable gdbserver binary.
+ const FilePath path = config.ndkLocation(qtVersion)
+ .pathAppended(QString("prebuilt/android-%1/gdbserver/gdbserver")
+ .arg(gdbServerArch(preferredAbi)));
+ if (path.exists())
+ return path;
+ }
+
+ return {};
+}
+
+
AndroidRunnerWorker::AndroidRunnerWorker(RunWorker *runner, const QString &packageName)
: m_packageName(packageName)
, m_adbLogcatProcess(nullptr, deleter)
, m_psIsAlive(nullptr, deleter)
, m_logCatRegExp(regExpLogcat)
- , m_gdbServerProcess(nullptr, deleter)
+ , m_debugServerProcess(nullptr, deleter)
, m_jdbProcess(nullptr, deleter)
{
auto runControl = runner->runControl();
+ m_useLldb = Debugger::DebuggerKitAspect::engineType(runControl->kit())
+ == Debugger::LldbEngineType;
auto aspect = runControl->aspect<Debugger::DebuggerRunConfigurationAspect>();
Core::Id runMode = runControl->runMode();
const bool debuggingMode = runMode == ProjectExplorer::Constants::DEBUG_RUN_MODE;
@@ -178,8 +262,8 @@ AndroidRunnerWorker::AndroidRunnerWorker(RunWorker *runner, const QString &packa
m_qmlDebugServices = QmlDebug::QmlPreviewServices;
else
m_qmlDebugServices = QmlDebug::NoQmlDebugServices;
- m_localGdbServerPort = Utils::Port(5039);
- QTC_CHECK(m_localGdbServerPort.isValid());
+ m_localDebugServerPort = Utils::Port(5039);
+ QTC_CHECK(m_localDebugServerPort.isValid());
if (m_qmlDebugServices != QmlDebug::NoQmlDebugServices) {
qCDebug(androidRunWorkerLog) << "QML debugging enabled";
QTcpServer server;
@@ -220,16 +304,15 @@ AndroidRunnerWorker::AndroidRunnerWorker(RunWorker *runner, const QString &packa
for (const QString &shellCmd : runner->recordedData(Constants::ANDROID_POSTFINISHSHELLCMDLIST).toStringList())
m_afterFinishAdbCommands.append(QString("shell %1").arg(shellCmd));
+ m_debugServerPath = debugServer(m_useLldb, target).toString();
qCDebug(androidRunWorkerLog) << "Device Serial:" << m_deviceSerialNumber
<< "API level:" << m_apiLevel
<< "Extra Start Args:" << m_amStartExtraArgs
<< "Before Start ADB cmds:" << m_beforeStartAdbCommands
- << "After finish ADB cmds:" << m_afterFinishAdbCommands;
+ << "After finish ADB cmds:" << m_afterFinishAdbCommands
+ << "Debug server path:" << m_debugServerPath;
+
QtSupport::BaseQtVersion *version = QtSupport::QtKitAspect::qtVersion(target->kit());
- QString preferredAbi = AndroidManager::apkDevicePreferredAbi(target);
- if (!preferredAbi.isEmpty())
- m_gdbserverPath = AndroidConfigurations::instance()
- ->currentConfig().gdbServer(preferredAbi, version).toString();
m_useAppParamsForQmlDebugger = version->qtVersion() >= QtSupport::QtVersionNumber(5, 12);
}
@@ -254,45 +337,41 @@ bool AndroidRunnerWorker::runAdb(const QStringList &args, QString *stdOut,
return result.success();
}
-bool AndroidRunnerWorker::uploadGdbServer()
+bool AndroidRunnerWorker::uploadDebugServer(const QString &debugServerFileName)
{
- // Push the gdbserver to temp location and then to package dir.
+ // Push the gdbserver or lldb-server to temp location and then to package dir.
// the files can't be pushed directly to package because of permissions.
qCDebug(androidRunWorkerLog) << "Uploading GdbServer";
- bool foundUnique = true;
- auto cleanUp = [this, &foundUnique] (QString *p) {
- if (foundUnique && !runAdb({"shell", "rm", "-f", *p}))
- qCDebug(androidRunWorkerLog) << "Gdbserver cleanup failed.";
- delete p;
- };
- std::unique_ptr<QString, decltype (cleanUp)>
- tempGdbServerPath(new QString("/data/local/tmp/%1"), cleanUp);
-
- // Get a unique temp file name for gdbserver copy
+ // Get a unique temp file name for gdb/lldbserver copy
+ const QString tempDebugServerPathTemplate = "/data/local/tmp/%1";
int count = 0;
- while (deviceFileExists(tempGdbServerPath->arg(++count))) {
+ while (deviceFileExists(tempDebugServerPathTemplate.arg(++count))) {
if (count > GdbTempFileMaxCounter) {
qCDebug(androidRunWorkerLog) << "Can not get temporary file name";
- foundUnique = false;
return false;
}
}
- *tempGdbServerPath = tempGdbServerPath->arg(count);
+
+ const QString tempDebugServerPath = tempDebugServerPathTemplate.arg(count);
+ auto cleanUp = qScopeGuard([this, tempDebugServerPath] {
+ if (!runAdb({"shell", "rm", "-f", tempDebugServerPath}))
+ qCDebug(androidRunWorkerLog) << "Debug server cleanup failed.";
+ });
// Copy gdbserver to temp location
- if (!runAdb({"push", m_gdbserverPath , *tempGdbServerPath})) {
- qCDebug(androidRunWorkerLog) << "Gdbserver upload to temp directory failed";
+ if (!runAdb({"push", m_debugServerPath , tempDebugServerPath})) {
+ qCDebug(androidRunWorkerLog) << "Debug server upload to temp directory failed";
return false;
}
// Copy gdbserver from temp location to app directory
- if (!runAdb({"shell", "run-as", m_packageName, "cp" , *tempGdbServerPath, "./gdbserver"})) {
- qCDebug(androidRunWorkerLog) << "Gdbserver copy from temp directory failed";
+ if (!runAdb({"shell", "run-as", m_packageName, "cp" , tempDebugServerPath, debugServerFileName})) {
+ qCDebug(androidRunWorkerLog) << "Debug server copy from temp directory failed";
return false;
}
- QTC_ASSERT(runAdb({"shell", "run-as", m_packageName, "chmod", "777", "./gdbserver"}),
- qCDebug(androidRunWorkerLog) << "Gdbserver chmod 777 failed.");
+ QTC_ASSERT(runAdb({"shell", "run-as", m_packageName, "chmod", "777", debugServerFileName}),
+ qCDebug(androidRunWorkerLog) << "Debug server chmod 777 failed.");
return true;
}
@@ -447,32 +526,47 @@ void AndroidRunnerWorker::asyncStartHelper()
// e.g. on Android 8 with NDK 10e
runAdb({"shell", "run-as", m_packageName, "chmod", "a+x", packageDir.trimmed()});
- QString gdbServerExecutable = "gdbserver";
- QString gdbServerPrefix = "./lib/";
- auto findGdbServer = [this, &gdbServerExecutable, gdbServerPrefix](const QString& gdbEx) {
- if (!packageFileExists(gdbServerPrefix + gdbEx))
- return false;
- gdbServerExecutable = gdbEx;
- return true;
- };
-
- if (!findGdbServer("gdbserver") && !findGdbServer("libgdbserver.so")) {
- // Armv8. symlink lib is not available.
- // Kill the previous instances of gdbserver. Do this before copying the gdbserver.
- runAdb({"shell", "run-as", m_packageName, "killall", gdbServerExecutable});
- if (!m_gdbserverPath.isEmpty() && uploadGdbServer()) {
- gdbServerPrefix = "./";
- } else {
- emit remoteProcessFinished(tr("Cannot find or copy C++ debug server."));
+ if (!QFileInfo::exists(m_debugServerPath)) {
+ QString msg = tr("Cannot find C++ debug server in NDK installation");
+ if (m_useLldb) {
+ msg += "\n" + tr("The lldb-server binary has not been found. Maybe "
+ "sdk_definitions.json does not contain 'lldb;x.y' as "
+ "sdk_essential_package or LLDB was not installed.");
+ }
+ emit remoteProcessFinished(msg);
+ return;
+ }
+
+ QString debugServerFile;
+ if (m_useLldb) {
+ debugServerFile = "./lldb-server";
+ runAdb({"shell", "run-as", m_packageName, "killall", "lldb-server"});
+ if (!uploadDebugServer(debugServerFile)) {
+ emit remoteProcessFinished(tr("Cannot copy C++ debug server."));
return;
}
} else {
- qCDebug(androidRunWorkerLog) << "Found GDB server under ./lib";
- runAdb({"shell", "run-as", m_packageName, "killall", gdbServerExecutable});
+ if (packageFileExists("./lib/gdbserver")) {
+ debugServerFile = "./lib/gdbserver";
+ qCDebug(androidRunWorkerLog) << "Found GDB server " + debugServerFile;
+ runAdb({"shell", "run-as", m_packageName, "killall", "gdbserver"});
+ } else if (packageFileExists("./lib/libgdbserver.so")) {
+ debugServerFile = "./lib/libgdbserver.so";
+ qCDebug(androidRunWorkerLog) << "Found GDB server " + debugServerFile;
+ runAdb({"shell", "run-as", m_packageName, "killall", "libgdbserver.so"});
+ } else {
+ // Armv8. symlink lib is not available.
+ debugServerFile = "./gdbserver";
+ // Kill the previous instances of gdbserver. Do this before copying the gdbserver.
+ runAdb({"shell", "run-as", m_packageName, "killall", "gdbserver"});
+ if (!uploadDebugServer("./gdbserver")) {
+ emit remoteProcessFinished(tr("Cannot copy C++ debug server."));
+ return;
+ }
+ }
}
-
QString debuggerServerErr;
- if (!startDebuggerServer(packageDir, gdbServerPrefix, gdbServerExecutable, &debuggerServerErr)) {
+ if (!startDebuggerServer(packageDir, debugServerFile, &debuggerServerErr)) {
emit remoteProcessFinished(debuggerServerErr);
return;
}
@@ -525,37 +619,56 @@ void AndroidRunnerWorker::asyncStartHelper()
}
bool AndroidRunnerWorker::startDebuggerServer(const QString &packageDir,
- const QString &gdbServerPrefix,
- const QString &gdbServerExecutable,
+ const QString &debugServerFile,
QString *errorStr)
{
- QString gdbServerSocket = packageDir + "/debug-socket";
- runAdb({"shell", "run-as", m_packageName, "rm", gdbServerSocket});
-
- QString gdbProcessErr;
- QStringList gdbServerArgs = selector();
- gdbServerArgs << "shell" << "run-as" << m_packageName << gdbServerPrefix + gdbServerExecutable
- << "--multi" << "+" + gdbServerSocket;
- m_gdbServerProcess.reset(AndroidManager::runAdbCommandDetached(gdbServerArgs, &gdbProcessErr));
-
- if (!m_gdbServerProcess) {
- qCDebug(androidRunWorkerLog) << "Debugger process failed to start" << gdbProcessErr;
- if (errorStr)
- *errorStr = tr("Failed to start debugger server.");
- return false;
- }
- qCDebug(androidRunWorkerLog) << "Debugger process started";
- m_gdbServerProcess->setObjectName("AndroidDebugServerProcess");
+ if (m_useLldb) {
+ QString lldbServerErr;
+ QStringList lldbServerArgs = selector();
+ lldbServerArgs << "shell" << "run-as" << m_packageName << debugServerFile
+ << "platform"
+ // << "--server" // Can lead to zombie servers
+ << "--listen" << QString("*:%1").arg(m_localDebugServerPort.toString());
+ m_debugServerProcess.reset(AndroidManager::runAdbCommandDetached(lldbServerArgs, &lldbServerErr));
+
+ if (!m_debugServerProcess) {
+ qCDebug(androidRunWorkerLog) << "Debugger process failed to start" << lldbServerErr;
+ if (errorStr)
+ *errorStr = tr("Failed to start debugger server.");
+ return false;
+ }
+ qCDebug(androidRunWorkerLog) << "Debugger process started";
+ m_debugServerProcess->setObjectName("AndroidDebugServerProcess");
- QStringList removeForward{"forward", "--remove", "tcp:" + m_localGdbServerPort.toString()};
- runAdb(removeForward);
- if (!runAdb({"forward", "tcp:" + m_localGdbServerPort.toString(),
- "localfilesystem:" + gdbServerSocket})) {
- if (errorStr)
- *errorStr = tr("Failed to forward C++ debugging ports.");
- return false;
+ } else {
+ QString gdbServerSocket = packageDir + "/debug-socket";
+ runAdb({"shell", "run-as", m_packageName, "rm", gdbServerSocket});
+
+ QString gdbProcessErr;
+ QStringList gdbServerErr = selector();
+ gdbServerErr << "shell" << "run-as" << m_packageName << debugServerFile
+ << "--multi" << "+" + gdbServerSocket;
+ m_debugServerProcess.reset(AndroidManager::runAdbCommandDetached(gdbServerErr, &gdbProcessErr));
+
+ if (!m_debugServerProcess) {
+ qCDebug(androidRunWorkerLog) << "Debugger process failed to start" << gdbServerErr;
+ if (errorStr)
+ *errorStr = tr("Failed to start debugger server.");
+ return false;
+ }
+ qCDebug(androidRunWorkerLog) << "Debugger process started";
+ m_debugServerProcess->setObjectName("AndroidDebugServerProcess");
+
+ QStringList removeForward{"forward", "--remove", "tcp:" + m_localDebugServerPort.toString()};
+ runAdb(removeForward);
+ if (!runAdb({"forward", "tcp:" + m_localDebugServerPort.toString(),
+ "localfilesystem:" + gdbServerSocket})) {
+ if (errorStr)
+ *errorStr = tr("Failed to forward C++ debugging ports.");
+ return false;
+ }
+ m_afterFinishAdbCommands.push_back(removeForward.join(' '));
}
- m_afterFinishAdbCommands.push_back(removeForward.join(' '));
return true;
}
@@ -577,7 +690,7 @@ void AndroidRunnerWorker::asyncStop()
forceStop();
m_jdbProcess.reset();
- m_gdbServerProcess.reset();
+ m_debugServerProcess.reset();
}
void AndroidRunnerWorker::handleJdbWaiting()
@@ -612,7 +725,7 @@ void AndroidRunnerWorker::handleJdbWaiting()
void AndroidRunnerWorker::handleJdbSettled()
{
qCDebug(androidRunWorkerLog) << "Handle JDB settled";
- auto waitForCommand = [&]() {
+ auto waitForCommand = [this]() {
for (int i= 0; i < 5 && m_jdbProcess->state() == QProcess::Running; ++i) {
m_jdbProcess->waitForReadyRead(500);
QByteArray lines = m_jdbProcess->readAll();
@@ -655,11 +768,11 @@ void AndroidRunnerWorker::onProcessIdChanged(qint64 pid)
if (pid == -1) {
emit remoteProcessFinished(QLatin1String("\n\n") + tr("\"%1\" died.")
.arg(m_packageName));
- // App died/killed. Reset log, monitor, jdb & gdb processes.
+ // App died/killed. Reset log, monitor, jdb & gdbserver/lldb-server processes.
m_adbLogcatProcess.reset();
m_psIsAlive.reset();
m_jdbProcess.reset();
- m_gdbServerProcess.reset();
+ m_debugServerProcess.reset();
// Run adb commands after application quit.
for (const QString &entry: m_afterFinishAdbCommands)
@@ -667,7 +780,7 @@ void AndroidRunnerWorker::onProcessIdChanged(qint64 pid)
} else {
// In debugging cases this will be funneled to the engine to actually start
// and attach gdb. Afterwards this ends up in handleRemoteDebuggerRunning() below.
- emit remoteProcessStarted(m_localGdbServerPort, m_qmlServer, m_processPID);
+ emit remoteProcessStarted(m_localDebugServerPort, m_qmlServer, m_processPID);
logcatReadStandardOutput();
QTC_ASSERT(!m_psIsAlive, /**/);
QStringList isAliveArgs = selector() << "shell" << pidPollingScript.arg(m_processPID);
diff --git a/src/plugins/android/androidrunnerworker.h b/src/plugins/android/androidrunnerworker.h
index ae43200d8d..f889e9e90d 100644
--- a/src/plugins/android/androidrunnerworker.h
+++ b/src/plugins/android/androidrunnerworker.h
@@ -64,7 +64,7 @@ public:
void handleJdbSettled();
signals:
- void remoteProcessStarted(Utils::Port gdbServerPort, const QUrl &qmlServer, qint64 pid);
+ void remoteProcessStarted(Utils::Port debugServerPort, const QUrl &qmlServer, qint64 pid);
void remoteProcessFinished(const QString &errString = QString());
void remoteOutput(const QString &output);
@@ -72,11 +72,10 @@ signals:
private:
void asyncStartHelper();
- bool startDebuggerServer(const QString &packageDir, const QString &gdbServerPrefix,
- const QString &gdbServerExecutable, QString *errorStr = nullptr);
+ bool startDebuggerServer(const QString &packageDir, const QString &debugServerFile, QString *errorStr = nullptr);
bool deviceFileExists(const QString &filePath);
bool packageFileExists(const QString& filePath);
- bool uploadGdbServer();
+ bool uploadDebugServer(const QString &debugServerFileName);
enum class JDBState {
Idle,
@@ -101,18 +100,19 @@ private:
QRegExp m_logCatRegExp;
QFuture<qint64> m_pidFinder;
bool m_useCppDebugger = false;
+ bool m_useLldb = false; // FIXME: Un-implemented currently.
QmlDebug::QmlDebugServicesPreset m_qmlDebugServices;
- Utils::Port m_localGdbServerPort; // Local end of forwarded debug socket.
+ Utils::Port m_localDebugServerPort; // Local end of forwarded debug socket.
QUrl m_qmlServer;
JDBState m_jdbState = JDBState::Idle;
Utils::Port m_localJdbServerPort;
- std::unique_ptr<QProcess, Deleter> m_gdbServerProcess;
+ std::unique_ptr<QProcess, Deleter> m_debugServerProcess; // gdbserver or lldb-server
std::unique_ptr<QProcess, Deleter> m_jdbProcess;
QString m_deviceSerialNumber;
int m_apiLevel = -1;
QString m_extraAppParams;
Utils::Environment m_extraEnvVars;
- QString m_gdbserverPath;
+ QString m_debugServerPath;
bool m_useAppParamsForQmlDebugger = false;
};
diff --git a/src/plugins/android/androidsdkmanager.cpp b/src/plugins/android/androidsdkmanager.cpp
index 3b58d81ad2..0dc7a67ba8 100644
--- a/src/plugins/android/androidsdkmanager.cpp
+++ b/src/plugins/android/androidsdkmanager.cpp
@@ -278,6 +278,7 @@ public:
NdkMarker = 0x800,
ExtrasMarker = 0x1000,
CmdlineSdkToolsMarker = 0x2000,
+ GenericToolMarker = 0x4000,
SectionMarkers = InstalledPackagesMarker | AvailablePackagesMarkers | AvailableUpdatesMarker
};
@@ -300,6 +301,7 @@ private:
EmulatorTools *parseEmulatorToolsPackage(const QStringList &data) const;
Ndk *parseNdkPackage(const QStringList &data) const;
ExtraTools *parseExtraToolsPackage(const QStringList &data) const;
+ GenericSdkPackage *parseGenericTools(const QStringList &data) const;
MarkerTag parseMarkers(const QString &line);
MarkerTag m_currentSection = MarkerTag::None;
@@ -321,8 +323,7 @@ const std::map<SdkManagerOutputParser::MarkerTag, const char *> markerTags {
{SdkManagerOutputParser::MarkerTag::ExtrasMarker, "extras"}
};
-AndroidSdkManager::AndroidSdkManager(const AndroidConfig &config, QObject *parent):
- QObject(parent),
+AndroidSdkManager::AndroidSdkManager(const AndroidConfig &config):
m_d(new AndroidSdkManagerPrivate(*this, config))
{
}
@@ -633,6 +634,10 @@ void SdkManagerOutputParser::parsePackageData(MarkerTag packageMarker, const QSt
createPackage(&SdkManagerOutputParser::parseExtraToolsPackage);
break;
+ case MarkerTag::GenericToolMarker:
+ createPackage(&SdkManagerOutputParser::parseGenericTools);
+ break;
+
default:
qCDebug(sdkManagerLog) << "Unhandled package: " << markerTags.at(packageMarker);
break;
@@ -833,6 +838,22 @@ ExtraTools *SdkManagerOutputParser::parseExtraToolsPackage(const QStringList &da
return extraTools;
}
+GenericSdkPackage *SdkManagerOutputParser::parseGenericTools(const QStringList &data) const
+{
+ GenericSdkPackage *sdkPackage = nullptr;
+ GenericPackageData packageData;
+ if (parseAbstractData(packageData, data, 1, "Generic")) {
+ sdkPackage = new GenericSdkPackage(packageData.revision, data.at(0));
+ sdkPackage->setDescriptionText(packageData.description);
+ sdkPackage->setDisplayText(packageData.description);
+ sdkPackage->setInstalledLocation(packageData.installedLocation);
+ } else {
+ qCDebug(sdkManagerLog) << "Generic: Parsing failed. Minimum required data "
+ "unavailable:" << data;
+ }
+ return sdkPackage;
+}
+
SdkManagerOutputParser::MarkerTag SdkManagerOutputParser::parseMarkers(const QString &line)
{
if (line.isEmpty())
@@ -843,6 +864,10 @@ SdkManagerOutputParser::MarkerTag SdkManagerOutputParser::parseMarkers(const QSt
return pair.first;
}
+ QRegularExpressionMatch match = QRegularExpression("^[a-zA-Z]+[A-Za-z0-9;._-]+").match(line);
+ if (match.hasMatch() && match.captured(0) == line)
+ return GenericToolMarker;
+
return None;
}
diff --git a/src/plugins/android/androidsdkmanager.h b/src/plugins/android/androidsdkmanager.h
index ce5cf4e299..16a1dab705 100644
--- a/src/plugins/android/androidsdkmanager.h
+++ b/src/plugins/android/androidsdkmanager.h
@@ -62,7 +62,7 @@ public:
QString stdError;
};
- AndroidSdkManager(const AndroidConfig &config, QObject *parent = nullptr);
+ explicit AndroidSdkManager(const AndroidConfig &config);
~AndroidSdkManager() override;
SdkPlatformList installedSdkPlatforms();
@@ -97,8 +97,8 @@ signals:
void cancelActiveOperations();
private:
- std::unique_ptr<AndroidSdkManagerPrivate> m_d;
friend class AndroidSdkManagerPrivate;
+ std::unique_ptr<AndroidSdkManagerPrivate> m_d;
};
} // namespace Internal
diff --git a/src/plugins/android/androidsdkmanagerwidget.cpp b/src/plugins/android/androidsdkmanagerwidget.cpp
index cb489716a9..f1ebaa097e 100644
--- a/src/plugins/android/androidsdkmanagerwidget.cpp
+++ b/src/plugins/android/androidsdkmanagerwidget.cpp
@@ -169,6 +169,13 @@ void AndroidSdkManagerWidget::setSdkManagerControlsEnabled(bool enable)
void AndroidSdkManagerWidget::installEssentials()
{
m_sdkModel->selectMissingEssentials();
+ if (!m_sdkModel->missingEssentials().isEmpty()) {
+ QMessageBox::warning(this,
+ tr("Android SDK Changes"),
+ tr("Qt Creator couldn't find the following essential packages: \"%1\".\n"
+ "Install them manually after the current operation is done.\n")
+ .arg(m_sdkModel->missingEssentials().join("\", \"")));
+ }
m_ui->applySelectionButton->click();
}
@@ -436,10 +443,8 @@ void AndroidSdkManagerWidget::cancelPendingOperations()
void AndroidSdkManagerWidget::switchView(AndroidSdkManagerWidget::View view)
{
- if (m_currentView == PackageListing) {
+ if (m_currentView == PackageListing)
m_formatter->clear();
- m_ui->outputEdit->clear();
- }
m_currentView = view;
if (m_currentView == PackageListing)
emit updatingSdkFinished();
diff --git a/src/plugins/android/androidsdkmodel.cpp b/src/plugins/android/androidsdkmodel.cpp
index b2dce193c5..91bd62f7c8 100644
--- a/src/plugins/android/androidsdkmodel.cpp
+++ b/src/plugins/android/androidsdkmodel.cpp
@@ -31,6 +31,11 @@
#include <utils/utilsicons.h>
#include <QIcon>
+#include <QLoggingCategory>
+
+namespace {
+static Q_LOGGING_CATEGORY(androidSdkModelLog, "qtc.android.sdkmodel", QtWarningMsg)
+}
namespace Android {
namespace Internal {
@@ -294,7 +299,9 @@ void AndroidSdkModel::selectMissingEssentials()
// Select SDK platform
for (const SdkPlatform *platform : m_sdkPlatforms) {
- if (pendingPkgs.contains(platform->sdkStylePath()) &&
+ if (!platform->installedLocation().isEmpty()) {
+ pendingPkgs.removeOne(platform->sdkStylePath());
+ } else if (pendingPkgs.contains(platform->sdkStylePath()) &&
platform->installedLocation().isEmpty()) {
auto i = index(0, 0, index(1, 0));
m_changeState << platform;
@@ -304,6 +311,9 @@ void AndroidSdkModel::selectMissingEssentials()
if (pendingPkgs.isEmpty())
break;
}
+
+ m_missingEssentials = pendingPkgs;
+ qCDebug(androidSdkModelLog) << "Couldn't find some essential packages:" << m_missingEssentials;
}
QList<const AndroidSdkPackage *> AndroidSdkModel::userSelection() const
diff --git a/src/plugins/android/androidsdkmodel.h b/src/plugins/android/androidsdkmodel.h
index b7f89f7997..af25edfbb8 100644
--- a/src/plugins/android/androidsdkmodel.h
+++ b/src/plugins/android/androidsdkmodel.h
@@ -70,6 +70,8 @@ public:
QList<const AndroidSdkPackage *> userSelection() const;
void resetSelection();
+ QStringList missingEssentials() const { return m_missingEssentials; }
+
private:
void clearContainers();
void refreshData();
@@ -80,6 +82,7 @@ private:
QList<const SdkPlatform *> m_sdkPlatforms;
QList<const AndroidSdkPackage *> m_tools;
QSet<const AndroidSdkPackage *> m_changeState;
+ QStringList m_missingEssentials;
};
} // namespace Internal
diff --git a/src/plugins/android/androidsdkpackage.cpp b/src/plugins/android/androidsdkpackage.cpp
index a3da9625bc..d444d99313 100644
--- a/src/plugins/android/androidsdkpackage.cpp
+++ b/src/plugins/android/androidsdkpackage.cpp
@@ -319,4 +319,19 @@ void Ndk::setAsNdkBundle(const bool isBundle)
m_isBundle = isBundle;
}
+GenericSdkPackage::GenericSdkPackage(QVersionNumber revision, QString sdkStylePathStr, QObject *parent) :
+ AndroidSdkPackage(revision, sdkStylePathStr, parent)
+{
+}
+
+bool GenericSdkPackage::isValid() const
+{
+ return installedLocation().exists();
+}
+
+AndroidSdkPackage::PackageType GenericSdkPackage::type() const
+{
+ return AndroidSdkPackage::GenericSdkPackage;
+}
+
} // namespace Android
diff --git a/src/plugins/android/androidsdkpackage.h b/src/plugins/android/androidsdkpackage.h
index eed0fd4395..af083b6adb 100644
--- a/src/plugins/android/androidsdkpackage.h
+++ b/src/plugins/android/androidsdkpackage.h
@@ -55,9 +55,10 @@ public:
EmulatorToolsPackage = 1 << 6,
NDKPackage = 1 << 7,
ExtraToolsPackage = 1 << 8,
+ GenericSdkPackage = 1 << 9,
AnyValidType = SdkToolsPackage | BuildToolsPackage | PlatformToolsPackage |
SdkPlatformPackage | SystemImagePackage | EmulatorToolsPackage | NDKPackage |
- ExtraToolsPackage
+ ExtraToolsPackage | GenericSdkPackage
};
enum PackageState {
@@ -221,6 +222,18 @@ public:
ExtraTools(QVersionNumber revision, QString sdkStylePathStr, QObject *parent = nullptr);
// AndroidSdkPackage Overrides
+public:
+ bool isValid() const override;
+ PackageType type() const override;
+};
+
+class GenericSdkPackage : public AndroidSdkPackage
+{
+public:
+ GenericSdkPackage(QVersionNumber revision, QString sdkStylePathStr, QObject *parent = nullptr);
+
+// AndroidSdkPackage Overrides
+public:
bool isValid() const override;
PackageType type() const override;
};
diff --git a/src/plugins/android/androidservicewidget.cpp b/src/plugins/android/androidservicewidget.cpp
new file mode 100644
index 0000000000..465d2e2600
--- /dev/null
+++ b/src/plugins/android/androidservicewidget.cpp
@@ -0,0 +1,410 @@
+/****************************************************************************
+**
+** 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 "androidservicewidget.h"
+#include "androidservicewidget_p.h"
+
+#include <utils/utilsicons.h>
+
+#include <QAbstractTableModel>
+#include <QGridLayout>
+#include <QHBoxLayout>
+#include <QHeaderView>
+#include <QPushButton>
+#include <QTableView>
+
+namespace Android {
+namespace Internal {
+
+bool AndroidServiceData::isValid() const
+{
+ return !m_className.isEmpty()
+ && (!m_isRunInExternalProcess || !m_externalProcessName.isEmpty())
+ && (!m_isRunInExternalLibrary || !m_externalLibName.isEmpty())
+ && (m_isRunInExternalLibrary || !m_serviceArguments.isEmpty());
+}
+
+void AndroidServiceData::setClassName(const QString &className)
+{
+ m_className = className;
+}
+
+QString AndroidServiceData::className() const
+{
+ return m_className;
+}
+
+void AndroidServiceData::setRunInExternalProcess(bool isRunInExternalProcess)
+{
+ m_isRunInExternalProcess = isRunInExternalProcess;
+ if (!m_isRunInExternalProcess) {
+ m_isRunInExternalLibrary = false;
+ m_externalProcessName.clear();
+ m_externalLibName.clear();
+ }
+}
+
+bool AndroidServiceData::isRunInExternalProcess() const
+{
+ return m_isRunInExternalProcess;
+}
+
+void AndroidServiceData::setExternalProcessName(const QString &externalProcessName)
+{
+ if (m_isRunInExternalProcess)
+ m_externalProcessName = externalProcessName;
+}
+
+QString AndroidServiceData::externalProcessName() const
+{
+ return m_externalProcessName;
+}
+
+void AndroidServiceData::setRunInExternalLibrary(bool isRunInExternalLibrary)
+{
+ if (m_isRunInExternalProcess)
+ m_isRunInExternalLibrary = isRunInExternalLibrary;
+ if (!m_isRunInExternalLibrary)
+ m_externalLibName.clear();
+ else
+ m_serviceArguments.clear();
+}
+
+bool AndroidServiceData::isRunInExternalLibrary() const
+{
+ return m_isRunInExternalLibrary;
+}
+
+void AndroidServiceData::setExternalLibraryName(const QString &externalLibraryName)
+{
+ if (m_isRunInExternalLibrary)
+ m_externalLibName = externalLibraryName;
+}
+
+QString AndroidServiceData::externalLibraryName() const
+{
+ return m_externalLibName;
+}
+
+void AndroidServiceData::setServiceArguments(const QString &serviceArguments)
+{
+ if (!m_isRunInExternalLibrary)
+ m_serviceArguments = serviceArguments;
+}
+
+QString AndroidServiceData::serviceArguments() const
+{
+ return m_serviceArguments;
+}
+
+void AndroidServiceData::setNewService(bool isNewService)
+{
+ m_isNewService = isNewService;
+}
+
+bool AndroidServiceData::isNewService() const
+{
+ return m_isNewService;
+}
+
+void AndroidServiceWidget::AndroidServiceModel::setServices(const QList<AndroidServiceData> &androidServices)
+{
+ beginResetModel();
+ m_services = androidServices;
+ endResetModel();
+}
+
+const QList<AndroidServiceData> &AndroidServiceWidget::AndroidServiceModel::services()
+{
+ return m_services;
+}
+
+void AndroidServiceWidget::AndroidServiceModel::addService()
+{
+ int rowIndex = m_services.size();
+ beginInsertRows(QModelIndex(), rowIndex, rowIndex);
+ AndroidServiceData service;
+ service.setNewService(true);
+ m_services.push_back(service);
+ endInsertRows();
+ invalidDataChanged();
+}
+
+void AndroidServiceWidget::AndroidServiceModel::removeService(int row)
+{
+ beginRemoveRows(QModelIndex(), row, row);
+ m_services.removeAt(row);
+ endRemoveRows();
+}
+
+void AndroidServiceWidget::AndroidServiceModel::servicesSaved()
+{
+ for (auto && x : m_services)
+ x.setNewService(false);
+}
+
+int AndroidServiceWidget::AndroidServiceModel::rowCount(const QModelIndex &/*parent*/) const
+{
+ return m_services.count();
+}
+
+int AndroidServiceWidget::AndroidServiceModel::columnCount(const QModelIndex &/*parent*/) const
+{
+ return 6;
+}
+
+Qt::ItemFlags AndroidServiceWidget::AndroidServiceModel::flags(const QModelIndex &index) const
+{
+ if (index.column() == 0)
+ return Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable;
+ else if (index.column() == 1)
+ return Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsSelectable;
+ else if (index.column() == 2 && index.row() <= m_services.count()) {
+ if (m_services[index.row()].isRunInExternalProcess())
+ return Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable;
+ return Qt::ItemIsSelectable;
+ } else if (index.column() == 3 && index.row() <= m_services.count()) {
+ if (m_services[index.row()].isRunInExternalProcess())
+ return Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsSelectable;
+ return Qt::ItemIsUserCheckable | Qt::ItemIsSelectable;
+ } else if (index.column() == 4 && index.row() <= m_services.count()) {
+ if (m_services[index.row()].isRunInExternalLibrary())
+ return Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable;
+ return Qt::ItemIsSelectable;
+ } else if (index.column() == 5 && index.row() <= m_services.count()) {
+ if (!m_services[index.row()].isRunInExternalLibrary())
+ return Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable;
+ return Qt::ItemIsSelectable;
+ }
+ return Qt::ItemIsSelectable;
+}
+
+QVariant AndroidServiceWidget::AndroidServiceModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if (role == Qt::ToolTipRole && orientation == Qt::Horizontal) {
+ if (section == 0)
+ return tr("The name of the class implementing the service");
+ else if (section == 1)
+ return tr("Checked if the service is run in an external process");
+ else if (section == 2)
+ return tr("The name of the external process.\n"
+ "Prefix with : if the process is private, use a lowercase name if the process is global.");
+ else if (section == 3)
+ return tr("Checked if the service is in a separate dynamic library");
+ else if (section == 4)
+ return tr("The name of the separate dynamic library");
+ else if (section == 5)
+ return tr("The arguments for telling the app to run the service instead of the main activity");
+ } else if (role == Qt::DisplayRole && orientation == Qt::Horizontal) {
+ if (section == 0)
+ return tr("Service class name");
+ else if (section == 1)
+ return tr("Run in external process");
+ else if (section == 2)
+ return tr("Process name");
+ else if (section == 3)
+ return tr("Run in external library");
+ else if (section == 4)
+ return tr("Library name");
+ else if (section == 5)
+ return tr("Service arguments");
+ }
+ return {};
+}
+
+QVariant AndroidServiceWidget::AndroidServiceModel::data(const QModelIndex &index, int role) const
+{
+ if (!(index.row() >= 0 && index.row() < m_services.count()))
+ return {};
+ if (role == Qt::CheckStateRole) {
+ if (index.column() == 3)
+ return m_services[index.row()].isRunInExternalLibrary() ? Qt::Checked : Qt::Unchecked;
+ else if (index.column() == 1 && index.row() <= m_services.count())
+ return m_services[index.row()].isRunInExternalProcess() ? Qt::Checked : Qt::Unchecked;
+ return QVariant();
+ } else if (role == Qt::DisplayRole) {
+ if (index.column() == 0)
+ return m_services[index.row()].className();
+ else if (index.column() == 1)
+ return tr("Run in external process");
+ else if (index.column() == 2)
+ return m_services[index.row()].externalProcessName();
+ else if (index.column() == 3)
+ return tr("Run in external library");
+ else if (index.column() == 4)
+ return m_services[index.row()].externalLibraryName();
+ else if (index.column() == 5)
+ return m_services[index.row()].serviceArguments();
+ } else if (role == Qt::ToolTipRole) {
+ if (index.column() == 0 && m_services[index.row()].className().isEmpty())
+ return tr("The class name must be set");
+ else if (index.column() == 2 && m_services[index.row()].isRunInExternalProcess())
+ return tr("The process name must be set for a service run in an external process");
+ else if (index.column() == 4 && m_services[index.row()].isRunInExternalLibrary())
+ return tr("The library name must be set for a service run in an external library");
+ else if (index.column() == 5 && !m_services[index.row()].isRunInExternalLibrary())
+ return tr("The service arguments must be set for a service not run in an external library");
+ } else if (role == Qt::EditRole) {
+ if (index.column() == 0)
+ return m_services[index.row()].className();
+ else if (index.column() == 2)
+ return m_services[index.row()].externalProcessName();
+ else if (index.column() == 4)
+ return m_services[index.row()].externalLibraryName();
+ else if (index.column() == 5)
+ return m_services[index.row()].serviceArguments();
+ } else if (role == Qt::DecorationRole) {
+ if (index.column() == 0) {
+ if (m_services[index.row()].className().isEmpty())
+ return Utils::Icons::WARNING.icon();
+ } else if (index.column() == 2) {
+ if (m_services[index.row()].isRunInExternalProcess()
+ && m_services[index.row()].externalProcessName().isEmpty())
+ return Utils::Icons::WARNING.icon();
+ } else if (index.column() == 4) {
+ if (m_services[index.row()].isRunInExternalLibrary()
+ && m_services[index.row()].externalLibraryName().isEmpty())
+ return Utils::Icons::WARNING.icon();
+ } else if (index.column() == 5) {
+ if (!m_services[index.row()].isRunInExternalLibrary()
+ && m_services[index.row()].serviceArguments().isEmpty())
+ return Utils::Icons::WARNING.icon();
+ }
+ }
+ return {};
+}
+
+bool AndroidServiceWidget::AndroidServiceModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ if (!(index.row() >= 0 && index.row() < m_services.count()))
+ return {};
+ if (role == Qt::CheckStateRole) {
+ if (index.column() == 1)
+ m_services[index.row()].setRunInExternalProcess((value == Qt::Checked) ? true : false);
+ else if (index.column() == 3)
+ m_services[index.row()].setRunInExternalLibrary((value == Qt::Checked) ? true : false);
+ dataChanged(createIndex(index.row(), 0), createIndex(index.row(), 5));
+ if (m_services[index.row()].isValid())
+ validDataChanged();
+ else
+ invalidDataChanged();
+ } else if (role == Qt::EditRole) {
+ if (index.column() == 0) {
+ QString className = value.toString();
+ if (!className.isEmpty() && className[0] != QChar('.'))
+ className.push_front(QChar('.'));
+ m_services[index.row()].setClassName(className);
+ m_services[index.row()].setNewService(true);
+ } else if (index.column() == 2) {
+ m_services[index.row()].setExternalProcessName(value.toString());
+ } else if (index.column() == 4) {
+ m_services[index.row()].setExternalLibraryName(value.toString());
+ } else if (index.column() == 5) {
+ m_services[index.row()].setServiceArguments(value.toString());
+ }
+ dataChanged(index, index);
+ if (m_services[index.row()].isValid())
+ validDataChanged();
+ else
+ invalidDataChanged();
+ }
+ return true;
+}
+
+AndroidServiceWidget::AndroidServiceWidget(QWidget *parent) : QWidget(parent),
+ m_model(new AndroidServiceModel), m_tableView(new QTableView(this))
+{
+ m_tableView->setModel(m_model.data());
+ m_tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
+ QSizePolicy sizePolicy;
+ sizePolicy.setHorizontalPolicy(QSizePolicy::Expanding);
+ m_tableView->setSizePolicy(sizePolicy);
+ m_tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
+ auto layout = new QHBoxLayout(this);
+ layout->addWidget(m_tableView, 1);
+ auto buttonLayout = new QGridLayout();
+ auto addButton = new QPushButton(this);
+ addButton->setText(tr("Add"));
+ buttonLayout->addWidget(addButton, 0, 0);
+ m_removeButton = new QPushButton(this);
+ m_removeButton->setText(tr("Remove"));
+ m_removeButton->setEnabled(false);
+ buttonLayout->addWidget(m_removeButton, 1, 0);
+ layout->addLayout(buttonLayout);
+ layout->setAlignment(buttonLayout, Qt::AlignTop);
+ connect(addButton, &QAbstractButton::clicked,
+ this, &AndroidServiceWidget::addService);
+ connect(m_removeButton, &QAbstractButton::clicked,
+ this, &AndroidServiceWidget::removeService);
+ connect(m_tableView->selectionModel(), &QItemSelectionModel::selectionChanged,
+ [this](const QItemSelection &selected, const QItemSelection &/*deselected*/) {
+ if (!selected.isEmpty())
+ m_removeButton->setEnabled(true);
+ });
+ connect(m_model.data(), &AndroidServiceWidget::AndroidServiceModel::validDataChanged,
+ [this] {servicesModified();});
+ connect(m_model.data(), &AndroidServiceWidget::AndroidServiceModel::invalidDataChanged,
+ [this] {servicesInvalid();});
+}
+
+AndroidServiceWidget::~AndroidServiceWidget()
+{
+
+}
+
+void AndroidServiceWidget::setServices(const QList<AndroidServiceData> &androidServices)
+{
+ m_removeButton->setEnabled(false);
+ m_model->setServices(androidServices);
+}
+
+const QList<AndroidServiceData> &AndroidServiceWidget::services()
+{
+ return m_model->services();
+}
+
+void AndroidServiceWidget::servicesSaved()
+{
+ m_model->servicesSaved();
+}
+
+void AndroidServiceWidget::addService()
+{
+ m_model->addService();
+}
+
+void AndroidServiceWidget::removeService()
+{
+ auto selections = m_tableView->selectionModel()->selectedRows();
+ for (const auto &x : selections) {
+ m_model->removeService(x.row());
+ m_removeButton->setEnabled(false);
+ servicesModified();
+ break;
+ }
+}
+
+} // namespace Internal
+} // namespace Android
diff --git a/src/plugins/android/androidservicewidget.h b/src/plugins/android/androidservicewidget.h
new file mode 100644
index 0000000000..cc30003b65
--- /dev/null
+++ b/src/plugins/android/androidservicewidget.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** 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 <QList>
+#include <QString>
+#include <QWidget>
+
+class QPushButton;
+class QTableView;
+
+namespace Android {
+namespace Internal {
+
+struct AndroidServiceData
+{
+public:
+ bool isValid() const;
+ void setClassName(const QString &className);
+ QString className() const;
+ void setRunInExternalProcess(bool isRunInExternalProcess);
+ bool isRunInExternalProcess() const;
+ void setExternalProcessName(const QString &externalProcessName);
+ QString externalProcessName() const;
+ void setRunInExternalLibrary(bool isRunInExternalLibrary);
+ bool isRunInExternalLibrary() const ;
+ void setExternalLibraryName(const QString &externalLibraryName);
+ QString externalLibraryName() const;
+ void setServiceArguments(const QString &serviceArguments);
+ QString serviceArguments() const;
+ void setNewService(bool isNewService);
+ bool isNewService() const;
+private:
+ QString m_className;
+ bool m_isRunInExternalProcess = false;
+ QString m_externalProcessName;
+ bool m_isRunInExternalLibrary = false;
+ QString m_externalLibName;
+ QString m_serviceArguments;
+ bool m_isNewService = false;
+};
+
+class AndroidServiceWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ explicit AndroidServiceWidget(QWidget *parent = nullptr);
+ ~AndroidServiceWidget();
+ void setServices(const QList<AndroidServiceData> &androidServices);
+ const QList<AndroidServiceData> &services();
+ void servicesSaved();
+private:
+ void addService();
+ void removeService();
+signals:
+ void servicesModified();
+ void servicesInvalid();
+private:
+ class AndroidServiceModel;
+ QScopedPointer<AndroidServiceModel> m_model;
+ QTableView *m_tableView;
+ QPushButton *m_removeButton;
+};
+
+} // namespace Internal
+} // namespace Android
diff --git a/src/plugins/android/androidservicewidget_p.h b/src/plugins/android/androidservicewidget_p.h
new file mode 100644
index 0000000000..89b03639a1
--- /dev/null
+++ b/src/plugins/android/androidservicewidget_p.h
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** 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 "androidservicewidget.h"
+
+#include <QAbstractTableModel>
+
+namespace Android {
+namespace Internal {
+
+class AndroidServiceWidget::AndroidServiceModel : public QAbstractTableModel
+{
+ Q_OBJECT
+public:
+ void setServices(const QList<AndroidServiceData> &androidServices);
+ const QList<AndroidServiceData> &services();
+ void addService();
+ void removeService(int row);
+ void servicesSaved();
+signals:
+ void validDataChanged();
+ void invalidDataChanged();
+private:
+ int rowCount(const QModelIndex &/*parent*/ = QModelIndex()) const override;
+ int columnCount(const QModelIndex &/*parent*/ = QModelIndex()) const override;
+ Qt::ItemFlags flags(const QModelIndex &index) const override;
+ QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+ bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
+private:
+ QList<AndroidServiceData> m_services;
+};
+
+} // namespace Internal
+} // namespace Android
diff --git a/src/plugins/android/androidsettingswidget.cpp b/src/plugins/android/androidsettingswidget.cpp
index 95c67ae264..52cfbd4461 100644
--- a/src/plugins/android/androidsettingswidget.cpp
+++ b/src/plugins/android/androidsettingswidget.cpp
@@ -27,31 +27,27 @@
#include "ui_androidsettingswidget.h"
+#include "androidavdmanager.h"
#include "androidconfigurations.h"
#include "androidconstants.h"
-#include "androidtoolchain.h"
-#include "androidavdmanager.h"
-#include "androidsdkmanager.h"
-#include "avddialog.h"
#include "androidsdkdownloader.h"
+#include "androidsdkmanager.h"
#include "androidsdkmanagerwidget.h"
+#include "androidtoolchain.h"
+#include "avddialog.h"
+
+#include <projectexplorer/projectexplorerconstants.h>
-#include <utils/qtcassert.h>
#include <utils/environment.h>
#include <utils/hostosinfo.h>
#include <utils/infolabel.h>
+#include <utils/listmodel.h>
#include <utils/pathchooser.h>
+#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
-#include <utils/runextensions.h>
+#include <utils/synchronousprocess.h>
#include <utils/utilsicons.h>
-#include <projectexplorer/toolchainmanager.h>
-#include <projectexplorer/kitmanager.h>
-#include <projectexplorer/kitinformation.h>
-#include <projectexplorer/projectexplorerconstants.h>
-#include <qtsupport/qtkitinformation.h>
-#include <qtsupport/qtversionmanager.h>
-#include <QAbstractTableModel>
#include <QDesktopServices>
#include <QDir>
#include <QFileDialog>
@@ -68,6 +64,8 @@
#include <memory>
+using namespace Utils;
+
namespace {
static Q_LOGGING_CATEGORY(androidsettingswidget, "qtc.android.androidsettingswidget", QtWarningMsg);
}
@@ -76,26 +74,20 @@ namespace Android {
namespace Internal {
class AndroidSdkManagerWidget;
-
class AndroidAvdManager;
+class SummaryWidget;
-class AvdModel final : public QAbstractTableModel
+class AvdModel final : public ListModel<AndroidDeviceInfo>
{
Q_DECLARE_TR_FUNCTIONS(Android::Internal::AvdModel)
public:
- void setAvdList(const AndroidDeviceInfoList &list);
- QString avdName(const QModelIndex &index) const;
- QModelIndex indexForAvdName(const QString &avdName) const;
+ AvdModel();
-protected:
- QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const final;
- QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const final;
- int rowCount(const QModelIndex &parent = QModelIndex()) const final;
- int columnCount(const QModelIndex &parent = QModelIndex()) const final;
+ QVariant itemData(const AndroidDeviceInfo &info, int column, int role) const final;
-private:
- AndroidDeviceInfoList m_list;
+ QString avdName(const QModelIndex &index) const;
+ QModelIndex indexForAvdName(const QString &avdName) const;
};
class AndroidSettingsWidget final : public Core::IOptionsPageWidget
@@ -111,7 +103,7 @@ private:
void apply() final { AndroidConfigurations::setConfig(m_androidConfig); }
void validateJdk();
- Utils::FilePath findJdkInCommonPaths();
+ FilePath findJdkInCommonPaths() const;
void validateNdk();
void updateNdkList();
void onSdkPathChanged();
@@ -139,28 +131,33 @@ private:
void downloadSdk();
bool allEssentialsInstalled();
bool sdkToolsOk() const;
- Utils::FilePath getDefaultSdkPath();
- void showEvent(QShowEvent *event) override;
+ FilePath getDefaultSdkPath() const;
+ void showEvent(QShowEvent *event) final;
void addCustomNdkItem();
void validateOpenSsl();
- Ui_AndroidSettingsWidget *m_ui;
+ Ui_AndroidSettingsWidget m_ui;
AndroidSdkManagerWidget *m_sdkManagerWidget = nullptr;
- AndroidConfig m_androidConfig;
+ AndroidConfig m_androidConfig{AndroidConfigurations::currentConfig()};
AvdModel m_AVDModel;
QFutureWatcher<CreateAvdInfo> m_futureWatcher;
QFutureWatcher<AndroidDeviceInfoList> m_virtualDevicesWatcher;
QString m_lastAddedAvd;
- std::unique_ptr<AndroidAvdManager> m_avdManager;
- std::unique_ptr<AndroidSdkManager> m_sdkManager;
- std::unique_ptr<AndroidSdkDownloader> m_sdkDownloader;
+ AndroidAvdManager m_avdManager{AndroidConfigurations::currentConfig()};
+ AndroidSdkManager m_sdkManager{AndroidConfigurations::currentConfig()};
+ AndroidSdkDownloader m_sdkDownloader;
bool m_isInitialReloadDone = false;
+
+ SummaryWidget *m_androidSummary = nullptr;
+ SummaryWidget *m_javaSummary = nullptr;
+ SummaryWidget *m_openSslSummary = nullptr;
};
enum JavaValidation {
JavaPathExistsRow,
- JavaJdkValidRow
+ JavaJdkValidRow,
+ JavaJdkValidVersionRow
};
enum AndroidValidation {
@@ -187,13 +184,13 @@ class SummaryWidget : public QWidget
{
class RowData {
public:
- Utils::InfoLabel *m_infoLabel = nullptr;
+ InfoLabel *m_infoLabel = nullptr;
bool m_valid = false;
};
public:
SummaryWidget(const QMap<int, QString> &validationPoints, const QString &validText,
- const QString &invalidText, Utils::DetailsWidget *detailsWidget) :
+ const QString &invalidText, DetailsWidget *detailsWidget) :
QWidget(detailsWidget),
m_validText(validText),
m_invalidText(invalidText),
@@ -204,24 +201,25 @@ public:
layout->setContentsMargins(12, 12, 12, 12);
for (auto itr = validationPoints.cbegin(); itr != validationPoints.cend(); ++itr) {
RowData data;
- data.m_infoLabel = new Utils::InfoLabel(itr.value());
+ data.m_infoLabel = new InfoLabel(itr.value());
layout->addWidget(data.m_infoLabel);
m_validationData[itr.key()] = data;
setPointValid(itr.key(), true);
}
+ m_detailsWidget->setWidget(this);
}
void setPointValid(int key, bool valid)
{
if (!m_validationData.contains(key))
return;
- RowData& data = m_validationData[key];
+ RowData &data = m_validationData[key];
data.m_valid = valid;
- data.m_infoLabel->setType(valid ? Utils::InfoLabel::Ok : Utils::InfoLabel::NotOk);
+ data.m_infoLabel->setType(valid ? InfoLabel::Ok : InfoLabel::NotOk);
updateUi();
}
- bool rowsOk(QList<int> keys) const
+ bool rowsOk(const QList<int> &keys) const
{
for (auto key : keys) {
if (!m_validationData[key].m_valid)
@@ -230,125 +228,93 @@ public:
return true;
}
- bool allRowsOk() const { return rowsOk(m_validationData.keys()); }
- void setInfoText(const QString &text) {
+ bool allRowsOk() const
+ {
+ return rowsOk(m_validationData.keys());
+ }
+
+ void setInfoText(const QString &text)
+ {
m_infoText = text;
updateUi();
}
+ void setSetupOk(bool ok)
+ {
+ m_detailsWidget->setState(ok ? DetailsWidget::Collapsed : DetailsWidget::Expanded);
+ }
+
private:
void updateUi() {
bool ok = allRowsOk();
- m_detailsWidget->setIcon(ok ? Utils::Icons::OK.icon() :
- Utils::Icons::CRITICAL.icon());
+ m_detailsWidget->setIcon(ok ? Icons::OK.icon() : Icons::CRITICAL.icon());
m_detailsWidget->setSummaryText(ok ? QString("%1 %2").arg(m_validText).arg(m_infoText)
: m_invalidText);
}
QString m_validText;
QString m_invalidText;
QString m_infoText;
- Utils::DetailsWidget *m_detailsWidget = nullptr;
+ DetailsWidget *m_detailsWidget = nullptr;
QMap<int, RowData> m_validationData;
};
-void AvdModel::setAvdList(const AndroidDeviceInfoList &list)
-{
- beginResetModel();
- m_list = list;
- endResetModel();
-}
-
QModelIndex AvdModel::indexForAvdName(const QString &avdName) const
{
- for (int i = 0; i < m_list.size(); ++i) {
- if (m_list.at(i).serialNumber == avdName)
- return index(i, 0);
- }
- return QModelIndex();
+ return findIndex([avdName](const AndroidDeviceInfo &info) { return info.avdname == avdName; });
}
QString AvdModel::avdName(const QModelIndex &index) const
{
- return m_list.at(index.row()).avdname;
+ return dataAt(index.row()).avdname;
}
-QVariant AvdModel::data(const QModelIndex &index, int role) const
+QVariant AvdModel::itemData(const AndroidDeviceInfo &info, int column, int role) const
{
- if (role != Qt::DisplayRole || !index.isValid())
- return QVariant();
+ if (role != Qt::DisplayRole)
+ return {};
- const AndroidDeviceInfo currentRow = m_list.at(index.row());
- switch (index.column()) {
+ switch (column) {
case 0:
- return currentRow.avdname;
+ return info.avdname;
case 1:
- return currentRow.sdk;
- case 2: {
- QStringList cpuAbis = currentRow.cpuAbi;
- return cpuAbis.isEmpty() ? QVariant() : QVariant(cpuAbis.first());
- }
+ return info.sdk;
+ case 2:
+ return info.cpuAbi.isEmpty() ? QVariant() : QVariant(info.cpuAbi.first());
case 3:
- return currentRow.avdDevice.isEmpty() ? QVariant("Custom")
- : currentRow.avdDevice;
+ return info.avdDevice.isEmpty() ? QVariant("Custom") : info.avdDevice;
case 4:
- return currentRow.avdTarget;
+ return info.avdTarget;
case 5:
- return currentRow.avdSdcardSize;
- }
- return QVariant();
-}
-
-QVariant AvdModel::headerData(int section, Qt::Orientation orientation, int role) const
-{
- if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
- switch (section) {
- case 0:
- //: AVD - Android Virtual Device
- return tr("AVD Name");
- case 1:
- return tr("API");
- case 2:
- return tr("CPU/ABI");
- case 3:
- return tr("Device type");
- case 4:
- return tr("Target");
- case 5:
- return tr("SD-card size");
- }
+ return info.avdSdcardSize;
}
- return QAbstractItemModel::headerData(section, orientation, role );
-}
-
-int AvdModel::rowCount(const QModelIndex &/*parent*/) const
-{
- return m_list.size();
+ return {};
}
-int AvdModel::columnCount(const QModelIndex &/*parent*/) const
+AvdModel::AvdModel()
{
- return 6;
+ //: AVD - Android Virtual Device
+ setHeader({tr("AVD Name"), tr("API"), tr("CPU/ABI"), tr("Device type"), tr("Target"), tr("SD-card size")});
}
-Utils::FilePath AndroidSettingsWidget::getDefaultSdkPath()
+FilePath AndroidSettingsWidget::getDefaultSdkPath() const
{
QString sdkFromEnvVar = QString::fromLocal8Bit(getenv("ANDROID_SDK_ROOT"));
if (!sdkFromEnvVar.isEmpty())
- return Utils::FilePath::fromString(sdkFromEnvVar);
+ return FilePath::fromString(sdkFromEnvVar);
// Set default path of SDK as used by Android Studio
- if (Utils::HostOsInfo::isMacHost()) {
- return Utils::FilePath::fromString(
+ if (HostOsInfo::isMacHost()) {
+ return FilePath::fromString(
QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation)
+ "/../Android/sdk");
}
- if (Utils::HostOsInfo::isWindowsHost()) {
- return Utils::FilePath::fromString(
+ if (HostOsInfo::isWindowsHost()) {
+ return FilePath::fromString(
QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + "/Android/sdk");
}
- return Utils::FilePath::fromString(
+ return FilePath::fromString(
QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + "/Android/Sdk");
}
@@ -359,7 +325,7 @@ void AndroidSettingsWidget::showEvent(QShowEvent *event)
// Reloading SDK packages (force) is still synchronous. Use zero timer
// to let settings dialog open first.
QTimer::singleShot(0, std::bind(&AndroidSdkManager::reloadPackages,
- m_sdkManager.get(), false));
+ &m_sdkManager, false));
validateOpenSsl();
m_isInitialReloadDone = true;
}
@@ -367,22 +333,21 @@ void AndroidSettingsWidget::showEvent(QShowEvent *event)
void AndroidSettingsWidget::updateNdkList()
{
- m_ui->ndkListWidget->clear();
- for (const Ndk *ndk : m_sdkManager->installedNdkPackages()) {
- m_ui->ndkListWidget->addItem(new QListWidgetItem(Utils::Icons::LOCKED.icon(),
- ndk->installedLocation().toString()));
+ m_ui.ndkListWidget->clear();
+ for (const Ndk *ndk : m_sdkManager.installedNdkPackages()) {
+ m_ui.ndkListWidget->addItem(new QListWidgetItem(Icons::LOCKED.icon(),
+ ndk->installedLocation().toString()));
}
for (const QString &ndk : m_androidConfig.getCustomNdkList()) {
if (m_androidConfig.isValidNdk(ndk)) {
- m_ui->ndkListWidget->addItem(
- new QListWidgetItem(Utils::Icons::UNLOCKED.icon(), ndk));
+ m_ui.ndkListWidget->addItem(new QListWidgetItem(Icons::UNLOCKED.icon(), ndk));
} else {
m_androidConfig.removeCustomNdk(ndk);
}
}
- m_ui->ndkListWidget->setCurrentRow(0);
+ m_ui.ndkListWidget->setCurrentRow(0);
}
void AndroidSettingsWidget::addCustomNdkItem()
@@ -392,9 +357,8 @@ void AndroidSettingsWidget::addCustomNdkItem()
if (m_androidConfig.isValidNdk(ndkPath)) {
m_androidConfig.addCustomNdk(ndkPath);
- if (m_ui->ndkListWidget->findItems(ndkPath, Qt::MatchExactly).size() == 0) {
- m_ui->ndkListWidget->addItem(
- new QListWidgetItem(Utils::Icons::UNLOCKED.icon(), ndkPath));
+ if (m_ui.ndkListWidget->findItems(ndkPath, Qt::MatchExactly).size() == 0) {
+ m_ui.ndkListWidget->addItem(new QListWidgetItem(Icons::UNLOCKED.icon(), ndkPath));
}
} else if (!ndkPath.isEmpty()) {
QMessageBox::warning(
@@ -408,38 +372,33 @@ void AndroidSettingsWidget::addCustomNdkItem()
}
AndroidSettingsWidget::AndroidSettingsWidget()
- : m_ui(new Ui_AndroidSettingsWidget),
- m_androidConfig(AndroidConfigurations::currentConfig()),
- m_avdManager(new AndroidAvdManager(m_androidConfig)),
- m_sdkManager(new AndroidSdkManager(m_androidConfig)),
- m_sdkDownloader(new AndroidSdkDownloader())
{
- m_ui->setupUi(this);
- m_sdkManagerWidget = new AndroidSdkManagerWidget(m_androidConfig, m_sdkManager.get(),
- m_ui->sdkManagerTab);
- auto sdkMangerLayout = new QVBoxLayout(m_ui->sdkManagerTab);
+ m_ui.setupUi(this);
+ m_sdkManagerWidget = new AndroidSdkManagerWidget(m_androidConfig, &m_sdkManager,
+ m_ui.sdkManagerTab);
+ auto sdkMangerLayout = new QVBoxLayout(m_ui.sdkManagerTab);
sdkMangerLayout->setContentsMargins(0, 0, 0, 0);
sdkMangerLayout->addWidget(m_sdkManagerWidget);
- connect(m_sdkManagerWidget, &AndroidSdkManagerWidget::updatingSdk, [this]() {
- m_ui->SDKLocationPathChooser->setEnabled(false);
+ connect(m_sdkManagerWidget, &AndroidSdkManagerWidget::updatingSdk, [this] {
+ m_ui.SDKLocationPathChooser->setEnabled(false);
// Disable the tab bar to restrict the user moving away from sdk manager tab untill
// operations finish.
- m_ui->managerTabWidget->tabBar()->setEnabled(false);
+ m_ui.managerTabWidget->tabBar()->setEnabled(false);
});
- connect(m_sdkManagerWidget, &AndroidSdkManagerWidget::updatingSdkFinished, [this]() {
- m_ui->SDKLocationPathChooser->setEnabled(true);
- m_ui->managerTabWidget->tabBar()->setEnabled(true);
+ connect(m_sdkManagerWidget, &AndroidSdkManagerWidget::updatingSdkFinished, [this] {
+ m_ui.SDKLocationPathChooser->setEnabled(true);
+ m_ui.managerTabWidget->tabBar()->setEnabled(true);
});
- connect(m_sdkManagerWidget, &AndroidSdkManagerWidget::licenseWorkflowStarted, [this]() {
- m_ui->scrollArea->ensureWidgetVisible(m_ui->managerTabWidget);
+ connect(m_sdkManagerWidget, &AndroidSdkManagerWidget::licenseWorkflowStarted, [this] {
+ m_ui.scrollArea->ensureWidgetVisible(m_ui.managerTabWidget);
});
QMap<int, QString> javaValidationPoints;
javaValidationPoints[JavaPathExistsRow] = tr("JDK path exists.");
javaValidationPoints[JavaJdkValidRow] = tr("JDK path is a valid JDK root folder.");
- auto javaSummary = new SummaryWidget(javaValidationPoints, tr("Java Settings are OK."),
- tr("Java settings have errors."), m_ui->javaDetailsWidget);
- m_ui->javaDetailsWidget->setWidget(javaSummary);
+ javaValidationPoints[JavaJdkValidVersionRow] = tr("Working JDK version (8) detected.");
+ m_javaSummary = new SummaryWidget(javaValidationPoints, tr("Java Settings are OK."),
+ tr("Java settings have errors."), m_ui.javaDetailsWidget);
QMap<int, QString> androidValidationPoints;
androidValidationPoints[SdkPathExistsRow] = tr("Android SDK path exists.");
@@ -456,10 +415,9 @@ AndroidSettingsWidget::AndroidSettingsWidget()
androidValidationPoints[NdkDirStructureRow] = tr("Default Android NDK directory structure is correct.");
androidValidationPoints[NdkinstallDirOkRow] = tr("Default Android NDK installed into a path without "
"spaces.");
- auto androidSummary = new SummaryWidget(androidValidationPoints, tr("Android settings are OK."),
- tr("Android settings have errors."),
- m_ui->androidDetailsWidget);
- m_ui->androidDetailsWidget->setWidget(androidSummary);
+ m_androidSummary = new SummaryWidget(androidValidationPoints, tr("Android settings are OK."),
+ tr("Android settings have errors."),
+ m_ui.androidDetailsWidget);
QMap<int, QString> openSslValidationPoints;
openSslValidationPoints[OpenSslPathExistsRow] = tr("OpenSSL path exists.");
@@ -467,116 +425,115 @@ AndroidSettingsWidget::AndroidSettingsWidget()
"QMake include project (openssl.pri) exists.");
openSslValidationPoints[OpenSslCmakeListsPathExists] = tr(
"CMake include project (CMakeLists.txt) exists.");
- auto openSslSummary = new SummaryWidget(openSslValidationPoints,
- tr("OpenSSL Settings are OK."),
- tr("OpenSSL settings have errors."),
- m_ui->openSslDetailsWidget);
- m_ui->openSslDetailsWidget->setWidget(openSslSummary);
+ m_openSslSummary = new SummaryWidget(openSslValidationPoints,
+ tr("OpenSSL Settings are OK."),
+ tr("OpenSSL settings have errors."),
+ m_ui.openSslDetailsWidget);
- connect(m_ui->OpenJDKLocationPathChooser, &Utils::PathChooser::rawPathChanged,
+ connect(m_ui.OpenJDKLocationPathChooser, &PathChooser::rawPathChanged,
this, &AndroidSettingsWidget::validateJdk);
- Utils::FilePath currentJdkPath = m_androidConfig.openJDKLocation();
+ FilePath currentJdkPath = m_androidConfig.openJDKLocation();
if (currentJdkPath.isEmpty())
currentJdkPath = findJdkInCommonPaths();
- m_ui->OpenJDKLocationPathChooser->setFileName(currentJdkPath);
- m_ui->OpenJDKLocationPathChooser->setPromptDialogTitle(tr("Select JDK Path"));
+ m_ui.OpenJDKLocationPathChooser->setFilePath(currentJdkPath);
+ m_ui.OpenJDKLocationPathChooser->setPromptDialogTitle(tr("Select JDK Path"));
- Utils::FilePath currentSDKPath = m_androidConfig.sdkLocation();
+ FilePath currentSDKPath = m_androidConfig.sdkLocation();
if (currentSDKPath.isEmpty())
currentSDKPath = getDefaultSdkPath();
- m_ui->SDKLocationPathChooser->setFileName(currentSDKPath);
- m_ui->SDKLocationPathChooser->setPromptDialogTitle(tr("Select Android SDK folder"));
+ m_ui.SDKLocationPathChooser->setFilePath(currentSDKPath);
+ m_ui.SDKLocationPathChooser->setPromptDialogTitle(tr("Select Android SDK folder"));
- m_ui->openSslPathChooser->setPromptDialogTitle(tr("Select OpenSSL Include Project File"));
- Utils::FilePath currentOpenSslPath = m_androidConfig.openSslLocation();
+ m_ui.openSslPathChooser->setPromptDialogTitle(tr("Select OpenSSL Include Project File"));
+ FilePath currentOpenSslPath = m_androidConfig.openSslLocation();
if (currentOpenSslPath.isEmpty())
currentOpenSslPath = currentSDKPath.pathAppended("android_openssl");
- m_ui->openSslPathChooser->setFileName(currentOpenSslPath);
-
- m_ui->DataPartitionSizeSpinBox->setValue(m_androidConfig.partitionSize());
- m_ui->CreateKitCheckBox->setChecked(m_androidConfig.automaticKitCreation());
- m_ui->AVDTableView->setModel(&m_AVDModel);
- m_ui->AVDTableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
- m_ui->AVDTableView->horizontalHeader()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
-
- m_ui->downloadOpenJDKToolButton->setVisible(!Utils::HostOsInfo::isLinuxHost());
-
- const QIcon downloadIcon = Utils::Icons::DOWNLOAD.icon();
- m_ui->downloadSDKToolButton->setIcon(downloadIcon);
- m_ui->downloadNDKToolButton->setIcon(downloadIcon);
- m_ui->downloadOpenJDKToolButton->setIcon(downloadIcon);
- m_ui->downloadOpenSSLPrebuiltLibs->setIcon(downloadIcon);
- m_ui->sdkToolsAutoDownloadButton->setIcon(Utils::Icons::RELOAD.icon());
- m_ui->sdkToolsAutoDownloadButton->setToolTip(tr(
+ m_ui.openSslPathChooser->setFilePath(currentOpenSslPath);
+
+ m_ui.DataPartitionSizeSpinBox->setValue(m_androidConfig.partitionSize());
+ m_ui.CreateKitCheckBox->setChecked(m_androidConfig.automaticKitCreation());
+ m_ui.AVDTableView->setModel(&m_AVDModel);
+ m_ui.AVDTableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
+ m_ui.AVDTableView->horizontalHeader()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
+
+ m_ui.downloadOpenJDKToolButton->setVisible(!HostOsInfo::isLinuxHost());
+
+ const QIcon downloadIcon = Icons::DOWNLOAD.icon();
+ m_ui.downloadSDKToolButton->setIcon(downloadIcon);
+ m_ui.downloadNDKToolButton->setIcon(downloadIcon);
+ m_ui.downloadOpenJDKToolButton->setIcon(downloadIcon);
+ m_ui.downloadOpenSSLPrebuiltLibs->setIcon(downloadIcon);
+ m_ui.sdkToolsAutoDownloadButton->setToolTip(tr(
"Automatically download Android SDK Tools to selected location.\n\n"
"If the selected path contains no valid SDK Tools, the SDK Tools package "
"is downloaded from %1, and extracted to the selected path.\n"
"After the SDK Tools are properly set up, you are prompted to install "
- "any essential packages required for Qt to build for Android.\n")
+ "any essential packages required for Qt to build for Android.")
.arg(m_androidConfig.sdkToolsUrl().toString()));
- connect(m_ui->SDKLocationPathChooser, &Utils::PathChooser::rawPathChanged,
+ connect(m_ui.SDKLocationPathChooser, &PathChooser::rawPathChanged,
this, &AndroidSettingsWidget::onSdkPathChanged);
- connect(m_ui->ndkListWidget, &QListWidget::currentTextChanged, [this](const QString &ndk) {
+ connect(m_ui.ndkListWidget, &QListWidget::currentTextChanged, [this](const QString &ndk) {
validateNdk();
- m_ui->removeCustomNdkButton->setEnabled(m_androidConfig.getCustomNdkList().contains(ndk));
+ m_ui.removeCustomNdkButton->setEnabled(m_androidConfig.getCustomNdkList().contains(ndk));
});
- connect(m_ui->addCustomNdkButton, &QPushButton::clicked, this,
+ connect(m_ui.addCustomNdkButton, &QPushButton::clicked, this,
&AndroidSettingsWidget::addCustomNdkItem);
- connect(m_ui->removeCustomNdkButton, &QPushButton::clicked, this, [this]() {
- m_androidConfig.removeCustomNdk(m_ui->ndkListWidget->currentItem()->text());
- m_ui->ndkListWidget->takeItem(m_ui->ndkListWidget->currentRow());
+ connect(m_ui.removeCustomNdkButton, &QPushButton::clicked, this, [this] {
+ m_androidConfig.removeCustomNdk(m_ui.ndkListWidget->currentItem()->text());
+ m_ui.ndkListWidget->takeItem(m_ui.ndkListWidget->currentRow());
});
- connect(m_ui->openSslPathChooser, &Utils::PathChooser::rawPathChanged, this,
- &AndroidSettingsWidget::validateOpenSsl);
+ connect(m_ui.openSslPathChooser, &PathChooser::rawPathChanged,
+ this, &AndroidSettingsWidget::validateOpenSsl);
connect(&m_virtualDevicesWatcher, &QFutureWatcherBase::finished,
this, &AndroidSettingsWidget::updateAvds);
- connect(m_ui->AVDRefreshPushButton, &QAbstractButton::clicked,
+ connect(m_ui.AVDRefreshPushButton, &QAbstractButton::clicked,
this, &AndroidSettingsWidget::startUpdateAvd);
- connect(&m_futureWatcher, &QFutureWatcherBase::finished, this, &AndroidSettingsWidget::avdAdded);
- connect(m_ui->AVDAddPushButton, &QAbstractButton::clicked,
+ connect(&m_futureWatcher, &QFutureWatcherBase::finished,
+ this, &AndroidSettingsWidget::avdAdded);
+ connect(m_ui.AVDAddPushButton, &QAbstractButton::clicked,
this, &AndroidSettingsWidget::addAVD);
- connect(m_ui->AVDRemovePushButton, &QAbstractButton::clicked,
+ connect(m_ui.AVDRemovePushButton, &QAbstractButton::clicked,
this, &AndroidSettingsWidget::removeAVD);
- connect(m_ui->AVDStartPushButton, &QAbstractButton::clicked,
+ connect(m_ui.AVDStartPushButton, &QAbstractButton::clicked,
this, &AndroidSettingsWidget::startAVD);
- connect(m_ui->AVDTableView, &QAbstractItemView::activated,
+ connect(m_ui.AVDTableView, &QAbstractItemView::activated,
this, &AndroidSettingsWidget::avdActivated);
- connect(m_ui->AVDTableView, &QAbstractItemView::clicked,
+ connect(m_ui.AVDTableView, &QAbstractItemView::clicked,
this, &AndroidSettingsWidget::avdActivated);
- connect(m_ui->DataPartitionSizeSpinBox, &QAbstractSpinBox::editingFinished,
+ connect(m_ui.DataPartitionSizeSpinBox, &QAbstractSpinBox::editingFinished,
this, &AndroidSettingsWidget::dataPartitionSizeEditingFinished);
- connect(m_ui->nativeAvdManagerButton, &QAbstractButton::clicked,
+ connect(m_ui.nativeAvdManagerButton, &QAbstractButton::clicked,
this, &AndroidSettingsWidget::manageAVD);
- connect(m_ui->CreateKitCheckBox, &QAbstractButton::toggled,
+ connect(m_ui.CreateKitCheckBox, &QAbstractButton::toggled,
this, &AndroidSettingsWidget::createKitToggled);
- connect(m_ui->downloadNDKToolButton, &QAbstractButton::clicked,
+ connect(m_ui.downloadNDKToolButton, &QAbstractButton::clicked,
this, &AndroidSettingsWidget::openNDKDownloadUrl);
- connect(m_ui->downloadSDKToolButton, &QAbstractButton::clicked,
+ connect(m_ui.downloadSDKToolButton, &QAbstractButton::clicked,
this, &AndroidSettingsWidget::openSDKDownloadUrl);
- connect(m_ui->downloadOpenSSLPrebuiltLibs, &QAbstractButton::clicked,
+ connect(m_ui.downloadOpenSSLPrebuiltLibs, &QAbstractButton::clicked,
this, &AndroidSettingsWidget::downloadOpenSslRepo);
- connect(m_ui->downloadOpenJDKToolButton, &QAbstractButton::clicked,
+ connect(m_ui.downloadOpenJDKToolButton, &QAbstractButton::clicked,
this, &AndroidSettingsWidget::openOpenJDKDownloadUrl);
// Validate SDK again after any change in SDK packages.
- connect(m_sdkManager.get(), &AndroidSdkManager::packageReloadFinished,
+ connect(&m_sdkManager, &AndroidSdkManager::packageReloadFinished,
this, &AndroidSettingsWidget::validateSdk);
- connect(m_ui->sdkToolsAutoDownloadButton, &QAbstractButton::clicked,
+ connect(m_ui.sdkToolsAutoDownloadButton, &QAbstractButton::clicked,
this, &AndroidSettingsWidget::downloadSdk);
- connect(m_sdkDownloader.get(), &AndroidSdkDownloader::sdkDownloaderError, this, [this](const QString &error) {
+ connect(&m_sdkDownloader, &AndroidSdkDownloader::sdkDownloaderError, this, [this](const QString &error) {
QMessageBox::warning(this, AndroidSdkDownloader::dialogTitle(), error);
});
- connect(m_sdkDownloader.get(), &AndroidSdkDownloader::sdkExtracted, this, [this]() {
- m_sdkManager->reloadPackages(true);
+ connect(&m_sdkDownloader, &AndroidSdkDownloader::sdkExtracted, this, [this] {
+ m_sdkManager.reloadPackages(true);
updateUI();
apply();
QMetaObject::Connection *const openSslOneShot = new QMetaObject::Connection;
- *openSslOneShot = connect(m_sdkManager.get(), &AndroidSdkManager::packageReloadFinished,
- this, [this, openSslOneShot]() {
+ *openSslOneShot = connect(&m_sdkManager, &AndroidSdkManager::packageReloadFinished,
+ this, [this, openSslOneShot] {
QObject::disconnect(*openSslOneShot);
downloadOpenSslRepo(true);
delete openSslOneShot;
@@ -588,36 +545,35 @@ AndroidSettingsWidget::~AndroidSettingsWidget()
{
// Deleting m_sdkManagerWidget will cancel all ongoing and pending sdkmanager operations.
delete m_sdkManagerWidget;
- delete m_ui;
m_futureWatcher.waitForFinished();
}
void AndroidSettingsWidget::disableAvdControls()
{
- m_ui->AVDAddPushButton->setEnabled(false);
- m_ui->AVDTableView->setEnabled(false);
- m_ui->AVDRemovePushButton->setEnabled(false);
- m_ui->AVDStartPushButton->setEnabled(false);
+ m_ui.AVDAddPushButton->setEnabled(false);
+ m_ui.AVDTableView->setEnabled(false);
+ m_ui.AVDRemovePushButton->setEnabled(false);
+ m_ui.AVDStartPushButton->setEnabled(false);
}
void AndroidSettingsWidget::enableAvdControls()
{
- m_ui->AVDTableView->setEnabled(true);
- m_ui->AVDAddPushButton->setEnabled(true);
- avdActivated(m_ui->AVDTableView->currentIndex());
+ m_ui.AVDTableView->setEnabled(true);
+ m_ui.AVDAddPushButton->setEnabled(true);
+ avdActivated(m_ui.AVDTableView->currentIndex());
}
void AndroidSettingsWidget::startUpdateAvd()
{
disableAvdControls();
- m_virtualDevicesWatcher.setFuture(m_avdManager->avdList());
+ m_virtualDevicesWatcher.setFuture(m_avdManager.avdList());
}
void AndroidSettingsWidget::updateAvds()
{
- m_AVDModel.setAvdList(m_virtualDevicesWatcher.result());
+ m_AVDModel.setAllData(m_virtualDevicesWatcher.result());
if (!m_lastAddedAvd.isEmpty()) {
- m_ui->AVDTableView->setCurrentIndex(m_AVDModel.indexForAvdName(m_lastAddedAvd));
+ m_ui.AVDTableView->setCurrentIndex(m_AVDModel.indexForAvdName(m_lastAddedAvd));
m_lastAddedAvd.clear();
}
enableAvdControls();
@@ -625,49 +581,65 @@ void AndroidSettingsWidget::updateAvds()
void AndroidSettingsWidget::validateJdk()
{
- auto javaPath = Utils::FilePath::fromUserInput(m_ui->OpenJDKLocationPathChooser->rawPath());
- m_androidConfig.setOpenJDKLocation(javaPath);
+ m_androidConfig.setOpenJDKLocation(m_ui.OpenJDKLocationPathChooser->filePath());
bool jdkPathExists = m_androidConfig.openJDKLocation().exists();
- auto summaryWidget = static_cast<SummaryWidget *>(m_ui->javaDetailsWidget->widget());
- summaryWidget->setPointValid(JavaPathExistsRow, jdkPathExists);
+ m_javaSummary->setPointValid(JavaPathExistsRow, jdkPathExists);
+
+ const FilePath bin = m_androidConfig.openJDKLocation().pathAppended("bin/javac" QTC_HOST_EXE_SUFFIX);
+ m_javaSummary->setPointValid(JavaJdkValidRow, jdkPathExists && bin.exists());
+
+ bool jdkVersionCorrect = false;
+ SynchronousProcess javacProcess;
+ const int timeoutS = 5;
+ javacProcess.setTimeoutS(timeoutS);
+ const CommandLine cmd(bin, {"-version"});
+ SynchronousProcessResponse response = javacProcess.runBlocking(cmd);
+ if (response.result == SynchronousProcessResponse::Finished) {
+ QString output = response.stdOut(); // JDK 14 uses stdOut for this output.
+ if (output.isEmpty())
+ output = response.stdErr(); // JDK 8 uses stdErr for this output.
+ if (output.startsWith("javac ")) {
+ const QVersionNumber javacVersion = QVersionNumber::fromString(output.mid(6));
+ if (QVersionNumber(1, 8).isPrefixOf(javacVersion))
+ jdkVersionCorrect = true;
+ }
+ }
+ m_javaSummary->setPointValid(JavaJdkValidVersionRow, jdkVersionCorrect);
- const Utils::FilePath bin = m_androidConfig.openJDKLocation().pathAppended("bin/javac" QTC_HOST_EXE_SUFFIX);
- summaryWidget->setPointValid(JavaJdkValidRow, jdkPathExists && bin.exists());
updateUI();
}
void AndroidSettingsWidget::validateOpenSsl()
{
- auto openSslPath = Utils::FilePath::fromUserInput(m_ui->openSslPathChooser->rawPath());
- m_androidConfig.setOpenSslLocation(openSslPath);
+ m_androidConfig.setOpenSslLocation(m_ui.openSslPathChooser->filePath());
- auto summaryWidget = static_cast<SummaryWidget *>(m_ui->openSslDetailsWidget->widget());
- summaryWidget->setPointValid(OpenSslPathExistsRow, m_androidConfig.openSslLocation().exists());
+ m_openSslSummary->setPointValid(OpenSslPathExistsRow, m_androidConfig.openSslLocation().exists());
const bool priFileExists = m_androidConfig.openSslLocation().pathAppended("openssl.pri").exists();
- summaryWidget->setPointValid(OpenSslPriPathExists, priFileExists);
+ m_openSslSummary->setPointValid(OpenSslPriPathExists, priFileExists);
const bool cmakeListsExists
= m_androidConfig.openSslLocation().pathAppended("CMakeLists.txt").exists();
- summaryWidget->setPointValid(OpenSslCmakeListsPathExists, cmakeListsExists);
+ m_openSslSummary->setPointValid(OpenSslCmakeListsPathExists, cmakeListsExists);
+
updateUI();
}
-Utils::FilePath AndroidSettingsWidget::findJdkInCommonPaths()
+FilePath AndroidSettingsWidget::findJdkInCommonPaths() const
{
QString jdkFromEnvVar = QString::fromLocal8Bit(getenv("JAVA_HOME"));
if (!jdkFromEnvVar.isEmpty())
- return Utils::FilePath::fromUserInput(jdkFromEnvVar);
+ return FilePath::fromUserInput(jdkFromEnvVar);
- if (Utils::HostOsInfo::isWindowsHost()) {
+ if (HostOsInfo::isWindowsHost()) {
QString jdkRegisteryPath = "HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\JDK\\";
QSettings jdkSettings(jdkRegisteryPath, QSettings::NativeFormat);
QStringList jdkVersions = jdkSettings.childGroups();
- Utils::FilePath jdkHome;
+ FilePath jdkHome;
for (const QString &version : jdkVersions) {
jdkSettings.beginGroup(version);
- jdkHome = Utils::FilePath::fromUserInput(jdkSettings.value("JavaHome").toString());
+ jdkHome = FilePath::fromUserInput(jdkSettings.value("JavaHome").toString());
jdkSettings.endGroup();
if (version.startsWith("1.8"))
return jdkHome;
@@ -681,7 +653,7 @@ Utils::FilePath AndroidSettingsWidget::findJdkInCommonPaths()
QString cmd;
QStringList args;
- if (Utils::HostOsInfo::isMacHost()) {
+ if (HostOsInfo::isMacHost()) {
cmd = "sh";
args << "-c" << "/usr/libexec/java_home";
} else {
@@ -693,73 +665,75 @@ Utils::FilePath AndroidSettingsWidget::findJdkInCommonPaths()
findJdkPathProc.waitForFinished();
QByteArray jdkPath = findJdkPathProc.readAllStandardOutput().trimmed();
- if (Utils::HostOsInfo::isMacHost())
- return Utils::FilePath::fromUtf8(jdkPath);
+ if (HostOsInfo::isMacHost())
+ return FilePath::fromUtf8(jdkPath);
else
- return Utils::FilePath::fromUtf8(jdkPath.replace("jre/bin/java", ""));
+ return FilePath::fromUtf8(jdkPath.replace("jre/bin/java", ""));
}
void AndroidSettingsWidget::validateNdk()
{
- const QListWidgetItem *currentItem = m_ui->ndkListWidget->currentItem();
- Utils::FilePath ndkPath = Utils::FilePath::fromString(currentItem ? currentItem->text() : "");
-
- auto summaryWidget = static_cast<SummaryWidget *>(m_ui->androidDetailsWidget->widget());
- summaryWidget->setPointValid(NdkPathExistsRow, ndkPath.exists());
-
- const Utils::FilePath ndkPlatformsDir = ndkPath.pathAppended("platforms");
- const Utils::FilePath ndkToolChainsDir = ndkPath.pathAppended("toolchains");
- const Utils::FilePath ndkSourcesDir = ndkPath.pathAppended("sources/cxx-stl");
- summaryWidget->setPointValid(NdkDirStructureRow,
- ndkPlatformsDir.exists()
- && ndkToolChainsDir.exists()
- && ndkSourcesDir.exists());
- summaryWidget->setPointValid(NdkinstallDirOkRow,
- ndkPlatformsDir.exists() &&
- !ndkPlatformsDir.toString().contains(' '));
+ const QListWidgetItem *currentItem = m_ui.ndkListWidget->currentItem();
+ const FilePath ndkPath = FilePath::fromString(currentItem ? currentItem->text() : "");
+
+ m_androidSummary->setPointValid(NdkPathExistsRow, ndkPath.exists());
+
+ const FilePath ndkPlatformsDir = ndkPath.pathAppended("platforms");
+ const FilePath ndkToolChainsDir = ndkPath.pathAppended("toolchains");
+ const FilePath ndkSourcesDir = ndkPath.pathAppended("sources/cxx-stl");
+ m_androidSummary->setPointValid(NdkDirStructureRow,
+ ndkPlatformsDir.exists()
+ && ndkToolChainsDir.exists()
+ && ndkSourcesDir.exists());
+ m_androidSummary->setPointValid(NdkinstallDirOkRow,
+ ndkPlatformsDir.exists()
+ && !ndkPlatformsDir.toString().contains(' '));
updateUI();
}
void AndroidSettingsWidget::onSdkPathChanged()
{
- auto sdkPath = Utils::FilePath::fromUserInput(m_ui->SDKLocationPathChooser->rawPath());
+ auto sdkPath = FilePath::fromUserInput(m_ui.SDKLocationPathChooser->rawPath());
m_androidConfig.setSdkLocation(sdkPath);
- Utils::FilePath currentOpenSslPath = m_androidConfig.openSslLocation();
+ FilePath currentOpenSslPath = m_androidConfig.openSslLocation();
if (currentOpenSslPath.isEmpty() || !currentOpenSslPath.exists())
currentOpenSslPath = sdkPath.pathAppended("android_openssl");
- m_ui->openSslPathChooser->setFileName(currentOpenSslPath);
+ m_ui.openSslPathChooser->setFileName(currentOpenSslPath);
// Package reload will trigger validateSdk.
- m_sdkManager->reloadPackages();
+ m_sdkManager.reloadPackages();
}
void AndroidSettingsWidget::validateSdk()
{
- auto sdkPath = Utils::FilePath::fromUserInput(m_ui->SDKLocationPathChooser->rawPath());
+ auto sdkPath = FilePath::fromUserInput(m_ui.SDKLocationPathChooser->rawPath());
m_androidConfig.setSdkLocation(sdkPath);
- auto summaryWidget = static_cast<SummaryWidget *>(m_ui->androidDetailsWidget->widget());
- summaryWidget->setPointValid(SdkPathExistsRow, m_androidConfig.sdkLocation().exists());
- summaryWidget->setPointValid(SdkPathWritableRow, m_androidConfig.sdkLocation().isWritablePath());
- summaryWidget->setPointValid(SdkToolsInstalledRow,
- !m_androidConfig.sdkToolsVersion().isNull());
- summaryWidget->setPointValid(PlatformToolsInstalledRow,
- m_androidConfig.adbToolPath().exists());
- summaryWidget->setPointValid(BuildToolsInstalledRow,
- !m_androidConfig.buildToolsVersion().isNull());
- summaryWidget->setPointValid(SdkManagerSuccessfulRow, m_sdkManager->packageListingSuccessful());
+ m_androidSummary->setPointValid(SdkPathExistsRow, m_androidConfig.sdkLocation().exists());
+ m_androidSummary->setPointValid(SdkPathWritableRow, m_androidConfig.sdkLocation().isWritablePath());
+ m_androidSummary->setPointValid(SdkToolsInstalledRow,
+ !m_androidConfig.sdkToolsVersion().isNull());
+ m_androidSummary->setPointValid(PlatformToolsInstalledRow,
+ m_androidConfig.adbToolPath().exists());
+ m_androidSummary->setPointValid(BuildToolsInstalledRow,
+ !m_androidConfig.buildToolsVersion().isNull());
+ m_androidSummary->setPointValid(SdkManagerSuccessfulRow, m_sdkManager.packageListingSuccessful());
// installedSdkPlatforms should not trigger a package reload as validate SDK is only called
// after AndroidSdkManager::packageReloadFinished.
- summaryWidget->setPointValid(PlatformSdkInstalledRow,
- !m_sdkManager->installedSdkPlatforms().isEmpty());
+ m_androidSummary->setPointValid(PlatformSdkInstalledRow,
+ !m_sdkManager.installedSdkPlatforms().isEmpty());
+
+ m_androidSummary->setPointValid(AllEssentialsInstalledRow, allEssentialsInstalled());
- summaryWidget->setPointValid(AllEssentialsInstalledRow, allEssentialsInstalled());
updateUI();
- bool sdkToolsOk = summaryWidget->rowsOk(
- {SdkPathExistsRow, SdkPathWritableRow, SdkToolsInstalledRow, SdkManagerSuccessfulRow});
- bool componentsOk = summaryWidget->rowsOk({PlatformToolsInstalledRow,
- BuildToolsInstalledRow,
- PlatformSdkInstalledRow,
- AllEssentialsInstalledRow});
+
+ const bool sdkToolsOk = m_androidSummary->rowsOk({SdkPathExistsRow,
+ SdkPathWritableRow,
+ SdkToolsInstalledRow,
+ SdkManagerSuccessfulRow});
+ const bool componentsOk = m_androidSummary->rowsOk({PlatformToolsInstalledRow,
+ BuildToolsInstalledRow,
+ PlatformSdkInstalledRow,
+ AllEssentialsInstalledRow});
m_androidConfig.setSdkFullyConfigured(sdkToolsOk && componentsOk);
if (sdkToolsOk && !componentsOk && !m_androidConfig.useNativeUiTools()) {
// Ask user to install essential SDK components. Works only for sdk tools version >= 26.0.0
@@ -768,7 +742,7 @@ void AndroidSettingsWidget::validateSdk()
auto userInput = QMessageBox::information(this, tr("Missing Android SDK packages"),
message, QMessageBox::Yes | QMessageBox::No);
if (userInput == QMessageBox::Yes) {
- m_ui->managerTabWidget->setCurrentWidget(m_ui->sdkManagerTab);
+ m_ui.managerTabWidget->setCurrentWidget(m_ui.sdkManagerTab);
m_sdkManagerWidget->installEssentials();
}
}
@@ -795,11 +769,10 @@ void AndroidSettingsWidget::openOpenJDKDownloadUrl()
void AndroidSettingsWidget::downloadOpenSslRepo(const bool silent)
{
- const Utils::FilePath openSslPath = m_ui->openSslPathChooser->fileName();
+ const FilePath openSslPath = m_ui.openSslPathChooser->filePath();
const QString openSslCloneTitle(tr("OpenSSL Cloning"));
- auto openSslSummaryWidget = static_cast<SummaryWidget *>(m_ui->openSslDetailsWidget->widget());
- if (openSslSummaryWidget->allRowsOk()) {
+ if (m_openSslSummary->allRowsOk()) {
if (!silent) {
QMessageBox::information(this, openSslCloneTitle,
tr("OpenSSL prebuilt libraries repository is already configured."));
@@ -808,13 +781,11 @@ void AndroidSettingsWidget::downloadOpenSslRepo(const bool silent)
}
const QString openSslRepo("https://github.com/KDAB/android_openssl.git");
- Utils::QtcProcess *gitCloner = new Utils::QtcProcess(this);
- Utils::CommandLine gitCloneCommand("git",
- {"clone", "--depth=1", openSslRepo, openSslPath.toString()});
+ QtcProcess *gitCloner = new QtcProcess(this);
+ CommandLine gitCloneCommand("git", {"clone", "--depth=1", openSslRepo, openSslPath.toString()});
gitCloner->setCommand(gitCloneCommand);
- qCDebug(androidsettingswidget) << "Cloning OpenSSL repo: " <<
- gitCloneCommand.toUserOutput();
+ qCDebug(androidsettingswidget) << "Cloning OpenSSL repo: " << gitCloneCommand.toUserOutput();
QDir openSslDir(openSslPath.toString());
if (openSslDir.exists()) {
@@ -836,20 +807,18 @@ void AndroidSettingsWidget::downloadOpenSslRepo(const bool silent)
openSslProgressDialog->setWindowTitle(openSslCloneTitle);
openSslProgressDialog->setFixedSize(openSslProgressDialog->sizeHint());
- connect(openSslProgressDialog, &QProgressDialog::canceled, this, [gitCloner]() {
- gitCloner->kill();
- });
+ connect(openSslProgressDialog, &QProgressDialog::canceled, gitCloner, &QtcProcess::kill);
gitCloner->start();
openSslProgressDialog->show();
- connect(gitCloner, QOverload<int, Utils::QtcProcess::ExitStatus>::of(&Utils::QtcProcess::finished),
+ connect(gitCloner, QOverload<int, QtcProcess::ExitStatus>::of(&QtcProcess::finished),
[=](int exitCode, QProcess::ExitStatus exitStatus) {
openSslProgressDialog->close();
validateOpenSsl();
if (!openSslProgressDialog->wasCanceled() ||
- (exitStatus == Utils::QtcProcess::NormalExit && exitCode != 0)) {
+ (exitStatus == QtcProcess::NormalExit && exitCode != 0)) {
QMessageBox::information(this, openSslCloneTitle,
tr("OpenSSL prebuilt libraries cloning failed. "
"Opening OpenSSL URL for manual download."));
@@ -861,14 +830,14 @@ void AndroidSettingsWidget::downloadOpenSslRepo(const bool silent)
void AndroidSettingsWidget::addAVD()
{
disableAvdControls();
- CreateAvdInfo info = AvdDialog::gatherCreateAVDInfo(this, m_sdkManager.get(), m_androidConfig);
+ CreateAvdInfo info = AvdDialog::gatherCreateAVDInfo(this, &m_sdkManager, m_androidConfig);
if (!info.isValid()) {
enableAvdControls();
return;
}
- m_futureWatcher.setFuture(m_avdManager->createAvd(info));
+ m_futureWatcher.setFuture(m_avdManager.createAvd(info));
}
void AndroidSettingsWidget::avdAdded()
@@ -887,7 +856,7 @@ void AndroidSettingsWidget::avdAdded()
void AndroidSettingsWidget::removeAVD()
{
disableAvdControls();
- QString avdName = m_AVDModel.avdName(m_ui->AVDTableView->currentIndex());
+ QString avdName = m_AVDModel.avdName(m_ui.AVDTableView->currentIndex());
if (QMessageBox::question(this, tr("Remove Android Virtual Device"),
tr("Remove device \"%1\"? This cannot be undone.").arg(avdName),
QMessageBox::Yes | QMessageBox::No)
@@ -896,64 +865,58 @@ void AndroidSettingsWidget::removeAVD()
return;
}
- m_avdManager->removeAvd(avdName);
+ m_avdManager.removeAvd(avdName);
startUpdateAvd();
}
void AndroidSettingsWidget::startAVD()
{
- m_avdManager->startAvdAsync(m_AVDModel.avdName(m_ui->AVDTableView->currentIndex()));
+ m_avdManager.startAvdAsync(m_AVDModel.avdName(m_ui.AVDTableView->currentIndex()));
}
void AndroidSettingsWidget::avdActivated(const QModelIndex &index)
{
- m_ui->AVDRemovePushButton->setEnabled(index.isValid());
- m_ui->AVDStartPushButton->setEnabled(index.isValid());
+ m_ui.AVDRemovePushButton->setEnabled(index.isValid());
+ m_ui.AVDStartPushButton->setEnabled(index.isValid());
}
void AndroidSettingsWidget::dataPartitionSizeEditingFinished()
{
- m_androidConfig.setPartitionSize(m_ui->DataPartitionSizeSpinBox->value());
+ m_androidConfig.setPartitionSize(m_ui.DataPartitionSizeSpinBox->value());
}
void AndroidSettingsWidget::createKitToggled()
{
- m_androidConfig.setAutomaticKitCreation(m_ui->CreateKitCheckBox->isChecked());
+ m_androidConfig.setAutomaticKitCreation(m_ui.CreateKitCheckBox->isChecked());
}
void AndroidSettingsWidget::updateUI()
{
- auto javaSummaryWidget = static_cast<SummaryWidget *>(m_ui->javaDetailsWidget->widget());
- auto androidSummaryWidget = static_cast<SummaryWidget *>(m_ui->androidDetailsWidget->widget());
- auto openSslSummaryWidget = static_cast<SummaryWidget *>(m_ui->openSslDetailsWidget->widget());
- const bool javaSetupOk = javaSummaryWidget->allRowsOk();
- const bool sdkToolsOk = androidSummaryWidget->rowsOk({SdkPathExistsRow, SdkPathWritableRow, SdkToolsInstalledRow});
- const bool androidSetupOk = androidSummaryWidget->allRowsOk();
- const bool openSslOk = openSslSummaryWidget->allRowsOk();
-
- m_ui->avdManagerTab->setEnabled(javaSetupOk && androidSetupOk);
- m_ui->sdkManagerTab->setEnabled(sdkToolsOk);
+ const bool javaSetupOk = m_javaSummary->allRowsOk();
+ const bool sdkToolsOk = m_androidSummary->rowsOk({SdkPathExistsRow, SdkPathWritableRow, SdkToolsInstalledRow});
+ const bool androidSetupOk = m_androidSummary->allRowsOk();
+ const bool openSslOk = m_openSslSummary->allRowsOk();
+
+ m_ui.avdManagerTab->setEnabled(javaSetupOk && androidSetupOk);
+ m_ui.sdkManagerTab->setEnabled(sdkToolsOk);
m_sdkManagerWidget->setSdkManagerControlsEnabled(!m_androidConfig.useNativeUiTools());
- const QListWidgetItem *currentItem = m_ui->ndkListWidget->currentItem();
- Utils::FilePath currentNdk = Utils::FilePath::fromString(currentItem ? currentItem->text() : "");
- auto infoText = tr("(SDK Version: %1, NDK Bundle Version: %2)")
- .arg(m_androidConfig.sdkToolsVersion().toString())
- .arg(currentNdk.isEmpty() ? "" : m_androidConfig.ndkVersion(currentNdk).toString());
- androidSummaryWidget->setInfoText(androidSetupOk ? infoText : "");
-
- m_ui->javaDetailsWidget->setState(javaSetupOk ? Utils::DetailsWidget::Collapsed :
- Utils::DetailsWidget::Expanded);
- m_ui->androidDetailsWidget->setState(androidSetupOk ? Utils::DetailsWidget::Collapsed :
- Utils::DetailsWidget::Expanded);
- m_ui->openSslDetailsWidget->setState(openSslOk ? Utils::DetailsWidget::Collapsed :
- Utils::DetailsWidget::Expanded);
+ const QListWidgetItem *currentItem = m_ui.ndkListWidget->currentItem();
+ const FilePath currentNdk = FilePath::fromString(currentItem ? currentItem->text() : "");
+ const QString infoText = tr("(SDK Version: %1, NDK Bundle Version: %2)")
+ .arg(m_androidConfig.sdkToolsVersion().toString())
+ .arg(currentNdk.isEmpty() ? "" : m_androidConfig.ndkVersion(currentNdk).toString());
+ m_androidSummary->setInfoText(androidSetupOk ? infoText : "");
+
+ m_javaSummary->setSetupOk(javaSetupOk);
+ m_androidSummary->setSetupOk(androidSetupOk);
+ m_openSslSummary->setSetupOk(openSslOk);
}
void AndroidSettingsWidget::manageAVD()
{
if (m_androidConfig.useNativeUiTools()) {
- m_avdManager->launchAvdManagerUiTool();
+ m_avdManager.launchAvdManagerUiTool();
} else {
QMessageBox::warning(this, tr("AVD Manager Not Available"),
tr("AVD manager UI tool is not available in the installed SDK tools "
@@ -972,26 +935,24 @@ void AndroidSettingsWidget::downloadSdk()
return;
}
- QString message(tr("Download and install Android SDK Tools to: %1?")
- .arg(QDir::toNativeSeparators(m_ui->SDKLocationPathChooser->rawPath())));
+ const QString message = tr("Download and install Android SDK Tools to: %1?")
+ .arg(QDir::toNativeSeparators(m_ui.SDKLocationPathChooser->rawPath()));
auto userInput = QMessageBox::information(this, AndroidSdkDownloader::dialogTitle(),
message, QMessageBox::Yes | QMessageBox::No);
if (userInput == QMessageBox::Yes) {
- auto javaSummaryWidget = static_cast<SummaryWidget *>(m_ui->javaDetailsWidget->widget());
- if (javaSummaryWidget->allRowsOk()) {
- auto javaPath = Utils::FilePath::fromUserInput(m_ui->OpenJDKLocationPathChooser->rawPath());
- m_sdkDownloader->downloadAndExtractSdk(javaPath.toString(),
- m_ui->SDKLocationPathChooser->path());
+ if (m_javaSummary->allRowsOk()) {
+ auto javaPath = FilePath::fromUserInput(m_ui.OpenJDKLocationPathChooser->rawPath());
+ m_sdkDownloader.downloadAndExtractSdk(javaPath.toString(),
+ m_ui.SDKLocationPathChooser->filePath().toString());
}
}
}
bool AndroidSettingsWidget::allEssentialsInstalled()
{
- QStringList essentialPkgs(m_androidConfig.allEssentials());
- for (const AndroidSdkPackage *pkg : m_sdkManager->installedSdkPackages()) {
- if (essentialPkgs.contains(pkg->sdkStylePath()))
- essentialPkgs.removeOne(pkg->sdkStylePath());
+ QStringList essentialPkgs = m_androidConfig.allEssentials();
+ for (const AndroidSdkPackage *pkg : m_sdkManager.installedSdkPackages()) {
+ essentialPkgs.removeOne(pkg->sdkStylePath());
if (essentialPkgs.isEmpty())
break;
}
@@ -1016,7 +977,7 @@ AndroidSettingsPage::AndroidSettingsPage()
setWidgetCreator([] {
auto widget = new AndroidSettingsWidget;
QPalette pal = widget->palette();
- pal.setColor(QPalette::Window, Utils::creatorTheme()->color(Utils::Theme::BackgroundColorNormal));
+ pal.setColor(QPalette::Window, Utils::creatorTheme()->color(Theme::BackgroundColorNormal));
widget->setPalette(pal);
return widget;
});
diff --git a/src/plugins/android/androidsettingswidget.ui b/src/plugins/android/androidsettingswidget.ui
index 56eba59b99..3e12ae34b9 100644
--- a/src/plugins/android/androidsettingswidget.ui
+++ b/src/plugins/android/androidsettingswidget.ui
@@ -129,62 +129,6 @@
<string>Android Settings</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
- <item row="0" column="0">
- <widget class="QLabel" name="SDKLocationLabel">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="text">
- <string>Android SDK location:</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- </widget>
- </item>
- <item row="0" column="5">
- <widget class="QToolButton" name="sdkToolsAutoDownloadButton">
- <property name="toolTip">
- <string>Automatically download Android SDK Tools to selected location.</string>
- </property>
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item row="0" column="6">
- <widget class="QToolButton" name="downloadSDKToolButton">
- <property name="toolTip">
- <string>Open Android SDK download URL in the system's browser.</string>
- </property>
- </widget>
- </item>
- <item row="2" column="6">
- <widget class="QToolButton" name="downloadNDKToolButton">
- <property name="toolTip">
- <string>Open Android NDK download URL in the system's browser.</string>
- </property>
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item row="0" column="1" colspan="4">
- <widget class="Utils::PathChooser" name="SDKLocationPathChooser" native="true"/>
- </item>
- <item row="5" column="0" colspan="7">
- <widget class="Utils::DetailsWidget" name="androidDetailsWidget" native="true"/>
- </item>
- <item row="2" column="0">
- <widget class="QLabel" name="ndkComboBoxLabel">
- <property name="text">
- <string>Android NDK list:</string>
- </property>
- </widget>
- </item>
<item row="2" column="1" rowspan="3">
<widget class="QListWidget" name="ndkListWidget">
<property name="sizeAdjustPolicy">
@@ -256,6 +200,59 @@
</item>
</layout>
</item>
+ <item row="5" column="0" colspan="7">
+ <widget class="Utils::DetailsWidget" name="androidDetailsWidget" native="true"/>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="ndkComboBoxLabel">
+ <property name="text">
+ <string>Android NDK list:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="6">
+ <widget class="QToolButton" name="downloadSDKToolButton">
+ <property name="toolTip">
+ <string>Open Android SDK download URL in the system's browser.</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="SDKLocationLabel">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Android SDK location:</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="6">
+ <widget class="QToolButton" name="downloadNDKToolButton">
+ <property name="toolTip">
+ <string>Open Android NDK download URL in the system's browser.</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="Utils::PathChooser" name="SDKLocationPathChooser" native="true"/>
+ </item>
+ <item row="0" column="2" colspan="3">
+ <widget class="QPushButton" name="sdkToolsAutoDownloadButton">
+ <property name="text">
+ <string>Set Up SDK</string>
+ </property>
+ </widget>
+ </item>
</layout>
</widget>
</item>
@@ -274,7 +271,7 @@
</sizepolicy>
</property>
<property name="text">
- <string>OpenSSL .pri location:</string>
+ <string>OpenSSL binaries location:</string>
</property>
</widget>
</item>
diff --git a/src/plugins/android/androidtoolchain.cpp b/src/plugins/android/androidtoolchain.cpp
index 5372fa3b3b..d140f08b0c 100644
--- a/src/plugins/android/androidtoolchain.cpp
+++ b/src/plugins/android/androidtoolchain.cpp
@@ -76,7 +76,7 @@ static ToolChain *findToolChain(Utils::FilePath &compilerPath, Core::Id lang, co
AndroidToolChain::AndroidToolChain()
: ClangToolChain(Constants::ANDROID_TOOLCHAIN_TYPEID)
{
- setTypeDisplayName(AndroidToolChainFactory::tr("Android Clang"));
+ setTypeDisplayName(AndroidToolChain::tr("Android Clang"));
}
Utils::FilePath AndroidToolChain::ndkLocation() const
@@ -163,7 +163,7 @@ GccToolChain::DetectedAbisResult AndroidToolChain::detectSupportedAbis() const
AndroidToolChainFactory::AndroidToolChainFactory()
{
- setDisplayName(tr("Android Clang"));
+ setDisplayName(AndroidToolChain::tr("Android Clang"));
setSupportedToolChainType(Constants::ANDROID_TOOLCHAIN_TYPEID);
setSupportedLanguages({ProjectExplorer::Constants::CXX_LANGUAGE_ID});
setToolchainConstructor([] { return new AndroidToolChain; });
diff --git a/src/plugins/android/androidtoolchain.h b/src/plugins/android/androidtoolchain.h
index d530b3c25e..b074633c62 100644
--- a/src/plugins/android/androidtoolchain.h
+++ b/src/plugins/android/androidtoolchain.h
@@ -36,6 +36,8 @@ using ToolChainList = QList<ProjectExplorer::ToolChain *>;
class AndroidToolChain : public ProjectExplorer::ClangToolChain
{
+ Q_DECLARE_TR_FUNCTIONS(Android::Internal::AndroidToolChain)
+
public:
~AndroidToolChain() override;
@@ -62,8 +64,6 @@ private:
class AndroidToolChainFactory : public ProjectExplorer::ToolChainFactory
{
- Q_OBJECT
-
public:
AndroidToolChainFactory();
diff --git a/src/plugins/android/avddialog.cpp b/src/plugins/android/avddialog.cpp
index 78fcfe6b0f..3e11cd1823 100644
--- a/src/plugins/android/avddialog.cpp
+++ b/src/plugins/android/avddialog.cpp
@@ -64,7 +64,7 @@ AvdDialog::AvdDialog(int minApiLevel, AndroidSdkManager *sdkManager, const QStri
m_avdDialog.abiComboBox->addItems(abis);
}
- auto v = new QRegExpValidator(m_allowedNameChars, this);
+ auto v = new QRegularExpressionValidator(m_allowedNameChars, this);
m_avdDialog.nameLineEdit->setValidator(v);
m_avdDialog.nameLineEdit->installEventFilter(this);
@@ -258,7 +258,7 @@ bool AvdDialog::eventFilter(QObject *obj, QEvent *event)
if (obj == m_avdDialog.nameLineEdit && event->type() == QEvent::KeyPress) {
auto ke = static_cast<QKeyEvent *>(event);
const QString key = ke->text();
- if (!key.isEmpty() && !m_allowedNameChars.exactMatch(key)) {
+ if (!key.isEmpty() && !m_allowedNameChars.match(key).hasMatch()) {
QPoint position = m_avdDialog.nameLineEdit->parentWidget()->mapToGlobal(m_avdDialog.nameLineEdit->geometry().bottomLeft());
position -= Utils::ToolTip::offsetFromPosition();
Utils::ToolTip::show(position, tr("Allowed characters are: a-z A-Z 0-9 and . _ -"), m_avdDialog.nameLineEdit);
diff --git a/src/plugins/android/avddialog.h b/src/plugins/android/avddialog.h
index ba3d75837c..9813cc813b 100644
--- a/src/plugins/android/avddialog.h
+++ b/src/plugins/android/avddialog.h
@@ -85,7 +85,7 @@ private:
AndroidSdkManager *m_sdkManager;
int m_minApiLevel;
QTimer m_hideTipTimer;
- QRegExp m_allowedNameChars;
+ QRegularExpression m_allowedNameChars;
QList<DeviceDefinitionStruct> m_deviceDefinitionsList;
AndroidConfig m_androidConfig;
};
diff --git a/src/plugins/android/createandroidmanifestwizard.cpp b/src/plugins/android/createandroidmanifestwizard.cpp
index 4a5e6968a7..097828ce38 100644
--- a/src/plugins/android/createandroidmanifestwizard.cpp
+++ b/src/plugins/android/createandroidmanifestwizard.cpp
@@ -108,15 +108,13 @@ ChooseProFilePage::ChooseProFilePage(CreateAndroidManifestWizard *wizard)
fl->addRow(label);
BuildSystem *buildSystem = wizard->buildSystem();
- QString currentBuildTarget;
- if (RunConfiguration *rc = buildSystem->target()->activeRunConfiguration())
- currentBuildTarget = rc->buildKey();
+ QString currentBuildKey = buildSystem->target()->activeBuildKey();
m_comboBox = new QComboBox(this);
for (const BuildTargetInfo &bti : buildSystem->applicationTargets()) {
const QString displayName = bti.buildKey;
m_comboBox->addItem(displayName, QVariant(bti.buildKey)); // TODO something more?
- if (bti.buildKey == currentBuildTarget)
+ if (bti.buildKey == currentBuildKey)
m_comboBox->setCurrentIndex(m_comboBox->count() - 1);
}
@@ -198,7 +196,7 @@ void ChooseDirectoryPage::checkPackageSourceDir()
const BuildTargetInfo bti = m_wizard->buildSystem()->buildTarget(buildKey);
const QString projectDir = bti.projectFilePath.toFileInfo().absolutePath();
- const QString newDir = m_androidPackageSourceDir->path();
+ const QString newDir = m_androidPackageSourceDir->filePath().toString();
bool isComplete = QFileInfo(projectDir) != QFileInfo(newDir);
m_sourceDirectoryWarning->setVisible(!isComplete);
@@ -240,7 +238,7 @@ void ChooseDirectoryPage::initializePage()
}
- m_wizard->setDirectory(m_androidPackageSourceDir->path());
+ m_wizard->setDirectory(m_androidPackageSourceDir->filePath().toString());
}
//
@@ -389,18 +387,21 @@ void CreateAndroidManifestWizard::createAndroidTemplateFiles()
if (node) {
node->addFiles(addedFiles);
androidPackageDir = node->data(Android::Constants::AndroidPackageSourceDir).toString();
- }
- if (androidPackageDir.isEmpty()) {
- // and now time for some magic
- const BuildTargetInfo bti = target->buildTarget(m_buildKey);
- const QString value = "$$PWD/" + bti.projectFilePath.toFileInfo().absoluteDir().relativeFilePath(m_directory);
- bool result = node->setData(Android::Constants::AndroidPackageSourceDir, value);
-
- if (!result) {
- QMessageBox::warning(this, tr("Project File not Updated"),
- tr("Could not update the project file %1.")
- .arg(bti.projectFilePath.toUserOutput()));
+ if (androidPackageDir.isEmpty()) {
+ // and now time for some magic
+ const BuildTargetInfo bti = target->buildTarget(m_buildKey);
+ const QString value = "$$PWD/"
+ + bti.projectFilePath.toFileInfo().absoluteDir().relativeFilePath(
+ m_directory);
+ bool result = node->setData(Android::Constants::AndroidPackageSourceDir, value);
+
+ if (!result) {
+ QMessageBox::warning(this,
+ tr("Project File not Updated"),
+ tr("Could not update the project file %1.")
+ .arg(bti.projectFilePath.toUserOutput()));
+ }
}
}
Core::EditorManager::openEditor(m_directory + QLatin1String("/AndroidManifest.xml"));
diff --git a/src/plugins/android/javaparser.cpp b/src/plugins/android/javaparser.cpp
index 359d9be819..04035c851d 100644
--- a/src/plugins/android/javaparser.cpp
+++ b/src/plugins/android/javaparser.cpp
@@ -36,18 +36,6 @@ JavaParser::JavaParser() :
m_javaRegExp(QLatin1String("^(.*\\[javac\\]\\s)(.*\\.java):(\\d+):(.*)$"))
{ }
-void JavaParser::stdOutput(const QString &line)
-{
- parse(line);
- IOutputParser::stdOutput(line);
-}
-
-void JavaParser::stdError(const QString &line)
-{
- parse(line);
- IOutputParser::stdError(line);
-}
-
void JavaParser::setProjectFileList(const QStringList &fileList)
{
m_fileList = fileList;
@@ -63,33 +51,36 @@ void JavaParser::setSourceDirectory(const Utils::FilePath &sourceDirectory)
m_sourceDirectory = sourceDirectory;
}
-void JavaParser::parse(const QString &line)
+Utils::OutputLineParser::Result JavaParser::handleLine(const QString &line,
+ Utils::OutputFormat type)
{
- if (m_javaRegExp.indexIn(line) > -1) {
- bool ok;
- int lineno = m_javaRegExp.cap(3).toInt(&ok);
- if (!ok)
- lineno = -1;
- Utils::FilePath file = Utils::FilePath::fromUserInput(m_javaRegExp.cap(2));
- if (file.isChildOf(m_buildDirectory)) {
- Utils::FilePath relativePath = file.relativeChildPath(m_buildDirectory);
- file = m_sourceDirectory.pathAppended(relativePath.toString());
- }
+ Q_UNUSED(type);
+ if (m_javaRegExp.indexIn(line) == -1)
+ return Status::NotHandled;
- if (file.toFileInfo().isRelative()) {
- for (int i = 0; i < m_fileList.size(); i++)
- if (m_fileList[i].endsWith(file.toString())) {
- file = Utils::FilePath::fromString(m_fileList[i]);
- break;
- }
- }
-
- CompileTask task(Task::Error,
- m_javaRegExp.cap(4).trimmed(),
- file /* filename */,
- lineno);
- emit addTask(task, 1);
- return;
+ bool ok;
+ int lineno = m_javaRegExp.cap(3).toInt(&ok);
+ if (!ok)
+ lineno = -1;
+ Utils::FilePath file = Utils::FilePath::fromUserInput(m_javaRegExp.cap(2));
+ if (file.isChildOf(m_buildDirectory)) {
+ Utils::FilePath relativePath = file.relativeChildPath(m_buildDirectory);
+ file = m_sourceDirectory.pathAppended(relativePath.toString());
+ }
+ if (file.toFileInfo().isRelative()) {
+ for (int i = 0; i < m_fileList.size(); i++)
+ if (m_fileList[i].endsWith(file.toString())) {
+ file = Utils::FilePath::fromString(m_fileList[i]);
+ break;
+ }
}
+ CompileTask task(Task::Error,
+ m_javaRegExp.cap(4).trimmed(),
+ absoluteFilePath(file),
+ lineno);
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, task.file, task.line, m_javaRegExp, 2);
+ scheduleTask(task, 1);
+ return {Status::Done, linkSpecs};
}
diff --git a/src/plugins/android/javaparser.h b/src/plugins/android/javaparser.h
index ee9a53df1f..09b19d5bdb 100644
--- a/src/plugins/android/javaparser.h
+++ b/src/plugins/android/javaparser.h
@@ -33,21 +33,19 @@
namespace Android {
namespace Internal {
-class JavaParser : public ProjectExplorer::IOutputParser
+class JavaParser : public ProjectExplorer::OutputTaskParser
{
Q_OBJECT
public:
JavaParser();
- void stdOutput(const QString &line) override;
- void stdError(const QString &line) override;
void setProjectFileList(const QStringList &fileList);
void setBuildDirectory(const Utils::FilePath &buildDirectory);
void setSourceDirectory(const Utils::FilePath &sourceDirectory);
private:
- void parse(const QString &line);
+ Result handleLine(const QString &line, Utils::OutputFormat type) override;
QRegExp m_javaRegExp;
QStringList m_fileList;
diff --git a/src/plugins/autotest/CMakeLists.txt b/src/plugins/autotest/CMakeLists.txt
index b624c4eff3..1ee331dc5f 100644
--- a/src/plugins/autotest/CMakeLists.txt
+++ b/src/plugins/autotest/CMakeLists.txt
@@ -21,6 +21,13 @@ add_qtc_plugin(AutoTest
boost/boosttestsettings.cpp boost/boosttestsettings.h
boost/boosttestsettingspage.cpp boost/boosttestsettingspage.h boost/boosttestsettingspage.ui
boost/boosttesttreeitem.cpp boost/boosttesttreeitem.h
+ catch/catchcodeparser.cpp catch/catchcodeparser.h
+ catch/catchconfiguration.cpp catch/catchconfiguration.h
+ catch/catchframework.h catch/catchframework.cpp catch/catchoutputreader.h
+ catch/catchoutputreader.cpp catch/catchresult.h catch/catchresult.cpp catch/catchtestparser.h
+ catch/catchtestparser.cpp catch/catchtreeitem.h catch/catchtreeitem.cpp
+ catch/catchtestsettings.cpp catch/catchtestsettings.h
+ catch/catchtestsettingspage.cpp catch/catchtestsettingspage.h catch/catchtestsettingspage.ui
gtest/gtest_utils.cpp gtest/gtest_utils.h
gtest/gtestconfiguration.cpp gtest/gtestconfiguration.h
gtest/gtestconstants.h
@@ -33,7 +40,7 @@ add_qtc_plugin(AutoTest
gtest/gtesttreeitem.cpp gtest/gtesttreeitem.h
gtest/gtestvisitors.cpp gtest/gtestvisitors.h
iframeworksettings.h
- itestframework.h
+ itestframework.cpp itestframework.h
itestparser.cpp itestparser.h
projectsettingswidget.cpp projectsettingswidget.h
qtest/qttest_utils.cpp qtest/qttest_utils.h
@@ -72,7 +79,6 @@ add_qtc_plugin(AutoTest
testtreeitemdelegate.cpp testtreeitemdelegate.h
testtreemodel.cpp testtreemodel.h
testtreeview.cpp testtreeview.h
- EXPLICIT_MOC boost/boosttestsettingspage.h
)
extend_qtc_plugin(AutoTest
diff --git a/src/plugins/autotest/autotest.pro b/src/plugins/autotest/autotest.pro
index c816a32a44..5d1db25e3a 100644
--- a/src/plugins/autotest/autotest.pro
+++ b/src/plugins/autotest/autotest.pro
@@ -7,6 +7,7 @@ DEFINES += AUTOTEST_LIBRARY
SOURCES += \
autotestplugin.cpp \
+ itestframework.cpp \
itestparser.cpp \
projectsettingswidget.cpp \
testcodeparser.cpp \
@@ -27,6 +28,15 @@ SOURCES += \
testtreeitemdelegate.cpp \
testtreemodel.cpp \
testtreeview.cpp \
+ catch/catchcodeparser.cpp \
+ catch/catchconfiguration.cpp \
+ catch/catchframework.cpp \
+ catch/catchoutputreader.cpp \
+ catch/catchresult.cpp \
+ catch/catchtestparser.cpp \
+ catch/catchtestsettings.cpp \
+ catch/catchtestsettingspage.cpp \
+ catch/catchtreeitem.cpp \
gtest/gtestconfiguration.cpp \
gtest/gtestparser.cpp \
gtest/gtesttreeitem.cpp \
@@ -91,6 +101,15 @@ HEADERS += \
testtreeitemdelegate.h \
testtreemodel.h \
testtreeview.h \
+ catch/catchcodeparser.h \
+ catch/catchconfiguration.h \
+ catch/catchframework.h \
+ catch/catchoutputreader.h \
+ catch/catchresult.h \
+ catch/catchtestparser.h \
+ catch/catchtestsettings.h \
+ catch/catchtestsettingspage.h \
+ catch/catchtreeitem.h \
gtest/gtestconfiguration.h \
gtest/gtestparser.h \
gtest/gtesttreeitem.h \
@@ -136,6 +155,7 @@ RESOURCES += \
FORMS += \
testsettingspage.ui \
boost/boosttestsettingspage.ui \
+ catch/catchtestsettingspage.ui \
qtest/qttestsettingspage.ui \
gtest/gtestsettingspage.ui
diff --git a/src/plugins/autotest/autotest.qbs b/src/plugins/autotest/autotest.qbs
index 737776dfc7..ea014bc06d 100644
--- a/src/plugins/autotest/autotest.qbs
+++ b/src/plugins/autotest/autotest.qbs
@@ -76,6 +76,7 @@ QtcPlugin {
"testprojectsettings.h",
"itestparser.cpp",
"itestparser.h",
+ "itestframework.cpp",
"itestframework.h",
"iframeworksettings.h",
"testframeworkmanager.cpp",
@@ -112,6 +113,13 @@ QtcPlugin {
}
Group {
+ name: "Catch framework files"
+ files: [
+ "catch/*"
+ ]
+ }
+
+ Group {
name: "Test sources"
condition: qtc.testsEnabled
files: [
diff --git a/src/plugins/autotest/autotestplugin.cpp b/src/plugins/autotest/autotestplugin.cpp
index 46e00c8267..9e01a295ce 100644
--- a/src/plugins/autotest/autotestplugin.cpp
+++ b/src/plugins/autotest/autotestplugin.cpp
@@ -43,6 +43,7 @@
#include "quick/quicktestframework.h"
#include "gtest/gtestframework.h"
#include "boost/boosttestframework.h"
+#include "catch/catchframework.h"
#include <coreplugin/icore.h>
#include <coreplugin/icontext.h>
@@ -86,12 +87,9 @@ class AutotestPluginPrivate : public QObject
{
Q_OBJECT
public:
- explicit AutotestPluginPrivate(AutotestPlugin *parent);
+ AutotestPluginPrivate();
~AutotestPluginPrivate() override;
- AutotestPlugin *q = nullptr;
- TestFrameworkManager *m_frameworkManager = nullptr;
- TestSettingsPage *m_testSettingPage = nullptr;
TestNavigationWidgetFactory *m_navigationWidgetFactory = nullptr;
TestResultsPane *m_resultsPane = nullptr;
QMap<QString, ChoicePair> m_runconfigCache;
@@ -101,39 +99,44 @@ public:
void onRunSelectedTriggered();
void onRunFileTriggered();
void onRunUnderCursorTriggered(TestRunMode mode);
+
+ TestSettings m_settings;
+ TestSettingsPage m_testSettingPage{&m_settings};
+
+ TestCodeParser m_testCodeParser;
+ TestTreeModel m_testTreeModel{&m_testCodeParser};
+ TestRunner m_testRunner;
+ TestFrameworkManager m_frameworkManager;
};
-static AutotestPlugin *s_instance = nullptr;
+static AutotestPluginPrivate *dd = nullptr;
static QHash<ProjectExplorer::Project *, TestProjectSettings *> s_projectSettings;
AutotestPlugin::AutotestPlugin()
- : m_settings(new TestSettings)
{
// needed to be used in QueuedConnection connects
qRegisterMetaType<TestResult>();
qRegisterMetaType<TestTreeItem *>();
qRegisterMetaType<TestCodeLocationAndType>();
-
- s_instance = this;
}
AutotestPlugin::~AutotestPlugin()
{
- delete d;
+ delete dd;
+ dd = nullptr;
}
-AutotestPluginPrivate::AutotestPluginPrivate(AutotestPlugin *parent)
- : q(parent)
+AutotestPluginPrivate::AutotestPluginPrivate()
{
- m_frameworkManager = TestFrameworkManager::instance();
+ dd = this; // Needed as the code below access it via the static plugin interface
initializeMenuEntries();
- m_frameworkManager->registerTestFramework(new QtTestFramework);
- m_frameworkManager->registerTestFramework(new QuickTestFramework);
- m_frameworkManager->registerTestFramework(new GTestFramework);
- m_frameworkManager->registerTestFramework(new BoostTestFramework);
+ m_frameworkManager.registerTestFramework(new QtTestFramework);
+ m_frameworkManager.registerTestFramework(new QuickTestFramework);
+ m_frameworkManager.registerTestFramework(new GTestFramework);
+ m_frameworkManager.registerTestFramework(new BoostTestFramework);
+ m_frameworkManager.registerTestFramework(new CatchFramework);
- m_frameworkManager->synchronizeSettings(ICore::settings());
- m_testSettingPage = new TestSettingsPage(q->settings());
+ m_frameworkManager.synchronizeSettings(ICore::settings());
m_navigationWidgetFactory = new TestNavigationWidgetFactory;
m_resultsPane = TestResultsPane::instance();
@@ -146,15 +149,15 @@ AutotestPluginPrivate::AutotestPluginPrivate(AutotestPlugin *parent)
});
ProjectExplorer::ProjectPanelFactory::registerFactory(panelFactory);
- m_frameworkManager->activateFrameworksFromSettings(q->settings());
- TestTreeModel::instance()->synchronizeTestFrameworks();
+ m_frameworkManager.activateFrameworksFromSettings(&m_settings);
+ m_testTreeModel.synchronizeTestFrameworks();
auto sessionManager = ProjectExplorer::SessionManager::instance();
connect(sessionManager, &ProjectExplorer::SessionManager::startupProjectChanged,
this, [this] { m_runconfigCache.clear(); });
connect(sessionManager, &ProjectExplorer::SessionManager::aboutToRemoveProject,
- this, [this] (ProjectExplorer::Project *project) {
+ this, [] (ProjectExplorer::Project *project) {
auto it = s_projectSettings.find(project);
if (it != s_projectSettings.end()) {
delete it.value();
@@ -172,13 +175,11 @@ AutotestPluginPrivate::~AutotestPluginPrivate()
delete m_navigationWidgetFactory;
delete m_resultsPane;
- delete m_testSettingPage;
- delete m_frameworkManager;
}
-QSharedPointer<TestSettings> AutotestPlugin::settings()
+TestSettings *AutotestPlugin::settings()
{
- return s_instance->m_settings;
+ return &dd->m_settings;
}
TestProjectSettings *AutotestPlugin::projectSettings(ProjectExplorer::Project *project)
@@ -236,9 +237,8 @@ void AutotestPluginPrivate::initializeMenuEntries()
command = ActionManager::registerAction(action, Constants::ACTION_SCAN_ID);
command->setDefaultKeySequence(
QKeySequence(useMacShortcuts ? tr("Ctrl+Meta+T, Ctrl+Meta+S") : tr("Alt+Shift+T,Alt+S")));
- connect(action, &QAction::triggered, this, []() {
- TestTreeModel::instance()->parser()->updateTestTree();
- });
+
+ connect(action, &QAction::triggered, this, [] { dd->m_testCodeParser.updateTestTree(); });
menu->addAction(command);
ActionContainer *toolsMenu = ActionManager::actionContainer(Core::Constants::M_TOOLS);
@@ -250,7 +250,7 @@ void AutotestPluginPrivate::initializeMenuEntries()
this, &AutotestPlugin::updateMenuItemsEnabledState);
connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::runActionsUpdated,
this, &AutotestPlugin::updateMenuItemsEnabledState);
- connect(TestTreeModel::instance(), &TestTreeModel::testTreeModelChanged,
+ connect(&dd->m_testTreeModel, &TestTreeModel::testTreeModelChanged,
this, &AutotestPlugin::updateMenuItemsEnabledState);
}
@@ -259,7 +259,7 @@ bool AutotestPlugin::initialize(const QStringList &arguments, QString *errorStri
Q_UNUSED(arguments)
Q_UNUSED(errorString)
- d = new AutotestPluginPrivate(this);
+ dd = new AutotestPluginPrivate;
return true;
}
@@ -275,7 +275,7 @@ void AutotestPlugin::extensionsInitialized()
Command *command = ActionManager::registerAction(action, Constants::ACTION_RUN_UCURSOR);
connect(action, &QAction::triggered,
- std::bind(&AutotestPluginPrivate::onRunUnderCursorTriggered, d, TestRunMode::Run));
+ std::bind(&AutotestPluginPrivate::onRunUnderCursorTriggered, dd, TestRunMode::Run));
contextMenu->addSeparator();
contextMenu->addAction(command);
@@ -285,31 +285,28 @@ void AutotestPlugin::extensionsInitialized()
command = ActionManager::registerAction(action, Constants::ACTION_RUN_DBG_UCURSOR);
connect(action, &QAction::triggered,
- std::bind(&AutotestPluginPrivate::onRunUnderCursorTriggered, d, TestRunMode::Debug));
+ std::bind(&AutotestPluginPrivate::onRunUnderCursorTriggered, dd, TestRunMode::Debug));
contextMenu->addAction(command);
contextMenu->addSeparator();
}
ExtensionSystem::IPlugin::ShutdownFlag AutotestPlugin::aboutToShutdown()
{
- TestTreeModel::instance()->parser()->aboutToShutdown();
+ dd->m_testCodeParser.aboutToShutdown();
+ dd->m_testTreeModel.disconnect();
return SynchronousShutdown;
}
void AutotestPluginPrivate::onRunAllTriggered()
{
- TestRunner *runner = TestRunner::instance();
- TestTreeModel *model = TestTreeModel::instance();
- runner->setSelectedTests(model->getAllTestCases());
- runner->prepareToRunTests(TestRunMode::Run);
+ m_testRunner.setSelectedTests(m_testTreeModel.getAllTestCases());
+ m_testRunner.prepareToRunTests(TestRunMode::Run);
}
void AutotestPluginPrivate::onRunSelectedTriggered()
{
- TestRunner *runner = TestRunner::instance();
- TestTreeModel *model = TestTreeModel::instance();
- runner->setSelectedTests(model->getSelectedTests());
- runner->prepareToRunTests(TestRunMode::Run);
+ m_testRunner.setSelectedTests(m_testTreeModel.getSelectedTests());
+ m_testRunner.prepareToRunTests(TestRunMode::Run);
}
void AutotestPluginPrivate::onRunFileTriggered()
@@ -322,14 +319,12 @@ void AutotestPluginPrivate::onRunFileTriggered()
if (fileName.isEmpty())
return;
- TestTreeModel *model = TestTreeModel::instance();
- const QList<TestConfiguration *> tests = model->getTestsForFile(fileName);
+ const QList<TestConfiguration *> tests = m_testTreeModel.getTestsForFile(fileName);
if (tests.isEmpty())
return;
- TestRunner *runner = TestRunner::instance();
- runner->setSelectedTests(tests);
- runner->prepareToRunTests(TestRunMode::Run);
+ m_testRunner.setSelectedTests(tests);
+ m_testRunner.prepareToRunTests(TestRunMode::Run);
}
static QList<TestConfiguration *> testItemsToTestConfigurations(const QList<TestTreeItem *> &items,
@@ -352,7 +347,7 @@ void AutotestPluginPrivate::onRunUnderCursorTriggered(TestRunMode mode)
if (text.isEmpty())
return; // Do not trigger when no name under cursor
- const QList<TestTreeItem *> testsItems = TestTreeModel::instance()->testItemsByName(text);
+ const QList<TestTreeItem *> testsItems = m_testTreeModel.testItemsByName(text);
if (testsItems.isEmpty())
return; // Wrong location triggered
@@ -371,18 +366,17 @@ void AutotestPluginPrivate::onRunUnderCursorTriggered(TestRunMode mode)
return;
}
- auto runner = TestRunner::instance();
- runner->setSelectedTests(testsToRun);
- runner->prepareToRunTests(mode);
+ m_testRunner.setSelectedTests(testsToRun);
+ m_testRunner.prepareToRunTests(mode);
}
void AutotestPlugin::updateMenuItemsEnabledState()
{
const ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject();
const ProjectExplorer::Target *target = project ? project->activeTarget() : nullptr;
- const bool canScan = !TestRunner::instance()->isTestRunning()
- && TestTreeModel::instance()->parser()->state() == TestCodeParser::Idle;
- const bool hasTests = TestTreeModel::instance()->hasTests();
+ const bool canScan = !dd->m_testRunner.isTestRunning()
+ && dd->m_testCodeParser.state() == TestCodeParser::Idle;
+ const bool hasTests = dd->m_testTreeModel.hasTests();
// avoid expensive call to PE::canRunStartupProject() - limit to minimum necessary checks
const bool canRun = hasTests && canScan
&& project && !project->needsConfiguration()
@@ -404,32 +398,32 @@ void AutotestPlugin::updateMenuItemsEnabledState()
void AutotestPlugin::cacheRunConfigChoice(const QString &buildTargetKey, const ChoicePair &choice)
{
- if (s_instance)
- s_instance->d->m_runconfigCache.insert(buildTargetKey, choice);
+ if (dd)
+ dd->m_runconfigCache.insert(buildTargetKey, choice);
}
ChoicePair AutotestPlugin::cachedChoiceFor(const QString &buildTargetKey)
{
- return s_instance ? s_instance->d->m_runconfigCache.value(buildTargetKey) : ChoicePair();
+ return dd ? dd->m_runconfigCache.value(buildTargetKey) : ChoicePair();
}
void AutotestPlugin::clearChoiceCache()
{
- if (s_instance)
- s_instance->d->m_runconfigCache.clear();
+ if (dd)
+ dd->m_runconfigCache.clear();
}
void AutotestPlugin::popupResultsPane()
{
- if (s_instance)
- s_instance->d->m_resultsPane->popup(Core::IOutputPane::NoModeSwitch);
+ if (dd)
+ dd->m_resultsPane->popup(Core::IOutputPane::NoModeSwitch);
}
QVector<QObject *> AutotestPlugin::createTestObjects() const
{
QVector<QObject *> tests;
#ifdef WITH_TESTS
- tests << new AutoTestUnitTests(TestTreeModel::instance());
+ tests << new AutoTestUnitTests(&dd->m_testTreeModel);
#endif
return tests;
}
diff --git a/src/plugins/autotest/autotestplugin.h b/src/plugins/autotest/autotestplugin.h
index b34fd95c36..c30db79e12 100644
--- a/src/plugins/autotest/autotestplugin.h
+++ b/src/plugins/autotest/autotestplugin.h
@@ -29,8 +29,6 @@
#include <extensionsystem/iplugin.h>
-#include <QMap>
-
namespace ProjectExplorer {
class Project;
class RunConfiguration;
@@ -65,7 +63,7 @@ public:
void extensionsInitialized() override;
ShutdownFlag aboutToShutdown() override;
- static QSharedPointer<TestSettings> settings();
+ static TestSettings *settings();
static TestProjectSettings *projectSettings(ProjectExplorer::Project *project);
static void updateMenuItemsEnabledState();
static void cacheRunConfigChoice(const QString &buildTargetKey, const ChoicePair &choice);
@@ -75,8 +73,6 @@ public:
private:
QVector<QObject *> createTestObjects() const override;
- class AutotestPluginPrivate *d = nullptr;
- const QSharedPointer<TestSettings> m_settings;
};
} // namespace Internal
diff --git a/src/plugins/autotest/autotestunittests.cpp b/src/plugins/autotest/autotestunittests.cpp
index 767aee6a13..9a70fb2fdc 100644
--- a/src/plugins/autotest/autotestunittests.cpp
+++ b/src/plugins/autotest/autotestunittests.cpp
@@ -67,8 +67,7 @@ void AutoTestUnitTests::initTestCase()
m_isQt4 = qtVersion->qtVersionString().startsWith('4');
else
QSKIP("Could not figure out which Qt version is used for default kit.");
- const ToolChain * const toolchain = ToolChainKitAspect::toolChain(allKits.first(),
- ProjectExplorer::Constants::CXX_LANGUAGE_ID);
+ const ToolChain * const toolchain = ToolChainKitAspect::cxxToolChain(allKits.first());
if (!toolchain)
QSKIP("This test requires that there is a kit with a toolchain.");
diff --git a/src/plugins/autotest/boost/boosttestconfiguration.cpp b/src/plugins/autotest/boost/boosttestconfiguration.cpp
index e24b45196d..8bd90f78fe 100644
--- a/src/plugins/autotest/boost/boosttestconfiguration.cpp
+++ b/src/plugins/autotest/boost/boosttestconfiguration.cpp
@@ -29,24 +29,16 @@
#include "boosttestsettings.h"
#include "../autotestplugin.h"
-#include "../testframeworkmanager.h"
+#include "../itestframework.h"
#include "../testsettings.h"
namespace Autotest {
namespace Internal {
-static QSharedPointer<BoostTestSettings> getBoostSettings()
-{
- const Core::Id id = Core::Id(Constants::FRAMEWORK_PREFIX).withSuffix(
- BoostTest::Constants::FRAMEWORK_NAME);
- TestFrameworkManager *manager = TestFrameworkManager::instance();
- return qSharedPointerCast<BoostTestSettings>(manager->settingsForTestFramework(id));
-}
-
TestOutputReader *BoostTestConfiguration::outputReader(const QFutureInterface<TestResultPtr> &fi,
QProcess *app) const
{
- auto settings = getBoostSettings();
+ auto settings = dynamic_cast<BoostTestSettings *>(framework()->frameworkSettings());
return new BoostTestOutputReader(fi, app, buildDirectory(), projectFile(),
settings->logLevel, settings->reportLevel);
}
@@ -113,7 +105,7 @@ static QStringList filterInterfering(const QStringList &provided, QStringList *o
QStringList BoostTestConfiguration::argumentsForTestRunner(QStringList *omitted) const
{
- auto boostSettings = getBoostSettings();
+ auto boostSettings = dynamic_cast<BoostTestSettings *>(framework()->frameworkSettings());
QStringList arguments;
arguments << "-l" << BoostTestSettings::logLevelToOption(boostSettings->logLevel);
arguments << "-r" << BoostTestSettings::reportLevelToOption(boostSettings->reportLevel);
diff --git a/src/plugins/autotest/boost/boosttestconfiguration.h b/src/plugins/autotest/boost/boosttestconfiguration.h
index e792fe21d5..2259eca513 100644
--- a/src/plugins/autotest/boost/boosttestconfiguration.h
+++ b/src/plugins/autotest/boost/boosttestconfiguration.h
@@ -33,7 +33,8 @@ namespace Internal {
class BoostTestConfiguration : public DebuggableTestConfiguration
{
public:
- BoostTestConfiguration() {}
+ explicit BoostTestConfiguration(ITestFramework *framework)
+ : DebuggableTestConfiguration(framework) {}
TestOutputReader *outputReader(const QFutureInterface<TestResultPtr> &fi,
QProcess *app) const override;
QStringList argumentsForTestRunner(QStringList *omitted = nullptr) const override;
diff --git a/src/plugins/autotest/boost/boosttestframework.cpp b/src/plugins/autotest/boost/boosttestframework.cpp
index d54881540a..a1448e33cc 100644
--- a/src/plugins/autotest/boost/boosttestframework.cpp
+++ b/src/plugins/autotest/boost/boosttestframework.cpp
@@ -25,8 +25,6 @@
#include "boosttestframework.h"
#include "boosttestconstants.h"
-#include "boosttestsettings.h"
-#include "boosttestsettingspage.h"
#include "boosttesttreeitem.h"
#include "boosttestparser.h"
#include "../testframeworkmanager.h"
@@ -34,14 +32,15 @@
namespace Autotest {
namespace Internal {
-ITestParser *BoostTestFramework::createTestParser() const
+ITestParser *BoostTestFramework::createTestParser()
{
- return new BoostTestParser;
+ return new BoostTestParser(this);
}
-TestTreeItem *BoostTestFramework::createRootNode() const
+TestTreeItem *BoostTestFramework::createRootNode()
{
return new BoostTestTreeItem(
+ this,
QCoreApplication::translate("BoostTestFramework",
BoostTest::Constants::FRAMEWORK_SETTINGS_CATEGORY),
QString(), TestTreeItem::Root);
@@ -57,20 +56,5 @@ unsigned BoostTestFramework::priority() const
return BoostTest::Constants::FRAMEWORK_PRIORITY;
}
-IFrameworkSettings *BoostTestFramework::createFrameworkSettings() const
-{
- return new BoostTestSettings;
-}
-
-Core::IOptionsPage *BoostTestFramework::createSettingsPage(QSharedPointer<IFrameworkSettings> settings) const
-{
- return new BoostTestSettingsPage(settings, settingsId());
-}
-
-bool BoostTestFramework::hasFrameworkSettings() const
-{
- return true;
-}
-
} // namespace Internal
} // namespace Autotest
diff --git a/src/plugins/autotest/boost/boosttestframework.h b/src/plugins/autotest/boost/boosttestframework.h
index dfe46dd0fe..2d112ae077 100644
--- a/src/plugins/autotest/boost/boosttestframework.h
+++ b/src/plugins/autotest/boost/boosttestframework.h
@@ -27,6 +27,9 @@
#include "../itestframework.h"
+#include "boosttestsettings.h"
+#include "boosttestsettingspage.h"
+
namespace Autotest {
namespace Internal {
@@ -34,14 +37,16 @@ class BoostTestFramework : public ITestFramework
{
public:
BoostTestFramework() : ITestFramework(true) {}
+
+private:
const char *name() const override;
unsigned priority() const override;
- IFrameworkSettings *createFrameworkSettings() const override;
- Core::IOptionsPage *createSettingsPage(QSharedPointer<IFrameworkSettings> settings) const override;
- bool hasFrameworkSettings() const override;
-protected:
- ITestParser *createTestParser() const override;
- TestTreeItem *createRootNode() const override;
+ IFrameworkSettings *frameworkSettings() override { return &m_settings; }
+ ITestParser *createTestParser() override;
+ TestTreeItem *createRootNode() override;
+
+ BoostTestSettings m_settings;
+ BoostTestSettingsPage m_settingsPage{&m_settings, settingsId()};
};
} // namespace Internal
diff --git a/src/plugins/autotest/boost/boosttestparser.cpp b/src/plugins/autotest/boost/boosttestparser.cpp
index 09c216c1b6..db49187d37 100644
--- a/src/plugins/autotest/boost/boosttestparser.cpp
+++ b/src/plugins/autotest/boost/boosttestparser.cpp
@@ -56,7 +56,7 @@ TestTreeItem *BoostTestParseResult::createTestTreeItem() const
if (itemType == TestTreeItem::Root)
return nullptr;
- BoostTestTreeItem *item = new BoostTestTreeItem(displayName, fileName, itemType);
+ BoostTestTreeItem *item = new BoostTestTreeItem(framework, displayName, fileName, itemType);
item->setProFile(proFile);
item->setLine(line);
item->setColumn(column);
@@ -98,10 +98,10 @@ static bool hasBoostTestMacros(const CPlusPlus::Document::Ptr &doc)
}
static BoostTestParseResult *createParseResult(const QString &name, const QString &filePath,
- const QString &projectFile, const Core::Id &id,
+ const QString &projectFile, ITestFramework *framework,
TestTreeItem::Type type, const BoostTestInfo &info)
{
- BoostTestParseResult *partialSuite = new BoostTestParseResult(id);
+ BoostTestParseResult *partialSuite = new BoostTestParseResult(framework);
partialSuite->itemType = type;
partialSuite->fileName = filePath;
partialSuite->name = info.fullName;
@@ -117,7 +117,7 @@ static BoostTestParseResult *createParseResult(const QString &name, const QStrin
static bool handleBoostTest(QFutureInterface<TestParseResultPtr> futureInterface,
const CPlusPlus::Document::Ptr &doc,
const CPlusPlus::Snapshot &snapshot,
- const Core::Id &id)
+ ITestFramework *framework)
{
const CppTools::CppModelManager *modelManager = CppTools::CppModelManager::instance();
const QString &filePath = doc->fileName();
@@ -139,7 +139,7 @@ static bool handleBoostTest(QFutureInterface<TestParseResultPtr> futureInterface
BoostTestInfo firstSuite = suitesStates.first();
QStringList suites = firstSuite.fullName.split('/');
BoostTestParseResult *topLevelSuite = createParseResult(suites.first(), filePath,
- projectFile, id,
+ projectFile, framework,
TestTreeItem::TestSuite,
firstSuite);
BoostTestParseResult *currentSuite = topLevelSuite;
@@ -148,7 +148,7 @@ static bool handleBoostTest(QFutureInterface<TestParseResultPtr> futureInterface
firstSuite = suitesStates.first();
suites = firstSuite.fullName.split('/');
BoostTestParseResult *suiteResult = createParseResult(suites.last(), filePath,
- projectFile, id,
+ projectFile, framework,
TestTreeItem::TestSuite,
firstSuite);
currentSuite->children.append(suiteResult);
@@ -161,7 +161,7 @@ static bool handleBoostTest(QFutureInterface<TestParseResultPtr> futureInterface
locationAndType.m_suitesState.last().fullName + "::" + locationAndType.m_name,
locationAndType.m_state, locationAndType.m_line};
BoostTestParseResult *funcResult = createParseResult(locationAndType.m_name, filePath,
- projectFile, id,
+ projectFile, framework,
locationAndType.m_type,
tmpInfo);
currentSuite->children.append(funcResult);
@@ -177,7 +177,7 @@ bool BoostTestParser::processDocument(QFutureInterface<TestParseResultPtr> futur
CPlusPlus::Document::Ptr doc = document(fileName);
if (doc.isNull() || !includesBoostTest(doc, m_cppSnapshot) || !hasBoostTestMacros(doc))
return false;
- return handleBoostTest(futureInterface, doc, m_cppSnapshot, id());
+ return handleBoostTest(futureInterface, doc, m_cppSnapshot, framework());
}
} // namespace Internal
diff --git a/src/plugins/autotest/boost/boosttestparser.h b/src/plugins/autotest/boost/boosttestparser.h
index 678b859cc9..bba9640ef2 100644
--- a/src/plugins/autotest/boost/boosttestparser.h
+++ b/src/plugins/autotest/boost/boosttestparser.h
@@ -34,7 +34,7 @@ namespace Internal {
class BoostTestParseResult : public TestParseResult
{
public:
- explicit BoostTestParseResult(const Core::Id &id) : TestParseResult(id) {}
+ explicit BoostTestParseResult(ITestFramework *framework) : TestParseResult(framework) {}
TestTreeItem *createTestTreeItem() const override;
// TODO special attributes/states (labeled, timeout,...?)
BoostTestTreeItem::TestStates state = BoostTestTreeItem::Enabled;
@@ -43,6 +43,7 @@ public:
class BoostTestParser : public CppParser
{
public:
+ explicit BoostTestParser(ITestFramework *framework) : CppParser(framework) {}
bool processDocument(QFutureInterface<TestParseResultPtr> futureInterface,
const QString &fileName) override;
};
diff --git a/src/plugins/autotest/boost/boosttestsettingspage.cpp b/src/plugins/autotest/boost/boosttestsettingspage.cpp
index 28afad5c15..ea9d41a0d5 100644
--- a/src/plugins/autotest/boost/boosttestsettingspage.cpp
+++ b/src/plugins/autotest/boost/boosttestsettingspage.cpp
@@ -39,7 +39,7 @@ class BoostTestSettingsWidget : public Core::IOptionsPageWidget
Q_DECLARE_TR_FUNCTIONS(Autotest::Internal::BoostTestSettingsWidget)
public:
- explicit BoostTestSettingsWidget(QSharedPointer<BoostTestSettings> settings);
+ explicit BoostTestSettingsWidget(BoostTestSettings *settings);
void apply() final;
@@ -49,10 +49,10 @@ public:
private:
void fillComboBoxes();
Ui::BoostSettingsPage m_ui;
- QSharedPointer<BoostTestSettings> m_settings;
+ BoostTestSettings *m_settings;
};
-BoostTestSettingsWidget::BoostTestSettingsWidget(QSharedPointer<BoostTestSettings> settings)
+BoostTestSettingsWidget::BoostTestSettingsWidget(BoostTestSettings *settings)
: m_settings(settings)
{
m_ui.setupUi(this);
@@ -101,16 +101,13 @@ void BoostTestSettingsWidget::fillComboBoxes()
m_ui.reportLevelCB->addItem("No", QVariant::fromValue(ReportLevel::No));
}
-BoostTestSettingsPage::BoostTestSettingsPage(QSharedPointer<IFrameworkSettings> settings,
- Core::Id settingsId)
+BoostTestSettingsPage::BoostTestSettingsPage(BoostTestSettings *settings, Core::Id settingsId)
{
setId(settingsId);
setCategory(Constants::AUTOTEST_SETTINGS_CATEGORY);
setDisplayName(QCoreApplication::translate("BoostTestFramework",
BoostTest::Constants::FRAMEWORK_SETTINGS_CATEGORY));
- setWidgetCreator([settings] {
- return new BoostTestSettingsWidget(qSharedPointerCast<BoostTestSettings>(settings));
- });
+ setWidgetCreator([settings] { return new BoostTestSettingsWidget(settings); });
}
} // Internal
diff --git a/src/plugins/autotest/boost/boosttestsettingspage.h b/src/plugins/autotest/boost/boosttestsettingspage.h
index 27a7efd2c1..0c5340d91a 100644
--- a/src/plugins/autotest/boost/boosttestsettingspage.h
+++ b/src/plugins/autotest/boost/boosttestsettingspage.h
@@ -28,15 +28,14 @@
#include <coreplugin/dialogs/ioptionspage.h>
namespace Autotest {
-
-class IFrameworkSettings;
-
namespace Internal {
+class BoostTestSettings;
+
class BoostTestSettingsPage final : public Core::IOptionsPage
{
public:
- BoostTestSettingsPage(QSharedPointer<IFrameworkSettings> settings, Core::Id settingsId);
+ BoostTestSettingsPage(BoostTestSettings *settings, Core::Id settingsId);
};
} // Internal
diff --git a/src/plugins/autotest/boost/boosttesttreeitem.cpp b/src/plugins/autotest/boost/boosttesttreeitem.cpp
index 995331f625..faf5062494 100644
--- a/src/plugins/autotest/boost/boosttesttreeitem.cpp
+++ b/src/plugins/autotest/boost/boosttesttreeitem.cpp
@@ -40,7 +40,7 @@ namespace Internal {
TestTreeItem *BoostTestTreeItem::copyWithoutChildren()
{
- BoostTestTreeItem *copied = new BoostTestTreeItem;
+ BoostTestTreeItem *copied = new BoostTestTreeItem(framework());
copied->copyBasicDataFrom(this);
copied->m_state = m_state;
copied->m_fullName = m_fullName;
@@ -74,7 +74,7 @@ TestTreeItem *BoostTestTreeItem::find(const TestParseResult *result)
switch (type()) {
case Root:
- if (TestFrameworkManager::instance()->groupingEnabled(result->frameworkId)) {
+ if (result->framework->grouping()) {
const QFileInfo fileInfo(bResult->fileName);
const QFileInfo base(fileInfo.absolutePath());
for (int row = 0; row < childCount(); ++row) {
@@ -146,7 +146,7 @@ TestTreeItem *BoostTestTreeItem::createParentGroupNode() const
{
const QFileInfo fileInfo(filePath());
const QFileInfo base(fileInfo.absolutePath());
- return new BoostTestTreeItem(base.baseName(), fileInfo.absolutePath(), TestTreeItem::GroupNode);
+ return new BoostTestTreeItem(framework(), base.baseName(), fileInfo.absolutePath(), TestTreeItem::GroupNode);
}
QString BoostTestTreeItem::prependWithParentsSuitePaths(const QString &testName) const
@@ -204,7 +204,7 @@ QList<TestConfiguration *> BoostTestTreeItem::getAllTestConfigurations() const
for (auto it = testsPerProjectfile.begin(), end = testsPerProjectfile.end(); it != end; ++it) {
for (const QString &target : qAsConst(it.value().internalTargets)) {
- BoostTestConfiguration *config = new BoostTestConfiguration;
+ BoostTestConfiguration *config = new BoostTestConfiguration(framework());
config->setProject(project);
config->setProjectFile(it.key());
config->setTestCaseCount(it.value().testCases);
@@ -250,7 +250,7 @@ QList<TestConfiguration *> BoostTestTreeItem::getSelectedTestConfigurations() co
auto end = testCasesForProjectFile.cend();
for (auto it = testCasesForProjectFile.cbegin(); it != end; ++it) {
for (const QString &target : it.value().internalTargets) {
- BoostTestConfiguration *config = new BoostTestConfiguration;
+ BoostTestConfiguration *config = new BoostTestConfiguration(framework());
config->setProject(project);
config->setProjectFile(it.key());
config->setTestCases(it.value().testCases);
@@ -294,7 +294,7 @@ TestConfiguration *BoostTestTreeItem::testConfiguration() const
testCases.append(prependWithParentsSuitePaths(handleSpecialFunctionNames(tcName)));
}
- BoostTestConfiguration *config = new BoostTestConfiguration;
+ BoostTestConfiguration *config = new BoostTestConfiguration(framework());
config->setProjectFile(proFile());
config->setProject(project);
config->setTestCases(testCases);
diff --git a/src/plugins/autotest/boost/boosttesttreeitem.h b/src/plugins/autotest/boost/boosttesttreeitem.h
index a3676c39de..f9dc154a56 100644
--- a/src/plugins/autotest/boost/boosttesttreeitem.h
+++ b/src/plugins/autotest/boost/boosttesttreeitem.h
@@ -48,8 +48,12 @@ public:
Q_FLAGS(TestState)
Q_DECLARE_FLAGS(TestStates, TestState)
- explicit BoostTestTreeItem(const QString &name = QString(), const QString &filePath = QString(),
- Type type = Root) : TestTreeItem(name, filePath, type) {}
+ explicit BoostTestTreeItem(ITestFramework *framework,
+ const QString &name = QString(),
+ const QString &filePath = QString(),
+ Type type = Root)
+ : TestTreeItem(framework, name, filePath, type)
+ {}
public:
TestTreeItem *copyWithoutChildren() override;
diff --git a/src/plugins/autotest/catch/catchcodeparser.cpp b/src/plugins/autotest/catch/catchcodeparser.cpp
new file mode 100644
index 0000000000..c1368c1aa7
--- /dev/null
+++ b/src/plugins/autotest/catch/catchcodeparser.cpp
@@ -0,0 +1,286 @@
+/****************************************************************************
+**
+** 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 "catchcodeparser.h"
+
+#include <cplusplus/Token.h>
+
+#include <utils/qtcassert.h>
+
+#include <QRegularExpression>
+
+namespace Autotest {
+namespace Internal {
+
+using namespace CPlusPlus;
+
+CatchCodeParser::CatchCodeParser(const QByteArray &source, const LanguageFeatures &features)
+ : m_source(source)
+ , m_features(features)
+{
+}
+
+static CatchTestCodeLocationAndType locationAndTypeFromToken(const Token &tkn)
+{
+ CatchTestCodeLocationAndType locationAndType;
+ locationAndType.m_type = TestTreeItem::TestCase;
+ locationAndType.m_line = tkn.lineno;
+ locationAndType.m_column = 0;
+ return locationAndType;
+}
+
+static Tokens tokensForSource(const QByteArray &source, const LanguageFeatures &features)
+{
+ SimpleLexer lexer;
+ lexer.setPreprocessorMode(false); // or true? does not make a difference so far..
+ lexer.setLanguageFeatures(features);
+ return lexer(QString::fromUtf8(source));
+}
+
+static QStringList parseTags(const QString &tagsString)
+{
+ QStringList tagsList;
+
+ const QRegularExpression tagRegEx("\\[(.*?)\\]",QRegularExpression::CaseInsensitiveOption);
+ int pos = 0;
+ QRegularExpressionMatch it = tagRegEx.match(tagsString, pos);
+ while (it.hasMatch()) {
+ tagsList.append(it.captured(1));
+ pos += it.capturedLength();
+ it = tagRegEx.match(tagsString, pos);
+ }
+ return tagsList;
+}
+
+CatchTestCodeLocationList CatchCodeParser::findTests()
+{
+ m_tokens = tokensForSource(m_source, m_features);
+ m_currentIndex = 0;
+ for ( ; m_currentIndex < m_tokens.size(); ++m_currentIndex) {
+ if (m_tokens.at(m_currentIndex).kind() == T_IDENTIFIER)
+ handleIdentifier();
+ }
+ return m_testCases;
+}
+
+void CatchCodeParser::handleIdentifier()
+{
+ QTC_ASSERT(m_currentIndex < m_tokens.size(), return);
+ const Token &token = m_tokens.at(m_currentIndex);
+ const QByteArray &identifier = m_source.mid(int(token.bytesBegin()), int(token.bytes()));
+ if (identifier == "TEST_CASE") {
+ handleTestCase(false);
+ } else if (identifier == "SCENARIO") {
+ handleTestCase(true);
+ } else if (identifier == "TEMPLATE_TEST_CASE" || identifier == "TEMPLATE_PRODUCT_TEST_CASE"
+ || identifier == "TEMPLATE_LIST_TEST_CASE" || identifier == "TEMPLATE_TEST_CASE_SIG"
+ || identifier == "TEMPLATE_PRODUCT_TEST_CASE_SIG") {
+ handleParameterizedTestCase(false);
+ } else if (identifier == "TEST_CASE_METHOD") {
+ handleFixtureOrRegisteredTestCase(true);
+ } else if (identifier == "TEMPLATE_TEST_CASE_METHOD_SIG"
+ || identifier == "TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG"
+ || identifier == "TEMPLATE_TEST_CASE_METHOD"
+ || identifier == "TEMPLATE_LIST_TEST_CASE_METHOD") {
+ handleParameterizedTestCase(true);
+ } else if (identifier == "METHOD_AS_TEST_CASE" || identifier == "REGISTER_TEST_CASE") {
+ handleFixtureOrRegisteredTestCase(false);
+ }
+}
+
+void CatchCodeParser::handleTestCase(bool isScenario)
+{
+ if (!skipCommentsUntil(T_LPAREN))
+ return;
+
+ CatchTestCodeLocationAndType locationAndType
+ = locationAndTypeFromToken(m_tokens.at(m_currentIndex));
+
+ Kind stoppedAt;
+ ++m_currentIndex;
+ QString testCaseName = getStringLiteral(stoppedAt);
+ QString tagsString; // TODO: use them
+
+ if (stoppedAt == T_COMMA) {
+ ++m_currentIndex;
+ tagsString = getStringLiteral(stoppedAt);
+ }
+
+ if (stoppedAt != T_RPAREN)
+ return;
+
+ if (isScenario)
+ testCaseName.prepend("Scenario: "); // use a flag?
+
+ locationAndType.m_name = testCaseName;
+ locationAndType.tags = parseTags(tagsString);
+ m_testCases.append(locationAndType);
+}
+
+void CatchCodeParser::handleParameterizedTestCase(bool isFixture)
+{
+ if (!skipCommentsUntil(T_LPAREN))
+ return;
+
+ if (isFixture && !skipFixtureParameter())
+ return;
+
+ CatchTestCodeLocationAndType locationAndType
+ = locationAndTypeFromToken(m_tokens.at(m_currentIndex));
+
+ Kind stoppedAt;
+ ++m_currentIndex;
+ QString testCaseName = getStringLiteral(stoppedAt);
+ QString tagsString;
+
+ if (stoppedAt != T_COMMA)
+ return;
+
+ ++m_currentIndex;
+ tagsString = getStringLiteral(stoppedAt);
+
+ if (stoppedAt == T_COMMA)
+ stoppedAt = skipUntilCorrespondingRParen();
+
+ if (stoppedAt != T_RPAREN)
+ return;
+ locationAndType.m_name = testCaseName;
+ locationAndType.tags = parseTags(tagsString);
+ locationAndType.states = CatchTreeItem::Parameterized;
+ if (isFixture)
+ locationAndType.states |= CatchTreeItem::Fixture;
+ m_testCases.append(locationAndType);
+}
+
+void CatchCodeParser::handleFixtureOrRegisteredTestCase(bool isFixture)
+{
+ if (!skipCommentsUntil(T_LPAREN))
+ return;
+
+ if (isFixture) {
+ if (!skipFixtureParameter())
+ return;
+ } else {
+ if (!skipFunctionParameter())
+ return;
+ }
+
+ CatchTestCodeLocationAndType locationAndType
+ = locationAndTypeFromToken(m_tokens.at(m_currentIndex));
+
+ Kind stoppedAt;
+ ++m_currentIndex;
+ QString testCaseName = getStringLiteral(stoppedAt);
+ QString tagsString;
+
+ if (stoppedAt == T_COMMA) {
+ ++m_currentIndex;
+ tagsString = getStringLiteral(stoppedAt);
+ }
+
+ if (stoppedAt != T_RPAREN)
+ return;
+
+ locationAndType.m_name = testCaseName;
+ locationAndType.tags = parseTags(tagsString);
+ if (isFixture)
+ locationAndType.states = CatchTreeItem::Fixture;
+ m_testCases.append(locationAndType);
+}
+
+QString CatchCodeParser::getStringLiteral(Kind &stoppedAtKind)
+{
+ QByteArray captured;
+ int end = m_tokens.size();
+ while (m_currentIndex < end) {
+ const Token token = m_tokens.at(m_currentIndex);
+ Kind kind = token.kind();
+ if (kind == T_STRING_LITERAL) {
+ // store the string without its quotes
+ captured.append(m_source.mid(token.bytesBegin() + 1, token.bytes() - 2));
+ } else if (kind == T_RPAREN || kind == T_COMMA) {
+ stoppedAtKind = kind;
+ return QString::fromUtf8(captured);
+ } else if (!token.isComment()) { // comments are okay - but anything else will cancel
+ stoppedAtKind = kind;
+ return {};
+ }
+ ++m_currentIndex;
+ }
+ stoppedAtKind = T_ERROR;
+ return {};
+}
+
+bool CatchCodeParser::skipCommentsUntil(Kind nextExpectedKind)
+{
+ for (int index = m_currentIndex + 1, end = m_tokens.size(); index < end; ++index) {
+ const Token &token = m_tokens.at(index);
+ if (token.isComment())
+ continue;
+ if (token.kind() != nextExpectedKind)
+ break;
+ m_currentIndex = index;
+ return true;
+ }
+ return false;
+}
+
+Kind CatchCodeParser::skipUntilCorrespondingRParen()
+{
+ int openParens = 1; // we have already one open, looking for the corresponding closing
+ int end = m_tokens.size();
+ while (m_currentIndex < end) {
+ Kind kind = m_tokens.at(m_currentIndex).kind();
+ if (kind == T_LPAREN) {
+ ++openParens;
+ } else if (kind == T_RPAREN) {
+ --openParens;
+ if (openParens == 0)
+ return T_RPAREN;
+ }
+ ++m_currentIndex;
+ }
+ return T_ERROR;
+}
+
+bool CatchCodeParser::skipFixtureParameter()
+{
+ if (!skipCommentsUntil(T_IDENTIFIER))
+ return false;
+ return skipCommentsUntil(T_COMMA);
+}
+
+bool CatchCodeParser::skipFunctionParameter()
+{
+ if (!skipCommentsUntil(T_IDENTIFIER))
+ return false;
+ if (skipCommentsUntil(T_COLON_COLON))
+ return skipFunctionParameter();
+
+ return skipCommentsUntil(T_COMMA);
+}
+
+} // namespace Internal
+} // namespace Autotest
diff --git a/src/plugins/autotest/catch/catchcodeparser.h b/src/plugins/autotest/catch/catchcodeparser.h
new file mode 100644
index 0000000000..863f05a2db
--- /dev/null
+++ b/src/plugins/autotest/catch/catchcodeparser.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** 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 "catchtreeitem.h"
+
+#include <cplusplus/SimpleLexer.h>
+
+#include <QByteArray>
+
+namespace Autotest {
+namespace Internal {
+
+class CatchCodeParser
+{
+public:
+ CatchCodeParser(const QByteArray &source, const CPlusPlus::LanguageFeatures &features);
+ virtual ~CatchCodeParser() = default;
+ CatchTestCodeLocationList findTests();
+private:
+ void handleIdentifier();
+ void handleTestCase(bool isScenario);
+ void handleParameterizedTestCase(bool isFixture);
+ void handleFixtureOrRegisteredTestCase(bool isFixture);
+
+ QString getStringLiteral(CPlusPlus::Kind &stoppedAtKind);
+ bool skipCommentsUntil(CPlusPlus::Kind nextExpectedKind); // moves currentIndex if succeeds
+ CPlusPlus::Kind skipUntilCorrespondingRParen(); // moves currentIndex
+ bool skipFixtureParameter();
+ bool skipFunctionParameter();
+
+ const QByteArray &m_source;
+ const CPlusPlus::LanguageFeatures &m_features;
+ CPlusPlus::Tokens m_tokens;
+ int m_currentIndex = 0;
+ CatchTestCodeLocationList m_testCases;
+};
+
+} // namespace Internal
+} // namespace Autotest
diff --git a/src/plugins/autotest/catch/catchconfiguration.cpp b/src/plugins/autotest/catch/catchconfiguration.cpp
new file mode 100644
index 0000000000..51b2946a4f
--- /dev/null
+++ b/src/plugins/autotest/catch/catchconfiguration.cpp
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Jochen Seemann
+**
+** 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 "catchconfiguration.h"
+#include "catchoutputreader.h"
+#include "catchtestsettings.h"
+
+#include "../autotestplugin.h"
+#include "../itestframework.h"
+#include "../testsettings.h"
+
+namespace Autotest {
+namespace Internal {
+
+TestOutputReader *CatchConfiguration::outputReader(const QFutureInterface<TestResultPtr> &fi, QProcess *app) const
+{
+ return new CatchOutputReader(fi, app, buildDirectory(), projectFile());
+}
+
+static QStringList filterInterfering(const QStringList &provided, QStringList *omitted)
+{
+ static const QSet<QString> singleOptions { "-l", "--list-tests",
+ "--list-test-names-only",
+ "-t", "--list-tags",
+ "--list-reporters",
+ "-s", "--success",
+ "-b", "--break",
+ "-e", "--nothrow",
+ "-a", "--abort",
+ "-#", "--filenames-as-tags",
+ "--benchmark-no-analysis",
+ "--help"
+ };
+ static const QSet<QString> paramOptions { "-o", "--out",
+ "-r", "--reporter",
+ "-x", "--abortx",
+ "-w", "--warn",
+ "-d", "--durations",
+ "-f", "--input-file",
+ "-c", "--section",
+ "--wait-for-keypress",
+ "--benchmark-samples",
+ "--benchmark-resamples",
+ "--benchmark-confidence-interval",
+ "--benchmark-warmup-time",
+ "--use-color"
+ };
+
+ QStringList allowed;
+ bool filterNext = false;
+ for (auto arg : provided) {
+ bool interferes = false;
+ if (filterNext) {
+ omitted->append(arg);
+ filterNext = false;
+ continue;
+ }
+ if (singleOptions.contains(arg)) {
+ interferes = true;
+ } else if (paramOptions.contains(arg)) {
+ interferes = true;
+ filterNext = true;
+ }
+ if (!interferes)
+ allowed.append(arg);
+ else if (omitted)
+ omitted->append(arg);
+ }
+ return allowed;
+}
+
+QStringList CatchConfiguration::argumentsForTestRunner(QStringList *omitted) const
+{
+ QStringList arguments;
+ if (testCaseCount())
+ arguments << "\"" + testCases().join("\",\"") + "\"";
+ arguments << "--reporter" << "xml";
+
+ if (AutotestPlugin::settings()->processArgs) {
+ arguments << filterInterfering(runnable().commandLineArguments.split(
+ ' ', QString::SkipEmptyParts), omitted);
+ }
+
+ auto settings = dynamic_cast<CatchTestSettings *>(framework()->frameworkSettings());
+ if (!settings)
+ return arguments;
+
+ if (settings->abortAfterChecked)
+ arguments << "-x" << QString::number(settings->abortAfter);
+ if (settings->samplesChecked)
+ arguments << "--benchmark-samples" << QString::number(settings->benchmarkSamples);
+ if (settings->resamplesChecked)
+ arguments << "--benchmark-resamples" << QString::number(settings->benchmarkResamples);
+ if (settings->warmupChecked)
+ arguments << "--benchmark-warmup-time" << QString::number(settings->benchmarkWarmupTime);
+ if (settings->confidenceIntervalChecked)
+ arguments << "--benchmark-confidence-interval" << QString::number(settings->confidenceInterval);
+ if (settings->noAnalysis)
+ arguments << "--benchmark-no-analysis";
+ if (settings->showSuccess)
+ arguments << "-s";
+ if (settings->noThrow)
+ arguments << "-e";
+ if (settings->visibleWhitespace)
+ arguments << "-i";
+ if (settings->warnOnEmpty)
+ arguments << "-w" << "NoAssertions";
+
+ if (isDebugRunMode() && settings->breakOnFailure)
+ arguments << "-b";
+ return arguments;
+}
+
+Utils::Environment CatchConfiguration::filteredEnvironment(const Utils::Environment &original) const
+{
+ return original;
+}
+
+} // namespace Internal
+} // namespace Autotest
diff --git a/src/plugins/autotest/catch/catchconfiguration.h b/src/plugins/autotest/catch/catchconfiguration.h
new file mode 100644
index 0000000000..2a19855809
--- /dev/null
+++ b/src/plugins/autotest/catch/catchconfiguration.h
@@ -0,0 +1,43 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Jochen Seemann
+**
+** 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 "../testconfiguration.h"
+
+namespace Autotest {
+namespace Internal {
+
+class CatchConfiguration : public DebuggableTestConfiguration
+{
+public:
+ CatchConfiguration(ITestFramework *framework) : DebuggableTestConfiguration(framework) {}
+ TestOutputReader *outputReader(const QFutureInterface<TestResultPtr> &fi,
+ QProcess *app) const override;
+ QStringList argumentsForTestRunner(QStringList *omitted = nullptr) const override;
+ Utils::Environment filteredEnvironment(const Utils::Environment &original) const override;
+};
+
+} // namespace Internal
+} // namespace Autotest
diff --git a/src/plugins/autotest/catch/catchframework.cpp b/src/plugins/autotest/catch/catchframework.cpp
new file mode 100644
index 0000000000..9ccff39cbe
--- /dev/null
+++ b/src/plugins/autotest/catch/catchframework.cpp
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Jochen Seemann
+**
+** 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 "catchframework.h"
+
+#include "catchtestparser.h"
+#include "catchtreeitem.h"
+
+namespace Autotest {
+namespace Internal {
+
+const char *CatchFramework::name() const
+{
+ return "Catch";
+}
+
+unsigned CatchFramework::priority() const
+{
+ return 12;
+}
+
+ITestParser *CatchFramework::createTestParser()
+{
+ return new CatchTestParser(this);
+}
+
+TestTreeItem *CatchFramework::createRootNode()
+{
+ return new CatchTreeItem(this,
+ QCoreApplication::translate("CatchFramework", "Catch Test"),
+ QString(), TestTreeItem::Root);
+}
+
+} // namespace Internal
+} // namespace Autotest
diff --git a/src/plugins/autotest/catch/catchframework.h b/src/plugins/autotest/catch/catchframework.h
new file mode 100644
index 0000000000..178f5ebc14
--- /dev/null
+++ b/src/plugins/autotest/catch/catchframework.h
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Jochen Seemann
+**
+** 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 "../itestframework.h"
+
+#include "catchtestsettings.h"
+#include "catchtestsettingspage.h"
+
+namespace Autotest {
+namespace Internal {
+
+class CatchFramework : public ITestFramework
+{
+public:
+ CatchFramework() : ITestFramework(true) {}
+
+ const char *name() const override;
+ unsigned priority() const override;
+
+protected:
+ ITestParser *createTestParser() override;
+ TestTreeItem *createRootNode() override;
+
+private:
+ IFrameworkSettings * frameworkSettings() override { return &m_settings; }
+ CatchTestSettings m_settings;
+ CatchTestSettingsPage m_settingsPage{&m_settings, settingsId()};
+};
+
+} // namespace Internal
+} // namespace Autotest
diff --git a/src/plugins/autotest/catch/catchoutputreader.cpp b/src/plugins/autotest/catch/catchoutputreader.cpp
new file mode 100644
index 0000000000..68d4f0b260
--- /dev/null
+++ b/src/plugins/autotest/catch/catchoutputreader.cpp
@@ -0,0 +1,323 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Jochen Seemann
+**
+** 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 "catchoutputreader.h"
+#include "catchresult.h"
+
+#include "../testtreeitem.h"
+
+#include <utils/qtcassert.h>
+
+#include <QFileInfo>
+
+namespace Autotest {
+namespace Internal {
+
+namespace CatchXml {
+ const char GroupElement[] = "Group";
+ const char TestCaseElement[] = "TestCase";
+ const char SectionElement[] = "Section";
+ const char ExpressionElement[] = "Expression";
+ const char ExpandedElement[] = "Expanded";
+ const char BenchmarkResults[] = "BenchmarkResults";
+ const char MeanElement[] = "mean";
+ const char StandardDevElement[] = "standardDeviation";
+ const char SectionResultElement[] = "OverallResults";
+ const char TestCaseResultElement[] = "OverallResult";
+}
+
+CatchOutputReader::CatchOutputReader(const QFutureInterface<TestResultPtr> &futureInterface,
+ QProcess *testApplication, const QString &buildDirectory,
+ const QString &projectFile)
+ : TestOutputReader (futureInterface, testApplication, buildDirectory)
+ , m_projectFile(projectFile)
+{
+}
+
+void CatchOutputReader::processOutputLine(const QByteArray &outputLineWithNewLine)
+{
+ if (outputLineWithNewLine.trimmed().isEmpty())
+ return;
+
+ m_xmlReader.addData(QString::fromUtf8(outputLineWithNewLine));
+ while (!m_xmlReader.atEnd()) {
+ QXmlStreamReader::TokenType token = m_xmlReader.readNext();
+
+ switch (token) {
+ case QXmlStreamReader::StartDocument:
+ break;
+ case QXmlStreamReader::EndDocument:
+ m_xmlReader.clear();
+ break;
+ case QXmlStreamReader::StartElement: {
+ m_currentTagName = m_xmlReader.name().toString();
+
+ if (m_currentTagName == CatchXml::GroupElement) {
+ testOutputNodeStarted(GroupNode);
+ } else if (m_currentTagName == CatchXml::TestCaseElement) {
+ m_reportedResult = false;
+ testOutputNodeStarted(TestCaseNode);
+ recordTestInformation(m_xmlReader.attributes());
+ sendResult(ResultType::TestStart);
+ } else if (m_currentTagName == CatchXml::SectionElement) {
+ testOutputNodeStarted(SectionNode);
+ recordTestInformation(m_xmlReader.attributes());
+ sendResult(ResultType::TestStart);
+ } else if (m_currentTagName == CatchXml::TestCaseResultElement) {
+ if (m_currentTestNode == OverallNode || m_currentTestNode == GroupNode)
+ continue;
+ if (m_reportedResult)
+ continue;
+ if (m_xmlReader.attributes().value("success").toString() == QStringLiteral("true"))
+ sendResult(ResultType::Pass);
+ else if (m_shouldFail)
+ sendResult(ResultType::UnexpectedPass);
+ } else if (m_currentTagName == CatchXml::SectionResultElement) {
+ const QXmlStreamAttributes attributes = m_xmlReader.attributes();
+ if (m_currentTestNode == OverallNode) { // the final results for the executable
+ int passes = attributes.value("successes").toInt();
+ int fails = attributes.value("failures").toInt();
+ int xfails = attributes.value("expectedFailures").toInt();
+ m_summary[ResultType::Pass] = passes - m_xpassCount;
+ m_summary[ResultType::Fail] = fails;
+ if (xfails)
+ m_summary[ResultType::ExpectedFail] = xfails;
+ if (m_xpassCount)
+ m_summary[ResultType::UnexpectedPass] = m_xpassCount;
+ }
+ if (m_currentTestNode == OverallNode || m_currentTestNode == GroupNode)
+ continue;
+ if (attributes.value("failures").toInt() == 0)
+ if (!m_reportedSectionResult)
+ sendResult(ResultType::Pass);
+ } else if (m_currentTagName == CatchXml::ExpressionElement) {
+ recordTestInformation(m_xmlReader.attributes());
+ if (m_xmlReader.attributes().value("success").toString() == QStringLiteral("true"))
+ m_currentResult = m_shouldFail ? ResultType::UnexpectedPass : ResultType::Pass;
+ else
+ m_currentResult = m_mayFail || m_shouldFail ? ResultType::ExpectedFail : ResultType::Fail;
+ } else if (m_currentTagName == CatchXml::BenchmarkResults) {
+ recordBenchmarkInformation(m_xmlReader.attributes());
+ m_currentResult = ResultType::Benchmark;
+ } else if (m_currentTagName == CatchXml::MeanElement) {
+ recordBenchmarkDetails(m_xmlReader.attributes(), {{{"mean"}, {"value"}},
+ {{"low mean"}, {"lowerBound"}},
+ {{"high mean"}, {"upperBound"}}});
+ } else if (m_currentTagName == CatchXml::StandardDevElement) {
+ recordBenchmarkDetails(m_xmlReader.attributes(), {
+ {{"standard deviation"}, {"value"}},
+ {{"low std dev"}, {"lowerBound"}},
+ {{"high std dev"}, {"upperBound"}}});
+ }
+ break;
+ }
+ case QXmlStreamReader::Characters: {
+ const QStringRef text = m_xmlReader.text();
+ if (m_currentTagName == CatchXml::ExpandedElement) {
+ m_currentExpression.append(text);
+ }
+ break;
+ }
+ case QXmlStreamReader::EndElement: {
+ const QStringRef currentTag = m_xmlReader.name();
+
+ if (currentTag == CatchXml::SectionElement) {
+ sendResult(ResultType::TestEnd);
+ testOutputNodeFinished(SectionNode);
+ } else if (currentTag == CatchXml::TestCaseElement) {
+ sendResult(ResultType::TestEnd);
+ testOutputNodeFinished(TestCaseNode);
+ } else if (currentTag == CatchXml::GroupElement) {
+ testOutputNodeFinished(GroupNode);
+ } else if (currentTag == CatchXml::ExpressionElement
+ || currentTag == CatchXml::BenchmarkResults) {
+ sendResult(m_currentResult);
+ m_currentExpression.clear();
+ m_testCaseInfo.pop();
+ }
+ break;
+ }
+ default:
+ // ignore
+ break;
+ }
+ }
+}
+
+TestResultPtr CatchOutputReader::createDefaultResult() const
+{
+ CatchResult *result = nullptr;
+ if (m_testCaseInfo.size() > 0) {
+ result = new CatchResult(id(), m_testCaseInfo.first().name);
+ result->setDescription(m_testCaseInfo.last().name);
+ result->setLine(m_testCaseInfo.last().line);
+ const QString &relativePathFromBuildDir = m_testCaseInfo.last().filename;
+ if (!relativePathFromBuildDir.isEmpty()) {
+ const QFileInfo fileInfo(m_buildDir + '/' + relativePathFromBuildDir);
+ result->setFileName(fileInfo.canonicalFilePath());
+ }
+ } else {
+ result = new CatchResult(id(), QString());
+ }
+ result->setSectionDepth(m_sectionDepth);
+
+ return TestResultPtr(result);
+}
+
+void CatchOutputReader::recordTestInformation(const QXmlStreamAttributes &attributes)
+{
+ QString name;
+ if (attributes.hasAttribute("name")) // successful expressions do not have one
+ name = attributes.value("name").toString();
+ else if (!m_testCaseInfo.isEmpty())
+ name = m_testCaseInfo.top().name;
+
+ m_testCaseInfo.append(TestOutputNode{
+ name,
+ attributes.value("filename").toString(),
+ attributes.value("line").toInt()
+ });
+ if (attributes.hasAttribute("tags")) {
+ const QString tags = attributes.value("tags").toString();
+ m_mayFail = tags.contains("[!mayfail]");
+ m_shouldFail = tags.contains("[!shouldfail]");
+ }
+}
+
+void CatchOutputReader::recordBenchmarkInformation(const QXmlStreamAttributes &attributes)
+{
+ QString name = attributes.value("name").toString();
+ QString fileName;
+ int line = 0;
+ if (!m_testCaseInfo.isEmpty()) {
+ fileName = m_testCaseInfo.top().filename;
+ line = m_testCaseInfo.top().line;
+ }
+ m_testCaseInfo.append(TestOutputNode{name, fileName, line});
+
+ m_currentExpression.append(name);
+ recordBenchmarkDetails(attributes, {{{"samples"}, {"samples"}},
+ {{"iterations"}, {"iterations"}},
+ {{"estimated duration"}, {"estimatedDuration"}}});
+ m_currentExpression.append(" ms"); // ugly
+}
+
+void CatchOutputReader::recordBenchmarkDetails(
+ const QXmlStreamAttributes &attributes,
+ const QList<QPair<QString, QString>> &stringAndAttrNames)
+{
+ m_currentExpression.append('\n');
+ int counter = 0;
+ for (const QPair<QString, QString> &curr : stringAndAttrNames) {
+ m_currentExpression.append(curr.first).append(": ");
+ m_currentExpression.append(attributes.value(curr.second).toString());
+ if (counter < stringAndAttrNames.size() - 1)
+ m_currentExpression.append(", ");
+ ++counter;
+ }
+}
+
+void CatchOutputReader::sendResult(const ResultType result)
+{
+ TestResultPtr catchResult = createDefaultResult();
+ catchResult->setResult(result);
+
+ if (result == ResultType::TestStart && m_testCaseInfo.size() > 0) {
+ catchResult->setDescription(tr("Executing %1 \"%2\"").arg(testOutputNodeToString().toLower())
+ .arg(catchResult->description()));
+ } else if (result == ResultType::Pass || result == ResultType::UnexpectedPass) {
+ if (result == ResultType::UnexpectedPass)
+ ++m_xpassCount;
+
+ if (m_currentExpression.isEmpty()) {
+ catchResult->setDescription(tr("%1 \"%2\" passed").arg(testOutputNodeToString())
+ .arg(catchResult->description()));
+ } else {
+ catchResult->setDescription(tr("Expression passed")
+ .append('\n').append(m_currentExpression));
+ }
+ m_reportedSectionResult = true;
+ m_reportedResult = true;
+ } else if (result == ResultType::Fail || result == ResultType::ExpectedFail) {
+ catchResult->setDescription(tr("Expression failed: %1").arg(m_currentExpression.trimmed()));
+ if (!m_reportedSectionResult)
+ m_reportedSectionResult = true;
+ m_reportedResult = true;
+ } else if (result == ResultType::TestEnd) {
+ catchResult->setDescription(tr("Finished executing %1 \"%2\"").arg(testOutputNodeToString().toLower())
+ .arg(catchResult->description()));
+ } else if (result == ResultType::Benchmark) {
+ catchResult->setDescription(m_currentExpression);
+ }
+
+ reportResult(catchResult);
+}
+
+void CatchOutputReader::testOutputNodeStarted(CatchOutputReader::TestOutputNodeType type)
+{
+ m_currentTestNode = type;
+ if (type == SectionNode) {
+ ++m_sectionDepth;
+ m_reportedSectionResult = false;
+ }
+}
+
+void CatchOutputReader::testOutputNodeFinished(CatchOutputReader::TestOutputNodeType type)
+{
+ switch (type) {
+ case GroupNode:
+ m_currentTestNode = OverallNode;
+ return;
+ case TestCaseNode:
+ m_currentTestNode = GroupNode;
+ m_testCaseInfo.pop();
+ return;
+ case SectionNode:
+ --m_sectionDepth;
+ m_testCaseInfo.pop();
+ m_currentTestNode = m_sectionDepth == 0 ? TestCaseNode : SectionNode;
+ return;
+ default:
+ return;
+ }
+}
+
+QString CatchOutputReader::testOutputNodeToString() const
+{
+ switch (m_currentTestNode) {
+ case OverallNode:
+ return QStringLiteral("Overall");
+ case GroupNode:
+ return QStringLiteral("Group");
+ case TestCaseNode:
+ return QStringLiteral("Test case");
+ case SectionNode:
+ return QStringLiteral("Section");
+ }
+
+ return QString();
+}
+
+} // namespace Internal
+} // namespace Autotest
diff --git a/src/plugins/autotest/catch/catchoutputreader.h b/src/plugins/autotest/catch/catchoutputreader.h
new file mode 100644
index 0000000000..86f016478b
--- /dev/null
+++ b/src/plugins/autotest/catch/catchoutputreader.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Jochen Seemann
+**
+** 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 "../testoutputreader.h"
+
+#include <QCoreApplication>
+#include <QStack>
+#include <QXmlStreamReader>
+
+namespace Autotest {
+namespace Internal {
+
+class CatchOutputReader : public TestOutputReader
+{
+ Q_DECLARE_TR_FUNCTIONS(Autotest::Internal::CatchOutputReader)
+
+public:
+ CatchOutputReader(const QFutureInterface<TestResultPtr> &futureInterface,
+ QProcess *testApplication, const QString &buildDirectory,
+ const QString &projectFile);
+
+protected:
+ void processOutputLine(const QByteArray &outputLineWithNewLine) override;
+ TestResultPtr createDefaultResult() const override;
+
+private:
+ enum TestOutputNodeType {
+ OverallNode,
+ GroupNode,
+ TestCaseNode,
+ SectionNode
+ } m_currentTestNode = OverallNode;
+
+ struct TestOutputNode {
+ QString name;
+ QString filename;
+ int line;
+ };
+
+ void recordTestInformation(const QXmlStreamAttributes &attributes);
+ void recordBenchmarkInformation(const QXmlStreamAttributes &attributes);
+ void recordBenchmarkDetails(const QXmlStreamAttributes &attributes,
+ const QList<QPair<QString, QString>> &stringAndAttrNames);
+ void sendResult(const ResultType result);
+
+ void testOutputNodeStarted(TestOutputNodeType type);
+ void testOutputNodeFinished(TestOutputNodeType type);
+
+ QString testOutputNodeToString() const;
+
+ QStack<TestOutputNode> m_testCaseInfo;
+ int m_sectionDepth = 0;
+
+ QString m_projectFile;
+ QString m_currentTagName;
+ QString m_currentExpression;
+ QXmlStreamReader m_xmlReader;
+ ResultType m_currentResult = ResultType::Invalid;
+ int m_xpassCount = 0;
+ bool m_mayFail = false;
+ bool m_shouldFail = false;
+ bool m_reportedResult = false;
+ bool m_reportedSectionResult = false;
+};
+
+} // namespace Internal
+} // namespace Autotest
diff --git a/src/plugins/autotest/catch/catchresult.cpp b/src/plugins/autotest/catch/catchresult.cpp
new file mode 100644
index 0000000000..12b701af5d
--- /dev/null
+++ b/src/plugins/autotest/catch/catchresult.cpp
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Jochen Seemann
+**
+** 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 "catchresult.h"
+
+namespace Autotest {
+namespace Internal {
+
+CatchResult::CatchResult(const QString &id, const QString &name)
+ : TestResult(id, name)
+{
+}
+
+bool CatchResult::isDirectParentOf(const TestResult *other, bool *needsIntermediate) const
+{
+ if (!TestResult::isDirectParentOf(other, needsIntermediate))
+ return false;
+ const CatchResult *catchOther = static_cast<const CatchResult *>(other);
+
+ if (result() != ResultType::TestStart)
+ return false;
+
+ if (catchOther->result() == ResultType::TestStart) {
+ if (fileName() != catchOther->fileName())
+ return false;
+
+ return sectionDepth() + 1 == catchOther->sectionDepth();
+ }
+
+ if (sectionDepth() <= catchOther->sectionDepth() && catchOther->result() == ResultType::Pass)
+ return true;
+
+ if (fileName() != catchOther->fileName() || sectionDepth() > catchOther->sectionDepth())
+ return false;
+
+ return name() == catchOther->name();
+}
+
+} // namespace Internal
+} // namespace Autotest
diff --git a/src/plugins/autotest/catch/catchresult.h b/src/plugins/autotest/catch/catchresult.h
new file mode 100644
index 0000000000..65e996f84b
--- /dev/null
+++ b/src/plugins/autotest/catch/catchresult.h
@@ -0,0 +1,47 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Jochen Seemann
+**
+** 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 "../testresult.h"
+
+namespace Autotest {
+namespace Internal {
+
+class CatchResult : public TestResult
+{
+public:
+ CatchResult(const QString &id, const QString &name);
+
+ bool isDirectParentOf(const TestResult *other, bool *needsIntermediate) const override;
+
+ void setSectionDepth(int depth) { m_sectionDepth = depth; }
+ int sectionDepth() const { return m_sectionDepth; }
+
+private:
+ int m_sectionDepth = 0;
+};
+
+} // namespace Internal
+} // namespace Autotest
diff --git a/src/plugins/autotest/catch/catchtestparser.cpp b/src/plugins/autotest/catch/catchtestparser.cpp
new file mode 100644
index 0000000000..7e6d10630b
--- /dev/null
+++ b/src/plugins/autotest/catch/catchtestparser.cpp
@@ -0,0 +1,168 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Jochen Seemann
+**
+** 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 "catchtestparser.h"
+
+#include "catchcodeparser.h"
+#include "catchtreeitem.h"
+
+#include <cpptools/cppmodelmanager.h>
+#include <cpptools/projectpart.h>
+#include <utils/qtcassert.h>
+
+#include <QRegularExpression>
+
+namespace Autotest {
+namespace Internal {
+
+static bool isCatchTestCaseMacro(const QString &macroName)
+{
+ const QStringList validTestCaseMacros = {
+ QStringLiteral("TEST_CASE"), QStringLiteral("SCENARIO"),
+ QStringLiteral("TEMPLATE_TEST_CASE"), QStringLiteral("TEMPLATE_PRODUCT_TEST_CASE"),
+ QStringLiteral("TEMPLATE_LIST_TEST_CASE"),
+ QStringLiteral("TEMPLATE_TEST_CASE_SIG"), QStringLiteral("TEMPLATE_PRODUCT_TEST_CASE_SIG"),
+ QStringLiteral("TEST_CASE_METHOD"), QStringLiteral("TEMPLATE_TEST_CASE_METHOD"),
+ QStringLiteral("TEMPLATE_PRODUCT_TEST_CASE_METHOD"),
+ QStringLiteral("TEST_CASE_METHOD"), QStringLiteral("TEMPLATE_TEST_CASE_METHOD_SIG"),
+ QStringLiteral("TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG"),
+ QStringLiteral("TEMPLATE_TEST_CASE_METHOD"),
+ QStringLiteral("TEMPLATE_LIST_TEST_CASE_METHOD"),
+ QStringLiteral("METHOD_AS_TEST_CASE"), QStringLiteral("REGISTER_TEST_CASE")
+ };
+ return validTestCaseMacros.contains(macroName);
+}
+
+static bool isCatchMacro(const QString &macroName)
+{
+ const QStringList validSectionMacros = {
+ QStringLiteral("SECTION"), QStringLiteral("WHEN")
+ };
+ return isCatchTestCaseMacro(macroName) || validSectionMacros.contains(macroName);
+}
+
+static bool includesCatchHeader(const CPlusPlus::Document::Ptr &doc,
+ const CPlusPlus::Snapshot &snapshot)
+{
+ static const QString catchHeader("catch.hpp");
+ for (const CPlusPlus::Document::Include &inc : doc->resolvedIncludes()) {
+ if (inc.resolvedFileName().endsWith(catchHeader))
+ return true;
+ }
+
+ for (const QString &include : snapshot.allIncludesForDocument(doc->fileName())) {
+ if (include.endsWith(catchHeader))
+ return true;
+ }
+
+ return false;
+}
+
+static bool hasCatchNames(const CPlusPlus::Document::Ptr &document)
+{
+ for (const CPlusPlus::Document::MacroUse &macro : document->macroUses()) {
+ if (!macro.isFunctionLike())
+ continue;
+
+ if (isCatchMacro(QLatin1String(macro.macro().name()))) {
+ const QVector<CPlusPlus::Document::Block> args = macro.arguments();
+ if (args.size() < 1)
+ continue;
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool handleCatchDocument(QFutureInterface<TestParseResultPtr> futureInterface,
+ const CPlusPlus::Document::Ptr &doc,
+ ITestFramework *framework)
+{
+ const CppTools::CppModelManager *modelManager = CppTools::CppModelManager::instance();
+ const QString &filePath = doc->fileName();
+ const QByteArray &fileContent = CppParser::getFileContent(filePath);
+
+ const QList<CppTools::ProjectPart::Ptr> projectParts = modelManager->projectPart(filePath);
+ if (projectParts.isEmpty()) // happens if shutting down while parsing
+ return false;
+ QString proFile;
+ const CppTools::ProjectPart::Ptr projectPart = projectParts.first();
+ proFile = projectPart->projectFile;
+
+ CatchCodeParser codeParser(fileContent, projectPart->languageFeatures);
+ const CatchTestCodeLocationList foundTests = codeParser.findTests();
+
+ CatchParseResult *parseResult = new CatchParseResult(framework);
+ parseResult->itemType = TestTreeItem::TestSuite;
+ parseResult->fileName = filePath;
+ parseResult->name = filePath;
+ parseResult->displayName = filePath;
+ parseResult->proFile = projectParts.first()->projectFile;
+
+ for (const CatchTestCodeLocationAndType & testLocation : foundTests) {
+ CatchParseResult *testCase = new CatchParseResult(framework);
+ testCase->fileName = filePath;
+ testCase->name = testLocation.m_name;
+ testCase->proFile = proFile;
+ testCase->itemType = testLocation.m_type;
+ testCase->line = testLocation.m_line;
+ testCase->column = testLocation.m_column;
+ testCase->states = testLocation.states;
+
+ parseResult->children.append(testCase);
+ }
+
+ futureInterface.reportResult(TestParseResultPtr(parseResult));
+
+ return !foundTests.isEmpty();
+}
+
+bool CatchTestParser::processDocument(QFutureInterface<TestParseResultPtr> futureInterface, const QString &fileName)
+{
+ CPlusPlus::Document::Ptr doc = document(fileName);
+ if (doc.isNull() || !includesCatchHeader(doc, m_cppSnapshot) || !hasCatchNames(doc))
+ return false;
+
+ return handleCatchDocument(futureInterface, doc, framework());
+}
+
+TestTreeItem *CatchParseResult::createTestTreeItem() const
+{
+ if (itemType == TestTreeItem::Root)
+ return nullptr;
+
+ CatchTreeItem *item = new CatchTreeItem(framework, name, fileName, itemType);
+ item->setProFile(proFile);
+ item->setLine(line);
+ item->setColumn(column);
+ item->setStates(states);
+
+ for (const TestParseResult *testSet : children)
+ item->appendChild(testSet->createTestTreeItem());
+
+ return item;
+}
+
+} // namespace Internal
+} // namespace Autotest
diff --git a/src/plugins/autotest/catch/catchtestparser.h b/src/plugins/autotest/catch/catchtestparser.h
new file mode 100644
index 0000000000..4c558aa637
--- /dev/null
+++ b/src/plugins/autotest/catch/catchtestparser.h
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Jochen Seemann
+**
+** 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 "catchtreeitem.h"
+#include "../itestparser.h"
+
+namespace Autotest {
+namespace Internal {
+
+class CatchParseResult : public TestParseResult
+{
+public:
+ explicit CatchParseResult(ITestFramework *framework)
+ : TestParseResult(framework) {}
+ TestTreeItem *createTestTreeItem() const override;
+ CatchTreeItem::TestStates states;
+};
+
+class CatchTestParser : public CppParser
+{
+public:
+ CatchTestParser(ITestFramework *framework)
+ : CppParser(framework) {}
+ bool processDocument(QFutureInterface<TestParseResultPtr> futureInterface,
+ const QString &fileName) override;
+};
+
+} // namespace Internal
+} // namespace Autotest
diff --git a/src/plugins/autotest/catch/catchtestsettings.cpp b/src/plugins/autotest/catch/catchtestsettings.cpp
new file mode 100644
index 0000000000..276a54985b
--- /dev/null
+++ b/src/plugins/autotest/catch/catchtestsettings.cpp
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** 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 "catchtestsettings.h"
+
+namespace Autotest {
+namespace Internal {
+
+static const char abortAfterKey[] = "AbortAfter";
+static const char abortAfterCheckedKey[] = "AbortChecked";
+static const char benchmarkSamplesKey[] = "BenchSamples";
+static const char samplesCheckedKey[] = "SamplesChecked";
+static const char benchmarkResamplesKey[] = "BenchResamples";
+static const char resamplesCheckedKey[] = "ResamplesChecked";
+static const char benchmarConfidenceIntervalKey[] = "BenchConfInt";
+static const char confIntCheckedKey[] = "ConfIntChecked";
+static const char benchmarWarmupTimeKey[] = "BenchWarmup";
+static const char warmupCheckedKey[] = "WarmupChecked";
+static const char noAnalysisKey[] = "NoAnalysis";
+static const char showSuccessKey[] = "ShowSuccess";
+static const char breakOnFailureKey[] = "BreakOnFailure";
+static const char noThrowKey[] = "NoThrow";
+static const char visibleWhitespaceKey[] = "VisibleWS";
+static const char warnOnEmptyKey[] = "WarnEmpty";
+
+QString CatchTestSettings::name() const
+{
+ return QString("Catch2");
+}
+
+void CatchTestSettings::toFrameworkSettings(QSettings *s) const
+{
+ s->setValue(abortAfterCheckedKey, abortAfterChecked);
+ s->setValue(abortAfterKey, abortAfter);
+ s->setValue(samplesCheckedKey, samplesChecked);
+ s->setValue(benchmarkSamplesKey, benchmarkSamples);
+ s->setValue(resamplesCheckedKey, resamplesChecked);
+ s->setValue(benchmarkResamplesKey, benchmarkResamples);
+ s->setValue(confIntCheckedKey, confidenceIntervalChecked);
+ s->setValue(benchmarConfidenceIntervalKey, confidenceInterval);
+ s->setValue(warmupCheckedKey, warmupChecked);
+ s->setValue(benchmarWarmupTimeKey, benchmarkWarmupTime);
+ s->setValue(noAnalysisKey, noAnalysis);
+ s->setValue(showSuccessKey, showSuccess);
+ s->setValue(breakOnFailureKey, breakOnFailure);
+ s->setValue(noThrowKey, noThrow);
+ s->setValue(visibleWhitespaceKey, visibleWhitespace);
+ s->setValue(warnOnEmptyKey, warnOnEmpty);
+}
+
+void CatchTestSettings::fromFrameworkSettings(const QSettings *s)
+{
+ abortAfterChecked = s->value(abortAfterCheckedKey, false).toBool();
+ abortAfter = s->value(abortAfterKey, 0).toInt();
+ samplesChecked = s->value(samplesCheckedKey, false).toBool();
+ benchmarkSamples = s->value(benchmarkSamplesKey, 100).toInt();
+ resamplesChecked = s->value(resamplesCheckedKey, false).toBool();
+ benchmarkResamples = s->value(benchmarkResamplesKey, 100000).toInt();
+ confidenceIntervalChecked = s->value(confIntCheckedKey, false).toBool();
+ confidenceInterval = s->value(benchmarConfidenceIntervalKey, 0.95).toDouble();
+ warmupChecked = s->value(warmupCheckedKey, false).toBool();
+ benchmarkWarmupTime = s->value(benchmarWarmupTimeKey, 0).toInt();
+ noAnalysis = s->value(noAnalysisKey, false).toBool();
+ showSuccess = s->value(showSuccessKey, false).toBool();
+ breakOnFailure = s->value(breakOnFailureKey, true).toBool();
+ noThrow = s->value(noThrowKey, false).toBool();
+ visibleWhitespace = s->value(visibleWhitespaceKey, false).toBool();
+ warnOnEmpty = s->value(warnOnEmptyKey, false).toBool();
+}
+
+} // namespace Internal
+} // namespace Autotest
diff --git a/src/plugins/cmakeprojectmanager/builddirreader.cpp b/src/plugins/autotest/catch/catchtestsettings.h
index ca808d36fd..71c8d9eea5 100644
--- a/src/plugins/cmakeprojectmanager/builddirreader.cpp
+++ b/src/plugins/autotest/catch/catchtestsettings.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -23,37 +23,40 @@
**
****************************************************************************/
-#include "builddirreader.h"
+#pragma once
-#include "fileapireader.h"
-#include "servermodereader.h"
-#include "tealeafreader.h"
+#include "../iframeworksettings.h"
-#include <utils/qtcassert.h>
-
-using namespace ProjectExplorer;
-
-namespace CMakeProjectManager {
+namespace Autotest {
namespace Internal {
-// --------------------------------------------------------------------
-// BuildDirReader:
-// --------------------------------------------------------------------
-
-std::unique_ptr<BuildDirReader> BuildDirReader::createReader(const BuildDirParameters &p)
+class CatchTestSettings : public IFrameworkSettings
{
- CMakeTool *cmake = p.cmakeTool();
- QTC_ASSERT(p.isValid() && cmake, return {});
-
- switch (cmake->readerType()) {
- case CMakeTool::FileApi:
- return std::make_unique<FileApiReader>();
- case CMakeTool::ServerMode:
- return std::make_unique<ServerModeReader>();
- default:
- return std::make_unique<TeaLeafReader>();
- }
-}
+public:
+ CatchTestSettings() = default;
+ QString name() const override;
+
+ int abortAfter = 0;
+ int benchmarkSamples = 0;
+ int benchmarkResamples = 0;
+ double confidenceInterval = 0;
+ int benchmarkWarmupTime = 0;
+ bool abortAfterChecked = false;
+ bool samplesChecked = false;
+ bool resamplesChecked = false;
+ bool confidenceIntervalChecked = false;
+ bool warmupChecked = false;
+ bool noAnalysis = false;
+ bool showSuccess = false;
+ bool breakOnFailure = true;
+ bool noThrow = false;
+ bool visibleWhitespace = false;
+ bool warnOnEmpty = false;
+
+protected:
+ void toFrameworkSettings(QSettings *s) const override;
+ void fromFrameworkSettings(const QSettings *s) override;
+};
} // namespace Internal
-} // namespace CMakeProjectManager
+} // namespace Autotest
diff --git a/src/plugins/autotest/catch/catchtestsettingspage.cpp b/src/plugins/autotest/catch/catchtestsettingspage.cpp
new file mode 100644
index 0000000000..8c54dbe8c8
--- /dev/null
+++ b/src/plugins/autotest/catch/catchtestsettingspage.cpp
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** 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 "catchtestsettingspage.h"
+#include "catchtestsettings.h"
+#include "ui_catchtestsettingspage.h"
+#include "../autotestconstants.h"
+
+#include <coreplugin/icore.h>
+
+namespace Autotest {
+namespace Internal {
+
+class CatchTestSettingsWidget final : public Core::IOptionsPageWidget
+{
+ Q_DECLARE_TR_FUNCTIONS(Autotest::Internal::CatchTestSettingsWidget)
+public:
+ explicit CatchTestSettingsWidget(CatchTestSettings *settings);
+ void apply() override;
+private:
+ Ui::CatchTestSettingsPage m_ui;
+ CatchTestSettings *m_settings;
+};
+
+CatchTestSettingsWidget::CatchTestSettingsWidget(CatchTestSettings *settings)
+ : m_settings(settings)
+{
+ m_ui.setupUi(this);
+
+ m_ui.abortSB->setEnabled(m_settings->abortAfterChecked);
+ m_ui.samplesSB->setEnabled(m_settings->samplesChecked),
+ m_ui.resamplesSB->setEnabled(m_settings->resamplesChecked);
+ m_ui.confIntSB->setEnabled(m_settings->confidenceIntervalChecked);
+ m_ui.warmupSB->setEnabled(m_settings->warmupChecked);
+
+ connect(m_ui.abortCB, &QCheckBox::toggled, m_ui.abortSB, &QSpinBox::setEnabled);
+ connect(m_ui.samplesCB, &QCheckBox::toggled, m_ui.samplesSB, &QSpinBox::setEnabled);
+ connect(m_ui.resamplesCB, &QCheckBox::toggled, m_ui.resamplesSB, &QSpinBox::setEnabled);
+ connect(m_ui.confIntCB, &QCheckBox::toggled, m_ui.confIntSB, &QDoubleSpinBox::setEnabled);
+ connect(m_ui.warmupCB, &QCheckBox::toggled, m_ui.warmupSB, &QSpinBox::setEnabled);
+
+ m_ui.showSuccessCB->setChecked(m_settings->showSuccess);
+ m_ui.breakOnFailCB->setChecked(m_settings->breakOnFailure);
+ m_ui.noThrowCB->setChecked(m_settings->noThrow);
+ m_ui.visibleWhiteCB->setChecked(m_settings->visibleWhitespace);
+ m_ui.warnOnEmpty->setChecked(m_settings->warnOnEmpty);
+ m_ui.noAnalysisCB->setChecked(m_settings->noAnalysis);
+ m_ui.abortCB->setChecked(m_settings->abortAfterChecked);
+ m_ui.abortSB->setValue(m_settings->abortAfter);
+ m_ui.samplesCB->setChecked(m_settings->samplesChecked);
+ m_ui.samplesSB->setValue(m_settings->benchmarkSamples);
+ m_ui.resamplesCB->setChecked(m_settings->resamplesChecked);
+ m_ui.resamplesSB->setValue(m_settings->benchmarkResamples);
+ m_ui.confIntCB->setChecked(m_settings->confidenceIntervalChecked);
+ m_ui.confIntSB->setValue(m_settings->confidenceInterval);
+ m_ui.warmupCB->setChecked(m_settings->warmupChecked);
+ m_ui.warmupSB->setValue(m_settings->benchmarkWarmupTime);
+}
+
+void CatchTestSettingsWidget::apply()
+{
+ m_settings->showSuccess = m_ui.showSuccessCB->isChecked();
+ m_settings->breakOnFailure = m_ui.breakOnFailCB->isChecked();
+ m_settings->noThrow = m_ui.noThrowCB->isChecked();
+ m_settings->visibleWhitespace = m_ui.visibleWhiteCB->isChecked();
+ m_settings->warnOnEmpty = m_ui.warnOnEmpty->isChecked();
+ m_settings->noAnalysis = m_ui.noAnalysisCB->isChecked();
+ m_settings->abortAfterChecked = m_ui.abortCB->isChecked();
+ m_settings->abortAfter = m_ui.abortSB->value();
+ m_settings->samplesChecked = m_ui.samplesCB->isChecked();
+ m_settings->benchmarkSamples = m_ui.samplesSB->value();
+ m_settings->resamplesChecked = m_ui.resamplesCB->isChecked();
+ m_settings->benchmarkResamples = m_ui.resamplesSB->value();
+ m_settings->confidenceIntervalChecked = m_ui.confIntCB->isChecked();
+ m_settings->confidenceInterval = m_ui.confIntSB->value();
+ m_settings->warmupChecked = m_ui.warmupCB->isChecked();
+ m_settings->benchmarkWarmupTime = m_ui.warmupSB->value();
+
+ m_settings->toSettings(Core::ICore::settings());
+}
+
+CatchTestSettingsPage::CatchTestSettingsPage(CatchTestSettings *settings, Core::Id settingsId)
+{
+ setId(settingsId);
+ setCategory(Constants::AUTOTEST_SETTINGS_CATEGORY);
+ setDisplayName(QCoreApplication::translate("CatchTestFramework", "Catch Test"));
+ setWidgetCreator([settings] { return new CatchTestSettingsWidget(settings); });
+}
+
+} // namespace Internal
+} // namespace Autotest
diff --git a/src/plugins/boot2qt/qdbdeploystepfactory.h b/src/plugins/autotest/catch/catchtestsettingspage.h
index fada4a8478..1c659c7f10 100644
--- a/src/plugins/boot2qt/qdbdeploystepfactory.h
+++ b/src/plugins/autotest/catch/catchtestsettingspage.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2019 The Qt Company Ltd.
+** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -25,22 +25,18 @@
#pragma once
-#include <projectexplorer/buildstep.h>
+#include <coreplugin/dialogs/ioptionspage.h>
-namespace Qdb {
+namespace Autotest {
namespace Internal {
-class QdbMakeDefaultAppStepFactory : public ProjectExplorer::BuildStepFactory
-{
-public:
- QdbMakeDefaultAppStepFactory();
-};
+class CatchTestSettings;
-class QdbStopApplicationStepFactory : public ProjectExplorer::BuildStepFactory
+class CatchTestSettingsPage : public Core::IOptionsPage
{
public:
- QdbStopApplicationStepFactory();
+ CatchTestSettingsPage(CatchTestSettings *settings, Core::Id settingsId);
};
} // namespace Internal
-} // namespace Qdb
+} // namespace Autotest
diff --git a/src/plugins/autotest/catch/catchtestsettingspage.ui b/src/plugins/autotest/catch/catchtestsettingspage.ui
new file mode 100644
index 0000000000..aaa3ea26dd
--- /dev/null
+++ b/src/plugins/autotest/catch/catchtestsettingspage.ui
@@ -0,0 +1,306 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>CatchTestSettingsPage</class>
+ <widget class="QWidget" name="CatchTestSettingsPage">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>314</width>
+ <height>323</height>
+ </rect>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QCheckBox" name="showSuccessCB">
+ <property name="toolTip">
+ <string>Show success for tests.</string>
+ </property>
+ <property name="text">
+ <string>Show success</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="breakOnFailCB">
+ <property name="toolTip">
+ <string>Turns failures into debugger breakpoints.</string>
+ </property>
+ <property name="text">
+ <string>Break on failure while debugging</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="noThrowCB">
+ <property name="toolTip">
+ <string>Skips all assertions that test for thrown exceptions.</string>
+ </property>
+ <property name="text">
+ <string>Skip throwing assertions</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="visibleWhiteCB">
+ <property name="toolTip">
+ <string>Makes whitespace visible.</string>
+ </property>
+ <property name="text">
+ <string>Visualize whitespace</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="warnOnEmpty">
+ <property name="toolTip">
+ <string>Warns if a test section does not check any assertion.</string>
+ </property>
+ <property name="text">
+ <string>Warn on empty tests</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="abortHL">
+ <item>
+ <widget class="QCheckBox" name="abortCB">
+ <property name="toolTip">
+ <string>Aborts after the specified number of failures.</string>
+ </property>
+ <property name="text">
+ <string>Abort after</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="abortSB">
+ <property name="minimum">
+ <number>1</number>
+ </property>
+ <property name="maximum">
+ <number>9999</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="samplesHL">
+ <item>
+ <widget class="QCheckBox" name="samplesCB">
+ <property name="toolTip">
+ <string>Number of samples to collect while running benchmarks.</string>
+ </property>
+ <property name="text">
+ <string>Benchmark samples</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="samplesSB">
+ <property name="maximum">
+ <number>999999</number>
+ </property>
+ <property name="value">
+ <number>100</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="resamplesHL">
+ <item>
+ <widget class="QCheckBox" name="resamplesCB">
+ <property name="toolTip">
+ <string>Number of resamples used for statistical bootstrapping.</string>
+ </property>
+ <property name="text">
+ <string>Benchmark resamples</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="resamplesSB">
+ <property name="toolTip">
+ <string>Number of resamples for bootstrapping.</string>
+ </property>
+ <property name="maximum">
+ <number>9999999</number>
+ </property>
+ <property name="value">
+ <number>100000</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="confIntHL">
+ <item>
+ <widget class="QCheckBox" name="confIntCB">
+ <property name="toolTip">
+ <string>Confidence interval used for statistical bootstrapping.</string>
+ </property>
+ <property name="text">
+ <string>Benchmark confidence interval</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_4">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QDoubleSpinBox" name="confIntSB">
+ <property name="maximum">
+ <double>1.000000000000000</double>
+ </property>
+ <property name="singleStep">
+ <double>0.050000000000000</double>
+ </property>
+ <property name="value">
+ <double>0.950000000000000</double>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="warmupHL">
+ <item>
+ <widget class="QCheckBox" name="warmupCB">
+ <property name="toolTip">
+ <string>Warmup time for each test.</string>
+ </property>
+ <property name="text">
+ <string>Benchmark warmup time</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_5">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="warmupSB">
+ <property name="suffix">
+ <string> ms</string>
+ </property>
+ <property name="maximum">
+ <number>10000</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="noAnalysisCB">
+ <property name="toolTip">
+ <string>Disables statistical analysis and bootstrapping.</string>
+ </property>
+ <property name="text">
+ <string>Disable analysis</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_6">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/autotest/catch/catchtreeitem.cpp b/src/plugins/autotest/catch/catchtreeitem.cpp
new file mode 100644
index 0000000000..cdd48d8536
--- /dev/null
+++ b/src/plugins/autotest/catch/catchtreeitem.cpp
@@ -0,0 +1,293 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Jochen Seemann
+**
+** 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 "catchtreeitem.h"
+#include "catchtestparser.h"
+#include "catchconfiguration.h"
+#include "catchframework.h"
+
+#include <projectexplorer/session.h>
+#include <utils/qtcassert.h>
+
+namespace Autotest {
+namespace Internal {
+
+QString CatchTreeItem::testCasesString() const
+{
+ return m_state & CatchTreeItem::Parameterized ? QString(name() + " -*") : name();
+}
+
+QVariant CatchTreeItem::data(int column, int role) const
+{
+
+ switch (role) {
+ case Qt::DisplayRole:
+ if (type() == Root)
+ break;
+ return QString(name() + stateSuffix());
+ case Qt::CheckStateRole:
+ switch (type()) {
+ case Root:
+ case GroupNode:
+ case TestSuite:
+ case TestCase:
+ return checked();
+ default:
+ return QVariant();
+ }
+ }
+ return TestTreeItem::data(column, role);
+}
+
+TestTreeItem *CatchTreeItem::copyWithoutChildren()
+{
+ CatchTreeItem *copied = new CatchTreeItem(framework());
+ copied->copyBasicDataFrom(this);
+ return copied;
+}
+
+TestTreeItem *CatchTreeItem::find(const TestParseResult *result)
+{
+ QTC_ASSERT(result, return nullptr);
+
+ switch (type()) {
+ case Root:
+ if (result->framework->grouping()) {
+ const QString path = QFileInfo(result->fileName).absolutePath();
+ for (int row = 0; row < childCount(); ++row) {
+ TestTreeItem *group = childAt(row);
+ if (group->filePath() != path)
+ continue;
+ if (auto groupChild = group->findChildByFile(result->fileName))
+ return groupChild;
+ }
+ return nullptr;
+ }
+ return findChildByFile(result->fileName);
+ case GroupNode:
+ return findChildByFile(result->fileName);
+ case TestSuite:
+ return findChildByNameAndFile(result->name, result->fileName);
+ default:
+ return nullptr;
+ }
+}
+
+TestTreeItem *CatchTreeItem::findChild(const TestTreeItem *other)
+{
+ QTC_ASSERT(other, return nullptr);
+
+ switch (type()) {
+ case Root:
+ return findChildByFileAndType(other->filePath(), other->type());
+ case GroupNode:
+ return other->type() == TestSuite ? findChildByFile(other->filePath()) : nullptr;
+ case TestSuite:
+ return findChildByNameAndFile(other->name(), other->filePath());
+ default:
+ return nullptr;
+ }
+}
+
+bool CatchTreeItem::modify(const TestParseResult *result)
+{
+ QTC_ASSERT(result, return false);
+
+ switch (type()) {
+ case TestSuite:
+ case TestCase:
+ return modifyTestFunctionContent(result);
+ default:
+ return false;
+ }
+}
+
+TestTreeItem *CatchTreeItem::createParentGroupNode() const
+{
+ const QFileInfo fileInfo(filePath());
+ const QFileInfo base(fileInfo.absolutePath());
+ return new CatchTreeItem(framework(), base.baseName(), fileInfo.absolutePath(), TestTreeItem::GroupNode);
+}
+
+bool CatchTreeItem::canProvideTestConfiguration() const
+{
+ return type() == TestCase;
+}
+
+bool CatchTreeItem::canProvideDebugConfiguration() const
+{
+ return canProvideTestConfiguration();
+}
+
+TestConfiguration *CatchTreeItem::testConfiguration() const
+{
+ ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject();
+ QTC_ASSERT(project, return nullptr);
+
+ if (type() != TestCase)
+ return nullptr;
+
+ CatchConfiguration *config = nullptr;
+ config = new CatchConfiguration(framework());
+ config->setTestCaseCount(childCount());
+ config->setProjectFile(proFile());
+ config->setProject(project);
+ config->setTestCases(QStringList(testCasesString()));
+ config->setInternalTargets(internalTargets());
+ return config;
+}
+
+TestConfiguration *CatchTreeItem::debugConfiguration() const
+{
+ CatchConfiguration *config = static_cast<CatchConfiguration *>(testConfiguration());
+ if (config)
+ config->setRunMode(TestRunMode::Debug);
+ return config;
+}
+
+struct CatchTestCases
+{
+ QStringList names;
+ QSet<QString> internalTargets;
+};
+
+static void collectTestInfo(const TestTreeItem *item,
+ QHash<QString, CatchTestCases> &testCasesForProfile,
+ bool ignoreCheckState)
+{
+ QTC_ASSERT(item, return);
+ const int childCount = item->childCount();
+ if (item->type() == TestTreeItem::GroupNode) {
+ item->forFirstLevelChildren([&testCasesForProfile, ignoreCheckState](TestTreeItem *it) {
+ collectTestInfo(it, testCasesForProfile, ignoreCheckState);
+ });
+ return;
+ }
+
+ QTC_ASSERT(childCount != 0, return);
+ QTC_ASSERT(item->type() == TestTreeItem::TestSuite, return);
+ if (ignoreCheckState || item->checked() == Qt::Checked) {
+ const QString &projectFile = item->childAt(0)->proFile();
+ item->forAllChildren([&testCasesForProfile, &projectFile](TestTreeItem *it) {
+ CatchTreeItem *current = static_cast<CatchTreeItem *>(it);
+ testCasesForProfile[projectFile].names.append(current->testCasesString());
+ });
+ testCasesForProfile[projectFile].internalTargets.unite(item->internalTargets());
+ } else if (item->checked() == Qt::PartiallyChecked) {
+ item->forFirstLevelChildren([&testCasesForProfile](TestTreeItem *child) {
+ QTC_ASSERT(child->type() == TestTreeItem::TestCase, return);
+ if (child->checked() == Qt::Checked) {
+ CatchTreeItem *current = static_cast<CatchTreeItem *>(child);
+ testCasesForProfile[child->proFile()].names.append(current->testCasesString());
+ testCasesForProfile[child->proFile()].internalTargets.unite(
+ child->internalTargets());
+ }
+
+ });
+ }
+}
+
+QList<TestConfiguration *> CatchTreeItem::getAllTestConfigurations() const
+{
+ return getTestConfigurations(true);
+}
+
+QList<TestConfiguration *> CatchTreeItem::getSelectedTestConfigurations() const
+{
+ return getTestConfigurations(false);
+}
+
+QList<TestConfiguration *> CatchTreeItem::getTestConfigurationsForFile(const Utils::FilePath &fileName) const
+{
+ QList<TestConfiguration *> result;
+ ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject();
+ if (!project || type() != Root)
+ return result;
+
+ const QString filePath = fileName.toString();
+ for (int row = 0, count = childCount(); row < count; ++row) {
+ const TestTreeItem *item = childAt(row);
+ QTC_ASSERT(item, continue);
+
+ if (childAt(row)->name() != filePath)
+ continue;
+
+ CatchConfiguration *testConfig = nullptr;
+ QStringList testCases;
+
+ item->forFirstLevelChildren([&testCases](TestTreeItem *child) {
+ CatchTreeItem *current = static_cast<CatchTreeItem *>(child);
+ testCases << current->testCasesString();
+ });
+
+ testConfig = new CatchConfiguration(framework());
+ testConfig->setTestCases(testCases);
+ testConfig->setProjectFile(item->proFile());
+ testConfig->setProject(ProjectExplorer::SessionManager::startupProject());
+ testConfig->setInternalTargets(item->internalTargets());
+ result << testConfig;
+ }
+
+ return result;
+}
+
+QString CatchTreeItem::stateSuffix() const
+{
+ QStringList types;
+ if (m_state & CatchTreeItem::Parameterized)
+ types.append(QCoreApplication::translate("CatchTreeItem", "parameterized"));
+ if (m_state & CatchTreeItem::Fixture)
+ types.append(QCoreApplication::translate("CatchTreeItem", "fixture"));
+ return types.isEmpty() ? QString() : QString(" [" + types.join(", ") + ']');
+}
+
+QList<TestConfiguration *> CatchTreeItem::getTestConfigurations(bool ignoreCheckState) const
+{
+ QList<TestConfiguration *> result;
+ ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject();
+ if (!project || type() != Root)
+ return result;
+
+ QHash<QString, CatchTestCases> testCasesForProfile;
+ forFirstLevelChildren([&testCasesForProfile, ignoreCheckState](TestTreeItem *item) {
+ collectTestInfo(item, testCasesForProfile, ignoreCheckState);
+ });
+
+ for (auto it = testCasesForProfile.begin(), end = testCasesForProfile.end(); it != end; ++it) {
+ for (const QString &target : qAsConst(it.value().internalTargets)) {
+ CatchConfiguration *tc = new CatchConfiguration(framework());
+ tc->setTestCases(it.value().names);
+ if (ignoreCheckState)
+ tc->setTestCaseCount(0);
+ tc->setProjectFile(it.key());
+ tc->setProject(project);
+ tc->setInternalTarget(target);
+ result << tc;
+ }
+ }
+ return result;
+}
+
+} // namespace Internal
+} // namespace Autotest
diff --git a/src/plugins/autotest/catch/catchtreeitem.h b/src/plugins/autotest/catch/catchtreeitem.h
new file mode 100644
index 0000000000..b52fc9417d
--- /dev/null
+++ b/src/plugins/autotest/catch/catchtreeitem.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Jochen Seemann
+**
+** 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 "../testtreeitem.h"
+
+namespace Autotest {
+namespace Internal {
+
+class CatchTreeItem : public TestTreeItem
+{
+public:
+ enum TestState
+ {
+ Normal = 0x0,
+ Parameterized = 0x1,
+ Fixture = 0x2
+ };
+ Q_FLAGS(TestState)
+ Q_DECLARE_FLAGS(TestStates, TestState)
+
+ explicit CatchTreeItem(ITestFramework *framework, const QString &name = QString(),
+ const QString &filePath = QString(), Type type = Root)
+ : TestTreeItem(framework, name, filePath, type) {}
+
+ void setStates(CatchTreeItem::TestStates state) { m_state = state; }
+ QString testCasesString() const;
+
+ QVariant data(int column, int role) const override;
+
+ TestTreeItem *copyWithoutChildren() override;
+ TestTreeItem *find(const TestParseResult *result) override;
+ TestTreeItem *findChild(const TestTreeItem *other) override;
+ bool modify(const TestParseResult *result) override;
+ TestTreeItem *createParentGroupNode() const override;
+
+ bool canProvideTestConfiguration() const override;
+ bool canProvideDebugConfiguration() const override;
+ TestConfiguration *testConfiguration() const override;
+ TestConfiguration *debugConfiguration() const override;
+ QList<TestConfiguration *> getAllTestConfigurations() const override;
+ QList<TestConfiguration *> getSelectedTestConfigurations() const override;
+ QList<TestConfiguration *> getTestConfigurationsForFile(const Utils::FilePath &fileName) const override;
+
+private:
+ QString stateSuffix() const;
+ QList<TestConfiguration *> getTestConfigurations(bool ignoreCheckState) const;
+ TestStates m_state = Normal;
+};
+
+class CatchTestCodeLocationAndType : public TestCodeLocationAndType
+{
+public:
+ CatchTreeItem::TestStates states = CatchTreeItem::Normal;
+ QStringList tags; // TODO: use them for the item
+};
+
+typedef QVector<CatchTestCodeLocationAndType> CatchTestCodeLocationList;
+
+} // namespace Internal
+} // namespace Autotest
diff --git a/src/plugins/autotest/gtest/gtestconfiguration.cpp b/src/plugins/autotest/gtest/gtestconfiguration.cpp
index e662f3702f..615ddcd3da 100644
--- a/src/plugins/autotest/gtest/gtestconfiguration.cpp
+++ b/src/plugins/autotest/gtest/gtestconfiguration.cpp
@@ -28,7 +28,7 @@
#include "gtestoutputreader.h"
#include "gtestsettings.h"
#include "../autotestplugin.h"
-#include "../testframeworkmanager.h"
+#include "../itestframework.h"
#include "../testsettings.h"
#include <utils/algorithm.h>
@@ -73,9 +73,6 @@ QStringList filterInterfering(const QStringList &provided, QStringList *omitted)
QStringList GTestConfiguration::argumentsForTestRunner(QStringList *omitted) const
{
- static const Core::Id id
- = Core::Id(Constants::FRAMEWORK_PREFIX).withSuffix(GTest::Constants::FRAMEWORK_NAME);
-
QStringList arguments;
if (AutotestPlugin::settings()->processArgs) {
arguments << filterInterfering(runnable().commandLineArguments.split(
@@ -86,9 +83,8 @@ QStringList GTestConfiguration::argumentsForTestRunner(QStringList *omitted) con
if (!testSets.isEmpty())
arguments << "--gtest_filter=" + testSets.join(':');
- TestFrameworkManager *manager = TestFrameworkManager::instance();
- auto gSettings = qSharedPointerCast<GTestSettings>(manager->settingsForTestFramework(id));
- if (gSettings.isNull())
+ auto gSettings = dynamic_cast<GTestSettings *>(framework()->frameworkSettings());
+ if (!gSettings)
return arguments;
if (gSettings->runDisabled)
diff --git a/src/plugins/autotest/gtest/gtestconfiguration.h b/src/plugins/autotest/gtest/gtestconfiguration.h
index 51f88293ec..822ad99fd1 100644
--- a/src/plugins/autotest/gtest/gtestconfiguration.h
+++ b/src/plugins/autotest/gtest/gtestconfiguration.h
@@ -33,7 +33,9 @@ namespace Internal {
class GTestConfiguration : public DebuggableTestConfiguration
{
public:
- explicit GTestConfiguration() {}
+ explicit GTestConfiguration(ITestFramework *framework)
+ : DebuggableTestConfiguration(framework) {}
+
TestOutputReader *outputReader(const QFutureInterface<TestResultPtr> &fi,
QProcess *app) const override;
QStringList argumentsForTestRunner(QStringList *omitted = nullptr) const override;
diff --git a/src/plugins/autotest/gtest/gtestframework.cpp b/src/plugins/autotest/gtest/gtestframework.cpp
index 7e5ea7b681..c97f209b6c 100644
--- a/src/plugins/autotest/gtest/gtestframework.cpp
+++ b/src/plugins/autotest/gtest/gtestframework.cpp
@@ -24,8 +24,6 @@
****************************************************************************/
#include "gtestframework.h"
-#include "gtestsettings.h"
-#include "gtestsettingspage.h"
#include "gtesttreeitem.h"
#include "gtestparser.h"
#include "../testframeworkmanager.h"
@@ -33,14 +31,23 @@
namespace Autotest {
namespace Internal {
-ITestParser *GTestFramework::createTestParser() const
+static GTestSettings *g_settings;
+
+GTestFramework::GTestFramework()
+ : ITestFramework(true)
+{
+ g_settings = &m_settings;
+}
+
+ITestParser *GTestFramework::createTestParser()
{
- return new GTestParser;
+ return new GTestParser(this);
}
-TestTreeItem *GTestFramework::createRootNode() const
+TestTreeItem *GTestFramework::createRootNode()
{
return new GTestTreeItem(
+ this,
QCoreApplication::translate("GTestFramework",
GTest::Constants::FRAMEWORK_SETTINGS_CATEGORY),
QString(), TestTreeItem::Root);
@@ -56,29 +63,9 @@ unsigned GTestFramework::priority() const
return GTest::Constants::FRAMEWORK_PRIORITY;
}
-IFrameworkSettings *GTestFramework::createFrameworkSettings() const
-{
- return new GTestSettings;
-}
-
-Core::IOptionsPage *GTestFramework::createSettingsPage(QSharedPointer<IFrameworkSettings> settings) const
-{
- return new GTestSettingsPage(settings, settingsId());
-}
-
-bool GTestFramework::hasFrameworkSettings() const
-{
- return true;
-}
-
QString GTestFramework::currentGTestFilter()
{
- static const Core::Id id
- = Core::Id(Constants::FRAMEWORK_PREFIX).withSuffix(GTest::Constants::FRAMEWORK_NAME);
- const auto manager = TestFrameworkManager::instance();
-
- auto gSettings = qSharedPointerCast<GTestSettings>(manager->settingsForTestFramework(id));
- return gSettings.isNull() ? QString(GTest::Constants::DEFAULT_FILTER) : gSettings->gtestFilter;
+ return g_settings->gtestFilter;
}
QString GTestFramework::groupingToolTip() const
@@ -90,14 +77,7 @@ QString GTestFramework::groupingToolTip() const
GTest::Constants::GroupMode GTestFramework::groupMode()
{
- static const Core::Id id
- = Core::Id(Constants::FRAMEWORK_PREFIX).withSuffix(GTest::Constants::FRAMEWORK_NAME);
- const auto manager = TestFrameworkManager::instance();
- if (!manager->groupingEnabled(id))
- return GTest::Constants::None;
-
- auto gSettings = qSharedPointerCast<GTestSettings>(manager->settingsForTestFramework(id));
- return gSettings.isNull() ? GTest::Constants::Directory : gSettings->groupMode;
+ return g_settings->groupMode;
}
} // namespace Internal
diff --git a/src/plugins/autotest/gtest/gtestframework.h b/src/plugins/autotest/gtest/gtestframework.h
index e6f1618c7b..25c43918c2 100644
--- a/src/plugins/autotest/gtest/gtestframework.h
+++ b/src/plugins/autotest/gtest/gtestframework.h
@@ -27,6 +27,8 @@
#include "../itestframework.h"
#include "gtestconstants.h"
+#include "gtestsettings.h"
+#include "gtestsettingspage.h"
namespace Autotest {
namespace Internal {
@@ -34,18 +36,21 @@ namespace Internal {
class GTestFramework : public ITestFramework
{
public:
- GTestFramework() : ITestFramework(true) {}
- const char *name() const override;
- unsigned priority() const override;
- IFrameworkSettings *createFrameworkSettings() const override;
- Core::IOptionsPage *createSettingsPage(QSharedPointer<IFrameworkSettings> settings) const override;
- bool hasFrameworkSettings() const override;
+ GTestFramework();
+
static GTest::Constants::GroupMode groupMode();
static QString currentGTestFilter();
+
+private:
+ const char *name() const override;
+ unsigned priority() const override;
QString groupingToolTip() const override;
-protected:
- ITestParser *createTestParser() const override;
- TestTreeItem *createRootNode() const override;
+ IFrameworkSettings *frameworkSettings() override { return &m_settings; }
+ ITestParser *createTestParser() override;
+ TestTreeItem *createRootNode() override;
+
+ GTestSettings m_settings;
+ GTestSettingsPage m_settingsPage{&m_settings, settingsId()};
};
} // namespace Internal
diff --git a/src/plugins/autotest/gtest/gtestoutputreader.h b/src/plugins/autotest/gtest/gtestoutputreader.h
index 2cf13a2b95..9bed450971 100644
--- a/src/plugins/autotest/gtest/gtestoutputreader.h
+++ b/src/plugins/autotest/gtest/gtestoutputreader.h
@@ -32,8 +32,6 @@
namespace Autotest {
namespace Internal {
-class GTestResult;
-
class GTestOutputReader : public TestOutputReader
{
Q_DECLARE_TR_FUNCTIONS(Autotest::Internal::GTestOutputReader)
diff --git a/src/plugins/autotest/gtest/gtestparser.cpp b/src/plugins/autotest/gtest/gtestparser.cpp
index e5eecf44ff..194c5a4b30 100644
--- a/src/plugins/autotest/gtest/gtestparser.cpp
+++ b/src/plugins/autotest/gtest/gtestparser.cpp
@@ -38,7 +38,7 @@ TestTreeItem *GTestParseResult::createTestTreeItem() const
{
if (itemType != TestTreeItem::TestSuite && itemType != TestTreeItem::TestCase)
return nullptr;
- GTestTreeItem *item = new GTestTreeItem(name, fileName, itemType);
+ GTestTreeItem *item = new GTestTreeItem(framework, name, fileName, itemType);
item->setProFile(proFile);
item->setLine(line);
item->setColumn(column);
@@ -89,7 +89,7 @@ static bool hasGTestNames(const CPlusPlus::Document::Ptr &document)
static bool handleGTest(QFutureInterface<TestParseResultPtr> futureInterface,
const CPlusPlus::Document::Ptr &doc,
const CPlusPlus::Snapshot &snapshot,
- const Core::Id &id)
+ ITestFramework *framework)
{
const CppTools::CppModelManager *modelManager = CppTools::CppModelManager::instance();
const QString &filePath = doc->fileName();
@@ -109,7 +109,7 @@ static bool handleGTest(QFutureInterface<TestParseResultPtr> futureInterface,
return false; // happens if shutting down while parsing
for (const GTestCaseSpec &testSpec : result.keys()) {
- GTestParseResult *parseResult = new GTestParseResult(id);
+ GTestParseResult *parseResult = new GTestParseResult(framework);
parseResult->itemType = TestTreeItem::TestSuite;
parseResult->fileName = filePath;
parseResult->name = testSpec.testCaseName;
@@ -119,7 +119,7 @@ static bool handleGTest(QFutureInterface<TestParseResultPtr> futureInterface,
parseResult->proFile = proFile;
for (const GTestCodeLocationAndType &location : result.value(testSpec)) {
- GTestParseResult *testSet = new GTestParseResult(id);
+ GTestParseResult *testSet = new GTestParseResult(framework);
testSet->name = location.m_name;
testSet->fileName = filePath;
testSet->line = location.m_line;
@@ -142,7 +142,7 @@ bool GTestParser::processDocument(QFutureInterface<TestParseResultPtr> futureInt
CPlusPlus::Document::Ptr doc = document(fileName);
if (doc.isNull() || !includesGTest(doc, m_cppSnapshot) || !hasGTestNames(doc))
return false;
- return handleGTest(futureInterface, doc, m_cppSnapshot, id());
+ return handleGTest(futureInterface, doc, m_cppSnapshot, framework());
}
} // namespace Internal
diff --git a/src/plugins/autotest/gtest/gtestparser.h b/src/plugins/autotest/gtest/gtestparser.h
index 67e2e074d4..781c9fe902 100644
--- a/src/plugins/autotest/gtest/gtestparser.h
+++ b/src/plugins/autotest/gtest/gtestparser.h
@@ -33,7 +33,7 @@ namespace Internal {
class GTestParseResult : public TestParseResult
{
public:
- explicit GTestParseResult(const Core::Id &id) : TestParseResult(id) {}
+ explicit GTestParseResult(ITestFramework *framework) : TestParseResult(framework) {}
TestTreeItem *createTestTreeItem() const override;
bool parameterized = false;
bool typed = false;
@@ -43,6 +43,7 @@ public:
class GTestParser : public CppParser
{
public:
+ explicit GTestParser(ITestFramework *framework) : CppParser(framework) {}
bool processDocument(QFutureInterface<TestParseResultPtr> futureInterface,
const QString &fileName) override;
};
diff --git a/src/plugins/autotest/gtest/gtestresult.cpp b/src/plugins/autotest/gtest/gtestresult.cpp
index b2f3aae67b..ee3be04821 100644
--- a/src/plugins/autotest/gtest/gtestresult.cpp
+++ b/src/plugins/autotest/gtest/gtestresult.cpp
@@ -96,7 +96,9 @@ static QString normalizeTestName(const QString &testname)
const TestTreeItem *GTestResult::findTestTreeItem() const
{
auto id = Core::Id(Constants::FRAMEWORK_PREFIX).withSuffix(GTest::Constants::FRAMEWORK_NAME);
- const TestTreeItem *rootNode = TestFrameworkManager::instance()->rootNodeForTestFramework(id);
+ ITestFramework *framework = TestFrameworkManager::frameworkForId(id);
+ QTC_ASSERT(framework, return nullptr);
+ const TestTreeItem *rootNode = framework->rootNode();
if (!rootNode)
return nullptr;
diff --git a/src/plugins/autotest/gtest/gtestsettingspage.cpp b/src/plugins/autotest/gtest/gtestsettingspage.cpp
index f285fafde5..c788d201af 100644
--- a/src/plugins/autotest/gtest/gtestsettingspage.cpp
+++ b/src/plugins/autotest/gtest/gtestsettingspage.cpp
@@ -46,17 +46,17 @@ class GTestSettingsWidget final : public Core::IOptionsPageWidget
Q_DECLARE_TR_FUNCTIONS(Autotest::Internal::GTestSettingsWidget)
public:
- explicit GTestSettingsWidget(const QSharedPointer<GTestSettings> &settings);
+ explicit GTestSettingsWidget(GTestSettings *settings);
private:
void apply() final;
Ui::GTestSettingsPage m_ui;
QString m_currentGTestFilter;
- QSharedPointer<GTestSettings> m_settings;
+ GTestSettings *m_settings;
};
-GTestSettingsWidget::GTestSettingsWidget(const QSharedPointer<GTestSettings> &settings)
+GTestSettingsWidget::GTestSettingsWidget(GTestSettings *settings)
: m_settings(settings)
{
m_ui.setupUi(this);
@@ -109,14 +109,13 @@ void GTestSettingsWidget::apply()
TestTreeModel::instance()->rebuild({id});
}
-GTestSettingsPage::GTestSettingsPage(QSharedPointer<IFrameworkSettings> settings,
- Core::Id settingsId)
+GTestSettingsPage::GTestSettingsPage(GTestSettings *settings, Core::Id settingsId)
{
setId(settingsId);
setCategory(Constants::AUTOTEST_SETTINGS_CATEGORY);
setDisplayName(QCoreApplication::translate("GTestFramework",
GTest::Constants::FRAMEWORK_SETTINGS_CATEGORY));
- setWidgetCreator([settings] { return new GTestSettingsWidget(qSharedPointerCast<GTestSettings>(settings)); });
+ setWidgetCreator([settings] { return new GTestSettingsWidget(settings); });
}
} // namespace Internal
diff --git a/src/plugins/autotest/gtest/gtestsettingspage.h b/src/plugins/autotest/gtest/gtestsettingspage.h
index d789fd4622..8cc20ae8b0 100644
--- a/src/plugins/autotest/gtest/gtestsettingspage.h
+++ b/src/plugins/autotest/gtest/gtestsettingspage.h
@@ -28,15 +28,14 @@
#include <coreplugin/dialogs/ioptionspage.h>
namespace Autotest {
-
-class IFrameworkSettings;
-
namespace Internal {
+class GTestSettings;
+
class GTestSettingsPage final : public Core::IOptionsPage
{
public:
- GTestSettingsPage(QSharedPointer<IFrameworkSettings> settings, Core::Id settingsId);
+ GTestSettingsPage(GTestSettings *settings, Core::Id settingsId);
};
} // namespace Internal
diff --git a/src/plugins/autotest/gtest/gtesttreeitem.cpp b/src/plugins/autotest/gtest/gtesttreeitem.cpp
index fdae1fa309..f2821ca1bf 100644
--- a/src/plugins/autotest/gtest/gtesttreeitem.cpp
+++ b/src/plugins/autotest/gtest/gtesttreeitem.cpp
@@ -65,7 +65,7 @@ static QString gtestFilter(GTestTreeItem::TestStates states)
TestTreeItem *GTestTreeItem::copyWithoutChildren()
{
- GTestTreeItem *copied = new GTestTreeItem;
+ GTestTreeItem *copied = new GTestTreeItem(framework());
copied->copyBasicDataFrom(this);
copied->m_state = m_state;
return copied;
@@ -170,7 +170,7 @@ TestConfiguration *GTestTreeItem::testConfiguration() const
case TestSuite: {
const QString &testSpecifier = gtestFilter(state()).arg(name()).arg('*');
if (int count = childCount()) {
- config = new GTestConfiguration;
+ config = new GTestConfiguration(framework());
config->setTestCases(QStringList(testSpecifier));
config->setTestCaseCount(count);
config->setProjectFile(proFile());
@@ -183,7 +183,7 @@ TestConfiguration *GTestTreeItem::testConfiguration() const
if (!parent)
return nullptr;
const QString &testSpecifier = gtestFilter(parent->state()).arg(parent->name()).arg(name());
- config = new GTestConfiguration;
+ config = new GTestConfiguration(framework());
config->setTestCases(QStringList(testSpecifier));
config->setProjectFile(proFile());
config->setProject(project);
@@ -261,7 +261,7 @@ QList<TestConfiguration *> GTestTreeItem::getTestConfigurations(bool ignoreCheck
for (auto it = testCasesForProFile.begin(), end = testCasesForProFile.end(); it != end; ++it) {
for (const QString &target : qAsConst(it.value().internalTargets)) {
- GTestConfiguration *tc = new GTestConfiguration;
+ GTestConfiguration *tc = new GTestConfiguration(framework());
if (!ignoreCheckState)
tc->setTestCases(it.value().filters);
tc->setTestCaseCount(tc->testCaseCount() + it.value().testSetCount);
@@ -307,7 +307,7 @@ QList<TestConfiguration *> GTestTreeItem::getTestConfigurationsForFile(const Uti
});
for (auto it = testCases.begin(), end = testCases.end(); it != end; ++it) {
for (const QString &target : qAsConst(it.value().internalTargets)) {
- GTestConfiguration *tc = new GTestConfiguration;
+ GTestConfiguration *tc = new GTestConfiguration(framework());
tc->setTestCases(it.value().filters);
tc->setProjectFile(it.key());
tc->setProject(project);
@@ -331,7 +331,7 @@ TestTreeItem *GTestTreeItem::find(const TestParseResult *result)
states |= GTestTreeItem::Typed;
switch (type()) {
case Root:
- if (TestFrameworkManager::instance()->groupingEnabled(result->frameworkId)) {
+ if (result->framework->grouping()) {
if (GTestFramework::groupMode() == GTest::Constants::Directory) {
const QFileInfo fileInfo(parseResult->fileName);
const QFileInfo base(fileInfo.absolutePath());
@@ -420,7 +420,7 @@ TestTreeItem *GTestTreeItem::createParentGroupNode() const
if (GTestFramework::groupMode() == GTest::Constants::Directory) {
const QFileInfo fileInfo(filePath());
const QFileInfo base(fileInfo.absolutePath());
- return new GTestTreeItem(base.baseName(), fileInfo.absolutePath(), TestTreeItem::GroupNode);
+ return new GTestTreeItem(framework(), base.baseName(), fileInfo.absolutePath(), TestTreeItem::GroupNode);
} else { // GTestFilter
QTC_ASSERT(childCount(), return nullptr); // paranoia
const TestTreeItem *firstChild = childAt(0);
@@ -428,7 +428,7 @@ TestTreeItem *GTestTreeItem::createParentGroupNode() const
const QString fullTestName = name() + '.' + firstChild->name();
const QString groupNodeName =
matchesFilter(activeFilter, fullTestName) ? matchingString() : notMatchingString();
- auto groupNode = new GTestTreeItem(groupNodeName, activeFilter, TestTreeItem::GroupNode);
+ auto groupNode = new GTestTreeItem(framework(), groupNodeName, activeFilter, TestTreeItem::GroupNode);
if (groupNodeName == notMatchingString())
groupNode->setData(0, Qt::Unchecked, Qt::CheckStateRole);
return groupNode;
diff --git a/src/plugins/autotest/gtest/gtesttreeitem.h b/src/plugins/autotest/gtest/gtesttreeitem.h
index 3b93116ffc..3e5c1620a1 100644
--- a/src/plugins/autotest/gtest/gtesttreeitem.h
+++ b/src/plugins/autotest/gtest/gtesttreeitem.h
@@ -46,8 +46,12 @@ public:
Q_FLAGS(TestState)
Q_DECLARE_FLAGS(TestStates, TestState)
- explicit GTestTreeItem(const QString &name = QString(), const QString &filePath = QString(),
- Type type = Root) : TestTreeItem(name, filePath, type), m_state(Enabled) {}
+ explicit GTestTreeItem(ITestFramework *framework,
+ const QString &name = QString(),
+ const QString &filePath = QString(),
+ Type type = Root)
+ : TestTreeItem(framework, name, filePath, type), m_state(Enabled)
+ {}
TestTreeItem *copyWithoutChildren() override;
QVariant data(int column, int role) const override;
diff --git a/src/plugins/autotest/itestframework.cpp b/src/plugins/autotest/itestframework.cpp
new file mode 100644
index 0000000000..e43a1ca65e
--- /dev/null
+++ b/src/plugins/autotest/itestframework.cpp
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** 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 "itestframework.h"
+#include "itestparser.h"
+
+namespace Autotest {
+
+ITestFramework::ITestFramework(bool activeByDefault)
+ : m_active(activeByDefault)
+{}
+
+ITestFramework::~ITestFramework()
+{
+ delete m_testParser;
+}
+
+TestTreeItem *ITestFramework::rootNode()
+{
+ if (!m_rootNode)
+ m_rootNode = createRootNode();
+ // These are stored in the TestTreeModel and destroyed on shutdown there.
+ return m_rootNode;
+}
+
+ITestParser *ITestFramework::testParser()
+{
+ if (!m_testParser)
+ m_testParser = createTestParser();
+ return m_testParser;
+}
+
+Core::Id ITestFramework::settingsId() const
+{
+ return Core::Id(Constants::SETTINGSPAGE_PREFIX)
+ .withSuffix(QString("%1.%2").arg(priority()).arg(QLatin1String(name())));
+}
+
+Core::Id ITestFramework::id() const
+{
+ return Core::Id(Constants::FRAMEWORK_PREFIX).withSuffix(name());
+}
+
+void ITestFramework::resetRootNode()
+{
+ if (!m_rootNode)
+ return;
+ if (m_rootNode->model())
+ static_cast<TestTreeModel *>(m_rootNode->model())->takeItem(m_rootNode);
+ delete m_rootNode;
+ m_rootNode = nullptr;
+}
+
+} // namespace Autotest
diff --git a/src/plugins/autotest/itestframework.h b/src/plugins/autotest/itestframework.h
index 11bdfa31cc..960b9d8ad5 100644
--- a/src/plugins/autotest/itestframework.h
+++ b/src/plugins/autotest/itestframework.h
@@ -28,8 +28,6 @@
#include "testtreeitem.h"
#include "itestparser.h"
-namespace Core { class IOptionsPage; }
-
namespace Autotest {
class IFrameworkSettings;
@@ -37,37 +35,19 @@ class IFrameworkSettings;
class ITestFramework
{
public:
- explicit ITestFramework(bool activeByDefault) : m_active(activeByDefault) {}
- virtual ~ITestFramework()
- {
- delete m_rootNode;
- delete m_testParser;
- }
+ explicit ITestFramework(bool activeByDefault);
+ virtual ~ITestFramework();
virtual const char *name() const = 0;
virtual unsigned priority() const = 0; // should this be modifyable?
- virtual bool hasFrameworkSettings() const { return false; }
- virtual IFrameworkSettings *createFrameworkSettings() const { return nullptr; }
- virtual Core::IOptionsPage *createSettingsPage(QSharedPointer<IFrameworkSettings> settings) const
- {
- Q_UNUSED(settings)
- return nullptr;
- }
- TestTreeItem *rootNode()
- { if (!m_rootNode)
- m_rootNode = createRootNode();
- return m_rootNode;
- }
+ virtual IFrameworkSettings *frameworkSettings() { return nullptr; }
- ITestParser *testParser()
- {
- if (!m_testParser)
- m_testParser = createTestParser();
- return m_testParser;
- }
+ TestTreeItem *rootNode();
+ ITestParser *testParser();
Core::Id settingsId() const;
+ Core::Id id() const;
bool active() const { return m_active; }
void setActive(bool active) { m_active = active; }
@@ -75,9 +55,12 @@ public:
void setGrouping(bool group) { m_grouping = group; }
// framework specific tool tip to be displayed on the general settings page
virtual QString groupingToolTip() const { return QString(); }
+
+ void resetRootNode();
+
protected:
- virtual ITestParser *createTestParser() const = 0;
- virtual TestTreeItem *createRootNode() const = 0;
+ virtual ITestParser *createTestParser() = 0;
+ virtual TestTreeItem *createRootNode() = 0;
private:
TestTreeItem *m_rootNode = nullptr;
@@ -86,4 +69,6 @@ private:
bool m_grouping = false;
};
+using TestFrameworks = QList<ITestFramework *>;
+
} // namespace Autotest
diff --git a/src/plugins/autotest/itestparser.cpp b/src/plugins/autotest/itestparser.cpp
index 316245cdee..335c56cbab 100644
--- a/src/plugins/autotest/itestparser.cpp
+++ b/src/plugins/autotest/itestparser.cpp
@@ -33,7 +33,8 @@ namespace Autotest {
static CppParser *s_parserInstance = nullptr;
-CppParser::CppParser()
+CppParser::CppParser(ITestFramework *framework)
+ : ITestParser(framework)
{
s_parserInstance = this;
}
diff --git a/src/plugins/autotest/itestparser.h b/src/plugins/autotest/itestparser.h
index d9a8c92801..e2ea592e09 100644
--- a/src/plugins/autotest/itestparser.h
+++ b/src/plugins/autotest/itestparser.h
@@ -35,16 +35,18 @@
namespace Autotest {
+class ITestFramework;
+
class TestParseResult
{
public:
- explicit TestParseResult(const Core::Id &id) : frameworkId(id) {}
+ explicit TestParseResult(ITestFramework *framework) : framework(framework) {}
virtual ~TestParseResult() { qDeleteAll(children); }
virtual TestTreeItem *createTestTreeItem() const = 0;
QVector<TestParseResult *> children;
- Core::Id frameworkId;
+ ITestFramework *framework;
TestTreeItem::Type itemType = TestTreeItem::Root;
QString displayName;
QString fileName;
@@ -59,22 +61,23 @@ using TestParseResultPtr = QSharedPointer<TestParseResult>;
class ITestParser
{
public:
+ explicit ITestParser(ITestFramework *framework) : m_framework(framework) {}
virtual ~ITestParser() { }
virtual void init(const QStringList &filesToParse, bool fullParse) = 0;
virtual bool processDocument(QFutureInterface<TestParseResultPtr> futureInterface,
const QString &fileName) = 0;
virtual void release() = 0;
- void setId(const Core::Id &id) { m_id = id; }
- Core::Id id() const { return m_id; }
+
+ ITestFramework *framework() const { return m_framework; }
private:
- Core::Id m_id;
+ ITestFramework *m_framework;
};
class CppParser : public ITestParser
{
public:
- CppParser();
+ explicit CppParser(ITestFramework *framework);
void init(const QStringList &filesToParse, bool fullParse) override;
static bool selectedForBuilding(const QString &fileName);
static QByteArray getFileContent(const QString &filePath);
diff --git a/src/plugins/autotest/projectsettingswidget.cpp b/src/plugins/autotest/projectsettingswidget.cpp
index 4fb66be7f8..f5021e5c3c 100644
--- a/src/plugins/autotest/projectsettingswidget.cpp
+++ b/src/plugins/autotest/projectsettingswidget.cpp
@@ -105,16 +105,16 @@ ProjectTestSettingsWidget::ProjectTestSettingsWidget(ProjectExplorer::Project *p
TestTreeModel::instance(), &TestTreeModel::synchronizeTestFrameworks);
}
-void ProjectTestSettingsWidget::populateFrameworks(const QMap<Core::Id, bool> &frameworks)
+void ProjectTestSettingsWidget::populateFrameworks(const QMap<ITestFramework *, bool> &frameworks)
{
- TestFrameworkManager *frameworkManager = TestFrameworkManager::instance();
- auto end = frameworks.cend();
- for (auto it = frameworks.cbegin(); it != end; ++it) {
- auto *item = new QTreeWidgetItem(m_activeFrameworks,
- QStringList(frameworkManager->frameworkNameForId(it.key())));
+ TestFrameworks sortedFrameworks = frameworks.keys();
+ Utils::sort(sortedFrameworks, &ITestFramework::priority);
+
+ for (ITestFramework *framework : sortedFrameworks) {
+ auto item = new QTreeWidgetItem(m_activeFrameworks, QStringList(QLatin1String(framework->name())));
item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable);
- item->setCheckState(0, it.value() ? Qt::Checked : Qt::Unchecked);
- item->setData(0, FrameworkIdRole, it.key().toSetting());
+ item->setCheckState(0, frameworks.value(framework) ? Qt::Checked : Qt::Unchecked);
+ item->setData(0, FrameworkIdRole, framework->id().toSetting());
}
}
diff --git a/src/plugins/autotest/projectsettingswidget.h b/src/plugins/autotest/projectsettingswidget.h
index 66da382f02..d921d56e88 100644
--- a/src/plugins/autotest/projectsettingswidget.h
+++ b/src/plugins/autotest/projectsettingswidget.h
@@ -34,10 +34,12 @@ class QTreeWidget;
class QTreeWidgetItem;
QT_END_NAMESPACE
-namespace Core { class Id; }
namespace ProjectExplorer { class Project; }
namespace Autotest {
+
+class ITestFramework;
+
namespace Internal {
class TestProjectSettings;
@@ -49,7 +51,7 @@ public:
explicit ProjectTestSettingsWidget(ProjectExplorer::Project *project,
QWidget *parent = nullptr);
private:
- void populateFrameworks(const QMap<Core::Id, bool> &frameworks);
+ void populateFrameworks(const QMap<Autotest::ITestFramework *, bool> &frameworks);
void onActiveFrameworkChanged(QTreeWidgetItem *item, int column);
TestProjectSettings *m_projectSettings;
QComboBox *m_useGlobalSettings = nullptr;
diff --git a/src/plugins/autotest/qtest/qttest_utils.cpp b/src/plugins/autotest/qtest/qttest_utils.cpp
index ff49155a98..6cf5fd679c 100644
--- a/src/plugins/autotest/qtest/qttest_utils.cpp
+++ b/src/plugins/autotest/qtest/qttest_utils.cpp
@@ -46,10 +46,10 @@ bool isQTestMacro(const QByteArray &macro)
return valid.contains(macro);
}
-QHash<QString, QString> testCaseNamesForFiles(const Core::Id &id, const QStringList &files)
+QHash<QString, QString> testCaseNamesForFiles(ITestFramework *framework, const QStringList &files)
{
QHash<QString, QString> result;
- TestTreeItem *rootNode = TestFrameworkManager::instance()->rootNodeForTestFramework(id);
+ TestTreeItem *rootNode = framework->rootNode();
QTC_ASSERT(rootNode, return result);
rootNode->forFirstLevelChildren([&result, &files](TestTreeItem *child) {
@@ -63,10 +63,10 @@ QHash<QString, QString> testCaseNamesForFiles(const Core::Id &id, const QStringL
return result;
}
-QMultiHash<QString, QString> alternativeFiles(const Core::Id &id, const QStringList &files)
+QMultiHash<QString, QString> alternativeFiles(ITestFramework *framework, const QStringList &files)
{
QMultiHash<QString, QString> result;
- TestTreeItem *rootNode = TestFrameworkManager::instance()->rootNodeForTestFramework(id);
+ TestTreeItem *rootNode = framework->rootNode();
QTC_ASSERT(rootNode, return result);
rootNode->forFirstLevelChildren([&result, &files](TestTreeItem *child) {
diff --git a/src/plugins/autotest/qtest/qttest_utils.h b/src/plugins/autotest/qtest/qttest_utils.h
index 23820c05d9..4d13df0d1e 100644
--- a/src/plugins/autotest/qtest/qttest_utils.h
+++ b/src/plugins/autotest/qtest/qttest_utils.h
@@ -31,12 +31,15 @@ namespace Core { class Id; }
namespace Utils { class Environment; }
namespace Autotest {
+
+class ITestFramework;
+
namespace Internal {
namespace QTestUtils {
bool isQTestMacro(const QByteArray &macro);
-QHash<QString, QString> testCaseNamesForFiles(const Core::Id &id, const QStringList &files);
-QMultiHash<QString, QString> alternativeFiles(const Core::Id &id, const QStringList &files);
+QHash<QString, QString> testCaseNamesForFiles(ITestFramework *framework, const QStringList &files);
+QMultiHash<QString, QString> alternativeFiles(ITestFramework *framework, const QStringList &files);
QStringList filterInterfering(const QStringList &provided, QStringList *omitted, bool isQuickTest);
Utils::Environment prepareBasicEnvironment(const Utils::Environment &env);
diff --git a/src/plugins/autotest/qtest/qttestconfiguration.cpp b/src/plugins/autotest/qtest/qttestconfiguration.cpp
index 1212f3b852..a3bc92c67c 100644
--- a/src/plugins/autotest/qtest/qttestconfiguration.cpp
+++ b/src/plugins/autotest/qtest/qttestconfiguration.cpp
@@ -29,7 +29,7 @@
#include "qttestsettings.h"
#include "qttest_utils.h"
#include "../autotestplugin.h"
-#include "../testframeworkmanager.h"
+#include "../itestframework.h"
#include "../testsettings.h"
namespace Autotest {
@@ -38,10 +38,7 @@ namespace Internal {
TestOutputReader *QtTestConfiguration::outputReader(const QFutureInterface<TestResultPtr> &fi,
QProcess *app) const
{
- static const Core::Id id
- = Core::Id(Constants::FRAMEWORK_PREFIX).withSuffix(QtTest::Constants::FRAMEWORK_NAME);
- TestFrameworkManager *manager = TestFrameworkManager::instance();
- auto qtSettings = qSharedPointerCast<QtTestSettings>(manager->settingsForTestFramework(id));
+ auto qtSettings = dynamic_cast<QtTestSettings *>(framework()->frameworkSettings());
const QtTestOutputReader::OutputMode mode = qtSettings && qtSettings->useXMLOutput
? QtTestOutputReader::XML
: QtTestOutputReader::PlainText;
@@ -50,18 +47,14 @@ TestOutputReader *QtTestConfiguration::outputReader(const QFutureInterface<TestR
QStringList QtTestConfiguration::argumentsForTestRunner(QStringList *omitted) const
{
- static const Core::Id id
- = Core::Id(Constants::FRAMEWORK_PREFIX).withSuffix(QtTest::Constants::FRAMEWORK_NAME);
-
QStringList arguments;
if (AutotestPlugin::settings()->processArgs) {
arguments.append(QTestUtils::filterInterfering(
runnable().commandLineArguments.split(' ', QString::SkipEmptyParts),
omitted, false));
}
- TestFrameworkManager *manager = TestFrameworkManager::instance();
- auto qtSettings = qSharedPointerCast<QtTestSettings>(manager->settingsForTestFramework(id));
- if (qtSettings.isNull())
+ auto qtSettings = dynamic_cast<QtTestSettings *>(framework()->frameworkSettings());
+ if (!qtSettings)
return arguments;
if (qtSettings->useXMLOutput)
arguments << "-xml";
diff --git a/src/plugins/autotest/qtest/qttestconfiguration.h b/src/plugins/autotest/qtest/qttestconfiguration.h
index f38ad7f847..8196665679 100644
--- a/src/plugins/autotest/qtest/qttestconfiguration.h
+++ b/src/plugins/autotest/qtest/qttestconfiguration.h
@@ -33,7 +33,8 @@ namespace Internal {
class QtTestConfiguration : public DebuggableTestConfiguration
{
public:
- explicit QtTestConfiguration() {}
+ explicit QtTestConfiguration(ITestFramework *framework)
+ : DebuggableTestConfiguration(framework) {}
TestOutputReader *outputReader(const QFutureInterface<TestResultPtr> &fi,
QProcess *app) const override;
QStringList argumentsForTestRunner(QStringList *omitted = nullptr) const override;
diff --git a/src/plugins/autotest/qtest/qttestframework.cpp b/src/plugins/autotest/qtest/qttestframework.cpp
index bbf42a844a..c606c53f32 100644
--- a/src/plugins/autotest/qtest/qttestframework.cpp
+++ b/src/plugins/autotest/qtest/qttestframework.cpp
@@ -26,41 +26,25 @@
#include "qttestframework.h"
#include "qttestconstants.h"
#include "qttestparser.h"
-#include "qttestsettings.h"
-#include "qttestsettingspage.h"
#include "qttesttreeitem.h"
namespace Autotest {
namespace Internal {
-ITestParser *QtTestFramework::createTestParser() const
+ITestParser *QtTestFramework::createTestParser()
{
- return new QtTestParser;
+ return new QtTestParser(this);
}
-TestTreeItem *QtTestFramework::createRootNode() const
+TestTreeItem *QtTestFramework::createRootNode()
{
return new QtTestTreeItem(
+ this,
QCoreApplication::translate("QtTestFramework",
QtTest::Constants::FRAMEWORK_SETTINGS_CATEGORY),
QString(), TestTreeItem::Root);
}
-IFrameworkSettings *QtTestFramework::createFrameworkSettings() const
-{
- return new QtTestSettings;
-}
-
-Core::IOptionsPage *QtTestFramework::createSettingsPage(QSharedPointer<IFrameworkSettings> settings) const
-{
- return new QtTestSettingsPage(settings, settingsId());
-}
-
-bool QtTestFramework::hasFrameworkSettings() const
-{
- return true;
-}
-
const char *QtTestFramework::name() const
{
return QtTest::Constants::FRAMEWORK_NAME;
diff --git a/src/plugins/autotest/qtest/qttestframework.h b/src/plugins/autotest/qtest/qttestframework.h
index a6cfcb9f2a..6cfa70a211 100644
--- a/src/plugins/autotest/qtest/qttestframework.h
+++ b/src/plugins/autotest/qtest/qttestframework.h
@@ -27,6 +27,9 @@
#include "../itestframework.h"
+#include "qttestsettings.h"
+#include "qttestsettingspage.h"
+
namespace Autotest {
namespace Internal {
@@ -34,15 +37,16 @@ class QtTestFramework : public ITestFramework
{
public:
QtTestFramework() : ITestFramework(true) {}
+
+private:
const char *name() const override;
unsigned priority() const override;
- IFrameworkSettings *createFrameworkSettings() const override;
- Core::IOptionsPage *createSettingsPage(QSharedPointer<IFrameworkSettings> settings) const override;
- bool hasFrameworkSettings() const override;
+ ITestParser *createTestParser() override;
+ TestTreeItem *createRootNode() override;
+ IFrameworkSettings *frameworkSettings() override { return &m_settings; }
-protected:
- ITestParser *createTestParser() const override;
- TestTreeItem *createRootNode() const override;
+ QtTestSettings m_settings;
+ QtTestSettingsPage m_settingsPage{&m_settings, settingsId()};
};
} // namespace Internal
diff --git a/src/plugins/autotest/qtest/qttestparser.cpp b/src/plugins/autotest/qtest/qttestparser.cpp
index 564be5df26..5367d89a55 100644
--- a/src/plugins/autotest/qtest/qttestparser.cpp
+++ b/src/plugins/autotest/qtest/qttestparser.cpp
@@ -41,7 +41,7 @@ TestTreeItem *QtTestParseResult::createTestTreeItem() const
if (itemType == TestTreeItem::Root)
return nullptr;
- QtTestTreeItem *item = new QtTestTreeItem(displayName, fileName, itemType);
+ QtTestTreeItem *item = new QtTestTreeItem(framework, displayName, fileName, itemType);
item->setProFile(proFile);
item->setLine(line);
item->setColumn(column);
@@ -284,7 +284,7 @@ static bool handleQtTest(QFutureInterface<TestParseResultPtr> futureInterface,
const CPlusPlus::Snapshot &snapshot,
const QString &oldTestCaseName,
const QStringList &alternativeFiles,
- const Core::Id &id)
+ ITestFramework *framework)
{
const CppTools::CppModelManager *modelManager = CppTools::CppModelManager::instance();
const QString &fileName = document->fileName();
@@ -321,7 +321,7 @@ static bool handleQtTest(QFutureInterface<TestParseResultPtr> futureInterface,
for (const QString &file : files)
Utils::addToHash(&dataTags, checkForDataTags(file, snapshot));
- QtTestParseResult *parseResult = new QtTestParseResult(id);
+ QtTestParseResult *parseResult = new QtTestParseResult(framework);
parseResult->itemType = TestTreeItem::TestCase;
parseResult->fileName = declaringDoc->fileName();
parseResult->name = testCaseName;
@@ -338,7 +338,7 @@ static bool handleQtTest(QFutureInterface<TestParseResultPtr> futureInterface,
const QtTestCodeLocationAndType &location = it.value();
QString functionName = it.key();
functionName = functionName.mid(functionName.lastIndexOf(':') + 1);
- QtTestParseResult *func = new QtTestParseResult(id);
+ QtTestParseResult *func = new QtTestParseResult(framework);
func->itemType = location.m_type;
func->name = testCaseName + "::" + functionName;
func->displayName = functionName;
@@ -349,7 +349,7 @@ static bool handleQtTest(QFutureInterface<TestParseResultPtr> futureInterface,
const QtTestCodeLocationList &tagLocations = tagLocationsFor(func, dataTags);
for (const QtTestCodeLocationAndType &tag : tagLocations) {
- QtTestParseResult *dataTag = new QtTestParseResult(id);
+ QtTestParseResult *dataTag = new QtTestParseResult(framework);
dataTag->itemType = tag.m_type;
dataTag->name = tag.m_name;
dataTag->displayName = tag.m_name;
@@ -372,8 +372,8 @@ static bool handleQtTest(QFutureInterface<TestParseResultPtr> futureInterface,
void QtTestParser::init(const QStringList &filesToParse, bool fullParse)
{
if (!fullParse) { // in a full parse cached information might lead to wrong results
- m_testCaseNames = QTestUtils::testCaseNamesForFiles(id(), filesToParse);
- m_alternativeFiles = QTestUtils::alternativeFiles(id(), filesToParse);
+ m_testCaseNames = QTestUtils::testCaseNamesForFiles(framework(), filesToParse);
+ m_alternativeFiles = QTestUtils::alternativeFiles(framework(), filesToParse);
}
CppParser::init(filesToParse, fullParse);
}
@@ -396,7 +396,7 @@ bool QtTestParser::processDocument(QFutureInterface<TestParseResultPtr> futureIn
if ((!includesQtTest(doc, m_cppSnapshot) || !qtTestLibDefined(fileName)) && oldName.isEmpty())
return false;
- return handleQtTest(futureInterface, doc, m_cppSnapshot, oldName, alternativeFiles, id());
+ return handleQtTest(futureInterface, doc, m_cppSnapshot, oldName, alternativeFiles, framework());
}
} // namespace Internal
diff --git a/src/plugins/autotest/qtest/qttestparser.h b/src/plugins/autotest/qtest/qttestparser.h
index 9cf0709c7d..dac8a5d094 100644
--- a/src/plugins/autotest/qtest/qttestparser.h
+++ b/src/plugins/autotest/qtest/qttestparser.h
@@ -33,7 +33,7 @@ namespace Internal {
class QtTestParseResult : public TestParseResult
{
public:
- explicit QtTestParseResult(const Core::Id &id) : TestParseResult(id) {}
+ explicit QtTestParseResult(ITestFramework *framework) : TestParseResult(framework) {}
void setInherited(bool inherited) { m_inherited = inherited; }
bool inherited() const { return m_inherited; }
TestTreeItem *createTestTreeItem() const override;
@@ -44,6 +44,8 @@ private:
class QtTestParser : public CppParser
{
public:
+ explicit QtTestParser(ITestFramework *framework) : CppParser(framework) {}
+
void init(const QStringList &filesToParse, bool fullParse) override;
void release() override;
bool processDocument(QFutureInterface<TestParseResultPtr> futureInterface,
diff --git a/src/plugins/autotest/qtest/qttestresult.cpp b/src/plugins/autotest/qtest/qttestresult.cpp
index 65ec0c8270..38fefa171b 100644
--- a/src/plugins/autotest/qtest/qttestresult.cpp
+++ b/src/plugins/autotest/qtest/qttestresult.cpp
@@ -136,7 +136,9 @@ const TestTreeItem *QtTestResult::findTestTreeItem() const
id = Core::Id(Constants::FRAMEWORK_PREFIX).withSuffix(QtTest::Constants::FRAMEWORK_NAME);
else
id = Core::Id(Constants::FRAMEWORK_PREFIX).withSuffix(QuickTest::Constants::FRAMEWORK_NAME);
- const TestTreeItem *rootNode = TestFrameworkManager::instance()->rootNodeForTestFramework(id);
+ ITestFramework *framework = TestFrameworkManager::frameworkForId(id);
+ QTC_ASSERT(framework, return nullptr);
+ const TestTreeItem *rootNode = framework->rootNode();
QTC_ASSERT(rootNode, return nullptr);
const auto item = rootNode->findAnyChild([this](const Utils::TreeItem *item) {
diff --git a/src/plugins/autotest/qtest/qttestsettingspage.cpp b/src/plugins/autotest/qtest/qttestsettingspage.cpp
index fcc01853a1..02a74cb344 100644
--- a/src/plugins/autotest/qtest/qttestsettingspage.cpp
+++ b/src/plugins/autotest/qtest/qttestsettingspage.cpp
@@ -41,16 +41,16 @@ class QtTestSettingsWidget final : public Core::IOptionsPageWidget
Q_DECLARE_TR_FUNCTIONS(Autotest::Internal::QtTestSettingsWidget)
public:
- explicit QtTestSettingsWidget(QSharedPointer<QtTestSettings> settings);
+ explicit QtTestSettingsWidget(QtTestSettings *settings);
void apply() final;
private:
Ui::QtTestSettingsPage m_ui;
- QSharedPointer<QtTestSettings> m_settings;
+ QtTestSettings *m_settings;
};
-QtTestSettingsWidget::QtTestSettingsWidget(QSharedPointer<QtTestSettings> settings)
+QtTestSettingsWidget::QtTestSettingsWidget(QtTestSettings *settings)
: m_settings(settings)
{
m_ui.setupUi(this);
@@ -100,16 +100,13 @@ void QtTestSettingsWidget::apply()
m_settings->toSettings(Core::ICore::settings());
}
-QtTestSettingsPage::QtTestSettingsPage(QSharedPointer<IFrameworkSettings> settings,
- Core::Id settingsId)
+QtTestSettingsPage::QtTestSettingsPage(QtTestSettings *settings, Core::Id settingsId)
{
setId(settingsId);
setCategory(Constants::AUTOTEST_SETTINGS_CATEGORY);
setDisplayName(QCoreApplication::translate("QtTestFramework",
QtTest::Constants::FRAMEWORK_SETTINGS_CATEGORY));
- setWidgetCreator([settings] {
- return new QtTestSettingsWidget(qSharedPointerCast<QtTestSettings>(settings));
- });
+ setWidgetCreator([settings] { return new QtTestSettingsWidget(settings); });
}
} // namespace Internal
diff --git a/src/plugins/autotest/qtest/qttestsettingspage.h b/src/plugins/autotest/qtest/qttestsettingspage.h
index 6818ea441c..3ed9c76eaa 100644
--- a/src/plugins/autotest/qtest/qttestsettingspage.h
+++ b/src/plugins/autotest/qtest/qttestsettingspage.h
@@ -28,15 +28,14 @@
#include <coreplugin/dialogs/ioptionspage.h>
namespace Autotest {
-
-class IFrameworkSettings;
-
namespace Internal {
+class QtTestSettings;
+
class QtTestSettingsPage final : public Core::IOptionsPage
{
public:
- QtTestSettingsPage(QSharedPointer<IFrameworkSettings> settings, Core::Id settingsId);
+ QtTestSettingsPage(QtTestSettings *settings, Core::Id settingsId);
};
} // namespace Internal
diff --git a/src/plugins/autotest/qtest/qttesttreeitem.cpp b/src/plugins/autotest/qtest/qttesttreeitem.cpp
index 7069e29961..a128a80941 100644
--- a/src/plugins/autotest/qtest/qttesttreeitem.cpp
+++ b/src/plugins/autotest/qtest/qttesttreeitem.cpp
@@ -34,8 +34,9 @@
namespace Autotest {
namespace Internal {
-QtTestTreeItem::QtTestTreeItem(const QString &name, const QString &filePath, TestTreeItem::Type type)
- : TestTreeItem(name, filePath, type)
+QtTestTreeItem::QtTestTreeItem(ITestFramework *framework, const QString &name,
+ const QString &filePath, TestTreeItem::Type type)
+ : TestTreeItem(framework, name, filePath, type)
{
if (type == TestDataTag)
setData(0, Qt::Checked, Qt::CheckStateRole);
@@ -43,7 +44,7 @@ QtTestTreeItem::QtTestTreeItem(const QString &name, const QString &filePath, Tes
TestTreeItem *QtTestTreeItem::copyWithoutChildren()
{
- QtTestTreeItem *copied = new QtTestTreeItem;
+ QtTestTreeItem *copied = new QtTestTreeItem(framework());
copied->copyBasicDataFrom(this);
copied->m_inherited = m_inherited;
return copied;
@@ -114,14 +115,14 @@ TestConfiguration *QtTestTreeItem::testConfiguration() const
QtTestConfiguration *config = nullptr;
switch (type()) {
case TestCase:
- config = new QtTestConfiguration;
+ config = new QtTestConfiguration(framework());
config->setTestCaseCount(childCount());
config->setProjectFile(proFile());
config->setProject(project);
break;
case TestFunction: {
TestTreeItem *parent = parentItem();
- config = new QtTestConfiguration();
+ config = new QtTestConfiguration(framework());
config->setTestCases(QStringList(name()));
config->setProjectFile(parent->proFile());
config->setProject(project);
@@ -133,7 +134,7 @@ TestConfiguration *QtTestTreeItem::testConfiguration() const
if (!parent)
return nullptr;
const QString functionWithTag = function->name() + ':' + name();
- config = new QtTestConfiguration();
+ config = new QtTestConfiguration(framework());
config->setTestCases(QStringList(functionWithTag));
config->setProjectFile(parent->proFile());
config->setProject(project);
@@ -180,7 +181,7 @@ static void fillTestConfigurationsFromCheckState(const TestTreeItem *item,
}
});
- testConfig = new QtTestConfiguration();
+ testConfig = new QtTestConfiguration(item->framework());
testConfig->setTestCases(testCases);
testConfig->setProjectFile(item->proFile());
testConfig->setProject(ProjectExplorer::SessionManager::startupProject());
@@ -269,7 +270,7 @@ TestTreeItem *QtTestTreeItem::find(const TestParseResult *result)
switch (type()) {
case Root:
- if (TestFrameworkManager::instance()->groupingEnabled(result->frameworkId)) {
+ if (result->framework->grouping()) {
const QString path = QFileInfo(result->fileName).absolutePath();
for (int row = 0; row < childCount(); ++row) {
TestTreeItem *group = childAt(row);
@@ -342,7 +343,7 @@ TestTreeItem *QtTestTreeItem::createParentGroupNode() const
{
const QFileInfo fileInfo(filePath());
const QFileInfo base(fileInfo.absolutePath());
- return new QtTestTreeItem(base.baseName(), fileInfo.absolutePath(), TestTreeItem::GroupNode);
+ return new QtTestTreeItem(framework(), base.baseName(), fileInfo.absolutePath(), TestTreeItem::GroupNode);
}
bool QtTestTreeItem::isGroupable() const
diff --git a/src/plugins/autotest/qtest/qttesttreeitem.h b/src/plugins/autotest/qtest/qttesttreeitem.h
index 97ad853580..9b803ee92e 100644
--- a/src/plugins/autotest/qtest/qttesttreeitem.h
+++ b/src/plugins/autotest/qtest/qttesttreeitem.h
@@ -33,7 +33,7 @@ namespace Internal {
class QtTestTreeItem : public TestTreeItem
{
public:
- explicit QtTestTreeItem(const QString &name = QString(), const QString &filePath = QString(),
+ explicit QtTestTreeItem(ITestFramework *framework, const QString &name = QString(), const QString &filePath = QString(),
Type type = Root);
TestTreeItem *copyWithoutChildren() override;
diff --git a/src/plugins/autotest/quick/quicktest_utils.cpp b/src/plugins/autotest/quick/quicktest_utils.cpp
index 92a36a9a19..eab91c9324 100644
--- a/src/plugins/autotest/quick/quicktest_utils.cpp
+++ b/src/plugins/autotest/quick/quicktest_utils.cpp
@@ -43,10 +43,10 @@ bool isQuickTestMacro(const QByteArray &macro)
return valid.contains(macro);
}
-QHash<QString, QString> proFilesForQmlFiles(const Core::Id &id, const QStringList &files)
+QHash<QString, QString> proFilesForQmlFiles(ITestFramework *framework, const QStringList &files)
{
QHash<QString, QString> result;
- TestTreeItem *rootNode = TestFrameworkManager::instance()->rootNodeForTestFramework(id);
+ TestTreeItem *rootNode = framework->rootNode();
QTC_ASSERT(rootNode, return result);
if (files.isEmpty())
diff --git a/src/plugins/autotest/quick/quicktest_utils.h b/src/plugins/autotest/quick/quicktest_utils.h
index af5cfdb7bf..8eca2a2569 100644
--- a/src/plugins/autotest/quick/quicktest_utils.h
+++ b/src/plugins/autotest/quick/quicktest_utils.h
@@ -30,11 +30,14 @@
namespace Core { class Id; }
namespace Autotest {
+
+class ITestFramework;
+
namespace Internal {
namespace QuickTestUtils {
bool isQuickTestMacro(const QByteArray &macro);
-QHash<QString, QString> proFilesForQmlFiles(const Core::Id &id, const QStringList &files);
+QHash<QString, QString> proFilesForQmlFiles(ITestFramework *framework, const QStringList &files);
} // namespace QuickTestUtils
} // namespace Internal
diff --git a/src/plugins/autotest/quick/quicktestconfiguration.cpp b/src/plugins/autotest/quick/quicktestconfiguration.cpp
index 57d075fe7d..e61c4f12d8 100644
--- a/src/plugins/autotest/quick/quicktestconfiguration.cpp
+++ b/src/plugins/autotest/quick/quicktestconfiguration.cpp
@@ -29,13 +29,14 @@
#include "../qtest/qttestsettings.h"
#include "../qtest/qttest_utils.h"
#include "../autotestplugin.h"
-#include "../testframeworkmanager.h"
+#include "../itestframework.h"
#include "../testsettings.h"
namespace Autotest {
namespace Internal {
-QuickTestConfiguration::QuickTestConfiguration()
+QuickTestConfiguration::QuickTestConfiguration(ITestFramework *framework)
+ : DebuggableTestConfiguration(framework)
{
setMixedDebugging(true);
}
@@ -43,10 +44,7 @@ QuickTestConfiguration::QuickTestConfiguration()
TestOutputReader *QuickTestConfiguration::outputReader(const QFutureInterface<TestResultPtr> &fi,
QProcess *app) const
{
- static const Core::Id id
- = Core::Id(Constants::FRAMEWORK_PREFIX).withSuffix(QtTest::Constants::FRAMEWORK_NAME);
- TestFrameworkManager *manager = TestFrameworkManager::instance();
- auto qtSettings = qSharedPointerCast<QtTestSettings>(manager->settingsForTestFramework(id));
+ auto qtSettings = dynamic_cast<QtTestSettings *>(framework()->frameworkSettings());
const QtTestOutputReader::OutputMode mode = qtSettings && qtSettings->useXMLOutput
? QtTestOutputReader::XML
: QtTestOutputReader::PlainText;
@@ -56,9 +54,6 @@ TestOutputReader *QuickTestConfiguration::outputReader(const QFutureInterface<Te
QStringList QuickTestConfiguration::argumentsForTestRunner(QStringList *omitted) const
{
- static const Core::Id id
- = Core::Id(Constants::FRAMEWORK_PREFIX).withSuffix(QtTest::Constants::FRAMEWORK_NAME);
-
QStringList arguments;
if (AutotestPlugin::settings()->processArgs) {
arguments.append(QTestUtils::filterInterfering
@@ -66,9 +61,8 @@ QStringList QuickTestConfiguration::argumentsForTestRunner(QStringList *omitted)
omitted, true));
}
- TestFrameworkManager *manager = TestFrameworkManager::instance();
- auto qtSettings = qSharedPointerCast<QtTestSettings>(manager->settingsForTestFramework(id));
- if (qtSettings.isNull())
+ auto qtSettings = dynamic_cast<QtTestSettings *>(framework()->frameworkSettings());
+ if (!qtSettings)
return arguments;
if (qtSettings->useXMLOutput)
arguments << "-xml";
diff --git a/src/plugins/autotest/quick/quicktestconfiguration.h b/src/plugins/autotest/quick/quicktestconfiguration.h
index 286b891741..ae1e46797c 100644
--- a/src/plugins/autotest/quick/quicktestconfiguration.h
+++ b/src/plugins/autotest/quick/quicktestconfiguration.h
@@ -33,7 +33,7 @@ namespace Internal {
class QuickTestConfiguration : public DebuggableTestConfiguration
{
public:
- QuickTestConfiguration();
+ explicit QuickTestConfiguration(ITestFramework *framework);
TestOutputReader *outputReader(const QFutureInterface<TestResultPtr> &fi,
QProcess *app) const override;
QStringList argumentsForTestRunner(QStringList *omitted = nullptr) const override;
diff --git a/src/plugins/autotest/quick/quicktestframework.cpp b/src/plugins/autotest/quick/quicktestframework.cpp
index 81642ae6fd..50d46c7e1e 100644
--- a/src/plugins/autotest/quick/quicktestframework.cpp
+++ b/src/plugins/autotest/quick/quicktestframework.cpp
@@ -27,17 +27,20 @@
#include "quicktestparser.h"
#include "quicktesttreeitem.h"
+#include "../testframeworkmanager.h"
+#include "../qtest/qttestconstants.h"
+
namespace Autotest {
namespace Internal {
-ITestParser *QuickTestFramework::createTestParser() const
+ITestParser *QuickTestFramework::createTestParser()
{
- return new QuickTestParser;
+ return new QuickTestParser(this);
}
-TestTreeItem *QuickTestFramework::createRootNode() const
+TestTreeItem *QuickTestFramework::createRootNode()
{
- return new QuickTestTreeItem(QCoreApplication::translate("QuickTestFramework", "Quick Test"),
+ return new QuickTestTreeItem(this, QCoreApplication::translate("QuickTestFramework", "Quick Test"),
QString(), TestTreeItem::Root);
}
@@ -51,5 +54,13 @@ unsigned QuickTestFramework::priority() const
return 5;
}
+IFrameworkSettings *QuickTestFramework::frameworkSettings()
+{
+ static const Core::Id id
+ = Core::Id(Constants::FRAMEWORK_PREFIX).withSuffix(QtTest::Constants::FRAMEWORK_NAME);
+ ITestFramework *qtTestFramework = TestFrameworkManager::frameworkForId(id);
+ return qtTestFramework->frameworkSettings();
+}
+
} // namespace Internal
} // namespace Autotest
diff --git a/src/plugins/autotest/quick/quicktestframework.h b/src/plugins/autotest/quick/quicktestframework.h
index 80befb53d1..a50b224c8d 100644
--- a/src/plugins/autotest/quick/quicktestframework.h
+++ b/src/plugins/autotest/quick/quicktestframework.h
@@ -44,10 +44,11 @@ public:
QuickTestFramework() : ITestFramework(true) {}
const char *name() const override;
unsigned priority() const override;
+ IFrameworkSettings *frameworkSettings() override;
protected:
- ITestParser *createTestParser() const override;
- TestTreeItem *createRootNode() const override;
+ ITestParser *createTestParser() override;
+ TestTreeItem *createRootNode() override;
};
} // namespace Internal
diff --git a/src/plugins/autotest/quick/quicktestparser.cpp b/src/plugins/autotest/quick/quicktestparser.cpp
index 478735048c..5ee01e1c90 100644
--- a/src/plugins/autotest/quick/quicktestparser.cpp
+++ b/src/plugins/autotest/quick/quicktestparser.cpp
@@ -49,7 +49,7 @@ TestTreeItem *QuickTestParseResult::createTestTreeItem() const
if (itemType == TestTreeItem::Root || itemType == TestTreeItem::TestDataTag)
return nullptr;
- QuickTestTreeItem *item = new QuickTestTreeItem(name, fileName, itemType);
+ QuickTestTreeItem *item = new QuickTestTreeItem(framework, name, fileName, itemType);
item->setProFile(proFile);
item->setLine(line);
item->setColumn(column);
@@ -179,7 +179,7 @@ QList<Document::Ptr> QuickTestParser::scanDirectoryForQuickTestQmlFiles(const QS
static bool checkQmlDocumentForQuickTestCode(QFutureInterface<TestParseResultPtr> futureInterface,
const Document::Ptr &qmlJSDoc,
- const Core::Id &id,
+ ITestFramework *framework,
const QString &proFile = QString())
{
if (qmlJSDoc.isNull())
@@ -197,7 +197,7 @@ static bool checkQmlDocumentForQuickTestCode(QFutureInterface<TestParseResultPtr
for (const QuickTestCaseSpec &testCase : testCases) {
const QString testCaseName = testCase.m_caseName;
- QuickTestParseResult *parseResult = new QuickTestParseResult(id);
+ QuickTestParseResult *parseResult = new QuickTestParseResult(framework);
parseResult->proFile = proFile;
parseResult->itemType = TestTreeItem::TestCase;
if (!testCaseName.isEmpty()) {
@@ -208,7 +208,7 @@ static bool checkQmlDocumentForQuickTestCode(QFutureInterface<TestParseResultPtr
}
for (auto function : testCase.m_functions) {
- QuickTestParseResult *funcResult = new QuickTestParseResult(id);
+ QuickTestParseResult *funcResult = new QuickTestParseResult(framework);
funcResult->name = function.m_functionName;
funcResult->displayName = function.m_functionName;
funcResult->itemType = function.m_locationAndType.m_type;
@@ -227,7 +227,7 @@ static bool checkQmlDocumentForQuickTestCode(QFutureInterface<TestParseResultPtr
bool QuickTestParser::handleQtQuickTest(QFutureInterface<TestParseResultPtr> futureInterface,
CPlusPlus::Document::Ptr document,
- const Core::Id &id)
+ ITestFramework *framework)
{
const CppTools::CppModelManager *modelManager = CppTools::CppModelManager::instance();
if (quickTestName(document, m_cppSnapshot).isEmpty())
@@ -250,7 +250,7 @@ bool QuickTestParser::handleQtQuickTest(QFutureInterface<TestParseResultPtr> fut
for (const Document::Ptr &qmlJSDoc : qmlDocs) {
if (futureInterface.isCanceled())
break;
- result |= checkQmlDocumentForQuickTestCode(futureInterface, qmlJSDoc, id, proFile);
+ result |= checkQmlDocumentForQuickTestCode(futureInterface, qmlJSDoc, framework, proFile);
}
return result;
}
@@ -269,7 +269,7 @@ void QuickTestParser::handleDirectoryChanged(const QString &directory)
{
const QMap<QString, QDateTime> &filesAndDates = qmlFilesWithMTime(directory);
const QMap<QString, QDateTime> &watched = m_watchedFiles.value(directory);
- const QStringList &keys = watched.keys();
+ const QList<QString> &keys = watched.keys();
if (filesAndDates.keys() != keys) { // removed or added files
m_watchedFiles[directory] = filesAndDates;
TestTreeModel::instance()->parser()->emitUpdateTestTree(this);
@@ -298,8 +298,8 @@ void QuickTestParser::doUpdateWatchPaths(const QStringList &directories)
}
}
-QuickTestParser::QuickTestParser()
- : CppParser()
+QuickTestParser::QuickTestParser(ITestFramework *framework)
+ : CppParser(framework)
{
connect(ProjectExplorer::SessionManager::instance(),
&ProjectExplorer::SessionManager::startupProjectChanged, [this] {
@@ -319,7 +319,7 @@ void QuickTestParser::init(const QStringList &filesToParse, bool fullParse)
m_qmlSnapshot = QmlJSTools::Internal::ModelManager::instance()->snapshot();
if (!fullParse) {
// in a full parse we get the correct entry points by the respective main
- m_proFilesForQmlFiles = QuickTestUtils::proFilesForQmlFiles(id(), filesToParse);
+ m_proFilesForQmlFiles = QuickTestUtils::proFilesForQmlFiles(framework(), filesToParse);
// get rid of cached main cpp files that are going to get processed anyhow
for (const QString &file : filesToParse) {
if (m_mainCppFiles.contains(file)) {
@@ -350,14 +350,14 @@ bool QuickTestParser::processDocument(QFutureInterface<TestParseResultPtr> futur
if (proFile.isEmpty())
return false;
Document::Ptr qmlJSDoc = m_qmlSnapshot.document(fileName);
- return checkQmlDocumentForQuickTestCode(futureInterface, qmlJSDoc, id(), proFile);
+ return checkQmlDocumentForQuickTestCode(futureInterface, qmlJSDoc, framework(), proFile);
}
if (!m_cppSnapshot.contains(fileName) || !selectedForBuilding(fileName))
return false;
CPlusPlus::Document::Ptr document = m_cppSnapshot.find(fileName).value();
if (!includesQtQuickTest(document, m_cppSnapshot))
return false;
- return handleQtQuickTest(futureInterface, document, id());
+ return handleQtQuickTest(futureInterface, document, framework());
}
QString QuickTestParser::projectFileForMainCppFile(const QString &fileName) const
diff --git a/src/plugins/autotest/quick/quicktestparser.h b/src/plugins/autotest/quick/quicktestparser.h
index c05fa607dd..21e7667832 100644
--- a/src/plugins/autotest/quick/quicktestparser.h
+++ b/src/plugins/autotest/quick/quicktestparser.h
@@ -37,7 +37,7 @@ namespace Internal {
class QuickTestParseResult : public TestParseResult
{
public:
- explicit QuickTestParseResult(const Core::Id &id) : TestParseResult(id) {}
+ explicit QuickTestParseResult(ITestFramework *framework) : TestParseResult(framework) {}
TestTreeItem *createTestTreeItem() const override;
};
@@ -45,7 +45,7 @@ class QuickTestParser : public QObject, public CppParser
{
Q_OBJECT
public:
- QuickTestParser();
+ explicit QuickTestParser(ITestFramework *framework);
void init(const QStringList &filesToParse, bool fullParse) override;
void release() override;
bool processDocument(QFutureInterface<TestParseResultPtr> futureInterface,
@@ -55,7 +55,7 @@ signals:
void updateWatchPaths(const QStringList &directories) const;
private:
bool handleQtQuickTest(QFutureInterface<TestParseResultPtr> futureInterface,
- CPlusPlus::Document::Ptr document, const Core::Id &id);
+ CPlusPlus::Document::Ptr document, ITestFramework *framework);
void handleDirectoryChanged(const QString &directory);
void doUpdateWatchPaths(const QStringList &directories);
QList<QmlJS::Document::Ptr> scanDirectoryForQuickTestQmlFiles(const QString &srcDir) const;
diff --git a/src/plugins/autotest/quick/quicktesttreeitem.cpp b/src/plugins/autotest/quick/quicktesttreeitem.cpp
index bb09159af1..5274a27099 100644
--- a/src/plugins/autotest/quick/quicktesttreeitem.cpp
+++ b/src/plugins/autotest/quick/quicktesttreeitem.cpp
@@ -38,7 +38,7 @@ namespace Internal {
TestTreeItem *QuickTestTreeItem::copyWithoutChildren()
{
- QuickTestTreeItem *copied = new QuickTestTreeItem;
+ QuickTestTreeItem *copied = new QuickTestTreeItem(framework());
copied->copyBasicDataFrom(this);
return copied;
}
@@ -137,7 +137,7 @@ TestConfiguration *QuickTestTreeItem::testConfiguration() const
if (child->type() == TestTreeItem::TestFunction)
testFunctions << testName + "::" + child->name();
});
- config = new QuickTestConfiguration;
+ config = new QuickTestConfiguration(framework());
config->setTestCases(testFunctions);
config->setProjectFile(proFile());
config->setProject(project);
@@ -146,7 +146,7 @@ TestConfiguration *QuickTestTreeItem::testConfiguration() const
case TestFunction: {
TestTreeItem *parent = parentItem();
QStringList testFunction(parent->name() + "::" + name());
- config = new QuickTestConfiguration;
+ config = new QuickTestConfiguration(framework());
config->setTestCases(testFunction);
config->setProjectFile(parent->proFile());
config->setProject(project);
@@ -186,7 +186,7 @@ static void testConfigurationFromCheckState(const TestTreeItem *item,
oldFunctions << testFunctions;
tc->setTestCases(oldFunctions);
} else {
- tc = new QuickTestConfiguration;
+ tc = new QuickTestConfiguration(item->framework());
tc->setTestCases(testFunctions);
tc->setProjectFile(item->proFile());
tc->setProject(ProjectExplorer::SessionManager::startupProject());
@@ -244,7 +244,7 @@ QList<TestConfiguration *> QuickTestTreeItem::getAllTestConfigurations() const
});
// create TestConfiguration for each project file
for (auto it = testsForProfile.begin(), end = testsForProfile.end(); it != end; ++it) {
- QuickTestConfiguration *tc = new QuickTestConfiguration;
+ QuickTestConfiguration *tc = new QuickTestConfiguration(framework());
tc->setTestCaseCount(it.value().testCount);
tc->setProjectFile(it.key());
tc->setProject(project);
@@ -318,7 +318,7 @@ TestTreeItem *QuickTestTreeItem::find(const TestParseResult *result)
case Root:
if (result->name.isEmpty())
return unnamedQuickTests();
- if (TestFrameworkManager::instance()->groupingEnabled(result->frameworkId)) {
+ if (result->framework->grouping()) {
const QString path = QFileInfo(result->fileName).absolutePath();
TestTreeItem *group = findFirstLevelChild([path](TestTreeItem *group) {
return group->filePath() == path;
@@ -404,7 +404,7 @@ TestTreeItem *QuickTestTreeItem::createParentGroupNode() const
{
const QFileInfo fileInfo(filePath());
const QFileInfo base(fileInfo.absolutePath());
- return new QuickTestTreeItem(base.baseName(), fileInfo.absolutePath(), TestTreeItem::GroupNode);
+ return new QuickTestTreeItem(framework(), base.baseName(), fileInfo.absolutePath(), TestTreeItem::GroupNode);
}
bool QuickTestTreeItem::isGroupable() const
@@ -430,14 +430,10 @@ QSet<QString> QuickTestTreeItem::internalTargets() const
void QuickTestTreeItem::markForRemovalRecursively(const QString &filePath)
{
- static const Core::Id id = Core::Id(Constants::FRAMEWORK_PREFIX).withSuffix(
- QuickTest::Constants::FRAMEWORK_NAME);
- TestTreeItem::markForRemovalRecursively(filePath);
- auto parser = dynamic_cast<QuickTestParser *>(TestFrameworkManager::instance()
- ->testParserForTestFramework(id));
+ auto parser = dynamic_cast<QuickTestParser *>(framework()->testParser());
const QString proFile = parser->projectFileForMainCppFile(filePath);
if (!proFile.isEmpty()) {
- TestTreeItem *root = TestFrameworkManager::instance()->rootNodeForTestFramework(id);
+ TestTreeItem *root = framework()->rootNode();
root->forAllChildren([proFile](TestTreeItem *it) {
if (it->proFile() == proFile)
it->markForRemoval(true);
diff --git a/src/plugins/autotest/quick/quicktesttreeitem.h b/src/plugins/autotest/quick/quicktesttreeitem.h
index f99db4ce54..050c7c4dd1 100644
--- a/src/plugins/autotest/quick/quicktesttreeitem.h
+++ b/src/plugins/autotest/quick/quicktesttreeitem.h
@@ -33,8 +33,12 @@ namespace Internal {
class QuickTestTreeItem : public TestTreeItem
{
public:
- explicit QuickTestTreeItem(const QString &name = QString(), const QString &filePath = QString(),
- Type type = Root) : TestTreeItem(name, filePath, type) {}
+ explicit QuickTestTreeItem(ITestFramework *framework,
+ const QString &name = QString(),
+ const QString &filePath = QString(),
+ Type type = Root)
+ : TestTreeItem(framework, name, filePath, type)
+ {}
TestTreeItem *copyWithoutChildren() override;
QVariant data(int column, int role) const override;
diff --git a/src/plugins/autotest/testcodeparser.cpp b/src/plugins/autotest/testcodeparser.cpp
index deb5085ade..c8c74075ae 100644
--- a/src/plugins/autotest/testcodeparser.cpp
+++ b/src/plugins/autotest/testcodeparser.cpp
@@ -55,10 +55,8 @@ namespace Internal {
using namespace ProjectExplorer;
-TestCodeParser::TestCodeParser(TestTreeModel *parent)
- : QObject(parent),
- m_model(parent),
- m_threadPool(new QThreadPool(this))
+TestCodeParser::TestCodeParser()
+ : m_threadPool(new QThreadPool(this))
{
// connect to ProgressManager to postpone test parsing when CppModelManager is parsing
auto progressManager = qobject_cast<Core::ProgressManager *>(Core::ProgressManager::instance());
@@ -110,7 +108,7 @@ void TestCodeParser::setState(State state)
}
}
-void TestCodeParser::syncTestFrameworks(const QList<Core::Id> &frameworkIds)
+void TestCodeParser::syncTestFrameworks(const QList<ITestFramework *> &frameworks)
{
if (m_parserState != Idle) {
// there's a running parse
@@ -119,10 +117,9 @@ void TestCodeParser::syncTestFrameworks(const QList<Core::Id> &frameworkIds)
Core::ProgressManager::instance()->cancelTasks(Constants::TASK_PARSE);
}
m_testCodeParsers.clear();
- TestFrameworkManager *frameworkManager = TestFrameworkManager::instance();
- qCDebug(LOG) << "Setting" << frameworkIds << "as current parsers";
- for (const Core::Id &id : frameworkIds) {
- ITestParser *testParser = frameworkManager->testParserForTestFramework(id);
+ qCDebug(LOG) << "Setting" << frameworks << "as current parsers";
+ for (ITestFramework *framework : frameworks) {
+ ITestParser *testParser = framework->testParser();
QTC_ASSERT(testParser, continue);
m_testCodeParsers.append(testParser);
}
@@ -133,7 +130,7 @@ void TestCodeParser::emitUpdateTestTree(ITestParser *parser)
if (m_testCodeParsers.isEmpty())
return;
if (parser)
- m_updateParsers.insert(parser->id());
+ m_updateParsers.insert(parser->framework());
else
m_updateParsers.clear();
if (m_singleShotScheduled) {
@@ -146,18 +143,18 @@ void TestCodeParser::emitUpdateTestTree(ITestParser *parser)
QTimer::singleShot(1000, this, [this]() { updateTestTree(m_updateParsers); });
}
-void TestCodeParser::updateTestTree(const QSet<Core::Id> &frameworkIds)
+void TestCodeParser::updateTestTree(const QSet<ITestFramework *> &frameworks)
{
m_singleShotScheduled = false;
if (m_codeModelParsing) {
m_fullUpdatePostponed = true;
m_partialUpdatePostponed = false;
m_postponedFiles.clear();
- if (frameworkIds.isEmpty()) {
+ if (frameworks.isEmpty()) {
m_updateParsers.clear();
} else {
- for (const Core::Id &id : frameworkIds)
- m_updateParsers.insert(id);
+ for (ITestFramework *framework : frameworks)
+ m_updateParsers.insert(framework);
}
return;
}
@@ -167,11 +164,8 @@ void TestCodeParser::updateTestTree(const QSet<Core::Id> &frameworkIds)
m_fullUpdatePostponed = false;
qCDebug(LOG) << "calling scanForTests (updateTestTree)";
- QList<Core::Id> sortedFrameworks = Utils::toList(frameworkIds);
- Utils::sort(sortedFrameworks, [manager = TestFrameworkManager::instance()]
- (const Core::Id &lhs, const Core::Id &rhs) {
- return manager->priority(lhs) < manager->priority(rhs);
- });
+ TestFrameworks sortedFrameworks = Utils::toList(frameworks);
+ Utils::sort(sortedFrameworks, &ITestFramework::priority);
scanForTests(QStringList(), sortedFrameworks);
}
@@ -210,7 +204,6 @@ void TestCodeParser::onQmlDocumentUpdated(const QmlJS::Document::Ptr &document)
void TestCodeParser::onStartupProjectChanged(Project *project)
{
- m_model->synchronizeTestFrameworks(); // we might have project settings
if (m_parserState == FullParse || m_parserState == PartialParse) {
qCDebug(LOG) << "Canceling scanForTest (startup project changed)";
Core::ProgressManager::instance()->cancelTasks(Constants::TASK_PARSE);
@@ -307,7 +300,7 @@ static void parseFileForTests(const QList<ITestParser *> &parsers,
}
}
-void TestCodeParser::scanForTests(const QStringList &fileList, const QList<Core::Id> &parserIds)
+void TestCodeParser::scanForTests(const QStringList &fileList, const QList<ITestFramework *> &parsers)
{
if (m_parserState == Shutdown || m_testCodeParsers.isEmpty())
return;
@@ -341,37 +334,33 @@ void TestCodeParser::scanForTests(const QStringList &fileList, const QList<Core:
}
parsingHasFailed = false;
- TestFrameworkManager *manager = TestFrameworkManager::instance();
if (isFullParse) {
// remove qml files as they will be found automatically by the referencing cpp file
list = Utils::filtered(list, [] (const QString &fn) {
return !fn.endsWith(".qml");
});
- if (!parserIds.isEmpty()) {
- for (const Core::Id &id : parserIds)
- manager->rootNodeForTestFramework(id)->markForRemovalRecursively(true);
+ if (!parsers.isEmpty()) {
+ for (ITestFramework *framework : parsers)
+ framework->rootNode()->markForRemovalRecursively(true);
} else {
- m_model->markAllForRemoval();
+ emit requestRemoveAll();
}
- } else if (!parserIds.isEmpty()) {
- for (const Core::Id &id : parserIds) {
- TestTreeItem *root = manager->rootNodeForTestFramework(id);
+ } else if (!parsers.isEmpty()) {
+ for (ITestFramework *framework : parsers) {
for (const QString &filePath : list)
- root->markForRemovalRecursively(filePath);
+ framework->rootNode()->markForRemovalRecursively(filePath);
}
} else {
for (const QString &filePath : list)
- m_model->markForRemoval(filePath);
+ emit requestRemoval(filePath);
}
QTC_ASSERT(!(isFullParse && list.isEmpty()), onFinished(); return);
// use only a single parser or all current active?
const QList<ITestParser *> codeParsers
- = parserIds.isEmpty() ? m_testCodeParsers
- : Utils::transform(parserIds, [](const Core::Id &id) {
- return TestFrameworkManager::instance()->testParserForTestFramework(id);
- });
+ = parsers.isEmpty() ? m_testCodeParsers
+ : Utils::transform(parsers, &ITestFramework::testParser);
qCDebug(LOG) << QDateTime::currentDateTime().toString("hh:mm:ss.zzz") << "StartParsing";
for (ITestParser *parser : codeParsers)
parser->init(list, isFullParse);
diff --git a/src/plugins/autotest/testcodeparser.h b/src/plugins/autotest/testcodeparser.h
index 867a6349e6..a480c78f81 100644
--- a/src/plugins/autotest/testcodeparser.h
+++ b/src/plugins/autotest/testcodeparser.h
@@ -43,6 +43,9 @@ class QThreadPool;
QT_END_NAMESPACE
namespace Autotest {
+
+class ITestFramework;
+
namespace Internal {
class TestCodeParser : public QObject
@@ -56,12 +59,13 @@ public:
Shutdown
};
- explicit TestCodeParser(TestTreeModel *parent = nullptr);
+ TestCodeParser();
+
void setState(State state);
State state() const { return m_parserState; }
bool isParsing() const { return m_parserState == PartialParse || m_parserState == FullParse; }
void setDirty() { m_dirty = true; }
- void syncTestFrameworks(const QList<Core::Id> &frameworkIds);
+ void syncTestFrameworks(const QList<ITestFramework *> &frameworks);
#ifdef WITH_TESTS
bool furtherParsingExpected() const
{ return m_singleShotScheduled || m_fullUpdatePostponed || m_partialUpdatePostponed; }
@@ -73,10 +77,12 @@ signals:
void parsingStarted();
void parsingFinished();
void parsingFailed();
+ void requestRemoval(const QString &filePath);
+ void requestRemoveAll();
public:
void emitUpdateTestTree(ITestParser *parser = nullptr);
- void updateTestTree(const QSet<Core::Id> &frameworkIds = {});
+ void updateTestTree(const QSet<ITestFramework *> &frameworks = {});
void onCppDocumentUpdated(const CPlusPlus::Document::Ptr &document);
void onQmlDocumentUpdated(const QmlJS::Document::Ptr &document);
void onStartupProjectChanged(ProjectExplorer::Project *project);
@@ -86,7 +92,7 @@ public:
private:
bool postponed(const QStringList &fileList);
void scanForTests(const QStringList &fileList = QStringList(),
- const QList<Core::Id> &parserIds = {});
+ const QList<ITestFramework *> &parserIds = {});
// qml files must be handled slightly different
void onDocumentUpdated(const QString &fileName, bool isQmlFile = false);
@@ -97,8 +103,6 @@ private:
void parsePostponedFiles();
void releaseParserInternals();
- TestTreeModel *m_model;
-
bool m_codeModelParsing = false;
bool m_fullUpdatePostponed = false;
bool m_partialUpdatePostponed = false;
@@ -110,7 +114,7 @@ private:
QFutureWatcher<TestParseResultPtr> m_futureWatcher;
QList<ITestParser *> m_testCodeParsers; // ptrs are still owned by TestFrameworkManager
QTimer m_reparseTimer;
- QSet<Core::Id> m_updateParsers;
+ QSet<ITestFramework *> m_updateParsers;
QThreadPool *m_threadPool = nullptr;
};
diff --git a/src/plugins/autotest/testconfiguration.cpp b/src/plugins/autotest/testconfiguration.cpp
index 38704fe07c..96a5a842db 100644
--- a/src/plugins/autotest/testconfiguration.cpp
+++ b/src/plugins/autotest/testconfiguration.cpp
@@ -31,6 +31,7 @@
#include <cpptools/projectinfo.h>
#include <projectexplorer/buildconfiguration.h>
+#include <projectexplorer/buildsystem.h>
#include <projectexplorer/buildtargetinfo.h>
#include <projectexplorer/deploymentdata.h>
#include <projectexplorer/environmentaspect.h>
@@ -48,6 +49,11 @@ using namespace Utils;
namespace Autotest {
+TestConfiguration::TestConfiguration(ITestFramework *framework)
+ : m_framework(framework)
+{
+}
+
TestConfiguration::~TestConfiguration()
{
m_testCases.clear();
@@ -137,8 +143,9 @@ void TestConfiguration::completeTestInformation(TestRunMode runMode)
const QSet<QString> buildSystemTargets = m_buildTargets;
qCDebug(LOG) << "BuildSystemTargets\n " << buildSystemTargets;
+ const QList<BuildTargetInfo> buildTargets = target->buildSystem()->applicationTargets();
BuildTargetInfo targetInfo
- = Utils::findOrDefault(target->applicationTargets(),
+ = Utils::findOrDefault(buildTargets,
[&buildSystemTargets] (const BuildTargetInfo &bti) {
return buildSystemTargets.contains(bti.buildKey);
});
@@ -146,7 +153,6 @@ void TestConfiguration::completeTestInformation(TestRunMode runMode)
// there would be no BuildTargetInfo that could match
if (targetInfo.targetFilePath.isEmpty()) {
qCDebug(LOG) << "BuildTargetInfos";
- const QList<BuildTargetInfo> buildTargets = target->applicationTargets();
// if there is only one build target just use it (but be honest that we're deducing)
if (buildTargets.size() == 1) {
targetInfo = buildTargets.first();
@@ -350,4 +356,9 @@ bool TestConfiguration::hasExecutable() const
return !m_runnable.executable.isEmpty();
}
+ITestFramework *TestConfiguration::framework() const
+{
+ return m_framework;
+}
+
} // namespace Autotest
diff --git a/src/plugins/autotest/testconfiguration.h b/src/plugins/autotest/testconfiguration.h
index 56533f8a52..2c8d4046a7 100644
--- a/src/plugins/autotest/testconfiguration.h
+++ b/src/plugins/autotest/testconfiguration.h
@@ -45,6 +45,7 @@ namespace Internal {
class TestRunConfiguration;
} // namespace Internal
+class ITestFramework;
class TestOutputReader;
class TestResult;
enum class TestRunMode;
@@ -54,7 +55,7 @@ using TestResultPtr = QSharedPointer<TestResult>;
class TestConfiguration
{
public:
- explicit TestConfiguration() = default;
+ explicit TestConfiguration(ITestFramework *framework);
virtual ~TestConfiguration();
void completeTestInformation(TestRunMode runMode);
@@ -73,6 +74,7 @@ public:
void setInternalTargets(const QSet<QString> &targets);
void setOriginalRunConfiguration(ProjectExplorer::RunConfiguration *runConfig);
+ ITestFramework *framework() const;
QStringList testCases() const { return m_testCases; }
int testCaseCount() const { return m_testCaseCount; }
QString executableFilePath() const;
@@ -95,7 +97,9 @@ public:
QProcess *app) const = 0;
virtual QStringList argumentsForTestRunner(QStringList *omitted = nullptr) const = 0;
virtual Utils::Environment filteredEnvironment(const Utils::Environment &original) const = 0;
+
private:
+ ITestFramework *m_framework;
QStringList m_testCases;
int m_testCaseCount = 0;
QString m_projectFile;
@@ -113,8 +117,8 @@ private:
class DebuggableTestConfiguration : public TestConfiguration
{
public:
- explicit DebuggableTestConfiguration(TestRunMode runMode = TestRunMode::Run)
- : m_runMode(runMode) {}
+ explicit DebuggableTestConfiguration(ITestFramework *framework, TestRunMode runMode = TestRunMode::Run)
+ : TestConfiguration(framework), m_runMode(runMode) {}
void setRunMode(TestRunMode mode) { m_runMode = mode; }
TestRunMode runMode() const { return m_runMode; }
diff --git a/src/plugins/autotest/testframeworkmanager.cpp b/src/plugins/autotest/testframeworkmanager.cpp
index 43eb59d847..d7f1354f30 100644
--- a/src/plugins/autotest/testframeworkmanager.cpp
+++ b/src/plugins/autotest/testframeworkmanager.cpp
@@ -27,22 +27,13 @@
#include "autotestconstants.h"
#include "autotestplugin.h"
#include "iframeworksettings.h"
-#include "itestparser.h"
-#include "testrunner.h"
#include "testsettings.h"
-#include "testtreeitem.h"
-#include "testtreemodel.h"
-
-#include <coreplugin/dialogs/ioptionspage.h>
#include <utils/algorithm.h>
#include <utils/qtcassert.h>
-#include <QLoggingCategory>
#include <QSettings>
-static Q_LOGGING_CATEGORY(LOG, "qtc.autotest.frameworkmanager", QtWarningMsg)
-
using namespace Core;
namespace Autotest {
@@ -51,178 +42,53 @@ static TestFrameworkManager *s_instance = nullptr;
TestFrameworkManager::TestFrameworkManager()
{
- m_testTreeModel = TestTreeModel::instance();
- m_testRunner = Internal::TestRunner::instance();
s_instance = this;
}
-TestFrameworkManager *TestFrameworkManager::instance()
-{
- if (!s_instance)
- return new TestFrameworkManager;
- return s_instance;
-}
-
TestFrameworkManager::~TestFrameworkManager()
{
- delete m_testRunner;
- delete m_testTreeModel;
- qDeleteAll(m_frameworkSettingsPages);
- m_frameworkSettingsPages.clear();
- for (ITestFramework *framework : m_registeredFrameworks.values())
- delete framework;
+ qDeleteAll(m_registeredFrameworks);
+ s_instance = nullptr;
}
bool TestFrameworkManager::registerTestFramework(ITestFramework *framework)
{
QTC_ASSERT(framework, return false);
- Id id = Id(Constants::FRAMEWORK_PREFIX).withSuffix(framework->name());
- QTC_ASSERT(!m_registeredFrameworks.contains(id), delete framework; return false);
+ QTC_ASSERT(!m_registeredFrameworks.contains(framework), return false);
// TODO check for unique priority before registering
- qCDebug(LOG) << "Registering" << id;
- m_registeredFrameworks.insert(id, framework);
-
- if (framework->hasFrameworkSettings()) {
- QSharedPointer<IFrameworkSettings> frameworkSettings(framework->createFrameworkSettings());
- m_frameworkSettings.insert(id, frameworkSettings);
- if (auto page = framework->createSettingsPage(frameworkSettings))
- m_frameworkSettingsPages.append(page);
- }
+ m_registeredFrameworks.append(framework);
+ Utils::sort(m_registeredFrameworks, &ITestFramework::priority);
return true;
}
-void TestFrameworkManager::activateFrameworksFromSettings(QSharedPointer<Internal::TestSettings> settings)
-{
- FrameworkIterator it = m_registeredFrameworks.begin();
- FrameworkIterator end = m_registeredFrameworks.end();
- for ( ; it != end; ++it) {
- it.value()->setActive(settings->frameworks.value(it.key(), false));
- it.value()->setGrouping(settings->frameworksGrouping.value(it.key(), false));
- }
-}
-
-QString TestFrameworkManager::frameworkNameForId(const Id &id) const
-{
- ITestFramework *framework = m_registeredFrameworks.value(id, nullptr);
- return framework ? QString::fromLatin1(framework->name()) : QString();
-}
-
-QList<Id> TestFrameworkManager::registeredFrameworkIds() const
-{
- return m_registeredFrameworks.keys();
-}
-
-QList<Id> TestFrameworkManager::sortedRegisteredFrameworkIds() const
-{
- QList<Id> registered = m_registeredFrameworks.keys();
- Utils::sort(registered, [this] (const Id &lhs, const Id &rhs) {
- return m_registeredFrameworks[lhs]->priority() < m_registeredFrameworks[rhs]->priority();
- });
- qCDebug(LOG) << "Registered frameworks sorted by priority" << registered;
- return registered;
-}
-
-QList<Id> TestFrameworkManager::activeFrameworkIds() const
+void TestFrameworkManager::activateFrameworksFromSettings(const Internal::TestSettings *settings)
{
- QList<Id> active;
- FrameworkIterator it = m_registeredFrameworks.begin();
- FrameworkIterator end = m_registeredFrameworks.end();
- for ( ; it != end; ++it) {
- if (it.value()->active())
- active.append(it.key());
+ for (ITestFramework *framework : qAsConst(s_instance->m_registeredFrameworks)) {
+ framework->setActive(settings->frameworks.value(framework->id(), false));
+ framework->setGrouping(settings->frameworksGrouping.value(framework->id(), false));
}
- return active;
-}
-
-QList<Id> TestFrameworkManager::sortedActiveFrameworkIds() const
-{
- QList<Id> active = activeFrameworkIds();
- Utils::sort(active, [this] (const Id &lhs, const Id &rhs) {
- return m_registeredFrameworks[lhs]->priority() < m_registeredFrameworks[rhs]->priority();
- });
- qCDebug(LOG) << "Active frameworks sorted by priority" << active;
- return active;
-}
-
-TestTreeItem *TestFrameworkManager::rootNodeForTestFramework(const Id &frameworkId) const
-{
- ITestFramework *framework = m_registeredFrameworks.value(frameworkId, nullptr);
- return framework ? framework->rootNode() : nullptr;
}
-ITestParser *TestFrameworkManager::testParserForTestFramework(const Id &frameworkId) const
+TestFrameworks TestFrameworkManager::registeredFrameworks()
{
- ITestFramework *framework = m_registeredFrameworks.value(frameworkId, nullptr);
- if (!framework)
- return nullptr;
- ITestParser *testParser = framework->testParser();
- qCDebug(LOG) << "Setting" << frameworkId << "as Id for test parser";
- testParser->setId(frameworkId);
- return testParser;
+ return s_instance->m_registeredFrameworks;
}
-QSharedPointer<IFrameworkSettings> TestFrameworkManager::settingsForTestFramework(
- const Id &frameworkId) const
+ITestFramework *TestFrameworkManager::frameworkForId(Id frameworkId)
{
- return m_frameworkSettings.contains(frameworkId) ? m_frameworkSettings.value(frameworkId)
- : QSharedPointer<IFrameworkSettings>();
+ return Utils::findOrDefault(s_instance->m_registeredFrameworks,
+ [frameworkId](ITestFramework *framework) {
+ return framework->id() == frameworkId;
+ });
}
void TestFrameworkManager::synchronizeSettings(QSettings *s)
{
Internal::AutotestPlugin::settings()->fromSettings(s);
- for (const Id &id : m_frameworkSettings.keys()) {
- QSharedPointer<IFrameworkSettings> fSettings = settingsForTestFramework(id);
- if (!fSettings.isNull())
+ for (ITestFramework *framework : qAsConst(m_registeredFrameworks)) {
+ if (IFrameworkSettings *fSettings = framework->frameworkSettings())
fSettings->fromSettings(s);
}
}
-bool TestFrameworkManager::isActive(const Id &frameworkId) const
-{
- ITestFramework *framework = m_registeredFrameworks.value(frameworkId);
- return framework ? framework->active() : false;
-}
-
-bool TestFrameworkManager::groupingEnabled(const Id &frameworkId) const
-{
- ITestFramework *framework = m_registeredFrameworks.value(frameworkId);
- return framework ? framework->grouping() : false;
-}
-
-void TestFrameworkManager::setGroupingEnabledFor(const Id &frameworkId, bool enabled)
-{
- if (ITestFramework *framework = m_registeredFrameworks.value(frameworkId))
- framework->setGrouping(enabled);
-}
-
-QString TestFrameworkManager::groupingToolTip(const Id &frameworkId) const
-{
- if (ITestFramework *framework = m_registeredFrameworks.value(frameworkId))
- return framework->groupingToolTip();
- return QString();
-}
-
-bool TestFrameworkManager::hasActiveFrameworks() const
-{
- for (ITestFramework *framework : m_registeredFrameworks.values()) {
- if (framework->active())
- return true;
- }
- return false;
-}
-
-unsigned TestFrameworkManager::priority(const Id &frameworkId) const
-{
- if (ITestFramework *framework = m_registeredFrameworks.value(frameworkId))
- return framework->priority();
- return unsigned(-1);
-}
-
-Id ITestFramework::settingsId() const
-{
- return Core::Id(Constants::SETTINGSPAGE_PREFIX)
- .withSuffix(QString("%1.%2").arg(priority()).arg(QLatin1String(name())));
-}
-
} // namespace Autotest
diff --git a/src/plugins/autotest/testframeworkmanager.h b/src/plugins/autotest/testframeworkmanager.h
index fd0c4bea47..2975fb0c42 100644
--- a/src/plugins/autotest/testframeworkmanager.h
+++ b/src/plugins/autotest/testframeworkmanager.h
@@ -27,9 +27,6 @@
#include "itestframework.h"
-#include <QHash>
-#include <QSharedPointer>
-
QT_BEGIN_NAMESPACE
class QSettings;
QT_END_NAMESPACE
@@ -37,52 +34,26 @@ QT_END_NAMESPACE
namespace Core { class Id; }
namespace Autotest {
-
-class TestTreeItem;
-
namespace Internal {
-
-class TestRunner;
struct TestSettings;
}
-class IFrameworkSettings;
-class ITestParser;
-class TestTreeModel;
-
-class TestFrameworkManager
+class TestFrameworkManager final
{
+
public:
- static TestFrameworkManager *instance();
- virtual ~TestFrameworkManager();
+ TestFrameworkManager();
+ ~TestFrameworkManager();
+
bool registerTestFramework(ITestFramework *framework);
+ void synchronizeSettings(QSettings *s);
- void activateFrameworksFromSettings(QSharedPointer<Internal::TestSettings> settings);
- QString frameworkNameForId(const Core::Id &id) const;
- QList<Core::Id> registeredFrameworkIds() const;
- QList<Core::Id> sortedRegisteredFrameworkIds() const;
- QList<Core::Id> sortedActiveFrameworkIds() const;
+ static ITestFramework *frameworkForId(Core::Id frameworkId);
+ static void activateFrameworksFromSettings(const Internal::TestSettings *settings);
+ static TestFrameworks registeredFrameworks();
- TestTreeItem *rootNodeForTestFramework(const Core::Id &frameworkId) const;
- ITestParser *testParserForTestFramework(const Core::Id &frameworkId) const;
- QSharedPointer<IFrameworkSettings> settingsForTestFramework(const Core::Id &frameworkId) const;
- void synchronizeSettings(QSettings *s);
- bool isActive(const Core::Id &frameworkId) const;
- bool groupingEnabled(const Core::Id &frameworkId) const;
- void setGroupingEnabledFor(const Core::Id &frameworkId, bool enabled);
- QString groupingToolTip(const Core::Id &frameworkId) const;
- bool hasActiveFrameworks() const;
- unsigned priority(const Core::Id &frameworkId) const;
private:
- QList<Core::Id> activeFrameworkIds() const;
- explicit TestFrameworkManager();
- QHash<Core::Id, ITestFramework *> m_registeredFrameworks;
- QHash<Core::Id, QSharedPointer<IFrameworkSettings> > m_frameworkSettings;
- QVector<Core::IOptionsPage *> m_frameworkSettingsPages;
- TestTreeModel *m_testTreeModel;
- Internal::TestRunner *m_testRunner;
-
- typedef QHash<Core::Id, ITestFramework *>::ConstIterator FrameworkIterator;
+ TestFrameworks m_registeredFrameworks;
};
} // namespace Autotest
diff --git a/src/plugins/autotest/testnavigationwidget.cpp b/src/plugins/autotest/testnavigationwidget.cpp
index cf5db81364..7eb210eb76 100644
--- a/src/plugins/autotest/testnavigationwidget.cpp
+++ b/src/plugins/autotest/testnavigationwidget.cpp
@@ -76,7 +76,9 @@ TestNavigationWidget::TestNavigationWidget(QWidget *parent) :
QHBoxLayout *hLayout = new QHBoxLayout;
m_missingFrameworksWidget->setLayout(hLayout);
hLayout->addWidget(new QLabel(tr("No active test frameworks.")));
- m_missingFrameworksWidget->setVisible(!TestFrameworkManager::instance()->hasActiveFrameworks());
+ const bool hasActiveFrameworks = Utils::anyOf(TestFrameworkManager::registeredFrameworks(),
+ &ITestFramework::active);
+ m_missingFrameworksWidget->setVisible(!hasActiveFrameworks);
QVBoxLayout *layout = new QVBoxLayout;
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(0);
diff --git a/src/plugins/autotest/testprojectsettings.cpp b/src/plugins/autotest/testprojectsettings.cpp
index 47f672ea0f..3925671bde 100644
--- a/src/plugins/autotest/testprojectsettings.cpp
+++ b/src/plugins/autotest/testprojectsettings.cpp
@@ -36,6 +36,8 @@ namespace Internal {
static const char SK_ACTIVE_FRAMEWORKS[] = "AutoTest.ActiveFrameworks";
static const char SK_RUN_AFTER_BUILD[] = "AutoTest.RunAfterBuild";
+static Q_LOGGING_CATEGORY(LOG, "qtc.autotest.frameworkmanager", QtWarningMsg)
+
TestProjectSettings::TestProjectSettings(ProjectExplorer::Project *project)
: m_project(project)
{
@@ -60,9 +62,10 @@ void TestProjectSettings::setUseGlobalSettings(bool useGlobal)
void TestProjectSettings::activateFramework(const Core::Id &id, bool activate)
{
- if (m_activeTestFrameworks.value(id) != activate) {
- m_activeTestFrameworks[id] = activate;
- }
+ ITestFramework *framework = TestFrameworkManager::frameworkForId(id);
+ m_activeTestFrameworks[framework] = activate;
+ if (!activate)
+ framework->resetRootNode();
}
void TestProjectSettings::load()
@@ -70,21 +73,21 @@ void TestProjectSettings::load()
const QVariant useGlobal = m_project->namedSettings(Constants::SK_USE_GLOBAL);
m_useGlobalSettings = useGlobal.isValid() ? useGlobal.toBool() : true;
- TestFrameworkManager *frameworkManager = TestFrameworkManager::instance();
- const QList<Core::Id> registered = frameworkManager->sortedRegisteredFrameworkIds();
+ const TestFrameworks registered = TestFrameworkManager::registeredFrameworks();
+ qCDebug(LOG) << "Registered frameworks sorted by priority" << registered;
const QVariant activeFrameworks = m_project->namedSettings(SK_ACTIVE_FRAMEWORKS);
m_activeTestFrameworks.clear();
if (activeFrameworks.isValid()) {
const QMap<QString, QVariant> frameworksMap = activeFrameworks.toMap();
- for (const Core::Id &id : registered) {
- const QString idStr = id.toString();
- bool active = frameworksMap.value(idStr, frameworkManager->isActive(id)).toBool();
- m_activeTestFrameworks.insert(id, active);
+ for (ITestFramework *framework : registered) {
+ const Core::Id id = framework->id();
+ bool active = frameworksMap.value(id.toString(), framework->active()).toBool();
+ m_activeTestFrameworks.insert(framework, active);
}
} else {
- for (const Core::Id &id : registered)
- m_activeTestFrameworks.insert(id, frameworkManager->isActive(id));
+ for (ITestFramework *framework : registered)
+ m_activeTestFrameworks.insert(framework, framework->active());
}
const QVariant runAfterBuild = m_project->namedSettings(SK_RUN_AFTER_BUILD);
@@ -98,7 +101,7 @@ void TestProjectSettings::save()
QVariantMap activeFrameworks;
auto end = m_activeTestFrameworks.cend();
for (auto it = m_activeTestFrameworks.cbegin(); it != end; ++it)
- activeFrameworks.insert(it.key().toString(), it.value());
+ activeFrameworks.insert(it.key()->id().toString(), it.value());
m_project->setNamedSettings(SK_ACTIVE_FRAMEWORKS, activeFrameworks);
m_project->setNamedSettings(SK_RUN_AFTER_BUILD, int(m_runAfterBuild));
}
diff --git a/src/plugins/autotest/testprojectsettings.h b/src/plugins/autotest/testprojectsettings.h
index 595032ff0c..d0b35d5c5f 100644
--- a/src/plugins/autotest/testprojectsettings.h
+++ b/src/plugins/autotest/testprojectsettings.h
@@ -30,6 +30,9 @@
#include <projectexplorer/project.h>
namespace Autotest {
+
+class ITestFramework;
+
namespace Internal {
class TestProjectSettings : public QObject
@@ -43,9 +46,9 @@ public:
bool useGlobalSettings() const { return m_useGlobalSettings; }
void setRunAfterBuild(RunAfterBuildMode mode) {m_runAfterBuild = mode; }
RunAfterBuildMode runAfterBuild() const { return m_runAfterBuild; }
- void setActiveFrameworks(const QMap<Core::Id, bool> enabledFrameworks)
+ void setActiveFrameworks(const QMap<ITestFramework *, bool> enabledFrameworks)
{ m_activeTestFrameworks = enabledFrameworks; }
- QMap<Core::Id, bool> activeFrameworks() const { return m_activeTestFrameworks; }
+ QMap<ITestFramework *, bool> activeFrameworks() const { return m_activeTestFrameworks; }
void activateFramework(const Core::Id &id, bool activate);
private:
void load();
@@ -54,7 +57,7 @@ private:
ProjectExplorer::Project *m_project;
bool m_useGlobalSettings = true;
RunAfterBuildMode m_runAfterBuild = RunAfterBuildMode::None;
- QMap<Core::Id, bool> m_activeTestFrameworks;
+ QMap<ITestFramework *, bool> m_activeTestFrameworks;
};
} // namespace Internal
diff --git a/src/plugins/autotest/testrunner.cpp b/src/plugins/autotest/testrunner.cpp
index 6942759947..ac3a433304 100644
--- a/src/plugins/autotest/testrunner.cpp
+++ b/src/plugins/autotest/testrunner.cpp
@@ -82,14 +82,13 @@ static TestRunner *s_instance = nullptr;
TestRunner *TestRunner::instance()
{
- if (!s_instance)
- s_instance = new TestRunner;
return s_instance;
}
-TestRunner::TestRunner(QObject *parent) :
- QObject(parent)
+TestRunner::TestRunner()
{
+ s_instance = this;
+
connect(&m_futureWatcher, &QFutureWatcher<TestResultPtr>::resultReadyAt,
this, [this](int index) { emit testResultReady(m_futureWatcher.resultAt(index)); });
connect(&m_futureWatcher, &QFutureWatcher<TestResultPtr>::finished,
@@ -511,8 +510,8 @@ static void processOutput(TestOutputReader *outputreader, const QString &msg,
{
QByteArray message = msg.toUtf8();
switch (format) {
- case Utils::OutputFormat::StdErrFormatSameLine:
- case Utils::OutputFormat::StdOutFormatSameLine:
+ case Utils::OutputFormat::StdErrFormat:
+ case Utils::OutputFormat::StdOutFormat:
case Utils::OutputFormat::DebugFormat: {
static const QByteArray gdbSpecialOut = "Qt: gdb: -nograb added to command-line options.\n"
"\t Use the -dograb option to enforce grabbing.";
@@ -521,7 +520,7 @@ static void processOutput(TestOutputReader *outputreader, const QString &msg,
message.chop(1); // all messages have an additional \n at the end
for (auto line : message.split('\n')) {
- if (format == Utils::OutputFormat::StdOutFormatSameLine)
+ if (format == Utils::OutputFormat::StdOutFormat)
outputreader->processStdOutput(line);
else
outputreader->processStdError(line);
diff --git a/src/plugins/autotest/testrunner.h b/src/plugins/autotest/testrunner.h
index a33f6248e1..52e11d5e20 100644
--- a/src/plugins/autotest/testrunner.h
+++ b/src/plugins/autotest/testrunner.h
@@ -53,14 +53,17 @@ enum class TestRunMode;
namespace Internal {
-class AUTOTESTSHARED_EXPORT TestRunner : public QObject
+class AUTOTESTSHARED_EXPORT TestRunner final : public QObject
{
Q_OBJECT
+
public:
+ TestRunner();
+ ~TestRunner() final;
+
enum CancelReason { UserCanceled, Timeout, KitChanged };
static TestRunner* instance();
- ~TestRunner() override;
void setSelectedTests(const QList<TestConfiguration *> &selected);
void runTest(TestRunMode mode, const TestTreeItem *item);
@@ -92,7 +95,6 @@ private:
void debugTests();
void runOrDebugTests();
void reportResult(ResultType type, const QString &description);
- explicit TestRunner(QObject *parent = nullptr);
bool postponeTestRunWithEmptyExecutable(ProjectExplorer::Project *project);
void onBuildSystemUpdated();
diff --git a/src/plugins/autotest/testsettings.cpp b/src/plugins/autotest/testsettings.cpp
index b8d9571f9d..71d306a5cf 100644
--- a/src/plugins/autotest/testsettings.cpp
+++ b/src/plugins/autotest/testsettings.cpp
@@ -70,8 +70,8 @@ void TestSettings::toSettings(QSettings *s) const
s->setValue(runAfterBuildKey, int(runAfterBuild));
// store frameworks and their current active and grouping state
for (const Core::Id &id : frameworks.keys()) {
- s->setValue(QLatin1String(id.name()), frameworks.value(id));
- s->setValue(QLatin1String(id.name().append(groupSuffix)), frameworksGrouping.value(id));
+ s->setValue(id.toString(), frameworks.value(id));
+ s->setValue(id.toString() + groupSuffix, frameworksGrouping.value(id));
}
s->endGroup();
}
@@ -92,17 +92,16 @@ void TestSettings::fromSettings(QSettings *s)
runAfterBuild = RunAfterBuildMode(s->value(runAfterBuildKey,
int(RunAfterBuildMode::None)).toInt());
// try to get settings for registered frameworks
- TestFrameworkManager *frameworkManager = TestFrameworkManager::instance();
- const QList<Core::Id> &registered = frameworkManager->registeredFrameworkIds();
+ const TestFrameworks &registered = TestFrameworkManager::registeredFrameworks();
frameworks.clear();
frameworksGrouping.clear();
- for (const Core::Id &id : registered) {
+ for (const ITestFramework *framework : registered) {
// get their active state
- frameworks.insert(id, s->value(QLatin1String(id.name()),
- frameworkManager->isActive(id)).toBool());
+ const Core::Id id = framework->id();
+ const QString key = id.toString();
+ frameworks.insert(id, s->value(key, framework->active()).toBool());
// and whether grouping is enabled
- frameworksGrouping.insert(id, s->value(QLatin1String(id.name().append(groupSuffix)),
- frameworkManager->groupingEnabled(id)).toBool());
+ frameworksGrouping.insert(id, s->value(key + groupSuffix, framework->grouping()).toBool());
}
s->endGroup();
}
diff --git a/src/plugins/autotest/testsettingspage.cpp b/src/plugins/autotest/testsettingspage.cpp
index 1f0ddca7c5..30bb78acd6 100644
--- a/src/plugins/autotest/testsettingspage.cpp
+++ b/src/plugins/autotest/testsettingspage.cpp
@@ -93,20 +93,18 @@ TestSettings TestSettingsWidget::settings() const
void TestSettingsWidget::populateFrameworksListWidget(const QHash<Core::Id, bool> &frameworks)
{
- TestFrameworkManager *frameworkManager = TestFrameworkManager::instance();
- const QList<Core::Id> &registered = frameworkManager->sortedRegisteredFrameworkIds();
+ const TestFrameworks &registered = TestFrameworkManager::registeredFrameworks();
m_ui.frameworkTreeWidget->clear();
- for (const Core::Id &id : registered) {
- auto *item = new QTreeWidgetItem(m_ui.frameworkTreeWidget,
- QStringList(frameworkManager->frameworkNameForId(id)));
+ for (const ITestFramework *framework : registered) {
+ const Core::Id id = framework->id();
+ auto item = new QTreeWidgetItem(m_ui.frameworkTreeWidget, QStringList(QLatin1String(framework->name())));
item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable);
item->setCheckState(0, frameworks.value(id) ? Qt::Checked : Qt::Unchecked);
item->setData(0, Qt::UserRole, id.toSetting());
- item->setData(1, Qt::CheckStateRole, frameworkManager->groupingEnabled(id) ? Qt::Checked
- : Qt::Unchecked);
+ item->setData(1, Qt::CheckStateRole, framework->grouping() ? Qt::Checked : Qt::Unchecked);
item->setToolTip(0, tr("Enable or disable test frameworks to be handled by the AutoTest "
"plugin."));
- QString toolTip = frameworkManager->groupingToolTip(id);
+ QString toolTip = framework->groupingToolTip();
if (toolTip.isEmpty())
toolTip = tr("Enable or disable grouping of test cases by folder.");
item->setToolTip(1, toolTip);
@@ -140,7 +138,7 @@ void TestSettingsWidget::onFrameworkItemChanged()
m_ui.frameworksWarn->setVisible(true);
}
-TestSettingsPage::TestSettingsPage(const QSharedPointer<TestSettings> &settings)
+TestSettingsPage::TestSettingsPage(TestSettings *settings)
: m_settings(settings)
{
setId("A.AutoTest.0.General");
@@ -170,8 +168,12 @@ void TestSettingsPage::apply()
});
*m_settings = newSettings;
m_settings->toSettings(Core::ICore::settings());
- TestFrameworkManager *frameworkManager = TestFrameworkManager::instance();
- frameworkManager->activateFrameworksFromSettings(m_settings);
+
+ for (ITestFramework *framework : TestFrameworkManager::registeredFrameworks()) {
+ framework->setActive(m_settings->frameworks.value(framework->id(), false));
+ framework->setGrouping(m_settings->frameworksGrouping.value(framework->id(), false));
+ }
+
TestTreeModel::instance()->synchronizeTestFrameworks();
if (!changedIds.isEmpty())
TestTreeModel::instance()->rebuild(changedIds);
diff --git a/src/plugins/autotest/testsettingspage.h b/src/plugins/autotest/testsettingspage.h
index a100500476..8834511313 100644
--- a/src/plugins/autotest/testsettingspage.h
+++ b/src/plugins/autotest/testsettingspage.h
@@ -57,14 +57,14 @@ class TestSettingsPage : public Core::IOptionsPage
{
Q_OBJECT
public:
- explicit TestSettingsPage(const QSharedPointer<TestSettings> &settings);
+ explicit TestSettingsPage(TestSettings *settings);
QWidget *widget() override;
void apply() override;
void finish() override { }
private:
- QSharedPointer<TestSettings> m_settings;
+ TestSettings *m_settings;
QPointer<TestSettingsWidget> m_widget;
};
diff --git a/src/plugins/autotest/testtreeitem.cpp b/src/plugins/autotest/testtreeitem.cpp
index fee361e25e..5debb983d6 100644
--- a/src/plugins/autotest/testtreeitem.cpp
+++ b/src/plugins/autotest/testtreeitem.cpp
@@ -38,8 +38,10 @@
namespace Autotest {
-TestTreeItem::TestTreeItem(const QString &name, const QString &filePath, Type type)
- : m_name(name),
+TestTreeItem::TestTreeItem(ITestFramework *framework, const QString &name,
+ const QString &filePath, Type type)
+ : m_framework(framework),
+ m_name(name),
m_filePath(filePath),
m_type(type)
{
@@ -355,6 +357,11 @@ inline bool TestTreeItem::modifyName(const QString &name)
return false;
}
+ITestFramework *TestTreeItem::framework() const
+{
+ return m_framework;
+}
+
/*
* try to find build system target that depends on the given file - if the file is no header
* try to find the corresponding header and use this instead to find the respective target
diff --git a/src/plugins/autotest/testtreeitem.h b/src/plugins/autotest/testtreeitem.h
index ad86dcb842..8d77ba0a6c 100644
--- a/src/plugins/autotest/testtreeitem.h
+++ b/src/plugins/autotest/testtreeitem.h
@@ -46,6 +46,7 @@ namespace Utils { class FilePath; }
namespace Autotest {
+class ITestFramework;
class TestConfiguration;
class TestParseResult;
enum class TestRunMode;
@@ -71,7 +72,9 @@ public:
Naturally
};
- explicit TestTreeItem(const QString &name = QString(), const QString &filePath = QString(),
+ explicit TestTreeItem(ITestFramework *framework,
+ const QString &name = QString(),
+ const QString &filePath = QString(),
Type type = Root);
virtual TestTreeItem *copyWithoutChildren() = 0;
@@ -83,6 +86,7 @@ public:
bool modifyDataTagContent(const TestParseResult *result);
bool modifyLineAndColumn(const TestParseResult *result);
+ ITestFramework *framework() const;
const QString name() const { return m_name; }
void setName(const QString &name) { m_name = name; }
const QString filePath() const { return m_filePath; }
@@ -129,6 +133,7 @@ public:
// decide whether an item should still be added to the treemodel
virtual bool shouldBeAddedAfterFiltering() const { return true; }
virtual QSet<QString> internalTargets() const;
+
protected:
void copyBasicDataFrom(const TestTreeItem *other);
typedef std::function<bool(const TestTreeItem *)> CompareFunction;
@@ -146,6 +151,7 @@ private:
Cleared
};
+ ITestFramework *m_framework = nullptr;
QString m_name;
QString m_filePath;
Qt::CheckState m_checked;
diff --git a/src/plugins/autotest/testtreemodel.cpp b/src/plugins/autotest/testtreemodel.cpp
index 22d4b3921e..c4d7510b50 100644
--- a/src/plugins/autotest/testtreemodel.cpp
+++ b/src/plugins/autotest/testtreemodel.cpp
@@ -39,14 +39,20 @@
#include <texteditor/texteditor.h>
#include <utils/qtcassert.h>
+using namespace ProjectExplorer;
+using namespace Autotest::Internal;
+
namespace Autotest {
-using namespace Internal;
+static Q_LOGGING_CATEGORY(LOG, "qtc.autotest.frameworkmanager", QtWarningMsg)
+
+static TestTreeModel *s_instance = nullptr;
-TestTreeModel::TestTreeModel(QObject *parent) :
- TreeModel<>(parent),
- m_parser(new TestCodeParser(this))
+TestTreeModel::TestTreeModel(TestCodeParser *parser) :
+ m_parser(parser)
{
+ s_instance = this;
+
connect(m_parser, &TestCodeParser::aboutToPerformFullParse, this,
&TestTreeModel::removeAllTestItems, Qt::QueuedConnection);
connect(m_parser, &TestCodeParser::testParseResultReady,
@@ -55,22 +61,21 @@ TestTreeModel::TestTreeModel(QObject *parent) :
this, &TestTreeModel::sweep, Qt::QueuedConnection);
connect(m_parser, &TestCodeParser::parsingFailed,
this, &TestTreeModel::sweep, Qt::QueuedConnection);
+ connect(m_parser, &TestCodeParser::requestRemoveAll,
+ this, &TestTreeModel::markAllForRemoval);
+ connect(m_parser, &TestCodeParser::requestRemoval,
+ this, &TestTreeModel::markForRemoval);
setupParsingConnections();
}
-static TestTreeModel *s_instance = nullptr;
-
TestTreeModel *TestTreeModel::instance()
{
- if (!s_instance)
- s_instance = new TestTreeModel;
return s_instance;
}
TestTreeModel::~TestTreeModel()
{
- removeTestRootNodes();
s_instance = nullptr;
}
@@ -82,9 +87,11 @@ void TestTreeModel::setupParsingConnections()
m_parser->setDirty();
m_parser->setState(TestCodeParser::Idle);
- ProjectExplorer::SessionManager *sm = ProjectExplorer::SessionManager::instance();
- connect(sm, &ProjectExplorer::SessionManager::startupProjectChanged,
- m_parser, &TestCodeParser::onStartupProjectChanged);
+ SessionManager *sm = SessionManager::instance();
+ connect(sm, &SessionManager::startupProjectChanged, [this](Project *project) {
+ synchronizeTestFrameworks(); // we might have project settings
+ m_parser->onStartupProjectChanged(project);
+ });
CppTools::CppModelManager *cppMM = CppTools::CppModelManager::instance();
connect(cppMM, &CppTools::CppModelManager::documentUpdated,
@@ -205,23 +212,25 @@ QList<TestTreeItem *> TestTreeModel::testItemsByName(const QString &testName)
void TestTreeModel::synchronizeTestFrameworks()
{
ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject();
- QList<Core::Id> sortedIds;
- TestFrameworkManager *manager = TestFrameworkManager::instance();
+ TestFrameworks sorted;
const QVariant useGlobal = project ? project->namedSettings(Constants::SK_USE_GLOBAL)
: QVariant();
if (!useGlobal.isValid() || AutotestPlugin::projectSettings(project)->useGlobalSettings()) {
- sortedIds = manager->sortedActiveFrameworkIds();
+ sorted = Utils::filtered(TestFrameworkManager::registeredFrameworks(),
+ &ITestFramework::active);
+ qCDebug(LOG) << "Active frameworks sorted by priority" << sorted;
} else { // we've got custom project settings
const TestProjectSettings *settings = AutotestPlugin::projectSettings(project);
- const QMap<Core::Id, bool> active = settings->activeFrameworks();
- sortedIds = Utils::filtered(active.keys(), [active](const Core::Id &id) {
- return active.value(id);
+ const QMap<ITestFramework *, bool> active = settings->activeFrameworks();
+ sorted = Utils::filtered(active.keys(), [active](ITestFramework *framework) {
+ return active.value(framework);
});
+ Utils::sort(sorted, &ITestFramework::priority);
}
// pre-check to avoid further processing when frameworks are unchanged
Utils::TreeItem *invisibleRoot = rootItem();
- QSet<Core::Id> newlyAdded;
+ QSet<ITestFramework *> newlyAdded;
QList<Utils::TreeItem *> oldFrameworkRoots;
for (Utils::TreeItem *oldFrameworkRoot : *invisibleRoot)
oldFrameworkRoots.append(oldFrameworkRoot);
@@ -229,19 +238,19 @@ void TestTreeModel::synchronizeTestFrameworks()
for (Utils::TreeItem *oldFrameworkRoot : oldFrameworkRoots)
takeItem(oldFrameworkRoot); // do NOT delete the ptr is still held by TestFrameworkManager
- for (const Core::Id &id : sortedIds) {
- TestTreeItem *frameworkRootNode = manager->rootNodeForTestFramework(id);
+ for (ITestFramework *framework : sorted) {
+ TestTreeItem *frameworkRootNode = framework->rootNode();
invisibleRoot->appendChild(frameworkRootNode);
if (!oldFrameworkRoots.removeOne(frameworkRootNode))
- newlyAdded.insert(id);
+ newlyAdded.insert(framework);
}
for (Utils::TreeItem *oldFrameworkRoot : oldFrameworkRoots)
oldFrameworkRoot->removeChildren();
- m_parser->syncTestFrameworks(sortedIds);
+ m_parser->syncTestFrameworks(sorted);
if (!newlyAdded.isEmpty())
m_parser->updateTestTree(newlyAdded);
- emit updatedActiveFrameworks(sortedIds.size());
+ emit updatedActiveFrameworks(sorted.size());
}
void TestTreeModel::filterAndInsert(TestTreeItem *item, TestTreeItem *root, bool groupingEnabled)
@@ -257,10 +266,10 @@ void TestTreeModel::filterAndInsert(TestTreeItem *item, TestTreeItem *root, bool
void TestTreeModel::rebuild(const QList<Core::Id> &frameworkIds)
{
- TestFrameworkManager *frameworkManager = TestFrameworkManager::instance();
for (const Core::Id &id : frameworkIds) {
- TestTreeItem *frameworkRoot = frameworkManager->rootNodeForTestFramework(id);
- const bool groupingEnabled = TestFrameworkManager::instance()->groupingEnabled(id);
+ ITestFramework *framework = TestFrameworkManager::frameworkForId(id);
+ TestTreeItem *frameworkRoot = framework->rootNode();
+ const bool groupingEnabled = framework->grouping();
for (int row = frameworkRoot->childCount() - 1; row >= 0; --row) {
auto testItem = frameworkRoot->childAt(row);
if (testItem->type() == TestTreeItem::GroupNode) {
@@ -450,16 +459,14 @@ void TestTreeModel::revalidateCheckState(TestTreeItem *item)
void TestTreeModel::onParseResultReady(const TestParseResultPtr result)
{
- TestTreeItem *rootNode
- = TestFrameworkManager::instance()->rootNodeForTestFramework(result->frameworkId);
+ TestTreeItem *rootNode = result->framework->rootNode();
QTC_ASSERT(rootNode, return);
handleParseResult(result.data(), rootNode);
}
void TestTreeModel::handleParseResult(const TestParseResult *result, TestTreeItem *parentNode)
{
- const bool groupingEnabled =
- TestFrameworkManager::instance()->groupingEnabled(result->frameworkId);
+ const bool groupingEnabled = result->framework->grouping();
// lookup existing items
if (TestTreeItem *toBeModified = parentNode->find(result)) {
// found existing item... Do not remove
@@ -500,41 +507,30 @@ void TestTreeModel::removeAllTestItems()
emit testTreeModelChanged();
}
-void TestTreeModel::removeTestRootNodes()
-{
- const Utils::TreeItem *invisibleRoot = rootItem();
- const int frameworkRootCount = invisibleRoot ? invisibleRoot->childCount() : 0;
- for (int row = frameworkRootCount - 1; row >= 0; --row) {
- Utils::TreeItem *item = invisibleRoot->childAt(row);
- item->removeChildren();
- takeItem(item); // do NOT delete the item as it's still a ptr held by TestFrameworkManager
- }
-}
-
#ifdef WITH_TESTS
// we're inside tests - so use some internal knowledge to make testing easier
static TestTreeItem *qtRootNode()
{
- return TestFrameworkManager::instance()->rootNodeForTestFramework(
- Core::Id(Constants::FRAMEWORK_PREFIX).withSuffix("QtTest"));
+ auto id = Core::Id(Constants::FRAMEWORK_PREFIX).withSuffix("QtTest");
+ return TestFrameworkManager::frameworkForId(id)->rootNode();
}
static TestTreeItem *quickRootNode()
{
- return TestFrameworkManager::instance()->rootNodeForTestFramework(
- Core::Id(Constants::FRAMEWORK_PREFIX).withSuffix("QtQuickTest"));
+ auto id = Core::Id(Constants::FRAMEWORK_PREFIX).withSuffix("QtQuickTest");
+ return TestFrameworkManager::frameworkForId(id)->rootNode();
}
static TestTreeItem *gtestRootNode()
{
- return TestFrameworkManager::instance()->rootNodeForTestFramework(
- Core::Id(Constants::FRAMEWORK_PREFIX).withSuffix("GTest"));
+ auto id = Core::Id(Constants::FRAMEWORK_PREFIX).withSuffix("GTest");
+ return TestFrameworkManager::frameworkForId(id)->rootNode();
}
static TestTreeItem *boostTestRootNode()
{
- return TestFrameworkManager::instance()->rootNodeForTestFramework(
- Core::Id(Constants::FRAMEWORK_PREFIX).withSuffix("Boost"));
+ auto id = Core::Id(Constants::FRAMEWORK_PREFIX).withSuffix("Boost");
+ return TestFrameworkManager::frameworkForId(id)->rootNode();
}
int TestTreeModel::autoTestsCount() const
diff --git a/src/plugins/autotest/testtreemodel.h b/src/plugins/autotest/testtreemodel.h
index 895d71bbac..7d64db73f0 100644
--- a/src/plugins/autotest/testtreemodel.h
+++ b/src/plugins/autotest/testtreemodel.h
@@ -36,6 +36,7 @@
namespace Autotest {
namespace Internal {
+class AutotestPluginPrivate;
class TestCodeParser;
} // namespace Internal
@@ -45,6 +46,10 @@ using TestParseResultPtr = QSharedPointer<TestParseResult>;
class AUTOTESTSHARED_EXPORT TestTreeModel : public Utils::TreeModel<>
{
Q_OBJECT
+
+ friend class Internal::AutotestPluginPrivate; // For ctor.
+ explicit TestTreeModel(Internal::TestCodeParser *parser);
+
public:
static TestTreeModel* instance();
~TestTreeModel() override;
@@ -89,12 +94,10 @@ private:
void onParseResultReady(const TestParseResultPtr result);
void handleParseResult(const TestParseResult *result, TestTreeItem *rootNode);
void removeAllTestItems();
- void removeTestRootNodes();
void removeFiles(const QStringList &files);
bool sweepChildren(TestTreeItem *item);
void insertItemInParent(TestTreeItem *item, TestTreeItem *root, bool groupingEnabled);
void revalidateCheckState(TestTreeItem *item);
- explicit TestTreeModel(QObject *parent = nullptr);
void setupParsingConnections();
void filterAndInsert(TestTreeItem *item, TestTreeItem *root, bool groupingEnabled);
QList<TestTreeItem *> testItemsByName(TestTreeItem *root, const QString &testName);
diff --git a/src/plugins/autotoolsprojectmanager/autogenstep.cpp b/src/plugins/autotoolsprojectmanager/autogenstep.cpp
index 07bc98024e..89d828d60a 100644
--- a/src/plugins/autotoolsprojectmanager/autogenstep.cpp
+++ b/src/plugins/autotoolsprojectmanager/autogenstep.cpp
@@ -86,12 +86,10 @@ AutogenStep::AutogenStep(BuildStepList *bsl, Core::Id id) : AbstractProcessStep(
});
setSummaryUpdater([this] {
- BuildConfiguration *bc = buildConfiguration();
-
ProcessParameters param;
- param.setMacroExpander(bc->macroExpander());
- param.setEnvironment(bc->environment());
- param.setWorkingDirectory(bc->target()->project()->projectDirectory());
+ param.setMacroExpander(macroExpander());
+ param.setEnvironment(buildEnvironment());
+ param.setWorkingDirectory(project()->projectDirectory());
param.setCommandLine({FilePath::fromString("./autogen.sh"),
m_additionalArgumentsAspect->value(),
CommandLine::Raw});
@@ -102,12 +100,10 @@ AutogenStep::AutogenStep(BuildStepList *bsl, Core::Id id) : AbstractProcessStep(
bool AutogenStep::init()
{
- BuildConfiguration *bc = buildConfiguration();
-
ProcessParameters *pp = processParameters();
- pp->setMacroExpander(bc->macroExpander());
- pp->setEnvironment(bc->environment());
- pp->setWorkingDirectory(bc->target()->project()->projectDirectory());
+ pp->setMacroExpander(macroExpander());
+ pp->setEnvironment(buildEnvironment());
+ pp->setWorkingDirectory(project()->projectDirectory());
pp->setCommandLine({FilePath::fromString("./autogen.sh"),
m_additionalArgumentsAspect->value(),
CommandLine::Raw});
@@ -117,10 +113,8 @@ bool AutogenStep::init()
void AutogenStep::doRun()
{
- BuildConfiguration *bc = buildConfiguration();
-
// Check whether we need to run autogen.sh
- const QString projectDir = bc->target()->project()->projectDirectory().toString();
+ const QString projectDir = project()->projectDirectory().toString();
const QFileInfo configureInfo(projectDir + "/configure");
const QFileInfo configureAcInfo(projectDir + "/configure.ac");
const QFileInfo makefileAmInfo(projectDir + "/Makefile.am");
diff --git a/src/plugins/autotoolsprojectmanager/autoreconfstep.cpp b/src/plugins/autotoolsprojectmanager/autoreconfstep.cpp
index d3651e6f3b..3be62f4e71 100644
--- a/src/plugins/autotoolsprojectmanager/autoreconfstep.cpp
+++ b/src/plugins/autotoolsprojectmanager/autoreconfstep.cpp
@@ -84,12 +84,10 @@ AutoreconfStep::AutoreconfStep(BuildStepList *bsl, Core::Id id)
});
setSummaryUpdater([this] {
- BuildConfiguration *bc = buildConfiguration();
-
ProcessParameters param;
- param.setMacroExpander(bc->macroExpander());
- param.setEnvironment(bc->environment());
- param.setWorkingDirectory(bc->target()->project()->projectDirectory());
+ param.setMacroExpander(macroExpander());
+ param.setEnvironment(buildEnvironment());
+ param.setWorkingDirectory(project()->projectDirectory());
param.setCommandLine({Utils::FilePath::fromString("autoreconf"),
m_additionalArgumentsAspect->value(),
Utils::CommandLine::Raw});
@@ -100,12 +98,10 @@ AutoreconfStep::AutoreconfStep(BuildStepList *bsl, Core::Id id)
bool AutoreconfStep::init()
{
- BuildConfiguration *bc = buildConfiguration();
-
ProcessParameters *pp = processParameters();
- pp->setMacroExpander(bc->macroExpander());
- pp->setEnvironment(bc->environment());
- pp->setWorkingDirectory(bc->target()->project()->projectDirectory());
+ pp->setMacroExpander(macroExpander());
+ pp->setEnvironment(buildEnvironment());
+ pp->setWorkingDirectory(project()->projectDirectory());
pp->setCommandLine({Utils::FilePath::fromString("autoreconf"),
m_additionalArgumentsAspect->value(), Utils::CommandLine::Raw});
@@ -114,10 +110,8 @@ bool AutoreconfStep::init()
void AutoreconfStep::doRun()
{
- BuildConfiguration *bc = buildConfiguration();
-
// Check whether we need to run autoreconf
- const QString projectDir(bc->target()->project()->projectDirectory().toString());
+ const QString projectDir(project()->projectDirectory().toString());
if (!QFileInfo::exists(projectDir + "/configure"))
m_runAutoreconf = true;
diff --git a/src/plugins/autotoolsprojectmanager/autotoolsopenprojectwizard.cpp b/src/plugins/autotoolsprojectmanager/autotoolsopenprojectwizard.cpp
index d56f2ecdb7..8617f5e47e 100644
--- a/src/plugins/autotoolsprojectmanager/autotoolsopenprojectwizard.cpp
+++ b/src/plugins/autotoolsprojectmanager/autotoolsopenprojectwizard.cpp
@@ -95,5 +95,5 @@ BuildPathPage::BuildPathPage(AutotoolsOpenProjectWizard *w) : QWizardPage(w),
void BuildPathPage::buildDirectoryChanged()
{
- static_cast<AutotoolsOpenProjectWizard *>(wizard())->setBuildDirectory(m_pc->path());
+ static_cast<AutotoolsOpenProjectWizard *>(wizard())->setBuildDirectory(m_pc->filePath().toString());
}
diff --git a/src/plugins/autotoolsprojectmanager/configurestep.cpp b/src/plugins/autotoolsprojectmanager/configurestep.cpp
index 044e8fd4c7..737840ef19 100644
--- a/src/plugins/autotoolsprojectmanager/configurestep.cpp
+++ b/src/plugins/autotoolsprojectmanager/configurestep.cpp
@@ -109,9 +109,9 @@ ConfigureStep::ConfigureStep(BuildStepList *bsl, Core::Id id)
BuildConfiguration *bc = buildConfiguration();
ProcessParameters param;
- param.setMacroExpander(bc->macroExpander());
- param.setEnvironment(bc->environment());
- param.setWorkingDirectory(bc->buildDirectory());
+ param.setMacroExpander(macroExpander());
+ param.setEnvironment(buildEnvironment());
+ param.setWorkingDirectory(buildDirectory());
param.setCommandLine({FilePath::fromString(projectDirRelativeToBuildDir(bc) + "configure"),
m_additionalArgumentsAspect->value(),
CommandLine::Raw});
@@ -125,9 +125,9 @@ bool ConfigureStep::init()
BuildConfiguration *bc = buildConfiguration();
ProcessParameters *pp = processParameters();
- pp->setMacroExpander(bc->macroExpander());
- pp->setEnvironment(bc->environment());
- pp->setWorkingDirectory(bc->buildDirectory());
+ pp->setMacroExpander(macroExpander());
+ pp->setEnvironment(buildEnvironment());
+ pp->setWorkingDirectory(buildDirectory());
pp->setCommandLine({FilePath::fromString(projectDirRelativeToBuildDir(bc) + "configure"),
m_additionalArgumentsAspect->value(),
CommandLine::Raw});
@@ -137,12 +137,10 @@ bool ConfigureStep::init()
void ConfigureStep::doRun()
{
- BuildConfiguration *bc = buildConfiguration();
-
//Check whether we need to run configure
- const QString projectDir(bc->target()->project()->projectDirectory().toString());
+ const QString projectDir(project()->projectDirectory().toString());
const QFileInfo configureInfo(projectDir + "/configure");
- const QFileInfo configStatusInfo(bc->buildDirectory().toString() + "/config.status");
+ const QFileInfo configStatusInfo(buildDirectory().toString() + "/config.status");
if (!configStatusInfo.exists()
|| configStatusInfo.lastModified() < configureInfo.lastModified()) {
diff --git a/src/plugins/baremetal/CMakeLists.txt b/src/plugins/baremetal/CMakeLists.txt
index 7783e91ec8..0a6721c4e7 100644
--- a/src/plugins/baremetal/CMakeLists.txt
+++ b/src/plugins/baremetal/CMakeLists.txt
@@ -20,6 +20,7 @@ add_qtc_plugin(BareMetal
debugservers/gdb/eblinkgdbserverprovider.cpp debugservers/gdb/eblinkgdbserverprovider.h
debugservers/uvsc/simulatoruvscserverprovider.cpp debugservers/uvsc/simulatoruvscserverprovider.h
debugservers/uvsc/stlinkuvscserverprovider.cpp debugservers/uvsc/stlinkuvscserverprovider.h
+ debugservers/uvsc/jlinkuvscserverprovider.cpp debugservers/uvsc/jlinkuvscserverprovider.h
debugservers/uvsc/uvproject.cpp debugservers/uvsc/uvproject.h
debugservers/uvsc/uvprojectwriter.cpp debugservers/uvsc/uvprojectwriter.h
debugservers/uvsc/uvscserverprovider.cpp debugservers/uvsc/uvscserverprovider.h
diff --git a/src/plugins/baremetal/baremetal.qbs b/src/plugins/baremetal/baremetal.qbs
index c5fc698597..c194201800 100644
--- a/src/plugins/baremetal/baremetal.qbs
+++ b/src/plugins/baremetal/baremetal.qbs
@@ -55,6 +55,7 @@ QtcPlugin {
files: [
"simulatoruvscserverprovider.cpp", "simulatoruvscserverprovider.h",
"stlinkuvscserverprovider.cpp", "stlinkuvscserverprovider.h",
+ "jlinkuvscserverprovider.cpp", "jlinkuvscserverprovider.h",
"uvproject.cpp", "uvproject.h",
"uvprojectwriter.cpp", "uvprojectwriter.h",
"uvscserverprovider.cpp", "uvscserverprovider.h",
diff --git a/src/plugins/baremetal/baremetalconstants.h b/src/plugins/baremetal/baremetalconstants.h
index 3519a3c50c..816aa0a51a 100644
--- a/src/plugins/baremetal/baremetalconstants.h
+++ b/src/plugins/baremetal/baremetalconstants.h
@@ -45,6 +45,7 @@ const char GDBSERVER_EBLINK_PROVIDER_ID[] = "BareMetal.GdbServerProvider.EBlink"
// uVision Debugger Server Provider Ids.
const char UVSC_SIMULATOR_PROVIDER_ID[] = "BareMetal.UvscServerProvider.Simulator";
const char UVSC_STLINK_PROVIDER_ID[] = "BareMetal.UvscServerProvider.StLink";
+const char UVSC_JLINK_PROVIDER_ID[] = "BareMetal.UvscServerProvider.JLink";
// Toolchain types.
const char IAREW_TOOLCHAIN_TYPEID[] = "BareMetal.ToolChain.Iar";
diff --git a/src/plugins/baremetal/baremetalplugin.cpp b/src/plugins/baremetal/baremetalplugin.cpp
index e39790f80c..a01ae59551 100644
--- a/src/plugins/baremetal/baremetalplugin.cpp
+++ b/src/plugins/baremetal/baremetalplugin.cpp
@@ -70,7 +70,7 @@ class BareMetalPluginPrivate
{
public:
IarToolChainFactory iarToolChainFactory;
- KeilToolchainFactory keilToolChainFactory;
+ KeilToolChainFactory keilToolChainFactory;
SdccToolChainFactory sdccToolChainFactory;
BareMetalDeviceFactory deviceFactory;
BareMetalRunConfigurationFactory runConfigurationFactory;
diff --git a/src/plugins/baremetal/debugserverprovidermanager.cpp b/src/plugins/baremetal/debugserverprovidermanager.cpp
index 6a9bbad8a2..52969600fb 100644
--- a/src/plugins/baremetal/debugserverprovidermanager.cpp
+++ b/src/plugins/baremetal/debugserverprovidermanager.cpp
@@ -35,6 +35,7 @@
// UVSC debug servers.
#include "debugservers/uvsc/simulatoruvscserverprovider.h"
#include "debugservers/uvsc/stlinkuvscserverprovider.h"
+#include "debugservers/uvsc/jlinkuvscserverprovider.h"
#include <coreplugin/icore.h>
@@ -65,7 +66,8 @@ DebugServerProviderManager::DebugServerProviderManager()
new StLinkUtilGdbServerProviderFactory,
new EBlinkGdbServerProviderFactory,
new SimulatorUvscServerProviderFactory,
- new StLinkUvscServerProviderFactory})
+ new StLinkUvscServerProviderFactory,
+ new JLinkUvscServerProviderFactory})
{
m_instance = this;
m_writer = new Utils::PersistentSettingsWriter(
diff --git a/src/plugins/baremetal/debugservers/gdb/eblinkgdbserverprovider.cpp b/src/plugins/baremetal/debugservers/gdb/eblinkgdbserverprovider.cpp
index b663033e94..d54b701460 100644
--- a/src/plugins/baremetal/debugservers/gdb/eblinkgdbserverprovider.cpp
+++ b/src/plugins/baremetal/debugservers/gdb/eblinkgdbserverprovider.cpp
@@ -356,9 +356,9 @@ void EBlinkGdbServerProviderConfigWidget::setFromProvider()
Q_ASSERT(p);
m_gdbHostWidget->setChannel(p->channel());
- m_executableFileChooser->setFileName(p->m_executableFile);
+ m_executableFileChooser->setFilePath(p->m_executableFile);
m_verboseLevelSpinBox->setValue(p->m_verboseLevel);
- m_scriptFileChooser->setFileName(p->m_deviceScript);
+ m_scriptFileChooser->setFilePath(p->m_deviceScript);
m_interfaceTypeComboBox->setCurrentIndex(p->m_interfaceType);
m_resetOnConnectCheckBox->setChecked(p->m_interfaceResetOnConnect);
m_interfaceSpeedSpinBox->setValue(p->m_interfaceSpeed);
@@ -376,9 +376,9 @@ void EBlinkGdbServerProviderConfigWidget::apply()
Q_ASSERT(p);
p->setChannel(m_gdbHostWidget->channel());
- p->m_executableFile = m_executableFileChooser->fileName();
+ p->m_executableFile = m_executableFileChooser->filePath();
p->m_verboseLevel = m_verboseLevelSpinBox->value();
- p->m_deviceScript = m_scriptFileChooser->fileName();
+ p->m_deviceScript = m_scriptFileChooser->filePath();
p->m_interfaceType = interfaceTypeFromWidget();
p->m_interfaceResetOnConnect = m_resetOnConnectCheckBox->isChecked();
p->m_interfaceSpeed = m_interfaceSpeedSpinBox->value();
diff --git a/src/plugins/baremetal/debugservers/gdb/gdbserverprovider.cpp b/src/plugins/baremetal/debugservers/gdb/gdbserverprovider.cpp
index 4e4e73a90c..77dfee82ff 100644
--- a/src/plugins/baremetal/debugservers/gdb/gdbserverprovider.cpp
+++ b/src/plugins/baremetal/debugservers/gdb/gdbserverprovider.cpp
@@ -311,12 +311,12 @@ void GdbServerProviderConfigWidget::populateStartupModes()
Utils::FilePath GdbServerProviderConfigWidget::peripheralDescriptionFile() const
{
- return m_peripheralDescriptionFileChooser->fileName();
+ return m_peripheralDescriptionFileChooser->filePath();
}
void GdbServerProviderConfigWidget::setPeripheralDescriptionFile(const Utils::FilePath &file)
{
- m_peripheralDescriptionFileChooser->setFileName(file);
+ m_peripheralDescriptionFileChooser->setFilePath(file);
}
void GdbServerProviderConfigWidget::setFromProvider()
diff --git a/src/plugins/baremetal/debugservers/gdb/jlinkgdbserverprovider.cpp b/src/plugins/baremetal/debugservers/gdb/jlinkgdbserverprovider.cpp
index 3d6d9d0596..047c1feba2 100644
--- a/src/plugins/baremetal/debugservers/gdb/jlinkgdbserverprovider.cpp
+++ b/src/plugins/baremetal/debugservers/gdb/jlinkgdbserverprovider.cpp
@@ -313,7 +313,7 @@ void JLinkGdbServerProviderConfigWidget::apply()
Q_ASSERT(p);
p->setChannel(m_hostWidget->channel());
- p->m_executableFile = m_executableFileChooser->fileName();
+ p->m_executableFile = m_executableFileChooser->filePath();
p->m_jlinkDevice = m_jlinkDeviceLineEdit->text();
p->m_jlinkHost = m_hostInterfaceComboBox->currentText();
p->m_jlinkHostAddr = m_hostInterfaceAddressLineEdit->text();
@@ -357,7 +357,7 @@ void JLinkGdbServerProviderConfigWidget::setFromProvider()
const QSignalBlocker blocker(this);
m_hostWidget->setChannel(p->channel());
- m_executableFileChooser->setFileName(p->m_executableFile);
+ m_executableFileChooser->setFilePath(p->m_executableFile);
m_jlinkDeviceLineEdit->setText(p->m_jlinkDevice);
m_additionalArgumentsTextEdit->setPlainText(p->m_additionalArguments);
m_jlinkDeviceLineEdit->setText( p->m_jlinkDevice);
diff --git a/src/plugins/baremetal/debugservers/gdb/openocdgdbserverprovider.cpp b/src/plugins/baremetal/debugservers/gdb/openocdgdbserverprovider.cpp
index 57692d0d53..093f1cbc94 100644
--- a/src/plugins/baremetal/debugservers/gdb/openocdgdbserverprovider.cpp
+++ b/src/plugins/baremetal/debugservers/gdb/openocdgdbserverprovider.cpp
@@ -259,9 +259,9 @@ void OpenOcdGdbServerProviderConfigWidget::apply()
Q_ASSERT(p);
p->setChannel(m_hostWidget->channel());
- p->m_executableFile = m_executableFileChooser->fileName();
- p->m_rootScriptsDir = m_rootScriptsDirChooser->fileName().toString();
- p->m_configurationFile = m_configurationFileChooser->fileName().toString();
+ p->m_executableFile = m_executableFileChooser->filePath();
+ p->m_rootScriptsDir = m_rootScriptsDirChooser->filePath().toString();
+ p->m_configurationFile = m_configurationFileChooser->filePath().toString();
p->m_additionalArguments = m_additionalArgumentsLineEdit->text();
p->setInitCommands(m_initCommandsTextEdit->toPlainText());
p->setResetCommands(m_resetCommandsTextEdit->toPlainText());
@@ -290,9 +290,9 @@ void OpenOcdGdbServerProviderConfigWidget::setFromProvider()
const QSignalBlocker blocker(this);
startupModeChanged();
m_hostWidget->setChannel(p->channel());
- m_executableFileChooser->setFileName(p->m_executableFile);
- m_rootScriptsDirChooser->setFileName(Utils::FilePath::fromString(p->m_rootScriptsDir));
- m_configurationFileChooser->setFileName(Utils::FilePath::fromString(p->m_configurationFile));
+ m_executableFileChooser->setFilePath(p->m_executableFile);
+ m_rootScriptsDirChooser->setFilePath(Utils::FilePath::fromString(p->m_rootScriptsDir));
+ m_configurationFileChooser->setFilePath(Utils::FilePath::fromString(p->m_configurationFile));
m_additionalArgumentsLineEdit->setText(p->m_additionalArguments);
m_initCommandsTextEdit->setPlainText(p->initCommands());
m_resetCommandsTextEdit->setPlainText(p->resetCommands());
diff --git a/src/plugins/baremetal/debugservers/gdb/stlinkutilgdbserverprovider.cpp b/src/plugins/baremetal/debugservers/gdb/stlinkutilgdbserverprovider.cpp
index eabba4c083..c9379e72a1 100644
--- a/src/plugins/baremetal/debugservers/gdb/stlinkutilgdbserverprovider.cpp
+++ b/src/plugins/baremetal/debugservers/gdb/stlinkutilgdbserverprovider.cpp
@@ -254,7 +254,7 @@ void StLinkUtilGdbServerProviderConfigWidget::apply()
Q_ASSERT(p);
p->setChannel(m_hostWidget->channel());
- p->m_executableFile = m_executableFileChooser->fileName();
+ p->m_executableFile = m_executableFileChooser->filePath();
p->m_verboseLevel = m_verboseLevelSpinBox->value();
p->m_extendedMode = m_extendedModeCheckBox->isChecked();
p->m_resetBoard = m_resetBoardCheckBox->isChecked();
@@ -312,7 +312,7 @@ void StLinkUtilGdbServerProviderConfigWidget::setFromProvider()
const QSignalBlocker blocker(this);
m_hostWidget->setChannel(p->channel());
- m_executableFileChooser->setFileName(p->m_executableFile);
+ m_executableFileChooser->setFilePath(p->m_executableFile);
m_verboseLevelSpinBox->setValue(p->m_verboseLevel);
m_extendedModeCheckBox->setChecked(p->m_extendedMode);
m_resetBoardCheckBox->setChecked(p->m_resetBoard);
diff --git a/src/plugins/baremetal/debugservers/uvsc/jlinkuvscserverprovider.cpp b/src/plugins/baremetal/debugservers/uvsc/jlinkuvscserverprovider.cpp
new file mode 100644
index 0000000000..ee835d6f46
--- /dev/null
+++ b/src/plugins/baremetal/debugservers/uvsc/jlinkuvscserverprovider.cpp
@@ -0,0 +1,373 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com>
+** 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 "jlinkuvscserverprovider.h"
+
+#include "uvproject.h"
+#include "uvprojectwriter.h"
+
+#include <baremetal/baremetalconstants.h>
+#include <baremetal/baremetaldebugsupport.h>
+#include <baremetal/debugserverprovidermanager.h>
+
+#include <debugger/debuggerruncontrol.h>
+
+#include <utils/qtcassert.h>
+
+#include <QComboBox>
+#include <QFileInfo>
+#include <QFormLayout>
+#include <QLabel>
+
+#include <fstream> // for std::ofstream
+
+using namespace Debugger;
+using namespace ProjectExplorer;
+using namespace Utils;
+
+namespace BareMetal {
+namespace Internal {
+
+using namespace Uv;
+
+constexpr char adapterOptionsKeyC[] = "BareMetal.JLinkUvscServerProvider.AdapterOptions";
+constexpr char adapterPortKeyC[] = "BareMetal.JLinkUvscServerProvider.AdapterPort";
+constexpr char adapterSpeedKeyC[] = "BareMetal.JLinkUvscServerProvider.AdapterSpeed";
+
+static int decodeSpeedCode(JLinkUvscAdapterOptions::Speed speed)
+{
+ switch (speed) {
+ case JLinkUvscAdapterOptions::Speed_50MHz:
+ return 8;
+ case JLinkUvscAdapterOptions::Speed_33MHz:
+ return 9;
+ case JLinkUvscAdapterOptions::Speed_25MHz:
+ return 10;
+ case JLinkUvscAdapterOptions::Speed_20MHz:
+ return 0;
+ case JLinkUvscAdapterOptions::Speed_10MHz:
+ return 1;
+ case JLinkUvscAdapterOptions::Speed_5MHz:
+ return 2;
+ case JLinkUvscAdapterOptions::Speed_3MHz:
+ return 3;
+ case JLinkUvscAdapterOptions::Speed_2MHz:
+ return 4;
+ case JLinkUvscAdapterOptions::Speed_1MHz:
+ return 5;
+ case JLinkUvscAdapterOptions::Speed_500kHz:
+ return 6;
+ case JLinkUvscAdapterOptions::Speed_200kHz:
+ return 7;
+ default:
+ return 8;
+ }
+}
+
+static QString buildAdapterOptions(const JLinkUvscAdapterOptions &opts)
+{
+ QString s;
+ if (opts.port == JLinkUvscAdapterOptions::JTAG)
+ s += "-O14";
+ else if (opts.port == JLinkUvscAdapterOptions::SWD)
+ s += "-O78";
+
+ const int code = decodeSpeedCode(opts.speed);
+ s += " -S" + QString::number(code) + " -ZTIFSpeedSel" + QString::number(opts.speed);
+ return s;
+}
+
+static QString buildDllRegistryName(const DeviceSelection &device,
+ const JLinkUvscAdapterOptions &opts)
+{
+ if (device.algorithmIndex < 0 || device.algorithmIndex >= int(device.algorithms.size()))
+ return {};
+
+ const DeviceSelection::Algorithm algorithm = device.algorithms.at(device.algorithmIndex);
+ const QFileInfo path(algorithm.path);
+ const QString flashStart = UvscServerProvider::adjustFlashAlgorithmProperty(algorithm.flashStart);
+ const QString flashSize = UvscServerProvider::adjustFlashAlgorithmProperty(algorithm.flashSize);
+ const QString adaptOpts = buildAdapterOptions(opts);
+
+ QString content = QStringLiteral(" %6 -FN1 -FF0%1 -FS0%2 -FL0%3 -FP0($$Device:%4$%5)")
+ .arg(path.fileName(), flashStart, flashSize, device.name, path.filePath(), adaptOpts);
+
+ if (!algorithm.ramStart.isEmpty()) {
+ const QString ramStart = UvscServerProvider::adjustFlashAlgorithmProperty(algorithm.ramStart);
+ content += QStringLiteral(" -FD%1").arg(ramStart);
+ }
+ if (!algorithm.ramSize.isEmpty()) {
+ const QString ramSize = UvscServerProvider::adjustFlashAlgorithmProperty(algorithm.ramSize);
+ content += QStringLiteral(" -FC%1").arg(ramSize);
+ }
+
+ return content;
+}
+
+// JLinkUvProjectOptions
+
+class JLinkUvProjectOptions final : public Uv::ProjectOptions
+{
+public:
+ explicit JLinkUvProjectOptions(const JLinkUvscServerProvider *provider)
+ : Uv::ProjectOptions(provider)
+ {
+ const DriverSelection driver = provider->driverSelection();
+ const DeviceSelection device = provider->deviceSelection();
+ m_debugOpt->appendProperty("nTsel", driver.index);
+ m_debugOpt->appendProperty("pMon", driver.dll);
+
+ // Fill 'TargetDriverDllRegistry' (required for dedugging).
+ const auto dllRegistry = m_targetOption->appendPropertyGroup("TargetDriverDllRegistry");
+ const auto setRegEntry = dllRegistry->appendPropertyGroup("SetRegEntry");
+ setRegEntry->appendProperty("Number", 0);
+ const QString key = UvscServerProvider::buildDllRegistryKey(driver);
+ setRegEntry->appendProperty("Key", key);
+ const QString name = buildDllRegistryName(device, provider->m_adapterOpts);
+ setRegEntry->appendProperty("Name", name);
+ }
+};
+
+// JLinkUvscAdapterOptions
+
+QVariantMap JLinkUvscAdapterOptions::toMap() const
+{
+ QVariantMap map;
+ map.insert(adapterPortKeyC, port);
+ map.insert(adapterSpeedKeyC, speed);
+ return map;
+}
+
+bool JLinkUvscAdapterOptions::fromMap(const QVariantMap &data)
+{
+ port = static_cast<Port>(data.value(adapterPortKeyC, SWD).toInt());
+ speed = static_cast<Speed>(data.value(adapterSpeedKeyC, Speed_1MHz).toInt());
+ return true;
+}
+
+bool JLinkUvscAdapterOptions::operator==(const JLinkUvscAdapterOptions &other) const
+{
+ return port == other.port && speed == other.speed;
+}
+
+// JLinkUvscServerProvider
+
+JLinkUvscServerProvider::JLinkUvscServerProvider()
+ : UvscServerProvider(Constants::UVSC_JLINK_PROVIDER_ID)
+{
+ setTypeDisplayName(tr("uVision JLink"));
+ setConfigurationWidgetCreator([this] { return new JLinkUvscServerProviderConfigWidget(this); });
+ setSupportedDrivers({"Segger\\JL2CM3.dll"});
+}
+
+QVariantMap JLinkUvscServerProvider::toMap() const
+{
+ QVariantMap data = UvscServerProvider::toMap();
+ data.insert(adapterOptionsKeyC, m_adapterOpts.toMap());
+ return data;
+}
+
+bool JLinkUvscServerProvider::fromMap(const QVariantMap &data)
+{
+ if (!UvscServerProvider::fromMap(data))
+ return false;
+ m_adapterOpts.fromMap(data.value(adapterOptionsKeyC).toMap());
+ return true;
+}
+
+bool JLinkUvscServerProvider::operator==(const IDebugServerProvider &other) const
+{
+ if (!UvscServerProvider::operator==(other))
+ return false;
+ const auto p = static_cast<const JLinkUvscServerProvider *>(&other);
+ return m_adapterOpts == p->m_adapterOpts;
+ return true;
+}
+
+FilePath JLinkUvscServerProvider::optionsFilePath(DebuggerRunTool *runTool,
+ QString &errorMessage) const
+{
+ const FilePath optionsPath = buildOptionsFilePath(runTool);
+ std::ofstream ofs(optionsPath.toString().toStdString(), std::ofstream::out);
+ Uv::ProjectOptionsWriter writer(&ofs);
+ const JLinkUvProjectOptions projectOptions(this);
+ if (!writer.write(&projectOptions)) {
+ errorMessage = BareMetalDebugSupport::tr(
+ "Unable to create an uVision project options template");
+ return {};
+ }
+ return optionsPath;
+}
+
+// JLinkUvscServerProviderFactory
+
+JLinkUvscServerProviderFactory::JLinkUvscServerProviderFactory()
+{
+ setId(Constants::UVSC_JLINK_PROVIDER_ID);
+ setDisplayName(UvscServerProvider::tr("uVision JLink"));
+ setCreator([] { return new JLinkUvscServerProvider; });
+}
+
+// JLinkUvscServerProviderConfigWidget
+
+JLinkUvscServerProviderConfigWidget::JLinkUvscServerProviderConfigWidget(
+ JLinkUvscServerProvider *p)
+ : UvscServerProviderConfigWidget(p)
+{
+ Q_ASSERT(p);
+
+ m_adapterOptionsWidget = new JLinkUvscAdapterOptionsWidget;
+ m_mainLayout->addRow(tr("Adapter options:"), m_adapterOptionsWidget);
+
+ setFromProvider();
+
+ connect(m_adapterOptionsWidget, &JLinkUvscAdapterOptionsWidget::optionsChanged,
+ this, &JLinkUvscServerProviderConfigWidget::dirty);
+}
+
+void JLinkUvscServerProviderConfigWidget::apply()
+{
+ const auto p = static_cast<JLinkUvscServerProvider *>(m_provider);
+ Q_ASSERT(p);
+ p->m_adapterOpts = adapterOptions();
+ UvscServerProviderConfigWidget::apply();
+}
+
+void JLinkUvscServerProviderConfigWidget::discard()
+{
+ setFromProvider();
+ UvscServerProviderConfigWidget::discard();
+}
+
+void JLinkUvscServerProviderConfigWidget::setAdapterOpitons(
+ const JLinkUvscAdapterOptions &adapterOpts)
+{
+ m_adapterOptionsWidget->setAdapterOptions(adapterOpts);
+}
+
+JLinkUvscAdapterOptions JLinkUvscServerProviderConfigWidget::adapterOptions() const
+{
+ return m_adapterOptionsWidget->adapterOptions();
+}
+
+void JLinkUvscServerProviderConfigWidget::setFromProvider()
+{
+ const auto p = static_cast<JLinkUvscServerProvider *>(m_provider);
+ Q_ASSERT(p);
+ const QSignalBlocker blocker(this);
+ setAdapterOpitons(p->m_adapterOpts);
+}
+
+// JLinkUvscAdapterOptionsWidget
+
+JLinkUvscAdapterOptionsWidget::JLinkUvscAdapterOptionsWidget(QWidget *parent)
+ : QWidget(parent)
+{
+ const auto layout = new QHBoxLayout;
+ layout->setContentsMargins(0, 0, 0, 0);
+ layout->addWidget(new QLabel(tr("Port:")));
+ m_portBox = new QComboBox;
+ layout->addWidget(m_portBox);
+ layout->addWidget(new QLabel(tr("Speed:")));
+ m_speedBox = new QComboBox;
+ layout->addWidget(m_speedBox);
+ setLayout(layout);
+
+ populatePorts();
+
+ connect(m_portBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
+ this, [this](int index) {
+ Q_UNUSED(index);
+ populateSpeeds();
+ emit optionsChanged();
+ });
+ connect(m_speedBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
+ this, &JLinkUvscAdapterOptionsWidget::optionsChanged);
+}
+
+void JLinkUvscAdapterOptionsWidget::setAdapterOptions(
+ const JLinkUvscAdapterOptions &adapterOpts)
+{
+ for (auto index = 0; m_portBox->count(); ++index) {
+ const JLinkUvscAdapterOptions::Port port = portAt(index);
+ if (port == adapterOpts.port) {
+ m_portBox->setCurrentIndex(index);
+ break;
+ }
+ }
+
+ populateSpeeds();
+
+ for (auto index = 0; m_speedBox->count(); ++index) {
+ const JLinkUvscAdapterOptions::Speed speed = speedAt(index);
+ if (speed == adapterOpts.speed) {
+ m_speedBox->setCurrentIndex(index);
+ break;
+ }
+ }
+}
+
+JLinkUvscAdapterOptions JLinkUvscAdapterOptionsWidget::adapterOptions() const
+{
+ const auto port = portAt(m_portBox->currentIndex());
+ const auto speed = speedAt(m_speedBox->currentIndex());
+ return {port, speed};
+}
+
+JLinkUvscAdapterOptions::Port JLinkUvscAdapterOptionsWidget::portAt(int index) const
+{
+ return static_cast<JLinkUvscAdapterOptions::Port>(m_portBox->itemData(index).toInt());
+}
+
+JLinkUvscAdapterOptions::Speed JLinkUvscAdapterOptionsWidget::speedAt(int index) const
+{
+ return static_cast<JLinkUvscAdapterOptions::Speed>(m_speedBox->itemData(index).toInt());
+}
+
+void JLinkUvscAdapterOptionsWidget::populatePorts()
+{
+ m_portBox->addItem(tr("JTAG"), JLinkUvscAdapterOptions::JTAG);
+ m_portBox->addItem(tr("SWD"), JLinkUvscAdapterOptions::SWD);
+}
+
+void JLinkUvscAdapterOptionsWidget::populateSpeeds()
+{
+ m_speedBox->clear();
+ m_speedBox->addItem(tr("50MHz"), JLinkUvscAdapterOptions::Speed_50MHz);
+ m_speedBox->addItem(tr("33MHz"), JLinkUvscAdapterOptions::Speed_33MHz);
+ m_speedBox->addItem(tr("25MHz"), JLinkUvscAdapterOptions::Speed_25MHz);
+ m_speedBox->addItem(tr("20MHz"), JLinkUvscAdapterOptions::Speed_20MHz);
+ m_speedBox->addItem(tr("10MHz"), JLinkUvscAdapterOptions::Speed_10MHz);
+ m_speedBox->addItem(tr("5MHz"), JLinkUvscAdapterOptions::Speed_5MHz);
+ m_speedBox->addItem(tr("3MHz"), JLinkUvscAdapterOptions::Speed_3MHz);
+ m_speedBox->addItem(tr("2MHz"), JLinkUvscAdapterOptions::Speed_2MHz);
+ m_speedBox->addItem(tr("1MHz"), JLinkUvscAdapterOptions::Speed_1MHz);
+ m_speedBox->addItem(tr("500kHz"), JLinkUvscAdapterOptions::Speed_500kHz);
+ m_speedBox->addItem(tr("200kHz"), JLinkUvscAdapterOptions::Speed_200kHz);
+ m_speedBox->addItem(tr("100kHz"), JLinkUvscAdapterOptions::Speed_100kHz);
+}
+
+} // namespace Internal
+} // namespace BareMetal
diff --git a/src/plugins/baremetal/debugservers/uvsc/jlinkuvscserverprovider.h b/src/plugins/baremetal/debugservers/uvsc/jlinkuvscserverprovider.h
new file mode 100644
index 0000000000..aae713d8ad
--- /dev/null
+++ b/src/plugins/baremetal/debugservers/uvsc/jlinkuvscserverprovider.h
@@ -0,0 +1,133 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com>
+** 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 "uvscserverprovider.h"
+
+QT_BEGIN_NAMESPACE
+class QComboBox;
+QT_END_NAMESPACE
+
+namespace BareMetal {
+namespace Internal {
+
+// JLinkUvscAdapterOptions
+
+class JLinkUvscAdapterOptions final
+{
+public:
+ enum Port { JTAG, SWD };
+ enum Speed {
+ Speed_50MHz = 50000, Speed_33MHz = 33000, Speed_25MHz = 25000,
+ Speed_20MHz = 20000, Speed_10MHz = 10000, Speed_5MHz = 5000,
+ Speed_3MHz = 3000, Speed_2MHz = 2000, Speed_1MHz = 1000,
+ Speed_500kHz = 500, Speed_200kHz = 200, Speed_100kHz = 100,
+ };
+ Port port = Port::SWD;
+ Speed speed = Speed::Speed_1MHz;
+
+ QVariantMap toMap() const;
+ bool fromMap(const QVariantMap &data);
+ bool operator==(const JLinkUvscAdapterOptions &other) const;
+};
+
+// JLinkUvscServerProvider
+
+class JLinkUvscServerProvider final : public UvscServerProvider
+{
+public:
+ QVariantMap toMap() const final;
+ bool fromMap(const QVariantMap &data) final;
+
+ bool operator==(const IDebugServerProvider &other) const final;
+ Utils::FilePath optionsFilePath(Debugger::DebuggerRunTool *runTool,
+ QString &errorMessage) const final;
+private:
+ explicit JLinkUvscServerProvider();
+
+ JLinkUvscAdapterOptions m_adapterOpts;
+
+ friend class JLinkUvscServerProviderConfigWidget;
+ friend class JLinkUvscServerProviderFactory;
+ friend class JLinkUvProjectOptions;
+};
+
+// JLinkUvscServerProviderFactory
+
+class JLinkUvscServerProviderFactory final : public IDebugServerProviderFactory
+{
+public:
+ JLinkUvscServerProviderFactory();
+};
+
+// JLinkUvscServerProviderConfigWidget
+
+class JLinkUvscAdapterOptionsWidget;
+class JLinkUvscServerProviderConfigWidget final : public UvscServerProviderConfigWidget
+{
+ Q_OBJECT
+
+public:
+ explicit JLinkUvscServerProviderConfigWidget(JLinkUvscServerProvider *provider);
+
+private:
+ void apply() override;
+ void discard() override;
+
+ void setAdapterOpitons(const JLinkUvscAdapterOptions &adapterOpts);
+ JLinkUvscAdapterOptions adapterOptions() const;
+ void setFromProvider();
+
+ JLinkUvscAdapterOptionsWidget *m_adapterOptionsWidget = nullptr;
+};
+
+// JLinkUvscAdapterOptionsWidget
+
+class JLinkUvscAdapterOptionsWidget final : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit JLinkUvscAdapterOptionsWidget(QWidget *parent = nullptr);
+ void setAdapterOptions(const JLinkUvscAdapterOptions &adapterOpts);
+ JLinkUvscAdapterOptions adapterOptions() const;
+
+signals:
+ void optionsChanged();
+
+private:
+ JLinkUvscAdapterOptions::Port portAt(int index) const;
+ JLinkUvscAdapterOptions::Speed speedAt(int index) const;
+
+ void populatePorts();
+ void populateSpeeds();
+
+ QComboBox *m_portBox = nullptr;
+ QComboBox *m_speedBox = nullptr;
+};
+
+} // namespace Internal
+} // namespace BareMetal
diff --git a/src/plugins/baremetal/debugservers/uvsc/stlinkuvscserverprovider.cpp b/src/plugins/baremetal/debugservers/uvsc/stlinkuvscserverprovider.cpp
index 074bce6164..98adbb212a 100644
--- a/src/plugins/baremetal/debugservers/uvsc/stlinkuvscserverprovider.cpp
+++ b/src/plugins/baremetal/debugservers/uvsc/stlinkuvscserverprovider.cpp
@@ -68,12 +68,6 @@ static QString buildAdapterOptions(const StLinkUvscAdapterOptions &opts)
return s;
}
-static QString buildDllRegistryKey(const DriverSelection &driver)
-{
- const QFileInfo fi(driver.dll);
- return fi.baseName();
-}
-
static QString buildDllRegistryName(const DeviceSelection &device,
const StLinkUvscAdapterOptions &opts)
{
@@ -81,13 +75,11 @@ static QString buildDllRegistryName(const DeviceSelection &device,
return {};
const DeviceSelection::Algorithm algorithm = device.algorithms.at(device.algorithmIndex);
const QFileInfo path(algorithm.path);
- const QString start = algorithm.start.startsWith("0x") ? algorithm.start.mid(2)
- : algorithm.start;
- const QString size = algorithm.size.startsWith("0x") ? algorithm.size.mid(2)
- : algorithm.size;
+ const QString flashStart = UvscServerProvider::adjustFlashAlgorithmProperty(algorithm.flashStart);
+ const QString flashSize = UvscServerProvider::adjustFlashAlgorithmProperty(algorithm.flashSize);
const QString adaptOpts = buildAdapterOptions(opts);
return QStringLiteral(" %6 -FN1 -FF0%1 -FS0%2 -FL0%3 -FP0($$Device:%4$%5)")
- .arg(path.fileName(), start, size, device.name, path.filePath(), adaptOpts);
+ .arg(path.fileName(), flashStart, flashSize, device.name, path.filePath(), adaptOpts);
}
// StLinkUvProjectOptions
@@ -107,7 +99,7 @@ public:
const auto dllRegistry = m_targetOption->appendPropertyGroup("TargetDriverDllRegistry");
const auto setRegEntry = dllRegistry->appendPropertyGroup("SetRegEntry");
setRegEntry->appendProperty("Number", 0);
- const QString key = buildDllRegistryKey(driver);
+ const QString key = UvscServerProvider::buildDllRegistryKey(driver);
setRegEntry->appendProperty("Key", key);
const QString name = buildDllRegistryName(device, provider->m_adapterOpts);
setRegEntry->appendProperty("Name", name);
diff --git a/src/plugins/baremetal/debugservers/uvsc/uvproject.cpp b/src/plugins/baremetal/debugservers/uvsc/uvproject.cpp
index 785582f137..1834dbfe50 100644
--- a/src/plugins/baremetal/debugservers/uvsc/uvproject.cpp
+++ b/src/plugins/baremetal/debugservers/uvsc/uvproject.cpp
@@ -111,6 +111,11 @@ static void extractAllFiles(const DebuggerRunTool *runTool, QStringList &include
}
}
+QString buildPackageId(const DeviceSelection &selection)
+{
+ return buildPackageId(selection.package);
+}
+
// Project
Project::Project(const UvscServerProvider *provider, DebuggerRunTool *runTool)
diff --git a/src/plugins/baremetal/debugservers/uvsc/uvproject.h b/src/plugins/baremetal/debugservers/uvsc/uvproject.h
index 6642cf6cc3..ccc11bd611 100644
--- a/src/plugins/baremetal/debugservers/uvsc/uvproject.h
+++ b/src/plugins/baremetal/debugservers/uvsc/uvproject.h
@@ -39,6 +39,11 @@ class UvscServerProvider;
namespace Uv {
+class DeviceSelection;
+
+// Helper function.
+QString buildPackageId(const DeviceSelection &selection);
+
// UvProject
class Project final : public Gen::Xml::Project
diff --git a/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.cpp b/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.cpp
index 1c10441f1b..59b0b6d373 100644
--- a/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.cpp
+++ b/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.cpp
@@ -66,6 +66,17 @@ constexpr int defaultPortNumber = 5101;
// UvscServerProvider
+QString UvscServerProvider::buildDllRegistryKey(const DriverSelection &driver)
+{
+ const QFileInfo fi(driver.dll);
+ return fi.baseName();
+}
+
+QString UvscServerProvider::adjustFlashAlgorithmProperty(const QString &property)
+{
+ return property.startsWith("0x") ? property.mid(2) : property;
+}
+
UvscServerProvider::UvscServerProvider(const QString &id)
: IDebugServerProvider(id)
{
@@ -201,8 +212,12 @@ bool UvscServerProvider::aboutToRun(DebuggerRunTool *runTool, QString &errorMess
if (!optFilePath.exists())
return false;
+ const FilePath peripheralDescriptionFile = FilePath::fromString(m_deviceSelection.svd);
+
Runnable inferior;
inferior.executable = bin;
+ inferior.extraData.insert(Debugger::Constants::kPeripheralDescriptionFile,
+ peripheralDescriptionFile.toVariant());
inferior.extraData.insert(Debugger::Constants::kUVisionProjectFilePath, projFilePath.toString());
inferior.extraData.insert(Debugger::Constants::kUVisionOptionsFilePath, optFilePath.toString());
inferior.extraData.insert(Debugger::Constants::kUVisionSimulator, isSimulator());
@@ -294,7 +309,7 @@ UvscServerProviderConfigWidget::UvscServerProviderConfigWidget(UvscServerProvide
this, &UvscServerProviderConfigWidget::dirty);
auto updateSelectors = [this]() {
- const FilePath toolsIniFile = m_toolsIniChooser->fileName();
+ const FilePath toolsIniFile = m_toolsIniChooser->filePath();
m_deviceSelector->setToolsIniFile(toolsIniFile);
m_driverSelector->setToolsIniFile(toolsIniFile);
};
@@ -320,12 +335,12 @@ void UvscServerProviderConfigWidget::discard()
void UvscServerProviderConfigWidget::setToolsIniFile(const Utils::FilePath &toolsIniFile)
{
- m_toolsIniChooser->setFileName(toolsIniFile);
+ m_toolsIniChooser->setFilePath(toolsIniFile);
}
Utils::FilePath UvscServerProviderConfigWidget::toolsIniFile() const
{
- return m_toolsIniChooser->fileName();
+ return m_toolsIniChooser->filePath();
}
void UvscServerProviderConfigWidget::setDeviceSelection(const DeviceSelection &deviceSelection)
@@ -352,7 +367,7 @@ void UvscServerProviderConfigWidget::setFromProvider()
{
const auto p = static_cast<UvscServerProvider *>(m_provider);
m_hostWidget->setChannel(p->channel());
- m_toolsIniChooser->setFileName(p->toolsIniFile());
+ m_toolsIniChooser->setFilePath(p->toolsIniFile());
m_deviceSelector->setSelection(p->deviceSelection());
m_driverSelector->setSelection(p->driverSelection());
}
diff --git a/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.h b/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.h
index f4527f03a4..dbc054e02f 100644
--- a/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.h
+++ b/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.h
@@ -78,6 +78,9 @@ public:
bool isValid() const override;
QString channelString() const final;
+ static QString buildDllRegistryKey(const Uv::DriverSelection &driver);
+ static QString adjustFlashAlgorithmProperty(const QString &property);
+
protected:
explicit UvscServerProvider(const QString &id);
explicit UvscServerProvider(const UvscServerProvider &other);
diff --git a/src/plugins/baremetal/debugservers/uvsc/uvscservers.pri b/src/plugins/baremetal/debugservers/uvsc/uvscservers.pri
index 1b1ce579f3..0d5cba4113 100644
--- a/src/plugins/baremetal/debugservers/uvsc/uvscservers.pri
+++ b/src/plugins/baremetal/debugservers/uvsc/uvscservers.pri
@@ -1,6 +1,7 @@
HEADERS += \
$$PWD/simulatoruvscserverprovider.h \
$$PWD/stlinkuvscserverprovider.h \
+ $$PWD/jlinkuvscserverprovider.h \
$$PWD/uvproject.h \
$$PWD/uvprojectwriter.h \
$$PWD/uvscserverprovider.h \
@@ -19,6 +20,7 @@ HEADERS += \
SOURCES += \
$$PWD/simulatoruvscserverprovider.cpp \
$$PWD/stlinkuvscserverprovider.cpp \
+ $$PWD/jlinkuvscserverprovider.cpp \
$$PWD/uvproject.cpp \
$$PWD/uvprojectwriter.cpp \
$$PWD/uvscserverprovider.cpp \
diff --git a/src/plugins/baremetal/debugservers/uvsc/uvtargetdevicemodel.cpp b/src/plugins/baremetal/debugservers/uvsc/uvtargetdevicemodel.cpp
index aaad906214..8d0e610fb3 100644
--- a/src/plugins/baremetal/debugservers/uvsc/uvtargetdevicemodel.cpp
+++ b/src/plugins/baremetal/debugservers/uvsc/uvtargetdevicemodel.cpp
@@ -67,8 +67,26 @@ static QString extractPackVersion(const QString &packFilePath)
static QStringList findKeilPackFiles(const QString &path)
{
QStringList files;
- // Search for the STMicroelectronics devices.
- QDirIterator it(path, {"STM*_DFP"}, QDir::Dirs);
+ // Search for STMicroelectronics and NXP S32 devices.
+ QDirIterator it(path, {"STM*_DFP", "S32*_DFP"}, QDir::Dirs);
+ while (it.hasNext()) {
+ const QDir dfpDir(it.next());
+ const QFileInfoList entries = dfpDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot,
+ QDir::Name);
+ if (entries.isEmpty())
+ continue;
+ QDirIterator fit(entries.last().absoluteFilePath(), {"*.pdsc"},
+ QDir::Files | QDir::NoSymLinks);
+ while (fit.hasNext())
+ files.push_back(fit.next());
+ }
+ return files;
+}
+
+static QStringList findNordicSemiconductorPackFiles(const QString &path)
+{
+ QStringList files;
+ QDirIterator it(path, {"*_DeviceFamilyPack"}, QDir::Dirs);
while (it.hasNext()) {
const QDir dfpDir(it.next());
const QFileInfoList entries = dfpDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot,
@@ -115,8 +133,10 @@ static void fillAlgorithms(QXmlStreamReader &in, DeviceSelection::Algorithms &al
in.skipCurrentElement();
DeviceSelection::Algorithm algorithm;
algorithm.path = attrs.value("name").toString();
- algorithm.start = attrs.value("start").toString();
- algorithm.size = attrs.value("size").toString();
+ algorithm.flashStart = attrs.value("start").toString();
+ algorithm.flashSize = attrs.value("size").toString();
+ algorithm.ramStart = attrs.value("RAMstart").toString();
+ algorithm.ramSize = attrs.value("RAMsize").toString();
algorithms.push_back(algorithm);
}
@@ -147,9 +167,10 @@ static void fillSvd(QXmlStreamReader &in, QString &svd)
class DeviceSelectionItem final : public TreeItem
{
public:
+ enum Type { Root, Package, Family, SubFamily, Device, DeviceVariant };
enum Column { NameColumn, VersionColumn, VendorNameColumn };
- explicit DeviceSelectionItem()
- {}
+ explicit DeviceSelectionItem(const Type &type = Root)
+ : type(type) {}
QVariant data(int column, int role) const final
{
@@ -170,6 +191,7 @@ public:
return hasChildren() ? Qt::ItemIsEnabled : (Qt::ItemIsEnabled | Qt::ItemIsSelectable);
}
+ const Type type;
QString desc;
QString fullPath;
QString name;
@@ -204,11 +226,13 @@ void DeviceSelectionModel::fillAllPacks(const FilePath &toolsIniFile)
return;
QStringList allPackFiles;
- QDirIterator it(packsPath, {"Keil"}, QDir::Dirs | QDir::NoDotAndDotDot);
+ QDirIterator it(packsPath, {"Keil", "NordicSemiconductor"}, QDir::Dirs | QDir::NoDotAndDotDot);
while (it.hasNext()) {
const QString path = it.next();
if (path.endsWith("/Keil"))
allPackFiles << findKeilPackFiles(path);
+ else if (path.endsWith("/NordicSemiconductor"))
+ allPackFiles << findNordicSemiconductorPackFiles(path);
}
if (allPackFiles.isEmpty())
@@ -235,7 +259,7 @@ void DeviceSelectionModel::parsePackage(const QString &packageFile)
void DeviceSelectionModel::parsePackage(QXmlStreamReader &in, const QString &packageFile)
{
// Create and fill the 'package' item.
- const auto child = new DeviceSelectionItem;
+ const auto child = new DeviceSelectionItem(DeviceSelectionItem::Package);
rootItem()->appendChild(child);
child->fullPath = packageFile;
child->version = extractPackVersion(packageFile);
@@ -266,7 +290,7 @@ void DeviceSelectionModel::parsePackage(QXmlStreamReader &in, const QString &pac
void DeviceSelectionModel::parseFamily(QXmlStreamReader &in, DeviceSelectionItem *parent)
{
// Create and fill the 'family' item.
- const auto child = new DeviceSelectionItem;
+ const auto child = new DeviceSelectionItem(DeviceSelectionItem::Family);
parent->appendChild(child);
const QXmlStreamAttributes attrs = in.attributes();
child->name = attrs.value("Dfamily").toString();
@@ -275,6 +299,8 @@ void DeviceSelectionModel::parseFamily(QXmlStreamReader &in, DeviceSelectionItem
const QStringRef elementName = in.name();
if (elementName == "processor") {
fillCpu(in, child->cpu);
+ } else if (elementName == "algorithm") {
+ fillAlgorithms(in, child->algorithms);
} else if (elementName == "memory") {
fillMemories(in, child->memories);
} else if (elementName == "description") {
@@ -292,7 +318,7 @@ void DeviceSelectionModel::parseFamily(QXmlStreamReader &in, DeviceSelectionItem
void DeviceSelectionModel::parseSubFamily(QXmlStreamReader &in, DeviceSelectionItem *parent)
{
// Create and fill the 'sub-family' item.
- const auto child = new DeviceSelectionItem;
+ const auto child = new DeviceSelectionItem(DeviceSelectionItem::SubFamily);
parent->appendChild(child);
const QXmlStreamAttributes attrs = in.attributes();
child->name = attrs.value("DsubFamily").toString();
@@ -313,7 +339,7 @@ void DeviceSelectionModel::parseSubFamily(QXmlStreamReader &in, DeviceSelectionI
void DeviceSelectionModel::parseDevice(QXmlStreamReader &in, DeviceSelectionItem *parent)
{
// Create and fill the 'device' item.
- const auto child = new DeviceSelectionItem;
+ const auto child = new DeviceSelectionItem(DeviceSelectionItem::Device);
parent->appendChild(child);
const QXmlStreamAttributes attrs = in.attributes();
child->name = attrs.value("Dname").toString();
@@ -321,6 +347,10 @@ void DeviceSelectionModel::parseDevice(QXmlStreamReader &in, DeviceSelectionItem
const QStringRef elementName = in.name();
if (elementName == "processor") {
fillCpu(in, child->cpu);
+ } else if (elementName == "debug") {
+ fillSvd(in, child->svd);
+ } else if (elementName == "description") {
+ fillElementProperty(in, child->desc);
} else if (elementName == "memory") {
fillMemories(in, child->memories);
} else if (elementName == "algorithm") {
@@ -336,7 +366,7 @@ void DeviceSelectionModel::parseDevice(QXmlStreamReader &in, DeviceSelectionItem
void DeviceSelectionModel::parseDeviceVariant(QXmlStreamReader &in, DeviceSelectionItem *parent)
{
// Create and fill the 'device-variant' item.
- const auto child = new DeviceSelectionItem;
+ const auto child = new DeviceSelectionItem(DeviceSelectionItem::DeviceVariant);
parent->appendChild(child);
const QXmlStreamAttributes attrs = in.attributes();
child->name = attrs.value("Dvariant").toString();
@@ -391,31 +421,15 @@ DeviceSelection DeviceSelectionView::buildSelection(const DeviceSelectionItem *i
DeviceSelection::Memories &mems = selection.memories;
DeviceSelection::Package &pkg = selection.package;
- do {
+ auto extractBaseProps = [&selection, &algs, &cpu, &mems](const DeviceSelectionItem *item) {
if (selection.name.isEmpty())
selection.name = item->name;
- else if (selection.subfamily.isEmpty())
- selection.subfamily = item->name;
- else if (selection.family.isEmpty())
- selection.family = item->name;
- else if (pkg.name.isEmpty())
- pkg.name = item->name;
-
if (selection.desc.isEmpty())
selection.desc = item->desc;
- else if (pkg.desc.isEmpty())
- pkg.desc = item->desc;
-
if (selection.vendorId.isEmpty())
selection.vendorId = item->vendorId;
- else if (pkg.vendorId.isEmpty())
- pkg.vendorId = item->vendorId;
-
if (selection.vendorName.isEmpty())
selection.vendorName = item->vendorName;
- else if (pkg.vendorName.isEmpty())
- pkg.vendorName = item->vendorName;
-
if (selection.svd.isEmpty())
selection.svd = item->svd;
@@ -428,13 +442,6 @@ DeviceSelection DeviceSelectionView::buildSelection(const DeviceSelectionItem *i
if (cpu.mpu.isEmpty())
cpu.mpu = item->cpu.mpu;
- if (pkg.file.isEmpty())
- pkg.file = item->fullPath;
- if (pkg.url.isEmpty())
- pkg.url = item->url;
- if (pkg.version.isEmpty())
- pkg.version = item->version;
-
// Add only new flash algorithms.
for (const DeviceSelection::Algorithm &newAlg : item->algorithms) {
const bool contains = Utils::contains(algs, [&newAlg](const DeviceSelection::Algorithm &existAlg) {
@@ -452,8 +459,44 @@ DeviceSelection DeviceSelectionView::buildSelection(const DeviceSelectionItem *i
if (!contains)
mems.push_back(newMem);
}
+ };
+
+ auto extractPackageProps = [&pkg](const DeviceSelectionItem *item) {
+ pkg.desc = item->desc;
+ pkg.file = item->fullPath;
+ pkg.name = item->name;
+ pkg.url = item->url;
+ pkg.vendorId = item->vendorId;
+ pkg.vendorName = item->vendorName;
+ pkg.version = item->version;
+ };
+ do {
+ if (item->type == DeviceSelectionItem::DeviceVariant
+ || item->type == DeviceSelectionItem::Device) {
+ extractBaseProps(item);
+ } else if (item->type == DeviceSelectionItem::SubFamily) {
+ extractBaseProps(item);
+ if (selection.subfamily.isEmpty())
+ selection.subfamily = item->name;
+ } else if (item->type == DeviceSelectionItem::Family) {
+ extractBaseProps(item);
+ if (selection.family.isEmpty())
+ selection.family = item->name;
+ } else if (item->type == DeviceSelectionItem::Package) {
+ extractPackageProps(item);
+ }
} while ((item->level() > 1) && (item = static_cast<const DeviceSelectionItem *>(item->parent())));
+
+ // Fix relative SVD file sub-path to make it as an absolute file path.
+ if (!selection.svd.isEmpty()) {
+ const QFileInfo fi(selection.svd);
+ if (!fi.isAbsolute()) {
+ const QDir dir(QFileInfo(selection.package.file).path());
+ selection.svd = QFileInfo(dir, fi.filePath()).absoluteFilePath();
+ }
+ }
+
return selection;
}
diff --git a/src/plugins/baremetal/debugservers/uvsc/uvtargetdeviceselection.cpp b/src/plugins/baremetal/debugservers/uvsc/uvtargetdeviceselection.cpp
index 4b09a3d5df..7bb3eca896 100644
--- a/src/plugins/baremetal/debugservers/uvsc/uvtargetdeviceselection.cpp
+++ b/src/plugins/baremetal/debugservers/uvsc/uvtargetdeviceselection.cpp
@@ -27,7 +27,8 @@
#include <QComboBox>
#include <QDataWidgetMapper>
-#include <QHBoxLayout>
+#include <QGridLayout>
+#include <QLabel>
#include <QLineEdit>
using namespace Utils;
@@ -65,8 +66,10 @@ constexpr char deviceMemorySizeKeyC[] = "BareMetal.UvscServerProvider.DeviceMemo
// Device ALGORITHM data keys.
constexpr char deviceAlgorithmKeyC[] = "BareMetal.UvscServerProvider.DeviceAlgorithm";
constexpr char deviceAlgorithmPathKeyC[] = "BareMetal.UvscServerProvider.DeviceAlgorithmPath";
-constexpr char deviceAlgorithmStartKeyC[] = "BareMetal.UvscServerProvider.DeviceAlgorithmStart";
-constexpr char deviceAlgorithmSizeKeyC[] = "BareMetal.UvscServerProvider.DeviceAlgorithmSize";
+constexpr char deviceAlgorithmFlashStartKeyC[] = "BareMetal.UvscServerProvider.DeviceAlgorithmStart";
+constexpr char deviceAlgorithmFlashSizeKeyC[] = "BareMetal.UvscServerProvider.DeviceAlgorithmSize";
+constexpr char deviceAlgorithmRamStartKeyC[] = "BareMetal.UvscServerProvider.DeviceAlgorithmRamStart";
+constexpr char deviceAlgorithmRamSizeKeyC[] = "BareMetal.UvscServerProvider.DeviceAlgorithmRamSize";
constexpr char deviceAlgorithmIndexKeyC[] = "BareMetal.UvscServerProvider.DeviceAlgorithmIndex";
// DeviceSelection
@@ -110,8 +113,10 @@ QVariantMap DeviceSelection::toMap() const
for (const DeviceSelection::Algorithm &algorithm : qAsConst(algorithms)) {
QVariantMap m;
m.insert(deviceAlgorithmPathKeyC, algorithm.path);
- m.insert(deviceAlgorithmStartKeyC, algorithm.start);
- m.insert(deviceAlgorithmSizeKeyC, algorithm.size);
+ m.insert(deviceAlgorithmFlashStartKeyC, algorithm.flashStart);
+ m.insert(deviceAlgorithmFlashSizeKeyC, algorithm.flashSize);
+ m.insert(deviceAlgorithmRamStartKeyC, algorithm.ramStart);
+ m.insert(deviceAlgorithmRamSizeKeyC, algorithm.ramSize);
algorithmList.push_back(m);
}
map.insert(deviceAlgorithmKeyC, algorithmList);
@@ -159,8 +164,10 @@ void DeviceSelection::fromMap(const QVariantMap &map)
const auto m = entry.toMap();
DeviceSelection::Algorithm algorithm;
algorithm.path = m.value(deviceAlgorithmPathKeyC).toString();
- algorithm.start = m.value(deviceAlgorithmStartKeyC).toString();
- algorithm.size = m.value(deviceAlgorithmSizeKeyC).toString();
+ algorithm.flashStart = m.value(deviceAlgorithmFlashStartKeyC).toString();
+ algorithm.flashSize = m.value(deviceAlgorithmFlashSizeKeyC).toString();
+ algorithm.ramStart = m.value(deviceAlgorithmRamStartKeyC).toString();
+ algorithm.ramSize = m.value(deviceAlgorithmRamSizeKeyC).toString();
algorithms.push_back(algorithm);
}
}
@@ -186,7 +193,9 @@ bool DeviceSelection::Memory::operator==(const Memory &other) const
bool DeviceSelection::Algorithm::operator==(const Algorithm &other) const
{
- return path == other.path && start == other.start && size == other.size;
+ return path == other.path
+ && flashStart == other.flashStart && flashSize == other.flashSize
+ && ramStart == other.ramStart && ramSize == other.ramSize;
}
bool DeviceSelection::operator==(const DeviceSelection &other) const
@@ -297,7 +306,7 @@ void DeviceSelectionMemoryView::refresh()
class DeviceSelectionAlgorithmItem final : public TreeItem
{
public:
- enum Column { PathColumn, StartColumn, SizeColumn };
+ enum Column { PathColumn, FlashStartColumn, FlashSizeColumn, RamStartColumn, RamSizeColumn };
explicit DeviceSelectionAlgorithmItem(int index, DeviceSelection &selection)
: m_index(index), m_selection(selection)
{}
@@ -308,8 +317,10 @@ public:
const auto &algorithm = m_selection.algorithms.at(m_index);
switch (column) {
case PathColumn: return algorithm.path;
- case StartColumn: return algorithm.start;
- case SizeColumn: return algorithm.size;
+ case FlashStartColumn: return algorithm.flashStart;
+ case FlashSizeColumn: return algorithm.flashSize;
+ case RamStartColumn: return algorithm.ramStart;
+ case RamSizeColumn: return algorithm.ramSize;
}
}
return {};
@@ -320,11 +331,17 @@ public:
if (role == Qt::EditRole) {
auto &algorithm = m_selection.algorithms.at(m_index);
switch (column) {
- case StartColumn:
- algorithm.start = data.toString();
+ case FlashStartColumn:
+ algorithm.flashStart = data.toString();
return true;
- case SizeColumn:
- algorithm.size = data.toString();
+ case FlashSizeColumn:
+ algorithm.flashSize = data.toString();
+ return true;
+ case RamStartColumn:
+ algorithm.ramStart = data.toString();
+ return true;
+ case RamSizeColumn:
+ algorithm.ramSize = data.toString();
return true;
}
}
@@ -334,8 +351,10 @@ public:
Qt::ItemFlags flags(int column) const final
{
Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
- if (column == StartColumn || column == SizeColumn)
+ if (column == FlashStartColumn || column == FlashSizeColumn
+ || column == RamStartColumn || column == RamSizeColumn) {
flags |= Qt::ItemIsEditable;
+ }
return flags;
}
@@ -350,7 +369,7 @@ DeviceSelectionAlgorithmModel::DeviceSelectionAlgorithmModel(DeviceSelection &se
QObject *parent)
: TreeModel<TreeItem, DeviceSelectionAlgorithmItem>(parent), m_selection(selection)
{
- setHeader({tr("Name"), tr("Start"), tr("Size")});
+ setHeader({tr("Name"), tr("FLASH Start"), tr("FLASH Size"), tr("RAM Start"), tr("RAM Size")});
refresh();
}
@@ -373,25 +392,40 @@ DeviceSelectionAlgorithmView::DeviceSelectionAlgorithmView(DeviceSelection &sele
: QWidget(parent)
{
const auto model = new DeviceSelectionAlgorithmModel(selection, this);
- const auto layout = new QHBoxLayout;
+ const auto layout = new QGridLayout;
layout->setContentsMargins(0, 0, 0, 0);
m_comboBox = new QComboBox;
m_comboBox->setToolTip(tr("Algorithm path."));
m_comboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents);
m_comboBox->setModel(model);
- layout->addWidget(m_comboBox);
- const auto startEdit = new QLineEdit;
- startEdit->setToolTip(tr("Start address."));
- layout->addWidget(startEdit);
- const auto sizeEdit = new QLineEdit;
- sizeEdit->setToolTip(tr("Size."));
- layout->addWidget(sizeEdit);
+ layout->addWidget(m_comboBox, 0, 0, 1, 0);
+ // Add FLASH area settings.
+ const auto flashLabel = new QLabel(tr("FLASH:"));
+ layout->addWidget(flashLabel, 1, 0);
+ const auto flashStartEdit = new QLineEdit;
+ flashStartEdit->setToolTip(tr("Start address."));
+ layout->addWidget(flashStartEdit, 1, 1);
+ const auto flashSizeEdit = new QLineEdit;
+ flashSizeEdit->setToolTip(tr("Size."));
+ layout->addWidget(flashSizeEdit, 1, 2);
+ // Add RAM area settings.
+ const auto ramLabel = new QLabel(tr("RAM:"));
+ layout->addWidget(ramLabel, 2, 0);
+ const auto ramStartEdit = new QLineEdit;
+ ramStartEdit->setToolTip(tr("Start address."));
+ layout->addWidget(ramStartEdit, 2, 1);
+ const auto ramSizeEdit = new QLineEdit;
+ ramSizeEdit->setToolTip(tr("Size."));
+ layout->addWidget(ramSizeEdit, 2, 2);
+
setLayout(layout);
const auto mapper = new QDataWidgetMapper(this);
mapper->setModel(model);
- mapper->addMapping(startEdit, DeviceSelectionAlgorithmItem::StartColumn);
- mapper->addMapping(sizeEdit, DeviceSelectionAlgorithmItem::SizeColumn);
+ mapper->addMapping(flashStartEdit, DeviceSelectionAlgorithmItem::FlashStartColumn);
+ mapper->addMapping(flashSizeEdit, DeviceSelectionAlgorithmItem::FlashSizeColumn);
+ mapper->addMapping(ramStartEdit, DeviceSelectionAlgorithmItem::RamStartColumn);
+ mapper->addMapping(ramSizeEdit, DeviceSelectionAlgorithmItem::RamSizeColumn);
connect(m_comboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, [mapper, this](int index) {
@@ -403,8 +437,10 @@ DeviceSelectionAlgorithmView::DeviceSelectionAlgorithmView(DeviceSelection &sele
emit algorithmChanged(-1);
});
- connect(startEdit, &QLineEdit::editingFinished, mapper, &QDataWidgetMapper::submit);
- connect(sizeEdit, &QLineEdit::editingFinished, mapper, &QDataWidgetMapper::submit);
+ connect(flashStartEdit, &QLineEdit::editingFinished, mapper, &QDataWidgetMapper::submit);
+ connect(flashSizeEdit, &QLineEdit::editingFinished, mapper, &QDataWidgetMapper::submit);
+ connect(ramStartEdit, &QLineEdit::editingFinished, mapper, &QDataWidgetMapper::submit);
+ connect(ramSizeEdit, &QLineEdit::editingFinished, mapper, &QDataWidgetMapper::submit);
}
void DeviceSelectionAlgorithmView::setAlgorithm(int index)
diff --git a/src/plugins/baremetal/debugservers/uvsc/uvtargetdeviceselection.h b/src/plugins/baremetal/debugservers/uvsc/uvtargetdeviceselection.h
index fe9879cde5..67afedbec0 100644
--- a/src/plugins/baremetal/debugservers/uvsc/uvtargetdeviceselection.h
+++ b/src/plugins/baremetal/debugservers/uvsc/uvtargetdeviceselection.h
@@ -73,8 +73,10 @@ public:
struct Algorithm {
QString path;
- QString size;
- QString start;
+ QString flashSize;
+ QString flashStart;
+ QString ramSize;
+ QString ramStart;
bool operator==(const Algorithm &other) const;
};
diff --git a/src/plugins/baremetal/debugservers/uvsc/uvtargetdeviceviewer.cpp b/src/plugins/baremetal/debugservers/uvsc/uvtargetdeviceviewer.cpp
index 31a954c3c4..7d01bd1440 100644
--- a/src/plugins/baremetal/debugservers/uvsc/uvtargetdeviceviewer.cpp
+++ b/src/plugins/baremetal/debugservers/uvsc/uvtargetdeviceviewer.cpp
@@ -23,10 +23,12 @@
**
****************************************************************************/
-#include "uvproject.h" // for targetUVisionPath()
+#include "uvproject.h" // for buildPackageId()
#include "uvtargetdevicemodel.h"
#include "uvtargetdeviceviewer.h"
+#include <utils/pathchooser.h>
+
#include <QDialogButtonBox>
#include <QFormLayout>
#include <QHBoxLayout>
@@ -73,16 +75,24 @@ DeviceSelectorDetailsPanel::DeviceSelectorDetailsPanel(DeviceSelection &selectio
m_vendorEdit = new QLineEdit;
m_vendorEdit->setReadOnly(true);
layout->addRow(tr("Vendor:"), m_vendorEdit);
- m_fimilyEdit = new QLineEdit;;
- m_fimilyEdit->setReadOnly(true);
- layout->addRow(tr("Family:"), m_fimilyEdit);
- m_descEdit = new QPlainTextEdit;;
+ m_packageEdit = new QLineEdit;
+ m_packageEdit->setReadOnly(true);
+ layout->addRow(tr("Package:"), m_packageEdit);
+ m_descEdit = new QPlainTextEdit;
m_descEdit->setReadOnly(true);
layout->addRow(tr("Description:"), m_descEdit);
m_memoryView = new DeviceSelectionMemoryView(m_selection);
layout->addRow(tr("Memory:"), m_memoryView);
m_algorithmView = new DeviceSelectionAlgorithmView(m_selection);
- layout->addRow(tr("Flash algorithm"), m_algorithmView);
+ layout->addRow(tr("Flash algorithm:"), m_algorithmView);
+ m_peripheralDescriptionFileChooser = new Utils::PathChooser(this);
+ m_peripheralDescriptionFileChooser->setExpectedKind(Utils::PathChooser::File);
+ m_peripheralDescriptionFileChooser->setPromptDialogFilter(
+ tr("Peripheral description files (*.svd)"));
+ m_peripheralDescriptionFileChooser->setPromptDialogTitle(
+ tr("Select Peripheral Description File"));
+ layout->addRow(tr("Peripheral description file:"),
+ m_peripheralDescriptionFileChooser);
setLayout(layout);
refresh();
@@ -95,6 +105,8 @@ DeviceSelectorDetailsPanel::DeviceSelectorDetailsPanel(DeviceSelection &selectio
m_selection.algorithmIndex = index;
emit selectionChanged();
});
+ connect(m_peripheralDescriptionFileChooser, &Utils::PathChooser::pathChanged,
+ this, &DeviceSelectorDetailsPanel::selectionChanged);
}
static QString trimVendor(const QString &vendor)
@@ -106,11 +118,12 @@ static QString trimVendor(const QString &vendor)
void DeviceSelectorDetailsPanel::refresh()
{
m_vendorEdit->setText(trimVendor(m_selection.vendorName));
- m_fimilyEdit->setText(m_selection.family);
+ m_packageEdit->setText(buildPackageId(m_selection));
m_descEdit->setPlainText(m_selection.desc);
m_memoryView->refresh();
m_algorithmView->refresh();
m_algorithmView->setAlgorithm(m_selection.algorithmIndex);
+ m_peripheralDescriptionFileChooser->setPath(m_selection.svd);
}
// DeviceSelector
diff --git a/src/plugins/baremetal/debugservers/uvsc/uvtargetdeviceviewer.h b/src/plugins/baremetal/debugservers/uvsc/uvtargetdeviceviewer.h
index abc00e9c1c..a1639c4864 100644
--- a/src/plugins/baremetal/debugservers/uvsc/uvtargetdeviceviewer.h
+++ b/src/plugins/baremetal/debugservers/uvsc/uvtargetdeviceviewer.h
@@ -38,6 +38,8 @@ class QLineEdit;
class QPlainTextEdit;
QT_END_NAMESPACE
+namespace Utils { class PathChooser; }
+
namespace BareMetal {
namespace Internal {
namespace Uv {
@@ -103,10 +105,11 @@ signals:
private:
DeviceSelection &m_selection;
QLineEdit *m_vendorEdit = nullptr;
- QLineEdit *m_fimilyEdit = nullptr;
+ QLineEdit *m_packageEdit = nullptr;
QPlainTextEdit *m_descEdit = nullptr;
DeviceSelectionMemoryView *m_memoryView = nullptr;
DeviceSelectionAlgorithmView *m_algorithmView = nullptr;
+ Utils::PathChooser *m_peripheralDescriptionFileChooser = nullptr;
};
// DeviceSelectionDialog
diff --git a/src/plugins/baremetal/iarewparser.cpp b/src/plugins/baremetal/iarewparser.cpp
index 2686f58d90..01ce9de32e 100644
--- a/src/plugins/baremetal/iarewparser.cpp
+++ b/src/plugins/baremetal/iarewparser.cpp
@@ -28,9 +28,6 @@
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/task.h>
-#include <texteditor/fontsettings.h>
-#include <texteditor/texteditorsettings.h>
-
#include <QRegularExpression>
using namespace ProjectExplorer;
@@ -64,33 +61,11 @@ Core::Id IarParser::id()
void IarParser::newTask(const Task &task)
{
- doFlush();
+ flush();
m_lastTask = task;
m_lines = 1;
}
-void IarParser::amendDescription()
-{
- while (!m_descriptionParts.isEmpty())
- m_lastTask.description.append(m_descriptionParts.takeFirst());
-
- while (!m_snippets.isEmpty()) {
- const QString snippet = m_snippets.takeFirst();
- const int start = m_lastTask.description.count() + 1;
- m_lastTask.description.append('\n');
- m_lastTask.description.append(snippet);
-
- QTextLayout::FormatRange fr;
- fr.start = start;
- fr.length = m_lastTask.description.count() + 1;
- fr.format.setFont(TextEditor::TextEditorSettings::fontSettings().font());
- fr.format.setFontStyleHint(QFont::Monospace);
- m_lastTask.formats.append(fr);
-
- ++m_lines;
- }
-}
-
void IarParser::amendFilePath()
{
if (m_filePathParts.isEmpty())
@@ -145,12 +120,12 @@ bool IarParser::parseErrorOrFatalErrorDetailsMessage2(const QString &lne)
return true;
}
-bool IarParser::parseWarningOrErrorOrFatalErrorDetailsMessage1(const QString &lne)
+OutputLineParser::Result IarParser::parseWarningOrErrorOrFatalErrorDetailsMessage1(const QString &lne)
{
const QRegularExpression re("^\"(.+)\",(\\d+)?\\s+(Warning|Error|Fatal error)\\[(.+)\\].+$");
const QRegularExpressionMatch match = re.match(lne);
if (!match.hasMatch())
- return false;
+ return Status::NotHandled;
enum CaptureIndex { FilePathIndex = 1, LineNumberIndex,
MessageTypeIndex, MessageCodeIndex };
const Utils::FilePath fileName = Utils::FilePath::fromUserInput(
@@ -158,13 +133,16 @@ bool IarParser::parseWarningOrErrorOrFatalErrorDetailsMessage1(const QString &ln
const int lineno = match.captured(LineNumberIndex).toInt();
const Task::TaskType type = taskType(match.captured(MessageTypeIndex));
// A full description will be received later on next lines.
- newTask(CompileTask(type, {}, fileName, lineno));
+ newTask(CompileTask(type, {}, absoluteFilePath(fileName), lineno));
const QString firstPart = QString("[%1]: ").arg(match.captured(MessageCodeIndex));
m_descriptionParts.append(firstPart);
m_expectDescription = true;
m_expectSnippet = false;
m_expectFilePath = false;
- return true;
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, m_lastTask.file, m_lastTask.line, match,
+ FilePathIndex);
+ return {Status::InProgress, linkSpecs};
}
bool IarParser::parseErrorInCommandLineMessage(const QString &lne)
@@ -190,67 +168,70 @@ bool IarParser::parseErrorMessage1(const QString &lne)
return true;
}
-void IarParser::stdError(const QString &line)
+OutputLineParser::Result IarParser::handleLine(const QString &line, OutputFormat type)
{
- IOutputParser::stdError(line);
-
const QString lne = rightTrimmed(line);
+ if (type == StdOutFormat) {
+ // The call sequence has the meaning!
+ const bool leastOneParsed = parseErrorInCommandLineMessage(lne)
+ || parseErrorMessage1(lne);
+ if (!leastOneParsed) {
+ flush();
+ return Status::NotHandled;
+ }
+ return Status::InProgress;
+ }
if (parseErrorOrFatalErrorDetailsMessage1(lne))
- return;
+ return Status::InProgress;
if (parseErrorOrFatalErrorDetailsMessage2(lne))
- return;
- if (parseWarningOrErrorOrFatalErrorDetailsMessage1(lne))
- return;
+ return Status::InProgress;
+ const Result res = parseWarningOrErrorOrFatalErrorDetailsMessage1(lne);
+ if (res.status != Status::NotHandled)
+ return res;
- if (lne.isEmpty()) {
- //
- } else if (!lne.startsWith(' ')) {
- return;
- } else if (m_expectFilePath) {
+ if (m_expectFilePath) {
if (lne.endsWith(']')) {
const QString lastPart = lne.left(lne.size() - 1);
m_filePathParts.push_back(lastPart);
+ flush();
+ return Status::Done;
} else {
m_filePathParts.push_back(lne);
- return;
+ return Status::InProgress;
}
- } else if (m_expectSnippet) {
+ }
+ if (m_expectSnippet && lne.startsWith(' ')) {
if (!lne.endsWith("Fatal error detected, aborting.")) {
m_snippets.push_back(lne);
- return;
+ return Status::InProgress;
}
} else if (m_expectDescription) {
if (!lne.startsWith(" ")) {
m_descriptionParts.push_back(lne.trimmed());
- return;
+ return Status::InProgress;
}
}
- doFlush();
-}
-
-void IarParser::stdOutput(const QString &line)
-{
- IOutputParser::stdOutput(line);
-
- const QString lne = rightTrimmed(line);
-
- // The call sequence has the meaning!
- const bool leastOneParsed = parseErrorInCommandLineMessage(lne)
- || parseErrorMessage1(lne);
- if (!leastOneParsed)
- return;
+ if (!m_lastTask.isNull()) {
+ flush();
+ return Status::Done;
+ }
- doFlush();
+ return Status::NotHandled;
}
-void IarParser::doFlush()
+void IarParser::flush()
{
if (m_lastTask.isNull())
return;
- amendDescription();
+ while (!m_descriptionParts.isEmpty())
+ m_lastTask.summary.append(m_descriptionParts.takeFirst());
+ m_lastTask.details = m_snippets;
+ m_snippets.clear();
+ m_lines += m_lastTask.details.count();
+ setDetailsFormat(m_lastTask);
amendFilePath();
m_expectSnippet = true;
@@ -259,7 +240,7 @@ void IarParser::doFlush()
Task t = m_lastTask;
m_lastTask.clear();
- emit addTask(t, m_lines, 1);
+ scheduleTask(t, m_lines, 1);
m_lines = 0;
}
@@ -300,7 +281,7 @@ void BareMetalPlugin::testIarOutputParsers_data()
QTest::newRow("Error in command line")
<< QString::fromLatin1("Error in command line: Some error")
<< OutputParserTester::STDOUT
- << QString::fromLatin1("Error in command line: Some error\n")
+ << QString()
<< QString()
<< (Tasks() << CompileTask(Task::Error,
"Error in command line: Some error"))
@@ -309,7 +290,7 @@ void BareMetalPlugin::testIarOutputParsers_data()
QTest::newRow("Linker error")
<< QString::fromLatin1("Error[e46]: Some error")
<< OutputParserTester::STDOUT
- << QString::fromLatin1("Error[e46]: Some error\n")
+ << QString()
<< QString()
<< (Tasks() << CompileTask(Task::Error,
"[e46]: Some error"))
@@ -321,8 +302,7 @@ void BareMetalPlugin::testIarOutputParsers_data()
" Some warning \"foo\" bar")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("\"c:\\foo\\main.c\",63 Warning[Pe223]:\n"
- " Some warning \"foo\" bar\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Warning,
"[Pe223]: Some warning \"foo\" bar",
Utils::FilePath::fromUserInput("c:\\foo\\main.c"),
@@ -336,10 +316,7 @@ void BareMetalPlugin::testIarOutputParsers_data()
" Some warning")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1(" some_detail;\n"
- " ^\n"
- "\"c:\\foo\\main.c\",63 Warning[Pe223]:\n"
- " Some warning\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Warning,
"[Pe223]: Some warning\n"
" some_detail;\n"
@@ -354,9 +331,7 @@ void BareMetalPlugin::testIarOutputParsers_data()
" , split")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("\"c:\\foo\\main.c\",63 Warning[Pe223]:\n"
- " Some warning\n"
- " , split\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Warning,
"[Pe223]: Some warning, split",
FilePath::fromUserInput("c:\\foo\\main.c"),
@@ -368,8 +343,7 @@ void BareMetalPlugin::testIarOutputParsers_data()
" Some error")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("\"c:\\foo\\main.c\",63 Error[Pe223]:\n"
- " Some error\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Error,
"[Pe223]: Some error",
FilePath::fromUserInput("c:\\foo\\main.c"),
@@ -383,10 +357,7 @@ void BareMetalPlugin::testIarOutputParsers_data()
" Some error")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1(" some_detail;\n"
- " ^\n"
- "\"c:\\foo\\main.c\",63 Error[Pe223]:\n"
- " Some error\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Error,
"[Pe223]: Some error\n"
" some_detail;\n"
@@ -401,9 +372,7 @@ void BareMetalPlugin::testIarOutputParsers_data()
" , split")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("\"c:\\foo\\main.c\",63 Error[Pe223]:\n"
- " Some error\n"
- " , split\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Error,
"[Pe223]: Some error, split",
FilePath::fromUserInput("c:\\foo\\main.c"),
@@ -417,10 +386,7 @@ void BareMetalPlugin::testIarOutputParsers_data()
"]")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("Error[Li005]: Some error \"foo\" [referenced from c:\\fo\n"
- " o\\bar\\mai\n"
- " n.c.o\n"
- "]\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Error,
"[Li005]: Some error \"foo\"",
FilePath::fromUserInput("c:\\foo\\bar\\main.c.o")))
@@ -433,10 +399,7 @@ void BareMetalPlugin::testIarOutputParsers_data()
"Fatal error detected, aborting.")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("Fatal error[Su011]: Some error:\n"
- " c:\\foo.c\n"
- " c:\\bar.c\n"
- "Fatal error detected, aborting.\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Error,
"[Su011]: Some error:\n"
" c:\\foo.c\n"
@@ -447,7 +410,7 @@ void BareMetalPlugin::testIarOutputParsers_data()
<< QString::fromLatin1("At end of source Error[Pe040]: Some error \";\"")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("At end of source Error[Pe040]: Some error \";\"\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Error,
"[Pe040]: Some error \";\""))
<< QString();
@@ -456,7 +419,7 @@ void BareMetalPlugin::testIarOutputParsers_data()
void BareMetalPlugin::testIarOutputParsers()
{
OutputParserTester testbench;
- testbench.appendOutputParser(new IarParser);
+ testbench.addLineParser(new IarParser);
QFETCH(QString, input);
QFETCH(OutputParserTester::Channel, inputChannel);
QFETCH(Tasks, tasks);
diff --git a/src/plugins/baremetal/iarewparser.h b/src/plugins/baremetal/iarewparser.h
index 28cd89960f..92b38bd26f 100644
--- a/src/plugins/baremetal/iarewparser.h
+++ b/src/plugins/baremetal/iarewparser.h
@@ -33,7 +33,7 @@ namespace Internal {
// IarParser
-class IarParser final : public ProjectExplorer::IOutputParser
+class IarParser final : public ProjectExplorer::OutputTaskParser
{
Q_OBJECT
@@ -48,13 +48,12 @@ private:
bool parseErrorOrFatalErrorDetailsMessage1(const QString &lne);
bool parseErrorOrFatalErrorDetailsMessage2(const QString &lne);
- bool parseWarningOrErrorOrFatalErrorDetailsMessage1(const QString &lne);
+ Result parseWarningOrErrorOrFatalErrorDetailsMessage1(const QString &lne);
bool parseErrorInCommandLineMessage(const QString &lne);
bool parseErrorMessage1(const QString &lne);
- void stdError(const QString &line) final;
- void stdOutput(const QString &line) final;
- void doFlush() final;
+ Result handleLine(const QString &line, Utils::OutputFormat type) final;
+ void flush() final;
ProjectExplorer::Task m_lastTask;
int m_lines = 0;
diff --git a/src/plugins/baremetal/iarewtoolchain.cpp b/src/plugins/baremetal/iarewtoolchain.cpp
index b16d5465c7..48b1a18a31 100644
--- a/src/plugins/baremetal/iarewtoolchain.cpp
+++ b/src/plugins/baremetal/iarewtoolchain.cpp
@@ -37,6 +37,7 @@
#include <utils/environment.h>
#include <utils/pathchooser.h>
#include <utils/qtcassert.h>
+#include <utils/qtcprocess.h>
#include <utils/synchronousprocess.h>
#include <QDebug>
@@ -58,6 +59,7 @@ namespace Internal {
// Helpers:
static const char compilerCommandKeyC[] = "BareMetal.IarToolChain.CompilerPath";
+static const char compilerPlatformCodeGenFlagsKeyC[] = "BareMetal.IarToolChain.PlatformCodeGenFlags";
static const char targetAbiKeyC[] = "BareMetal.IarToolChain.TargetAbi";
static bool compilerExists(const FilePath &compilerPath)
@@ -69,17 +71,23 @@ static bool compilerExists(const FilePath &compilerPath)
static QString cppLanguageOption(const FilePath &compiler)
{
const QString baseName = compiler.toFileInfo().baseName();
- if (baseName == "iccarm" || baseName == "iccrl78")
+ if (baseName == "iccarm" || baseName == "iccrl78"
+ || baseName == "iccrh850" || baseName == "iccrx"
+ || baseName == "iccriscv") {
return QString("--c++");
+ }
if (baseName == "icc8051" || baseName == "iccavr"
- || baseName == "iccstm8" || baseName == "icc430") {
+ || baseName == "iccstm8" || baseName == "icc430"
+ || baseName == "iccv850" || baseName == "icc78k"
+ || baseName == "iccavr32" || baseName == "iccsh"
+ || baseName == "icccf" || baseName == "iccm32c") {
return QString("--ec++");
}
return {};
}
-static Macros dumpPredefinedMacros(const FilePath &compiler, const Core::Id languageId,
- const QStringList &env)
+static Macros dumpPredefinedMacros(const FilePath &compiler, const QStringList &extraArgs,
+ const Core::Id languageId, const QStringList &env)
{
if (compiler.isEmpty() || !compiler.toFileInfo().isExecutable())
return {};
@@ -100,6 +108,7 @@ static Macros dumpPredefinedMacros(const FilePath &compiler, const Core::Id lang
CommandLine cmd(compiler, {fakeIn.fileName()});
if (languageId == ProjectExplorer::Constants::CXX_LANGUAGE_ID)
cmd.addArg(cppLanguageOption(compiler));
+ cmd.addArgs(extraArgs);
cmd.addArg("--predef_macros");
cmd.addArg(outpath);
@@ -191,12 +200,30 @@ static Abi::Architecture guessArchitecture(const Macros &macros)
return Abi::Architecture::Mcs51Architecture;
if (macro.key == "__ICCAVR__")
return Abi::Architecture::AvrArchitecture;
+ if (macro.key == "__ICCAVR32__")
+ return Abi::Architecture::Avr32Architecture;
if (macro.key == "__ICCSTM8__")
return Abi::Architecture::Stm8Architecture;
if (macro.key == "__ICC430__")
return Abi::Architecture::Msp430Architecture;
if (macro.key == "__ICCRL78__")
return Abi::Architecture::Rl78Architecture;
+ if (macro.key == "__ICCV850__")
+ return Abi::Architecture::V850Architecture;
+ if (macro.key == "__ICCRH850__")
+ return Abi::Architecture::Rh850Architecture;
+ if (macro.key == "__ICCRX__")
+ return Abi::Architecture::RxArchitecture;
+ if (macro.key == "__ICC78K__")
+ return Abi::Architecture::K78Architecture;
+ if (macro.key == "__ICCSH__")
+ return Abi::Architecture::ShArchitecture;
+ if (macro.key == "__ICCRISCV__")
+ return Abi::Architecture::RiscVArchitecture;
+ if (macro.key == "__ICCCF__")
+ return Abi::Architecture::M68KArchitecture;
+ if (macro.key == "__ICCM32C__")
+ return Abi::Architecture::M32CArchitecture;
}
return Abi::Architecture::UnknownArchitecture;
}
@@ -215,12 +242,21 @@ static Abi::BinaryFormat guessFormat(Abi::Architecture arch)
{
if (arch == Abi::Architecture::ArmArchitecture
|| arch == Abi::Architecture::Stm8Architecture
- || arch == Abi::Architecture::Rl78Architecture) {
+ || arch == Abi::Architecture::Rl78Architecture
+ || arch == Abi::Architecture::Rh850Architecture
+ || arch == Abi::Architecture::RxArchitecture
+ || arch == Abi::Architecture::ShArchitecture
+ || arch == Abi::Architecture::RiscVArchitecture) {
return Abi::BinaryFormat::ElfFormat;
}
if (arch == Abi::Architecture::Mcs51Architecture
|| arch == Abi::Architecture::AvrArchitecture
- || arch == Abi::Architecture::Msp430Architecture) {
+ || arch == Abi::Architecture::Avr32Architecture
+ || arch == Abi::Architecture::Msp430Architecture
+ || arch == Abi::Architecture::V850Architecture
+ || arch == Abi::Architecture::K78Architecture
+ || arch == Abi::Architecture::M68KArchitecture
+ || arch == Abi::Architecture::M32CArchitecture) {
return Abi::BinaryFormat::UbrofFormat;
}
return Abi::BinaryFormat::UnknownFormat;
@@ -238,8 +274,7 @@ static QString buildDisplayName(Abi::Architecture arch, Core::Id language,
{
const auto archName = Abi::toString(arch);
const auto langName = ToolChainManager::displayNameOfLanguageId(language);
- return IarToolChain::tr("IAREW %1 (%2, %3)")
- .arg(version, langName, archName);
+ return IarToolChain::tr("IAREW %1 (%2, %3)").arg(version, langName, archName);
}
// IarToolChain
@@ -247,7 +282,7 @@ static QString buildDisplayName(Abi::Architecture arch, Core::Id language,
IarToolChain::IarToolChain() :
ToolChain(Constants::IAREW_TOOLCHAIN_TYPEID)
{
- setTypeDisplayName(Internal::IarToolChainFactory::tr("IAREW"));
+ setTypeDisplayName(Internal::IarToolChain::tr("IAREW"));
}
void IarToolChain::setTargetAbi(const Abi &abi)
@@ -275,16 +310,14 @@ ToolChain::MacroInspectionRunner IarToolChain::createMacroInspectionRunner() con
const Utils::FilePath compilerCommand = m_compilerCommand;
const Core::Id languageId = language();
-
+ const QStringList extraArgs = m_extraCodeModelFlags;
MacrosCache macrosCache = predefinedMacrosCache();
- return [env, compilerCommand,
- macrosCache,
- languageId]
+ return [env, compilerCommand, extraArgs, macrosCache, languageId]
(const QStringList &flags) {
Q_UNUSED(flags)
- Macros macros = dumpPredefinedMacros(compilerCommand, languageId, env.toStringList());
+ Macros macros = dumpPredefinedMacros(compilerCommand, extraArgs, languageId, env.toStringList());
macros.append({"__intrinsic", "", MacroType::Define});
macros.append({"__nounwind", "", MacroType::Define});
macros.append({"__noreturn", "", MacroType::Define});
@@ -355,15 +388,16 @@ void IarToolChain::addToEnvironment(Environment &env) const
}
}
-IOutputParser *IarToolChain::outputParser() const
+QList<Utils::OutputLineParser *> IarToolChain::createOutputParsers() const
{
- return new IarParser;
+ return {new IarParser()};
}
QVariantMap IarToolChain::toMap() const
{
QVariantMap data = ToolChain::toMap();
data.insert(compilerCommandKeyC, m_compilerCommand.toString());
+ data.insert(compilerPlatformCodeGenFlagsKeyC, m_extraCodeModelFlags);
data.insert(targetAbiKeyC, m_targetAbi.toString());
return data;
}
@@ -373,6 +407,7 @@ bool IarToolChain::fromMap(const QVariantMap &data)
if (!ToolChain::fromMap(data))
return false;
m_compilerCommand = FilePath::fromString(data.value(compilerCommandKeyC).toString());
+ m_extraCodeModelFlags = data.value(compilerPlatformCodeGenFlagsKeyC).toStringList();
m_targetAbi = Abi::fromString(data.value(targetAbiKeyC).toString());
return true;
}
@@ -390,6 +425,7 @@ bool IarToolChain::operator==(const ToolChain &other) const
const auto customTc = static_cast<const IarToolChain *>(&other);
return m_compilerCommand == customTc->m_compilerCommand
&& m_targetAbi == customTc->m_targetAbi
+ && m_extraCodeModelFlags == customTc->m_extraCodeModelFlags
;
}
@@ -406,6 +442,19 @@ FilePath IarToolChain::compilerCommand() const
return m_compilerCommand;
}
+void IarToolChain::setExtraCodeModelFlags(const QStringList &flags)
+{
+ if (flags == m_extraCodeModelFlags)
+ return;
+ m_extraCodeModelFlags = flags;
+ toolChainUpdated();
+}
+
+QStringList IarToolChain::extraCodeModelFlags() const
+{
+ return m_extraCodeModelFlags;
+}
+
FilePath IarToolChain::makeCommand(const Environment &env) const
{
Q_UNUSED(env)
@@ -416,7 +465,7 @@ FilePath IarToolChain::makeCommand(const Environment &env) const
IarToolChainFactory::IarToolChainFactory()
{
- setDisplayName(tr("IAREW"));
+ setDisplayName(IarToolChain::tr("IAREW"));
setSupportedToolChainType(Constants::IAREW_TOOLCHAIN_TYPEID);
setSupportedLanguages({ProjectExplorer::Constants::C_LANGUAGE_ID,
ProjectExplorer::Constants::CXX_LANGUAGE_ID});
@@ -441,12 +490,21 @@ QList<ToolChain *> IarToolChainFactory::autoDetect(const QList<ToolChain *> &alr
QString registryKey;
QString subExePath;
} knowToolchains[] = {
- {{"EWARM"}, {"\\arm\\bin\\iccarm.exe"}},
- {{"EWAVR"}, {"\\avr\\bin\\iccavr.exe"}},
- {{"EW8051"}, {"\\8051\\bin\\icc8051.exe"}},
- {{"EWSTM8"}, {"\\stm8\\bin\\iccstm8.exe"}},
- {{"EW430"}, {"\\430\\bin\\icc430.exe"}},
- {{"EWRL78"}, {"\\rl78\\bin\\iccrl78.exe"}},
+ {{"EWARM"}, {"/arm/bin/iccarm.exe"}},
+ {{"EWAVR"}, {"/avr/bin/iccavr.exe"}},
+ {{"EWAVR32"}, {"/avr32/bin/iccavr32.exe"}},
+ {{"EW8051"}, {"/8051/bin/icc8051.exe"}},
+ {{"EWSTM8"}, {"/stm8/bin/iccstm8.exe"}},
+ {{"EW430"}, {"/430/bin/icc430.exe"}},
+ {{"EWRL78"}, {"/rl78/bin/iccrl78.exe"}},
+ {{"EWV850"}, {"/v850/bin/iccv850.exe"}},
+ {{"EWRH850"}, {"/rh850/bin/iccrh850.exe"}},
+ {{"EWRX"}, {"/rx/bin/iccrx.exe"}},
+ {{"EW78K"}, {"/78k/bin/icc78k.exe"}},
+ {{"EWSH"}, {"/sh/bin/iccsh.exe"}},
+ {{"EWRISCV"}, {"/riscv/bin/iccriscv.exe"}},
+ {{"EWCF"}, {"/cf/bin/icccf.exe"}},
+ {{"EWM32C"}, {"/m32c/bin/iccm32c.exe"}},
};
QSettings registry(kRegistryNode, QSettings::NativeFormat);
@@ -514,7 +572,7 @@ QList<ToolChain *> IarToolChainFactory::autoDetectToolchain(
const Candidate &candidate, Core::Id languageId) const
{
const auto env = Environment::systemEnvironment();
- const Macros macros = dumpPredefinedMacros(candidate.compilerPath, languageId,
+ const Macros macros = dumpPredefinedMacros(candidate.compilerPath, {}, languageId,
env.toStringList());
if (macros.isEmpty())
return {};
@@ -543,6 +601,9 @@ IarToolChainConfigWidget::IarToolChainConfigWidget(IarToolChain *tc) :
m_compilerCommand->setExpectedKind(PathChooser::ExistingCommand);
m_compilerCommand->setHistoryCompleter("PE.IAREW.Command.History");
m_mainLayout->addRow(tr("&Compiler path:"), m_compilerCommand);
+ m_platformCodeGenFlagsLineEdit = new QLineEdit(this);
+ m_platformCodeGenFlagsLineEdit->setText(QtcProcess::joinArgs(tc->extraCodeModelFlags()));
+ m_mainLayout->addRow(tr("Platform codegen flags:"), m_platformCodeGenFlagsLineEdit);
m_mainLayout->addRow(tr("&ABI:"), m_abiWidget);
m_abiWidget->setEnabled(false);
@@ -552,6 +613,8 @@ IarToolChainConfigWidget::IarToolChainConfigWidget(IarToolChain *tc) :
connect(m_compilerCommand, &PathChooser::rawPathChanged,
this, &IarToolChainConfigWidget::handleCompilerCommandChange);
+ connect(m_platformCodeGenFlagsLineEdit, &QLineEdit::editingFinished,
+ this, &IarToolChainConfigWidget::handlePlatformCodeGenFlagsChange);
connect(m_abiWidget, &AbiWidget::abiChanged,
this, &ToolChainConfigWidget::dirty);
}
@@ -563,7 +626,8 @@ void IarToolChainConfigWidget::applyImpl()
const auto tc = static_cast<IarToolChain *>(toolChain());
const QString displayName = tc->displayName();
- tc->setCompilerCommand(m_compilerCommand->fileName());
+ tc->setCompilerCommand(m_compilerCommand->filePath());
+ tc->setExtraCodeModelFlags(splitString(m_platformCodeGenFlagsLineEdit->text()));
tc->setTargetAbi(m_abiWidget->currentAbi());
tc->setDisplayName(displayName);
@@ -579,7 +643,8 @@ void IarToolChainConfigWidget::applyImpl()
bool IarToolChainConfigWidget::isDirtyImpl() const
{
const auto tc = static_cast<IarToolChain *>(toolChain());
- return m_compilerCommand->fileName() != tc->compilerCommand()
+ return m_compilerCommand->filePath() != tc->compilerCommand()
+ || m_platformCodeGenFlagsLineEdit->text() != QtcProcess::joinArgs(tc->extraCodeModelFlags())
|| m_abiWidget->currentAbi() != tc->targetAbi()
;
}
@@ -587,6 +652,7 @@ bool IarToolChainConfigWidget::isDirtyImpl() const
void IarToolChainConfigWidget::makeReadOnlyImpl()
{
m_compilerCommand->setReadOnly(true);
+ m_platformCodeGenFlagsLineEdit->setEnabled(false);
m_abiWidget->setEnabled(false);
}
@@ -594,20 +660,22 @@ void IarToolChainConfigWidget::setFromToolchain()
{
const QSignalBlocker blocker(this);
const auto tc = static_cast<IarToolChain *>(toolChain());
- m_compilerCommand->setFileName(tc->compilerCommand());
+ m_compilerCommand->setFilePath(tc->compilerCommand());
+ m_platformCodeGenFlagsLineEdit->setText(QtcProcess::joinArgs(tc->extraCodeModelFlags()));
m_abiWidget->setAbis({}, tc->targetAbi());
- const bool haveCompiler = compilerExists(m_compilerCommand->fileName());
+ const bool haveCompiler = compilerExists(m_compilerCommand->filePath());
m_abiWidget->setEnabled(haveCompiler && !tc->isAutoDetected());
}
void IarToolChainConfigWidget::handleCompilerCommandChange()
{
- const FilePath compilerPath = m_compilerCommand->fileName();
+ const FilePath compilerPath = m_compilerCommand->filePath();
const bool haveCompiler = compilerExists(compilerPath);
if (haveCompiler) {
const auto env = Environment::systemEnvironment();
+ const QStringList extraArgs = splitString(m_platformCodeGenFlagsLineEdit->text());
const auto languageId = toolChain()->language();
- m_macros = dumpPredefinedMacros(compilerPath, languageId,
+ m_macros = dumpPredefinedMacros(compilerPath, extraArgs, languageId,
env.toStringList());
const Abi guessed = guessAbi(m_macros);
m_abiWidget->setAbis({}, guessed);
@@ -617,5 +685,15 @@ void IarToolChainConfigWidget::handleCompilerCommandChange()
emit dirty();
}
+void IarToolChainConfigWidget::handlePlatformCodeGenFlagsChange()
+{
+ const QString str1 = m_platformCodeGenFlagsLineEdit->text();
+ const QString str2 = QtcProcess::joinArgs(splitString(str1));
+ if (str1 != str2)
+ m_platformCodeGenFlagsLineEdit->setText(str2);
+ else
+ handleCompilerCommandChange();
+}
+
} // namespace Internal
} // namespace BareMetal
diff --git a/src/plugins/baremetal/iarewtoolchain.h b/src/plugins/baremetal/iarewtoolchain.h
index 3c8c95a325..0486629539 100644
--- a/src/plugins/baremetal/iarewtoolchain.h
+++ b/src/plugins/baremetal/iarewtoolchain.h
@@ -30,6 +30,7 @@
#include <projectexplorer/toolchainconfigwidget.h>
QT_BEGIN_NAMESPACE
+class QLineEdit;
class QPlainTextEdit;
class QPushButton;
class QTextEdit;
@@ -68,7 +69,7 @@ public:
const Utils::FilePath &,
const Utils::Environment &env) const final;
void addToEnvironment(Utils::Environment &env) const final;
- ProjectExplorer::IOutputParser *outputParser() const final;
+ QList<Utils::OutputLineParser *> createOutputParsers() const final;
QVariantMap toMap() const final;
bool fromMap(const QVariantMap &data) final;
@@ -80,6 +81,9 @@ public:
void setCompilerCommand(const Utils::FilePath &file);
Utils::FilePath compilerCommand() const final;
+ void setExtraCodeModelFlags(const QStringList &flags);
+ QStringList extraCodeModelFlags() const final;
+
Utils::FilePath makeCommand(const Utils::Environment &env) const final;
private:
@@ -87,6 +91,7 @@ private:
ProjectExplorer::Abi m_targetAbi;
Utils::FilePath m_compilerCommand;
+ QStringList m_extraCodeModelFlags;
friend class IarToolChainFactory;
friend class IarToolChainConfigWidget;
@@ -96,8 +101,6 @@ private:
class IarToolChainFactory final : public ProjectExplorer::ToolChainFactory
{
- Q_OBJECT
-
public:
IarToolChainFactory();
@@ -128,9 +131,11 @@ private:
void setFromToolchain();
void handleCompilerCommandChange();
+ void handlePlatformCodeGenFlagsChange();
Utils::PathChooser *m_compilerCommand = nullptr;
ProjectExplorer::AbiWidget *m_abiWidget = nullptr;
+ QLineEdit *m_platformCodeGenFlagsLineEdit = nullptr;
ProjectExplorer::Macros m_macros;
};
diff --git a/src/plugins/baremetal/keilparser.cpp b/src/plugins/baremetal/keilparser.cpp
index 1a09a68b2d..5ee130073e 100644
--- a/src/plugins/baremetal/keilparser.cpp
+++ b/src/plugins/baremetal/keilparser.cpp
@@ -28,9 +28,6 @@
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/task.h>
-#include <texteditor/fontsettings.h>
-#include <texteditor/texteditorsettings.h>
-
#include <QRegularExpression>
using namespace ProjectExplorer;
@@ -66,39 +63,19 @@ Core::Id KeilParser::id()
void KeilParser::newTask(const Task &task)
{
- doFlush();
+ flush();
m_lastTask = task;
m_lines = 1;
}
-void KeilParser::amendDescription()
-{
- while (!m_snippets.isEmpty()) {
- const QString snippet = m_snippets.takeFirst();
-
- const int start = m_lastTask.description.count() + 1;
- m_lastTask.description.append('\n');
- m_lastTask.description.append(snippet);
-
- QTextLayout::FormatRange fr;
- fr.start = start;
- fr.length = m_lastTask.description.count() + 1;
- fr.format.setFont(TextEditor::TextEditorSettings::fontSettings().font());
- fr.format.setFontStyleHint(QFont::Monospace);
- m_lastTask.formats.append(fr);
-
- ++m_lines;
- }
-}
-
// ARM compiler specific parsers.
-bool KeilParser::parseArmWarningOrErrorDetailsMessage(const QString &lne)
+OutputLineParser::Result KeilParser::parseArmWarningOrErrorDetailsMessage(const QString &lne)
{
const QRegularExpression re("^\"(.+)\", line (\\d+).*:\\s+(Warning|Error):(\\s+|.+)([#|L].+)$");
const QRegularExpressionMatch match = re.match(lne);
if (!match.hasMatch())
- return false;
+ return Status::NotHandled;
enum CaptureIndex { FilePathIndex = 1, LineNumberIndex,
MessageTypeIndex, MessageNoteIndex, DescriptionIndex };
const Utils::FilePath fileName = Utils::FilePath::fromUserInput(
@@ -106,8 +83,11 @@ bool KeilParser::parseArmWarningOrErrorDetailsMessage(const QString &lne)
const int lineno = match.captured(LineNumberIndex).toInt();
const Task::TaskType type = taskType(match.captured(MessageTypeIndex));
const QString descr = match.captured(DescriptionIndex);
- newTask(CompileTask(type, descr, fileName, lineno));
- return true;
+ newTask(CompileTask(type, descr, absoluteFilePath(fileName), lineno));
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, m_lastTask.file, m_lastTask.line, match,
+ FilePathIndex);
+ return {Status::InProgress, linkSpecs};
}
bool KeilParser::parseArmErrorOrFatalErorrMessage(const QString &lne)
@@ -125,12 +105,12 @@ bool KeilParser::parseArmErrorOrFatalErorrMessage(const QString &lne)
// MCS51 compiler specific parsers.
-bool KeilParser::parseMcs51WarningOrErrorDetailsMessage1(const QString &lne)
+OutputLineParser::Result KeilParser::parseMcs51WarningOrErrorDetailsMessage1(const QString &lne)
{
const QRegularExpression re("^\\*{3} (WARNING|ERROR) (\\w+) IN LINE (\\d+) OF (.+\\.\\S+): (.+)$");
const QRegularExpressionMatch match = re.match(lne);
if (!match.hasMatch())
- return false;
+ return Status::NotHandled;
enum CaptureIndex { MessageTypeIndex = 1, MessageCodeIndex, LineNumberIndex,
FilePathIndex, MessageTextIndex };
const Task::TaskType type = taskType(match.captured(MessageTypeIndex));
@@ -139,16 +119,19 @@ bool KeilParser::parseMcs51WarningOrErrorDetailsMessage1(const QString &lne)
match.captured(FilePathIndex));
const QString descr = QString("%1: %2").arg(match.captured(MessageCodeIndex),
match.captured(MessageTextIndex));
- newTask(CompileTask(type, descr, fileName, lineno));
- return true;
+ newTask(CompileTask(type, descr, absoluteFilePath(fileName), lineno));
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, m_lastTask.file, m_lastTask.line, match,
+ FilePathIndex);
+ return {Status::InProgress, linkSpecs};
}
-bool KeilParser::parseMcs51WarningOrErrorDetailsMessage2(const QString &lne)
+OutputLineParser::Result KeilParser::parseMcs51WarningOrErrorDetailsMessage2(const QString &lne)
{
const QRegularExpression re("^\\*{3} (WARNING|ERROR) (#\\w+) IN (\\d+) \\((.+), LINE \\d+\\): (.+)$");
const QRegularExpressionMatch match = re.match(lne);
if (!match.hasMatch())
- return false;
+ return Status::NotHandled;
enum CaptureIndex { MessageTypeIndex = 1, MessageCodeIndex, LineNumberIndex,
FilePathIndex, MessageTextIndex };
const Task::TaskType type = taskType(match.captured(MessageTypeIndex));
@@ -157,8 +140,11 @@ bool KeilParser::parseMcs51WarningOrErrorDetailsMessage2(const QString &lne)
match.captured(FilePathIndex));
const QString descr = QString("%1: %2").arg(match.captured(MessageCodeIndex),
match.captured(MessageTextIndex));
- newTask(CompileTask(type, descr, fileName, lineno));
- return true;
+ newTask(CompileTask(type, descr, absoluteFilePath(fileName), lineno));
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, m_lastTask.file, m_lastTask.line, match,
+ FilePathIndex);
+ return {Status::InProgress, linkSpecs};
}
bool KeilParser::parseMcs51WarningOrFatalErrorMessage(const QString &lne)
@@ -190,26 +176,6 @@ bool KeilParser::parseMcs51FatalErrorMessage2(const QString &lne)
return true;
}
-void KeilParser::stdError(const QString &line)
-{
- IOutputParser::stdError(line);
-
- const QString lne = rightTrimmed(line);
-
- // Check for ARM compiler specific patterns.
- if (parseArmWarningOrErrorDetailsMessage(lne))
- return;
- if (parseArmErrorOrFatalErorrMessage(lne))
- return;
-
- if (lne.startsWith(' ')) {
- m_snippets.push_back(lne);
- return;
- }
-
- doFlush();
-}
-
static bool hasDetailsEntry(const QString &trimmedLine)
{
const QRegularExpression re("^([0-9A-F]{4})");
@@ -226,58 +192,76 @@ static bool hasDetailsPointer(const QString &trimmedLine)
return trimmedLine.contains('_');
}
-void KeilParser::stdOutput(const QString &line)
+OutputLineParser::Result KeilParser::handleLine(const QString &line, OutputFormat type)
{
- IOutputParser::stdOutput(line);
-
QString lne = rightTrimmed(line);
-
- // Check for MSC51 compiler specific patterns.
- const bool parsed = parseMcs51WarningOrErrorDetailsMessage1(lne)
- || parseMcs51WarningOrErrorDetailsMessage2(lne);
- if (!parsed) {
+ if (type == StdOutFormat) {
+ // Check for MSC51 compiler specific patterns.
+ Result res = parseMcs51WarningOrErrorDetailsMessage1(lne);
+ if (res.status != Status::NotHandled)
+ return res;
+ res = parseMcs51WarningOrErrorDetailsMessage2(lne);
+ if (res.status != Status::NotHandled)
+ return res;
if (parseMcs51WarningOrFatalErrorMessage(lne))
- return;
+ return Status::InProgress;
if (parseMcs51FatalErrorMessage2(lne))
- return;
+ return Status::InProgress;
+
+ if (m_lastTask.isNull()) {
+ // Check for details, which are comes on a previous
+ // lines, before the message.
+
+ // This code handles the details in a form like:
+ // 0000 24 ljmp usb_stub_isr ; (00) Setup data available.
+ // *** _____________________________________^
+ // 003C 54 ljmp usb_stub_isr ; (3C) EP8 in/out.
+ // *** _____________________________________^
+ if (hasDetailsEntry(lne) || hasDetailsPointer(lne)) {
+ lne.replace(0, 4, " ");
+ m_snippets.push_back(lne);
+ return Status::InProgress;
+ }
+ } else {
+ // Check for details, which are comes on a next
+ // lines, after the message.
+ if (lne.startsWith(' ')) {
+ m_snippets.push_back(lne);
+ return Status::InProgress;
+ }
+ }
+ flush();
+ return Status::NotHandled;
}
- if (m_lastTask.isNull()) {
- // Check for details, which are comes on a previous
- // lines, before the message.
-
- // This code handles the details in a form like:
- // 0000 24 ljmp usb_stub_isr ; (00) Setup data available.
- // *** _____________________________________^
- // 003C 54 ljmp usb_stub_isr ; (3C) EP8 in/out.
- // *** _____________________________________^
- if (hasDetailsEntry(lne) || hasDetailsPointer(lne)) {
- lne.replace(0, 4, " ");
- m_snippets.push_back(lne);
- return;
- }
- } else {
- // Check for details, which are comes on a next
- // lines, after the message.
- if (lne.startsWith(' ')) {
- m_snippets.push_back(lne);
- return;
- }
+ // Check for ARM compiler specific patterns.
+ const Result res = parseArmWarningOrErrorDetailsMessage(lne);
+ if (res.status != Status::NotHandled)
+ return res;
+ if (parseArmErrorOrFatalErorrMessage(lne))
+ return Status::InProgress;
+
+ if (lne.startsWith(' ')) {
+ m_snippets.push_back(lne);
+ return Status::InProgress;
}
- doFlush();
+ flush();
+ return Status::NotHandled;
}
-void KeilParser::doFlush()
+void KeilParser::flush()
{
if (m_lastTask.isNull())
return;
- amendDescription();
-
+ m_lastTask.details = m_snippets;
+ m_snippets.clear();
+ m_lines += m_lastTask.details.count();
+ setDetailsFormat(m_lastTask);
Task t = m_lastTask;
m_lastTask.clear();
- emit addTask(t, m_lines, 1);
+ scheduleTask(t, m_lines, 1);
m_lines = 0;
}
@@ -320,7 +304,7 @@ void BareMetalPlugin::testKeilOutputParsers_data()
<< QString::fromLatin1("\"c:\\foo\\main.c\", line 63: Warning: #1234: Some warning")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("\"c:\\foo\\main.c\", line 63: Warning: #1234: Some warning\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Warning,
"#1234: Some warning",
FilePath::fromUserInput("c:\\foo\\main.c"),
@@ -333,9 +317,7 @@ void BareMetalPlugin::testKeilOutputParsers_data()
" ^")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("\"c:\\foo\\main.c\", line 63: Warning: #1234: Some warning\n"
- " int f;\n"
- " ^\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Warning,
"#1234: Some warning\n"
" int f;\n"
@@ -348,7 +330,7 @@ void BareMetalPlugin::testKeilOutputParsers_data()
<< QString::fromLatin1("\"c:\\foo\\main.c\", line 63: Error: #1234: Some error")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("\"c:\\foo\\main.c\", line 63: Error: #1234: Some error\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Error,
"#1234: Some error",
FilePath::fromUserInput("c:\\foo\\main.c"),
@@ -359,7 +341,7 @@ void BareMetalPlugin::testKeilOutputParsers_data()
<< QString::fromLatin1("\"flash.sct\", line 51 (column 20): Error: L1234: Some error")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("\"flash.sct\", line 51 (column 20): Error: L1234: Some error\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Error,
"L1234: Some error",
FilePath::fromUserInput("flash.sct"),
@@ -372,9 +354,7 @@ void BareMetalPlugin::testKeilOutputParsers_data()
" ^")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("\"c:\\foo\\main.c\", line 63: Error: #1234: Some error\n"
- " int f;\n"
- " ^\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Error,
"#1234: Some error\n"
" int f;\n"
@@ -387,7 +367,7 @@ void BareMetalPlugin::testKeilOutputParsers_data()
<< QString::fromLatin1("\"c:\\foo\\main.c\", line 71: Error: At end of source: #40: Some error")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("\"c:\\foo\\main.c\", line 71: Error: At end of source: #40: Some error\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Error,
"#40: Some error",
FilePath::fromUserInput("c:\\foo\\main.c"),
@@ -398,7 +378,7 @@ void BareMetalPlugin::testKeilOutputParsers_data()
<< QString::fromLatin1("Error: L6226E: Some error.")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("Error: L6226E: Some error.\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Error,
"L6226E: Some error."))
<< QString();
@@ -409,7 +389,7 @@ void BareMetalPlugin::testKeilOutputParsers_data()
QTest::newRow("MCS51: Assembler simple warning")
<< QString::fromLatin1("*** WARNING #A9 IN 15 (c:\\foo\\dscr.a51, LINE 15): Some warning")
<< OutputParserTester::STDOUT
- << QString::fromLatin1("*** WARNING #A9 IN 15 (c:\\foo\\dscr.a51, LINE 15): Some warning\n")
+ << QString()
<< QString()
<< (Tasks() << CompileTask(Task::Warning,
"#A9: Some warning",
@@ -420,7 +400,7 @@ void BareMetalPlugin::testKeilOutputParsers_data()
QTest::newRow("MCS51: Assembler simple error")
<< QString::fromLatin1("*** ERROR #A9 IN 15 (c:\\foo\\dscr.a51, LINE 15): Some error")
<< OutputParserTester::STDOUT
- << QString::fromLatin1("*** ERROR #A9 IN 15 (c:\\foo\\dscr.a51, LINE 15): Some error\n")
+ << QString()
<< QString()
<< (Tasks() << CompileTask(Task::Error,
"#A9: Some error",
@@ -433,9 +413,7 @@ void BareMetalPlugin::testKeilOutputParsers_data()
" Some detail 1\n"
" Some detail N")
<< OutputParserTester::STDOUT
- << QString::fromLatin1("A51 FATAL ERROR -\n"
- " Some detail 1\n"
- " Some detail N\n")
+ << QString()
<< QString()
<< (Tasks() << CompileTask(Task::Error,
"Assembler fatal error\n"
@@ -448,9 +426,7 @@ void BareMetalPlugin::testKeilOutputParsers_data()
"*** ___^\n"
"*** ERROR #A45 IN 28 (d:\\foo.a51, LINE 28): Some error")
<< OutputParserTester::STDOUT
- << QString::fromLatin1("01AF Some detail\n"
- "*** ___^\n"
- "*** ERROR #A45 IN 28 (d:\\foo.a51, LINE 28): Some error\n")
+ << QString()
<< QString()
<< (Tasks() << CompileTask(Task::Error,
"#A45: Some error\n"
@@ -464,7 +440,7 @@ void BareMetalPlugin::testKeilOutputParsers_data()
QTest::newRow("MCS51: Compiler simple warning")
<< QString::fromLatin1("*** WARNING C123 IN LINE 13 OF c:\\foo.c: Some warning")
<< OutputParserTester::STDOUT
- << QString::fromLatin1("*** WARNING C123 IN LINE 13 OF c:\\foo.c: Some warning\n")
+ << QString()
<< QString()
<< (Tasks() << CompileTask(Task::Warning,
"C123: Some warning",
@@ -475,7 +451,7 @@ void BareMetalPlugin::testKeilOutputParsers_data()
QTest::newRow("MCS51: Compiler extended warning")
<< QString::fromLatin1("*** WARNING C123 IN LINE 13 OF c:\\foo.c: Some warning : 'extended text'")
<< OutputParserTester::STDOUT
- << QString::fromLatin1("*** WARNING C123 IN LINE 13 OF c:\\foo.c: Some warning : 'extended text'\n")
+ << QString()
<< QString()
<< (Tasks() << CompileTask(Task::Warning,
"C123: Some warning : 'extended text'",
@@ -486,7 +462,7 @@ void BareMetalPlugin::testKeilOutputParsers_data()
QTest::newRow("MCS51: Compiler simple error")
<< QString::fromLatin1("*** ERROR C123 IN LINE 13 OF c:\\foo.c: Some error")
<< OutputParserTester::STDOUT
- << QString::fromLatin1("*** ERROR C123 IN LINE 13 OF c:\\foo.c: Some error\n")
+ << QString()
<< QString()
<< (Tasks() << CompileTask(Task::Error,
"C123: Some error",
@@ -497,7 +473,7 @@ void BareMetalPlugin::testKeilOutputParsers_data()
QTest::newRow("MCS51: Compiler extended error")
<< QString::fromLatin1("*** ERROR C123 IN LINE 13 OF c:\\foo.c: Some error : 'extended text'")
<< OutputParserTester::STDOUT
- << QString::fromLatin1("*** ERROR C123 IN LINE 13 OF c:\\foo.c: Some error : 'extended text'\n")
+ << QString()
<< QString()
<< (Tasks() << CompileTask(Task::Error,
"C123: Some error : 'extended text'",
@@ -510,9 +486,7 @@ void BareMetalPlugin::testKeilOutputParsers_data()
" Some detail 1\n"
" Some detail N")
<< OutputParserTester::STDOUT
- << QString::fromLatin1("C51 FATAL-ERROR -\n"
- " Some detail 1\n"
- " Some detail N\n")
+ << QString()
<< QString()
<< (Tasks() << CompileTask(Task::Error,
"Compiler fatal error\n"
@@ -525,8 +499,7 @@ void BareMetalPlugin::testKeilOutputParsers_data()
<< QString::fromLatin1("*** WARNING L16: Some warning\n"
" Some detail 1")
<< OutputParserTester::STDOUT
- << QString::fromLatin1("*** WARNING L16: Some warning\n"
- " Some detail 1\n")
+ << QString()
<< QString()
<< (Tasks() << CompileTask(Task::Warning,
"L16: Some warning\n"
@@ -536,7 +509,7 @@ void BareMetalPlugin::testKeilOutputParsers_data()
QTest::newRow("MCS51: Linker simple fatal error")
<< QString::fromLatin1("*** FATAL ERROR L456: Some error")
<< OutputParserTester::STDOUT
- << QString::fromLatin1("*** FATAL ERROR L456: Some error\n")
+ << QString()
<< QString()
<< (Tasks() << CompileTask(Task::Error,
"L456: Some error"))
@@ -547,9 +520,7 @@ void BareMetalPlugin::testKeilOutputParsers_data()
" Some detail 1\n"
" Some detail N")
<< OutputParserTester::STDOUT
- << QString::fromLatin1("*** FATAL ERROR L456: Some error\n"
- " Some detail 1\n"
- " Some detail N\n")
+ << QString()
<< QString()
<< (Tasks() << CompileTask(Task::Error,
"L456: Some error\n"
@@ -561,7 +532,7 @@ void BareMetalPlugin::testKeilOutputParsers_data()
void BareMetalPlugin::testKeilOutputParsers()
{
OutputParserTester testbench;
- testbench.appendOutputParser(new KeilParser);
+ testbench.addLineParser(new KeilParser);
QFETCH(QString, input);
QFETCH(OutputParserTester::Channel, inputChannel);
QFETCH(Tasks, tasks);
diff --git a/src/plugins/baremetal/keilparser.h b/src/plugins/baremetal/keilparser.h
index 857e67599f..26fa00fdea 100644
--- a/src/plugins/baremetal/keilparser.h
+++ b/src/plugins/baremetal/keilparser.h
@@ -33,7 +33,7 @@ namespace Internal {
// KeilParser
-class KeilParser final : public ProjectExplorer::IOutputParser
+class KeilParser final : public ProjectExplorer::OutputTaskParser
{
Q_OBJECT
@@ -43,21 +43,19 @@ public:
private:
void newTask(const ProjectExplorer::Task &task);
- void amendDescription();
// ARM compiler specific parsers.
- bool parseArmWarningOrErrorDetailsMessage(const QString &lne);
+ Result parseArmWarningOrErrorDetailsMessage(const QString &lne);
bool parseArmErrorOrFatalErorrMessage(const QString &lne);
// MCS51 compiler specific parsers.
- bool parseMcs51WarningOrErrorDetailsMessage1(const QString &lne);
- bool parseMcs51WarningOrErrorDetailsMessage2(const QString &lne);
+ Result parseMcs51WarningOrErrorDetailsMessage1(const QString &lne);
+ Result parseMcs51WarningOrErrorDetailsMessage2(const QString &lne);
bool parseMcs51WarningOrFatalErrorMessage(const QString &lne);
bool parseMcs51FatalErrorMessage2(const QString &lne);
- void stdError(const QString &line) final;
- void stdOutput(const QString &line) final;
- void doFlush() final;
+ Result handleLine(const QString &line, Utils::OutputFormat type) final;
+ void flush() final;
ProjectExplorer::Task m_lastTask;
int m_lines = 0;
diff --git a/src/plugins/baremetal/keiltoolchain.cpp b/src/plugins/baremetal/keiltoolchain.cpp
index 80ae51240e..208752f346 100644
--- a/src/plugins/baremetal/keiltoolchain.cpp
+++ b/src/plugins/baremetal/keiltoolchain.cpp
@@ -37,6 +37,7 @@
#include <utils/environment.h>
#include <utils/pathchooser.h>
#include <utils/qtcassert.h>
+#include <utils/qtcprocess.h>
#include <utils/synchronousprocess.h>
#include <QDebug>
@@ -60,6 +61,7 @@ namespace Internal {
// Helpers:
static const char compilerCommandKeyC[] = "BareMetal.KeilToolchain.CompilerPath";
+static const char compilerPlatformCodeGenFlagsKeyC[] = "BareMetal.KeilToolchain.PlatformCodeGenFlags";
static const char targetAbiKeyC[] = "BareMetal.KeilToolchain.TargetAbi";
static bool compilerExists(const FilePath &compilerPath)
@@ -74,28 +76,66 @@ static Abi::Architecture guessArchitecture(const FilePath &compilerPath)
const QString bn = fi.baseName().toLower();
if (bn == "c51" || bn == "cx51")
return Abi::Architecture::Mcs51Architecture;
+ if (bn == "c251")
+ return Abi::Architecture::Mcs251Architecture;
+ if (bn == "c166")
+ return Abi::Architecture::C166Architecture;
if (bn == "armcc")
return Abi::Architecture::ArmArchitecture;
return Abi::Architecture::UnknownArchitecture;
}
-// Note: The KEIL 8051 compiler does not support the predefined
-// macros dumping. So, we do it with following trick where we try
-// to compile a temporary file and to parse the console output.
-static Macros dumpC51PredefinedMacros(const FilePath &compiler, const QStringList &env)
+static Macros dumpMcsPredefinedMacros(const FilePath &compiler, const QStringList &env)
{
+ // Note: The KEIL C51 or C251 compiler does not support the predefined
+ // macros dumping. So, we do it with the following trick, where we try
+ // to create and compile a special temporary file and to parse the console
+ // output with the own magic pattern: (""|"key"|"value"|"").
+
QTemporaryFile fakeIn;
if (!fakeIn.open())
return {};
+
fakeIn.write("#define VALUE_TO_STRING(x) #x\n");
fakeIn.write("#define VALUE(x) VALUE_TO_STRING(x)\n");
- fakeIn.write("#define VAR_NAME_VALUE(var) \"\"\"|\"#var\"|\"VALUE(var)\n");
- fakeIn.write("#ifdef __C51__\n");
- fakeIn.write("#pragma message(VAR_NAME_VALUE(__C51__))\n");
+
+ // Prepare for C51 compiler.
+ fakeIn.write("#if defined(__C51__) || defined(__CX51__)\n");
+ fakeIn.write("# define VAR_NAME_VALUE(var) \"(\"\"\"\"|\"#var\"|\"VALUE(var)\"|\"\"\"\")\"\n");
+ fakeIn.write("# if defined (__C51__)\n");
+ fakeIn.write("# pragma message (VAR_NAME_VALUE(__C51__))\n");
+ fakeIn.write("# endif\n");
+ fakeIn.write("# if defined(__CX51__)\n");
+ fakeIn.write("# pragma message (VAR_NAME_VALUE(__CX51__))\n");
+ fakeIn.write("# endif\n");
+ fakeIn.write("# if defined(__MODEL__)\n");
+ fakeIn.write("# pragma message (VAR_NAME_VALUE(__MODEL__))\n");
+ fakeIn.write("# endif\n");
+ fakeIn.write("# if defined(__STDC__)\n");
+ fakeIn.write("# pragma message (VAR_NAME_VALUE(__STDC__))\n");
+ fakeIn.write("# endif\n");
fakeIn.write("#endif\n");
- fakeIn.write("#ifdef __CX51__\n");
- fakeIn.write("#pragma message(VAR_NAME_VALUE(__CX51__))\n");
+
+ // Prepare for C251 compiler.
+ fakeIn.write("#if defined(__C251__)\n");
+ fakeIn.write("# define VAR_NAME_VALUE(var) \"\"|#var|VALUE(var)|\"\"\n");
+ fakeIn.write("# if defined(__C251__)\n");
+ fakeIn.write("# warning (VAR_NAME_VALUE(__C251__))\n");
+ fakeIn.write("# endif\n");
+ fakeIn.write("# if defined(__MODEL__)\n");
+ fakeIn.write("# warning (VAR_NAME_VALUE(__MODEL__))\n");
+ fakeIn.write("# endif\n");
+ fakeIn.write("# if defined(__STDC__)\n");
+ fakeIn.write("# warning (VAR_NAME_VALUE(__STDC__))\n");
+ fakeIn.write("# endif\n");
+ fakeIn.write("# if defined(__FLOAT64__)\n");
+ fakeIn.write("# warning (VAR_NAME_VALUE(__FLOAT64__))\n");
+ fakeIn.write("# endif\n");
+ fakeIn.write("# if defined(__MODSRC__)\n");
+ fakeIn.write("# warning (VAR_NAME_VALUE(__MODSRC__))\n");
+ fakeIn.write("# endif\n");
fakeIn.write("#endif\n");
+
fakeIn.close();
SynchronousProcess cpp;
@@ -103,34 +143,151 @@ static Macros dumpC51PredefinedMacros(const FilePath &compiler, const QStringLis
cpp.setTimeoutS(10);
const CommandLine cmd(compiler, {fakeIn.fileName()});
-
const SynchronousProcessResponse response = cpp.runBlocking(cmd);
- if (response.result != SynchronousProcessResponse::Finished
- || response.exitCode != 0) {
- qWarning() << response.exitMessage(cmd.toUserOutput(), 10);
- return {};
- }
-
QString output = response.allOutput();
Macros macros;
QTextStream stream(&output);
QString line;
while (stream.readLineInto(&line)) {
+ enum { KEY_INDEX = 1, VALUE_INDEX = 2, ALL_PARTS = 4 };
const QStringList parts = line.split("\"|\"");
- if (parts.count() != 3)
+ if (parts.count() != ALL_PARTS)
continue;
- macros.push_back({parts.at(1).toUtf8(), parts.at(2).toUtf8()});
+ macros.push_back({parts.at(KEY_INDEX).toUtf8(), parts.at(VALUE_INDEX).toUtf8()});
}
return macros;
}
-static Macros dumpArmPredefinedMacros(const FilePath &compiler, const QStringList &env)
+static Macros dumpC166PredefinedMacros(const FilePath &compiler, const QStringList &env)
+{
+ // Note: The KEIL C166 compiler does not support the predefined
+ // macros dumping. Also, it does not support the '#pragma' and
+ // '#message|warning|error' directives properly (it is impossible
+ // to print to console the value of macro).
+ // So, we do it with the following trick, where we try
+ // to create and compile a special temporary file and to parse the console
+ // output with the own magic pattern, e.g:
+ //
+ // *** WARNING C320 IN LINE 41 OF c51.c: __C166__
+ // *** WARNING C2 IN LINE 42 OF c51.c: '757': unknown #pragma/control, line ignored
+ //
+ // where the '__C166__' is a key, and the '757' is a value.
+
+ QTemporaryFile fakeIn;
+ if (!fakeIn.open())
+ return {};
+
+ // Prepare for C166 compiler.
+ fakeIn.write("#if defined(__C166__)\n");
+ fakeIn.write("# if defined(__C166__)\n");
+ fakeIn.write("# warning __C166__\n");
+ fakeIn.write("# pragma __C166__\n");
+ fakeIn.write("# endif\n");
+ fakeIn.write("# if defined(__DUS__)\n");
+ fakeIn.write("# warning __DUS__\n");
+ fakeIn.write("# pragma __DUS__\n");
+ fakeIn.write("# endif\n");
+ fakeIn.write("# if defined(__MAC__)\n");
+ fakeIn.write("# warning __MAC__\n");
+ fakeIn.write("# pragma __MAC__\n");
+ fakeIn.write("# endif\n");
+ fakeIn.write("# if defined(__MOD167__)\n");
+ fakeIn.write("# warning __MOD167__\n");
+ fakeIn.write("# pragma __MOD167__\n");
+ fakeIn.write("# endif\n");
+ fakeIn.write("# if defined(__MODEL__)\n");
+ fakeIn.write("# warning __MODEL__\n");
+ fakeIn.write("# pragma __MODEL__\n");
+ fakeIn.write("# endif\n");
+ fakeIn.write("# if defined(__MODV2__)\n");
+ fakeIn.write("# warning __MODV2__\n");
+ fakeIn.write("# pragma __MODV2__\n");
+ fakeIn.write("# endif\n");
+ fakeIn.write("# if defined(__SAVEMAC__)\n");
+ fakeIn.write("# warning __SAVEMAC__\n");
+ fakeIn.write("# pragma __SAVEMAC__\n");
+ fakeIn.write("# endif\n");
+ fakeIn.write("# if defined(__STDC__)\n");
+ fakeIn.write("# warning __STDC__\n");
+ fakeIn.write("# pragma __STDC__\n");
+ fakeIn.write("# endif\n");
+ fakeIn.write("#endif\n");
+
+ fakeIn.close();
+
+ SynchronousProcess cpp;
+ cpp.setEnvironment(env);
+ cpp.setTimeoutS(10);
+
+ Macros macros;
+ auto extractMacros = [&macros](const QString &output) {
+ const QStringList lines = output.split('\n');
+ for (auto it = lines.cbegin(); it != lines.cend();) {
+ if (!it->startsWith("***")) {
+ ++it;
+ continue;
+ }
+
+ // Search for the key at a first line.
+ QByteArray key;
+ if (it->endsWith("__C166__"))
+ key = "__C166__";
+ else if (it->endsWith("__DUS__"))
+ key = "__DUS__";
+ else if (it->endsWith("__MAC__"))
+ key = "__MAC__";
+ else if (it->endsWith("__MOD167__"))
+ key = "__MOD167__";
+ else if (it->endsWith("__MODEL__"))
+ key = "__MODEL__";
+ else if (it->endsWith("__MODV2__"))
+ key = "__MODV2__";
+ else if (it->endsWith("__SAVEMAC__"))
+ key = "__SAVEMAC__";
+ else if (it->endsWith("__STDC__"))
+ key = "__STDC__";
+
+ if (key.isEmpty()) {
+ ++it;
+ continue;
+ }
+
+ ++it;
+ if (it == lines.cend() || !it->startsWith("***"))
+ break;
+
+ // Search for the value at a second line.
+ const int startIndex = it->indexOf('\'');
+ if (startIndex == -1)
+ break;
+ const int stopIndex = it->indexOf('\'', startIndex + 1);
+ if (stopIndex == -1)
+ break;
+ const QByteArray value = it->mid(startIndex + 1, stopIndex - startIndex - 1).toLatin1();
+
+ macros.append(Macro{key, value});
+
+ ++it;
+ }
+ };
+
+ const CommandLine cmd(compiler, {fakeIn.fileName()});
+ const SynchronousProcessResponse response = cpp.runBlocking(cmd);
+ const QString output = response.allOutput();
+ extractMacros(output);
+ return macros;
+}
+
+static Macros dumpArmPredefinedMacros(const FilePath &compiler, const QStringList &extraArgs, const QStringList &env)
{
SynchronousProcess cpp;
cpp.setEnvironment(env);
cpp.setTimeoutS(10);
- const CommandLine cmd(compiler, {"-E", "--list-macros"});
+ QStringList args = extraArgs;
+ args.push_back("-E");
+ args.push_back("--list-macros");
+ const CommandLine cmd(compiler, args);
const SynchronousProcessResponse response = cpp.runBlocking(cmd);
if (response.result != SynchronousProcessResponse::Finished
@@ -143,20 +300,35 @@ static Macros dumpArmPredefinedMacros(const FilePath &compiler, const QStringLis
return Macro::toMacros(output);
}
-static Macros dumpPredefinedMacros(const FilePath &compiler, const QStringList &env)
+static bool isMcsArchitecture(Abi::Architecture arch)
+{
+ return arch == Abi::Architecture::Mcs51Architecture
+ || arch == Abi::Architecture::Mcs251Architecture;
+}
+
+static bool isC166Architecture(Abi::Architecture arch)
+{
+ return arch == Abi::Architecture::C166Architecture;
+}
+
+static bool isArmArchitecture(Abi::Architecture arch)
+{
+ return arch == Abi::Architecture::ArmArchitecture;
+}
+
+static Macros dumpPredefinedMacros(const FilePath &compiler, const QStringList &args, const QStringList &env)
{
if (compiler.isEmpty() || !compiler.toFileInfo().isExecutable())
return {};
const Abi::Architecture arch = guessArchitecture(compiler);
- switch (arch) {
- case Abi::Architecture::Mcs51Architecture:
- return dumpC51PredefinedMacros(compiler, env);
- case Abi::Architecture::ArmArchitecture:
- return dumpArmPredefinedMacros(compiler, env);
- default:
- return {};
- }
+ if (isMcsArchitecture(arch))
+ return dumpMcsPredefinedMacros(compiler, env);
+ if (isC166Architecture(arch))
+ return dumpC166PredefinedMacros(compiler, env);
+ if (isArmArchitecture(arch))
+ return dumpArmPredefinedMacros(compiler, args, env);
+ return {};
}
static HeaderPaths dumpHeaderPaths(const FilePath &compiler)
@@ -171,11 +343,11 @@ static HeaderPaths dumpHeaderPaths(const FilePath &compiler)
HeaderPaths headerPaths;
const Abi::Architecture arch = guessArchitecture(compiler);
- if (arch == Abi::Architecture::Mcs51Architecture) {
+ if (isMcsArchitecture(arch) || isC166Architecture(arch)) {
QDir includeDir(toolkitDir);
if (includeDir.cd("inc"))
headerPaths.push_back({includeDir.canonicalPath(), HeaderPathType::BuiltIn});
- } else if (arch == Abi::Architecture::ArmArchitecture) {
+ } else if (isArmArchitecture(arch)) {
QDir includeDir(toolkitDir);
if (includeDir.cd("include"))
headerPaths.push_back({includeDir.canonicalPath(), HeaderPathType::BuiltIn});
@@ -191,15 +363,22 @@ static Abi::Architecture guessArchitecture(const Macros &macros)
return Abi::Architecture::ArmArchitecture;
if (macro.key == "__C51__" || macro.key == "__CX51__")
return Abi::Architecture::Mcs51Architecture;
+ if (macro.key == "__C251__")
+ return Abi::Architecture::Mcs251Architecture;
+ if (macro.key == "__C166__")
+ return Abi::Architecture::C166Architecture;
}
return Abi::Architecture::UnknownArchitecture;
}
static unsigned char guessWordWidth(const Macros &macros, Abi::Architecture arch)
{
- // Check for C51 compiler first.
- if (arch == Abi::Architecture::Mcs51Architecture)
- return 16; // C51 always have 16-bit word width.
+ // Check for C51 or C251 compiler first, which are always have 16-bit word width:
+ // * http://www.keil.com/support/man/docs/c51/c51_le_datatypes.htm
+ // * http://www.keil.com/support/man/docs/c251/c251_le_datatypes.htm
+ // * http://www.keil.com/support/man/docs/c166/c166_le_datatypes.htm
+ if (isMcsArchitecture(arch) || isC166Architecture(arch))
+ return 16;
const Macro sizeMacro = Utils::findOrDefault(macros, [](const Macro &m) {
return m.key == "__sizeof_int";
@@ -211,9 +390,9 @@ static unsigned char guessWordWidth(const Macros &macros, Abi::Architecture arch
static Abi::BinaryFormat guessFormat(Abi::Architecture arch)
{
- if (arch == Abi::Architecture::ArmArchitecture)
+ if (isArmArchitecture(arch))
return Abi::BinaryFormat::ElfFormat;
- if (arch == Abi::Architecture::Mcs51Architecture)
+ if (isMcsArchitecture(arch) || isC166Architecture(arch))
return Abi::BinaryFormat::OmfFormat;
return Abi::BinaryFormat::UnknownFormat;
}
@@ -230,19 +409,33 @@ static QString buildDisplayName(Abi::Architecture arch, Core::Id language,
{
const auto archName = Abi::toString(arch);
const auto langName = ToolChainManager::displayNameOfLanguageId(language);
- return KeilToolchain::tr("KEIL %1 (%2, %3)")
+ return KeilToolChain::tr("KEIL %1 (%2, %3)")
.arg(version, langName, archName);
}
+static void addDefaultCpuArgs(const FilePath &compiler, QStringList &extraArgs)
+{
+ const Abi::Architecture arch = guessArchitecture(compiler);
+ if (!isArmArchitecture(arch))
+ return;
+
+ const auto extraArgsIt = std::find_if(std::begin(extraArgs), std::end(extraArgs),
+ [](const QString &extraArg) {
+ return extraArg.contains("-cpu") || extraArg.contains("--cpu");
+ });
+ if (extraArgsIt == std::end(extraArgs))
+ extraArgs.push_back("--cpu=cortex-m0");
+}
+
// KeilToolchain
-KeilToolchain::KeilToolchain() :
+KeilToolChain::KeilToolChain() :
ToolChain(Constants::KEIL_TOOLCHAIN_TYPEID)
{
- setTypeDisplayName(Internal::KeilToolchainFactory::tr("KEIL"));
+ setTypeDisplayName(tr("KEIL"));
}
-void KeilToolchain::setTargetAbi(const Abi &abi)
+void KeilToolChain::setTargetAbi(const Abi &abi)
{
if (abi == m_targetAbi)
return;
@@ -250,17 +443,17 @@ void KeilToolchain::setTargetAbi(const Abi &abi)
toolChainUpdated();
}
-Abi KeilToolchain::targetAbi() const
+Abi KeilToolChain::targetAbi() const
{
return m_targetAbi;
}
-bool KeilToolchain::isValid() const
+bool KeilToolChain::isValid() const
{
return true;
}
-ToolChain::MacroInspectionRunner KeilToolchain::createMacroInspectionRunner() const
+ToolChain::MacroInspectionRunner KeilToolChain::createMacroInspectionRunner() const
{
Environment env = Environment::systemEnvironment();
addToEnvironment(env);
@@ -269,12 +462,13 @@ ToolChain::MacroInspectionRunner KeilToolchain::createMacroInspectionRunner() co
const Core::Id lang = language();
MacrosCache macroCache = predefinedMacrosCache();
+ const QStringList extraArgs = m_extraCodeModelFlags;
- return [env, compilerCommand, macroCache, lang]
+ return [env, compilerCommand, extraArgs, macroCache, lang]
(const QStringList &flags) {
Q_UNUSED(flags)
- const Macros macros = dumpPredefinedMacros(compilerCommand, env.toStringList());
+ const Macros macros = dumpPredefinedMacros(compilerCommand, extraArgs, env.toStringList());
const auto report = MacroInspectionReport{macros, languageVersion(lang, macros)};
macroCache->insert({}, report);
@@ -282,23 +476,23 @@ ToolChain::MacroInspectionRunner KeilToolchain::createMacroInspectionRunner() co
};
}
-Macros KeilToolchain::predefinedMacros(const QStringList &cxxflags) const
+Macros KeilToolChain::predefinedMacros(const QStringList &cxxflags) const
{
return createMacroInspectionRunner()(cxxflags).macros;
}
-Utils::LanguageExtensions KeilToolchain::languageExtensions(const QStringList &) const
+Utils::LanguageExtensions KeilToolChain::languageExtensions(const QStringList &) const
{
return LanguageExtension::None;
}
-WarningFlags KeilToolchain::warningFlags(const QStringList &cxxflags) const
+WarningFlags KeilToolChain::warningFlags(const QStringList &cxxflags) const
{
Q_UNUSED(cxxflags)
return WarningFlags::Default;
}
-ToolChain::BuiltInHeaderPathsRunner KeilToolchain::createBuiltInHeaderPathsRunner(
+ToolChain::BuiltInHeaderPathsRunner KeilToolChain::createBuiltInHeaderPathsRunner(
const Environment &) const
{
const Utils::FilePath compilerCommand = m_compilerCommand;
@@ -317,14 +511,14 @@ ToolChain::BuiltInHeaderPathsRunner KeilToolchain::createBuiltInHeaderPathsRunne
};
}
-HeaderPaths KeilToolchain::builtInHeaderPaths(const QStringList &cxxFlags,
+HeaderPaths KeilToolChain::builtInHeaderPaths(const QStringList &cxxFlags,
const FilePath &fileName,
const Environment &env) const
{
return createBuiltInHeaderPathsRunner(env)(cxxFlags, fileName.toString(), "");
}
-void KeilToolchain::addToEnvironment(Environment &env) const
+void KeilToolChain::addToEnvironment(Environment &env) const
{
if (!m_compilerCommand.isEmpty()) {
const FilePath path = m_compilerCommand.parentDir();
@@ -332,45 +526,48 @@ void KeilToolchain::addToEnvironment(Environment &env) const
}
}
-IOutputParser *KeilToolchain::outputParser() const
+QList<OutputLineParser *> KeilToolChain::createOutputParsers() const
{
- return new KeilParser;
+ return {new KeilParser};
}
-QVariantMap KeilToolchain::toMap() const
+QVariantMap KeilToolChain::toMap() const
{
QVariantMap data = ToolChain::toMap();
data.insert(compilerCommandKeyC, m_compilerCommand.toString());
+ data.insert(compilerPlatformCodeGenFlagsKeyC, m_extraCodeModelFlags);
data.insert(targetAbiKeyC, m_targetAbi.toString());
return data;
}
-bool KeilToolchain::fromMap(const QVariantMap &data)
+bool KeilToolChain::fromMap(const QVariantMap &data)
{
if (!ToolChain::fromMap(data))
return false;
m_compilerCommand = FilePath::fromString(data.value(compilerCommandKeyC).toString());
+ m_extraCodeModelFlags = data.value(compilerPlatformCodeGenFlagsKeyC).toStringList();
m_targetAbi = Abi::fromString(data.value(targetAbiKeyC).toString());
return true;
}
-std::unique_ptr<ToolChainConfigWidget> KeilToolchain::createConfigurationWidget()
+std::unique_ptr<ToolChainConfigWidget> KeilToolChain::createConfigurationWidget()
{
- return std::make_unique<KeilToolchainConfigWidget>(this);
+ return std::make_unique<KeilToolChainConfigWidget>(this);
}
-bool KeilToolchain::operator ==(const ToolChain &other) const
+bool KeilToolChain::operator ==(const ToolChain &other) const
{
if (!ToolChain::operator ==(other))
return false;
- const auto customTc = static_cast<const KeilToolchain *>(&other);
+ const auto customTc = static_cast<const KeilToolChain *>(&other);
return m_compilerCommand == customTc->m_compilerCommand
&& m_targetAbi == customTc->m_targetAbi
+ && m_extraCodeModelFlags == customTc->m_extraCodeModelFlags
;
}
-void KeilToolchain::setCompilerCommand(const FilePath &file)
+void KeilToolChain::setCompilerCommand(const FilePath &file)
{
if (file == m_compilerCommand)
return;
@@ -378,12 +575,25 @@ void KeilToolchain::setCompilerCommand(const FilePath &file)
toolChainUpdated();
}
-FilePath KeilToolchain::compilerCommand() const
+FilePath KeilToolChain::compilerCommand() const
{
return m_compilerCommand;
}
-FilePath KeilToolchain::makeCommand(const Environment &env) const
+void KeilToolChain::setExtraCodeModelFlags(const QStringList &flags)
+{
+ if (flags == m_extraCodeModelFlags)
+ return;
+ m_extraCodeModelFlags = flags;
+ toolChainUpdated();
+}
+
+QStringList KeilToolChain::extraCodeModelFlags() const
+{
+ return m_extraCodeModelFlags;
+}
+
+FilePath KeilToolChain::makeCommand(const Environment &env) const
{
Q_UNUSED(env)
return {};
@@ -391,13 +601,13 @@ FilePath KeilToolchain::makeCommand(const Environment &env) const
// KeilToolchainFactory
-KeilToolchainFactory::KeilToolchainFactory()
+KeilToolChainFactory::KeilToolChainFactory()
{
- setDisplayName(tr("KEIL"));
+ setDisplayName(KeilToolChain::tr("KEIL"));
setSupportedToolChainType(Constants::KEIL_TOOLCHAIN_TYPEID);
setSupportedLanguages({ProjectExplorer::Constants::C_LANGUAGE_ID,
ProjectExplorer::Constants::CXX_LANGUAGE_ID});
- setToolchainConstructor([] { return new KeilToolchain; });
+ setToolchainConstructor([] { return new KeilToolChain; });
setUserCreatable(true);
}
@@ -445,7 +655,7 @@ static QString extractVersion(const QString &toolsFile, const QString &section)
return {};
}
-QList<ToolChain *> KeilToolchainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown)
+QList<ToolChain *> KeilToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown)
{
#ifdef Q_OS_WIN64
static const char kRegistryNode[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Microsoft\\" \
@@ -468,9 +678,13 @@ QList<ToolChain *> KeilToolchainFactory::autoDetect(const QList<ToolChain *> &al
// Fetch the toolchain executable path.
FilePath compilerPath;
if (productPath.endsWith("ARM"))
- compilerPath = productPath.pathAppended("\\ARMCC\\bin\\armcc.exe");
+ compilerPath = productPath.pathAppended("ARMCC/bin/armcc.exe");
else if (productPath.endsWith("C51"))
- compilerPath = productPath.pathAppended("\\BIN\\c51.exe");
+ compilerPath = productPath.pathAppended("BIN/c51.exe");
+ else if (productPath.endsWith("C251"))
+ compilerPath = productPath.pathAppended("BIN/c251.exe");
+ else if (productPath.endsWith("C166"))
+ compilerPath = productPath.pathAppended("BIN/c166.exe");
if (compilerPath.exists()) {
// Fetch the toolchain version.
@@ -492,7 +706,7 @@ QList<ToolChain *> KeilToolchainFactory::autoDetect(const QList<ToolChain *> &al
return autoDetectToolchains(candidates, alreadyKnown);
}
-QList<ToolChain *> KeilToolchainFactory::autoDetectToolchains(
+QList<ToolChain *> KeilToolChainFactory::autoDetectToolchains(
const Candidates &candidates, const QList<ToolChain *> &alreadyKnown) const
{
QList<ToolChain *> result;
@@ -519,26 +733,30 @@ QList<ToolChain *> KeilToolchainFactory::autoDetectToolchains(
return result;
}
-QList<ToolChain *> KeilToolchainFactory::autoDetectToolchain(
+QList<ToolChain *> KeilToolChainFactory::autoDetectToolchain(
const Candidate &candidate, Core::Id language) const
{
const auto env = Environment::systemEnvironment();
- const Macros macros = dumpPredefinedMacros(candidate.compilerPath, env.toStringList());
+
+ QStringList extraArgs;
+ addDefaultCpuArgs(candidate.compilerPath, extraArgs);
+ const Macros macros = dumpPredefinedMacros(candidate.compilerPath, extraArgs, env.toStringList());
if (macros.isEmpty())
return {};
const Abi abi = guessAbi(macros);
const Abi::Architecture arch = abi.architecture();
- if (arch == Abi::Architecture::Mcs51Architecture
+ if ((isMcsArchitecture(arch) || isC166Architecture(arch))
&& language == ProjectExplorer::Constants::CXX_LANGUAGE_ID) {
- // KEIL C51 compiler does not support C++ language.
+ // KEIL C51/C251/C166 compilers does not support C++ language.
return {};
}
- const auto tc = new KeilToolchain;
+ const auto tc = new KeilToolChain;
tc->setDetection(ToolChain::AutoDetection);
tc->setLanguage(language);
tc->setCompilerCommand(candidate.compilerPath);
+ tc->setExtraCodeModelFlags(extraArgs);
tc->setTargetAbi(abi);
tc->setDisplayName(buildDisplayName(abi.architecture(), language, candidate.compilerVersion));
@@ -549,7 +767,7 @@ QList<ToolChain *> KeilToolchainFactory::autoDetectToolchain(
// KeilToolchainConfigWidget
-KeilToolchainConfigWidget::KeilToolchainConfigWidget(KeilToolchain *tc) :
+KeilToolChainConfigWidget::KeilToolChainConfigWidget(KeilToolChain *tc) :
ToolChainConfigWidget(tc),
m_compilerCommand(new PathChooser),
m_abiWidget(new AbiWidget)
@@ -557,27 +775,33 @@ KeilToolchainConfigWidget::KeilToolchainConfigWidget(KeilToolchain *tc) :
m_compilerCommand->setExpectedKind(PathChooser::ExistingCommand);
m_compilerCommand->setHistoryCompleter("PE.KEIL.Command.History");
m_mainLayout->addRow(tr("&Compiler path:"), m_compilerCommand);
+ m_platformCodeGenFlagsLineEdit = new QLineEdit(this);
+ m_platformCodeGenFlagsLineEdit->setText(QtcProcess::joinArgs(tc->extraCodeModelFlags()));
+ m_mainLayout->addRow(tr("Platform codegen flags:"), m_platformCodeGenFlagsLineEdit);
m_mainLayout->addRow(tr("&ABI:"), m_abiWidget);
m_abiWidget->setEnabled(false);
addErrorLabel();
- setFromToolchain();
+ setFromToolChain();
connect(m_compilerCommand, &PathChooser::rawPathChanged,
- this, &KeilToolchainConfigWidget::handleCompilerCommandChange);
+ this, &KeilToolChainConfigWidget::handleCompilerCommandChange);
+ connect(m_platformCodeGenFlagsLineEdit, &QLineEdit::editingFinished,
+ this, &KeilToolChainConfigWidget::handlePlatformCodeGenFlagsChange);
connect(m_abiWidget, &AbiWidget::abiChanged,
this, &ToolChainConfigWidget::dirty);
}
-void KeilToolchainConfigWidget::applyImpl()
+void KeilToolChainConfigWidget::applyImpl()
{
if (toolChain()->isAutoDetected())
return;
- const auto tc = static_cast<KeilToolchain *>(toolChain());
+ const auto tc = static_cast<KeilToolChain *>(toolChain());
const QString displayName = tc->displayName();
- tc->setCompilerCommand(m_compilerCommand->fileName());
+ tc->setCompilerCommand(m_compilerCommand->filePath());
+ tc->setExtraCodeModelFlags(splitString(m_platformCodeGenFlagsLineEdit->text()));
tc->setTargetAbi(m_abiWidget->currentAbi());
tc->setDisplayName(displayName);
@@ -587,40 +811,48 @@ void KeilToolchainConfigWidget::applyImpl()
const auto languageVersion = ToolChain::languageVersion(tc->language(), m_macros);
tc->predefinedMacrosCache()->insert({}, {m_macros, languageVersion});
- setFromToolchain();
+ setFromToolChain();
}
-bool KeilToolchainConfigWidget::isDirtyImpl() const
+bool KeilToolChainConfigWidget::isDirtyImpl() const
{
- const auto tc = static_cast<KeilToolchain *>(toolChain());
- return m_compilerCommand->fileName() != tc->compilerCommand()
+ const auto tc = static_cast<KeilToolChain *>(toolChain());
+ return m_compilerCommand->filePath() != tc->compilerCommand()
+ || m_platformCodeGenFlagsLineEdit->text() != QtcProcess::joinArgs(tc->extraCodeModelFlags())
|| m_abiWidget->currentAbi() != tc->targetAbi()
;
}
-void KeilToolchainConfigWidget::makeReadOnlyImpl()
+void KeilToolChainConfigWidget::makeReadOnlyImpl()
{
m_compilerCommand->setReadOnly(true);
+ m_platformCodeGenFlagsLineEdit->setEnabled(false);
m_abiWidget->setEnabled(false);
}
-void KeilToolchainConfigWidget::setFromToolchain()
+void KeilToolChainConfigWidget::setFromToolChain()
{
const QSignalBlocker blocker(this);
- const auto tc = static_cast<KeilToolchain *>(toolChain());
- m_compilerCommand->setFileName(tc->compilerCommand());
+ const auto tc = static_cast<KeilToolChain *>(toolChain());
+ m_compilerCommand->setFilePath(tc->compilerCommand());
+ m_platformCodeGenFlagsLineEdit->setText(QtcProcess::joinArgs(tc->extraCodeModelFlags()));
m_abiWidget->setAbis({}, tc->targetAbi());
- const bool haveCompiler = compilerExists(m_compilerCommand->fileName());
+ const bool haveCompiler = compilerExists(m_compilerCommand->filePath());
m_abiWidget->setEnabled(haveCompiler && !tc->isAutoDetected());
}
-void KeilToolchainConfigWidget::handleCompilerCommandChange()
+void KeilToolChainConfigWidget::handleCompilerCommandChange()
{
- const FilePath compilerPath = m_compilerCommand->fileName();
+ const FilePath compilerPath = m_compilerCommand->filePath();
const bool haveCompiler = compilerExists(compilerPath);
if (haveCompiler) {
const auto env = Environment::systemEnvironment();
- m_macros = dumpPredefinedMacros(compilerPath, env.toStringList());
+ const QStringList prevExtraArgs = splitString(m_platformCodeGenFlagsLineEdit->text());
+ QStringList newExtraArgs = prevExtraArgs;
+ addDefaultCpuArgs(compilerPath, newExtraArgs);
+ if (prevExtraArgs != newExtraArgs)
+ m_platformCodeGenFlagsLineEdit->setText(QtcProcess::joinArgs(newExtraArgs));
+ m_macros = dumpPredefinedMacros(compilerPath, newExtraArgs, env.toStringList());
const Abi guessed = guessAbi(m_macros);
m_abiWidget->setAbis({}, guessed);
}
@@ -629,5 +861,15 @@ void KeilToolchainConfigWidget::handleCompilerCommandChange()
emit dirty();
}
+void KeilToolChainConfigWidget::handlePlatformCodeGenFlagsChange()
+{
+ const QString str1 = m_platformCodeGenFlagsLineEdit->text();
+ const QString str2 = QtcProcess::joinArgs(splitString(str1));
+ if (str1 != str2)
+ m_platformCodeGenFlagsLineEdit->setText(str2);
+ else
+ handleCompilerCommandChange();
+}
+
} // namespace Internal
} // namespace BareMetal
diff --git a/src/plugins/baremetal/keiltoolchain.h b/src/plugins/baremetal/keiltoolchain.h
index a8b3c660a0..d9f85d33f6 100644
--- a/src/plugins/baremetal/keiltoolchain.h
+++ b/src/plugins/baremetal/keiltoolchain.h
@@ -30,6 +30,7 @@
#include <projectexplorer/toolchainconfigwidget.h>
QT_BEGIN_NAMESPACE
+class QLineEdit;
class QPlainTextEdit;
class QPushButton;
class QTextEdit;
@@ -45,11 +46,11 @@ namespace ProjectExplorer { class AbiWidget; }
namespace BareMetal {
namespace Internal {
-// KeilToolchain
+// KeilToolChain
-class KeilToolchain final : public ProjectExplorer::ToolChain
+class KeilToolChain final : public ProjectExplorer::ToolChain
{
- Q_DECLARE_TR_FUNCTIONS(KeilToolchain)
+ Q_DECLARE_TR_FUNCTIONS(KeilToolChain)
public:
void setTargetAbi(const ProjectExplorer::Abi &abi);
@@ -69,7 +70,7 @@ public:
const Utils::FilePath &,
const Utils::Environment &env) const final;
void addToEnvironment(Utils::Environment &env) const final;
- ProjectExplorer::IOutputParser *outputParser() const final;
+ QList<Utils::OutputLineParser *> createOutputParsers() const final;
QVariantMap toMap() const final;
bool fromMap(const QVariantMap &data) final;
@@ -81,26 +82,28 @@ public:
void setCompilerCommand(const Utils::FilePath &file);
Utils::FilePath compilerCommand() const final;
+ void setExtraCodeModelFlags(const QStringList &flags);
+ QStringList extraCodeModelFlags() const final;
+
Utils::FilePath makeCommand(const Utils::Environment &env) const final;
private:
- KeilToolchain();
+ KeilToolChain();
ProjectExplorer::Abi m_targetAbi;
Utils::FilePath m_compilerCommand;
+ QStringList m_extraCodeModelFlags;
- friend class KeilToolchainFactory;
- friend class KeilToolchainConfigWidget;
+ friend class KeilToolChainFactory;
+ friend class KeilToolChainConfigWidget;
};
// KeilToolchainFactory
-class KeilToolchainFactory final : public ProjectExplorer::ToolChainFactory
+class KeilToolChainFactory final : public ProjectExplorer::ToolChainFactory
{
- Q_OBJECT
-
public:
- KeilToolchainFactory();
+ KeilToolChainFactory();
QList<ProjectExplorer::ToolChain *> autoDetect(
const QList<ProjectExplorer::ToolChain *> &alreadyKnown) final;
@@ -114,24 +117,26 @@ private:
// KeilToolchainConfigWidget
-class KeilToolchainConfigWidget final : public ProjectExplorer::ToolChainConfigWidget
+class KeilToolChainConfigWidget final : public ProjectExplorer::ToolChainConfigWidget
{
Q_OBJECT
public:
- explicit KeilToolchainConfigWidget(KeilToolchain *tc);
+ explicit KeilToolChainConfigWidget(KeilToolChain *tc);
private:
void applyImpl() final;
- void discardImpl() final { setFromToolchain(); }
+ void discardImpl() final { setFromToolChain(); }
bool isDirtyImpl() const final;
void makeReadOnlyImpl() final;
- void setFromToolchain();
+ void setFromToolChain();
void handleCompilerCommandChange();
+ void handlePlatformCodeGenFlagsChange();
Utils::PathChooser *m_compilerCommand = nullptr;
ProjectExplorer::AbiWidget *m_abiWidget = nullptr;
+ QLineEdit *m_platformCodeGenFlagsLineEdit = nullptr;
ProjectExplorer::Macros m_macros;
};
diff --git a/src/plugins/baremetal/sdccparser.cpp b/src/plugins/baremetal/sdccparser.cpp
index 5a12b5d66e..5a6b23c0d0 100644
--- a/src/plugins/baremetal/sdccparser.cpp
+++ b/src/plugins/baremetal/sdccparser.cpp
@@ -28,9 +28,6 @@
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/task.h>
-#include <texteditor/fontsettings.h>
-#include <texteditor/texteditorsettings.h>
-
#include <QRegularExpression>
using namespace ProjectExplorer;
@@ -66,30 +63,21 @@ Core::Id SdccParser::id()
void SdccParser::newTask(const Task &task)
{
- doFlush();
+ flush();
m_lastTask = task;
m_lines = 1;
}
void SdccParser::amendDescription(const QString &desc)
{
- const int start = m_lastTask.description.count() + 1;
- m_lastTask.description.append('\n');
- m_lastTask.description.append(desc);
-
- QTextLayout::FormatRange fr;
- fr.start = start;
- fr.length = m_lastTask.description.count() + 1;
- fr.format.setFont(TextEditor::TextEditorSettings::fontSettings().font());
- fr.format.setFontStyleHint(QFont::Monospace);
- m_lastTask.formats.append(fr);
-
+ m_lastTask.details.append(desc);
++m_lines;
}
-void SdccParser::stdError(const QString &line)
+OutputLineParser::Result SdccParser::handleLine(const QString &line, OutputFormat type)
{
- IOutputParser::stdError(line);
+ if (type == StdOutFormat)
+ return Status::NotHandled;
const QString lne = rightTrimmed(line);
@@ -106,8 +94,11 @@ void SdccParser::stdError(const QString &line)
const int lineno = match.captured(LineNumberIndex).toInt();
const Task::TaskType type = taskType(match.captured(MessageTypeIndex));
const QString descr = match.captured(MessageTextIndex);
- newTask(CompileTask(type, descr, fileName, lineno));
- return;
+ newTask(CompileTask(type, descr, absoluteFilePath(fileName), lineno));
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, m_lastTask.file, m_lastTask.line, match,
+ FilePathIndex);
+ return {Status::InProgress, linkSpecs};
}
re.setPattern("^(.+\\.\\S+):(\\d+): (Error|error|syntax error): (.+)$");
@@ -120,8 +111,11 @@ void SdccParser::stdError(const QString &line)
const int lineno = match.captured(LineNumberIndex).toInt();
const Task::TaskType type = taskType(match.captured(MessageTypeIndex));
const QString descr = match.captured(MessageTextIndex);
- newTask(CompileTask(type, descr, fileName, lineno));
- return;
+ newTask(CompileTask(type, descr, absoluteFilePath(fileName), lineno));
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, m_lastTask.file, m_lastTask.line, match,
+ FilePathIndex);
+ return {Status::InProgress, linkSpecs};
}
re.setPattern("^at (\\d+): (warning|error) \\d+: (.+)$");
@@ -131,7 +125,7 @@ void SdccParser::stdError(const QString &line)
const Task::TaskType type = taskType(match.captured(MessageTypeIndex));
const QString descr = match.captured(MessageTextIndex);
newTask(CompileTask(type, descr));
- return;
+ return Status::InProgress;
}
re.setPattern("^\\?ASlink-(Warning|Error)-(.+)$");
@@ -141,30 +135,27 @@ void SdccParser::stdError(const QString &line)
const Task::TaskType type = taskType(match.captured(MessageTypeIndex));
const QString descr = match.captured(MessageTextIndex);
newTask(CompileTask(type, descr));
- return;
+ return Status::InProgress;
}
if (!m_lastTask.isNull()) {
amendDescription(lne);
- return;
+ return Status::InProgress;
}
- doFlush();
-}
-
-void SdccParser::stdOutput(const QString &line)
-{
- IOutputParser::stdOutput(line);
+ flush();
+ return Status::NotHandled;
}
-void SdccParser::doFlush()
+void SdccParser::flush()
{
if (m_lastTask.isNull())
return;
+ setDetailsFormat(m_lastTask);
Task t = m_lastTask;
m_lastTask.clear();
- emit addTask(t, m_lines, 1);
+ scheduleTask(t, m_lines, 1);
m_lines = 0;
}
@@ -207,7 +198,7 @@ void BareMetalPlugin::testSdccOutputParsers_data()
<< QString::fromLatin1("c:\\foo\\main.c:63: Error: Some error")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("c:\\foo\\main.c:63: Error: Some error\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Error,
"Some error",
FilePath::fromUserInput("c:\\foo\\main.c"),
@@ -218,7 +209,7 @@ void BareMetalPlugin::testSdccOutputParsers_data()
<< QString::fromLatin1("c:\\foo\\main.c:63: warning 123: Some warning")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("c:\\foo\\main.c:63: warning 123: Some warning\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Warning,
"Some warning",
FilePath::fromUserInput("c:\\foo\\main.c"),
@@ -231,9 +222,7 @@ void BareMetalPlugin::testSdccOutputParsers_data()
" details #2")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("c:\\foo\\main.c:63: warning 123: Some warning\n"
- "details #1\n"
- " details #2\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Warning,
"Some warning\n"
"details #1\n"
@@ -246,7 +235,7 @@ void BareMetalPlugin::testSdccOutputParsers_data()
<< QString::fromLatin1("c:\\foo\\main.c:63: error: Some error")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("c:\\foo\\main.c:63: error: Some error\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Error,
"Some error",
FilePath::fromUserInput("c:\\foo\\main.c"),
@@ -257,7 +246,7 @@ void BareMetalPlugin::testSdccOutputParsers_data()
<< QString::fromLatin1("c:\\foo\\main.c:63: error 123: Some error")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("c:\\foo\\main.c:63: error 123: Some error\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Error,
"Some error",
FilePath::fromUserInput("c:\\foo\\main.c"),
@@ -270,9 +259,7 @@ void BareMetalPlugin::testSdccOutputParsers_data()
" details #2")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("c:\\foo\\main.c:63: error 123: Some error\n"
- "details #1\n"
- " details #2\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Error,
"Some error\n"
"details #1\n"
@@ -285,7 +272,7 @@ void BareMetalPlugin::testSdccOutputParsers_data()
<< QString::fromLatin1("c:\\foo\\main.c:63: syntax error: Some error")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("c:\\foo\\main.c:63: syntax error: Some error\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Error,
"Some error",
FilePath::fromUserInput("c:\\foo\\main.c"),
@@ -296,7 +283,7 @@ void BareMetalPlugin::testSdccOutputParsers_data()
<< QString::fromLatin1("at 1: error 123: Some error")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("at 1: error 123: Some error\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Error,
"Some error"))
<< QString();
@@ -305,7 +292,7 @@ void BareMetalPlugin::testSdccOutputParsers_data()
<< QString::fromLatin1("at 1: warning 123: Some warning")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("at 1: warning 123: Some warning\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Warning,
"Some warning"))
<< QString();
@@ -314,7 +301,7 @@ void BareMetalPlugin::testSdccOutputParsers_data()
<< QString::fromLatin1("?ASlink-Warning-Couldn't find library 'foo.lib'")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("?ASlink-Warning-Couldn't find library 'foo.lib'\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Warning,
"Couldn't find library 'foo.lib'"))
<< QString();
@@ -323,7 +310,7 @@ void BareMetalPlugin::testSdccOutputParsers_data()
<< QString::fromLatin1("?ASlink-Error-<cannot open> : \"foo.rel\"")
<< OutputParserTester::STDERR
<< QString()
- << QString::fromLatin1("?ASlink-Error-<cannot open> : \"foo.rel\"\n")
+ << QString()
<< (Tasks() << CompileTask(Task::Error,
"<cannot open> : \"foo.rel\""))
<< QString();
@@ -332,7 +319,7 @@ void BareMetalPlugin::testSdccOutputParsers_data()
void BareMetalPlugin::testSdccOutputParsers()
{
OutputParserTester testbench;
- testbench.appendOutputParser(new SdccParser);
+ testbench.addLineParser(new SdccParser);
QFETCH(QString, input);
QFETCH(OutputParserTester::Channel, inputChannel);
QFETCH(Tasks, tasks);
diff --git a/src/plugins/baremetal/sdccparser.h b/src/plugins/baremetal/sdccparser.h
index fb7866c879..0b92b70225 100644
--- a/src/plugins/baremetal/sdccparser.h
+++ b/src/plugins/baremetal/sdccparser.h
@@ -33,7 +33,7 @@ namespace Internal {
// SdccParser
-class SdccParser final : public ProjectExplorer::IOutputParser
+class SdccParser final : public ProjectExplorer::OutputTaskParser
{
Q_OBJECT
@@ -45,9 +45,8 @@ private:
void newTask(const ProjectExplorer::Task &task);
void amendDescription(const QString &desc);
- void stdError(const QString &line) final;
- void stdOutput(const QString &line) final;
- void doFlush() final;
+ Result handleLine(const QString &line, Utils::OutputFormat type) final;
+ void flush() final;
ProjectExplorer::Task m_lastTask;
int m_lines = 0;
diff --git a/src/plugins/baremetal/sdcctoolchain.cpp b/src/plugins/baremetal/sdcctoolchain.cpp
index a7b62686c8..97db9a5910 100644
--- a/src/plugins/baremetal/sdcctoolchain.cpp
+++ b/src/plugins/baremetal/sdcctoolchain.cpp
@@ -217,7 +217,7 @@ static Utils::FilePath compilerPathFromEnvironment(const QString &compilerName)
SdccToolChain::SdccToolChain() :
ToolChain(Constants::SDCC_TOOLCHAIN_TYPEID)
{
- setTypeDisplayName(Internal::SdccToolChainFactory::tr("SDCC"));
+ setTypeDisplayName(Internal::SdccToolChain::tr("SDCC"));
}
void SdccToolChain::setTargetAbi(const Abi &abi)
@@ -307,9 +307,9 @@ void SdccToolChain::addToEnvironment(Environment &env) const
}
}
-IOutputParser *SdccToolChain::outputParser() const
+QList<Utils::OutputLineParser *> SdccToolChain::createOutputParsers() const
{
- return new SdccParser;
+ return {new SdccParser};
}
QVariantMap SdccToolChain::toMap() const
@@ -368,7 +368,7 @@ FilePath SdccToolChain::makeCommand(const Environment &env) const
SdccToolChainFactory::SdccToolChainFactory()
{
- setDisplayName(tr("SDCC"));
+ setDisplayName(SdccToolChain::tr("SDCC"));
setSupportedToolChainType(Constants::SDCC_TOOLCHAIN_TYPEID);
setSupportedLanguages({ProjectExplorer::Constants::C_LANGUAGE_ID});
setToolchainConstructor([] { return new SdccToolChain; });
@@ -390,7 +390,7 @@ QList<ToolChain *> SdccToolChainFactory::autoDetect(const QList<ToolChain *> &al
if (compilerPath.isEmpty())
return Candidate{};
// Build full compiler path.
- compilerPath += "\\bin\\sdcc.exe";
+ compilerPath += "/bin/sdcc.exe";
const FilePath fn = FilePath::fromString(
QFileInfo(compilerPath).absoluteFilePath());
if (!compilerExists(fn))
@@ -528,7 +528,7 @@ void SdccToolChainConfigWidget::applyImpl()
const auto tc = static_cast<SdccToolChain *>(toolChain());
const QString displayName = tc->displayName();
- tc->setCompilerCommand(m_compilerCommand->fileName());
+ tc->setCompilerCommand(m_compilerCommand->filePath());
tc->setTargetAbi(m_abiWidget->currentAbi());
tc->setDisplayName(displayName);
@@ -544,7 +544,7 @@ void SdccToolChainConfigWidget::applyImpl()
bool SdccToolChainConfigWidget::isDirtyImpl() const
{
const auto tc = static_cast<SdccToolChain *>(toolChain());
- return m_compilerCommand->fileName() != tc->compilerCommand()
+ return m_compilerCommand->filePath() != tc->compilerCommand()
|| m_abiWidget->currentAbi() != tc->targetAbi()
;
}
@@ -559,15 +559,15 @@ void SdccToolChainConfigWidget::setFromToolchain()
{
const QSignalBlocker blocker(this);
const auto tc = static_cast<SdccToolChain *>(toolChain());
- m_compilerCommand->setFileName(tc->compilerCommand());
+ m_compilerCommand->setFilePath(tc->compilerCommand());
m_abiWidget->setAbis({}, tc->targetAbi());
- const bool haveCompiler = compilerExists(m_compilerCommand->fileName());
+ const bool haveCompiler = compilerExists(m_compilerCommand->filePath());
m_abiWidget->setEnabled(haveCompiler && !tc->isAutoDetected());
}
void SdccToolChainConfigWidget::handleCompilerCommandChange()
{
- const FilePath compilerPath = m_compilerCommand->fileName();
+ const FilePath compilerPath = m_compilerCommand->filePath();
const bool haveCompiler = compilerExists(compilerPath);
if (haveCompiler) {
const auto env = Environment::systemEnvironment();
diff --git a/src/plugins/baremetal/sdcctoolchain.h b/src/plugins/baremetal/sdcctoolchain.h
index ef851f4a78..09aff331af 100644
--- a/src/plugins/baremetal/sdcctoolchain.h
+++ b/src/plugins/baremetal/sdcctoolchain.h
@@ -69,7 +69,7 @@ public:
const Utils::FilePath &,
const Utils::Environment &env) const final;
void addToEnvironment(Utils::Environment &env) const final;
- ProjectExplorer::IOutputParser *outputParser() const final;
+ QList<Utils::OutputLineParser *> createOutputParsers() const final;
QVariantMap toMap() const final;
bool fromMap(const QVariantMap &data) final;
@@ -97,8 +97,6 @@ private:
class SdccToolChainFactory final : public ProjectExplorer::ToolChainFactory
{
- Q_OBJECT
-
public:
SdccToolChainFactory();
diff --git a/src/plugins/bazaar/pullorpushdialog.cpp b/src/plugins/bazaar/pullorpushdialog.cpp
index 691dbca0db..c85b72c530 100644
--- a/src/plugins/bazaar/pullorpushdialog.cpp
+++ b/src/plugins/bazaar/pullorpushdialog.cpp
@@ -57,7 +57,7 @@ QString PullOrPushDialog::branchLocation() const
if (m_ui->defaultButton->isChecked())
return QString();
if (m_ui->localButton->isChecked())
- return m_ui->localPathChooser->path();
+ return m_ui->localPathChooser->filePath().toString();
return m_ui->urlLineEdit->text();
}
diff --git a/src/plugins/beautifier/artisticstyle/artisticstyleoptionspage.cpp b/src/plugins/beautifier/artisticstyle/artisticstyleoptionspage.cpp
index 66292f91c0..922f747742 100644
--- a/src/plugins/beautifier/artisticstyle/artisticstyleoptionspage.cpp
+++ b/src/plugins/beautifier/artisticstyle/artisticstyleoptionspage.cpp
@@ -66,11 +66,11 @@ ArtisticStyleOptionsPageWidget::ArtisticStyleOptionsPageWidget(ArtisticStyleSett
connect(ui.command, &Utils::PathChooser::validChanged, ui.options, &QWidget::setEnabled);
ui.configurations->setSettings(m_settings);
- ui.command->setFileName(m_settings->command());
+ ui.command->setFilePath(m_settings->command());
ui.mime->setText(m_settings->supportedMimeTypesAsString());
ui.useOtherFiles->setChecked(m_settings->useOtherFiles());
ui.useSpecificConfigFile->setChecked(m_settings->useSpecificConfigFile());
- ui.specificConfigFile->setFileName(m_settings->specificConfigFile());
+ ui.specificConfigFile->setFilePath(m_settings->specificConfigFile());
ui.useHomeFile->setChecked(m_settings->useHomeFile());
ui.useCustomStyle->setChecked(m_settings->useCustomStyle());
ui.configurations->setCurrentConfiguration(m_settings->customStyle());
@@ -78,11 +78,11 @@ ArtisticStyleOptionsPageWidget::ArtisticStyleOptionsPageWidget(ArtisticStyleSett
void ArtisticStyleOptionsPageWidget::apply()
{
- m_settings->setCommand(ui.command->path());
+ m_settings->setCommand(ui.command->filePath().toString());
m_settings->setSupportedMimeTypes(ui.mime->text());
m_settings->setUseOtherFiles(ui.useOtherFiles->isChecked());
m_settings->setUseSpecificConfigFile(ui.useSpecificConfigFile->isChecked());
- m_settings->setSpecificConfigFile(ui.specificConfigFile->fileName());
+ m_settings->setSpecificConfigFile(ui.specificConfigFile->filePath());
m_settings->setUseHomeFile(ui.useHomeFile->isChecked());
m_settings->setUseCustomStyle(ui.useCustomStyle->isChecked());
m_settings->setCustomStyle(ui.configurations->currentConfiguration());
diff --git a/src/plugins/beautifier/clangformat/clangformatoptionspage.cpp b/src/plugins/beautifier/clangformat/clangformatoptionspage.cpp
index 0ac10b98bf..767b44064c 100644
--- a/src/plugins/beautifier/clangformat/clangformatoptionspage.cpp
+++ b/src/plugins/beautifier/clangformat/clangformatoptionspage.cpp
@@ -71,7 +71,7 @@ ClangFormatOptionsPageWidget::ClangFormatOptionsPageWidget(ClangFormatSettings *
});
ui.configurations->setSettings(m_settings);
- ui.command->setFileName(m_settings->command());
+ ui.command->setFilePath(m_settings->command());
ui.mime->setText(m_settings->supportedMimeTypesAsString());
const int predefinedStyleIndex = ui.predefinedStyle->findText(m_settings->predefinedStyle());
if (predefinedStyleIndex != -1)
@@ -90,7 +90,7 @@ ClangFormatOptionsPageWidget::ClangFormatOptionsPageWidget(ClangFormatSettings *
void ClangFormatOptionsPageWidget::apply()
{
- m_settings->setCommand(ui.command->path());
+ m_settings->setCommand(ui.command->filePath().toString());
m_settings->setSupportedMimeTypes(ui.mime->text());
m_settings->setUsePredefinedStyle(ui.usePredefinedStyle->isChecked());
m_settings->setPredefinedStyle(ui.predefinedStyle->currentText());
diff --git a/src/plugins/beautifier/uncrustify/uncrustifyoptionspage.cpp b/src/plugins/beautifier/uncrustify/uncrustifyoptionspage.cpp
index c9d98f802c..10dd6377d8 100644
--- a/src/plugins/beautifier/uncrustify/uncrustifyoptionspage.cpp
+++ b/src/plugins/beautifier/uncrustify/uncrustifyoptionspage.cpp
@@ -67,12 +67,12 @@ UncrustifyOptionsPageWidget::UncrustifyOptionsPageWidget(UncrustifySettings *set
connect(ui.command, &Utils::PathChooser::validChanged, ui.options, &QWidget::setEnabled);
ui.configurations->setSettings(m_settings);
- ui.command->setFileName(m_settings->command());
+ ui.command->setFilePath(m_settings->command());
ui.mime->setText(m_settings->supportedMimeTypesAsString());
ui.useOtherFiles->setChecked(m_settings->useOtherFiles());
ui.useHomeFile->setChecked(m_settings->useHomeFile());
ui.useSpecificFile->setChecked(m_settings->useSpecificConfigFile());
- ui.uncrusifyFilePath->setFileName(m_settings->specificConfigFile());
+ ui.uncrusifyFilePath->setFilePath(m_settings->specificConfigFile());
ui.useCustomStyle->setChecked(m_settings->useCustomStyle());
ui.configurations->setCurrentConfiguration(m_settings->customStyle());
ui.formatEntireFileFallback->setChecked(m_settings->formatEntireFileFallback());
@@ -80,12 +80,12 @@ UncrustifyOptionsPageWidget::UncrustifyOptionsPageWidget(UncrustifySettings *set
void UncrustifyOptionsPageWidget::apply()
{
- m_settings->setCommand(ui.command->path());
+ m_settings->setCommand(ui.command->filePath().toString());
m_settings->setSupportedMimeTypes(ui.mime->text());
m_settings->setUseOtherFiles(ui.useOtherFiles->isChecked());
m_settings->setUseHomeFile(ui.useHomeFile->isChecked());
m_settings->setUseSpecificConfigFile(ui.useSpecificFile->isChecked());
- m_settings->setSpecificConfigFile(ui.uncrusifyFilePath->fileName());
+ m_settings->setSpecificConfigFile(ui.uncrusifyFilePath->filePath());
m_settings->setUseCustomStyle(ui.useCustomStyle->isChecked());
m_settings->setCustomStyle(ui.configurations->currentConfiguration());
m_settings->setFormatEntireFileFallback(ui.formatEntireFileFallback->isChecked());
diff --git a/src/plugins/bineditor/bineditorplugin.cpp b/src/plugins/bineditor/bineditorplugin.cpp
index c21f530ade..c25d36d1a1 100644
--- a/src/plugins/bineditor/bineditorplugin.cpp
+++ b/src/plugins/bineditor/bineditorplugin.cpp
@@ -42,7 +42,7 @@
#include <QMessageBox>
#include <QHBoxLayout>
#include <QLineEdit>
-#include <QRegExpValidator>
+#include <QRegularExpressionValidator>
#include <QToolBar>
#include <coreplugin/actionmanager/actionmanager.h>
@@ -363,7 +363,7 @@ public:
setWidget(widget);
m_file = new BinEditorDocument(widget);
m_addressEdit = new QLineEdit;
- auto addressValidator = new QRegExpValidator(QRegExp("[0-9a-fA-F]{1,16}"), m_addressEdit);
+ auto addressValidator = new QRegularExpressionValidator(QRegularExpression("[0-9a-fA-F]{1,16}"), m_addressEdit);
m_addressEdit->setValidator(addressValidator);
auto l = new QHBoxLayout;
diff --git a/src/plugins/bookmarks/bookmarkmanager.cpp b/src/plugins/bookmarks/bookmarkmanager.cpp
index f4147f02a3..7c1854ff29 100644
--- a/src/plugins/bookmarks/bookmarkmanager.cpp
+++ b/src/plugins/bookmarks/bookmarkmanager.cpp
@@ -274,7 +274,7 @@ void BookmarkView::removeBookmark(const QModelIndex& index)
void BookmarkView::keyPressEvent(QKeyEvent *event)
{
- if (event->key() == Qt::Key_Delete) {
+ if (event->key() == Qt::Key_Delete || event->key() == Qt::Key_Backspace) {
removeBookmark(currentIndex());
event->accept();
return;
diff --git a/src/plugins/boot2qt/CMakeLists.txt b/src/plugins/boot2qt/CMakeLists.txt
index c557459698..d11cd580f9 100644
--- a/src/plugins/boot2qt/CMakeLists.txt
+++ b/src/plugins/boot2qt/CMakeLists.txt
@@ -6,7 +6,6 @@ add_qtc_plugin(Boot2Qt
qdb_global.h
qdbconstants.h
qdbdeployconfigurationfactory.cpp qdbdeployconfigurationfactory.h
- qdbdeploystepfactory.cpp qdbdeploystepfactory.h
qdbdevice.cpp qdbdevice.h
qdbdevicedebugsupport.cpp qdbdevicedebugsupport.h
qdbmakedefaultappservice.cpp qdbmakedefaultappservice.h
diff --git a/src/plugins/boot2qt/boot2qt.pro b/src/plugins/boot2qt/boot2qt.pro
index 8c5f51e504..c6e5293845 100644
--- a/src/plugins/boot2qt/boot2qt.pro
+++ b/src/plugins/boot2qt/boot2qt.pro
@@ -16,7 +16,6 @@ HEADERS += \
qdbmakedefaultappservice.h \
qdbstopapplicationstep.h \
qdbstopapplicationservice.h \
- qdbdeploystepfactory.h \
qdbdevicedebugsupport.h \
qdbconstants.h \
qdb_global.h \
@@ -32,7 +31,6 @@ SOURCES += \
qdbmakedefaultappservice.cpp \
qdbstopapplicationstep.cpp \
qdbstopapplicationservice.cpp \
- qdbdeploystepfactory.cpp \
qdbdevicedebugsupport.cpp \
qdbplugin.cpp \
diff --git a/src/plugins/boot2qt/boot2qt.qbs b/src/plugins/boot2qt/boot2qt.qbs
index ac6a33f279..3487e3eb94 100644
--- a/src/plugins/boot2qt/boot2qt.qbs
+++ b/src/plugins/boot2qt/boot2qt.qbs
@@ -23,8 +23,6 @@ QtcPlugin {
"qdb_global.h",
"qdbdeployconfigurationfactory.cpp",
"qdbdeployconfigurationfactory.h",
- "qdbdeploystepfactory.cpp",
- "qdbdeploystepfactory.h",
"qdbdevice.cpp",
"qdbdevice.h",
"qdbdevicedebugsupport.cpp",
diff --git a/src/plugins/boot2qt/qdbconstants.h b/src/plugins/boot2qt/qdbconstants.h
index 34471f43df..3ea41608e9 100644
--- a/src/plugins/boot2qt/qdbconstants.h
+++ b/src/plugins/boot2qt/qdbconstants.h
@@ -34,6 +34,9 @@ const char QdbLinuxOsType[] = "QdbLinuxOsType";
const char QdbDeployConfigurationId[] = "Qt4ProjectManager.Qdb.QdbDeployConfiguration";
+const char QdbStopApplicationStepId[] = "Qdb.StopApplicationStep";
+const char QdbMakeDefaultAppStepId[] = "Qdb.MakeDefaultAppStep";
+
const Core::Id QdbHardwareDevicePrefix = "QdbHardwareDevice";
const char AppcontrollerFilepath[] = "/usr/bin/appcontroller";
diff --git a/src/plugins/boot2qt/qdbdeployconfigurationfactory.cpp b/src/plugins/boot2qt/qdbdeployconfigurationfactory.cpp
index 7e973d86e1..a8b86a87ff 100644
--- a/src/plugins/boot2qt/qdbdeployconfigurationfactory.cpp
+++ b/src/plugins/boot2qt/qdbdeployconfigurationfactory.cpp
@@ -26,20 +26,15 @@
#include "qdbdeployconfigurationfactory.h"
#include "qdbconstants.h"
-#include "qdbstopapplicationstep.h"
#include <projectexplorer/deploymentdataview.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/project.h>
#include <projectexplorer/target.h>
-#include <remotelinux/genericdirectuploadstep.h>
-#include <remotelinux/makeinstallstep.h>
-#include <remotelinux/remotelinuxcheckforfreediskspacestep.h>
-#include <remotelinux/remotelinuxdeployconfiguration.h>
+#include <remotelinux/remotelinux_constants.h>
using namespace ProjectExplorer;
-using namespace RemoteLinux;
namespace Qdb {
namespace Internal {
@@ -52,14 +47,14 @@ QdbDeployConfigurationFactory::QdbDeployConfigurationFactory()
"Deploy to Boot2Qt target"));
setUseDeploymentDataView();
- addInitialStep(RemoteLinux::MakeInstallStep::stepId(), [](Target *target) {
+ addInitialStep(RemoteLinux::Constants::MakeInstallStepId, [](Target *target) {
const Project * const prj = target->project();
return prj->deploymentKnowledge() == DeploymentKnowledge::Bad
&& prj->hasMakeInstallEquivalent();
});
- addInitialStep(RemoteLinuxCheckForFreeDiskSpaceStep::stepId());
- addInitialStep(QdbStopApplicationStep::stepId());
- addInitialStep(GenericDirectUploadStep::stepId());
+ addInitialStep(RemoteLinux::Constants::CheckForFreeDiskSpaceId);
+ addInitialStep(Qdb::Constants::QdbStopApplicationStepId);
+ addInitialStep(RemoteLinux::Constants::DirectUploadStepId);
}
} // namespace Internal
diff --git a/src/plugins/boot2qt/qdbdeployconfigurationfactory.h b/src/plugins/boot2qt/qdbdeployconfigurationfactory.h
index 90fd93f239..0aaa09eb34 100644
--- a/src/plugins/boot2qt/qdbdeployconfigurationfactory.h
+++ b/src/plugins/boot2qt/qdbdeployconfigurationfactory.h
@@ -30,7 +30,7 @@
namespace Qdb {
namespace Internal {
-class QdbDeployConfigurationFactory : public ProjectExplorer::DeployConfigurationFactory
+class QdbDeployConfigurationFactory final : public ProjectExplorer::DeployConfigurationFactory
{
public:
QdbDeployConfigurationFactory();
diff --git a/src/plugins/boot2qt/qdbmakedefaultappstep.cpp b/src/plugins/boot2qt/qdbmakedefaultappstep.cpp
index 917cbf1f41..8cb4ab2bdf 100644
--- a/src/plugins/boot2qt/qdbmakedefaultappstep.cpp
+++ b/src/plugins/boot2qt/qdbmakedefaultappstep.cpp
@@ -25,15 +25,28 @@
#include "qdbmakedefaultappstep.h"
+#include "qdbconstants.h"
#include "qdbmakedefaultappservice.h"
#include <projectexplorer/runconfigurationaspects.h>
+#include <remotelinux/abstractremotelinuxdeploystep.h>
+
using namespace ProjectExplorer;
namespace Qdb {
namespace Internal {
+class QdbMakeDefaultAppStep final : public RemoteLinux::AbstractRemoteLinuxDeployStep
+{
+ Q_DECLARE_TR_FUNCTIONS(Qdb::Internal::QdbMakeDefaultAppStep)
+
+public:
+ QdbMakeDefaultAppStep(BuildStepList *bsl, Core::Id id);
+
+ static QString stepDisplayName() { return tr("Change default application"); }
+};
+
QdbMakeDefaultAppStep::QdbMakeDefaultAppStep(BuildStepList *bsl, Core::Id id)
: AbstractRemoteLinuxDeployStep(bsl, id)
{
@@ -52,14 +65,14 @@ QdbMakeDefaultAppStep::QdbMakeDefaultAppStep(BuildStepList *bsl, Core::Id id)
});
}
-Core::Id QdbMakeDefaultAppStep::stepId()
-{
- return "Qdb.MakeDefaultAppStep";
-}
+// QdbMakeDefaultAppStepFactory
-QString QdbMakeDefaultAppStep::stepDisplayName()
+QdbMakeDefaultAppStepFactory::QdbMakeDefaultAppStepFactory()
{
- return QStringLiteral("Change default application");
+ registerStep<QdbMakeDefaultAppStep>(Constants::QdbMakeDefaultAppStepId);
+ setDisplayName(QdbMakeDefaultAppStep::stepDisplayName());
+ setSupportedDeviceType(Qdb::Constants::QdbLinuxOsType);
+ setSupportedStepList(ProjectExplorer::Constants::BUILDSTEPS_DEPLOY);
}
} // namespace Internal
diff --git a/src/plugins/boot2qt/qdbmakedefaultappstep.h b/src/plugins/boot2qt/qdbmakedefaultappstep.h
index 59c3c14afc..7f24bd2919 100644
--- a/src/plugins/boot2qt/qdbmakedefaultappstep.h
+++ b/src/plugins/boot2qt/qdbmakedefaultappstep.h
@@ -25,20 +25,15 @@
#pragma once
-#include <remotelinux/abstractremotelinuxdeploystep.h>
+#include <projectexplorer/buildstep.h>
namespace Qdb {
namespace Internal {
-class QdbMakeDefaultAppStep : public RemoteLinux::AbstractRemoteLinuxDeployStep
+class QdbMakeDefaultAppStepFactory final : public ProjectExplorer::BuildStepFactory
{
- Q_OBJECT
-
public:
- QdbMakeDefaultAppStep(ProjectExplorer::BuildStepList *bsl, Core::Id id);
-
- static Core::Id stepId();
- static QString stepDisplayName();
+ QdbMakeDefaultAppStepFactory();
};
} // namespace Internal
diff --git a/src/plugins/boot2qt/qdbplugin.cpp b/src/plugins/boot2qt/qdbplugin.cpp
index cad10b8ce0..cf6f67ebbd 100644
--- a/src/plugins/boot2qt/qdbplugin.cpp
+++ b/src/plugins/boot2qt/qdbplugin.cpp
@@ -27,7 +27,8 @@
#include "device-detection/devicedetector.h"
#include "qdbdeployconfigurationfactory.h"
-#include "qdbdeploystepfactory.h"
+#include "qdbstopapplicationstep.h"
+#include "qdbmakedefaultappstep.h"
#include "qdbdevicedebugsupport.h"
#include "qdbqtversion.h"
#include "qdbrunconfiguration.h"
@@ -44,9 +45,10 @@
#include <qtsupport/qtversionfactory.h>
-#include <remotelinux/remotelinuxcheckforfreediskspacestep.h>
#include <remotelinux/genericdirectuploadstep.h>
#include <remotelinux/makeinstallstep.h>
+#include <remotelinux/remotelinuxcheckforfreediskspacestep.h>
+#include <remotelinux/remotelinux_constants.h>
#include <utils/hostosinfo.h>
#include <utils/fileutils.h>
@@ -153,9 +155,9 @@ template <class Step>
class QdbDeployStepFactory : public ProjectExplorer::BuildStepFactory
{
public:
- QdbDeployStepFactory()
+ explicit QdbDeployStepFactory(Core::Id id)
{
- registerStep<Step>(Step::stepId());
+ registerStep<Step>(id);
setDisplayName(Step::displayName());
setSupportedConfiguration(Constants::QdbDeployConfigurationId);
setSupportedStepList(ProjectExplorer::Constants::BUILDSTEPS_DEPLOY);
@@ -175,9 +177,11 @@ public:
QdbMakeDefaultAppStepFactory m_makeDefaultAppStepFactory;
QdbDeployStepFactory<RemoteLinux::RemoteLinuxCheckForFreeDiskSpaceStep>
- m_checkForFreeDiskSpaceStepFactory;
- QdbDeployStepFactory<RemoteLinux::GenericDirectUploadStep> m_directUploadStepFactory;
- QdbDeployStepFactory<RemoteLinux::MakeInstallStep> m_makeInstallStepFactory;
+ m_checkForFreeDiskSpaceStepFactory{RemoteLinux::Constants::CheckForFreeDiskSpaceId};
+ QdbDeployStepFactory<RemoteLinux::GenericDirectUploadStep>
+ m_directUploadStepFactory{RemoteLinux::Constants::DirectUploadStepId};
+ QdbDeployStepFactory<RemoteLinux::MakeInstallStep>
+ m_makeInstallStepFactory{RemoteLinux::Constants::MakeInstallStepId};
const QList<Core::Id> supportedRunConfigs {
m_runConfigFactory.id(),
diff --git a/src/plugins/boot2qt/qdbstopapplicationstep.cpp b/src/plugins/boot2qt/qdbstopapplicationstep.cpp
index 240d2b8bab..a6a329666e 100644
--- a/src/plugins/boot2qt/qdbstopapplicationstep.cpp
+++ b/src/plugins/boot2qt/qdbstopapplicationstep.cpp
@@ -25,12 +25,29 @@
#include "qdbstopapplicationstep.h"
+#include "qdbconstants.h"
#include "qdbstopapplicationservice.h"
+#include <projectexplorer/projectexplorerconstants.h>
+
+#include <remotelinux/abstractremotelinuxdeploystep.h>
+
+using namespace ProjectExplorer;
+
namespace Qdb {
namespace Internal {
-QdbStopApplicationStep::QdbStopApplicationStep(ProjectExplorer::BuildStepList *bsl, Core::Id id)
+class QdbStopApplicationStep final : public RemoteLinux::AbstractRemoteLinuxDeployStep
+{
+ Q_DECLARE_TR_FUNCTIONS(Qdb::Internal::QdbStopApplicationStep)
+
+public:
+ QdbStopApplicationStep(BuildStepList *bsl, Core::Id id);
+
+ static QString stepDisplayName() { return tr("Stop already running application"); }
+};
+
+QdbStopApplicationStep::QdbStopApplicationStep(BuildStepList *bsl, Core::Id id)
: AbstractRemoteLinuxDeployStep(bsl, id)
{
auto service = createDeployService<QdbStopApplicationService>();
@@ -41,14 +58,14 @@ QdbStopApplicationStep::QdbStopApplicationStep(ProjectExplorer::BuildStepList *b
setInternalInitializer([service] { return service->isDeploymentPossible(); });
}
-Core::Id QdbStopApplicationStep::stepId()
-{
- return "Qdb.StopApplicationStep";
-}
+// QdbStopApplicationStepFactory
-QString QdbStopApplicationStep::stepDisplayName()
+QdbStopApplicationStepFactory::QdbStopApplicationStepFactory()
{
- return tr("Stop already running application");
+ registerStep<QdbStopApplicationStep>(Constants::QdbStopApplicationStepId);
+ setDisplayName(QdbStopApplicationStep::stepDisplayName());
+ setSupportedDeviceType(Constants::QdbLinuxOsType);
+ setSupportedStepList(ProjectExplorer::Constants::BUILDSTEPS_DEPLOY);
}
} // namespace Internal
diff --git a/src/plugins/boot2qt/qdbstopapplicationstep.h b/src/plugins/boot2qt/qdbstopapplicationstep.h
index a5e3418396..7115cf4c29 100644
--- a/src/plugins/boot2qt/qdbstopapplicationstep.h
+++ b/src/plugins/boot2qt/qdbstopapplicationstep.h
@@ -25,19 +25,15 @@
#pragma once
-#include <remotelinux/abstractremotelinuxdeploystep.h>
+#include <projectexplorer/buildstep.h>
namespace Qdb {
namespace Internal {
-class QdbStopApplicationStep : public RemoteLinux::AbstractRemoteLinuxDeployStep
+class QdbStopApplicationStepFactory final : public ProjectExplorer::BuildStepFactory
{
- Q_OBJECT
public:
- QdbStopApplicationStep(ProjectExplorer::BuildStepList *bsl, Core::Id id);
-
- static Core::Id stepId();
- static QString stepDisplayName();
+ QdbStopApplicationStepFactory();
};
} // namespace Internal
diff --git a/src/plugins/clangcodemodel/clangbackendcommunicator.cpp b/src/plugins/clangcodemodel/clangbackendcommunicator.cpp
index c411e0cfdf..180ffee119 100644
--- a/src/plugins/clangcodemodel/clangbackendcommunicator.cpp
+++ b/src/plugins/clangcodemodel/clangbackendcommunicator.cpp
@@ -513,5 +513,10 @@ void BackendCommunicator::requestCompletions(ClangCompletionAssistProcessor *ass
m_receiver.addExpectedCompletionsMessage(message.ticketNumber, assistProcessor);
}
+void BackendCommunicator::cancelCompletions(TextEditor::IAssistProcessor *processor)
+{
+ m_receiver.cancelProcessor(processor);
+}
+
} // namespace Internal
} // namespace ClangCodeModel
diff --git a/src/plugins/clangcodemodel/clangbackendcommunicator.h b/src/plugins/clangcodemodel/clangbackendcommunicator.h
index 81f151581d..af9b0b69b5 100644
--- a/src/plugins/clangcodemodel/clangbackendcommunicator.h
+++ b/src/plugins/clangcodemodel/clangbackendcommunicator.h
@@ -43,6 +43,8 @@ class IEditor;
class IDocument;
}
+namespace TextEditor { class IAssistProcessor; }
+
namespace ClangCodeModel {
namespace Internal {
@@ -88,6 +90,7 @@ public:
quint32 column,
qint32 funcNameStartLine = -1,
qint32 funcNameStartColumn = -1);
+ void cancelCompletions(TextEditor::IAssistProcessor *processor);
void requestAnnotations(const ClangBackEnd::FileContainer &fileContainer);
QFuture<CppTools::CursorInfo> requestReferences(
const FileContainer &fileContainer,
diff --git a/src/plugins/clangcodemodel/clangbackendreceiver.cpp b/src/plugins/clangcodemodel/clangbackendreceiver.cpp
index 39edf46c44..47d624a147 100644
--- a/src/plugins/clangcodemodel/clangbackendreceiver.cpp
+++ b/src/plugins/clangcodemodel/clangbackendreceiver.cpp
@@ -84,6 +84,18 @@ void BackendReceiver::addExpectedCompletionsMessage(
m_assistProcessorsTable.insert(ticket, processor);
}
+void BackendReceiver::cancelProcessor(TextEditor::IAssistProcessor *processor)
+{
+ for (auto it = m_assistProcessorsTable.cbegin(), end = m_assistProcessorsTable.cend();
+ it != end; ++it)
+ {
+ if (it.value() == processor) {
+ m_assistProcessorsTable.erase(it);
+ return;
+ }
+ }
+}
+
void BackendReceiver::deleteProcessorsOfEditorWidget(TextEditor::TextEditorWidget *textEditorWidget)
{
QList<quint64> toRemove;
@@ -190,8 +202,7 @@ void BackendReceiver::completions(const CompletionsMessage &message)
<< "items";
const quint64 ticket = message.ticketNumber;
- QScopedPointer<ClangCompletionAssistProcessor> processor(m_assistProcessorsTable.take(ticket));
- if (processor)
+ if (ClangCompletionAssistProcessor *processor = m_assistProcessorsTable.take(ticket))
processor->handleAvailableCompletions(message.codeCompletions);
}
@@ -328,7 +339,7 @@ static CppTools::ToolTipInfo toToolTipInfo(const ToolTipMessage &message)
info.qDocIdCandidates = toStringList(backendInfo.qdocIdCandidates);
info.qDocMark = backendInfo.qdocMark;
info.qDocCategory = toHelpItemCategory(backendInfo.qdocCategory);
-
+ info.value = backendInfo.value;
info.sizeInBytes = backendInfo.sizeInBytes;
return info;
diff --git a/src/plugins/clangcodemodel/clangbackendreceiver.h b/src/plugins/clangcodemodel/clangbackendreceiver.h
index 091b582b46..95e6f9b216 100644
--- a/src/plugins/clangcodemodel/clangbackendreceiver.h
+++ b/src/plugins/clangcodemodel/clangbackendreceiver.h
@@ -35,7 +35,10 @@
#include <QPointer>
#include <QTextDocument>
-namespace TextEditor { class TextEditorWidget; }
+namespace TextEditor {
+class IAssistProcessor;
+class TextEditorWidget;
+} // namespace TextEditor
namespace ClangCodeModel {
namespace Internal {
@@ -52,6 +55,7 @@ public:
void setAliveHandler(const AliveHandler &handler);
void addExpectedCompletionsMessage(quint64 ticket, ClangCompletionAssistProcessor *processor);
+ void cancelProcessor(TextEditor::IAssistProcessor *processor);
void deleteProcessorsOfEditorWidget(TextEditor::TextEditorWidget *textEditorWidget);
QFuture<CppTools::CursorInfo>
diff --git a/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp b/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp
index 592f7c8795..0c8e87648f 100644
--- a/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp
+++ b/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp
@@ -697,6 +697,10 @@ IAssistProposal *ClangCompletionAssistProcessor::createFunctionHintProposal(
return new FunctionHintProposal(m_positionForProposal, model);
}
+void ClangCompletionAssistProcessor::cancel()
+{
+ m_interface->communicator().cancelCompletions(this);
+}
+
} // namespace Internal
} // namespace ClangCodeModel
-
diff --git a/src/plugins/clangcodemodel/clangcompletionassistprocessor.h b/src/plugins/clangcodemodel/clangcompletionassistprocessor.h
index 5e8c772235..e3ed93a2cf 100644
--- a/src/plugins/clangcodemodel/clangcompletionassistprocessor.h
+++ b/src/plugins/clangcodemodel/clangcompletionassistprocessor.h
@@ -56,6 +56,7 @@ public:
const TextEditor::TextEditorWidget *textEditorWidget() const;
private:
+ void cancel() override;
TextEditor::IAssistProposal *startCompletionHelper();
int startOfOperator(int pos, unsigned *kind, bool wantFunctionCall) const;
int findStartOfName(int pos = -1) const;
diff --git a/src/plugins/clangcodemodel/clanghoverhandler.cpp b/src/plugins/clangcodemodel/clanghoverhandler.cpp
index ddd2940522..ff106ed16e 100644
--- a/src/plugins/clangcodemodel/clanghoverhandler.cpp
+++ b/src/plugins/clangcodemodel/clanghoverhandler.cpp
@@ -181,6 +181,22 @@ void ClangHoverHandler::processToolTipInfo(const CppTools::ToolTipInfo &info)
if (!info.sizeInBytes.isEmpty())
text.append("\n\n" + tr("%1 bytes").arg(info.sizeInBytes));
+ if (info.value.isValid()) {
+ text.append("\n\n" + tr("Value: "));
+ switch (info.value.type()) {
+ case static_cast<QVariant::Type>(QMetaType::LongLong):
+ text.append(QString::number(info.value.toLongLong()));
+ break;
+ case static_cast<QVariant::Type>(QMetaType::ULongLong):
+ text.append(QString::number(info.value.toULongLong()));
+ break;
+ case static_cast<QVariant::Type>(QMetaType::Double):
+ text.append(QString::number(info.value.toDouble()));
+ break;
+ default:
+ QTC_CHECK(false);
+ }
+ }
setToolTip(text);
m_reportPriority(priority());
diff --git a/src/plugins/clangcodemodel/clangutils.cpp b/src/plugins/clangcodemodel/clangutils.cpp
index 2734f23255..d2905e4834 100644
--- a/src/plugins/clangcodemodel/clangutils.cpp
+++ b/src/plugins/clangcodemodel/clangutils.cpp
@@ -60,6 +60,7 @@ using namespace ClangCodeModel;
using namespace ClangCodeModel::Internal;
using namespace Core;
using namespace CppTools;
+using namespace ProjectExplorer;
namespace ClangCodeModel {
namespace Utils {
@@ -303,12 +304,11 @@ QString diagnosticCategoryPrefixRemoved(const QString &text)
static ::Utils::FilePath compilerPath(const CppTools::ProjectPart &projectPart)
{
- ProjectExplorer::Target *target = projectPart.project->activeTarget();
+ Target *target = projectPart.project->activeTarget();
if (!target)
return ::Utils::FilePath();
- ProjectExplorer::ToolChain *toolchain = ProjectExplorer::ToolChainKitAspect::toolChain(
- target->kit(), ProjectExplorer::Constants::CXX_LANGUAGE_ID);
+ ToolChain *toolchain = ToolChainKitAspect::cxxToolChain(target->kit());
return toolchain->compilerCommand();
}
diff --git a/src/plugins/clangformat/clangformatplugin.cpp b/src/plugins/clangformat/clangformatplugin.cpp
index 561b7e888e..2ebef54584 100644
--- a/src/plugins/clangformat/clangformatplugin.cpp
+++ b/src/plugins/clangformat/clangformatplugin.cpp
@@ -153,10 +153,12 @@ bool ClangFormatPlugin::initialize(const QStringList &arguments, QString *errorS
}
return true;
#else
+#ifndef Q_CC_MSVC
#warning ClangFormat: building dummy plugin due to unmodified Clang, see README.md for more info
- *errorString = "Disabling ClangFormat plugin as it has not been built against a modified Clang's libFormat."
+#endif
+ *errorString = QStringLiteral("Disabling ClangFormat plugin as it has not been built against a modified Clang's libFormat."
"For more information see the Qt Creator README at "
- "https://code.qt.io/cgit/qt-creator/qt-creator.git/tree/README.md";
+ "https://code.qt.io/cgit/qt-creator/qt-creator.git/tree/README.md");
return false;
#endif
}
diff --git a/src/plugins/clangrefactoring/refactoringengine.cpp b/src/plugins/clangrefactoring/refactoringengine.cpp
index 6b5546cc88..1b6c81538d 100644
--- a/src/plugins/clangrefactoring/refactoringengine.cpp
+++ b/src/plugins/clangrefactoring/refactoringengine.cpp
@@ -56,6 +56,7 @@ RefactoringEngine::RefactoringEngine(ClangBackEnd::RefactoringServerInterface &s
m_filePathCache(filePathCache),
m_symbolQuery(symbolQuery)
{
+ Q_UNUSED(m_client)
}
RefactoringEngine::~RefactoringEngine() = default;
diff --git a/src/plugins/clangtools/clangselectablefilesdialog.cpp b/src/plugins/clangtools/clangselectablefilesdialog.cpp
index f879e5099d..6fa105e896 100644
--- a/src/plugins/clangtools/clangselectablefilesdialog.cpp
+++ b/src/plugins/clangtools/clangselectablefilesdialog.cpp
@@ -264,30 +264,6 @@ private:
}
};
-class FileFilterModel : public QSortFilterProxyModel
-{
- Q_OBJECT
-
-public:
- FileFilterModel(QObject *parent = nullptr)
- : QSortFilterProxyModel(parent)
- {}
-
-private:
- bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override
- {
- QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
- const int rowCount = sourceModel()->rowCount(index);
- if (rowCount == 0) // No children -> file node!
- return sourceModel()->data(index).toString().contains(filterRegExp());
- for (int row = 0; row < rowCount; ++row) {
- if (filterAcceptsRow(row, index))
- return true;
- }
- return false;
- }
-};
-
SelectableFilesDialog::SelectableFilesDialog(const ProjectInfo &projectInfo,
const FileInfoProviders &fileInfoProviders,
int initialProviderIndex)
diff --git a/src/plugins/clangtools/clangtidyclazyrunner.cpp b/src/plugins/clangtools/clangtidyclazyrunner.cpp
index 166d1c94e0..5bab62b474 100644
--- a/src/plugins/clangtools/clangtidyclazyrunner.cpp
+++ b/src/plugins/clangtools/clangtidyclazyrunner.cpp
@@ -53,28 +53,6 @@ static bool isClMode(const QStringList &options)
return options.contains("--driver-mode=cl");
}
-static QStringList serializeDiagnosticsArguments(const QStringList &baseOptions,
- const QString &outputFilePath)
-{
- const QStringList serializeArgs{"-serialize-diagnostics", outputFilePath};
- if (isClMode(baseOptions))
- return clangArgsForCl(serializeArgs);
- return serializeArgs;
-}
-
-static QStringList clazyPluginArguments(const ClangDiagnosticConfig diagnosticConfig)
-{
- QStringList arguments;
-
- if (diagnosticConfig.isClazyEnabled()) {
- arguments << XclangArgs({"-add-plugin", "clazy"});
- if (!diagnosticConfig.clazyChecks().isEmpty())
- arguments << XclangArgs({"-plugin-arg-clazy", diagnosticConfig.clazyChecks()});
- }
-
- return arguments;
-}
-
static QStringList tidyChecksArguments(const ClangDiagnosticConfig diagnosticConfig)
{
const ClangDiagnosticConfig::TidyMode tidyMode = diagnosticConfig.clangTidyMode();
@@ -147,19 +125,5 @@ ClazyStandaloneRunner::ClazyStandaloneRunner(const ClangDiagnosticConfig &config
});
}
-ClazyPluginRunner::ClazyPluginRunner(const ClangDiagnosticConfig &config, QObject *parent)
- : ClangToolRunner(parent)
-{
- setName(tr("Clazy"));
- setOutputFileFormat(OutputFileFormat::Serialized);
- setExecutable(Core::ICore::clangExecutable(CLANG_BINDIR));
- setArgsCreator([this, config](const QStringList &baseOptions) {
- return serializeDiagnosticsArguments(baseOptions, outputFilePath())
- << clazyPluginArguments(config)
- << clangArguments(config, baseOptions)
- << QDir::toNativeSeparators(fileToAnalyze());
- });
-}
-
} // namespace Internal
} // namespace ClangTools
diff --git a/src/plugins/clangtools/clangtidyclazyrunner.h b/src/plugins/clangtools/clangtidyclazyrunner.h
index 72cd7a155c..ec9b940a18 100644
--- a/src/plugins/clangtools/clangtidyclazyrunner.h
+++ b/src/plugins/clangtools/clangtidyclazyrunner.h
@@ -48,13 +48,5 @@ public:
ClazyStandaloneRunner(const CppTools::ClangDiagnosticConfig &config, QObject *parent = nullptr);
};
-class ClazyPluginRunner final : public ClangToolRunner
-{
- Q_OBJECT
-
-public:
- ClazyPluginRunner(const CppTools::ClangDiagnosticConfig &config, QObject *parent = nullptr);
-};
-
} // namespace Internal
} // namespace ClangTools
diff --git a/src/plugins/clangtools/clangtool.cpp b/src/plugins/clangtools/clangtool.cpp
index 0928e40e6b..d96bdfd40f 100644
--- a/src/plugins/clangtools/clangtool.cpp
+++ b/src/plugins/clangtools/clangtool.cpp
@@ -573,7 +573,7 @@ ClangTool::ClangTool()
menu->addAction(ActionManager::registerAction(action, "ClangTidyClazy.Action"),
Debugger::Constants::G_ANALYZER_TOOLS);
QObject::connect(action, &QAction::triggered, this, [this]() {
- startTool(FileSelection::AskUser);
+ startTool(FileSelectionType::AskUser);
});
QObject::connect(m_startAction, &QAction::triggered, action, &QAction::triggered);
QObject::connect(m_startAction, &QAction::changed, action, [action, this] {
@@ -581,7 +581,7 @@ ClangTool::ClangTool()
});
QObject::connect(m_startOnCurrentFileAction, &QAction::triggered, this, [this] {
- startTool(FileSelection::CurrentFile);
+ startTool(FileSelectionType::CurrentFile);
});
m_perspective.addToolBarAction(m_startAction);
@@ -647,7 +647,6 @@ static bool continueDespiteReleaseBuild(const QString &toolName)
== QDialogButtonBox::Yes;
}
-
void ClangTool::startTool(ClangTool::FileSelection fileSelection,
const RunSettings &runSettings,
const CppTools::ClangDiagnosticConfig &diagnosticConfig)
@@ -686,7 +685,9 @@ void ClangTool::startTool(ClangTool::FileSelection fileSelection,
connect(m_runControl, &RunControl::stopped, this, &ClangTool::onRunControlStopped);
// Run worker
- const bool preventBuild = fileSelection == FileSelection::CurrentFile;
+ const bool preventBuild = holds_alternative<FilePath>(fileSelection)
+ || get<FileSelectionType>(fileSelection)
+ == FileSelectionType::CurrentFile;
const bool buildBeforeAnalysis = !preventBuild && runSettings.buildBeforeAnalysis();
m_runWorker = new ClangToolRunWorker(m_runControl,
runSettings,
@@ -716,7 +717,6 @@ void ClangTool::startTool(ClangTool::FileSelection fileSelection,
Diagnostics ClangTool::read(OutputFileFormat outputFileFormat,
const QString &logFilePath,
- const QString &mainFilePath,
const QSet<FilePath> &projectFiles,
QString *errorMessage) const
{
@@ -729,23 +729,27 @@ Diagnostics ClangTool::read(OutputFileFormat outputFileFormat,
acceptFromFilePath,
errorMessage);
}
- return readSerializedDiagnostics(Utils::FilePath::fromString(logFilePath),
- Utils::FilePath::fromString(mainFilePath),
- acceptFromFilePath,
- errorMessage);
+
+ return {};
}
FileInfos ClangTool::collectFileInfos(Project *project, FileSelection fileSelection)
{
+ FileSelectionType *selectionType = get_if<FileSelectionType>(&fileSelection);
+ // early bailout
+ if (selectionType && *selectionType == FileSelectionType::CurrentFile
+ && !EditorManager::currentDocument())
+ return {};
+
auto projectInfo = CppTools::CppModelManager::instance()->projectInfo(project);
QTC_ASSERT(projectInfo.isValid(), return FileInfos());
const FileInfos allFileInfos = sortedFileInfos(projectInfo.projectParts());
- if (fileSelection == FileSelection::AllFiles)
+ if (selectionType && *selectionType == FileSelectionType::AllFiles)
return allFileInfos;
- if (fileSelection == FileSelection::AskUser) {
+ if (selectionType && *selectionType == FileSelectionType::AskUser) {
static int initialProviderIndex = 0;
SelectableFilesDialog dialog(projectInfo,
fileInfoProviders(project, allFileInfos),
@@ -756,18 +760,15 @@ FileInfos ClangTool::collectFileInfos(Project *project, FileSelection fileSelect
return dialog.fileInfos();
}
- if (fileSelection == FileSelection::CurrentFile) {
- if (const IDocument *document = EditorManager::currentDocument()) {
- const Utils::FilePath filePath = document->filePath();
- if (!filePath.isEmpty()) {
- const FileInfo fileInfo = Utils::findOrDefault(allFileInfos,
- [&](const FileInfo &fi) {
- return fi.file == filePath;
- });
- if (!fileInfo.file.isEmpty())
- return {fileInfo};
- }
- }
+ const FilePath filePath = holds_alternative<FilePath>(fileSelection)
+ ? get<FilePath>(fileSelection)
+ : EditorManager::currentDocument()->filePath(); // see early bailout
+ if (!filePath.isEmpty()) {
+ const FileInfo fileInfo = Utils::findOrDefault(allFileInfos, [&](const FileInfo &fi) {
+ return fi.file == filePath;
+ });
+ if (!fileInfo.file.isEmpty())
+ return {fileInfo};
}
return {};
@@ -875,7 +876,7 @@ static bool canAnalyzeProject(Project *project)
|| project->projectLanguages().contains(cxx);
return projectSupportsLanguage
&& CppModelManager::instance()->projectInfo(project).isValid()
- && ToolChainKitAspect::toolChain(target->kit(), cxx);
+ && ToolChainKitAspect::cxxToolChain(target->kit());
}
return false;
}
diff --git a/src/plugins/clangtools/clangtool.h b/src/plugins/clangtools/clangtool.h
index a32bb50c2c..7882245e91 100644
--- a/src/plugins/clangtools/clangtool.h
+++ b/src/plugins/clangtools/clangtool.h
@@ -35,6 +35,8 @@
#include <projectexplorer/runconfiguration.h>
#include <cpptools/projectinfo.h>
+#include <utils/variant.h>
+
QT_BEGIN_NAMESPACE
class QFrame;
class QToolButton;
@@ -79,11 +81,14 @@ public:
void selectPerspective();
- enum class FileSelection {
+ enum class FileSelectionType {
AllFiles,
CurrentFile,
AskUser,
};
+
+ using FileSelection = Utils::variant<FileSelectionType, Utils::FilePath>;
+
void startTool(FileSelection fileSelection);
void startTool(FileSelection fileSelection,
const RunSettings &runSettings,
@@ -91,7 +96,6 @@ public:
Diagnostics read(OutputFileFormat outputFileFormat,
const QString &logFilePath,
- const QString &mainFilePath,
const QSet<Utils::FilePath> &projectFiles,
QString *errorMessage) const;
diff --git a/src/plugins/clangtools/clangtoolruncontrol.cpp b/src/plugins/clangtools/clangtoolruncontrol.cpp
index b60e3d0400..5eca0a6515 100644
--- a/src/plugins/clangtools/clangtoolruncontrol.cpp
+++ b/src/plugins/clangtools/clangtoolruncontrol.cpp
@@ -223,8 +223,7 @@ ClangToolRunWorker::ClangToolRunWorker(RunControl *runControl,
QTC_ASSERT(buildConfiguration, return);
m_environment = buildConfiguration->environment();
- ToolChain *toolChain = ToolChainKitAspect::toolChain(target->kit(),
- ProjectExplorer::Constants::CXX_LANGUAGE_ID);
+ ToolChain *toolChain = ToolChainKitAspect::cxxToolChain(target->kit());
QTC_ASSERT(toolChain, return);
m_targetTriple = toolChain->originalTargetTriple();
m_toolChainType = toolChain->typeId();
@@ -237,12 +236,8 @@ QList<RunnerCreator> ClangToolRunWorker::runnerCreators()
if (m_diagnosticConfig.isClangTidyEnabled())
creators << [this]() { return createRunner<ClangTidyRunner>(); };
- if (m_diagnosticConfig.isClazyEnabled()) {
- if (!qEnvironmentVariable("QTC_USE_CLAZY_STANDALONE_PATH").isEmpty())
- creators << [this]() { return createRunner<ClazyStandaloneRunner>(); };
- else
- creators << [this]() { return createRunner<ClazyPluginRunner>(); };
- }
+ if (m_diagnosticConfig.isClazyEnabled())
+ creators << [this]() { return createRunner<ClazyStandaloneRunner>(); };
return creators;
}
@@ -389,7 +384,6 @@ void ClangToolRunWorker::onRunnerFinishedWithSuccess(const QString &filePath)
QString errorMessage;
const Diagnostics diagnostics = tool()->read(runner->outputFileFormat(),
outputFilePath,
- filePath,
m_projectFiles,
&errorMessage);
diff --git a/src/plugins/clangtools/clangtools.pro b/src/plugins/clangtools/clangtools.pro
index 9b1076fbda..7abb6bc53b 100644
--- a/src/plugins/clangtools/clangtools.pro
+++ b/src/plugins/clangtools/clangtools.pro
@@ -4,9 +4,6 @@ include(../../shared/clang/clang_defines.pri)
requires(!isEmpty(LLVM_VERSION))
-LIBS += $$LIBCLANG_LIBS
-INCLUDEPATH += $$LLVM_INCLUDEPATH
-
include(../../shared/yaml-cpp/yaml-cpp_installation.pri)
isEmpty(EXTERNAL_YAML_CPP_FOUND) {
DEFINES += YAML_CPP_DLL
diff --git a/src/plugins/clangtools/clangtools.qbs b/src/plugins/clangtools/clangtools.qbs
index 07ec6201b1..e3d93e34f5 100644
--- a/src/plugins/clangtools/clangtools.qbs
+++ b/src/plugins/clangtools/clangtools.qbs
@@ -12,7 +12,6 @@ QtcPlugin {
Depends { name: "QtcSsh" }
Depends { name: "Utils" }
- Depends { name: "libclang"; required: false }
Depends { name: "yaml-cpp" }
Depends { name: "clang_defines" }
@@ -27,13 +26,6 @@ QtcPlugin {
"QmakeProjectManager",
]
- condition: libclang.present
-
- cpp.includePaths: base.concat(libclang.llvmIncludeDir)
- cpp.libraryPaths: base.concat(libclang.llvmLibDir)
- cpp.dynamicLibraries: base.concat(libclang.llvmLibs)
- cpp.rpaths: base.concat(libclang.llvmLibDir)
-
files: [
"clangfileinfo.h",
"clangfixitsrefactoringchanges.cpp",
diff --git a/src/plugins/clangtools/clangtoolsdiagnosticmodel.cpp b/src/plugins/clangtools/clangtoolsdiagnosticmodel.cpp
index b04db2da3b..fdb113f7e3 100644
--- a/src/plugins/clangtools/clangtoolsdiagnosticmodel.cpp
+++ b/src/plugins/clangtools/clangtoolsdiagnosticmodel.cpp
@@ -32,6 +32,7 @@
#include <coreplugin/fileiconprovider.h>
#include <projectexplorer/project.h>
#include <projectexplorer/session.h>
+#include <texteditor/textmark.h>
#include <utils/qtcassert.h>
#include <utils/utilsicons.h>
@@ -217,7 +218,15 @@ static QString fixitStatus(FixitStatus status)
return QString();
}
-static QString createDiagnosticToolTipString(const Diagnostic &diagnostic, FixitStatus fixItStatus)
+static QString lineColumnString(const Debugger::DiagnosticLocation &location)
+{
+ return QString("%1:%2").arg(QString::number(location.line), QString::number(location.column));
+}
+
+static QString createDiagnosticToolTipString(
+ const Diagnostic &diagnostic,
+ Utils::optional<FixitStatus> fixItStatus = Utils::nullopt,
+ bool showSteps = true)
{
using StringPair = QPair<QString, QString>;
QList<StringPair> lines;
@@ -244,9 +253,24 @@ static QString createDiagnosticToolTipString(const Diagnostic &diagnostic, Fixit
QCoreApplication::translate("ClangTools::Diagnostic", "Location:"),
createFullLocationString(diagnostic.location));
- lines << qMakePair(
- QCoreApplication::translate("ClangTools::Diagnostic", "Fixit status:"),
- fixitStatus(fixItStatus));
+ if (fixItStatus.has_value()) {
+ lines << qMakePair(QCoreApplication::translate("ClangTools::Diagnostic", "Fixit status:"),
+ fixitStatus(fixItStatus.value()));
+ }
+
+ if (showSteps && !diagnostic.explainingSteps.isEmpty()) {
+ StringPair steps;
+ steps.first = QCoreApplication::translate("ClangTools::Diagnostic", "Steps:");
+ for (const ExplainingStep &step : diagnostic.explainingSteps) {
+ if (!steps.second.isEmpty())
+ steps.second += "<br>";
+ steps.second += QString("%1:%2: %3")
+ .arg(step.location.filePath,
+ lineColumnString(step.location),
+ step.message);
+ }
+ lines << steps;
+ }
QString html = QLatin1String("<html>"
"<head>"
@@ -319,11 +343,6 @@ static QString createExplainingStepString(const ExplainingStep &explainingStep,
}
-static QString lineColumnString(const Debugger::DiagnosticLocation &location)
-{
- return QString("%1:%2").arg(QString::number(location.line), QString::number(location.column));
-}
-
static QString fullText(const Diagnostic &diagnostic)
{
QString text = diagnostic.location.filePath + QLatin1Char(':');
@@ -346,6 +365,35 @@ static QString fullText(const Diagnostic &diagnostic)
return text;
}
+static Utils::optional<QIcon> iconForType(const QString &type)
+{
+ if (type == "warning")
+ return Utils::Icons::CODEMODEL_WARNING.icon();
+ if (type == "error" || type == "fatal")
+ return Utils::Icons::CODEMODEL_ERROR.icon();
+ if (type == "note")
+ return Utils::Icons::INFO.icon();
+ if (type == "fix-it")
+ return Utils::Icons::CODEMODEL_FIXIT.icon();
+ return Utils::nullopt;
+}
+
+static TextEditor::TextMark *generateDiagnosticTextMark(const Diagnostic &diag)
+{
+ auto mark = new TextEditor::TextMark(Utils::FilePath::fromString(diag.location.filePath),
+ diag.location.line,
+ Core::Id("ClangTool.DiagnosticMark"));
+ if (diag.type == "error" || diag.type == "fatal")
+ mark->setColor(Utils::Theme::CodeModel_Error_TextMarkColor);
+ else
+ mark->setColor(Utils::Theme::CodeModel_Warning_TextMarkColor);
+ mark->setPriority(TextEditor::TextMark::HighPriority);
+ mark->setIcon(iconForType(diag.type).value_or(Utils::Icons::CODEMODEL_WARNING.icon()));
+ mark->setToolTip(createDiagnosticToolTipString(diag));
+ mark->setLineAnnotation(diag.description);
+ return mark;
+}
+
DiagnosticItem::DiagnosticItem(const Diagnostic &diag,
const OnFixitStatusChanged &onFixitStatusChanged,
ClangToolsDiagnosticModel *parent)
@@ -356,6 +404,8 @@ DiagnosticItem::DiagnosticItem(const Diagnostic &diag,
if (diag.hasFixits)
m_fixitStatus = FixitStatus::NotScheduled;
+ m_mark = generateDiagnosticTextMark(diag);
+
// Don't show explaining steps if they add no information.
if (diag.explainingSteps.count() == 1) {
const ExplainingStep &step = diag.explainingSteps.first();
@@ -373,6 +423,7 @@ DiagnosticItem::DiagnosticItem(const Diagnostic &diag,
DiagnosticItem::~DiagnosticItem()
{
setFixitOperations(ReplacementOperations());
+ delete m_mark;
}
Qt::ItemFlags DiagnosticItem::flags(int column) const
@@ -385,15 +436,8 @@ Qt::ItemFlags DiagnosticItem::flags(int column) const
static QVariant iconData(const QString &type)
{
- if (type == "warning")
- return Utils::Icons::CODEMODEL_WARNING.icon();
- if (type == "error" || type == "fatal")
- return Utils::Icons::CODEMODEL_ERROR.icon();
- if (type == "note")
- return Utils::Icons::INFO.icon();
- if (type == "fix-it")
- return Utils::Icons::CODEMODEL_FIXIT.icon();
- return QVariant();
+ Utils::optional<QIcon> icon = iconForType(type);
+ return icon.has_value() ? QVariant(*icon) : QVariant();
}
QVariant DiagnosticItem::data(int column, int role) const
@@ -439,7 +483,7 @@ QVariant DiagnosticItem::data(int column, int role) const
return QString("%1: %2").arg(lineColumnString(m_diagnostic.location),
m_diagnostic.description);
case Qt::ToolTipRole:
- return createDiagnosticToolTipString(m_diagnostic, m_fixitStatus);
+ return createDiagnosticToolTipString(m_diagnostic, m_fixitStatus, false);
case Qt::DecorationRole:
return iconData(m_diagnostic.type);
default:
@@ -475,6 +519,10 @@ void DiagnosticItem::setFixItStatus(const FixitStatus &status)
update();
if (m_onFixitStatusChanged && status != oldStatus)
m_onFixitStatusChanged(index(), oldStatus, status);
+ if (status == FixitStatus::Applied || status == FixitStatus::Invalidated) {
+ delete m_mark;
+ m_mark = nullptr;
+ }
}
void DiagnosticItem::setFixitOperations(const ReplacementOperations &replacements)
diff --git a/src/plugins/clangtools/clangtoolsdiagnosticmodel.h b/src/plugins/clangtools/clangtoolsdiagnosticmodel.h
index b27e01b383..fe93a6e1ce 100644
--- a/src/plugins/clangtools/clangtoolsdiagnosticmodel.h
+++ b/src/plugins/clangtools/clangtoolsdiagnosticmodel.h
@@ -69,6 +69,8 @@ private:
const QString m_filePath;
};
+class DiagnosticMark;
+
class DiagnosticItem : public Utils::TreeItem
{
public:
@@ -101,6 +103,7 @@ private:
ReplacementOperations m_fixitOperations;
FixitStatus m_fixitStatus = FixitStatus::NotAvailable;
ClangToolsDiagnosticModel *m_parentModel = nullptr;
+ TextEditor::TextMark *m_mark = nullptr;
};
class ExplainingStepItem;
diff --git a/src/plugins/clangtools/clangtoolslogfilereader.cpp b/src/plugins/clangtools/clangtoolslogfilereader.cpp
index fc80a1b829..9acfe6c00e 100644
--- a/src/plugins/clangtools/clangtoolslogfilereader.cpp
+++ b/src/plugins/clangtools/clangtoolslogfilereader.cpp
@@ -27,198 +27,17 @@
#include <cpptools/cppprojectfile.h>
-#include <QDebug>
#include <QDir>
-#include <QFile>
#include <QFileInfo>
-#include <QObject>
-#include <QRegularExpression>
-#include <QXmlStreamReader>
-#include <utils/executeondestruction.h>
#include <utils/fileutils.h>
-#include <utils/hostosinfo.h>
-#include <utils/qtcassert.h>
#include <utils/textutils.h>
-#include <clang-c/Index.h>
-
#include <yaml-cpp/yaml.h>
namespace ClangTools {
namespace Internal {
-static QString fromCXString(CXString &&cxString)
-{
- QString result = QString::fromUtf8(clang_getCString(cxString));
- clang_disposeString(cxString);
- return result;
-}
-
-static Debugger::DiagnosticLocation diagLocationFromSourceLocation(CXSourceLocation cxLocation)
-{
- CXFile file;
- unsigned line;
- unsigned column;
- clang_getSpellingLocation(cxLocation, &file, &line, &column, nullptr);
-
- Debugger::DiagnosticLocation location;
- location.filePath = fromCXString(clang_getFileName(file));
- location.filePath = QDir::cleanPath(location.filePath); // Normalize to find duplicates later
- location.line = line;
- location.column = column;
- return location;
-}
-
-static QString cxDiagnosticType(const CXDiagnostic cxDiagnostic)
-{
- const CXDiagnosticSeverity severity = clang_getDiagnosticSeverity(cxDiagnostic);
- switch (severity) {
- case CXDiagnostic_Note:
- return QString("note");
- case CXDiagnostic_Warning:
- return QString("warning");
- case CXDiagnostic_Error:
- return QString("error");
- case CXDiagnostic_Fatal:
- return QString("fatal");
- case CXDiagnostic_Ignored:
- return QString("ignored");
- }
- return QString("ignored");
-}
-
-static ExplainingStep buildChildDiagnostic(const CXDiagnostic cxDiagnostic)
-{
- ExplainingStep diagnosticStep;
- QString type = cxDiagnosticType(cxDiagnostic);
- if (type == QStringLiteral("ignored"))
- return diagnosticStep;
-
- const CXSourceLocation cxLocation = clang_getDiagnosticLocation(cxDiagnostic);
- diagnosticStep.location = diagLocationFromSourceLocation(cxLocation);
- diagnosticStep.message = fromCXString(clang_getDiagnosticSpelling(cxDiagnostic));
- return diagnosticStep;
-}
-
-static bool isInvalidDiagnosticLocation(const Diagnostic &diagnostic, const ExplainingStep &child,
- const QString &nativeFilePath)
-{
- // When main file is considered included by itself - this diagnostic has invalid location.
- // This case usually happens when original diagnostic comes from system header but
- // has main file name set in the source location instead (which is incorrect).
- return child.message.indexOf(nativeFilePath) >= 0
- && child.message.indexOf("in file included from") >= 0
- && diagnostic.location.filePath == nativeFilePath;
-}
-
-static ExplainingStep buildFixIt(const CXDiagnostic cxDiagnostic, unsigned index)
-{
- ExplainingStep fixItStep;
- CXSourceRange cxFixItRange;
- fixItStep.isFixIt = true;
- fixItStep.message = fromCXString(clang_getDiagnosticFixIt(cxDiagnostic, index, &cxFixItRange));
- fixItStep.location = diagLocationFromSourceLocation(clang_getRangeStart(cxFixItRange));
- fixItStep.ranges.push_back(fixItStep.location);
- fixItStep.ranges.push_back(diagLocationFromSourceLocation(clang_getRangeEnd(cxFixItRange)));
- return fixItStep;
-}
-
-static Diagnostic buildDiagnostic(const CXDiagnostic cxDiagnostic,
- const AcceptDiagsFromFilePath &acceptFromFilePath,
- const QString &nativeFilePath)
-{
- Diagnostic diagnostic;
- diagnostic.type = cxDiagnosticType(cxDiagnostic);
- if (diagnostic.type == QStringLiteral("ignored"))
- return diagnostic;
-
- const CXSourceLocation cxLocation = clang_getDiagnosticLocation(cxDiagnostic);
- if (clang_Location_isInSystemHeader(cxLocation))
- return diagnostic;
-
- diagnostic.location = diagLocationFromSourceLocation(cxLocation);
- const auto diagnosticFilePath = Utils::FilePath::fromString(diagnostic.location.filePath);
- if (acceptFromFilePath && !acceptFromFilePath(diagnosticFilePath))
- return diagnostic;
-
- // TODO: Introduce CppTools::ProjectFile::isGenerated to filter these out properly
- const QString fileName = diagnosticFilePath.fileName();
- if ((fileName.startsWith("ui_") && fileName.endsWith(".h")) || fileName.endsWith(".moc"))
- return diagnostic;
-
- CXDiagnosticSet cxChildDiagnostics = clang_getChildDiagnostics(cxDiagnostic);
- Utils::ExecuteOnDestruction onBuildExit([&]() {
- clang_disposeDiagnosticSet(cxChildDiagnostics);
- });
-
- using CppTools::ProjectFile;
- const bool isHeaderFile = ProjectFile::isHeader(
- ProjectFile::classify(diagnostic.location.filePath));
-
- for (unsigned i = 0; i < clang_getNumDiagnosticsInSet(cxChildDiagnostics); ++i) {
- CXDiagnostic cxDiagnostic = clang_getDiagnosticInSet(cxChildDiagnostics, i);
- Utils::ExecuteOnDestruction cleanUpDiagnostic([&]() {
- clang_disposeDiagnostic(cxDiagnostic);
- });
- const ExplainingStep diagnosticStep = buildChildDiagnostic(cxDiagnostic);
- if (diagnosticStep.isValid())
- continue;
-
- if (isHeaderFile && diagnosticStep.message.contains("in file included from"))
- continue;
-
- if (isInvalidDiagnosticLocation(diagnostic, diagnosticStep, nativeFilePath))
- return diagnostic;
-
- diagnostic.explainingSteps.push_back(diagnosticStep);
- }
-
- const unsigned fixItCount = clang_getDiagnosticNumFixIts(cxDiagnostic);
- diagnostic.hasFixits = fixItCount != 0;
- for (unsigned i = 0; i < fixItCount; ++i)
- diagnostic.explainingSteps.push_back(buildFixIt(cxDiagnostic, i));
-
- diagnostic.description = fromCXString(clang_getDiagnosticSpelling(cxDiagnostic));
- diagnostic.category = fromCXString(clang_getDiagnosticCategoryText(cxDiagnostic));
-
- return diagnostic;
-}
-
-static Diagnostics readSerializedDiagnostics_helper(const Utils::FilePath &logFilePath,
- const Utils::FilePath &mainFilePath,
- const AcceptDiagsFromFilePath &acceptFromFilePath)
-{
- Diagnostics list;
- CXLoadDiag_Error error;
- CXString errorString;
-
- CXDiagnosticSet diagnostics = clang_loadDiagnostics(logFilePath.toString().toStdString().c_str(),
- &error,
- &errorString);
- if (error != CXLoadDiag_None || !diagnostics)
- return list;
-
- Utils::ExecuteOnDestruction onReadExit([&]() {
- clang_disposeDiagnosticSet(diagnostics);
- });
-
- const QString nativeFilePath = QDir::toNativeSeparators(mainFilePath.toString());
- for (unsigned i = 0; i < clang_getNumDiagnosticsInSet(diagnostics); ++i) {
- CXDiagnostic cxDiagnostic = clang_getDiagnosticInSet(diagnostics, i);
- Utils::ExecuteOnDestruction cleanUpDiagnostic([&]() {
- clang_disposeDiagnostic(cxDiagnostic);
- });
- const Diagnostic diagnostic = buildDiagnostic(cxDiagnostic, acceptFromFilePath, nativeFilePath);
- if (!diagnostic.isValid())
- continue;
-
- list.push_back(diagnostic);
- }
-
- return list;
-}
-
static bool checkFilePath(const Utils::FilePath &filePath, QString *errorMessage)
{
QFileInfo fi(filePath.toFileInfo());
@@ -234,17 +53,6 @@ static bool checkFilePath(const Utils::FilePath &filePath, QString *errorMessage
return true;
}
-Diagnostics readSerializedDiagnostics(const Utils::FilePath &logFilePath,
- const Utils::FilePath &mainFilePath,
- const AcceptDiagsFromFilePath &acceptFromFilePath,
- QString *errorMessage)
-{
- if (!checkFilePath(logFilePath, errorMessage))
- return {};
-
- return readSerializedDiagnostics_helper(logFilePath, mainFilePath, acceptFromFilePath);
-}
-
Utils::optional<LineColumnInfo> byteOffsetInUtf8TextToLineColumn(const char *text,
int offset,
int startLine)
diff --git a/src/plugins/clangtools/clangtoolslogfilereader.h b/src/plugins/clangtools/clangtoolslogfilereader.h
index 996f7ffbeb..8d06eb853f 100644
--- a/src/plugins/clangtools/clangtoolslogfilereader.h
+++ b/src/plugins/clangtools/clangtoolslogfilereader.h
@@ -34,16 +34,10 @@ namespace Utils { class FilePath; }
namespace ClangTools {
namespace Internal {
-enum class OutputFileFormat { Serialized, Yaml };
+enum class OutputFileFormat { Yaml };
using AcceptDiagsFromFilePath = std::function<bool(const Utils::FilePath &)>;
-// Reads diagnostics generated by "clang -serialize-diagnostics path/to/file"
-Diagnostics readSerializedDiagnostics(const Utils::FilePath &logFilePath,
- const Utils::FilePath &mainFilePath,
- const AcceptDiagsFromFilePath &acceptFromFilePath,
- QString *errorMessage);
-
// Reads diagnostics generated by "clang-tidy/clazy-standalone -export-fixes=path/to/file"
Diagnostics readExportedDiagnostics(const Utils::FilePath &logFilePath,
const AcceptDiagsFromFilePath &acceptFromFilePath,
diff --git a/src/plugins/clangtools/clangtoolsplugin.cpp b/src/plugins/clangtools/clangtoolsplugin.cpp
index eb1d73663e..242575d5fc 100644
--- a/src/plugins/clangtools/clangtoolsplugin.cpp
+++ b/src/plugins/clangtools/clangtoolsplugin.cpp
@@ -36,18 +36,23 @@
#include "clangtoolsunittests.h"
#endif
+#include <utils/mimetypes/mimedatabase.h>
+#include <utils/mimetypes/mimetype.h>
#include <utils/qtcassert.h>
-#include <coreplugin/icore.h>
-#include <coreplugin/icontext.h>
+#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/command.h>
-#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/coreconstants.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <coreplugin/icontext.h>
+#include <coreplugin/icore.h>
#include <cpptools/cpptoolsconstants.h>
#include <cpptools/cppmodelmanager.h>
+#include <texteditor/texteditor.h>
+
#include <cppeditor/cppeditorconstants.h>
#include <projectexplorer/kitinformation.h>
@@ -57,8 +62,9 @@
#include <QAction>
#include <QDebug>
#include <QMainWindow>
-#include <QMessageBox>
#include <QMenu>
+#include <QMessageBox>
+#include <QToolBar>
using namespace Core;
using namespace ProjectExplorer;
@@ -96,6 +102,20 @@ bool ClangToolsPlugin::initialize(const QStringList &arguments, QString *errorSt
d = new ClangToolsPluginPrivate;
+ registerAnalyzeActions();
+
+ auto panelFactory = m_projectPanelFactoryInstance = new ProjectPanelFactory;
+ panelFactory->setPriority(100);
+ panelFactory->setId(Constants::PROJECT_PANEL_ID);
+ panelFactory->setDisplayName(tr("Clang Tools"));
+ panelFactory->setCreateWidgetFunction([](Project *project) { return new ProjectSettingsWidget(project); });
+ ProjectPanelFactory::registerFactory(panelFactory);
+
+ return true;
+}
+
+void ClangToolsPlugin::registerAnalyzeActions()
+{
ActionManager::registerAction(d->clangTool.startAction(), Constants::RUN_ON_PROJECT);
Command *cmd = ActionManager::registerAction(d->clangTool.startOnCurrentFileAction(),
Constants::RUN_ON_CURRENT_FILE);
@@ -106,16 +126,27 @@ bool ClangToolsPlugin::initialize(const QStringList &arguments, QString *errorSt
Core::ActionContainer *mcontext = Core::ActionManager::actionContainer(
CppEditor::Constants::M_CONTEXT);
if (mcontext)
- mcontext->addAction(cmd, CppEditor::Constants::G_CONTEXT_FIRST); // TODO
-
- auto panelFactory = m_projectPanelFactoryInstance = new ProjectPanelFactory;
- panelFactory->setPriority(100);
- panelFactory->setId(Constants::PROJECT_PANEL_ID);
- panelFactory->setDisplayName(tr("Clang Tools"));
- panelFactory->setCreateWidgetFunction([](Project *project) { return new ProjectSettingsWidget(project); });
- ProjectPanelFactory::registerFactory(panelFactory);
-
- return true;
+ mcontext->addAction(cmd, CppEditor::Constants::G_CONTEXT_FIRST);
+
+ // add button to tool bar of C++ source files
+ connect(EditorManager::instance(), &EditorManager::editorOpened, this, [this, cmd](IEditor *editor) {
+ if (editor->document()->filePath().isEmpty()
+ || !Utils::mimeTypeForName(editor->document()->mimeType()).inherits("text/x-c++src"))
+ return;
+ auto *textEditor = qobject_cast<TextEditor::BaseTextEditor *>(editor);
+ if (!textEditor)
+ return;
+ TextEditor::TextEditorWidget *widget = textEditor->editorWidget();
+ if (!widget)
+ return;
+ const QIcon icon = Utils::Icon({{":/debugger/images/debugger_singleinstructionmode.png",
+ Utils::Theme::IconsBaseColor}})
+ .icon();
+ QAction *action = widget->toolBar()->addAction(icon, tr("Analyze File"), [this, editor]() {
+ d->clangTool.startTool(editor->document()->filePath());
+ });
+ cmd->augmentActionWithShortcutToolTip(action);
+ });
}
QVector<QObject *> ClangToolsPlugin::createTestObjects() const
diff --git a/src/plugins/clangtools/clangtoolsplugin.h b/src/plugins/clangtools/clangtoolsplugin.h
index 45dffbd191..aaf1711fd6 100644
--- a/src/plugins/clangtools/clangtoolsplugin.h
+++ b/src/plugins/clangtools/clangtoolsplugin.h
@@ -45,6 +45,8 @@ public:
private:
bool initialize(const QStringList &arguments, QString *errorString) final;
+ void registerAnalyzeActions();
+
QVector<QObject *> createTestObjects() const final;
class ClangToolsPluginPrivate *d = nullptr;
diff --git a/src/plugins/clangtools/clangtoolspreconfiguredsessiontests.cpp b/src/plugins/clangtools/clangtoolspreconfiguredsessiontests.cpp
index 2ed19354f2..cdabae308f 100644
--- a/src/plugins/clangtools/clangtoolspreconfiguredsessiontests.cpp
+++ b/src/plugins/clangtools/clangtoolspreconfiguredsessiontests.cpp
@@ -121,7 +121,7 @@ void PreconfiguredSessionTests::testPreconfiguredSession()
QVERIFY(switchToProjectAndTarget(project, target));
- ClangTool::instance()->startTool(ClangTool::FileSelection::AllFiles);
+ ClangTool::instance()->startTool(ClangTool::FileSelectionType::AllFiles);
QSignalSpy waitUntilAnalyzerFinished(ClangTool::instance(), SIGNAL(finished(bool)));
QVERIFY(waitUntilAnalyzerFinished.wait(30000));
const QList<QVariant> arguments = waitUntilAnalyzerFinished.takeFirst();
@@ -166,7 +166,7 @@ static QList<Target *> validTargets(Project *project)
return false;
}
- const ToolChain * const toolchain = ToolChainKitAspect::toolChain(kit, ProjectExplorer::Constants::CXX_LANGUAGE_ID);
+ const ToolChain * const toolchain = ToolChainKitAspect::cxxToolChain(kit);
QTC_ASSERT(toolchain, return false);
if (Core::ICore::clangExecutable(CLANG_BINDIR).isEmpty()) {
diff --git a/src/plugins/clangtools/clangtoolsunittests.cpp b/src/plugins/clangtools/clangtoolsunittests.cpp
index fdd9240e0d..e9df151476 100644
--- a/src/plugins/clangtools/clangtoolsunittests.cpp
+++ b/src/plugins/clangtools/clangtoolsunittests.cpp
@@ -62,8 +62,7 @@ void ClangToolsUnitTests::initTestCase()
const QList<Kit *> allKits = KitManager::kits();
if (allKits.count() != 1)
QSKIP("This test requires exactly one kit to be present");
- const ToolChain *const toolchain = ToolChainKitAspect::toolChain(allKits.first(),
- Constants::CXX_LANGUAGE_ID);
+ const ToolChain *const toolchain = ToolChainKitAspect::cxxToolChain(allKits.first());
if (!toolchain)
QSKIP("This test requires that there is a kit with a toolchain.");
@@ -100,9 +99,7 @@ void ClangToolsUnitTests::testProject()
QFETCH(int, expectedDiagCount);
QFETCH(ClangDiagnosticConfig, diagnosticConfig);
if (projectFilePath.contains("mingw")) {
- const ToolChain *const toolchain
- = ToolChainKitAspect::toolChain(KitManager::kits().constFirst(),
- Constants::CXX_LANGUAGE_ID);
+ const auto toolchain = ToolChainKitAspect::cxxToolChain(KitManager::kits().constFirst());
if (toolchain->typeId() != ProjectExplorer::Constants::MINGW_TOOLCHAIN_TYPEID)
QSKIP("This test is mingw specific, does not run for other toolchains");
}
@@ -115,7 +112,7 @@ void ClangToolsUnitTests::testProject()
// Run tool
ClangTool *tool = ClangTool::instance();
- tool->startTool(ClangTool::FileSelection::AllFiles,
+ tool->startTool(ClangTool::FileSelectionType::AllFiles,
ClangToolsSettings::instance()->runSettings(),
diagnosticConfig);
QSignalSpy waitForFinishedTool(tool, &ClangTool::finished);
diff --git a/src/plugins/clangtools/clangtoolsutils.cpp b/src/plugins/clangtools/clangtoolsutils.cpp
index 7fbcc35889..661a2165d0 100644
--- a/src/plugins/clangtools/clangtoolsutils.cpp
+++ b/src/plugins/clangtools/clangtoolsutils.cpp
@@ -153,7 +153,6 @@ QString clazyStandaloneFallbackExecutable()
{
return findValidExecutable({
shippedClazyStandaloneExecutable(),
- qEnvironmentVariable("QTC_USE_CLAZY_STANDALONE_PATH"),
Constants::CLAZY_STANDALONE_EXECUTABLE_NAME,
});
}
diff --git a/src/plugins/clangtools/settingswidget.cpp b/src/plugins/clangtools/settingswidget.cpp
index 9b41ce631b..b2ef284641 100644
--- a/src/plugins/clangtools/settingswidget.cpp
+++ b/src/plugins/clangtools/settingswidget.cpp
@@ -54,7 +54,7 @@ static void setupPathChooser(Utils::PathChooser *const chooser,
chooser->setExpectedKind(Utils::PathChooser::ExistingCommand);
chooser->setHistoryCompleter(historyCompleterId);
chooser->setValidationFunction([chooser](Utils::FancyLineEdit *edit, QString *errorMessage) {
- const QString currentFilePath = chooser->fileName().toString();
+ const QString currentFilePath = chooser->filePath().toString();
Utils::PathChooser pc;
Utils::PathChooser *helperPathChooser;
if (currentFilePath.isEmpty()) {
@@ -95,20 +95,15 @@ SettingsWidget::SettingsWidget()
path,
"ClangTools.ClangTidyExecutable.History");
- if (qEnvironmentVariable("QTC_USE_CLAZY_STANDALONE_PATH").isEmpty()) {
- m_ui->clazyStandalonePathChooser->setVisible(false);
- m_ui->clazyStandaloneLabel->setVisible(false);
- } else {
- placeHolderText = shippedClazyStandaloneExecutable();
- path = m_settings->clazyStandaloneExecutable();
- if (path.isEmpty() && placeHolderText.isEmpty())
- path = Constants::CLAZY_STANDALONE_EXECUTABLE_NAME;
- setupPathChooser(m_ui->clazyStandalonePathChooser,
- tr("Clazy Executable"),
- placeHolderText,
- path,
- "ClangTools.ClazyStandaloneExecutable.History");
- }
+ placeHolderText = shippedClazyStandaloneExecutable();
+ path = m_settings->clazyStandaloneExecutable();
+ if (path.isEmpty() && placeHolderText.isEmpty())
+ path = Constants::CLAZY_STANDALONE_EXECUTABLE_NAME;
+ setupPathChooser(m_ui->clazyStandalonePathChooser,
+ tr("Clazy Executable"),
+ placeHolderText,
+ path,
+ "ClangTools.ClazyStandaloneExecutable.History");
//
// Group box "Run Options"
diff --git a/src/plugins/cmakeprojectmanager/CMakeLists.txt b/src/plugins/cmakeprojectmanager/CMakeLists.txt
index 0b2955646f..14a17e17b1 100644
--- a/src/plugins/cmakeprojectmanager/CMakeLists.txt
+++ b/src/plugins/cmakeprojectmanager/CMakeLists.txt
@@ -3,9 +3,7 @@ add_qtc_plugin(CMakeProjectManager
PLUGIN_DEPENDS Core CppTools ProjectExplorer TextEditor QtSupport
PLUGIN_RECOMMENDS Designer
SOURCES
- builddirmanager.cpp builddirmanager.h
builddirparameters.cpp builddirparameters.h
- builddirreader.cpp builddirreader.h
cmake_global.h
cmakeautocompleter.cpp cmakeautocompleter.h
cmakebuildconfiguration.cpp cmakebuildconfiguration.h
@@ -13,7 +11,6 @@ add_qtc_plugin(CMakeProjectManager
cmakebuildsystem.cpp cmakebuildsystem.h
cmakebuildstep.cpp cmakebuildstep.h
cmakebuildtarget.h
- cmakecbpparser.cpp cmakecbpparser.h
cmakeconfigitem.cpp cmakeconfigitem.h
cmakeeditor.cpp cmakeeditor.h
cmakefilecompletionassist.cpp cmakefilecompletionassist.h
@@ -41,7 +38,4 @@ add_qtc_plugin(CMakeProjectManager
fileapiparser.cpp fileapiparser.h
fileapireader.cpp fileapireader.h
projecttreehelper.cpp projecttreehelper.h
- servermode.cpp servermode.h
- servermodereader.cpp servermodereader.h
- tealeafreader.cpp tealeafreader.h
)
diff --git a/src/plugins/cmakeprojectmanager/builddirmanager.cpp b/src/plugins/cmakeprojectmanager/builddirmanager.cpp
deleted file mode 100644
index 854483c315..0000000000
--- a/src/plugins/cmakeprojectmanager/builddirmanager.cpp
+++ /dev/null
@@ -1,599 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "builddirmanager.h"
-
-#include "cmakebuildconfiguration.h"
-#include "cmakebuildstep.h"
-#include "cmakekitinformation.h"
-#include "cmakeprojectnodes.h"
-#include "cmaketool.h"
-
-#include <coreplugin/icore.h>
-#include <projectexplorer/kit.h>
-#include <projectexplorer/kitinformation.h>
-#include <projectexplorer/project.h>
-#include <projectexplorer/projectexplorerconstants.h>
-#include <projectexplorer/target.h>
-#include <projectexplorer/taskhub.h>
-#include <projectexplorer/toolchain.h>
-
-#include <utils/algorithm.h>
-#include <utils/fileutils.h>
-#include <utils/qtcassert.h>
-
-#include <QDir>
-#include <QLoggingCategory>
-#include <QMessageBox>
-#include <QPointer>
-#include <QPushButton>
-#include <QSet>
-
-#include <app/app_version.h>
-
-using namespace ProjectExplorer;
-using namespace Utils;
-
-namespace CMakeProjectManager {
-namespace Internal {
-
-static Q_LOGGING_CATEGORY(cmakeBuildDirManagerLog, "qtc.cmake.builddirmanager", QtWarningMsg);
-
-// --------------------------------------------------------------------
-// BuildDirManager:
-// --------------------------------------------------------------------
-
-BuildDirManager::BuildDirManager(CMakeBuildSystem *buildSystem)
- : m_buildSystem(buildSystem)
-{
- assert(buildSystem);
-}
-
-BuildDirManager::~BuildDirManager() = default;
-
-FilePath BuildDirManager::workDirectory(const BuildDirParameters &parameters) const
-{
- const Utils::FilePath bdir = parameters.buildDirectory;
- const CMakeTool *cmake = parameters.cmakeTool();
- if (bdir.exists()) {
- m_buildDirToTempDir.erase(bdir);
- return bdir;
- }
-
- if (cmake && cmake->autoCreateBuildDirectory()) {
- if (!QDir().mkpath(bdir.toString()))
- emitErrorOccured(tr("Failed to create build directory \"%1\".").arg(bdir.toUserOutput()));
- return bdir;
- }
-
- auto tmpDirIt = m_buildDirToTempDir.find(bdir);
- if (tmpDirIt == m_buildDirToTempDir.end()) {
- auto ret = m_buildDirToTempDir.emplace(std::make_pair(bdir, std::make_unique<Utils::TemporaryDirectory>("qtc-cmake-XXXXXXXX")));
- QTC_ASSERT(ret.second, return bdir);
- tmpDirIt = ret.first;
-
- if (!tmpDirIt->second->isValid()) {
- emitErrorOccured(tr("Failed to create temporary directory \"%1\".")
- .arg(QDir::toNativeSeparators(tmpDirIt->second->path())));
- return bdir;
- }
- }
- return Utils::FilePath::fromString(tmpDirIt->second->path());
-}
-
-void BuildDirManager::updateReparseParameters(const int parameters)
-{
- m_reparseParameters |= parameters;
-}
-
-int BuildDirManager::takeReparseParameters()
-{
- int result = m_reparseParameters;
- m_reparseParameters = REPARSE_DEFAULT;
- return result;
-}
-
-void BuildDirManager::emitDataAvailable()
-{
- if (!isParsing())
- emit dataAvailable();
-}
-
-void BuildDirManager::emitErrorOccured(const QString &message) const
-{
- m_isHandlingError = true;
- emit errorOccured(message);
- m_isHandlingError = false;
-}
-
-void BuildDirManager::emitReparseRequest() const
-{
- if (m_reparseParameters & REPARSE_URGENT) {
- qCDebug(cmakeBuildDirManagerLog) << "emitting requestReparse";
- emit requestReparse();
- } else {
- qCDebug(cmakeBuildDirManagerLog) << "emitting requestDelayedReparse";
- emit requestDelayedReparse();
- }
-}
-
-void BuildDirManager::updateReaderType(const BuildDirParameters &p,
- std::function<void()> todo)
-{
- if (!m_reader || !m_reader->isCompatible(p)) {
- if (m_reader) {
- stopParsingAndClearState();
- qCDebug(cmakeBuildDirManagerLog) << "Creating new reader do to incompatible parameters";
- } else {
- qCDebug(cmakeBuildDirManagerLog) << "Creating first reader";
- }
- m_reader = BuildDirReader::createReader(p);
-
- connect(m_reader.get(),
- &BuildDirReader::configurationStarted,
- this,
- &BuildDirManager::parsingStarted);
- connect(m_reader.get(),
- &BuildDirReader::dataAvailable,
- this,
- &BuildDirManager::emitDataAvailable);
- connect(m_reader.get(),
- &BuildDirReader::errorOccured,
- this,
- &BuildDirManager::emitErrorOccured);
- connect(m_reader.get(), &BuildDirReader::dirty, this, &BuildDirManager::becameDirty);
- connect(m_reader.get(), &BuildDirReader::isReadyNow, this, todo);
- }
-
- QTC_ASSERT(m_reader, return );
-
- m_reader->setParameters(p);
-}
-
-bool BuildDirManager::hasConfigChanged()
-{
- checkConfiguration();
-
- const QByteArray GENERATOR_KEY = "CMAKE_GENERATOR";
- const QByteArray EXTRA_GENERATOR_KEY = "CMAKE_EXTRA_GENERATOR";
- const QByteArray CMAKE_COMMAND_KEY = "CMAKE_COMMAND";
- const QByteArray CMAKE_C_COMPILER_KEY = "CMAKE_C_COMPILER";
- const QByteArray CMAKE_CXX_COMPILER_KEY = "CMAKE_CXX_COMPILER";
-
- const QByteArrayList criticalKeys
- = {GENERATOR_KEY, CMAKE_COMMAND_KEY, CMAKE_C_COMPILER_KEY, CMAKE_CXX_COMPILER_KEY};
-
- QString errorMessage;
- const CMakeConfig currentConfig = takeCMakeConfiguration(errorMessage);
- if (!errorMessage.isEmpty())
- return false;
-
- const CMakeTool *tool = m_parameters.cmakeTool();
- QTC_ASSERT(tool, return false); // No cmake... we should not have ended up here in the first place
- const QString extraKitGenerator = m_parameters.extraGenerator;
- const QString mainKitGenerator = m_parameters.generator;
- CMakeConfig targetConfig = m_parameters.configuration;
- targetConfig.append(CMakeConfigItem(GENERATOR_KEY, CMakeConfigItem::INTERNAL,
- QByteArray(), mainKitGenerator.toUtf8()));
- if (!extraKitGenerator.isEmpty())
- targetConfig.append(CMakeConfigItem(EXTRA_GENERATOR_KEY, CMakeConfigItem::INTERNAL,
- QByteArray(), extraKitGenerator.toUtf8()));
- targetConfig.append(CMakeConfigItem(CMAKE_COMMAND_KEY, CMakeConfigItem::INTERNAL,
- QByteArray(), tool->cmakeExecutable().toUserOutput().toUtf8()));
- Utils::sort(targetConfig, CMakeConfigItem::sortOperator());
-
- bool mustReparse = false;
- auto ccit = currentConfig.constBegin();
- auto kcit = targetConfig.constBegin();
-
- while (ccit != currentConfig.constEnd() && kcit != targetConfig.constEnd()) {
- if (ccit->key == kcit->key) {
- if (ccit->value != kcit->value) {
- if (criticalKeys.contains(kcit->key)) {
- clearCache();
- return false; // no need to trigger a new reader, clearCache will do that
- }
- mustReparse = true;
- }
- ++ccit;
- ++kcit;
- } else {
- if (ccit->key < kcit->key) {
- ++ccit;
- } else {
- ++kcit;
- mustReparse = true;
- }
- }
- }
-
- // If we have keys that do not exist yet, then reparse.
- //
- // The critical keys *must* be set in cmake configuration, so those were already
- // handled above.
- return mustReparse || kcit != targetConfig.constEnd();
-}
-
-void BuildDirManager::writeConfigurationIntoBuildDirectory(const Utils::MacroExpander *expander)
-{
- QTC_ASSERT(expander, return );
-
- const FilePath buildDir = workDirectory(m_parameters);
- QTC_ASSERT(buildDir.exists(), return );
-
- const FilePath settingsFile = buildDir.pathAppended("qtcsettings.cmake");
-
- QByteArray contents;
- contents.append("# This file is managed by Qt Creator, do not edit!\n\n");
- contents.append(
- transform(m_parameters.configuration,
- [expander](const CMakeConfigItem &item) { return item.toCMakeSetLine(expander); })
- .join('\n')
- .toUtf8());
-
- QFile file(settingsFile.toString());
- QTC_ASSERT(file.open(QFile::WriteOnly | QFile::Truncate), return );
- file.write(contents);
-}
-
-bool BuildDirManager::isParsing() const
-{
- return m_reader && m_reader->isParsing();
-}
-
-void BuildDirManager::stopParsingAndClearState()
-{
- qCDebug(cmakeBuildDirManagerLog) << "stopping parsing run!";
- if (m_reader) {
- if (m_reader->isParsing())
- m_reader->errorOccured(tr("Parsing has been canceled."));
- disconnect(m_reader.get(), nullptr, this, nullptr);
- m_reader->stop();
- }
- m_reader.reset();
- resetData();
-}
-
-void BuildDirManager::setParametersAndRequestParse(const BuildDirParameters &parameters,
- const int reparseParameters)
-{
- qCDebug(cmakeBuildDirManagerLog) << "setting parameters and requesting reparse";
- if (!parameters.cmakeTool()) {
- TaskHub::addTask(BuildSystemTask(Task::Error, tr(
- "The kit needs to define a CMake tool to parse this project.")));
- return;
- }
- QTC_ASSERT(parameters.isValid(), return );
-
- m_parameters = parameters;
- m_parameters.workDirectory = workDirectory(parameters);
- updateReparseParameters(reparseParameters);
-
- updateReaderType(m_parameters, [this]() { emitReparseRequest(); });
-}
-
-CMakeBuildSystem *BuildDirManager::buildSystem() const
-{
- return m_buildSystem;
-}
-
-FilePath BuildDirManager::buildDirectory() const
-{
- return m_parameters.buildDirectory;
-}
-
-void BuildDirManager::becameDirty()
-{
- qCDebug(cmakeBuildDirManagerLog) << "BuildDirManager: becameDirty was triggered.";
- if (isParsing() || !buildSystem())
- return;
-
- const CMakeTool *tool = m_parameters.cmakeTool();
- if (!tool->isAutoRun())
- return;
-
- updateReparseParameters(REPARSE_CHECK_CONFIGURATION | REPARSE_SCAN);
- emit requestReparse();
-}
-
-void BuildDirManager::resetData()
-{
- if (m_reader)
- m_reader->resetData();
-}
-
-bool BuildDirManager::persistCMakeState()
-{
- QTC_ASSERT(m_parameters.isValid(), return false);
-
- if (m_parameters.workDirectory == m_parameters.buildDirectory)
- return false;
-
- const Utils::FilePath buildDir = m_parameters.buildDirectory;
- QDir dir(buildDir.toString());
- dir.mkpath(buildDir.toString());
-
- BuildDirParameters newParameters = m_parameters;
- newParameters.workDirectory.clear();
- qCDebug(cmakeBuildDirManagerLog) << "Requesting parse due to persisting CMake State";
- setParametersAndRequestParse(newParameters,
- REPARSE_URGENT | REPARSE_FORCE_CMAKE_RUN
- | REPARSE_FORCE_CONFIGURATION | REPARSE_CHECK_CONFIGURATION);
- return true;
-}
-
-void BuildDirManager::requestFilesystemScan()
-{
- updateReparseParameters(REPARSE_SCAN);
-}
-
-bool BuildDirManager::isFilesystemScanRequested() const
-{
- return m_reparseParameters & REPARSE_SCAN;
-}
-
-void BuildDirManager::parse()
-{
- qCDebug(cmakeBuildDirManagerLog) << "parsing!";
- QTC_ASSERT(m_parameters.isValid(), return );
- QTC_ASSERT(m_reader, return );
- QTC_ASSERT(!m_reader->isParsing(), return );
-
- m_reader->stop();
-
- TaskHub::clearTasks(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM);
-
- int reparseParameters = takeReparseParameters();
-
- qCDebug(cmakeBuildDirManagerLog)
- << "Parse called with flags:" << flagsString(reparseParameters);
-
- const QString cache = m_parameters.workDirectory.pathAppended("CMakeCache.txt").toString();
- if (!QFileInfo::exists(cache)) {
- reparseParameters |= REPARSE_FORCE_CONFIGURATION | REPARSE_FORCE_CMAKE_RUN;
- qCDebug(cmakeBuildDirManagerLog)
- << "No" << cache << "file found, new flags:" << flagsString(reparseParameters);
- } else if (reparseParameters & REPARSE_CHECK_CONFIGURATION) {
- if (checkConfiguration()) {
- reparseParameters |= REPARSE_FORCE_CONFIGURATION | REPARSE_FORCE_CMAKE_RUN;
- qCDebug(cmakeBuildDirManagerLog)
- << "Config check triggered flags change:" << flagsString(reparseParameters);
- }
- }
-
- writeConfigurationIntoBuildDirectory(m_parameters.expander);
-
- qCDebug(cmakeBuildDirManagerLog) << "Asking reader to parse";
- m_reader->parse(reparseParameters & REPARSE_FORCE_CMAKE_RUN,
- reparseParameters & REPARSE_FORCE_CONFIGURATION);
-}
-
-QSet<FilePath> BuildDirManager::projectFilesToWatch() const
-{
- QTC_ASSERT(!m_isHandlingError, return {});
- QTC_ASSERT(m_reader, return {});
-
- Utils::FilePath sourceDir = m_parameters.sourceDirectory;
- Utils::FilePath buildDir = m_parameters.workDirectory;
-
- return Utils::filtered(m_reader->projectFilesToWatch(),
- [&sourceDir,
- &buildDir](const Utils::FilePath &p) {
- return p.isChildOf(sourceDir)
- || p.isChildOf(buildDir);
- });
-}
-
-std::unique_ptr<CMakeProjectNode> BuildDirManager::generateProjectTree(
- const QList<const FileNode *> &allFiles, QString &errorMessage) const
-{
- QTC_ASSERT(!m_isHandlingError, return {});
- QTC_ASSERT(m_reader, return {});
-
- return m_reader->generateProjectTree(allFiles, errorMessage);
-}
-
-RawProjectParts BuildDirManager::createRawProjectParts(QString &errorMessage) const
-{
- QTC_ASSERT(!m_isHandlingError, return {});
- QTC_ASSERT(m_reader, return {});
- return m_reader->createRawProjectParts(errorMessage);
-}
-
-void BuildDirManager::clearCache()
-{
- QTC_ASSERT(m_parameters.isValid(), return);
- QTC_ASSERT(!m_isHandlingError, return);
-
- const FilePath cmakeCache = m_parameters.workDirectory.pathAppended("CMakeCache.txt");
- const FilePath cmakeFiles = m_parameters.workDirectory.pathAppended("CMakeFiles");
-
- const bool mustCleanUp = cmakeCache.exists() || cmakeFiles.exists();
- if (!mustCleanUp)
- return;
-
- Utils::FileUtils::removeRecursively(cmakeCache);
- Utils::FileUtils::removeRecursively(cmakeFiles);
-
- m_reader.reset();
-}
-
-static CMakeBuildTarget utilityTarget(const QString &title, const BuildDirManager *bdm)
-{
- CMakeBuildTarget target;
-
- target.title = title;
- target.targetType = UtilityType;
- target.workingDirectory = bdm->buildDirectory();
- target.sourceDirectory = bdm->buildSystem()->project()->projectDirectory();
-
- return target;
-}
-
-QList<CMakeBuildTarget> BuildDirManager::takeBuildTargets(QString &errorMessage) const
-{
- QList<CMakeBuildTarget> result = { utilityTarget(CMakeBuildStep::allTarget(), this),
- utilityTarget(CMakeBuildStep::cleanTarget(), this),
- utilityTarget(CMakeBuildStep::installTarget(), this),
- utilityTarget(CMakeBuildStep::testTarget(), this) };
- QTC_ASSERT(!m_isHandlingError, return result);
-
- if (m_reader) {
- QList<CMakeBuildTarget> readerTargets
- = Utils::filtered(m_reader->takeBuildTargets(errorMessage),
- [](const CMakeBuildTarget &bt) {
- return bt.title != CMakeBuildStep::allTarget()
- && bt.title != CMakeBuildStep::cleanTarget()
- && bt.title != CMakeBuildStep::installTarget()
- && bt.title != CMakeBuildStep::testTarget();
- });
-
- // Guess at the target definition position when no details are known
- for (CMakeBuildTarget &t : readerTargets) {
- if (t.backtrace.isEmpty()) {
- t.backtrace.append(
- FolderNode::LocationInfo(tr("CMakeLists.txt in source directory"),
- t.sourceDirectory.pathAppended("CMakeLists.txt")));
- }
- }
- result.append(readerTargets);
- }
- return result;
-}
-
-CMakeConfig BuildDirManager::takeCMakeConfiguration(QString &errorMessage) const
-{
- if (!m_reader)
- return CMakeConfig();
-
- CMakeConfig result = m_reader->takeParsedConfiguration(errorMessage);
- for (auto &ci : result)
- ci.inCMakeCache = true;
-
- return result;
-}
-
-CMakeConfig BuildDirManager::parseCMakeConfiguration(const Utils::FilePath &cacheFile,
- QString *errorMessage)
-{
- if (!cacheFile.exists()) {
- if (errorMessage)
- *errorMessage = tr("CMakeCache.txt file not found.");
- return { };
- }
- CMakeConfig result = CMakeConfigItem::itemsFromFile(cacheFile, errorMessage);
- if (!errorMessage->isEmpty())
- return { };
- return result;
-}
-
-QString BuildDirManager::flagsString(int reparseFlags)
-{
- QString result;
- if (reparseFlags == REPARSE_DEFAULT) {
- result = "<NONE>";
- } else {
- if (reparseFlags & REPARSE_URGENT)
- result += " URGENT";
- if (reparseFlags & REPARSE_FORCE_CMAKE_RUN)
- result += " FORCE_CMAKE_RUN";
- if (reparseFlags & REPARSE_FORCE_CONFIGURATION)
- result += " FORCE_CONFIG";
- if (reparseFlags & REPARSE_CHECK_CONFIGURATION)
- result += " CHECK_CONFIG";
- if (reparseFlags & REPARSE_SCAN)
- result += " SCAN";
- }
- return result.trimmed();
-}
-
-bool BuildDirManager::checkConfiguration()
-{
- if (m_parameters.workDirectory != m_parameters.buildDirectory) // always throw away changes in the tmpdir!
- return false;
-
- const CMakeConfig cache = m_buildSystem->cmakeBuildConfiguration()->configurationFromCMake();
- if (cache.isEmpty())
- return false; // No cache file yet.
-
- CMakeConfig newConfig;
- QHash<QString, QPair<QString, QString>> changedKeys;
- foreach (const CMakeConfigItem &projectItem, m_parameters.configuration) {
- const QString projectKey = QString::fromUtf8(projectItem.key);
- const QString projectValue = projectItem.expandedValue(m_parameters.expander);
- const CMakeConfigItem &cmakeItem
- = Utils::findOrDefault(cache, [&projectItem](const CMakeConfigItem &i) { return i.key == projectItem.key; });
- const QString iCacheValue = QString::fromUtf8(cmakeItem.value);
- if (cmakeItem.isNull()) {
- changedKeys.insert(projectKey, qMakePair(tr("<removed>"), projectValue));
- } else if (iCacheValue != projectValue) {
- changedKeys.insert(projectKey, qMakePair(iCacheValue, projectValue));
- newConfig.append(cmakeItem);
- } else {
- newConfig.append(projectItem);
- }
- }
-
- if (!changedKeys.isEmpty()) {
- QStringList keyList = changedKeys.keys();
- Utils::sort(keyList);
- QString table = QString::fromLatin1("<table><tr><th>%1</th><th>%2</th><th>%3</th></tr>")
- .arg(tr("Key"))
- .arg(tr("%1 Project").arg(Core::Constants::IDE_DISPLAY_NAME))
- .arg(tr("Changed value"));
- foreach (const QString &k, keyList) {
- const QPair<QString, QString> data = changedKeys.value(k);
- table += QString::fromLatin1("\n<tr><td>%1</td><td>%2</td><td>%3</td></tr>")
- .arg(k)
- .arg(data.second.toHtmlEscaped())
- .arg(data.first.toHtmlEscaped());
- }
- table += QLatin1String("\n</table>");
-
- QPointer<QMessageBox> box = new QMessageBox(Core::ICore::mainWindow());
- box->setText(tr("The project has been changed outside of %1.")
- .arg(Core::Constants::IDE_DISPLAY_NAME));
- box->setInformativeText(table);
- auto *defaultButton = box->addButton(tr("Discard External Changes"),
- QMessageBox::RejectRole);
- auto *applyButton = box->addButton(tr("Adapt %1 Project to Changes")
- .arg(Core::Constants::IDE_DISPLAY_NAME),
- QMessageBox::ApplyRole);
- box->setDefaultButton(defaultButton);
-
- box->exec();
- if (box->clickedButton() == applyButton) {
- m_parameters.configuration = newConfig;
- QSignalBlocker blocker(m_buildSystem->buildConfiguration());
- m_buildSystem->cmakeBuildConfiguration()->setConfigurationForCMake(newConfig);
- return false;
- } else if (box->clickedButton() == defaultButton)
- return true;
- }
- return false;
-}
-
-} // namespace Internal
-} // namespace CMakeProjectManager
diff --git a/src/plugins/cmakeprojectmanager/builddirmanager.h b/src/plugins/cmakeprojectmanager/builddirmanager.h
deleted file mode 100644
index 3138b24a81..0000000000
--- a/src/plugins/cmakeprojectmanager/builddirmanager.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "builddirparameters.h"
-#include "builddirreader.h"
-#include "cmakebuildtarget.h"
-#include "cmakeconfigitem.h"
-
-#include <projectexplorer/rawprojectpart.h>
-
-#include <utils/fileutils.h>
-#include <utils/temporarydirectory.h>
-
-#include <QObject>
-#include <QTimer>
-
-#include <functional>
-#include <memory>
-#include <unordered_map>
-
-namespace ProjectExplorer { class FileNode; }
-
-namespace CMakeProjectManager {
-namespace Internal {
-
-class CMakeBuildConfiguration;
-class CMakeBuildSystem;
-class CMakeProjectNode;
-
-class BuildDirManager final : public QObject
-{
- Q_OBJECT
-
-public:
- enum ReparseParameters {
- REPARSE_DEFAULT = 0, // Nothing special:-)
- REPARSE_FORCE_CMAKE_RUN = (1 << 0), // Force cmake to run
- REPARSE_FORCE_CONFIGURATION = (1 << 1), // Force configuration arguments to cmake
- REPARSE_CHECK_CONFIGURATION = (1 << 2), // Check for on-disk config and QtC config diff
- REPARSE_SCAN = (1 << 3), // Run filesystem scan
- REPARSE_URGENT = (1 << 4), // Do not delay the parser run by 1s
- };
-
- static QString flagsString(int reparseFlags);
-
- explicit BuildDirManager(CMakeBuildSystem *buildSystem);
- ~BuildDirManager() final;
-
- bool isParsing() const;
-
- void stopParsingAndClearState();
-
- void setParametersAndRequestParse(const BuildDirParameters &parameters,
- const int reparseOptions);
- // nullptr if the BC is not active anymore!
- CMakeBuildSystem *buildSystem() const;
- Utils::FilePath buildDirectory() const;
-
- void clearCache();
-
- void resetData();
- bool persistCMakeState();
-
- void requestFilesystemScan();
- bool isFilesystemScanRequested() const;
- void parse();
-
- QSet<Utils::FilePath> projectFilesToWatch() const;
- std::unique_ptr<CMakeProjectNode> generateProjectTree(const QList<const ProjectExplorer::FileNode *> &allFiles,
- QString &errorMessage) const;
- ProjectExplorer::RawProjectParts createRawProjectParts(QString &errorMessage) const;
-
- QList<CMakeBuildTarget> takeBuildTargets(QString &errorMessage) const;
- CMakeConfig takeCMakeConfiguration(QString &errorMessage) const;
-
- static CMakeConfig parseCMakeConfiguration(const Utils::FilePath &cacheFile,
- QString *errorMessage);
-
-signals:
- void requestReparse() const;
- void requestDelayedReparse() const;
- void parsingStarted() const;
- void dataAvailable() const;
- void errorOccured(const QString &err) const;
-
-private:
- void updateReparseParameters(const int parameters);
- int takeReparseParameters();
-
- void emitDataAvailable();
- void emitErrorOccured(const QString &message) const;
- void emitReparseRequest() const;
- bool checkConfiguration();
-
- Utils::FilePath workDirectory(const BuildDirParameters &parameters) const;
-
- void updateReaderType(const BuildDirParameters &p, std::function<void()> todo);
-
- bool hasConfigChanged();
-
- void writeConfigurationIntoBuildDirectory(const Utils::MacroExpander *expander);
-
- void becameDirty();
-
- BuildDirParameters m_parameters;
- int m_reparseParameters;
- CMakeBuildSystem *m_buildSystem = nullptr;
- mutable std::unordered_map<Utils::FilePath, std::unique_ptr<Utils::TemporaryDirectory>> m_buildDirToTempDir;
- mutable std::unique_ptr<BuildDirReader> m_reader;
- mutable bool m_isHandlingError = false;
-};
-
-} // namespace Internal
-} // namespace CMakeProjectManager
diff --git a/src/plugins/cmakeprojectmanager/builddirparameters.cpp b/src/plugins/cmakeprojectmanager/builddirparameters.cpp
index 1c71396c76..8522029e67 100644
--- a/src/plugins/cmakeprojectmanager/builddirparameters.cpp
+++ b/src/plugins/cmakeprojectmanager/builddirparameters.cpp
@@ -31,12 +31,12 @@
#include "cmakespecificsettings.h"
#include "cmaketoolmanager.h"
-#include <projectexplorer/kit.h>
#include <projectexplorer/kitinformation.h>
-#include <projectexplorer/projectexplorerconstants.h>
+#include <projectexplorer/project.h>
#include <projectexplorer/target.h>
+#include <projectexplorer/toolchain.h>
-#include <utils/hostosinfo.h>
+#include <utils/qtcassert.h>
using namespace ProjectExplorer;
@@ -47,13 +47,15 @@ BuildDirParameters::BuildDirParameters() = default;
BuildDirParameters::BuildDirParameters(CMakeBuildConfiguration *bc)
{
- initialized = bc != nullptr;
+ QTC_ASSERT(bc, return );
- const Kit *k = bc->target()->kit();
+ const Target *t = bc->target();
+ const Kit *k = t->kit();
+ const Project *p = t->project();
- projectName = bc->target()->project()->displayName();
+ projectName = p->displayName();
- sourceDirectory = bc->target()->project()->projectDirectory();
+ sourceDirectory = p->projectDirectory();
buildDirectory = bc->buildDirectory();
environment = bc->environment();
@@ -69,13 +71,12 @@ BuildDirParameters::BuildDirParameters(CMakeBuildConfiguration *bc)
cmakeToolId = CMakeKitAspect::cmakeToolId(k);
- auto tc = ToolChainKitAspect::toolChain(k, Constants::CXX_LANGUAGE_ID);
+ auto tc = ToolChainKitAspect::cxxToolChain(k);
if (tc)
cxxToolChainId = tc->id();
- tc = ToolChainKitAspect::toolChain(k, Constants::C_LANGUAGE_ID);
+ tc = ToolChainKitAspect::cToolChain(k);
if (tc)
cToolChainId = tc->id();
- sysRoot = SysRootKitAspect::sysRoot(k);
expander = k->macroExpander();
@@ -88,7 +89,10 @@ BuildDirParameters::BuildDirParameters(CMakeBuildConfiguration *bc)
generatorArguments = CMakeGeneratorKitAspect::generatorArguments(k);
}
-bool BuildDirParameters::isValid() const { return initialized && cmakeTool(); }
+bool BuildDirParameters::isValid() const
+{
+ return cmakeTool();
+}
CMakeTool *BuildDirParameters::cmakeTool() const
{
diff --git a/src/plugins/cmakeprojectmanager/builddirparameters.h b/src/plugins/cmakeprojectmanager/builddirparameters.h
index 740327dcad..7318ef03d8 100644
--- a/src/plugins/cmakeprojectmanager/builddirparameters.h
+++ b/src/plugins/cmakeprojectmanager/builddirparameters.h
@@ -49,7 +49,6 @@ public:
bool isValid() const;
CMakeTool *cmakeTool() const;
- bool initialized = false;
QString projectName;
Utils::FilePath sourceDirectory;
@@ -61,8 +60,6 @@ public:
QByteArray cxxToolChainId;
QByteArray cToolChainId;
- Utils::FilePath sysRoot;
-
Utils::MacroExpander *expander = nullptr;
CMakeConfig configuration;
diff --git a/src/plugins/cmakeprojectmanager/builddirreader.h b/src/plugins/cmakeprojectmanager/builddirreader.h
deleted file mode 100644
index 71b5edb974..0000000000
--- a/src/plugins/cmakeprojectmanager/builddirreader.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "builddirparameters.h"
-#include "cmakebuildtarget.h"
-#include "cmakeconfigitem.h"
-#include "cmaketool.h"
-
-#include <projectexplorer/rawprojectpart.h>
-
-#include <utils/environment.h>
-#include <utils/fileutils.h>
-#include <utils/macroexpander.h>
-
-#include <QFutureInterface>
-#include <QObject>
-#include <QVector>
-
-namespace ProjectExplorer { class FileNode; }
-
-namespace CMakeProjectManager {
-namespace Internal {
-
-class CMakeBuildConfiguration;
-class CMakeProjectNode;
-
-class BuildDirReader : public QObject
-{
- Q_OBJECT
-
-public:
- static std::unique_ptr<BuildDirReader> createReader(const BuildDirParameters &p);
- virtual void setParameters(const BuildDirParameters &p) = 0;
-
- virtual bool isCompatible(const BuildDirParameters &p) = 0;
- virtual void resetData() = 0;
- virtual void parse(bool forceCMakeRun, bool forceConfiguration) = 0;
- virtual void stop() = 0;
-
- virtual bool isParsing() const = 0;
-
- virtual QSet<Utils::FilePath> projectFilesToWatch() const = 0;
- virtual QList<CMakeBuildTarget> takeBuildTargets(QString &errorMessage) = 0;
- virtual CMakeConfig takeParsedConfiguration(QString &errorMessage) = 0;
- virtual std::unique_ptr<CMakeProjectNode> generateProjectTree(
- const QList<const ProjectExplorer::FileNode *> &allFiles, QString &errorMessage)
- = 0;
- virtual ProjectExplorer::RawProjectParts createRawProjectParts(QString &errorMessage) = 0;
-
-signals:
- void isReadyNow() const;
- void configurationStarted() const;
- void dataAvailable() const;
- void dirty() const;
- void errorOccured(const QString &message) const;
-
-protected:
- BuildDirParameters m_parameters;
-};
-
-} // namespace Internal
-} // namespace CMakeProjectManager
diff --git a/src/plugins/cmakeprojectmanager/cmakeautocompleter.cpp b/src/plugins/cmakeprojectmanager/cmakeautocompleter.cpp
index eb9ae0c76f..b0b145e7fd 100644
--- a/src/plugins/cmakeprojectmanager/cmakeautocompleter.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakeautocompleter.cpp
@@ -25,13 +25,6 @@
#include "cmakeautocompleter.h"
-#include <QRegExp>
-#include <QTextCursor>
-#include <QTextBlock>
-#include <QDebug>
-
-#include <texteditor/tabsettings.h>
-
namespace CMakeProjectManager {
namespace Internal {
diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp
index fdc02d0533..e920201211 100644
--- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp
@@ -25,37 +25,31 @@
#include "cmakebuildconfiguration.h"
-#include "builddirmanager.h"
+#include "cmakebuildsettingswidget.h"
#include "cmakebuildstep.h"
-#include "cmakeconfigitem.h"
+#include "cmakebuildsystem.h"
#include "cmakekitinformation.h"
#include "cmakeprojectconstants.h"
-#include "cmakebuildsettingswidget.h"
#include <android/androidconstants.h>
-
-#include <coreplugin/icore.h>
-
+#include <projectexplorer/buildaspects.h>
#include <projectexplorer/buildinfo.h>
#include <projectexplorer/buildmanager.h>
#include <projectexplorer/buildsteplist.h>
-#include <projectexplorer/kit.h>
#include <projectexplorer/kitinformation.h>
+#include <projectexplorer/project.h>
#include <projectexplorer/projectexplorer.h>
-#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/projectmacroexpander.h>
#include <projectexplorer/target.h>
-
#include <qtsupport/baseqtversion.h>
#include <qtsupport/qtbuildaspects.h>
#include <qtsupport/qtkitinformation.h>
-#include <utils/algorithm.h>
-#include <utils/mimetypes/mimedatabase.h>
#include <utils/qtcassert.h>
-#include <utils/qtcprocess.h>
+#include <QDir>
#include <QLoggingCategory>
+#include <QMessageBox>
using namespace ProjectExplorer;
using namespace Utils;
@@ -70,16 +64,34 @@ const char CONFIGURATION_KEY[] = "CMake.Configuration";
CMakeBuildConfiguration::CMakeBuildConfiguration(Target *target, Core::Id id)
: BuildConfiguration(target, id)
{
- setBuildDirectory(shadowBuildDirectory(project()->projectFilePath(),
- target->kit(),
- displayName(),
- BuildConfiguration::Unknown));
+ m_buildSystem = new CMakeBuildSystem(this);
+
+ buildDirectoryAspect()->setFileDialogOnly(true);
+ const auto buildDirAspect = aspect<BuildDirectoryAspect>();
+ buildDirAspect->setFileDialogOnly(true);
+ buildDirAspect->setValueAcceptor(
+ [this](const QString &oldDir, const QString &newDir) -> Utils::optional<QString> {
+ if (oldDir.isEmpty())
+ return newDir;
+
+ if (QDir(oldDir).exists("CMakeCache.txt")) {
+ if (QMessageBox::information(nullptr,
+ tr("Changing Build Directory"),
+ tr("Change the build directory and start with a "
+ "basic CMake configuration?"),
+ QMessageBox::Ok,
+ QMessageBox::Cancel)
+ == QMessageBox::Ok) {
+ return newDir;
+ }
+ }
+ return Utils::nullopt;
+ });
appendInitialBuildStep(Constants::CMAKE_BUILD_STEP_ID);
appendInitialCleanStep(Constants::CMAKE_BUILD_STEP_ID);
setInitializer([this, target](const BuildInfo &info) {
-
CMakeConfig config;
config.append({"CMAKE_BUILD_TYPE", info.typeName.toUtf8()});
@@ -87,9 +99,7 @@ CMakeBuildConfiguration::CMakeBuildConfiguration(Target *target, Core::Id id)
const QString sysRoot = SysRootKitAspect::sysRoot(k).toString();
if (!sysRoot.isEmpty()) {
config.append(CMakeConfigItem("CMAKE_SYSROOT", sysRoot.toUtf8()));
- ToolChain *tc = ToolChainKitAspect::toolChain(k,
- ProjectExplorer::Constants::CXX_LANGUAGE_ID);
- if (tc) {
+ if (ToolChain *tc = ToolChainKitAspect::cxxToolChain(k)) {
const QByteArray targetTriple = tc->originalTargetTriple().toUtf8();
config.append(CMakeConfigItem("CMAKE_C_COMPILER_TARGET", targetTriple));
config.append(CMakeConfigItem("CMAKE_CXX_COMPILER_TARGET ", targetTriple));
@@ -156,21 +166,12 @@ CMakeBuildConfiguration::CMakeBuildConfiguration(Target *target, Core::Id id)
}
setConfigurationForCMake(config);
-
- // Only do this after everything has been set up!
- m_buildSystem = new CMakeBuildSystem(this);
});
const auto qmlDebuggingAspect = addAspect<QtSupport::QmlDebuggingAspect>();
qmlDebuggingAspect->setKit(target->kit());
connect(qmlDebuggingAspect, &QtSupport::QmlDebuggingAspect::changed,
this, &CMakeBuildConfiguration::configurationForCMakeChanged);
-
- // m_buildSystem is still nullptr here since it the build directory to be available
- // before it can get created.
- //
- // This means this needs to be done in the lambda for the setInitializer(...) call
- // defined above as well as in fromMap!
}
CMakeBuildConfiguration::~CMakeBuildConfiguration()
@@ -189,8 +190,6 @@ QVariantMap CMakeBuildConfiguration::toMap() const
bool CMakeBuildConfiguration::fromMap(const QVariantMap &map)
{
- QTC_CHECK(!m_buildSystem);
-
if (!BuildConfiguration::fromMap(map))
return false;
@@ -201,17 +200,9 @@ bool CMakeBuildConfiguration::fromMap(const QVariantMap &map)
setConfigurationForCMake(conf);
- m_buildSystem = new CMakeBuildSystem(this);
-
return true;
}
-
-
-
-
-
-
FilePath CMakeBuildConfiguration::shadowBuildDirectory(const FilePath &projectFilePath,
const Kit *k,
const QString &bcName,
@@ -297,10 +288,7 @@ void CMakeBuildConfiguration::setConfigurationForCMake(const QList<ConfigModel::
return item.key.startsWith("ANDROID_BUILD_ABI_");
}) != -1) {
// We always need to clean when we change the ANDROID_BUILD_ABI_ variables
- QList<ProjectExplorer::BuildStepList *> stepLists;
- const Core::Id clean = ProjectExplorer::Constants::BUILDSTEPS_CLEAN;
- stepLists << cleanSteps();
- BuildManager::buildLists(stepLists, QStringList() << ProjectExplorerPlugin::displayNameForStepId(clean));
+ BuildManager::buildLists({cleanSteps()});
}
}
@@ -377,7 +365,7 @@ void CMakeBuildConfiguration::setError(const QString &message)
qCDebug(cmakeBuildConfigurationLog) << "Emitting enabledChanged signal";
emit enabledChanged();
}
- emit errorOccured(m_error);
+ emit errorOccurred(m_error);
}
void CMakeBuildConfiguration::setWarning(const QString &message)
@@ -385,15 +373,9 @@ void CMakeBuildConfiguration::setWarning(const QString &message)
if (m_warning == message)
return;
m_warning = message;
- emit warningOccured(m_warning);
-}
-
-bool CMakeBuildConfiguration::isQmlDebuggingEnabled() const
-{
- return aspect<QtSupport::QmlDebuggingAspect>()->setting() == TriState::Enabled;
+ emit warningOccurred(m_warning);
}
-
QString CMakeBuildConfiguration::error() const
{
return m_error;
@@ -418,8 +400,8 @@ CMakeBuildConfigurationFactory::CMakeBuildConfigurationFactory()
registerBuildConfiguration<CMakeBuildConfiguration>(
"CMakeProjectManager.CMakeBuildConfiguration");
- setSupportedProjectType(CMakeProjectManager::Constants::CMAKEPROJECT_ID);
- setSupportedProjectMimeTypeName(Constants::CMAKEPROJECTMIMETYPE);
+ setSupportedProjectType(CMakeProjectManager::Constants::CMAKE_PROJECT_ID);
+ setSupportedProjectMimeTypeName(Constants::CMAKE_PROJECT_MIMETYPE);
setBuildGenerator([](const Kit *k, const FilePath &projectPath, bool forSetup) {
QList<BuildInfo> result;
diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h
index 082b74c580..c3d0f06254 100644
--- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h
+++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h
@@ -26,19 +26,15 @@
#pragma once
#include "cmakeconfigitem.h"
-#include "cmakeproject.h"
#include "configmodel.h"
#include <projectexplorer/buildconfiguration.h>
-#include <projectexplorer/buildtargetinfo.h>
-#include <projectexplorer/deploymentdata.h>
namespace CMakeProjectManager {
class CMakeProject;
namespace Internal {
-class BuildDirManager;
class CMakeBuildSystem;
class CMakeBuildSettingsWidget;
@@ -46,11 +42,6 @@ class CMakeBuildConfiguration final : public ProjectExplorer::BuildConfiguration
{
Q_OBJECT
- // used in DebuggerRunConfigurationAspect
- Q_PROPERTY(bool linkQmlDebuggingLibrary
- READ isQmlDebuggingEnabled
- NOTIFY configurationForCMakeChanged)
-
friend class ProjectExplorer::BuildConfigurationFactory;
CMakeBuildConfiguration(ProjectExplorer::Target *target, Core::Id id);
~CMakeBuildConfiguration() final;
@@ -71,8 +62,8 @@ public:
ProjectExplorer::BuildSystem *buildSystem() const final;
signals:
- void errorOccured(const QString &message);
- void warningOccured(const QString &message);
+ void errorOccurred(const QString &message);
+ void warningOccurred(const QString &message);
void configurationForCMakeChanged();
@@ -94,8 +85,6 @@ private:
void setError(const QString &message);
void setWarning(const QString &message);
- bool isQmlDebuggingEnabled() const;
-
CMakeConfig m_configurationForCMake;
CMakeConfig m_initialConfiguration;
QString m_error;
@@ -107,7 +96,6 @@ private:
friend class CMakeBuildSettingsWidget;
friend class CMakeBuildSystem;
friend class CMakeProject;
- friend class BuildDirManager;
};
class CMakeProjectImporter;
diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.cpp
index 3464fd7291..c1b4d038c8 100644
--- a/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.cpp
@@ -25,39 +25,30 @@
#include "cmakebuildsettingswidget.h"
+#include "cmakebuildconfiguration.h"
+#include "cmakebuildsystem.h"
+#include "cmakekitinformation.h"
#include "configmodel.h"
#include "configmodelitemdelegate.h"
-#include "cmakekitinformation.h"
-#include "cmakeproject.h"
-#include "cmakebuildconfiguration.h"
-#include <coreplugin/icore.h>
#include <coreplugin/find/itemviewfind.h>
-#include <projectexplorer/kitmanager.h>
+#include <projectexplorer/buildaspects.h>
#include <projectexplorer/project.h>
-#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/target.h>
#include <qtsupport/qtbuildaspects.h>
#include <utils/categorysortfiltermodel.h>
#include <utils/detailswidget.h>
-#include <utils/fancylineedit.h>
#include <utils/headerviewstretcher.h>
#include <utils/infolabel.h>
#include <utils/itemviews.h>
-#include <utils/pathchooser.h>
#include <utils/progressindicator.h>
+#include <utils/qtcassert.h>
#include <QBoxLayout>
#include <QCheckBox>
-#include <QComboBox>
-#include <QFrame>
#include <QGridLayout>
-#include <QLabel>
#include <QPushButton>
-#include <QSortFilterProxyModel>
-#include <QSpacerItem>
-#include <QStyledItemDelegate>
#include <QMenu>
using namespace ProjectExplorer;
@@ -105,20 +96,15 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc)
mainLayout->setContentsMargins(0, 0, 0, 0);
mainLayout->setColumnStretch(1, 10);
- auto project = bc->project();
-
- auto buildDirChooser = new Utils::PathChooser;
- buildDirChooser->setBaseDirectory(project->projectDirectory());
- buildDirChooser->setFileName(bc->buildDirectory());
- connect(buildDirChooser, &Utils::PathChooser::rawPathChanged, this,
- [this](const QString &path) {
- m_configModel->flush(); // clear out config cache...
- m_buildConfiguration->setBuildDirectory(Utils::FilePath::fromString(path));
- });
-
int row = 0;
- mainLayout->addWidget(new QLabel(tr("Build directory:")), row, 0);
- mainLayout->addWidget(buildDirChooser, row, 1, 1, 2);
+ auto buildDirAspect = bc->buildDirectoryAspect();
+ connect(buildDirAspect, &ProjectConfigurationAspect::changed, this, [this]() {
+ m_configModel->flush(); // clear out config cache...;
+ });
+ auto buildDirWidget = new QWidget;
+ LayoutBuilder buildDirWidgetBuilder(buildDirWidget);
+ buildDirAspect->addToLayout(buildDirWidgetBuilder);
+ mainLayout->addWidget(buildDirWidget, row, 0, 1, 2);
++row;
auto qmlDebugAspect = bc->aspect<QtSupport::QmlDebuggingAspect>();
@@ -133,11 +119,6 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc)
mainLayout->addItem(new QSpacerItem(20, 10), row, 0);
++row;
- m_errorMessageLabel = new Utils::InfoLabel({}, Utils::InfoLabel::Error);
- m_errorMessageLabel->setVisible(false);
- mainLayout->addWidget(m_errorMessageLabel, row, 0, 1, -1, Qt::AlignHCenter);
-
- ++row;
m_warningMessageLabel = new Utils::InfoLabel({}, Utils::InfoLabel::Warning);
m_warningMessageLabel->setVisible(false);
mainLayout->addWidget(m_warningMessageLabel, row, 0, 1, -1, Qt::AlignHCenter);
@@ -257,18 +238,17 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc)
m_configView->expandAll();
}
- connect(bc->target(), &Target::parsingFinished, this, [this, buildDirChooser, stretcher] {
+ connect(bc->target(), &Target::parsingFinished, this, [this, stretcher] {
m_configModel->setConfiguration(m_buildConfiguration->configurationFromCMake());
m_configView->expandAll();
m_configView->setEnabled(true);
stretcher->stretch();
updateButtonState();
- buildDirChooser->triggerChanged(); // refresh valid state...
handleQmlDebugCxxFlags();
m_showProgressTimer.stop();
m_progressIndicator->hide();
});
- connect(m_buildConfiguration, &CMakeBuildConfiguration::errorOccured,
+ connect(m_buildConfiguration, &CMakeBuildConfiguration::errorOccurred,
this, [this]() {
m_showProgressTimer.stop();
m_progressIndicator->hide();
@@ -323,8 +303,8 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc)
m_configView->edit(idx);
});
- connect(bc, &CMakeBuildConfiguration::errorOccured, this, &CMakeBuildSettingsWidget::setError);
- connect(bc, &CMakeBuildConfiguration::warningOccured, this, &CMakeBuildSettingsWidget::setWarning);
+ connect(bc, &CMakeBuildConfiguration::errorOccurred, this, &CMakeBuildSettingsWidget::setError);
+ connect(bc, &CMakeBuildConfiguration::warningOccurred, this, &CMakeBuildSettingsWidget::setWarning);
updateFromKit();
connect(m_buildConfiguration->target(), &ProjectExplorer::Target::kitChanged,
@@ -342,9 +322,7 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc)
void CMakeBuildSettingsWidget::setError(const QString &message)
{
- bool showError = !message.isEmpty();
- m_errorMessageLabel->setVisible(showError);
- m_errorMessageLabel->setText(message);
+ m_buildConfiguration->buildDirectoryAspect()->setProblem(message);
}
void CMakeBuildSettingsWidget::setWarning(const QString &message)
diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.h b/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.h
index 9b315ce7db..1014d2f674 100644
--- a/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.h
+++ b/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.h
@@ -55,6 +55,7 @@ class CMakeBuildConfiguration;
class CMakeBuildSettingsWidget : public ProjectExplorer::NamedWidget
{
Q_OBJECT
+
public:
CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc);
@@ -88,7 +89,6 @@ private:
QPushButton *m_reconfigureButton;
QTimer m_showProgressTimer;
Utils::FancyLineEdit *m_filterEdit;
- Utils::InfoLabel *m_errorMessageLabel;
Utils::InfoLabel *m_warningMessageLabel;
};
diff --git a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp
index a50b4e19cc..287514c4df 100644
--- a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp
@@ -30,46 +30,53 @@
#include "cmakekitinformation.h"
#include "cmakeparser.h"
#include "cmakeprojectconstants.h"
-#include "cmakeproject.h"
#include "cmaketool.h"
+#include <coreplugin/find/itemviewfind.h>
#include <projectexplorer/buildsteplist.h>
-#include <projectexplorer/deployconfiguration.h>
#include <projectexplorer/gnumakeparser.h>
-#include <projectexplorer/kitinformation.h>
#include <projectexplorer/processparameters.h>
-#include <projectexplorer/projectexplorerconstants.h>
+#include <projectexplorer/project.h>
#include <projectexplorer/projectexplorer.h>
+#include <projectexplorer/runconfiguration.h>
#include <projectexplorer/target.h>
-#include <projectexplorer/toolchain.h>
-
-#include <qtsupport/qtkitinformation.h>
-#include <qtsupport/qtparser.h>
-
-#include <coreplugin/find/itemviewfind.h>
-
-#include <utils/algorithm.h>
-#include <utils/qtcprocess.h>
-#include <utils/pathchooser.h>
-#include <QCheckBox>
-#include <QDir>
+#include <QBoxLayout>
#include <QFormLayout>
-#include <QGroupBox>
#include <QLineEdit>
#include <QListWidget>
#include <QRadioButton>
-using namespace CMakeProjectManager;
-using namespace CMakeProjectManager::Internal;
using namespace ProjectExplorer;
-namespace {
+namespace CMakeProjectManager {
+namespace Internal {
+
const char BUILD_TARGETS_KEY[] = "CMakeProjectManager.MakeStep.BuildTargets";
const char TOOL_ARGUMENTS_KEY[] = "CMakeProjectManager.MakeStep.AdditionalArguments";
const char ADD_RUNCONFIGURATION_ARGUMENT_KEY[] = "CMakeProjectManager.MakeStep.AddRunConfigurationArgument";
const char ADD_RUNCONFIGURATION_TEXT[] = "Current executable";
-}
+
+class CMakeBuildStepConfigWidget : public BuildStepConfigWidget
+{
+ Q_DECLARE_TR_FUNCTIONS(CMakeProjectManager::Internal::CMakeBuildStepConfigWidget)
+
+public:
+ explicit CMakeBuildStepConfigWidget(CMakeBuildStep *buildStep);
+
+private:
+ void itemChanged(QListWidgetItem *);
+ void toolArgumentsEdited();
+ void updateDetails();
+ void buildTargetsChanged();
+ void updateBuildTarget();
+
+ QRadioButton *itemWidget(QListWidgetItem *item);
+
+ CMakeBuildStep *m_buildStep;
+ QLineEdit *m_toolArguments;
+ QListWidget *m_buildTargetsList;
+};
static bool isCurrentExecutableTarget(const QString &target)
{
@@ -131,18 +138,14 @@ bool CMakeBuildStep::fromMap(const QVariantMap &map)
return BuildStep::fromMap(map);
}
-
bool CMakeBuildStep::init()
{
bool canInit = true;
CMakeBuildConfiguration *bc = cmakeBuildConfiguration();
- if (!bc) {
- emit addTask(Task::buildConfigurationMissingTask());
- canInit = false;
- }
- if (bc && !bc->isEnabled()) {
- emit addTask(
- BuildSystemTask(Task::Error, tr("The build configuration is currently disabled.")));
+ QTC_ASSERT(bc, return false);
+ if (!bc->isEnabled()) {
+ emit addTask(BuildSystemTask(Task::Error,
+ tr("The build configuration is currently disabled.")));
canInit = false;
}
@@ -194,30 +197,28 @@ bool CMakeBuildStep::init()
pp->setCommandLine(cmakeCommand(rc));
pp->resolveAll();
- CMakeParser *cmakeParser = new CMakeParser;
- cmakeParser->setSourceDirectory(projectDirectory.toString());
- setOutputParser(cmakeParser);
- appendOutputParser(new GnuMakeParser);
- IOutputParser *parser = target()->kit()->createOutputParser();
- if (parser)
- appendOutputParser(parser);
- outputParser()->setWorkingDirectory(pp->effectiveWorkingDirectory());
-
return AbstractProcessStep::init();
}
+void CMakeBuildStep::setupOutputFormatter(Utils::OutputFormatter *formatter)
+{
+ CMakeParser *cmakeParser = new CMakeParser;
+ cmakeParser->setSourceDirectory(project()->projectDirectory().toString());
+ formatter->addLineParsers({cmakeParser, new GnuMakeParser});
+ formatter->addLineParsers(target()->kit()->createOutputParsers());
+ formatter->addSearchDir(processParameters()->effectiveWorkingDirectory());
+ AbstractProcessStep::setupOutputFormatter(formatter);
+}
+
void CMakeBuildStep::doRun()
{
// Make sure CMake state was written to disk before trying to build:
- CMakeBuildConfiguration *bc = cmakeBuildConfiguration();
- QTC_ASSERT(bc, return);
-
m_waiting = false;
- auto bs = static_cast<CMakeBuildSystem *>(buildConfiguration()->buildSystem());
+ auto bs = static_cast<CMakeBuildSystem *>(buildSystem());
if (bs->persistCMakeState()) {
emit addOutput(tr("Persisting CMake state..."), BuildStep::OutputFormat::NormalMessage);
m_waiting = true;
- } else if (buildConfiguration()->buildSystem()->isWaitingForParse()) {
+ } else if (buildSystem()->isWaitingForParse()) {
emit addOutput(tr("Running CMake in preparation to build..."), BuildStep::OutputFormat::NormalMessage);
m_waiting = true;
}
@@ -267,33 +268,45 @@ QString CMakeBuildStep::defaultBuildTarget() const
return allTarget();
}
-void CMakeBuildStep::stdOutput(const QString &line)
+void CMakeBuildStep::stdOutput(const QString &output)
{
- if (m_percentProgress.indexIn(line) != -1) {
- AbstractProcessStep::stdOutput(line);
- bool ok = false;
- int percent = m_percentProgress.cap(1).toInt(&ok);
- if (ok)
- emit progress(percent, QString());
- return;
- } else if (m_ninjaProgress.indexIn(line) != -1) {
- AbstractProcessStep::stdOutput(line);
- m_useNinja = true;
- bool ok = false;
- int done = m_ninjaProgress.cap(1).toInt(&ok);
- if (ok) {
- int all = m_ninjaProgress.cap(2).toInt(&ok);
- if (ok && all != 0) {
- const int percent = static_cast<int>(100.0 * done/all);
+ int offset = 0;
+ while (offset != -1) {
+ const int newlinePos = output.indexOf('\n', offset);
+ QString line;
+ if (newlinePos == -1) {
+ line = output.mid(offset);
+ offset = -1;
+ } else {
+ line = output.mid(offset, newlinePos - offset + 1);
+ offset = newlinePos + 1;
+ }
+ if (m_percentProgress.indexIn(line) != -1) {
+ AbstractProcessStep::stdOutput(line);
+ bool ok = false;
+ int percent = m_percentProgress.cap(1).toInt(&ok);
+ if (ok)
emit progress(percent, QString());
+ continue;
+ } else if (m_ninjaProgress.indexIn(line) != -1) {
+ AbstractProcessStep::stdOutput(line);
+ m_useNinja = true;
+ bool ok = false;
+ int done = m_ninjaProgress.cap(1).toInt(&ok);
+ if (ok) {
+ int all = m_ninjaProgress.cap(2).toInt(&ok);
+ if (ok && all != 0) {
+ const int percent = static_cast<int>(100.0 * done/all);
+ emit progress(percent, QString());
+ }
}
+ continue;
}
- return;
+ if (m_useNinja)
+ AbstractProcessStep::stdError(line);
+ else
+ AbstractProcessStep::stdOutput(line);
}
- if (m_useNinja)
- AbstractProcessStep::stdError(line);
- else
- AbstractProcessStep::stdOutput(line);
}
QString CMakeBuildStep::buildTarget() const
@@ -359,8 +372,8 @@ Utils::CommandLine CMakeBuildStep::cmakeCommand(RunConfiguration *rc) const
QStringList CMakeBuildStep::knownBuildTargets()
{
- auto bc = qobject_cast<CMakeBuildSystem *>(buildConfiguration()->buildSystem());
- return bc ? bc->buildTargetTitles() : QStringList();
+ auto bs = qobject_cast<CMakeBuildSystem *>(buildSystem());
+ return bs ? bs->buildTargetTitles() : QStringList();
}
QString CMakeBuildStep::cleanTarget()
@@ -528,16 +541,10 @@ QRadioButton *CMakeBuildStepConfigWidget::itemWidget(QListWidgetItem *item)
void CMakeBuildStepConfigWidget::updateDetails()
{
- BuildConfiguration *bc = m_buildStep->buildConfiguration();
- if (!bc) {
- setSummaryText(tr("<b>No build configuration found on this kit.</b>"));
- return;
- }
-
ProcessParameters param;
- param.setMacroExpander(bc->macroExpander());
- param.setEnvironment(bc->environment());
- param.setWorkingDirectory(bc->buildDirectory());
+ param.setMacroExpander(m_buildStep->macroExpander());
+ param.setEnvironment(m_buildStep->buildEnvironment());
+ param.setWorkingDirectory(m_buildStep->buildDirectory());
param.setCommandLine(m_buildStep->cmakeCommand(nullptr));
setSummaryText(param.summary(displayName()));
@@ -551,7 +558,7 @@ CMakeBuildStepFactory::CMakeBuildStepFactory()
{
registerStep<CMakeBuildStep>(Constants::CMAKE_BUILD_STEP_ID);
setDisplayName(CMakeBuildStep::tr("Build", "Display name for CMakeProjectManager::CMakeBuildStep id."));
- setSupportedProjectType(Constants::CMAKEPROJECT_ID);
+ setSupportedProjectType(Constants::CMAKE_PROJECT_ID);
}
void CMakeBuildStep::processStarted()
@@ -565,3 +572,6 @@ void CMakeBuildStep::processFinished(int exitCode, QProcess::ExitStatus status)
AbstractProcessStep::processFinished(exitCode, status);
emit progress(100, QString());
}
+
+} // Internal
+} // CMakeProjectManager
diff --git a/src/plugins/cmakeprojectmanager/cmakebuildstep.h b/src/plugins/cmakeprojectmanager/cmakebuildstep.h
index 1938c88b10..f2a650fe78 100644
--- a/src/plugins/cmakeprojectmanager/cmakebuildstep.h
+++ b/src/plugins/cmakeprojectmanager/cmakebuildstep.h
@@ -27,22 +27,9 @@
#include <projectexplorer/abstractprocessstep.h>
-#include <QRegExp>
+namespace Utils { class CommandLine; }
-QT_BEGIN_NAMESPACE
-class QLineEdit;
-class QListWidget;
-class QListWidgetItem;
-class QRadioButton;
-QT_END_NAMESPACE
-
-namespace Utils {
-class CommandLine;
-} // Utils
-
-namespace ProjectExplorer {
-class RunConfiguration;
-} // ProjectManager
+namespace ProjectExplorer { class RunConfiguration; }
namespace CMakeProjectManager {
namespace Internal {
@@ -90,12 +77,13 @@ protected:
bool fromMap(const QVariantMap &map) override;
// For parsing [ 76%]
- void stdOutput(const QString &line) override;
+ void stdOutput(const QString &output) override;
private:
void ctor(ProjectExplorer::BuildStepList *bsl);
bool init() override;
+ void setupOutputFormatter(Utils::OutputFormatter *formatter) override;
void doRun() override;
ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override;
@@ -117,26 +105,6 @@ private:
bool m_waiting = false;
};
-class CMakeBuildStepConfigWidget : public ProjectExplorer::BuildStepConfigWidget
-{
- Q_OBJECT
-public:
- CMakeBuildStepConfigWidget(CMakeBuildStep *buildStep);
-
-private:
- void itemChanged(QListWidgetItem*);
- void toolArgumentsEdited();
- void updateDetails();
- void buildTargetsChanged();
- void updateBuildTarget();
-
- QRadioButton *itemWidget(QListWidgetItem *item);
-
- CMakeBuildStep *m_buildStep;
- QLineEdit *m_toolArguments;
- QListWidget *m_buildTargetsList;
-};
-
class CMakeBuildStepFactory : public ProjectExplorer::BuildStepFactory
{
public:
diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp
index 2f4d146fb3..58b0c11ba9 100644
--- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp
@@ -25,35 +25,112 @@
#include "cmakebuildsystem.h"
+#include "builddirparameters.h"
#include "cmakebuildconfiguration.h"
#include "cmakekitinformation.h"
-#include "cmakeproject.h"
#include "cmakeprojectconstants.h"
#include "cmakeprojectnodes.h"
+#include "cmakeprojectplugin.h"
+#include "cmakespecificsettings.h"
#include <android/androidconstants.h>
-
+#include <coreplugin/icore.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <cpptools/cppprojectupdater.h>
+#include <cpptools/cpptoolsconstants.h>
#include <cpptools/generatedcodemodelsupport.h>
+#include <projectexplorer/kitinformation.h>
#include <projectexplorer/projectexplorerconstants.h>
-#include <projectexplorer/kitmanager.h>
-#include <projectexplorer/project.h>
+#include <projectexplorer/session.h>
#include <projectexplorer/target.h>
+#include <projectexplorer/taskhub.h>
#include <qmljs/qmljsmodelmanagerinterface.h>
-
#include <qtsupport/qtcppkitinfo.h>
-#include <qtsupport/qtkitinformation.h>
+#include <app/app_version.h>
+
+#include <utils/checkablemessagebox.h>
#include <utils/fileutils.h>
#include <utils/mimetypes/mimetype.h>
#include <utils/qtcassert.h>
+#include <QClipboard>
+#include <QDir>
+#include <QGuiApplication>
#include <QLoggingCategory>
+#include <QPushButton>
using namespace ProjectExplorer;
using namespace Utils;
+namespace {
+
+void copySourcePathToClipboard(Utils::optional<QString> srcPath,
+ const ProjectExplorer::ProjectNode *node)
+{
+ QClipboard *clip = QGuiApplication::clipboard();
+
+ QDir projDir{node->filePath().toFileInfo().absoluteFilePath()};
+ clip->setText(QDir::cleanPath(projDir.relativeFilePath(srcPath.value())));
+}
+
+void noAutoAdditionNotify(const QStringList &filePaths, const ProjectExplorer::ProjectNode *node)
+{
+ Utils::optional<QString> srcPath{};
+
+ for (const QString &file : filePaths) {
+ if (Utils::mimeTypeForFile(file).name() == CppTools::Constants::CPP_SOURCE_MIMETYPE) {
+ srcPath = file;
+ break;
+ }
+ }
+
+ if (srcPath) {
+ CMakeProjectManager::Internal::CMakeSpecificSettings *settings
+ = CMakeProjectManager::Internal::CMakeProjectPlugin::projectTypeSpecificSettings();
+ switch (settings->afterAddFileSetting()) {
+ case CMakeProjectManager::Internal::ASK_USER: {
+ bool checkValue{false};
+ QDialogButtonBox::StandardButton reply = Utils::CheckableMessageBox::question(
+ nullptr,
+ QMessageBox::tr("Copy to Clipboard?"),
+ QMessageBox::tr("Files are not automatically added to the "
+ "CMakeLists.txt file of the CMake project."
+ "\nCopy the path to the source files to the clipboard?"),
+ "Remember My Choice",
+ &checkValue,
+ QDialogButtonBox::Yes | QDialogButtonBox::No,
+ QDialogButtonBox::Yes);
+ if (checkValue) {
+ if (QDialogButtonBox::Yes == reply)
+ settings->setAfterAddFileSetting(
+ CMakeProjectManager::Internal::AfterAddFileAction::COPY_FILE_PATH);
+ else if (QDialogButtonBox::No == reply)
+ settings->setAfterAddFileSetting(
+ CMakeProjectManager::Internal::AfterAddFileAction::NEVER_COPY_FILE_PATH);
+
+ settings->toSettings(Core::ICore::settings());
+ }
+
+ if (QDialogButtonBox::Yes == reply) {
+ copySourcePathToClipboard(srcPath, node);
+ }
+ break;
+ }
+
+ case CMakeProjectManager::Internal::COPY_FILE_PATH: {
+ copySourcePathToClipboard(srcPath, node);
+ break;
+ }
+
+ case CMakeProjectManager::Internal::NEVER_COPY_FILE_PATH:
+ break;
+ }
+ }
+}
+
+} // namespace
+
namespace CMakeProjectManager {
namespace Internal {
@@ -65,8 +142,6 @@ static Q_LOGGING_CATEGORY(cmakeBuildSystemLog, "qtc.cmake.buildsystem", QtWarnin
CMakeBuildSystem::CMakeBuildSystem(CMakeBuildConfiguration *bc)
: BuildSystem(bc)
- , m_buildConfiguration(bc)
- , m_buildDirManager(this)
, m_cppCodeModelUpdater(new CppTools::CppProjectUpdater)
{
// TreeScanner:
@@ -97,123 +172,29 @@ CMakeBuildSystem::CMakeBuildSystem(CMakeBuildConfiguration *bc)
if (type == FileType::Unknown) {
if (mimeType.isValid()) {
const QString mt = mimeType.name();
- if (mt == CMakeProjectManager::Constants::CMAKEPROJECTMIMETYPE
- || mt == CMakeProjectManager::Constants::CMAKEMIMETYPE)
+ if (mt == CMakeProjectManager::Constants::CMAKE_PROJECT_MIMETYPE
+ || mt == CMakeProjectManager::Constants::CMAKE_MIMETYPE)
type = FileType::Project;
}
}
return type;
});
- // BuildDirManager:
- connect(&m_buildDirManager, &BuildDirManager::requestReparse, this, [this] {
- if (m_buildConfiguration->isActive())
- requestParse();
- });
- connect(&m_buildDirManager, &BuildDirManager::requestDelayedReparse, this, [this] {
- if (m_buildConfiguration->isActive())
- requestDelayedParse();
- });
-
- connect(&m_buildDirManager, &BuildDirManager::dataAvailable,
- this, &CMakeBuildSystem::handleParsingSucceeded);
-
- connect(&m_buildDirManager, &BuildDirManager::errorOccured,
- this, &CMakeBuildSystem::handleParsingFailed);
-
- connect(&m_buildDirManager, &BuildDirManager::parsingStarted, this, [this]() {
- m_buildConfiguration->clearError(CMakeBuildConfiguration::ForceEnabledChanged::True);
+ connect(&m_reader, &FileApiReader::configurationStarted, this, [this]() {
+ cmakeBuildConfiguration()->clearError(CMakeBuildConfiguration::ForceEnabledChanged::True);
});
- // Kit changed:
- connect(KitManager::instance(), &KitManager::kitUpdated, this, [this](Kit *k) {
- if (k != target()->kit())
- return; // not for us...
- // Build configuration has not changed, but Kit settings might have:
- // reparse and check the configuration, independent of whether the reader has changed
- qCDebug(cmakeBuildSystemLog) << "Requesting parse due to kit being updated";
- m_buildDirManager.setParametersAndRequestParse(BuildDirParameters(m_buildConfiguration),
- BuildDirManager::REPARSE_CHECK_CONFIGURATION);
- });
-
- // Became active/inactive:
- connect(project(), &Project::activeTargetChanged, this, [this](Target *t) {
- if (t == target()) {
- // Build configuration has switched:
- // * Check configuration if reader changes due to it not existing yet:-)
- // * run cmake without configuration arguments if the reader stays
- qCDebug(cmakeBuildSystemLog) << "Requesting parse due to active target changed";
- m_buildDirManager
- .setParametersAndRequestParse(BuildDirParameters(m_buildConfiguration),
- BuildDirManager::REPARSE_CHECK_CONFIGURATION);
- } else {
- m_buildDirManager.stopParsingAndClearState();
- }
- });
- connect(target(), &Target::activeBuildConfigurationChanged, this, [this](BuildConfiguration *bc) {
- if (m_buildConfiguration->isActive()) {
- if (m_buildConfiguration == bc) {
- // Build configuration has switched:
- // * Check configuration if reader changes due to it not existing yet:-)
- // * run cmake without configuration arguments if the reader stays
- qCDebug(cmakeBuildSystemLog) << "Requesting parse due to active BC changed";
- m_buildDirManager
- .setParametersAndRequestParse(BuildDirParameters(m_buildConfiguration),
- BuildDirManager::REPARSE_CHECK_CONFIGURATION);
- } else {
- m_buildDirManager.stopParsingAndClearState();
- }
- }
- });
-
- // BuildConfiguration changed:
- connect(m_buildConfiguration, &CMakeBuildConfiguration::environmentChanged, this, [this]() {
- if (m_buildConfiguration->isActive()) {
- // The environment on our BC has changed:
- // * Error out if the reader updates, cannot happen since all BCs share a target/kit.
- // * run cmake without configuration arguments if the reader stays
- qCDebug(cmakeBuildSystemLog) << "Requesting parse due to environment change";
- m_buildDirManager
- .setParametersAndRequestParse(BuildDirParameters(m_buildConfiguration),
- BuildDirManager::REPARSE_CHECK_CONFIGURATION);
- }
- });
- connect(m_buildConfiguration, &CMakeBuildConfiguration::buildDirectoryChanged, this, [this]() {
- if (m_buildConfiguration->isActive()) {
- // The build directory of our BC has changed:
- // * Error out if the reader updates, cannot happen since all BCs share a target/kit.
- // * run cmake without configuration arguments if the reader stays
- // If no configuration exists, then the arguments will get added automatically by
- // the reader.
- qCDebug(cmakeBuildSystemLog) << "Requesting parse due to build directory change";
- m_buildDirManager
- .setParametersAndRequestParse(BuildDirParameters(m_buildConfiguration),
- BuildDirManager::REPARSE_CHECK_CONFIGURATION);
- }
- });
- connect(m_buildConfiguration, &CMakeBuildConfiguration::configurationForCMakeChanged, this, [this]() {
- if (m_buildConfiguration->isActive()) {
- // The CMake configuration has changed on our BC:
- // * Error out if the reader updates, cannot happen since all BCs share a target/kit.
- // * run cmake with configuration arguments if the reader stays
- qCDebug(cmakeBuildSystemLog) << "Requesting parse due to cmake configuration change";
- m_buildDirManager
- .setParametersAndRequestParse(BuildDirParameters(m_buildConfiguration),
- BuildDirManager::REPARSE_FORCE_CONFIGURATION);
- }
- });
-
- connect(project(), &Project::projectFileIsDirty, this, [this]() {
- if (m_buildConfiguration->isActive() && !isParsing()) {
- const auto cmake = CMakeKitAspect::cmakeTool(m_buildConfiguration->target()->kit());
- if (cmake && cmake->isAutoRun()) {
- qCDebug(cmakeBuildSystemLog) << "Requesting parse due to dirty project file";
- m_buildDirManager.setParametersAndRequestParse(BuildDirParameters(
- m_buildConfiguration),
- BuildDirManager::REPARSE_DEFAULT);
- }
- }
- });
+ connect(&m_reader,
+ &FileApiReader::dataAvailable,
+ this,
+ &CMakeBuildSystem::handleParsingSucceeded);
+ connect(&m_reader, &FileApiReader::errorOccurred, this, &CMakeBuildSystem::handleParsingFailed);
+ connect(&m_reader, &FileApiReader::dirty, this, &CMakeBuildSystem::becameDirty);
+
+ connect(SessionManager::instance(),
+ &SessionManager::projectAdded,
+ this,
+ &CMakeBuildSystem::wireUpConnections);
}
CMakeBuildSystem::~CMakeBuildSystem()
@@ -238,22 +219,25 @@ void CMakeBuildSystem::triggerParsing()
// This can legitimately trigger if e.g. Build->Run CMake
// is selected while this here is already running.
- // FIXME: Instead of aborting the second run here we could try to
- // cancel the first one in the Build->Run CMake handler and then
- // continue to here normally. This here could then be an Assert.
- return;
+ // Stop old parse run and keep that ParseGuard!
+ stopParsingAndClearState();
+ } else {
+ // Use new ParseGuard
+ m_currentGuard = std::move(guard);
}
+ QTC_ASSERT(!m_reader.isParsing(), return );
- m_currentGuard = std::move(guard);
+ qCDebug(cmakeBuildSystemLog) << "ParseGuard acquired.";
if (m_allFiles.isEmpty())
- m_buildDirManager.requestFilesystemScan();
+ updateReparseParameters(REPARSE_SCAN);
- m_waitingForScan = m_buildDirManager.isFilesystemScanRequested();
+ m_waitingForScan = (m_reparseParameters | REPARSE_SCAN) != 0;
m_waitingForParse = true;
m_combinedScanAndParseResult = true;
if (m_waitingForScan) {
+ qCDebug(cmakeBuildSystemLog) << "Starting TreeScanner";
QTC_CHECK(m_treeScanner.isFinished());
m_treeScanner.asyncScanForFiles(projectDirectory());
Core::ProgressManager::addTask(m_treeScanner.future(),
@@ -262,7 +246,60 @@ void CMakeBuildSystem::triggerParsing()
"CMake.Scan.Tree");
}
- m_buildDirManager.parse();
+ QTC_ASSERT(m_parameters.isValid(), return );
+
+ TaskHub::clearTasks(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM);
+
+ int reparseParameters = takeReparseParameters();
+
+ qCDebug(cmakeBuildSystemLog) << "Parse called with flags:"
+ << reparseParametersString(reparseParameters);
+
+ const QString cache = m_parameters.workDirectory.pathAppended("CMakeCache.txt").toString();
+ if (!QFileInfo::exists(cache)) {
+ reparseParameters |= REPARSE_FORCE_CONFIGURATION | REPARSE_FORCE_CMAKE_RUN;
+ qCDebug(cmakeBuildSystemLog)
+ << "No" << cache
+ << "file found, new flags:" << reparseParametersString(reparseParameters);
+ } else if (reparseParameters & REPARSE_CHECK_CONFIGURATION) {
+ if (checkConfiguration()) {
+ reparseParameters |= REPARSE_FORCE_CONFIGURATION | REPARSE_FORCE_CMAKE_RUN;
+ qCDebug(cmakeBuildSystemLog) << "Config check triggered flags change:"
+ << reparseParametersString(reparseParameters);
+ }
+ }
+
+ writeConfigurationIntoBuildDirectory(m_parameters.expander);
+
+ qCDebug(cmakeBuildSystemLog) << "Asking reader to parse";
+ m_reader.parse(reparseParameters & REPARSE_FORCE_CMAKE_RUN,
+ reparseParameters & REPARSE_FORCE_CONFIGURATION);
+}
+
+bool CMakeBuildSystem::supportsAction(Node *context, ProjectAction action, const Node *node) const
+{
+ if (dynamic_cast<CMakeTargetNode *>(context))
+ return action == ProjectAction::AddNewFile;
+
+ if (dynamic_cast<CMakeListsNode *>(context))
+ return action == ProjectAction::AddNewFile;
+
+ return BuildSystem::supportsAction(context, action, node);
+}
+
+bool CMakeBuildSystem::addFiles(Node *context, const QStringList &filePaths, QStringList *notAdded)
+{
+ if (auto n = dynamic_cast<CMakeProjectNode *>(context)) {
+ noAutoAdditionNotify(filePaths, n);
+ return true; // Return always true as autoadd is not supported!
+ }
+
+ if (auto n = dynamic_cast<CMakeTargetNode *>(context)) {
+ noAutoAdditionNotify(filePaths, n);
+ return true; // Return always true as autoadd is not supported!
+ }
+
+ return BuildSystem::addFiles(context, filePaths, notAdded);
}
QStringList CMakeBuildSystem::filesGeneratedFrom(const QString &sourceFile) const
@@ -280,7 +317,7 @@ QStringList CMakeBuildSystem::filesGeneratedFrom(const QString &sourceFile) cons
QDir srcDirRoot = QDir(project.toString());
QString relativePath = srcDirRoot.relativeFilePath(baseDirectory.toString());
- QDir buildDir = QDir(buildConfiguration()->buildDirectory().toString());
+ QDir buildDir = QDir(cmakeBuildConfiguration()->buildDirectory().toString());
QString generatedFilePath = buildDir.absoluteFilePath(relativePath);
if (fi.suffix() == "ui") {
@@ -299,29 +336,95 @@ QStringList CMakeBuildSystem::filesGeneratedFrom(const QString &sourceFile) cons
return {};
}
+QString CMakeBuildSystem::reparseParametersString(int reparseFlags)
+{
+ QString result;
+ if (reparseFlags == REPARSE_DEFAULT) {
+ result = "<NONE>";
+ } else {
+ if (reparseFlags & REPARSE_URGENT)
+ result += " URGENT";
+ if (reparseFlags & REPARSE_FORCE_CMAKE_RUN)
+ result += " FORCE_CMAKE_RUN";
+ if (reparseFlags & REPARSE_FORCE_CONFIGURATION)
+ result += " FORCE_CONFIG";
+ if (reparseFlags & REPARSE_CHECK_CONFIGURATION)
+ result += " CHECK_CONFIG";
+ if (reparseFlags & REPARSE_SCAN)
+ result += " SCAN";
+ }
+ return result.trimmed();
+}
+
+void CMakeBuildSystem::setParametersAndRequestParse(const BuildDirParameters &parameters,
+ const int reparseParameters)
+{
+ qCDebug(cmakeBuildSystemLog) << "setting parameters and requesting reparse";
+ if (!parameters.cmakeTool()) {
+ TaskHub::addTask(
+ BuildSystemTask(Task::Error,
+ tr("The kit needs to define a CMake tool to parse this project.")));
+ return;
+ }
+ QTC_ASSERT(parameters.isValid(), return );
+
+ m_parameters = parameters;
+ m_parameters.workDirectory = workDirectory(parameters);
+ updateReparseParameters(reparseParameters);
+
+ m_reader.setParameters(m_parameters);
+
+ if (reparseParameters & REPARSE_URGENT) {
+ qCDebug(cmakeBuildSystemLog) << "calling requestReparse";
+ requestParse();
+ } else {
+ qCDebug(cmakeBuildSystemLog) << "calling requestDelayedReparse";
+ requestDelayedParse();
+ }
+}
+
+void CMakeBuildSystem::writeConfigurationIntoBuildDirectory(const Utils::MacroExpander *expander)
+{
+ QTC_ASSERT(expander, return );
+
+ const FilePath buildDir = workDirectory(m_parameters);
+ QTC_ASSERT(buildDir.exists(), return );
+
+ const FilePath settingsFile = buildDir.pathAppended("qtcsettings.cmake");
+
+ QByteArray contents;
+ contents.append("# This file is managed by Qt Creator, do not edit!\n\n");
+ contents.append(
+ transform(m_parameters.configuration,
+ [expander](const CMakeConfigItem &item) { return item.toCMakeSetLine(expander); })
+ .join('\n')
+ .toUtf8());
+
+ QFile file(settingsFile.toString());
+ QTC_ASSERT(file.open(QFile::WriteOnly | QFile::Truncate), return );
+ file.write(contents);
+}
+
void CMakeBuildSystem::runCMake()
{
- BuildDirParameters parameters(m_buildConfiguration);
+ BuildDirParameters parameters(cmakeBuildConfiguration());
qCDebug(cmakeBuildSystemLog) << "Requesting parse due \"Run CMake\" command";
- m_buildDirManager.setParametersAndRequestParse(parameters,
- BuildDirManager::REPARSE_CHECK_CONFIGURATION
- | BuildDirManager::REPARSE_FORCE_CMAKE_RUN
- | BuildDirManager::REPARSE_URGENT);
+ setParametersAndRequestParse(parameters,
+ REPARSE_CHECK_CONFIGURATION | REPARSE_FORCE_CMAKE_RUN
+ | REPARSE_URGENT);
}
void CMakeBuildSystem::runCMakeAndScanProjectTree()
{
- BuildDirParameters parameters(m_buildConfiguration);
+ BuildDirParameters parameters(cmakeBuildConfiguration());
qCDebug(cmakeBuildSystemLog) << "Requesting parse due to \"Rescan Project\" command";
- m_buildDirManager.setParametersAndRequestParse(parameters,
- BuildDirManager::REPARSE_CHECK_CONFIGURATION
- | BuildDirManager::REPARSE_SCAN);
+ setParametersAndRequestParse(parameters, REPARSE_CHECK_CONFIGURATION | REPARSE_SCAN);
}
void CMakeBuildSystem::buildCMakeTarget(const QString &buildTarget)
{
QTC_ASSERT(!buildTarget.isEmpty(), return);
- m_buildConfiguration->buildTarget(buildTarget);
+ cmakeBuildConfiguration()->buildTarget(buildTarget);
}
void CMakeBuildSystem::handleTreeScanningFinished()
@@ -338,45 +441,51 @@ void CMakeBuildSystem::handleTreeScanningFinished()
bool CMakeBuildSystem::persistCMakeState()
{
- return m_buildDirManager.persistCMakeState();
-}
-
-void CMakeBuildSystem::clearCMakeCache()
-{
- m_buildDirManager.clearCache();
-}
+ QTC_ASSERT(m_parameters.isValid(), return false);
-void CMakeBuildSystem::handleParsingSuccess()
-{
- QTC_ASSERT(m_waitingForParse, return );
+ if (m_parameters.workDirectory == m_parameters.buildDirectory)
+ return false;
- m_waitingForParse = false;
+ if (!buildConfiguration()->createBuildDirectory())
+ return false;
- combineScanAndParse();
+ BuildDirParameters newParameters = m_parameters;
+ newParameters.workDirectory.clear();
+ qCDebug(cmakeBuildSystemLog) << "Requesting parse due to persisting CMake State";
+ setParametersAndRequestParse(newParameters,
+ REPARSE_URGENT | REPARSE_FORCE_CMAKE_RUN
+ | REPARSE_FORCE_CONFIGURATION | REPARSE_CHECK_CONFIGURATION);
+ return true;
}
-void CMakeBuildSystem::handleParsingError()
+void CMakeBuildSystem::clearCMakeCache()
{
- QTC_CHECK(m_waitingForParse);
+ QTC_ASSERT(m_parameters.isValid(), return );
+ QTC_ASSERT(!m_isHandlingError, return );
- m_waitingForParse = false;
- m_combinedScanAndParseResult = false;
+ stopParsingAndClearState();
- combineScanAndParse();
+ const FilePath cmakeCache = m_parameters.workDirectory / "CMakeCache.txt";
+ const FilePath cmakeFiles = m_parameters.workDirectory / "CMakeFiles";
+
+ if (cmakeCache.exists())
+ Utils::FileUtils::removeRecursively(cmakeCache);
+ if (cmakeFiles.exists())
+ Utils::FileUtils::removeRecursively(cmakeFiles);
}
std::unique_ptr<CMakeProjectNode>
CMakeBuildSystem::generateProjectTree(const QList<const FileNode *> &allFiles)
{
QString errorMessage;
- auto root = m_buildDirManager.generateProjectTree(allFiles, errorMessage);
+ auto root = m_reader.generateProjectTree(allFiles, errorMessage);
checkAndReportError(errorMessage);
return root;
}
void CMakeBuildSystem::combineScanAndParse()
{
- if (m_buildConfiguration->isActive()) {
+ if (cmakeBuildConfiguration()->isActive()) {
if (m_waitingForParse || m_waitingForScan)
return;
@@ -386,6 +495,8 @@ void CMakeBuildSystem::combineScanAndParse()
}
}
+ m_reader.resetData();
+
m_currentGuard = {};
emitBuildSystemUpdated();
@@ -394,7 +505,7 @@ void CMakeBuildSystem::combineScanAndParse()
void CMakeBuildSystem::checkAndReportError(QString &errorMessage)
{
if (!errorMessage.isEmpty()) {
- m_buildConfiguration->setError(errorMessage);
+ cmakeBuildConfiguration()->setError(errorMessage);
errorMessage.clear();
}
}
@@ -403,15 +514,16 @@ void CMakeBuildSystem::updateProjectData()
{
qCDebug(cmakeBuildSystemLog) << "Updating CMake project data";
- QTC_ASSERT(m_treeScanner.isFinished() && !m_buildDirManager.isParsing(), return);
+ QTC_ASSERT(m_treeScanner.isFinished() && !m_reader.isParsing(), return );
- m_buildConfiguration->project()->setExtraProjectFiles(m_buildDirManager.projectFilesToWatch());
+ cmakeBuildConfiguration()->project()->setExtraProjectFiles(m_reader.projectFilesToWatch());
- CMakeConfig patchedConfig = m_buildConfiguration->configurationFromCMake();
+ CMakeConfig patchedConfig = cmakeBuildConfiguration()->configurationFromCMake();
{
CMakeConfigItem settingFileItem;
settingFileItem.key = "ANDROID_DEPLOYMENT_SETTINGS_FILE";
- settingFileItem.value = m_buildConfiguration->buildDirectory()
+ settingFileItem.value = cmakeBuildConfiguration()
+ ->buildDirectory()
.pathAppended("android_deployment_settings.json")
.toString()
.toUtf8();
@@ -473,9 +585,9 @@ void CMakeBuildSystem::updateProjectData()
{
QString errorMessage;
- RawProjectParts rpps = m_buildDirManager.createRawProjectParts(errorMessage);
+ RawProjectParts rpps = m_reader.createRawProjectParts(errorMessage);
if (!errorMessage.isEmpty())
- m_buildConfiguration->setError(errorMessage);
+ cmakeBuildConfiguration()->setError(errorMessage);
qCDebug(cmakeBuildSystemLog) << "Raw project parts created." << errorMessage;
for (RawProjectPart &rpp : rpps) {
@@ -487,65 +599,382 @@ void CMakeBuildSystem::updateProjectData()
rpp.setFlagsForC({kitInfo.cToolChain, rpp.flagsForC.commandLineFlags});
}
- m_cppCodeModelUpdater->update({p, kitInfo, m_buildConfiguration->environment(), rpps});
+ m_cppCodeModelUpdater->update({p, kitInfo, cmakeBuildConfiguration()->environment(), rpps});
}
{
updateQmlJSCodeModel();
}
- emit m_buildConfiguration->buildTypeChanged();
-
- m_buildDirManager.resetData();
+ emit cmakeBuildConfiguration()->buildTypeChanged();
qCDebug(cmakeBuildSystemLog) << "All CMake project data up to date.";
}
void CMakeBuildSystem::handleParsingSucceeded()
{
- if (!m_buildConfiguration->isActive()) {
- m_buildDirManager.stopParsingAndClearState();
+ if (!cmakeBuildConfiguration()->isActive()) {
+ stopParsingAndClearState();
return;
}
- m_buildConfiguration->clearError();
+ cmakeBuildConfiguration()->clearError();
QString errorMessage;
{
- m_buildTargets = m_buildDirManager.takeBuildTargets(errorMessage);
+ m_buildTargets = m_reader.takeBuildTargets(errorMessage);
checkAndReportError(errorMessage);
}
{
- const CMakeConfig cmakeConfig = m_buildDirManager.takeCMakeConfiguration(errorMessage);
+ CMakeConfig cmakeConfig = m_reader.takeParsedConfiguration(errorMessage);
+ for (auto &ci : cmakeConfig)
+ ci.inCMakeCache = true;
+ cmakeBuildConfiguration()->setConfigurationFromCMake(cmakeConfig);
checkAndReportError(errorMessage);
- m_buildConfiguration->setConfigurationFromCMake(cmakeConfig);
}
setApplicationTargets(appTargets());
setDeploymentData(deploymentData());
- handleParsingSuccess();
+ QTC_ASSERT(m_waitingForParse, return );
+ m_waitingForParse = false;
+
+ combineScanAndParse();
}
void CMakeBuildSystem::handleParsingFailed(const QString &msg)
{
- m_buildConfiguration->setError(msg);
+ cmakeBuildConfiguration()->setError(msg);
QString errorMessage;
- m_buildConfiguration->setConfigurationFromCMake(m_buildDirManager.takeCMakeConfiguration(errorMessage));
+ CMakeConfig cmakeConfig = m_reader.takeParsedConfiguration(errorMessage);
+ for (auto &ci : cmakeConfig)
+ ci.inCMakeCache = true;
+ cmakeBuildConfiguration()->setConfigurationFromCMake(cmakeConfig);
// ignore errorMessage here, we already got one.
- handleParsingError();
+ QTC_CHECK(m_waitingForParse);
+ m_waitingForParse = false;
+ m_combinedScanAndParseResult = false;
+
+ combineScanAndParse();
}
-BuildConfiguration *CMakeBuildSystem::buildConfiguration() const
+void CMakeBuildSystem::wireUpConnections(const Project *p)
{
- return m_buildConfiguration;
+ if (p != project())
+ return; // That's not us...
+
+ disconnect(SessionManager::instance(), nullptr, this, nullptr);
+
+ // 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...
+ // Build configuration has not changed, but Kit settings might have:
+ // reparse and check the configuration, independent of whether the reader has changed
+ qCDebug(cmakeBuildSystemLog) << "Requesting parse due to kit being updated";
+ setParametersAndRequestParse(BuildDirParameters(cmakeBuildConfiguration()),
+ CMakeBuildSystem::REPARSE_CHECK_CONFIGURATION);
+ });
+
+ // Became active/inactive:
+ connect(project(), &Project::activeTargetChanged, this, [this](Target *t) {
+ if (t == target()) {
+ // Build configuration has switched:
+ // * Check configuration if reader changes due to it not existing yet:-)
+ // * run cmake without configuration arguments if the reader stays
+ qCDebug(cmakeBuildSystemLog) << "Requesting parse due to active target changed";
+ setParametersAndRequestParse(BuildDirParameters(cmakeBuildConfiguration()),
+ CMakeBuildSystem::REPARSE_CHECK_CONFIGURATION);
+ } else {
+ stopParsingAndClearState();
+ }
+ });
+ connect(target(), &Target::activeBuildConfigurationChanged, this, [this](BuildConfiguration *bc) {
+ if (cmakeBuildConfiguration()->isActive()) {
+ if (cmakeBuildConfiguration() == bc) {
+ // Build configuration has switched:
+ // * Check configuration if reader changes due to it not existing yet:-)
+ // * run cmake without configuration arguments if the reader stays
+ qCDebug(cmakeBuildSystemLog) << "Requesting parse due to active BC changed";
+ setParametersAndRequestParse(BuildDirParameters(cmakeBuildConfiguration()),
+ CMakeBuildSystem::REPARSE_CHECK_CONFIGURATION);
+ } else {
+ stopParsingAndClearState();
+ }
+ }
+ });
+
+ // BuildConfiguration changed:
+ connect(cmakeBuildConfiguration(), &CMakeBuildConfiguration::environmentChanged, this, [this]() {
+ if (cmakeBuildConfiguration()->isActive()) {
+ // The environment on our BC has changed:
+ // * Error out if the reader updates, cannot happen since all BCs share a target/kit.
+ // * run cmake without configuration arguments if the reader stays
+ qCDebug(cmakeBuildSystemLog) << "Requesting parse due to environment change";
+ setParametersAndRequestParse(BuildDirParameters(cmakeBuildConfiguration()),
+ CMakeBuildSystem::REPARSE_CHECK_CONFIGURATION);
+ }
+ });
+ connect(cmakeBuildConfiguration(), &CMakeBuildConfiguration::buildDirectoryChanged, this, [this]() {
+ if (cmakeBuildConfiguration()->isActive()) {
+ // The build directory of our BC has changed:
+ // * Error out if the reader updates, cannot happen since all BCs share a target/kit.
+ // * run cmake without configuration arguments if the reader stays
+ // If no configuration exists, then the arguments will get added automatically by
+ // the reader.
+ qCDebug(cmakeBuildSystemLog) << "Requesting parse due to build directory change";
+ setParametersAndRequestParse(BuildDirParameters(cmakeBuildConfiguration()),
+ CMakeBuildSystem::REPARSE_CHECK_CONFIGURATION);
+ }
+ });
+ connect(cmakeBuildConfiguration(),
+ &CMakeBuildConfiguration::configurationForCMakeChanged,
+ this,
+ [this]() {
+ if (cmakeBuildConfiguration()->isActive()) {
+ // The CMake configuration has changed on our BC:
+ // * Error out if the reader updates, cannot happen since all BCs share a target/kit.
+ // * run cmake with configuration arguments if the reader stays
+ qCDebug(cmakeBuildSystemLog)
+ << "Requesting parse due to cmake configuration change";
+ setParametersAndRequestParse(BuildDirParameters(cmakeBuildConfiguration()),
+ CMakeBuildSystem::REPARSE_FORCE_CONFIGURATION);
+ }
+ });
+
+ connect(project(), &Project::projectFileIsDirty, this, [this]() {
+ if (cmakeBuildConfiguration()->isActive() && !isParsing()) {
+ const auto cmake = CMakeKitAspect::cmakeTool(cmakeBuildConfiguration()->target()->kit());
+ if (cmake && cmake->isAutoRun()) {
+ qCDebug(cmakeBuildSystemLog) << "Requesting parse due to dirty project file";
+ setParametersAndRequestParse(BuildDirParameters(cmakeBuildConfiguration()),
+ CMakeBuildSystem::REPARSE_DEFAULT);
+ }
+ }
+ });
+
+ // Force initial parsing run:
+ if (cmakeBuildConfiguration()->isActive())
+ setParametersAndRequestParse(BuildDirParameters(cmakeBuildConfiguration()),
+ CMakeBuildSystem::REPARSE_CHECK_CONFIGURATION);
+}
+
+FilePath CMakeBuildSystem::workDirectory(const BuildDirParameters &parameters)
+{
+ const Utils::FilePath bdir = parameters.buildDirectory;
+ const CMakeTool *cmake = parameters.cmakeTool();
+ if (bdir.exists()) {
+ m_buildDirToTempDir.erase(bdir);
+ return bdir;
+ }
+
+ if (cmake && cmake->autoCreateBuildDirectory()) {
+ if (!cmakeBuildConfiguration()->createBuildDirectory())
+ handleParsingFailed(
+ tr("Failed to create build directory \"%1\".").arg(bdir.toUserOutput()));
+ return bdir;
+ }
+
+ auto tmpDirIt = m_buildDirToTempDir.find(bdir);
+ if (tmpDirIt == m_buildDirToTempDir.end()) {
+ auto ret = m_buildDirToTempDir.emplace(
+ std::make_pair(bdir, std::make_unique<Utils::TemporaryDirectory>("qtc-cmake-XXXXXXXX")));
+ QTC_ASSERT(ret.second, return bdir);
+ tmpDirIt = ret.first;
+
+ if (!tmpDirIt->second->isValid()) {
+ handleParsingFailed(tr("Failed to create temporary directory \"%1\".")
+ .arg(QDir::toNativeSeparators(tmpDirIt->second->path())));
+ return bdir;
+ }
+ }
+ return Utils::FilePath::fromString(tmpDirIt->second->path());
+}
+
+void CMakeBuildSystem::stopParsingAndClearState()
+{
+ qCDebug(cmakeBuildSystemLog) << "stopping parsing run!";
+ m_reader.stop();
+ m_reader.resetData();
+}
+
+void CMakeBuildSystem::becameDirty()
+{
+ qCDebug(cmakeBuildSystemLog) << "CMakeBuildSystem: becameDirty was triggered.";
+ if (isParsing())
+ return;
+
+ const CMakeTool *tool = m_parameters.cmakeTool();
+ if (!tool->isAutoRun())
+ return;
+
+ setParametersAndRequestParse(BuildDirParameters(cmakeBuildConfiguration()),
+ REPARSE_CHECK_CONFIGURATION | REPARSE_SCAN);
+}
+
+void CMakeBuildSystem::updateReparseParameters(const int parameters)
+{
+ m_reparseParameters |= parameters;
+}
+
+int CMakeBuildSystem::takeReparseParameters()
+{
+ int result = m_reparseParameters;
+ m_reparseParameters = REPARSE_DEFAULT;
+ return result;
+}
+
+bool CMakeBuildSystem::hasConfigChanged()
+{
+ checkConfiguration();
+
+ const QByteArray GENERATOR_KEY = "CMAKE_GENERATOR";
+ const QByteArray EXTRA_GENERATOR_KEY = "CMAKE_EXTRA_GENERATOR";
+ const QByteArray CMAKE_COMMAND_KEY = "CMAKE_COMMAND";
+ const QByteArray CMAKE_C_COMPILER_KEY = "CMAKE_C_COMPILER";
+ const QByteArray CMAKE_CXX_COMPILER_KEY = "CMAKE_CXX_COMPILER";
+
+ const QByteArrayList criticalKeys = {GENERATOR_KEY,
+ CMAKE_COMMAND_KEY,
+ CMAKE_C_COMPILER_KEY,
+ CMAKE_CXX_COMPILER_KEY};
+
+ QString errorMessage;
+ const CMakeConfig currentConfig = cmakeBuildConfiguration()->configurationFromCMake();
+ if (!errorMessage.isEmpty())
+ return false;
+
+ const CMakeTool *tool = m_parameters.cmakeTool();
+ QTC_ASSERT(tool,
+ return false); // No cmake... we should not have ended up here in the first place
+ const QString extraKitGenerator = m_parameters.extraGenerator;
+ const QString mainKitGenerator = m_parameters.generator;
+ CMakeConfig targetConfig = m_parameters.configuration;
+ targetConfig.append(CMakeConfigItem(GENERATOR_KEY,
+ CMakeConfigItem::INTERNAL,
+ QByteArray(),
+ mainKitGenerator.toUtf8()));
+ if (!extraKitGenerator.isEmpty())
+ targetConfig.append(CMakeConfigItem(EXTRA_GENERATOR_KEY,
+ CMakeConfigItem::INTERNAL,
+ QByteArray(),
+ extraKitGenerator.toUtf8()));
+ targetConfig.append(CMakeConfigItem(CMAKE_COMMAND_KEY,
+ CMakeConfigItem::INTERNAL,
+ QByteArray(),
+ tool->cmakeExecutable().toUserOutput().toUtf8()));
+ Utils::sort(targetConfig, CMakeConfigItem::sortOperator());
+
+ bool mustReparse = false;
+ auto ccit = currentConfig.constBegin();
+ auto kcit = targetConfig.constBegin();
+
+ while (ccit != currentConfig.constEnd() && kcit != targetConfig.constEnd()) {
+ if (ccit->key == kcit->key) {
+ if (ccit->value != kcit->value) {
+ if (criticalKeys.contains(kcit->key)) {
+ clearCMakeCache();
+ return false; // no need to trigger a new reader, clearCache will do that
+ }
+ mustReparse = true;
+ }
+ ++ccit;
+ ++kcit;
+ } else {
+ if (ccit->key < kcit->key) {
+ ++ccit;
+ } else {
+ ++kcit;
+ mustReparse = true;
+ }
+ }
+ }
+
+ // If we have keys that do not exist yet, then reparse.
+ //
+ // The critical keys *must* be set in cmake configuration, so those were already
+ // handled above.
+ return mustReparse || kcit != targetConfig.constEnd();
+}
+
+bool CMakeBuildSystem::checkConfiguration()
+{
+ if (m_parameters.workDirectory
+ != m_parameters.buildDirectory) // always throw away changes in the tmpdir!
+ return false;
+
+ const CMakeConfig cache = cmakeBuildConfiguration()->configurationFromCMake();
+ if (cache.isEmpty())
+ return false; // No cache file yet.
+
+ CMakeConfig newConfig;
+ QHash<QString, QPair<QString, QString>> changedKeys;
+ foreach (const CMakeConfigItem &projectItem, m_parameters.configuration) {
+ const QString projectKey = QString::fromUtf8(projectItem.key);
+ const QString projectValue = projectItem.expandedValue(m_parameters.expander);
+ const CMakeConfigItem &cmakeItem = Utils::findOrDefault(cache,
+ [&projectItem](
+ const CMakeConfigItem &i) {
+ return i.key == projectItem.key;
+ });
+ const QString iCacheValue = QString::fromUtf8(cmakeItem.value);
+ if (cmakeItem.isNull()) {
+ changedKeys.insert(projectKey, qMakePair(tr("<removed>"), projectValue));
+ } else if (iCacheValue != projectValue) {
+ changedKeys.insert(projectKey, qMakePair(iCacheValue, projectValue));
+ newConfig.append(cmakeItem);
+ } else {
+ newConfig.append(projectItem);
+ }
+ }
+
+ if (!changedKeys.isEmpty()) {
+ QStringList keyList = changedKeys.keys();
+ Utils::sort(keyList);
+ QString table = QString::fromLatin1("<table><tr><th>%1</th><th>%2</th><th>%3</th></tr>")
+ .arg(tr("Key"))
+ .arg(tr("%1 Project").arg(Core::Constants::IDE_DISPLAY_NAME))
+ .arg(tr("Changed value"));
+ foreach (const QString &k, keyList) {
+ const QPair<QString, QString> data = changedKeys.value(k);
+ table += QString::fromLatin1("\n<tr><td>%1</td><td>%2</td><td>%3</td></tr>")
+ .arg(k)
+ .arg(data.second.toHtmlEscaped())
+ .arg(data.first.toHtmlEscaped());
+ }
+ table += QLatin1String("\n</table>");
+
+ QPointer<QMessageBox> box = new QMessageBox(Core::ICore::mainWindow());
+ box->setText(tr("The project has been changed outside of %1.")
+ .arg(Core::Constants::IDE_DISPLAY_NAME));
+ box->setInformativeText(table);
+ auto *defaultButton = box->addButton(tr("Discard External Changes"),
+ QMessageBox::RejectRole);
+ auto *applyButton = box->addButton(tr("Adapt %1 Project to Changes")
+ .arg(Core::Constants::IDE_DISPLAY_NAME),
+ QMessageBox::ApplyRole);
+ box->setDefaultButton(defaultButton);
+
+ box->exec();
+ if (box->clickedButton() == applyButton) {
+ m_parameters.configuration = newConfig;
+ QSignalBlocker blocker(buildConfiguration());
+ cmakeBuildConfiguration()->setConfigurationForCMake(newConfig);
+ return false;
+ } else if (box->clickedButton() == defaultButton)
+ return true;
+ }
+ return false;
}
CMakeBuildConfiguration *CMakeBuildSystem::cmakeBuildConfiguration() const
{
- return m_buildConfiguration;
+ return static_cast<CMakeBuildConfiguration *>(BuildSystem::buildConfiguration());
}
static Utils::FilePaths librarySearchPaths(const CMakeBuildSystem *bs, const QString &buildKey)
@@ -559,8 +988,8 @@ static Utils::FilePaths librarySearchPaths(const CMakeBuildSystem *bs, const QSt
const QList<BuildTargetInfo> CMakeBuildSystem::appTargets() const
{
QList<BuildTargetInfo> appTargetList;
- const bool forAndroid = DeviceTypeKitAspect::deviceTypeId(target()->kit())
- == Android::Constants::ANDROID_DEVICE_TYPE;
+ const bool forAndroid = DeviceTypeKitAspect::deviceTypeId(kit())
+ == Android::Constants::ANDROID_DEVICE_TYPE;
for (const CMakeBuildTarget &ct : m_buildTargets) {
if (ct.targetType == UtilityType)
continue;
@@ -601,12 +1030,26 @@ const QList<CMakeBuildTarget> &CMakeBuildSystem::buildTargets() const
return m_buildTargets;
}
+CMakeConfig CMakeBuildSystem::parseCMakeCacheDotTxt(const Utils::FilePath &cacheFile,
+ QString *errorMessage)
+{
+ if (!cacheFile.exists()) {
+ if (errorMessage)
+ *errorMessage = tr("CMakeCache.txt file not found.");
+ return {};
+ }
+ CMakeConfig result = CMakeConfigItem::itemsFromFile(cacheFile, errorMessage);
+ if (!errorMessage->isEmpty())
+ return {};
+ return result;
+}
+
DeploymentData CMakeBuildSystem::deploymentData() const
{
DeploymentData result;
- QDir sourceDir = target()->project()->projectDirectory().toString();
- QDir buildDir = buildConfiguration()->buildDirectory().toString();
+ QDir sourceDir = project()->projectDirectory().toString();
+ QDir buildDir = cmakeBuildConfiguration()->buildDirectory().toString();
QString deploymentPrefix;
QString deploymentFilePath = sourceDir.filePath("QtCreatorDeployment.txt");
@@ -705,7 +1148,7 @@ void CMakeBuildSystem::updateQmlJSCodeModel()
projectInfo.importPaths.clear();
- const CMakeConfig &cm = m_buildConfiguration->configurationFromCMake();
+ const CMakeConfig &cm = cmakeBuildConfiguration()->configurationFromCMake();
const QString cmakeImports = QString::fromUtf8(CMakeConfigItem::valueOf("QML_IMPORT_PATH", cm));
foreach (const QString &cmakeImport, CMakeConfigItem::cmakeSplitValue(cmakeImports))
diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.h b/src/plugins/cmakeprojectmanager/cmakebuildsystem.h
index ad119ab4ab..5ada71513c 100644
--- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.h
+++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.h
@@ -25,10 +25,17 @@
#pragma once
-#include "builddirmanager.h"
+#include "builddirparameters.h"
+#include "cmakebuildtarget.h"
+#include "cmakeprojectnodes.h"
+#include "fileapireader.h"
+#include "utils/macroexpander.h"
#include <projectexplorer/buildsystem.h>
+#include <utils/fileutils.h>
+#include <utils/temporarydirectory.h>
+
namespace ProjectExplorer { class ExtraCompiler; }
namespace CppTools {
@@ -36,10 +43,8 @@ class CppProjectUpdater;
} // namespace CppTools
namespace CMakeProjectManager {
-
-class CMakeProject;
-
namespace Internal {
+
class CMakeBuildConfiguration;
// --------------------------------------------------------------------
@@ -65,36 +70,59 @@ public:
QStringList filesGeneratedFrom(const QString &sourceFile) const final;
+ // Actions:
void runCMake();
void runCMakeAndScanProjectTree();
- // Context menu actions:
- void buildCMakeTarget(const QString &buildTarget);
- // Treescanner states:
- void handleTreeScanningFinished();
-
bool persistCMakeState();
void clearCMakeCache();
- // Parser states:
- void handleParsingSuccess();
- void handleParsingError();
-
- ProjectExplorer::BuildConfiguration *buildConfiguration() const;
- CMakeBuildConfiguration *cmakeBuildConfiguration() const;
+ // Context menu actions:
+ void buildCMakeTarget(const QString &buildTarget);
+ // Queries:
const QList<ProjectExplorer::BuildTargetInfo> appTargets() const;
QStringList buildTargetTitles() const;
const QList<CMakeBuildTarget> &buildTargets() const;
ProjectExplorer::DeploymentData deploymentData() const;
+ CMakeBuildConfiguration *cmakeBuildConfiguration() const;
+
+ // Generic CMake helper functions:
+ static CMakeConfig parseCMakeCacheDotTxt(const Utils::FilePath &cacheFile,
+ QString *errorMessage);
+
private:
- std::unique_ptr<CMakeProjectNode> generateProjectTree(
- const QList<const ProjectExplorer::FileNode *> &allFiles);
+ // Actually ask for parsing:
+ enum ReparseParameters {
+ REPARSE_DEFAULT = 0, // Nothing special:-)
+ REPARSE_FORCE_CMAKE_RUN = (1 << 0), // Force cmake to run
+ REPARSE_FORCE_CONFIGURATION = (1 << 1), // Force configuration arguments to cmake
+ REPARSE_CHECK_CONFIGURATION
+ = (1 << 2), // Check for on-disk config and QtC config diff // FIXME: Remove this!
+ REPARSE_SCAN = (1 << 3), // Run filesystem scan
+ REPARSE_URGENT = (1 << 4), // Do not delay the parser run by 1s
+ };
+ QString reparseParametersString(int reparseFlags);
+ void setParametersAndRequestParse(const BuildDirParameters &parameters,
+ const int reparseParameters);
+
+ void writeConfigurationIntoBuildDirectory(const Utils::MacroExpander *expander);
+
+ // State handling:
+ // Parser states:
+ void handleParsingSuccess();
+ void handleParsingError();
+
+ // Treescanner states:
+ void handleTreeScanningFinished();
// Combining Treescanner and Parser states:
void combineScanAndParse();
+ std::unique_ptr<CMakeProjectNode> generateProjectTree(
+ const QList<const ProjectExplorer::FileNode *> &allFiles);
+
void checkAndReportError(QString &errorMessage);
void updateProjectData();
@@ -104,8 +132,14 @@ private:
void handleParsingSucceeded();
void handleParsingFailed(const QString &msg);
- CMakeBuildConfiguration *m_buildConfiguration = nullptr;
- BuildDirManager m_buildDirManager;
+ void wireUpConnections(const ProjectExplorer::Project *p);
+
+ Utils::FilePath workDirectory(const BuildDirParameters &parameters);
+ void stopParsingAndClearState();
+ void becameDirty();
+
+ void updateReparseParameters(const int parameters);
+ int takeReparseParameters();
ProjectExplorer::TreeScanner m_treeScanner;
QHash<QString, bool> m_mimeBinaryCache;
@@ -120,6 +154,17 @@ private:
CppTools::CppProjectUpdater *m_cppCodeModelUpdater = nullptr;
QList<ProjectExplorer::ExtraCompiler *> m_extraCompilers;
QList<CMakeBuildTarget> m_buildTargets;
+
+ bool checkConfiguration();
+ bool hasConfigChanged();
+
+ // Parsing state:
+ BuildDirParameters m_parameters;
+ int m_reparseParameters;
+ mutable std::unordered_map<Utils::FilePath, std::unique_ptr<Utils::TemporaryDirectory>>
+ m_buildDirToTempDir;
+ FileApiReader m_reader;
+ mutable bool m_isHandlingError = false;
};
} // namespace Internal
diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.md b/src/plugins/cmakeprojectmanager/cmakebuildsystem.md
new file mode 100644
index 0000000000..ff42461bb1
--- /dev/null
+++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.md
@@ -0,0 +1,150 @@
+# `CMakeBuildSystem`
+
+## Big Picture: `BuildSystem`
+
+This is a sequence diagram of how `ProjectExplorer::BuildSystem` interacts with
+its implementations:
+
+```mermaid
+sequenceDiagram
+ User ->> BuildSystemImpl: provide data and ask for parse (impl. defined!)
+ BuildSystemImpl ->> BuildSystem: call requestParse() or requestDelayedParse()
+ activate BuildSystem
+ BuildSystem ->> BuildSys tem: m_delayedParsingTimer sends timeout()
+ BuildSystem ->> BuildSystemImpl: call triggerParsing()
+ deactivate BuildSystem
+ activate BuildSystemImpl
+ BuildSystemImpl ->> BuildSystem: call guardParsingRun()
+ activate BuildSystem
+ BuildSystem ->> ParseGuard: Construct
+ activate ParseGuard
+ ParseGuard ->> BuildSystem: call emitParsingStarted
+ BuildSystem ->> User: signal parsingStarted()
+ BuildSystem ->> BuildSystemImpl: Hand over ParseGuard
+ deactivate BuildSystem
+ BuildSystemImpl ->> BuildSystemImpl: Do parsing
+ opt Report Success
+ BuildSystemImpl ->> ParseGuard: markAsSuccess()
+ end
+ BuildSystemImpl ->> ParseGuard: Destruct
+ ParseGuard ->> BuildSystem: emitParsingFinished()
+ activate BuildSystem
+ BuildSystem ->> User: Signal ParsingFinished(...)
+ deactivate BuildSystem
+ deactivate ParseGuard
+ deactivate BuildSystemImpl
+```
+
+## The Details of `CMakeBuildSystem`
+
+### States Overview
+
+```mermaid
+graph TD
+ parse --> TreeScanner::asyncScanForFiles
+
+ parse --> FileApiReader::parse
+ FileApiReader::parse --> handleParsingSucceeded
+ handleParsingSucceeded --> combineScanAndParse
+ FileApiReader::parse --> handleParsingFailed
+ handleParsingFailed --> combineScanAndParse
+
+ TreeScanner::asyncScanForFiles --> handleTreeScanningFinished
+ handleTreeScanningFinished --> combineScanAndParse
+```
+
+### Full Sequence Diagram
+
+```mermaid
+sequenceDiagram
+ participant User
+ participant ParseGuard
+ participant CMakeBuildSystem
+ participant FileApiReader
+
+ alt Trigger Parsing
+ User ->> CMakeBuildSystem: Any of the Actions defined for CMakeBuildSystem
+ else
+ User ->> CMakeBuildSystem: Signal from outside the CMakeBuildSystem
+ end
+ activate CMakeBuildSystem
+ CMakeBuildSystem ->> CMakeBuildSystem: call setParametersAndRequestReparse()
+ CMakeBuildSystem ->> CMakeBuildSystem: Validate parameters
+ CMakeBuildSystem ->> FileApiReader: Construct
+ activate FileApiReader
+ CMakeBuildSystem ->> FileApiReader: call setParameters
+ CMakeBuildSystem ->> CMakeBuildSystem: call request*Reparse()
+ deactivate CMakeBuildSystem
+
+ CMakeBuildSystem ->> CMakeBuildSystem: m_delayedParsingTimer sends timeout() triggering triggerParsing()
+
+ activate CMakeBuildSystem
+
+ CMakeBuildSystem ->>+ CMakeBuildSystem: call guardParsingRun()
+ CMakeBuildSystem ->> ParseGuard: Construct
+ activate ParseGuard
+ ParseGuard ->> CMakeBuildSystem: call emitParsingStarted
+ CMakeBuildSystem ->> User: signal parsingStarted()
+ CMakeBuildSystem ->>- CMakeBuildSystem: Hand over ParseGuard
+
+ CMakeBuildSystem ->>+ TreeScanner: call asyncScanForFiles()
+
+ CMakeBuildSystem ->>+ FileApiReader: call parse(...)
+ FileApiReader ->> FileApiReader: startState()
+ deactivate CMakeBuildSystem
+
+ opt Parse
+ FileApiReader ->> FileApiReader: call startCMakeState(...)
+ FileApiReader ->> FileApiReader: call cmakeFinishedState(...)
+ end
+
+ FileApiReader ->> FileApiReader: call endState(...)
+
+ alt Return Result from FileApiReader
+ FileApiReader ->> CMakeBuildSystem: signal dataAvailable() and trigger handleParsingSucceeded()
+ CMakeBuildSystem ->> FileApiReader: call takeBuildTargets()
+ CMakeBuildSystem ->> FileApiReader: call takeParsedConfiguration(....)
+ else
+ FileApiReader ->> CMakeBuildSystem: signal errorOccurred(...) and trigger handelParsingFailed(...)
+ CMakeBuildSystem ->> FileApiReader: call takeParsedConfiguration(....)
+ end
+
+ deactivate FileApiReader
+ Note right of CMakeBuildSystem: TreeScanner is still missing here
+ CMakeBuildSystem ->> CMakeBuildSystem: call combineScanAndParse()
+
+ TreeScanner ->> CMakeBuildSystem: signal finished() triggering handleTreeScanningFinished()
+ CMakeBuildSystem ->> TreeScanner: call release() to get files
+ deactivate TreeScanner
+ Note right of CMakeBuildSystem: All results are in now...
+ CMakeBuildSystem ->> CMakeBuildSystem: call combineScanAndParse()
+
+ activate CMakeBuildSystem
+ opt: Parsing was a success
+ CMakeBuildSystem ->> CMakeBuildSystem: call updateProjectData()
+ CMakeBuildSystem ->> FileApiReader: call projectFilesToWatch()
+ CMakeBuildSystem ->> FileApiReader: call createRawProjectParts(...)
+ CMakeBuildSystem ->> FileApiReader: call resetData()
+ CMakeBuildSystem ->> ParseGuard: call markAsSuccess()
+ end
+
+ CMakeBuildSystem ->> ParseGuard: Destruct
+ deactivate ParseGuard
+
+ CMakeBuildSystem ->> CMakeBuildSystem: call emitBuildSystemUpdated()
+ deactivate FileApiReader
+ deactivate CMakeBuildSystem
+```
+
+# `FileApiReader`
+
+States in the `FileApiReader`.
+
+```mermaid
+graph TD
+ startState --> startCMakeState
+ startState --> endState
+ startCMakeState --> cmakeFinishedState
+ cmakeFinishedState --> endState
+```
+
diff --git a/src/plugins/cmakeprojectmanager/cmakecbpparser.cpp b/src/plugins/cmakeprojectmanager/cmakecbpparser.cpp
deleted file mode 100644
index 11f472cd51..0000000000
--- a/src/plugins/cmakeprojectmanager/cmakecbpparser.cpp
+++ /dev/null
@@ -1,511 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "cmakecbpparser.h"
-#include "cmakekitinformation.h"
-#include "cmaketool.h"
-
-#include <utils/fileutils.h>
-#include <utils/stringutils.h>
-#include <utils/algorithm.h>
-#include <projectexplorer/projectmacro.h>
-#include <projectexplorer/projectnodes.h>
-
-#include <QLoggingCategory>
-
-using namespace ProjectExplorer;
-using namespace Utils;
-
-namespace CMakeProjectManager {
-namespace Internal {
-
-/////
-// CMakeCbpParser
-////
-
-namespace {
-int distance(const FilePath &targetDirectory, const FilePath &fileName)
-{
- const QString commonParent = commonPath(QStringList({targetDirectory.toString(), fileName.toString()}));
- return targetDirectory.toString().midRef(commonParent.size()).count('/')
- + fileName.toString().midRef(commonParent.size()).count('/');
-}
-} // namespace
-
-// called after everything is parsed
-// this function tries to figure out to which CMakeBuildTarget
-// each file belongs, so that it gets the appropriate defines and
-// compiler flags
-void CMakeCbpParser::sortFiles()
-{
- QLoggingCategory log("qtc.cmakeprojectmanager.filetargetmapping", QtWarningMsg);
- FilePaths fileNames = transform<QList>(m_fileList, &FileNode::filePath);
-
- sort(fileNames);
-
- CMakeBuildTarget *last = nullptr;
- FilePath parentDirectory;
-
- qCDebug(log) << "###############";
- qCDebug(log) << "# Pre Dump #";
- qCDebug(log) << "###############";
- foreach (const CMakeBuildTarget &target, m_buildTargets)
- qCDebug(log) << target.title << target.sourceDirectory << target.includeFiles
- << ProjectExplorer::Macro::toByteArray(target.macros)
- << target.files << "\n";
-
- // find a good build target to fall back
- int fallbackIndex = 0;
- {
- int bestIncludeCount = -1;
- for (int i = 0; i < m_buildTargets.size(); ++i) {
- const CMakeBuildTarget &target = m_buildTargets.at(i);
- if (target.includeFiles.isEmpty())
- continue;
- if (target.sourceDirectory == m_sourceDirectory
- && target.includeFiles.count() > bestIncludeCount) {
- bestIncludeCount = target.includeFiles.count();
- fallbackIndex = i;
- }
- }
- }
-
- qCDebug(log) << "###############";
- qCDebug(log) << "# Sorting #";
- qCDebug(log) << "###############";
-
- foreach (const FilePath &fileName, fileNames) {
- qCDebug(log) << fileName;
- const QStringList unitTargets = m_unitTargetMap[fileName];
- if (!unitTargets.isEmpty()) {
- // cmake >= 3.3:
- foreach (const QString &unitTarget, unitTargets) {
- int index = indexOf(m_buildTargets, equal(&CMakeBuildTarget::title, unitTarget));
- if (index != -1) {
- m_buildTargets[index].files.append(fileName);
- qCDebug(log) << " into" << m_buildTargets[index].title << "(target attribute)";
- continue;
- }
- }
- continue;
- }
-
- // fallback for cmake < 3.3:
- if (fileName.parentDir() == parentDirectory && last) {
- // easy case, same parent directory as last file
- last->files.append(fileName);
- qCDebug(log) << " into" << last->title << "(same parent)";
- } else {
- int bestDistance = std::numeric_limits<int>::max();
- int bestIndex = -1;
- int bestIncludeCount = -1;
-
- for (int i = 0; i < m_buildTargets.size(); ++i) {
- const CMakeBuildTarget &target = m_buildTargets.at(i);
- if (target.includeFiles.isEmpty())
- continue;
- int dist = distance(target.sourceDirectory, fileName);
- qCDebug(log) << "distance to target" << target.title << dist;
- if (dist < bestDistance ||
- (dist == bestDistance &&
- target.includeFiles.count() > bestIncludeCount)) {
- bestDistance = dist;
- bestIncludeCount = target.includeFiles.count();
- bestIndex = i;
- }
- }
-
- if (bestIndex == -1 && !m_buildTargets.isEmpty()) {
- bestIndex = fallbackIndex;
- qCDebug(log) << " using fallbackIndex";
- }
-
- if (bestIndex != -1) {
- m_buildTargets[bestIndex].files.append(fileName);
- last = &m_buildTargets[bestIndex];
- parentDirectory = fileName.parentDir();
- qCDebug(log) << " into" << last->title;
- }
- }
- }
-
- qCDebug(log) << "###############";
- qCDebug(log) << "# After Dump #";
- qCDebug(log) << "###############";
- foreach (const CMakeBuildTarget &target, m_buildTargets)
- qCDebug(log) << target.title << target.sourceDirectory << target.includeFiles
- << ProjectExplorer::Macro::toByteArray(target.macros)
- << target.files << "\n";
-}
-
-bool CMakeCbpParser::parseCbpFile(CMakeTool::PathMapper mapper, const FilePath &fileName,
- const FilePath &sourceDirectory)
-{
-
- m_pathMapper = mapper;
- m_buildDirectory = FilePath::fromString(fileName.toFileInfo().absolutePath());
- m_sourceDirectory = sourceDirectory;
-
- QFile fi(fileName.toString());
- if (fi.exists() && fi.open(QFile::ReadOnly)) {
- setDevice(&fi);
-
- while (!atEnd()) {
- readNext();
- if (name() == "CodeBlocks_project_file")
- parseCodeBlocks_project_file();
- else if (isStartElement())
- parseUnknownElement();
- }
-
- sortFiles();
-
- fi.close();
-
- return true;
- }
- return false;
-}
-
-void CMakeCbpParser::parseCodeBlocks_project_file()
-{
- while (!atEnd()) {
- readNext();
- if (isEndElement())
- return;
- else if (name() == "Project")
- parseProject();
- else if (isStartElement())
- parseUnknownElement();
- }
-}
-
-void CMakeCbpParser::parseProject()
-{
- while (!atEnd()) {
- readNext();
- if (isEndElement())
- return;
- else if (name() == "Option")
- parseOption();
- else if (name() == "Unit")
- parseUnit();
- else if (name() == "Build")
- parseBuild();
- else if (isStartElement())
- parseUnknownElement();
- }
-}
-
-void CMakeCbpParser::parseBuild()
-{
- while (!atEnd()) {
- readNext();
- if (isEndElement())
- return;
- else if (name() == "Target")
- parseBuildTarget();
- else if (isStartElement())
- parseUnknownElement();
- }
-}
-
-void CMakeCbpParser::parseBuildTarget()
-{
- m_buildTarget = CMakeBuildTarget();
-
- if (attributes().hasAttribute("title"))
- m_buildTarget.title = attributes().value("title").toString();
- while (!atEnd()) {
- readNext();
- if (isEndElement()) {
- if (!m_buildTarget.title.endsWith("/fast")
- && !m_buildTarget.title.endsWith("_automoc")) {
- if (m_buildTarget.executable.isEmpty() && m_buildTarget.targetType == ExecutableType)
- m_buildTarget.targetType = UtilityType;
- m_buildTargets.append(m_buildTarget);
- }
- return;
- } else if (name() == "Compiler") {
- parseCompiler();
- } else if (name() == "Option") {
- parseBuildTargetOption();
- } else if (name() == "MakeCommands") {
- parseMakeCommands();
- } else if (isStartElement()) {
- parseUnknownElement();
- }
- }
-}
-
-void CMakeCbpParser::parseBuildTargetOption()
-{
- if (attributes().hasAttribute("output")) {
- m_buildTarget.executable = m_pathMapper(FilePath::fromString(attributes().value("output").toString()));
- } else if (attributes().hasAttribute("type")) {
- const QStringRef value = attributes().value("type");
- if (value == "0" || value == "1")
- m_buildTarget.targetType = ExecutableType;
- else if (value == "2")
- m_buildTarget.targetType = StaticLibraryType;
- else if (value == "3")
- m_buildTarget.targetType = DynamicLibraryType;
- else
- m_buildTarget.targetType = UtilityType;
- } else if (attributes().hasAttribute("working_dir")) {
- m_buildTarget.workingDirectory = FilePath::fromUserInput(attributes().value("working_dir").toString());
-
- QFile cmakeSourceInfoFile(m_buildTarget.workingDirectory.toString()
- + QStringLiteral("/CMakeFiles/CMakeDirectoryInformation.cmake"));
- if (cmakeSourceInfoFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
- QTextStream stream(&cmakeSourceInfoFile);
- const QLatin1String searchSource("SET(CMAKE_RELATIVE_PATH_TOP_SOURCE \"");
- while (!stream.atEnd()) {
- const QString lineTopSource = stream.readLine().trimmed();
- if (lineTopSource.startsWith(searchSource, Qt::CaseInsensitive)) {
- QString src = lineTopSource.mid(searchSource.size());
- src.chop(2);
- m_buildTarget.sourceDirectory = FilePath::fromString(src);
- break;
- }
- }
- }
-
- if (m_buildTarget.sourceDirectory.isEmpty()) {
- QDir dir(m_buildDirectory.toString());
- const QString relative = dir.relativeFilePath(m_buildTarget.workingDirectory.toString());
- m_buildTarget.sourceDirectory = m_sourceDirectory.pathAppended(relative);
- }
- }
- while (!atEnd()) {
- readNext();
- if (isEndElement())
- return;
- else if (isStartElement())
- parseUnknownElement();
- }
-}
-
-QString CMakeCbpParser::projectName() const
-{
- return m_projectName;
-}
-
-void CMakeCbpParser::parseOption()
-{
- if (attributes().hasAttribute("title"))
- m_projectName = attributes().value("title").toString();
-
- if (attributes().hasAttribute("compiler"))
- m_compiler = attributes().value("compiler").toString();
-
- while (!atEnd()) {
- readNext();
- if (isEndElement())
- return;
- else if (isStartElement())
- parseUnknownElement();
- }
-}
-
-void CMakeCbpParser::parseMakeCommands()
-{
- while (!atEnd()) {
- readNext();
- if (isEndElement())
- return;
- else if (name() == "Build")
- parseBuildTargetBuild();
- else if (name() == "Clean")
- parseBuildTargetClean();
- else if (isStartElement())
- parseUnknownElement();
- }
-}
-
-void CMakeCbpParser::parseBuildTargetBuild()
-{
- if (attributes().hasAttribute("command"))
- m_buildTarget.makeCommand = m_pathMapper(FilePath::fromUserInput(attributes().value("command").toString()));
- while (!atEnd()) {
- readNext();
- if (isEndElement())
- return;
- else if (isStartElement())
- parseUnknownElement();
- }
-}
-
-void CMakeCbpParser::parseBuildTargetClean()
-{
- while (!atEnd()) {
- readNext();
- if (isEndElement())
- return;
- else if (isStartElement())
- parseUnknownElement();
- }
-}
-
-void CMakeCbpParser::parseCompiler()
-{
- while (!atEnd()) {
- readNext();
- if (isEndElement())
- return;
- else if (name() == "Add")
- parseAdd();
- else if (isStartElement())
- parseUnknownElement();
- }
-}
-
-void CMakeCbpParser::parseAdd()
-{
- // CMake only supports <Add option=\> and <Add directory=\>
- const QXmlStreamAttributes addAttributes = attributes();
-
- FilePath includeDirectory
- = m_pathMapper(FilePath::fromString(addAttributes.value("directory").toString()));
-
- // allow adding multiple times because order happens
- if (!includeDirectory.isEmpty())
- m_buildTarget.includeFiles.append(includeDirectory);
-
- QString compilerOption = addAttributes.value("option").toString();
- // defining multiple times a macro to the same value makes no sense
- if (!compilerOption.isEmpty() && !m_buildTarget.compilerOptions.contains(compilerOption)) {
- m_buildTarget.compilerOptions.append(compilerOption);
- int macroNameIndex = compilerOption.indexOf("-D") + 2;
- if (macroNameIndex != 1) {
- const QString keyValue = compilerOption.mid(macroNameIndex);
- m_buildTarget.macros.append(ProjectExplorer::Macro::fromKeyValue(keyValue));
- }
- }
-
- while (!atEnd()) {
- readNext();
- if (isEndElement())
- return;
- else if (isStartElement())
- parseUnknownElement();
- }
-}
-
-void CMakeCbpParser::parseUnit()
-{
- FilePath fileName =
- m_pathMapper(FilePath::fromUserInput(attributes().value("filename").toString()));
-
- m_parsingCMakeUnit = false;
- m_unitTargets.clear();
- while (!atEnd()) {
- readNext();
- if (isEndElement()) {
- if (!fileName.endsWith(".rule") && !m_processedUnits.contains(fileName)) {
- // Now check whether we found a virtual element beneath
- if (m_parsingCMakeUnit) {
- m_cmakeFileList.emplace_back(
- std::make_unique<FileNode>(fileName, FileType::Project));
- } else {
- bool generated = false;
- QString onlyFileName = fileName.fileName();
- if ( (onlyFileName.startsWith("moc_") && onlyFileName.endsWith(".cxx"))
- || (onlyFileName.startsWith("ui_") && onlyFileName.endsWith(".h"))
- || (onlyFileName.startsWith("qrc_") && onlyFileName.endsWith(".cxx")))
- generated = true;
-
- if (fileName.endsWith(".qrc")) {
- m_fileList.emplace_back(
- std::make_unique<FileNode>(fileName, FileType::Resource));
- } else {
- m_fileList.emplace_back(
- std::make_unique<FileNode>(fileName, FileType::Source));
- }
- m_fileList.back()->setIsGenerated(generated);
- }
- m_unitTargetMap.insert(fileName, m_unitTargets);
- m_processedUnits.insert(fileName);
- }
- return;
- } else if (name() == "Option") {
- parseUnitOption();
- } else if (isStartElement()) {
- parseUnknownElement();
- }
- }
-}
-
-void CMakeCbpParser::parseUnitOption()
-{
- const QXmlStreamAttributes optionAttributes = attributes();
- m_parsingCMakeUnit = optionAttributes.hasAttribute("virtualFolder");
- const QString target = optionAttributes.value("target").toString();
- if (!target.isEmpty())
- m_unitTargets.append(target);
-
- while (!atEnd()) {
- readNext();
-
- if (isEndElement())
- break;
-
- if (isStartElement())
- parseUnknownElement();
- }
-}
-
-void CMakeCbpParser::parseUnknownElement()
-{
- Q_ASSERT(isStartElement());
-
- while (!atEnd()) {
- readNext();
-
- if (isEndElement())
- break;
-
- if (isStartElement())
- parseUnknownElement();
- }
-}
-
-bool CMakeCbpParser::hasCMakeFiles()
-{
- return m_cmakeFileList.size() > 0;
-}
-
-QList<CMakeBuildTarget> CMakeCbpParser::buildTargets()
-{
- return m_buildTargets;
-}
-
-QString CMakeCbpParser::compilerName() const
-{
- return m_compiler;
-}
-
-} // namespace Internal
-} // namespace CMakeProjectManager
diff --git a/src/plugins/cmakeprojectmanager/cmakecbpparser.h b/src/plugins/cmakeprojectmanager/cmakecbpparser.h
deleted file mode 100644
index 8a8d5fbe7f..0000000000
--- a/src/plugins/cmakeprojectmanager/cmakecbpparser.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "cmakeproject.h"
-#include "cmaketool.h"
-
-#include <utils/fileutils.h>
-
-#include <QList>
-#include <QMap>
-#include <QSet>
-#include <QString>
-#include <QXmlStreamReader>
-
-namespace ProjectExplorer {
-class FileNode;
-} // namespace ProjectExplorer
-
-namespace CMakeProjectManager {
-namespace Internal {
-
-class CMakeCbpParser : public QXmlStreamReader
-{
-public:
- bool parseCbpFile(CMakeTool::PathMapper mapper, const Utils::FilePath &fileName,
- const Utils::FilePath &sourceDirectory);
- std::vector<std::unique_ptr<ProjectExplorer::FileNode>> &&
- takeFileList() { return std::move(m_fileList); }
- std::vector<std::unique_ptr<ProjectExplorer::FileNode>> &&
- takeCmakeFileList() { return std::move(m_cmakeFileList); }
- QList<CMakeBuildTarget> buildTargets();
- QString projectName() const;
- QString compilerName() const;
- bool hasCMakeFiles();
-
-private:
- void parseCodeBlocks_project_file();
- void parseProject();
- void parseBuild();
- void parseOption();
- void parseBuildTarget();
- void parseBuildTargetOption();
- void parseMakeCommands();
- void parseBuildTargetBuild();
- void parseBuildTargetClean();
- void parseCompiler();
- void parseAdd();
- void parseUnit();
- void parseUnitOption();
- void parseUnknownElement();
- void sortFiles();
-
- QMap<Utils::FilePath, QStringList> m_unitTargetMap;
- CMakeTool::PathMapper m_pathMapper;
- std::vector<std::unique_ptr<ProjectExplorer::FileNode>> m_fileList;
- std::vector<std::unique_ptr<ProjectExplorer::FileNode>> m_cmakeFileList;
- QSet<Utils::FilePath> m_processedUnits;
- bool m_parsingCMakeUnit = false;
-
- CMakeBuildTarget m_buildTarget;
- QList<CMakeBuildTarget> m_buildTargets;
- QString m_projectName;
- QString m_compiler;
- Utils::FilePath m_sourceDirectory;
- Utils::FilePath m_buildDirectory;
- QStringList m_unitTargets;
-};
-
-} // namespace Internal
-} // namespace CMakeProjectManager
diff --git a/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp b/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp
index 7fdb7b2d60..a57d780d45 100644
--- a/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp
@@ -32,7 +32,8 @@
#include <utils/macroexpander.h>
#include <utils/qtcassert.h>
-#include <QString>
+#include <QFile>
+#include <QIODevice>
namespace CMakeProjectManager {
diff --git a/src/plugins/cmakeprojectmanager/cmakeconfigitem.h b/src/plugins/cmakeprojectmanager/cmakeconfigitem.h
index 15dae12a9c..c99f1e64f7 100644
--- a/src/plugins/cmakeprojectmanager/cmakeconfigitem.h
+++ b/src/plugins/cmakeprojectmanager/cmakeconfigitem.h
@@ -30,16 +30,17 @@
#include <utils/optional.h>
#include <QByteArray>
-#include <QList>
+#include <QStringList>
-#include <functional>
-
-namespace ProjectExplorer { class Kit; }
namespace Utils {
class FilePath;
class MacroExpander;
} // namespace Utils
+namespace ProjectExplorer {
+class Kit;
+}
+
namespace CMakeProjectManager {
class CMAKE_EXPORT CMakeConfigItem {
diff --git a/src/plugins/cmakeprojectmanager/cmakeeditor.cpp b/src/plugins/cmakeprojectmanager/cmakeeditor.cpp
index 7ec99a5254..6948eedf00 100644
--- a/src/plugins/cmakeprojectmanager/cmakeeditor.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakeeditor.cpp
@@ -27,31 +27,20 @@
#include "cmakefilecompletionassist.h"
#include "cmakeprojectconstants.h"
-#include "cmakeproject.h"
#include "cmakeindenter.h"
#include "cmakeautocompleter.h"
#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/actionmanager/actionmanager.h>
-#include <coreplugin/editormanager/editormanager.h>
-#include <coreplugin/icore.h>
-
-#include <extensionsystem/pluginmanager.h>
-
-#include <projectexplorer/projectexplorer.h>
-#include <projectexplorer/session.h>
-
+#include <texteditor/textdocument.h>
#include <texteditor/texteditoractionhandler.h>
-#include <texteditor/texteditorconstants.h>
-#include <utils/qtcassert.h>
-#include <utils/textutils.h>
+#include <QDir>
+#include <QTextDocument>
-#include <QFileInfo>
-#include <QTextBlock>
+#include <functional>
using namespace Core;
-using namespace ProjectExplorer;
using namespace TextEditor;
namespace CMakeProjectManager {
@@ -212,7 +201,7 @@ static TextDocument *createCMakeDocument()
{
auto doc = new TextDocument;
doc->setId(Constants::CMAKE_EDITOR_ID);
- doc->setMimeType(QLatin1String(Constants::CMAKEMIMETYPE));
+ doc->setMimeType(QLatin1String(Constants::CMAKE_MIMETYPE));
return doc;
}
@@ -224,8 +213,8 @@ CMakeEditorFactory::CMakeEditorFactory()
{
setId(Constants::CMAKE_EDITOR_ID);
setDisplayName(QCoreApplication::translate("OpenWith::Editors", "CMake Editor"));
- addMimeType(Constants::CMAKEMIMETYPE);
- addMimeType(Constants::CMAKEPROJECTMIMETYPE);
+ addMimeType(Constants::CMAKE_MIMETYPE);
+ addMimeType(Constants::CMAKE_PROJECT_MIMETYPE);
setEditorCreator([]() { return new CMakeEditor; });
setEditorWidgetCreator([]() { return new CMakeEditorWidget; });
diff --git a/src/plugins/cmakeprojectmanager/cmakeeditor.h b/src/plugins/cmakeprojectmanager/cmakeeditor.h
index 2eab78ed83..a2f67bef40 100644
--- a/src/plugins/cmakeprojectmanager/cmakeeditor.h
+++ b/src/plugins/cmakeprojectmanager/cmakeeditor.h
@@ -25,7 +25,6 @@
#pragma once
-#include <texteditor/textdocument.h>
#include <texteditor/texteditor.h>
namespace CMakeProjectManager {
diff --git a/src/plugins/cmakeprojectmanager/cmakefilecompletionassist.cpp b/src/plugins/cmakeprojectmanager/cmakefilecompletionassist.cpp
index 07f350caf1..1648902016 100644
--- a/src/plugins/cmakeprojectmanager/cmakefilecompletionassist.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakefilecompletionassist.cpp
@@ -24,19 +24,17 @@
****************************************************************************/
#include "cmakefilecompletionassist.h"
-#include "cmakeprojectconstants.h"
-#include "cmakeprojectmanager.h"
-#include "cmakesettingspage.h"
-#include "cmaketoolmanager.h"
+
#include "cmakekitinformation.h"
+#include "cmakeprojectconstants.h"
+#include "cmaketool.h"
#include <texteditor/codeassist/assistinterface.h>
-#include <projectexplorer/kit.h>
#include <projectexplorer/project.h>
#include <projectexplorer/session.h>
#include <projectexplorer/target.h>
-#include <coreplugin/editormanager/editormanager.h>
+#include <QFileInfo>
using namespace CMakeProjectManager::Internal;
using namespace TextEditor;
diff --git a/src/plugins/cmakeprojectmanager/cmakefilecompletionassist.h b/src/plugins/cmakeprojectmanager/cmakefilecompletionassist.h
index 220ed6ce26..440bbcb6c0 100644
--- a/src/plugins/cmakeprojectmanager/cmakefilecompletionassist.h
+++ b/src/plugins/cmakeprojectmanager/cmakefilecompletionassist.h
@@ -25,7 +25,6 @@
#pragma once
-#include <texteditor/codeassist/completionassistprovider.h>
#include <texteditor/codeassist/keywordscompletionassist.h>
namespace CMakeProjectManager {
diff --git a/src/plugins/cmakeprojectmanager/cmakeindenter.cpp b/src/plugins/cmakeprojectmanager/cmakeindenter.cpp
index e281d532db..4d0503482a 100644
--- a/src/plugins/cmakeprojectmanager/cmakeindenter.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakeindenter.cpp
@@ -25,12 +25,6 @@
#include "cmakeindenter.h"
-#include <QStack>
-#include <QDebug>
-
-#include <texteditor/tabsettings.h>
-#include <texteditor/textdocumentlayout.h>
-
namespace CMakeProjectManager {
namespace Internal {
diff --git a/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp b/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp
index 0e0d47cb5f..89ab5a9aab 100644
--- a/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp
@@ -24,16 +24,15 @@
****************************************************************************/
#include "cmakekitinformation.h"
+
#include "cmakeprojectconstants.h"
#include "cmakeprojectplugin.h"
#include "cmakespecificsettings.h"
#include "cmaketool.h"
#include "cmaketoolmanager.h"
-#include <app/app_version.h>
#include <coreplugin/icore.h>
#include <coreplugin/variablechooser.h>
-#include <projectexplorer/kit.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projectexplorersettings.h>
@@ -42,22 +41,23 @@
#include <qtsupport/baseqtversion.h>
#include <qtsupport/qtkitinformation.h>
#include <projectexplorer/projectexplorerconstants.h>
+
+#include <app/app_version.h>
+
#include <utils/algorithm.h>
#include <utils/elidinglabel.h>
#include <utils/environment.h>
+#include <utils/macroexpander.h>
#include <utils/qtcassert.h>
#include <QComboBox>
#include <QDialog>
#include <QDialogButtonBox>
-#include <QFileInfo>
#include <QGridLayout>
-#include <QLabel>
#include <QLineEdit>
#include <QPlainTextEdit>
#include <QPointer>
#include <QPushButton>
-#include <QVariant>
using namespace ProjectExplorer;
@@ -197,8 +197,7 @@ private:
void manageCMakeTools()
{
- Core::ICore::showOptionsDialog(Constants::CMAKE_SETTINGSPAGE_ID,
- buttonWidget());
+ Core::ICore::showOptionsDialog(Constants::CMAKE_SETTINGS_PAGE_ID, buttonWidget());
}
bool m_removingItem = false;
@@ -255,9 +254,11 @@ Tasks CMakeKitAspect::validate(const Kit *k) const
CMakeTool *tool = CMakeKitAspect::cmakeTool(k);
if (tool) {
CMakeTool::Version version = tool->version();
- if (version.major < 3) {
- result << BuildSystemTask(Task::Warning, tr("CMake version %1 is unsupported. Please update to "
- "version 3.0 or later.").arg(QString::fromUtf8(version.fullVersion)));
+ if (version.major < 3 || (version.major == 3 && version.minor < 14)) {
+ result << BuildSystemTask(Task::Warning,
+ tr("CMake version %1 is unsupported. Please update to "
+ "version 3.14 (with file-api) or later.")
+ .arg(QString::fromUtf8(version.fullVersion)));
}
}
return result;
@@ -468,7 +469,20 @@ private:
namespace {
-struct GeneratorInfo {
+class GeneratorInfo
+{
+public:
+ GeneratorInfo() = default;
+ GeneratorInfo(const QString &generator_,
+ const QString &extraGenerator_ = QString(),
+ const QString &platform_ = QString(),
+ const QString &toolset_ = QString())
+ : generator(generator_)
+ , extraGenerator(extraGenerator_)
+ , platform(platform_)
+ , toolset(toolset_)
+ {}
+
QVariant toVariant() const {
QVariantMap result;
result.insert(GENERATOR_KEY, generator);
@@ -570,10 +584,12 @@ void CMakeGeneratorKitAspect::setToolset(Kit *k, const QString &toolset)
}
void CMakeGeneratorKitAspect::set(Kit *k,
- const QString &generator, const QString &extraGenerator,
- const QString &platform, const QString &toolset)
+ const QString &generator,
+ const QString &extraGenerator,
+ const QString &platform,
+ const QString &toolset)
{
- GeneratorInfo info = {generator, extraGenerator, platform, toolset};
+ GeneratorInfo info(generator, extraGenerator, platform, toolset);
setGeneratorInfo(k, info);
}
@@ -607,12 +623,9 @@ QVariant CMakeGeneratorKitAspect::defaultValue(const Kit *k) const
if (!tool)
return QVariant();
- const QString extraGenerator = "CodeBlocks";
-
- QList<CMakeTool::Generator> known = tool->supportedGenerators();
- auto it = std::find_if(known.constBegin(), known.constEnd(),
- [extraGenerator](const CMakeTool::Generator &g) {
- return g.matches("Ninja", extraGenerator);
+ const QList<CMakeTool::Generator> known = tool->supportedGenerators();
+ auto it = std::find_if(known.constBegin(), known.constEnd(), [](const CMakeTool::Generator &g) {
+ return g.matches("Ninja");
});
if (it != known.constEnd()) {
const bool hasNinja = [k]() {
@@ -628,44 +641,45 @@ QVariant CMakeGeneratorKitAspect::defaultValue(const Kit *k) const
}();
if (hasNinja)
- return GeneratorInfo({QString("Ninja"), extraGenerator, QString(), QString()}).toVariant();
+ return GeneratorInfo("Ninja").toVariant();
}
if (Utils::HostOsInfo::isWindowsHost()) {
// *sigh* Windows with its zoo of incompatible stuff again...
- ToolChain *tc = ToolChainKitAspect::toolChain(k, ProjectExplorer::Constants::CXX_LANGUAGE_ID);
+ ToolChain *tc = ToolChainKitAspect::cxxToolChain(k);
if (tc && tc->typeId() == ProjectExplorer::Constants::MINGW_TOOLCHAIN_TYPEID) {
- it = std::find_if(known.constBegin(), known.constEnd(),
- [extraGenerator](const CMakeTool::Generator &g) {
- return g.matches("MinGW Makefiles", extraGenerator);
- });
+ it = std::find_if(known.constBegin(),
+ known.constEnd(),
+ [](const CMakeTool::Generator &g) {
+ return g.matches("MinGW Makefiles");
+ });
} else {
- it = std::find_if(known.constBegin(), known.constEnd(),
- [extraGenerator](const CMakeTool::Generator &g) {
- return g.matches("NMake Makefiles", extraGenerator)
- || g.matches("NMake Makefiles JOM", extraGenerator);
- });
+ it = std::find_if(known.constBegin(),
+ known.constEnd(),
+ [](const CMakeTool::Generator &g) {
+ return g.matches("NMake Makefiles")
+ || g.matches("NMake Makefiles JOM");
+ });
if (ProjectExplorerPlugin::projectExplorerSettings().useJom) {
it = std::find_if(known.constBegin(),
known.constEnd(),
- [extraGenerator](const CMakeTool::Generator &g) {
- return g.matches("NMake Makefiles JOM", extraGenerator);
+ [](const CMakeTool::Generator &g) {
+ return g.matches("NMake Makefiles JOM");
});
}
if (it == known.constEnd()) {
it = std::find_if(known.constBegin(),
known.constEnd(),
- [extraGenerator](const CMakeTool::Generator &g) {
- return g.matches("NMake Makefiles", extraGenerator);
+ [](const CMakeTool::Generator &g) {
+ return g.matches("NMake Makefiles");
});
}
}
} else {
// Unix-oid OSes:
- it = std::find_if(known.constBegin(), known.constEnd(),
- [extraGenerator](const CMakeTool::Generator &g) {
- return g.matches("Unix Makefiles", extraGenerator);
+ it = std::find_if(known.constBegin(), known.constEnd(), [](const CMakeTool::Generator &g) {
+ return g.matches("Unix Makefiles");
});
}
if (it == known.constEnd())
@@ -673,7 +687,7 @@ QVariant CMakeGeneratorKitAspect::defaultValue(const Kit *k) const
if (it == known.constEnd())
return QVariant();
- return GeneratorInfo({it->name, extraGenerator, QString(), QString()}).toVariant();
+ return GeneratorInfo(it->name).toVariant();
}
Tasks CMakeGeneratorKitAspect::validate(const Kit *k) const
@@ -703,11 +717,10 @@ Tasks CMakeGeneratorKitAspect::validate(const Kit *k) const
if (!it->supportsToolset && !info.toolset.isEmpty())
addWarning(tr("Toolset is not supported by the selected CMake generator."));
}
- if (!tool->hasServerMode() && !tool->hasFileApi() && info.extraGenerator != "CodeBlocks") {
- addWarning(tr("The selected CMake binary has no server-mode and the CMake "
- "generator does not generate a CodeBlocks file. "
+ if (!tool->hasFileApi()) {
+ addWarning(tr("The selected CMake binary does not support file-api. "
"%1 will not be able to parse CMake projects.")
- .arg(Core::Constants::IDE_DISPLAY_NAME));
+ .arg(Core::Constants::IDE_DISPLAY_NAME));
}
}
@@ -740,9 +753,10 @@ void CMakeGeneratorKitAspect::fix(Kit *k)
dv.fromVariant(defaultValue(k));
setGeneratorInfo(k, dv);
} else {
- const GeneratorInfo dv = {info.generator, info.extraGenerator,
- it->supportsPlatform ? info.platform : QString(),
- it->supportsToolset ? info.toolset : QString()};
+ const GeneratorInfo dv(info.generator,
+ info.extraGenerator,
+ it->supportsPlatform ? info.platform : QString(),
+ it->supportsToolset ? info.toolset : QString());
setGeneratorInfo(k, dv);
}
}
@@ -991,8 +1005,8 @@ Tasks CMakeConfigurationKitAspect::validate(const Kit *k) const
QTC_ASSERT(k, return Tasks());
const QtSupport::BaseQtVersion *const version = QtSupport::QtKitAspect::qtVersion(k);
- const ToolChain *const tcC = ToolChainKitAspect::toolChain(k, ProjectExplorer::Constants::C_LANGUAGE_ID);
- const ToolChain *const tcCxx = ToolChainKitAspect::toolChain(k, ProjectExplorer::Constants::CXX_LANGUAGE_ID);
+ const ToolChain *const tcC = ToolChainKitAspect::cToolChain(k);
+ const ToolChain *const tcCxx = ToolChainKitAspect::cxxToolChain(k);
const CMakeConfig config = configuration(k);
const bool isQt4 = version && version->qtVersion() < QtSupport::QtVersionNumber(5, 0, 0);
diff --git a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp
index a0a195ced6..290cabb868 100644
--- a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp
@@ -24,15 +24,14 @@
****************************************************************************/
#include "cmakelocatorfilter.h"
-#include "cmakebuildconfiguration.h"
+
#include "cmakebuildstep.h"
+#include "cmakebuildsystem.h"
#include "cmakeproject.h"
#include <coreplugin/editormanager/editormanager.h>
-#include <projectexplorer/buildconfiguration.h>
#include <projectexplorer/buildmanager.h>
#include <projectexplorer/buildsteplist.h>
-#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/session.h>
#include <projectexplorer/target.h>
diff --git a/src/plugins/cmakeprojectmanager/cmakeparser.cpp b/src/plugins/cmakeprojectmanager/cmakeparser.cpp
index 970dd64eee..2e008791e7 100644
--- a/src/plugins/cmakeprojectmanager/cmakeparser.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakeparser.cpp
@@ -54,21 +54,27 @@ CMakeParser::CMakeParser()
void CMakeParser::setSourceDirectory(const QString &sourceDir)
{
+ if (m_sourceDirectory)
+ emit searchDirExpired(FilePath::fromString(m_sourceDirectory.value().path()));
m_sourceDirectory = QDir(sourceDir);
+ emit addSearchDir(FilePath::fromString(sourceDir));
}
-void CMakeParser::stdError(const QString &line)
+OutputLineParser::Result CMakeParser::handleLine(const QString &line, OutputFormat type)
{
- QString trimmedLine = rightTrimmed(line);
+ if (type != StdErrFormat)
+ return Status::NotHandled;
+ QString trimmedLine = rightTrimmed(line);
switch (m_expectTripleLineErrorData) {
case NONE:
if (trimmedLine.isEmpty() && !m_lastTask.isNull()) {
- if (m_skippedFirstEmptyLine)
- doFlush();
- else
- m_skippedFirstEmptyLine = true;
- return;
+ if (m_skippedFirstEmptyLine) {
+ flush();
+ return Status::InProgress;
+ }
+ m_skippedFirstEmptyLine = true;
+ return Status::InProgress;
}
if (m_skippedFirstEmptyLine)
m_skippedFirstEmptyLine = false;
@@ -77,75 +83,84 @@ void CMakeParser::stdError(const QString &line)
QString path = m_sourceDirectory ? m_sourceDirectory->absoluteFilePath(
QDir::fromNativeSeparators(m_commonError.cap(1)))
: QDir::fromNativeSeparators(m_commonError.cap(1));
-
m_lastTask = BuildSystemTask(Task::Error,
QString(),
- FilePath::fromUserInput(path),
+ absoluteFilePath(FilePath::fromUserInput(path)),
m_commonError.cap(2).toInt());
m_lines = 1;
- return;
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, m_lastTask.file, m_lastTask.line,
+ m_commonError, 1);
+ return {Status::InProgress, linkSpecs};
} else if (m_nextSubError.indexIn(trimmedLine) != -1) {
m_lastTask = BuildSystemTask(Task::Error, QString(),
- FilePath::fromUserInput(m_nextSubError.cap(1)));
+ absoluteFilePath(FilePath::fromUserInput(m_nextSubError.cap(1))));
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, m_lastTask.file, m_lastTask.line,
+ m_nextSubError, 1);
m_lines = 1;
- return;
+ return {Status::InProgress, linkSpecs};
} else if (trimmedLine.startsWith(QLatin1String(" ")) && !m_lastTask.isNull()) {
- if (!m_lastTask.description.isEmpty())
- m_lastTask.description.append(QLatin1Char(' '));
- m_lastTask.description.append(trimmedLine.trimmed());
+ if (!m_lastTask.summary.isEmpty())
+ m_lastTask.summary.append(' ');
+ m_lastTask.summary.append(trimmedLine.trimmed());
++m_lines;
- return;
+ return Status::InProgress;
} else if (trimmedLine.endsWith(QLatin1String("in cmake code at"))) {
m_expectTripleLineErrorData = LINE_LOCATION;
- doFlush();
+ flush();
const Task::TaskType type =
trimmedLine.contains(QLatin1String("Error")) ? Task::Error : Task::Warning;
m_lastTask = BuildSystemTask(type, QString());
- return;
+ return Status::InProgress;
} else if (trimmedLine.startsWith("CMake Error: ")) {
m_lastTask = BuildSystemTask(Task::Error, trimmedLine.mid(13));
m_lines = 1;
- return;
+ return Status::InProgress;
} else if (trimmedLine.startsWith("-- ") || trimmedLine.startsWith(" * ")) {
// Do not pass on lines starting with "-- " or "* ". Those are typical CMake output
- return;
+ return Status::InProgress;
}
- IOutputParser::stdError(line);
- return;
+ return Status::NotHandled;
case LINE_LOCATION:
{
QRegularExpressionMatch m = m_locationLine.match(trimmedLine);
QTC_CHECK(m.hasMatch());
- m_lastTask.file = Utils::FilePath::fromUserInput(trimmedLine.mid(0, m.capturedStart()));
+ m_lastTask.file = absoluteFilePath(FilePath::fromUserInput(
+ trimmedLine.mid(0, m.capturedStart())));
m_lastTask.line = m.captured(1).toInt();
m_expectTripleLineErrorData = LINE_DESCRIPTION;
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, m_lastTask.file, m_lastTask.line, 0,
+ m.capturedStart());
+ return {Status::InProgress, linkSpecs};
}
- return;
case LINE_DESCRIPTION:
- m_lastTask.description = trimmedLine;
+ m_lastTask.summary = trimmedLine;
if (trimmedLine.endsWith(QLatin1Char('\"')))
m_expectTripleLineErrorData = LINE_DESCRIPTION2;
else {
m_expectTripleLineErrorData = NONE;
- doFlush();
+ flush();
+ return Status::Done;
}
- return;
+ return Status::InProgress;
case LINE_DESCRIPTION2:
- m_lastTask.description.append(QLatin1Char('\n'));
- m_lastTask.description.append(trimmedLine);
+ m_lastTask.details.append(trimmedLine);
m_expectTripleLineErrorData = NONE;
- doFlush();
- return;
+ flush();
+ return Status::Done;
}
+ return Status::NotHandled;
}
-void CMakeParser::doFlush()
+void CMakeParser::flush()
{
if (m_lastTask.isNull())
return;
Task t = m_lastTask;
m_lastTask.clear();
- emit addTask(t, m_lines, 1);
+ scheduleTask(t, m_lines, 1);
m_lines = 0;
}
@@ -297,7 +312,7 @@ void Internal::CMakeProjectPlugin::testCMakeParser_data()
void Internal::CMakeProjectPlugin::testCMakeParser()
{
OutputParserTester testbench;
- testbench.appendOutputParser(new CMakeParser);
+ testbench.addLineParser(new CMakeParser);
QFETCH(QString, input);
QFETCH(OutputParserTester::Channel, inputChannel);
QFETCH(Tasks, tasks);
diff --git a/src/plugins/cmakeprojectmanager/cmakeparser.h b/src/plugins/cmakeprojectmanager/cmakeparser.h
index 57b41ce559..b0cfc6f55a 100644
--- a/src/plugins/cmakeprojectmanager/cmakeparser.h
+++ b/src/plugins/cmakeprojectmanager/cmakeparser.h
@@ -30,25 +30,26 @@
#include <projectexplorer/ioutputparser.h>
#include <projectexplorer/task.h>
+#include <utils/optional.h>
+
#include <QDir>
#include <QRegExp>
#include <QRegularExpression>
namespace CMakeProjectManager {
-class CMAKE_EXPORT CMakeParser : public ProjectExplorer::IOutputParser
+class CMAKE_EXPORT CMakeParser : public ProjectExplorer::OutputTaskParser
{
Q_OBJECT
public:
explicit CMakeParser();
void setSourceDirectory(const QString &sourceDir);
- void stdError(const QString &line) override;
-
-protected:
- void doFlush() override;
private:
+ Result handleLine(const QString &line, Utils::OutputFormat type) override;
+ void flush() override;
+
enum TripleLineError { NONE, LINE_LOCATION, LINE_DESCRIPTION, LINE_DESCRIPTION2 };
TripleLineError m_expectTripleLineErrorData = NONE;
diff --git a/src/plugins/cmakeprojectmanager/cmakeprocess.cpp b/src/plugins/cmakeprojectmanager/cmakeprocess.cpp
index 2c603d7331..e500ac8c2e 100644
--- a/src/plugins/cmakeprojectmanager/cmakeprocess.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakeprocess.cpp
@@ -33,14 +33,9 @@
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/taskhub.h>
-#include <utils/algorithm.h>
-#include <utils/fileutils.h>
#include <utils/stringutils.h>
#include <QDir>
-#include <QObject>
-#include <QTime>
-#include <QTimer>
namespace CMakeProjectManager {
namespace Internal {
@@ -76,9 +71,7 @@ CMakeProcess::~CMakeProcess()
Core::Reaper::reap(m_process.release());
}
- // Delete issue parser:
- if (m_parser)
- m_parser->flush();
+ m_parser.flush();
if (m_future) {
reportCanceled();
@@ -88,7 +81,7 @@ CMakeProcess::~CMakeProcess()
void CMakeProcess::run(const BuildDirParameters &parameters, const QStringList &arguments)
{
- QTC_ASSERT(!m_process && !m_parser && !m_future, return);
+ QTC_ASSERT(!m_process && !m_future, return);
CMakeTool *cmake = parameters.cmakeTool();
QTC_ASSERT(parameters.isValid() && cmake, return);
@@ -98,19 +91,9 @@ void CMakeProcess::run(const BuildDirParameters &parameters, const QStringList &
const QString srcDir = parameters.sourceDirectory.toString();
- auto parser = std::make_unique<CMakeParser>();
+ const auto parser = new CMakeParser;
parser->setSourceDirectory(srcDir);
- QDir source = QDir(srcDir);
- connect(parser.get(), &IOutputParser::addTask, parser.get(),
- [source](const Task &task) {
- if (task.file.isEmpty() || task.file.toFileInfo().isAbsolute()) {
- TaskHub::addTask(task);
- } else {
- Task t = task;
- t.file = Utils::FilePath::fromString(source.absoluteFilePath(task.file.toString()));
- TaskHub::addTask(t);
- }
- });
+ m_parser.addLineParser(parser);
// Always use the sourceDir: If we are triggered because the build directory is getting deleted
// then we are racing against CMakeCache.txt also getting deleted.
@@ -155,7 +138,6 @@ void CMakeProcess::run(const BuildDirParameters &parameters, const QStringList &
process->start();
m_process = std::move(process);
- m_parser = std::move(parser);
m_future = std::move(future);
}
@@ -201,7 +183,7 @@ void CMakeProcess::processStandardError()
static QString rest;
rest = lineSplit(rest, m_process->readAllStandardError(), [this](const QString &s) {
- m_parser->stdError(s);
+ m_parser.appendMessage(s, Utils::StdErrFormat);
Core::MessageManager::write(s);
});
}
diff --git a/src/plugins/cmakeprojectmanager/cmakeprocess.h b/src/plugins/cmakeprojectmanager/cmakeprocess.h
index d71a56629f..c63f54952a 100644
--- a/src/plugins/cmakeprojectmanager/cmakeprocess.h
+++ b/src/plugins/cmakeprojectmanager/cmakeprocess.h
@@ -27,12 +27,13 @@
#include "builddirparameters.h"
-#include <projectexplorer/ioutputparser.h>
-
+#include <utils/outputformatter.h>
#include <utils/qtcprocess.h>
#include <QElapsedTimer>
#include <QFutureInterface>
+#include <QObject>
+#include <QStringList>
#include <QTimer>
#include <memory>
@@ -70,7 +71,7 @@ private:
void checkForCancelled();
std::unique_ptr<Utils::QtcProcess> m_process;
- std::unique_ptr<ProjectExplorer::IOutputParser> m_parser;
+ Utils::OutputFormatter m_parser;
std::unique_ptr<QFutureInterface<void>> m_future;
bool m_processWasCanceled = false;
QTimer m_cancelTimer;
diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.cpp b/src/plugins/cmakeprojectmanager/cmakeproject.cpp
index b458b9bf4c..381f25e37b 100644
--- a/src/plugins/cmakeprojectmanager/cmakeproject.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakeproject.cpp
@@ -25,41 +25,19 @@
#include "cmakeproject.h"
-#include "cmakebuildconfiguration.h"
#include "cmakebuildstep.h"
#include "cmakekitinformation.h"
#include "cmakeprojectconstants.h"
+#include "cmakeprojectimporter.h"
#include "cmakeprojectnodes.h"
-#include "cmakeprojectmanager.h"
+#include "cmaketool.h"
-#include <coreplugin/progressmanager/progressmanager.h>
-#include <cpptools/cppprojectupdater.h>
-#include <cpptools/cpptoolsconstants.h>
-#include <cpptools/generatedcodemodelsupport.h>
-#include <cpptools/projectinfo.h>
+#include <coreplugin/icontext.h>
+#include <projectexplorer/buildconfiguration.h>
#include <projectexplorer/buildsteplist.h>
-#include <projectexplorer/buildtargetinfo.h>
-#include <projectexplorer/deploymentdata.h>
-#include <projectexplorer/headerpath.h>
#include <projectexplorer/kitinformation.h>
-#include <projectexplorer/kitmanager.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/target.h>
-#include <projectexplorer/toolchain.h>
-#include <qmljs/qmljsmodelmanagerinterface.h>
-#include <qtsupport/baseqtversion.h>
-#include <qtsupport/qtcppkitinfo.h>
-#include <qtsupport/qtkitinformation.h>
-
-#include <utils/algorithm.h>
-#include <utils/qtcassert.h>
-#include <utils/qtcprocess.h>
-#include <utils/stringutils.h>
-#include <utils/hostosinfo.h>
-
-#include <QDir>
-#include <QElapsedTimer>
-#include <QSet>
using namespace ProjectExplorer;
using namespace Utils;
@@ -77,9 +55,9 @@ using namespace Internal;
\class CMakeProject
*/
CMakeProject::CMakeProject(const FilePath &fileName)
- : Project(Constants::CMAKEMIMETYPE, fileName)
+ : Project(Constants::CMAKE_MIMETYPE, fileName)
{
- setId(CMakeProjectManager::Constants::CMAKEPROJECT_ID);
+ setId(CMakeProjectManager::Constants::CMAKE_PROJECT_ID);
setProjectLanguages(Core::Context(ProjectExplorer::Constants::CXX_LANGUAGE_ID));
setDisplayName(projectDirectory().fileName());
setCanBuildProducts();
@@ -87,7 +65,10 @@ CMakeProject::CMakeProject(const FilePath &fileName)
setHasMakeInstallEquivalent(true);
}
-CMakeProject::~CMakeProject() = default;
+CMakeProject::~CMakeProject()
+{
+ delete m_projectImporter;
+}
Tasks CMakeProject::projectIssues(const Kit *k) const
{
@@ -105,8 +86,8 @@ Tasks CMakeProject::projectIssues(const Kit *k) const
ProjectImporter *CMakeProject::projectImporter() const
{
if (!m_projectImporter)
- m_projectImporter = std::make_unique<CMakeProjectImporter>(projectFilePath());
- return m_projectImporter.get();
+ m_projectImporter = new CMakeProjectImporter(projectFilePath());
+ return m_projectImporter;
}
bool CMakeProject::setupTarget(Target *t)
diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.h b/src/plugins/cmakeprojectmanager/cmakeproject.h
index 9266854a68..c96242b674 100644
--- a/src/plugins/cmakeprojectmanager/cmakeproject.h
+++ b/src/plugins/cmakeprojectmanager/cmakeproject.h
@@ -27,18 +27,14 @@
#include "cmake_global.h"
-#include "builddirmanager.h"
-#include "cmakebuildsystem.h"
-#include "cmakebuildtarget.h"
-#include "cmakeprojectimporter.h"
-
-#include <projectexplorer/buildsystem.h>
#include <projectexplorer/project.h>
-#include <memory>
-
namespace CMakeProjectManager {
+namespace Internal {
+class CMakeProjectImporter;
+}
+
class CMAKE_EXPORT CMakeProject final : public ProjectExplorer::Project
{
Q_OBJECT
@@ -59,7 +55,7 @@ private:
ProjectExplorer::MakeInstallCommand makeInstallCommand(const ProjectExplorer::Target *target,
const QString &installRoot) override;
- mutable std::unique_ptr<Internal::CMakeProjectImporter> m_projectImporter;
+ mutable Internal::CMakeProjectImporter *m_projectImporter = nullptr;
friend class CMakeBuildSystem;
};
diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectconstants.h b/src/plugins/cmakeprojectmanager/cmakeprojectconstants.h
index acd66a7bac..a59ac48c09 100644
--- a/src/plugins/cmakeprojectmanager/cmakeprojectconstants.h
+++ b/src/plugins/cmakeprojectmanager/cmakeprojectconstants.h
@@ -25,38 +25,36 @@
#pragma once
-#include <QtGlobal>
-
namespace CMakeProjectManager {
namespace Constants {
-const char CMAKEMIMETYPE[] = "text/x-cmake";
-const char CMAKEPROJECTMIMETYPE[] = "text/x-cmake-project";
+const char CMAKE_MIMETYPE[] = "text/x-cmake";
+const char CMAKE_PROJECT_MIMETYPE[] = "text/x-cmake-project";
const char CMAKE_EDITOR_ID[] = "CMakeProject.CMakeEditor";
-const char RUNCMAKE[] = "CMakeProject.RunCMake";
-const char CLEARCMAKECACHE[] = "CMakeProject.ClearCache";
-const char RESCANPROJECT[] = "CMakeProject.RescanProject";
-const char RUNCMAKECONTEXTMENU[] = "CMakeProject.RunCMakeContextMenu";
-const char BUILDFILECONTEXTMENU[] = "CMakeProject.BuildFileContextMenu";
-const char BUILDFILE[] = "CMakeProject.BuildFile";
+const char RUN_CMAKE[] = "CMakeProject.RunCMake";
+const char CLEAR_CMAKE_CACHE[] = "CMakeProject.ClearCache";
+const char RESCAN_PROJECT[] = "CMakeProject.RescanProject";
+const char RUN_CMAKE_CONTEXT_MENU[] = "CMakeProject.RunCMakeContextMenu";
+const char BUILD_FILE_CONTEXT_MENU[] = "CMakeProject.BuildFileContextMenu";
+const char BUILD_FILE[] = "CMakeProject.BuildFile";
// Project
-const char CMAKEPROJECT_ID[] = "CMakeProjectManager.CMakeProject";
+const char CMAKE_PROJECT_ID[] = "CMakeProjectManager.CMakeProject";
// Menu
const char M_CONTEXT[] = "CMakeEditor.ContextMenu";
// Settings page
-const char CMAKE_SETTINGSPAGE_ID[] = "Z.CMake";
+const char CMAKE_SETTINGS_PAGE_ID[] = "Z.CMake";
// Snippets
const char CMAKE_SNIPPETS_GROUP_ID[] = "CMake";
// Icons
-const char FILEOVERLAY_CMAKE[] = ":/cmakeproject/images/fileoverlay_cmake.png";
+const char FILE_OVERLAY_CMAKE[] = ":/cmakeproject/images/fileoverlay_cmake.png";
// Actions
-const char BUILD_TARGET_CONTEXTMENU[] = "CMake.BuildTargetContextMenu";
+const char BUILD_TARGET_CONTEXT_MENU[] = "CMake.BuildTargetContextMenu";
// Build Step
const char CMAKE_BUILD_STEP_ID[] = "CMakeProjectManager.MakeStep";
diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp
index ddfd3fd8f7..fc6b396997 100644
--- a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp
@@ -25,14 +25,13 @@
#include "cmakeprojectimporter.h"
-#include "builddirmanager.h"
#include "cmakebuildconfiguration.h"
+#include "cmakebuildsystem.h"
#include "cmakekitinformation.h"
#include "cmaketoolmanager.h"
#include <projectexplorer/buildinfo.h>
-#include <projectexplorer/kit.h>
-#include <projectexplorer/kitmanager.h>
+#include <projectexplorer/kitinformation.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <qtsupport/qtkitinformation.h>
@@ -40,9 +39,7 @@
#include <utils/algorithm.h>
#include <utils/qtcassert.h>
-#include <QDebug>
#include <QDir>
-#include <QFileInfo>
#include <QLoggingCategory>
using namespace ProjectExplorer;
@@ -232,7 +229,7 @@ QList<void *> CMakeProjectImporter::examineDirectory(const Utils::FilePath &impo
}
QString errorMessage;
- const CMakeConfig config = BuildDirManager::parseCMakeConfiguration(cacheFile, &errorMessage);
+ const CMakeConfig config = CMakeBuildSystem::parseCMakeCacheDotTxt(cacheFile, &errorMessage);
if (config.isEmpty() || !errorMessage.isEmpty()) {
qCDebug(cmInputLog()) << "Failed to read configuration from" << cacheFile << errorMessage;
return { };
diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp
index 104c3c9bbc..69a8f0adf6 100644
--- a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp
@@ -24,20 +24,17 @@
****************************************************************************/
#include "cmakeprojectmanager.h"
-#include "cmakebuildconfiguration.h"
+
+#include "cmakebuildsystem.h"
#include "cmakekitinformation.h"
-#include "cmakeprojectconstants.h"
#include "cmakeproject.h"
-#include "cmakesettingspage.h"
-#include "cmaketoolmanager.h"
+#include "cmakeprojectconstants.h"
#include "cmakeprojectnodes.h"
#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/actionmanager/actionmanager.h>
-#include <coreplugin/actionmanager/command.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/editormanager/ieditor.h>
-#include <coreplugin/icore.h>
#include <coreplugin/messagemanager.h>
#include <projectexplorer/buildmanager.h>
#include <projectexplorer/projectexplorer.h>
@@ -49,8 +46,6 @@
#include <utils/parameteraction.h>
#include <QAction>
-#include <QDateTime>
-#include <QIcon>
using namespace ProjectExplorer;
using namespace CMakeProjectManager::Internal;
@@ -70,11 +65,12 @@ CMakeManager::CMakeManager() :
Core::ActionContainer *mfile =
Core::ActionManager::actionContainer(ProjectExplorer::Constants::M_FILECONTEXT);
- const Core::Context projectContext(CMakeProjectManager::Constants::CMAKEPROJECT_ID);
+ const Core::Context projectContext(CMakeProjectManager::Constants::CMAKE_PROJECT_ID);
const Core::Context globalContext(Core::Constants::C_GLOBAL);
Core::Command *command = Core::ActionManager::registerAction(m_runCMakeAction,
- Constants::RUNCMAKE, globalContext);
+ Constants::RUN_CMAKE,
+ globalContext);
command->setAttribute(Core::Command::CA_Hide);
mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_DEPLOY);
connect(m_runCMakeAction, &QAction::triggered, [this]() {
@@ -82,7 +78,8 @@ CMakeManager::CMakeManager() :
});
command = Core::ActionManager::registerAction(m_clearCMakeCacheAction,
- Constants::CLEARCMAKECACHE, globalContext);
+ Constants::CLEAR_CMAKE_CACHE,
+ globalContext);
command->setAttribute(Core::Command::CA_Hide);
mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_DEPLOY);
connect(m_clearCMakeCacheAction, &QAction::triggered, [this]() {
@@ -90,7 +87,8 @@ CMakeManager::CMakeManager() :
});
command = Core::ActionManager::registerAction(m_runCMakeActionContextMenu,
- Constants::RUNCMAKECONTEXTMENU, projectContext);
+ Constants::RUN_CMAKE_CONTEXT_MENU,
+ projectContext);
command->setAttribute(Core::Command::CA_Hide);
mproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_BUILD);
msubproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_BUILD);
@@ -100,23 +98,27 @@ CMakeManager::CMakeManager() :
m_buildFileContextMenu = new QAction(tr("Build"), this);
command = Core::ActionManager::registerAction(m_buildFileContextMenu,
- Constants::BUILDFILECONTEXTMENU, projectContext);
+ Constants::BUILD_FILE_CONTEXT_MENU,
+ projectContext);
command->setAttribute(Core::Command::CA_Hide);
mfile->addAction(command, ProjectExplorer::Constants::G_FILE_OTHER);
connect(m_buildFileContextMenu, &QAction::triggered,
this, &CMakeManager::buildFileContextMenu);
command = Core::ActionManager::registerAction(m_rescanProjectAction,
- Constants::RESCANPROJECT, globalContext);
+ Constants::RESCAN_PROJECT,
+ globalContext);
command->setAttribute(Core::Command::CA_Hide);
mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_DEPLOY);
connect(m_rescanProjectAction, &QAction::triggered, [this]() {
rescanProject(ProjectTree::currentBuildSystem());
});
- m_buildFileAction = new Utils::ParameterAction(tr("Build File"), tr("Build File \"%1\""),
- Utils::ParameterAction::AlwaysEnabled, this);
- command = Core::ActionManager::registerAction(m_buildFileAction, Constants::BUILDFILE);
+ m_buildFileAction = new Utils::ParameterAction(tr("Build File"),
+ tr("Build File \"%1\""),
+ Utils::ParameterAction::AlwaysEnabled,
+ this);
+ command = Core::ActionManager::registerAction(m_buildFileAction, Constants::BUILD_FILE);
command->setAttribute(Core::Command::CA_Hide);
command->setAttribute(Core::Command::CA_UpdateText);
command->setDescription(m_buildFileAction->text());
@@ -241,9 +243,7 @@ void CMakeManager::buildFile(Node *node)
if (generator == "Ninja") {
const Utils::FilePath relativeBuildDir = targetNode->buildDirectory().relativeChildPath(
bc->buildDirectory());
- targetBase = relativeBuildDir
- .pathAppended("CMakeFiles")
- .pathAppended(targetNode->displayName() + ".dir");
+ targetBase = relativeBuildDir / "CMakeFiles" / (targetNode->displayName() + ".dir");
} else if (!generator.contains("Makefiles")) {
Core::MessageManager::write(tr("Build File is not supported for generator \"%1\"")
.arg(generator));
diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.pro b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.pro
index c1b26eabd8..31d9d7287d 100644
--- a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.pro
+++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.pro
@@ -1,9 +1,7 @@
DEFINES += CMAKEPROJECTMANAGER_LIBRARY
include(../../qtcreatorplugin.pri)
-HEADERS = builddirmanager.h \
- builddirparameters.h \
- builddirreader.h \
+HEADERS = builddirparameters.h \
cmakebuildstep.h \
cmakebuildsystem.h \
cmakebuildtarget.h \
@@ -26,7 +24,6 @@ HEADERS = builddirmanager.h \
cmaketoolmanager.h \
cmake_global.h \
cmakekitinformation.h \
- cmakecbpparser.h \
cmakebuildsettingswidget.h \
cmakeindenter.h \
cmakeautocompleter.h \
@@ -37,14 +34,9 @@ HEADERS = builddirmanager.h \
fileapidataextractor.h \
fileapiparser.h \
fileapireader.h \
- projecttreehelper.h \
- servermode.h \
- servermodereader.h \
- tealeafreader.h
+ projecttreehelper.h
-SOURCES = builddirmanager.cpp \
- builddirparameters.cpp \
- builddirreader.cpp \
+SOURCES = builddirparameters.cpp \
cmakebuildstep.cpp \
cmakebuildsystem.cpp \
cmakeconfigitem.cpp \
@@ -64,7 +56,6 @@ SOURCES = builddirmanager.cpp \
cmakesettingspage.cpp \
cmaketoolmanager.cpp \
cmakekitinformation.cpp \
- cmakecbpparser.cpp \
cmakebuildsettingswidget.cpp \
cmakeindenter.cpp \
cmakeautocompleter.cpp \
@@ -75,10 +66,7 @@ SOURCES = builddirmanager.cpp \
fileapidataextractor.cpp \
fileapiparser.cpp \
fileapireader.cpp \
- projecttreehelper.cpp \
- servermode.cpp \
- servermodereader.cpp \
- tealeafreader.cpp
+ projecttreehelper.cpp
RESOURCES += cmakeproject.qrc
diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs
index 6b002345ed..3575a93c7b 100644
--- a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs
+++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs
@@ -21,10 +21,6 @@ QtcPlugin {
files: [
"builddirparameters.cpp",
"builddirparameters.h",
- "builddirmanager.cpp",
- "builddirmanager.h",
- "builddirreader.cpp",
- "builddirreader.h",
"cmake_global.h",
"cmakebuildconfiguration.cpp",
"cmakebuildconfiguration.h",
@@ -35,8 +31,6 @@ QtcPlugin {
"cmakebuildsystem.cpp",
"cmakebuildsystem.h",
"cmakebuildtarget.h",
- "cmakecbpparser.cpp",
- "cmakecbpparser.h",
"cmakeconfigitem.cpp",
"cmakeconfigitem.h",
"cmakeeditor.cpp",
@@ -91,12 +85,6 @@ QtcPlugin {
"fileapireader.cpp",
"fileapireader.h",
"projecttreehelper.cpp",
- "projecttreehelper.h",
- "servermode.cpp",
- "servermode.h",
- "servermodereader.cpp",
- "servermodereader.h",
- "tealeafreader.cpp",
- "tealeafreader.h"
+ "projecttreehelper.h"
]
}
diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp
index 1645807959..6f130f2b1a 100644
--- a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp
@@ -25,98 +25,20 @@
#include "cmakeprojectnodes.h"
-#include "cmakeconfigitem.h"
-#include "cmakeproject.h"
+#include "cmakebuildsystem.h"
#include "cmakeprojectconstants.h"
-#include "cmakeprojectplugin.h"
-#include "cmakespecificsettings.h"
#include <android/androidconstants.h>
-
#include <coreplugin/fileiconprovider.h>
-#include <coreplugin/icore.h>
-#include <cpptools/cpptoolsconstants.h>
-
#include <projectexplorer/target.h>
-#include <utils/algorithm.h>
-#include <utils/checkablemessagebox.h>
-#include <utils/mimetypes/mimedatabase.h>
-#include <utils/optional.h>
#include <utils/qtcassert.h>
-#include <QClipboard>
-#include <QDir>
-#include <QGuiApplication>
-#include <QMessageBox>
-
using namespace ProjectExplorer;
namespace CMakeProjectManager {
namespace Internal {
-namespace {
-void copySourcePathToClipboard(Utils::optional<QString> srcPath,
- const ProjectExplorer::ProjectNode *node)
-{
- QClipboard *clip = QGuiApplication::clipboard();
-
- QDir projDir{node->filePath().toFileInfo().absoluteFilePath()};
- clip->setText(QDir::cleanPath(projDir.relativeFilePath(srcPath.value())));
-}
-
-void noAutoAdditionNotify(const QStringList &filePaths, const ProjectExplorer::ProjectNode *node)
-{
- Utils::optional<QString> srcPath{};
-
- for (const QString &file : filePaths) {
- if (Utils::mimeTypeForFile(file).name() == CppTools::Constants::CPP_SOURCE_MIMETYPE) {
- srcPath = file;
- break;
- }
- }
-
- if (srcPath) {
- CMakeSpecificSettings *settings = CMakeProjectPlugin::projectTypeSpecificSettings();
- switch (settings->afterAddFileSetting()) {
- case CMakeProjectManager::Internal::ASK_USER: {
- bool checkValue{false};
- QDialogButtonBox::StandardButton reply =
- Utils::CheckableMessageBox::question(nullptr,
- QMessageBox::tr("Copy to Clipboard?"),
- QMessageBox::tr("Files are not automatically added to the "
- "CMakeLists.txt file of the CMake project."
- "\nCopy the path to the source files to the clipboard?"),
- "Remember My Choice", &checkValue, QDialogButtonBox::Yes | QDialogButtonBox::No,
- QDialogButtonBox::Yes);
- if (checkValue) {
- if (QDialogButtonBox::Yes == reply)
- settings->setAfterAddFileSetting(AfterAddFileAction::COPY_FILE_PATH);
- else if (QDialogButtonBox::No == reply)
- settings->setAfterAddFileSetting(AfterAddFileAction::NEVER_COPY_FILE_PATH);
-
- settings->toSettings(Core::ICore::settings());
- }
-
- if (QDialogButtonBox::Yes == reply) {
- copySourcePathToClipboard(srcPath, node);
- }
- break;
- }
-
- case CMakeProjectManager::Internal::COPY_FILE_PATH: {
- copySourcePathToClipboard(srcPath, node);
- break;
- }
-
- case CMakeProjectManager::Internal::NEVER_COPY_FILE_PATH:
- break;
- }
- }
-}
-
-}
-
CMakeInputsNode::CMakeInputsNode(const Utils::FilePath &cmakeLists) :
ProjectExplorer::ProjectNode(cmakeLists)
{
@@ -129,7 +51,7 @@ CMakeInputsNode::CMakeInputsNode(const Utils::FilePath &cmakeLists) :
CMakeListsNode::CMakeListsNode(const Utils::FilePath &cmakeListPath) :
ProjectExplorer::ProjectNode(cmakeListPath)
{
- static QIcon folderIcon = Core::FileIconProvider::directoryIcon(Constants::FILEOVERLAY_CMAKE);
+ static QIcon folderIcon = Core::FileIconProvider::directoryIcon(Constants::FILE_OVERLAY_CMAKE);
setIcon(folderIcon);
setListInProject(false);
}
@@ -157,21 +79,6 @@ QString CMakeProjectNode::tooltip() const
return QString();
}
-bool CMakeBuildSystem::addFiles(Node *context, const QStringList &filePaths, QStringList *notAdded)
-{
- if (auto n = dynamic_cast<CMakeProjectNode *>(context)) {
- noAutoAdditionNotify(filePaths, n);
- return true; // Return always true as autoadd is not supported!
- }
-
- if (auto n = dynamic_cast<CMakeTargetNode *>(context)) {
- noAutoAdditionNotify(filePaths, n);
- return true; // Return always true as autoadd is not supported!
- }
-
- return BuildSystem::addFiles(context, filePaths, notAdded);
-}
-
CMakeTargetNode::CMakeTargetNode(const Utils::FilePath &directory, const QString &target) :
ProjectExplorer::ProjectNode(directory)
{
@@ -248,17 +155,6 @@ void CMakeTargetNode::setConfig(const CMakeConfig &config)
m_config = config;
}
-bool CMakeBuildSystem::supportsAction(Node *context, ProjectAction action, const Node *node) const
-{
- if (dynamic_cast<CMakeTargetNode *>(context))
- return action == ProjectAction::AddNewFile;
-
- if (dynamic_cast<CMakeListsNode *>(context))
- return action == ProjectAction::AddNewFile;
-
- return BuildSystem::supportsAction(context, action, node);
-}
-
Utils::optional<Utils::FilePath> CMakeTargetNode::visibleAfterAddFileAction() const
{
return filePath().pathAppended("CMakeLists.txt");
diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp
index 3b23b21180..1dae39f036 100644
--- a/src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp
@@ -25,31 +25,28 @@
#include "cmakeprojectplugin.h"
-#include "cmakeeditor.h"
+#include "cmakebuildconfiguration.h"
#include "cmakebuildstep.h"
+#include "cmakebuildsystem.h"
+#include "cmakeeditor.h"
+#include "cmakekitinformation.h"
+#include "cmakelocatorfilter.h"
#include "cmakeproject.h"
#include "cmakeprojectconstants.h"
#include "cmakeprojectmanager.h"
#include "cmakeprojectnodes.h"
-#include "cmakebuildconfiguration.h"
-#include "cmakeprojectconstants.h"
-#include "cmakelocatorfilter.h"
#include "cmakesettingspage.h"
-#include "cmaketoolmanager.h"
-#include "cmakekitinformation.h"
#include "cmakespecificsettings.h"
+#include "cmakespecificsettingspage.h"
+#include "cmaketoolmanager.h"
#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/fileiconprovider.h>
#include <coreplugin/icore.h>
-
-#include <projectexplorer/kitmanager.h>
+#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/projectmanager.h>
#include <projectexplorer/projecttree.h>
-#include <projectexplorer/runcontrol.h>
-#include <projectexplorer/target.h>
-
#include <texteditor/snippets/snippetprovider.h>
#include <utils/parameteraction.h>
@@ -105,19 +102,20 @@ bool CMakeProjectPlugin::initialize(const QStringList & /*arguments*/, QString *
d = new CMakeProjectPluginPrivate;
projectTypeSpecificSettings()->fromSettings(ICore::settings());
- const Context projectContext{CMakeProjectManager::Constants::CMAKEPROJECT_ID};
+ const Context projectContext{CMakeProjectManager::Constants::CMAKE_PROJECT_ID};
- FileIconProvider::registerIconOverlayForSuffix(Constants::FILEOVERLAY_CMAKE, "cmake");
- FileIconProvider::registerIconOverlayForFilename(Constants::FILEOVERLAY_CMAKE,
+ FileIconProvider::registerIconOverlayForSuffix(Constants::FILE_OVERLAY_CMAKE, "cmake");
+ FileIconProvider::registerIconOverlayForFilename(Constants::FILE_OVERLAY_CMAKE,
"CMakeLists.txt");
TextEditor::SnippetProvider::registerGroup(Constants::CMAKE_SNIPPETS_GROUP_ID,
tr("CMake", "SnippetProvider"));
- ProjectManager::registerProjectType<CMakeProject>(Constants::CMAKEPROJECTMIMETYPE);
+ ProjectManager::registerProjectType<CMakeProject>(Constants::CMAKE_PROJECT_MIMETYPE);
//register actions
Command *command = ActionManager::registerAction(&d->buildTargetContextAction,
- Constants::BUILD_TARGET_CONTEXTMENU, projectContext);
+ Constants::BUILD_TARGET_CONTEXT_MENU,
+ projectContext);
command->setAttribute(Command::CA_Hide);
command->setAttribute(Command::CA_UpdateText);
command->setDescription(d->buildTargetContextAction.text());
diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectplugin.h b/src/plugins/cmakeprojectmanager/cmakeprojectplugin.h
index c8a50219f4..7a9a1ecce6 100644
--- a/src/plugins/cmakeprojectmanager/cmakeprojectplugin.h
+++ b/src/plugins/cmakeprojectmanager/cmakeprojectplugin.h
@@ -25,21 +25,21 @@
#pragma once
-#include "cmakespecificsettingspage.h"
-
#include <extensionsystem/iplugin.h>
namespace CMakeProjectManager {
namespace Internal {
-class CMakeProjectPlugin : public ExtensionSystem::IPlugin
+class CMakeSpecificSettings;
+
+class CMakeProjectPlugin final : public ExtensionSystem::IPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "CMakeProjectManager.json")
public:
static CMakeSpecificSettings *projectTypeSpecificSettings();
- ~CMakeProjectPlugin() override;
+ ~CMakeProjectPlugin();
#ifdef WITH_TESTS
private slots:
@@ -54,14 +54,11 @@ private slots:
void testCMakeProjectImporterToolChain_data();
void testCMakeProjectImporterToolChain();
-
- void testServerModeReaderProgress_data();
- void testServerModeReaderProgress();
#endif
private:
- bool initialize(const QStringList &arguments, QString *errorMessage) override;
- void extensionsInitialized() override;
+ bool initialize(const QStringList &arguments, QString *errorMessage);
+ void extensionsInitialized();
void updateContextActions();
diff --git a/src/plugins/cmakeprojectmanager/cmakesettingspage.cpp b/src/plugins/cmakeprojectmanager/cmakesettingspage.cpp
index c7d2c001ce..d1009d2a16 100644
--- a/src/plugins/cmakeprojectmanager/cmakesettingspage.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakesettingspage.cpp
@@ -23,31 +23,35 @@
**
****************************************************************************/
-#include "cmakeprojectconstants.h"
#include "cmakesettingspage.h"
+
+#include "cmakeprojectconstants.h"
+#include "cmaketool.h"
#include "cmaketoolmanager.h"
-#include <coreplugin/icore.h>
+#include <coreplugin/dialogs/ioptionspage.h>
#include <projectexplorer/projectexplorerconstants.h>
-#include <projectexplorer/projectexplorericons.h>
+
#include <utils/detailswidget.h>
-#include <utils/environment.h>
+#include <utils/fileutils.h>
#include <utils/pathchooser.h>
#include <utils/qtcassert.h>
#include <utils/stringutils.h>
#include <utils/treemodel.h>
#include <utils/utilsicons.h>
+#include <QBoxLayout>
#include <QCheckBox>
+#include <QCoreApplication>
#include <QFileInfo>
#include <QFormLayout>
#include <QHeaderView>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
+#include <QString>
#include <QTreeView>
#include <QUuid>
-#include <QWidget>
using namespace Utils;
@@ -110,17 +114,17 @@ public:
, m_isAutoRun(item->isAutoRun())
, m_autoCreateBuildDirectory(item->autoCreateBuildDirectory())
, m_autodetected(item->isAutoDetected())
+ , m_isSupported(item->hasFileApi())
, m_changed(changed)
{
updateErrorFlags();
- m_tooltip = tr("Version: %1<br>Supports fileApi: %2<br>Supports server-mode: %3")
+ m_tooltip = tr("Version: %1<br>Supports fileApi: %2")
.arg(QString::fromUtf8(item->version().fullVersion))
- .arg(item->hasFileApi() ? tr("yes") : tr("no"))
- .arg(item->hasServerMode() ? tr("yes") : tr("no"));
+ .arg(item->hasFileApi() ? tr("yes") : tr("no"));
}
CMakeToolTreeItem(const QString &name,
- const Utils::FilePath &executable,
+ const FilePath &executable,
const FilePath &qchFile,
bool autoRun,
bool autoCreate,
@@ -186,6 +190,10 @@ public:
error = QCoreApplication::translate(
"CMakeProjectManager::Internal::CMakeToolTreeItem",
"CMake executable path is not executable.");
+ } else if (!m_isSupported) {
+ error = QCoreApplication::translate(
+ "CMakeProjectManager::Internal::CMakeToolTreeItem",
+ "CMake executable does not provided required IDE integration features.");
}
if (result.isEmpty() || error.isEmpty())
return QString("%1%2").arg(result).arg(error);
@@ -216,6 +224,7 @@ public:
bool m_pathIsExecutable = false;
bool m_autoCreateBuildDirectory = false;
bool m_autodetected = false;
+ bool m_isSupported = false;
bool m_changed = true;
};
@@ -463,7 +472,7 @@ CMakeToolItemConfigWidget::CMakeToolItemConfigWidget(CMakeToolItemModel *model)
connect(m_binaryChooser, &PathChooser::rawPathChanged, this, [this]() {
updateQchFilePath();
- m_qchFileChooser->setBaseDirectory(m_binaryChooser->fileName().parentDir());
+ m_qchFileChooser->setBaseDirectory(m_binaryChooser->filePath().parentDir());
store();
});
connect(m_qchFileChooser, &PathChooser::rawPathChanged, this, &CMakeToolItemConfigWidget::store);
@@ -479,16 +488,16 @@ void CMakeToolItemConfigWidget::store() const
if (!m_loadingItem && m_id.isValid())
m_model->updateCMakeTool(m_id,
m_displayNameLineEdit->text(),
- m_binaryChooser->fileName(),
- m_qchFileChooser->fileName(),
+ m_binaryChooser->filePath(),
+ m_qchFileChooser->filePath(),
m_autoRunCheckBox->checkState() == Qt::Checked,
m_autoCreateBuildDirectoryCheckBox->checkState() == Qt::Checked);
}
void CMakeToolItemConfigWidget::updateQchFilePath()
{
- if (m_qchFileChooser->fileName().isEmpty())
- m_qchFileChooser->setFileName(CMakeTool::searchQchFile(m_binaryChooser->fileName()));
+ if (m_qchFileChooser->filePath().isEmpty())
+ m_qchFileChooser->setFilePath(CMakeTool::searchQchFile(m_binaryChooser->filePath()));
}
void CMakeToolItemConfigWidget::load(const CMakeToolTreeItem *item)
@@ -505,11 +514,11 @@ void CMakeToolItemConfigWidget::load(const CMakeToolTreeItem *item)
m_displayNameLineEdit->setText(item->m_name);
m_binaryChooser->setReadOnly(item->m_autodetected);
- m_binaryChooser->setFileName(item->m_executable);
+ m_binaryChooser->setFilePath(item->m_executable);
m_qchFileChooser->setReadOnly(item->m_autodetected);
m_qchFileChooser->setBaseDirectory(item->m_executable.parentDir());
- m_qchFileChooser->setFileName(item->m_qchFile);
+ m_qchFileChooser->setFilePath(item->m_qchFile);
m_autoRunCheckBox->setChecked(item->m_isAutoRun);
m_autoCreateBuildDirectoryCheckBox->setChecked(item->m_autoCreateBuildDirectory);
@@ -688,7 +697,7 @@ void CMakeToolConfigWidget::currentCMakeToolChanged(const QModelIndex &newCurren
CMakeSettingsPage::CMakeSettingsPage()
{
- setId(Constants::CMAKE_SETTINGSPAGE_ID);
+ setId(Constants::CMAKE_SETTINGS_PAGE_ID);
setDisplayName(CMakeToolConfigWidget::tr("CMake"));
setCategory(ProjectExplorer::Constants::KITS_SETTINGS_CATEGORY);
setWidgetCreator([] { return new CMakeToolConfigWidget; });
diff --git a/src/plugins/cmakeprojectmanager/cmakespecificsettings.h b/src/plugins/cmakeprojectmanager/cmakespecificsettings.h
index ca94bc2c73..4a4c51b461 100644
--- a/src/plugins/cmakeprojectmanager/cmakespecificsettings.h
+++ b/src/plugins/cmakeprojectmanager/cmakespecificsettings.h
@@ -24,7 +24,9 @@
****************************************************************************/
#pragma once
+
#include <utils/fileutils.h>
+
#include <QSettings>
namespace CMakeProjectManager {
diff --git a/src/plugins/cmakeprojectmanager/cmaketool.cpp b/src/plugins/cmakeprojectmanager/cmaketool.cpp
index 52f6f67893..90bc67fc26 100644
--- a/src/plugins/cmakeprojectmanager/cmaketool.cpp
+++ b/src/plugins/cmakeprojectmanager/cmaketool.cpp
@@ -24,23 +24,21 @@
****************************************************************************/
#include "cmaketool.h"
+
#include "cmaketoolmanager.h"
#include <utils/algorithm.h>
#include <utils/environment.h>
-#include <utils/hostosinfo.h>
#include <utils/qtcassert.h>
#include <QDir>
-#include <QFileInfo>
#include <QJsonDocument>
#include <QJsonObject>
-#include <QProcess>
#include <QRegularExpression>
#include <QSet>
-#include <QTextDocument>
#include <QUuid>
-#include <QVariantMap>
+
+#include <memory>
namespace CMakeProjectManager {
@@ -60,38 +58,24 @@ bool CMakeTool::Generator::matches(const QString &n, const QString &ex) const
namespace Internal {
-const char READER_TYPE_TEALEAF[] = "tealeaf";
-const char READER_TYPE_SERVERMODE[] = "servermode";
const char READER_TYPE_FILEAPI[] = "fileapi";
-static bool ignoreFileApi()
-{
- static bool s_ignoreFileApi = qEnvironmentVariableIsSet("QTC_CMAKE_IGNORE_FILEAPI");
- return s_ignoreFileApi;
-}
-
static Utils::optional<CMakeTool::ReaderType> readerTypeFromString(const QString &input)
{
- if (input == READER_TYPE_TEALEAF)
- return CMakeTool::TeaLeaf;
- if (input == READER_TYPE_SERVERMODE)
- return CMakeTool::ServerMode;
+ // Do not try to be clever here, just use whatever is in the string!
if (input == READER_TYPE_FILEAPI)
- return ignoreFileApi() ? CMakeTool::ServerMode : CMakeTool::FileApi;
+ return CMakeTool::FileApi;
return {};
}
static QString readerTypeToString(const CMakeTool::ReaderType &type)
{
switch (type) {
- case CMakeTool::TeaLeaf:
- return QString(READER_TYPE_TEALEAF);
- case CMakeTool::ServerMode:
- return QString(READER_TYPE_SERVERMODE);
case CMakeTool::FileApi:
return QString(READER_TYPE_FILEAPI);
+ default:
+ return QString();
}
- return QString();
}
// --------------------------------------------------------------------
@@ -109,9 +93,7 @@ class IntrospectionData
public:
bool m_didAttemptToRun = false;
bool m_didRun = true;
- bool m_hasServerMode = false;
- bool m_queriedServerMode = false;
bool m_triedCapabilities = false;
QList<CMakeTool::Generator> m_generators;
@@ -127,9 +109,10 @@ public:
///////////////////////////
// CMakeTool
///////////////////////////
-CMakeTool::CMakeTool(Detection d, const Core::Id &id) :
- m_id(id), m_isAutoDetected(d == AutoDetection),
- m_introspection(std::make_unique<Internal::IntrospectionData>())
+CMakeTool::CMakeTool(Detection d, const Core::Id &id)
+ : m_id(id)
+ , m_isAutoDetected(d == AutoDetection)
+ , m_introspection(std::make_unique<Internal::IntrospectionData>())
{
QTC_ASSERT(m_id.isValid(), m_id = Core::Id::fromString(QUuid::createUuid().toString()));
}
@@ -199,13 +182,13 @@ void CMakeTool::setAutoCreateBuildDirectory(bool autoBuildDir)
bool CMakeTool::isValid() const
{
- if (!m_id.isValid())
+ if (!m_id.isValid() || !m_introspection)
return false;
if (!m_introspection->m_didAttemptToRun)
- supportedGenerators();
+ readInformation();
- return m_introspection->m_didRun;
+ return m_introspection->m_didRun && !m_introspection->m_fileApis.isEmpty();
}
Utils::SynchronousProcessResponse CMakeTool::run(const QStringList &args, int timeoutS) const
@@ -230,7 +213,7 @@ QVariantMap CMakeTool::toMap() const
data.insert(CMAKE_INFORMATION_QCH_FILE_PATH, m_qchFilePath.toString());
data.insert(CMAKE_INFORMATION_AUTORUN, m_isAutoRun);
data.insert(CMAKE_INFORMATION_AUTO_CREATE_BUILD_DIRECTORY, m_autoCreateBuildDirectory);
- if (m_readerType.has_value())
+ if (m_readerType)
data.insert(CMAKE_INFORMATION_READERTYPE,
Internal::readerTypeToString(m_readerType.value()));
data.insert(CMAKE_INFORMATION_AUTODETECTED, m_isAutoDetected);
@@ -290,12 +273,14 @@ bool CMakeTool::autoCreateBuildDirectory() const
QList<CMakeTool::Generator> CMakeTool::supportedGenerators() const
{
- readInformation(QueryType::GENERATORS);
- return m_introspection->m_generators;
+ return isValid() ? m_introspection->m_generators : QList<CMakeTool::Generator>();
}
TextEditor::Keywords CMakeTool::keywords()
{
+ if (!isValid())
+ return {};
+
if (m_introspection->m_functions.isEmpty() && m_introspection->m_didRun) {
Utils::SynchronousProcessResponse response;
response = run({"--help-command-list"}, 5);
@@ -323,28 +308,19 @@ TextEditor::Keywords CMakeTool::keywords()
m_introspection->m_functionArgs);
}
-bool CMakeTool::hasServerMode() const
-{
- readInformation(QueryType::SERVER_MODE);
- return m_introspection->m_hasServerMode;
-}
-
bool CMakeTool::hasFileApi() const
{
- readInformation(QueryType::SERVER_MODE);
- return !m_introspection->m_fileApis.isEmpty();
+ return isValid() ? !m_introspection->m_fileApis.isEmpty() : false;
}
-QVector<std::pair<QString, int> > CMakeTool::supportedFileApiObjects() const
+QVector<std::pair<QString, int>> CMakeTool::supportedFileApiObjects() const
{
- readInformation(QueryType::SERVER_MODE);
- return Utils::transform(m_introspection->m_fileApis, [](const Internal::FileApi &api) { return std::make_pair(api.kind, api.version.first); });
+ return isValid() ? Utils::transform(m_introspection->m_fileApis, [](const Internal::FileApi &api) { return std::make_pair(api.kind, api.version.first); }) : QVector<std::pair<QString, int>>();
}
CMakeTool::Version CMakeTool::version() const
{
- readInformation(QueryType::VERSION);
- return m_introspection->m_version;
+ return isValid() ? m_introspection->m_version : CMakeTool::Version();
}
bool CMakeTool::isAutoDetected() const
@@ -375,20 +351,15 @@ CMakeTool::PathMapper CMakeTool::pathMapper() const
return [](const Utils::FilePath &fn) { return fn; };
}
-CMakeTool::ReaderType CMakeTool::readerType() const
+Utils::optional<CMakeTool::ReaderType> CMakeTool::readerType() const
{
- if (!m_readerType.has_value()) {
- // Find best possible reader type:
- if (hasFileApi()) {
- if (hasServerMode() && Internal::ignoreFileApi())
- return ServerMode; // We were asked to fall back to server mode
- return FileApi;
- }
- if (hasServerMode())
- return ServerMode;
- return TeaLeaf;
- }
- return m_readerType.value();
+ if (m_readerType)
+ return m_readerType; // Allow overriding the auto-detected value via .user files
+
+ // Find best possible reader type:
+ if (hasFileApi())
+ return FileApi;
+ return {};
}
Utils::FilePath CMakeTool::searchQchFile(const Utils::FilePath &executable)
@@ -413,33 +384,16 @@ Utils::FilePath CMakeTool::searchQchFile(const Utils::FilePath &executable)
return {};
}
-void CMakeTool::readInformation(CMakeTool::QueryType type) const
+void CMakeTool::readInformation() const
{
+ QTC_ASSERT(m_introspection, return );
if (!m_introspection->m_didRun && m_introspection->m_didAttemptToRun)
return;
m_introspection->m_didAttemptToRun = true;
- if (!m_introspection->m_triedCapabilities) {
- fetchFromCapabilities();
- m_introspection->m_triedCapabilities = true;
- m_introspection->m_queriedServerMode = true; // Got added after "-E capabilities" support!
- } else {
- if ((type == QueryType::GENERATORS && !m_introspection->m_generators.isEmpty())
- || (type == QueryType::SERVER_MODE && m_introspection->m_queriedServerMode)
- || (type == QueryType::VERSION && !m_introspection->m_version.fullVersion.isEmpty()))
- return;
-
- if (type == QueryType::GENERATORS) {
- fetchGeneratorsFromHelp();
- } else if (type == QueryType::SERVER_MODE) {
- // Nothing to do...
- } else if (type == QueryType::VERSION) {
- fetchVersionFromVersionOutput();
- } else {
- QTC_ASSERT(false, return );
- }
- }
+ fetchFromCapabilities();
+ m_introspection->m_triedCapabilities = true;
}
static QStringList parseDefinition(const QString &definition)
@@ -533,96 +487,16 @@ QStringList CMakeTool::parseVariableOutput(const QString &output)
return result;
}
-void CMakeTool::fetchGeneratorsFromHelp() const
-{
- Utils::SynchronousProcessResponse response = run({"--help"});
- m_introspection->m_didRun = m_introspection->m_didRun
- && response.result == Utils::SynchronousProcessResponse::Finished;
-
- if (response.result == Utils::SynchronousProcessResponse::Finished)
- parseGeneratorsFromHelp(response.stdOut().split('\n'));
-}
-
-void CMakeTool::parseGeneratorsFromHelp(const QStringList &lines) const
-{
- bool inGeneratorSection = false;
- QHash<QString, QStringList> generatorInfo;
- foreach (const QString &line, lines) {
- if (line.isEmpty())
- continue;
- if (line == "Generators") {
- inGeneratorSection = true;
- continue;
- }
- if (!inGeneratorSection)
- continue;
-
- if (line.startsWith(" ") && line.at(3) != ' ') {
- int pos = line.indexOf('=');
- if (pos < 0)
- pos = line.length();
- if (pos >= 0) {
- --pos;
- while (pos > 2 && line.at(pos).isSpace())
- --pos;
- }
- if (pos > 2) {
- const QString fullName = line.mid(2, pos - 1);
- const int dashPos = fullName.indexOf(" - ");
- QString generator;
- QString extra;
- if (dashPos < 0) {
- generator = fullName;
- } else {
- extra = fullName.mid(0, dashPos);
- generator = fullName.mid(dashPos + 3);
- }
- QStringList value = generatorInfo.value(generator);
- if (!extra.isEmpty())
- value.append(extra);
- generatorInfo.insert(generator, value);
- }
- }
- }
-
- // Populate genertor list:
- for (auto it = generatorInfo.constBegin(); it != generatorInfo.constEnd(); ++it)
- m_introspection->m_generators.append(Generator(it.key(), it.value()));
-}
-
-void CMakeTool::fetchVersionFromVersionOutput() const
-{
- Utils::SynchronousProcessResponse response = run({"--version"});
-
- m_introspection->m_didRun = m_introspection->m_didRun
- && response.result == Utils::SynchronousProcessResponse::Finished;
-
- if (response.result == Utils::SynchronousProcessResponse::Finished)
- parseVersionFormVersionOutput(response.stdOut().split('\n'));
-}
-
-void CMakeTool::parseVersionFormVersionOutput(const QStringList &lines) const
-{
- QRegularExpression versionLine("^cmake.* version ((\\d+).(\\d+).(\\d+).*)$");
- for (const QString &line : lines) {
- QRegularExpressionMatch match = versionLine.match(line);
- if (!match.hasMatch())
- continue;
-
- m_introspection->m_version.major = match.captured(2).toInt();
- m_introspection->m_version.minor = match.captured(3).toInt();
- m_introspection->m_version.patch = match.captured(4).toInt();
- m_introspection->m_version.fullVersion = match.captured(1).toUtf8();
- break;
- }
-}
-
void CMakeTool::fetchFromCapabilities() const
{
Utils::SynchronousProcessResponse response = run({"-E", "capabilities"});
- if (response.result == Utils::SynchronousProcessResponse::Finished)
+ if (response.result == Utils::SynchronousProcessResponse::Finished) {
+ m_introspection->m_didRun = true;
parseFromCapabilities(response.stdOut());
+ } else {
+ m_introspection->m_didRun = false;
+ }
}
static int getVersion(const QVariantMap &obj, const QString value)
@@ -641,7 +515,6 @@ void CMakeTool::parseFromCapabilities(const QString &input) const
return;
const QVariantMap data = doc.object().toVariantMap();
- m_introspection->m_hasServerMode = data.value("serverMode").toBool();
const QVariantList generatorList = data.value("generators").toList();
for (const QVariant &v : generatorList) {
const QVariantMap gen = v.toMap();
diff --git a/src/plugins/cmakeprojectmanager/cmaketool.h b/src/plugins/cmakeprojectmanager/cmaketool.h
index fd2c087c20..c22a07fb7f 100644
--- a/src/plugins/cmakeprojectmanager/cmaketool.h
+++ b/src/plugins/cmakeprojectmanager/cmaketool.h
@@ -34,10 +34,6 @@
#include <utils/optional.h>
#include <utils/synchronousprocess.h>
-#include <QObject>
-#include <QMap>
-#include <QStringList>
-
QT_FORWARD_DECLARE_CLASS(QProcess)
namespace ProjectExplorer { class Kit; }
@@ -51,7 +47,7 @@ class CMAKE_EXPORT CMakeTool
public:
enum Detection { ManualDetection, AutoDetection };
- enum ReaderType { TeaLeaf, ServerMode, FileApi };
+ enum ReaderType { FileApi };
struct Version
{
@@ -73,7 +69,7 @@ public:
bool supportsPlatform = true;
bool supportsToolset = true;
- bool matches(const QString &n, const QString &ex) const;
+ bool matches(const QString &n, const QString &ex = QString()) const;
};
using PathMapper = std::function<Utils::FilePath (const Utils::FilePath &)>;
@@ -102,7 +98,6 @@ public:
bool autoCreateBuildDirectory() const;
QList<Generator> supportedGenerators() const;
TextEditor::Keywords keywords();
- bool hasServerMode() const;
bool hasFileApi() const;
QVector<std::pair<QString, int>> supportedFileApiObjects() const;
Version version() const;
@@ -114,26 +109,17 @@ public:
void setPathMapper(const PathMapper &includePathMapper);
PathMapper pathMapper() const;
- ReaderType readerType() const;
+ Utils::optional<ReaderType> readerType() const;
static Utils::FilePath searchQchFile(const Utils::FilePath &executable);
private:
- enum class QueryType {
- GENERATORS,
- SERVER_MODE,
- VERSION
- };
- void readInformation(QueryType type) const;
+ void readInformation() const;
Utils::SynchronousProcessResponse run(const QStringList &args, int timeoutS = 1) const;
void parseFunctionDetailsOutput(const QString &output);
QStringList parseVariableOutput(const QString &output);
- void fetchGeneratorsFromHelp() const;
- void parseGeneratorsFromHelp(const QStringList &lines) const;
- void fetchVersionFromVersionOutput() const;
- void parseVersionFormVersionOutput(const QStringList &lines) const;
void fetchFromCapabilities() const;
void parseFromCapabilities(const QString &input) const;
diff --git a/src/plugins/cmakeprojectmanager/cmaketoolmanager.cpp b/src/plugins/cmakeprojectmanager/cmaketoolmanager.cpp
index fd7af452c7..aeb33ba754 100644
--- a/src/plugins/cmakeprojectmanager/cmaketoolmanager.cpp
+++ b/src/plugins/cmakeprojectmanager/cmaketoolmanager.cpp
@@ -34,8 +34,6 @@
#include <utils/qtcassert.h>
using namespace Core;
-using namespace Utils;
-using namespace ProjectExplorer;
namespace CMakeProjectManager {
@@ -139,7 +137,7 @@ void CMakeToolManager::setDefaultCMakeTool(const Id &id)
ensureDefaultCMakeToolIsValid();
}
-CMakeTool *CMakeToolManager::findByCommand(const FilePath &command)
+CMakeTool *CMakeToolManager::findByCommand(const Utils::FilePath &command)
{
return Utils::findOrDefault(d->m_cmakeTools, Utils::equal(&CMakeTool::cmakeExecutable, command));
}
diff --git a/src/plugins/cmakeprojectmanager/cmaketoolmanager.h b/src/plugins/cmakeprojectmanager/cmaketoolmanager.h
index c91f649850..7b3e3c4aa0 100644
--- a/src/plugins/cmakeprojectmanager/cmaketoolmanager.h
+++ b/src/plugins/cmakeprojectmanager/cmaketoolmanager.h
@@ -26,14 +26,17 @@
#pragma once
#include "cmake_global.h"
+
#include "cmaketool.h"
+#include <coreplugin/id.h>
+
#include <utils/fileutils.h>
-#include <texteditor/codeassist/keywordscompletionassist.h>
-#include <functional>
#include <QObject>
+#include <memory>
+
namespace CMakeProjectManager {
class CMAKE_EXPORT CMakeToolManager : public QObject
@@ -41,7 +44,7 @@ class CMAKE_EXPORT CMakeToolManager : public QObject
Q_OBJECT
public:
CMakeToolManager();
- ~CMakeToolManager() override;
+ ~CMakeToolManager();
static CMakeToolManager *instance();
diff --git a/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.cpp b/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.cpp
index 7e7b311f72..4d90eb8099 100644
--- a/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.cpp
+++ b/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.cpp
@@ -31,9 +31,9 @@
#include <coreplugin/icore.h>
#include <app/app_version.h>
+#include <utils/environment.h>
#include <utils/algorithm.h>
-#include <utils/environment.h>
#include <QDebug>
#include <QDir>
diff --git a/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.h b/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.h
index 05c7ac6920..0e85b43dfc 100644
--- a/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.h
+++ b/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.h
@@ -29,10 +29,6 @@
#include <coreplugin/id.h>
-#include <QList>
-
-#include <memory>
-
namespace Core { class Id; }
namespace CMakeProjectManager {
diff --git a/src/plugins/cmakeprojectmanager/configmodel.cpp b/src/plugins/cmakeprojectmanager/configmodel.cpp
index c402478d3c..b6134b14fa 100644
--- a/src/plugins/cmakeprojectmanager/configmodel.cpp
+++ b/src/plugins/cmakeprojectmanager/configmodel.cpp
@@ -31,7 +31,6 @@
#include <QCoreApplication>
#include <QFont>
-#include <QString>
#include <QSortFilterProxyModel>
namespace CMakeProjectManager {
diff --git a/src/plugins/cmakeprojectmanager/configmodel.h b/src/plugins/cmakeprojectmanager/configmodel.h
index 3b0c8ffa6d..5844c388f9 100644
--- a/src/plugins/cmakeprojectmanager/configmodel.h
+++ b/src/plugins/cmakeprojectmanager/configmodel.h
@@ -27,9 +27,10 @@
#include "cmakeconfigitem.h"
-#include <QAbstractTableModel>
#include <utils/treemodel.h>
+#include <QString>
+
namespace CMakeProjectManager {
namespace Internal { class ConfigModelTreeItem; }
diff --git a/src/plugins/cmakeprojectmanager/configmodelitemdelegate.cpp b/src/plugins/cmakeprojectmanager/configmodelitemdelegate.cpp
index 9be346a0fd..d111ac0b6a 100644
--- a/src/plugins/cmakeprojectmanager/configmodelitemdelegate.cpp
+++ b/src/plugins/cmakeprojectmanager/configmodelitemdelegate.cpp
@@ -25,14 +25,12 @@
****************************************************************************/
#include "configmodelitemdelegate.h"
+
#include "configmodel.h"
#include <utils/pathchooser.h>
-#include <QComboBox>
#include <QCheckBox>
-#include <QLineEdit>
-#include <QPainter>
namespace CMakeProjectManager {
@@ -86,7 +84,7 @@ void ConfigModelItemDelegate::setEditorData(QWidget *editor, const QModelIndex &
ConfigModel::DataItem data = ConfigModel::dataItemFromIndex(index);
if (data.type == ConfigModel::DataItem::FILE || data.type == ConfigModel::DataItem::DIRECTORY) {
auto edit = static_cast<Utils::PathChooser *>(editor);
- edit->setFileName(Utils::FilePath::fromUserInput(data.value));
+ edit->setFilePath(Utils::FilePath::fromUserInput(data.value));
return;
} else if (!data.values.isEmpty()) {
auto edit = static_cast<QComboBox *>(editor);
@@ -114,7 +112,7 @@ void ConfigModelItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *
if (data.type == ConfigModel::DataItem::FILE || data.type == ConfigModel::DataItem::DIRECTORY) {
auto edit = static_cast<Utils::PathChooser *>(editor);
if (edit->rawPath() != data.value)
- model->setData(index, edit->fileName().toString(), Qt::EditRole);
+ model->setData(index, edit->filePath().toString(), Qt::EditRole);
return;
} else if (!data.values.isEmpty()) {
auto edit = static_cast<QComboBox *>(editor);
diff --git a/src/plugins/cmakeprojectmanager/configmodelitemdelegate.h b/src/plugins/cmakeprojectmanager/configmodelitemdelegate.h
index 5df8decd11..d2ccf2c3d9 100644
--- a/src/plugins/cmakeprojectmanager/configmodelitemdelegate.h
+++ b/src/plugins/cmakeprojectmanager/configmodelitemdelegate.h
@@ -26,11 +26,11 @@
#pragma once
+#include <utils/fileutils.h>
+
#include <QComboBox>
#include <QStyledItemDelegate>
-#include <utils/fileutils.h>
-
namespace CMakeProjectManager {
class ConfigModelItemDelegate : public QStyledItemDelegate
diff --git a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp
index 79891a8b5b..03dec15d86 100644
--- a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp
+++ b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp
@@ -25,11 +25,9 @@
#include "fileapidataextractor.h"
-#include "cmakeprojectnodes.h"
+#include "fileapiparser.h"
#include "projecttreehelper.h"
-#include <projectexplorer/projectnodes.h>
-
#include <utils/algorithm.h>
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
@@ -78,7 +76,7 @@ CMakeFileResult extractCMakeFilesData(const std::vector<FileApiDetails::CMakeFil
if (oldCount < result.cmakeFiles.count()) {
if (info.isCMake && !info.isCMakeListsDotTxt) {
// Skip files that cmake considers to be part of the installation -- but include
- // CMakeLists.txt files. This unbreaks cmake binaries running from their own
+ // CMakeLists.txt files. This fixes cmake binaries running from their own
// build directory.
continue;
}
diff --git a/src/plugins/cmakeprojectmanager/fileapidataextractor.h b/src/plugins/cmakeprojectmanager/fileapidataextractor.h
index 403e041a62..f89da90296 100644
--- a/src/plugins/cmakeprojectmanager/fileapidataextractor.h
+++ b/src/plugins/cmakeprojectmanager/fileapidataextractor.h
@@ -25,19 +25,24 @@
#pragma once
-#include "fileapiparser.h"
-
#include "cmakebuildtarget.h"
-#include "cmakeprocess.h"
#include "cmakeprojectnodes.h"
#include <projectexplorer/rawprojectpart.h>
+#include <utils/fileutils.h>
+
+#include <QList>
+#include <QSet>
+#include <QString>
+
#include <memory>
namespace CMakeProjectManager {
namespace Internal {
+class FileApiData;
+
class FileApiQtcData
{
public:
diff --git a/src/plugins/cmakeprojectmanager/fileapiparser.cpp b/src/plugins/cmakeprojectmanager/fileapiparser.cpp
index f1eb1e8aaa..1c314da5c3 100644
--- a/src/plugins/cmakeprojectmanager/fileapiparser.cpp
+++ b/src/plugins/cmakeprojectmanager/fileapiparser.cpp
@@ -26,13 +26,11 @@
#include "fileapiparser.h"
#include <coreplugin/messagemanager.h>
-#include <projectexplorer/headerpath.h>
#include <projectexplorer/rawprojectpart.h>
#include <utils/algorithm.h>
#include <utils/qtcassert.h>
-#include <QDir>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
@@ -49,10 +47,17 @@ const char CMAKE_RELATIVE_QUERY_PATH[] = ".cmake/api/v1/query";
static Q_LOGGING_CATEGORY(cmakeFileApi, "qtc.cmake.fileApi", QtWarningMsg);
+const QStringList CMAKE_QUERY_FILENAMES = {"cache-v2", "codemodel-v2", "cmakeFiles-v1"};
+
// --------------------------------------------------------------------
// Helper:
// --------------------------------------------------------------------
+static FilePath cmakeReplyDirectory(const FilePath &buildDirectory)
+{
+ return buildDirectory.pathAppended(CMAKE_RELATIVE_REPLY_PATH);
+}
+
static void reportFileApiSetupFailure()
{
Core::MessageManager::write(QCoreApplication::translate(
@@ -501,7 +506,7 @@ static std::vector<Configuration> readCodemodelFile(const QString &codemodelFile
std::vector<FileApiDetails::FragmentInfo> extractFragments(const QJsonObject &obj)
{
const QJsonArray fragments = obj.value("commandFragments").toArray();
- return Utils::transform<std::vector>(fragments, [](const QJsonValue &v) {
+ return transform<std::vector>(fragments, [](const QJsonValue &v) {
const QJsonObject o = v.toObject();
return FileApiDetails::FragmentInfo{o.value("fragment").toString(),
o.value("role").toString()};
@@ -809,49 +814,26 @@ QString FileApiDetails::ReplyFileContents::jsonFile(const QString &kind, const Q
// FileApi:
// --------------------------------------------------------------------
-FileApiParser::FileApiParser(const FilePath &sourceDirectory, const FilePath &buildDirectory)
- : m_sourceDirectory(sourceDirectory)
- , m_buildDirectory(buildDirectory)
-{
- setupCMakeFileApi();
-
- QObject::connect(&m_watcher,
- &FileSystemWatcher::directoryChanged,
- this,
- &FileApiParser::replyDirectoryHasChanged);
-
- m_watcher.addDirectory(cmakeReplyDirectory().toString(), FileSystemWatcher::WatchAllChanges);
-}
-
-FilePath FileApiParser::cmakeReplyDirectory() const
+bool FileApiParser::setupCMakeFileApi(const FilePath &buildDirectory, Utils::FileSystemWatcher &watcher)
{
- return m_buildDirectory.pathAppended(CMAKE_RELATIVE_REPLY_PATH);
-}
-
-FileApiParser::~FileApiParser() = default;
+ const QDir buildDir = QDir(buildDirectory.toString());
+ buildDir.mkpath(
+ QString::fromLatin1(CMAKE_RELATIVE_REPLY_PATH)); // So that we have a directory to watch!
-void FileApiParser::setupCMakeFileApi() const
-{
- const QDir buildDir = QDir(m_buildDirectory.toString());
const QString relativeQueryPath = QString::fromLatin1(CMAKE_RELATIVE_QUERY_PATH);
-
buildDir.mkpath(relativeQueryPath);
- buildDir.mkpath(
- QString::fromLatin1(CMAKE_RELATIVE_REPLY_PATH)); // So that we have a directory to watch!
QDir queryDir = buildDir;
queryDir.cd(relativeQueryPath);
if (!queryDir.exists()) {
reportFileApiSetupFailure();
- return;
+ return false;
}
QTC_ASSERT(queryDir.exists(), );
bool failedBefore = false;
- for (const QString &fileName : cmakeQueryFileNames()) {
- const QString filePath = queryDir.filePath(fileName);
-
+ for (const QString &filePath : cmakeQueryFilePaths(buildDirectory)) {
QFile f(filePath);
if (!f.exists()) {
f.open(QFile::WriteOnly);
@@ -863,6 +845,9 @@ void FileApiParser::setupCMakeFileApi() const
reportFileApiSetupFailure();
}
}
+
+ watcher.addDirectory(cmakeReplyDirectory(buildDirectory).toString(), FileSystemWatcher::WatchAllChanges);
+ return true;
}
static QStringList uniqueTargetFiles(const std::vector<Configuration> &configs)
@@ -912,9 +897,9 @@ FileApiData FileApiParser::parseData(const QFileInfo &replyFileInfo, QString &er
return result;
}
-QFileInfo FileApiParser::scanForCMakeReplyFile() const
+QFileInfo FileApiParser::scanForCMakeReplyFile(const FilePath &buildDirectory)
{
- QDir replyDir(cmakeReplyDirectory().toString());
+ QDir replyDir(cmakeReplyDirectory(buildDirectory).toString());
if (!replyDir.exists())
return {};
@@ -924,33 +909,12 @@ QFileInfo FileApiParser::scanForCMakeReplyFile() const
return fis.isEmpty() ? QFileInfo() : fis.last();
}
-QStringList FileApiParser::cmakeQueryFileNames() const
-{
- return {"cache-v2", "codemodel-v2", "cmakeFiles-v1"};
-}
-
-QStringList FileApiParser::cmakeQueryFilePaths() const
+QStringList FileApiParser::cmakeQueryFilePaths(const Utils::FilePath &buildDirectory)
{
- QDir queryDir(QDir::cleanPath(m_sourceDirectory.toString() + "/"
- + QString::fromLatin1(CMAKE_RELATIVE_QUERY_PATH)));
- return transform(cmakeQueryFileNames(),
+ QDir queryDir(QDir::cleanPath(buildDirectory.pathAppended(CMAKE_RELATIVE_QUERY_PATH).toString()));
+ return transform(CMAKE_QUERY_FILENAMES,
[&queryDir](const QString &name) { return queryDir.absoluteFilePath(name); });
}
-void FileApiParser::setParsedReplyFilePath(const QString &filePath)
-{
- m_lastParsedReplyFile = filePath;
-}
-
-void FileApiParser::replyDirectoryHasChanged(const QString &directory) const
-{
- if (directory == cmakeReplyDirectory().toString()) {
- QFileInfo fi = scanForCMakeReplyFile();
- if (fi.isFile() && fi.filePath() != m_lastParsedReplyFile) {
- emit dirty();
- }
- }
-}
-
} // namespace Internal
} // namespace CMakeProjectManager
diff --git a/src/plugins/cmakeprojectmanager/fileapiparser.h b/src/plugins/cmakeprojectmanager/fileapiparser.h
index 0a5d19649e..eb096b8a73 100644
--- a/src/plugins/cmakeprojectmanager/fileapiparser.h
+++ b/src/plugins/cmakeprojectmanager/fileapiparser.h
@@ -33,7 +33,11 @@
#include <utils/filesystemwatcher.h>
#include <utils/fileutils.h>
-#include <QObject>
+#include <QDir>
+#include <QString>
+#include <QVector>
+
+#include <vector>
namespace CMakeProjectManager {
namespace Internal {
@@ -237,38 +241,17 @@ public:
std::vector<FileApiDetails::TargetDetails> targetDetails;
};
-class FileApiParser final : public QObject
+class FileApiParser
{
- Q_OBJECT
-
public:
- FileApiParser(const Utils::FilePath &sourceDirectory, const Utils::FilePath &buildDirectory);
- ~FileApiParser() final;
-
- Utils::FilePath cmakeReplyDirectory() const;
- QFileInfo scanForCMakeReplyFile() const;
-
- QStringList cmakeQueryFileNames() const;
- QStringList cmakeQueryFilePaths() const;
-
- void setParsedReplyFilePath(const QString &filePath);
-
static FileApiData parseData(const QFileInfo &replyFileInfo, QString &errorMessage);
-signals:
- void dataAvailable() const;
- void errorOccurred(const QString &message) const;
- void dirty() const;
-
-private:
- void setupCMakeFileApi() const;
+ static bool setupCMakeFileApi(const Utils::FilePath &buildDirectory,
+ Utils::FileSystemWatcher &watcher);
- const Utils::FilePath &m_sourceDirectory;
- const Utils::FilePath &m_buildDirectory;
+ static QStringList cmakeQueryFilePaths(const Utils::FilePath &buildDirectory);
- void replyDirectoryHasChanged(const QString &directory) const;
- Utils::FileSystemWatcher m_watcher;
- QString m_lastParsedReplyFile;
+ static QFileInfo scanForCMakeReplyFile(const Utils::FilePath &buildDirectory);
};
} // namespace Internal
diff --git a/src/plugins/cmakeprojectmanager/fileapireader.cpp b/src/plugins/cmakeprojectmanager/fileapireader.cpp
index 089354dc80..5b252f6297 100644
--- a/src/plugins/cmakeprojectmanager/fileapireader.cpp
+++ b/src/plugins/cmakeprojectmanager/fileapireader.cpp
@@ -25,25 +25,13 @@
#include "fileapireader.h"
-#include "cmakebuildconfiguration.h"
-#include "cmakeprojectconstants.h"
-#include "cmakeprojectmanager.h"
#include "fileapidataextractor.h"
+#include "fileapiparser.h"
#include "projecttreehelper.h"
-#include <coreplugin/editormanager/editormanager.h>
-#include <coreplugin/fileiconprovider.h>
-#include <coreplugin/messagemanager.h>
-#include <coreplugin/progressmanager/progressmanager.h>
#include <projectexplorer/projectexplorer.h>
-#include <projectexplorer/projectexplorerconstants.h>
-#include <projectexplorer/task.h>
-#include <projectexplorer/taskhub.h>
-#include <projectexplorer/toolchain.h>
#include <utils/algorithm.h>
-#include <utils/optional.h>
-#include <utils/qtcassert.h>
#include <utils/runextensions.h>
#include <QDateTime>
@@ -63,10 +51,19 @@ using namespace FileApiDetails;
// FileApiReader:
// --------------------------------------------------------------------
-FileApiReader::FileApiReader() {}
+FileApiReader::FileApiReader()
+ : m_lastReplyTimestamp()
+{
+ QObject::connect(&m_watcher,
+ &FileSystemWatcher::directoryChanged,
+ this,
+ &FileApiReader::replyDirectoryHasChanged);
+}
FileApiReader::~FileApiReader()
{
+ if (isParsing())
+ emit errorOccurred(tr("Parsing has been canceled."));
stop();
resetData();
}
@@ -80,22 +77,13 @@ void FileApiReader::setParameters(const BuildDirParameters &p)
m_parameters = p;
qCDebug(cmakeFileApiMode) << "Work directory:" << m_parameters.workDirectory.toUserOutput();
- resetData();
+ // Reset watcher:
+ m_watcher.removeFiles(m_watcher.files());
+ m_watcher.removeDirectories(m_watcher.directories());
- m_fileApi = std::make_unique<FileApiParser>(m_parameters.sourceDirectory, m_parameters.workDirectory);
- connect(m_fileApi.get(), &FileApiParser::dirty, this, [this]() {
- if (!m_isParsing)
- emit dirty();
- });
+ FileApiParser::setupCMakeFileApi(m_parameters.workDirectory, m_watcher);
- qCDebug(cmakeFileApiMode) << "FileApiReader: IS READY NOW SIGNAL";
- emit isReadyNow();
-}
-
-bool FileApiReader::isCompatible(const BuildDirParameters &p)
-{
- const CMakeTool *cmakeTool = p.cmakeTool();
- return cmakeTool && cmakeTool->readerType() == CMakeTool::FileApi;
+ resetData();
}
void FileApiReader::resetData()
@@ -126,13 +114,13 @@ void FileApiReader::parse(bool forceCMakeRun, bool forceConfiguration)
return;
}
- const QFileInfo replyFi = m_fileApi->scanForCMakeReplyFile();
+ const QFileInfo replyFi = FileApiParser::scanForCMakeReplyFile(m_parameters.workDirectory);
// Only need to update when one of the following conditions is met:
// * The user forces the update,
// * There is no reply file,
// * One of the cmakefiles is newer than the replyFile and the user asked
// for creator to run CMake as needed,
- // * A query files are newer than the reply file
+ // * A query file is newer than the reply file
const bool mustUpdate = forceCMakeRun || !replyFi.exists()
|| (m_parameters.cmakeTool() && m_parameters.cmakeTool()->isAutoRun()
&& anyOf(m_cmakeFiles,
@@ -140,7 +128,7 @@ void FileApiReader::parse(bool forceCMakeRun, bool forceConfiguration)
return f.toFileInfo().lastModified()
> replyFi.lastModified();
}))
- || anyOf(m_fileApi->cmakeQueryFilePaths(), [&replyFi](const QString &qf) {
+ || anyOf(FileApiParser::cmakeQueryFilePaths(m_parameters.workDirectory), [&replyFi](const QString &qf) {
return QFileInfo(qf).lastModified() > replyFi.lastModified();
});
@@ -156,6 +144,8 @@ void FileApiReader::parse(bool forceCMakeRun, bool forceConfiguration)
void FileApiReader::stop()
{
+ if (m_cmakeProcess)
+ disconnect(m_cmakeProcess.get(), nullptr, this, nullptr);
m_cmakeProcess.reset();
}
@@ -225,7 +215,7 @@ void FileApiReader::endState(const QFileInfo &replyFi)
const FilePath sourceDirectory = m_parameters.sourceDirectory;
const FilePath buildDirectory = m_parameters.workDirectory;
- m_fileApi->setParsedReplyFilePath(replyFi.filePath());
+ m_lastReplyTimestamp = replyFi.lastModified();
m_future = runAsync(ProjectExplorerPlugin::sharedThreadPool(),
[replyFi, sourceDirectory, buildDirectory]() {
@@ -258,7 +248,7 @@ void FileApiReader::endState(const QFileInfo &replyFi)
if (value->errorMessage.isEmpty()) {
emit this->dataAvailable();
} else {
- emit this->errorOccured(value->errorMessage);
+ emit this->errorOccurred(value->errorMessage);
}
});
}
@@ -285,7 +275,22 @@ void FileApiReader::cmakeFinishedState(int code, QProcess::ExitStatus status)
m_cmakeProcess.release()->deleteLater();
- endState(m_fileApi->scanForCMakeReplyFile());
+ endState(FileApiParser::scanForCMakeReplyFile(m_parameters.workDirectory));
+}
+
+void FileApiReader::replyDirectoryHasChanged(const QString &directory) const
+{
+ if (m_isParsing)
+ return; // This has been triggered by ourselves, ignore.
+
+ const QFileInfo fi = FileApiParser::scanForCMakeReplyFile(m_parameters.workDirectory);
+ const QString dir = fi.absolutePath();
+ if (dir.isEmpty())
+ return; // CMake started to fill the result dir, but has not written a result file yet
+ QTC_ASSERT(dir == directory, return);
+
+ if (m_lastReplyTimestamp.isValid() && fi.lastModified() > m_lastReplyTimestamp)
+ emit dirty();
}
} // namespace Internal
diff --git a/src/plugins/cmakeprojectmanager/fileapireader.h b/src/plugins/cmakeprojectmanager/fileapireader.h
index 560aafc779..2319010aa4 100644
--- a/src/plugins/cmakeprojectmanager/fileapireader.h
+++ b/src/plugins/cmakeprojectmanager/fileapireader.h
@@ -25,16 +25,18 @@
#pragma once
-#include "builddirreader.h"
-#include "fileapiparser.h"
-
+#include "cmakebuildtarget.h"
#include "cmakeprocess.h"
+#include "cmakeprojectnodes.h"
-#include <utils/optional.h>
+#include <projectexplorer/rawprojectpart.h>
-#include <memory>
+#include <utils/filesystemwatcher.h>
+#include <utils/optional.h>
#include <QFuture>
+#include <QObject>
+#include <QDateTime>
namespace ProjectExplorer {
class ProjectNode;
@@ -45,29 +47,34 @@ namespace Internal {
class FileApiQtcData;
-class FileApiReader final : public BuildDirReader
+class FileApiReader final : public QObject
{
Q_OBJECT
public:
FileApiReader();
- ~FileApiReader() final;
+ ~FileApiReader();
- void setParameters(const BuildDirParameters &p) final;
+ void setParameters(const BuildDirParameters &p);
- bool isCompatible(const BuildDirParameters &p) final;
- void resetData() final;
- void parse(bool forceCMakeRun, bool forceConfiguration) final;
- void stop() final;
+ void resetData();
+ void parse(bool forceCMakeRun, bool forceConfiguration);
+ void stop();
- bool isParsing() const final;
+ bool isParsing() const;
- QSet<Utils::FilePath> projectFilesToWatch() const final;
- QList<CMakeBuildTarget> takeBuildTargets(QString &errorMessage) final;
- CMakeConfig takeParsedConfiguration(QString &errorMessage) final;
+ QSet<Utils::FilePath> projectFilesToWatch() const;
+ QList<CMakeBuildTarget> takeBuildTargets(QString &errorMessage);
+ CMakeConfig takeParsedConfiguration(QString &errorMessage);
std::unique_ptr<CMakeProjectNode> generateProjectTree(
- const QList<const ProjectExplorer::FileNode *> &allFiles, QString &errorMessage) final;
- ProjectExplorer::RawProjectParts createRawProjectParts(QString &errorMessage) final;
+ const QList<const ProjectExplorer::FileNode *> &allFiles, QString &errorMessage);
+ ProjectExplorer::RawProjectParts createRawProjectParts(QString &errorMessage);
+
+signals:
+ void configurationStarted() const;
+ void dataAvailable() const;
+ void dirty() const;
+ void errorOccurred(const QString &message) const;
private:
void startState();
@@ -75,6 +82,8 @@ private:
void startCMakeState(const QStringList &configurationArguments);
void cmakeFinishedState(int code, QProcess::ExitStatus status);
+ void replyDirectoryHasChanged(const QString &directory) const;
+
std::unique_ptr<CMakeProcess> m_cmakeProcess;
// cmake data:
@@ -89,8 +98,11 @@ private:
// Update related:
bool m_isParsing = false;
+ BuildDirParameters m_parameters;
- std::unique_ptr<FileApiParser> m_fileApi;
+ // Notification on changes outside of creator:
+ Utils::FileSystemWatcher m_watcher;
+ QDateTime m_lastReplyTimestamp;
};
} // namespace Internal
diff --git a/src/plugins/cmakeprojectmanager/projecttreehelper.cpp b/src/plugins/cmakeprojectmanager/projecttreehelper.cpp
index 46d0810b60..8a930de35b 100644
--- a/src/plugins/cmakeprojectmanager/projecttreehelper.cpp
+++ b/src/plugins/cmakeprojectmanager/projecttreehelper.cpp
@@ -97,13 +97,13 @@ void addCMakeInputs(FolderNode *root,
addCMakeVFolder(cmakeVFolder.get(),
buildDir,
100,
- QCoreApplication::translate("CMakeProjectManager::Internal::ServerModeReader",
+ QCoreApplication::translate("CMakeProjectManager::Internal::ProjectTreeHelper",
"<Build Directory>"),
removeKnownNodes(knownFiles, std::move(buildInputs)));
addCMakeVFolder(cmakeVFolder.get(),
Utils::FilePath(),
10,
- QCoreApplication::translate("CMakeProjectManager::Internal::ServerModeReader",
+ QCoreApplication::translate("CMakeProjectManager::Internal::ProjectTreeHelper",
"<Other Locations>"),
removeKnownNodes(knownFiles, std::move(rootInputs)));
@@ -187,7 +187,8 @@ void addHeaderNodes(ProjectNode *root,
auto headerNode = std::make_unique<VirtualFolderNode>(root->filePath());
headerNode->setPriority(Node::DefaultPriority - 5);
headerNode->setDisplayName(
- QCoreApplication::translate("CMakeProjectManager::Internal::ServerModeReader", "<Headers>"));
+ QCoreApplication::translate("CMakeProjectManager::Internal::ProjectTreeHelper",
+ "<Headers>"));
headerNode->setIcon(headerNodeIcon);
// Add scanned headers:
diff --git a/src/plugins/cmakeprojectmanager/projecttreehelper.h b/src/plugins/cmakeprojectmanager/projecttreehelper.h
index 1371330f70..a591cabf0e 100644
--- a/src/plugins/cmakeprojectmanager/projecttreehelper.h
+++ b/src/plugins/cmakeprojectmanager/projecttreehelper.h
@@ -25,8 +25,6 @@
#include "cmakeprojectnodes.h"
-#include <projectexplorer/projectnodes.h>
-
#include <utils/fileutils.h>
#include <memory>
diff --git a/src/plugins/cmakeprojectmanager/servermode.cpp b/src/plugins/cmakeprojectmanager/servermode.cpp
deleted file mode 100644
index ce57e9d979..0000000000
--- a/src/plugins/cmakeprojectmanager/servermode.cpp
+++ /dev/null
@@ -1,495 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "servermode.h"
-
-#include <coreplugin/icore.h>
-#include <coreplugin/reaper.h>
-
-#include <utils/algorithm.h>
-#include <utils/qtcassert.h>
-#include <utils/qtcprocess.h>
-#include <utils/temporarydirectory.h>
-
-#include <QByteArray>
-#include <QCryptographicHash>
-#include <QFile>
-#include <QJsonDocument>
-#include <QJsonObject>
-#include <QLocalSocket>
-#include <QUuid>
-
-using namespace Utils;
-
-namespace CMakeProjectManager {
-namespace Internal {
-
-const char COOKIE_KEY[] = "cookie";
-const char IN_REPLY_TO_KEY[] = "inReplyTo";
-const char NAME_KEY[] = "name";
-const char TYPE_KEY[] = "type";
-
-const char ERROR_TYPE[] = "error";
-const char HANDSHAKE_TYPE[] = "handshake";
-
-const char START_MAGIC[] = "\n[== \"CMake Server\" ==[\n";
-const char END_MAGIC[] = "\n]== \"CMake Server\" ==]\n";
-
-static Q_LOGGING_CATEGORY(cmakeServerMode, "qtc.cmake.serverMode", QtWarningMsg);
-
-// ----------------------------------------------------------------------
-// Helpers:
-// ----------------------------------------------------------------------
-
-bool isValid(const QVariant &v)
-{
- if (v.isNull())
- return false;
- if (v.type() == QVariant::String) // Workaround signals sending an empty string cookie
- return !v.toString().isEmpty();
- return true;
-}
-
-// --------------------------------------------------------------------
-// ServerMode:
-// --------------------------------------------------------------------
-
-
-ServerMode::ServerMode(const Environment &env,
- const FilePath &sourceDirectory, const FilePath &buildDirectory,
- const FilePath &cmakeExecutable,
- const QString &generator, const QString &extraGenerator,
- const QString &platform, const QString &toolset,
- bool experimental, int major, int minor,
- QObject *parent) :
- QObject(parent),
-#if defined(Q_OS_UNIX)
- // Some unixes (e.g. Darwin) limit the length of a local socket to about 100 char (or less).
- // Since some unixes (e.g. Darwin) also point TMPDIR to /really/long/paths we need to create
- // our own socket in a place closer to '/'.
- m_socketDir("/tmp/cmake-"),
-#endif
- m_sourceDirectory(sourceDirectory), m_buildDirectory(buildDirectory),
- m_cmakeCommand(cmakeExecutable, {}),
- m_generator(generator), m_extraGenerator(extraGenerator),
- m_platform(platform), m_toolset(toolset),
- m_useExperimental(experimental), m_majorProtocol(major), m_minorProtocol(minor)
-{
- QTC_ASSERT(!m_sourceDirectory.isEmpty() && m_sourceDirectory.exists(), return);
- QTC_ASSERT(!m_buildDirectory.isEmpty() && m_buildDirectory.exists(), return);
-
- m_connectionTimer.setInterval(100);
- connect(&m_connectionTimer, &QTimer::timeout, this, &ServerMode::connectToServer);
-
- m_cmakeProcess = std::make_unique<QtcProcess>();
-
- m_cmakeProcess->setEnvironment(env);
- m_cmakeProcess->setWorkingDirectory(buildDirectory.toString());
-
-#if defined(Q_OS_UNIX)
- m_socketName = m_socketDir.path() + "/socket";
-#else
- m_socketName = QString::fromLatin1("\\\\.\\pipe\\") + QUuid::createUuid().toString();
-#endif
-
- connect(m_cmakeProcess.get(), &QtcProcess::started, this, [this]() { m_connectionTimer.start(); });
- connect(m_cmakeProcess.get(),
- QOverload<int, QProcess::ExitStatus>::of(&QtcProcess::finished),
- this, &ServerMode::handleCMakeFinished);
-
- m_cmakeCommand.addArgs({"-E", "server", "--pipe=" + m_socketName});
- if (m_useExperimental)
- m_cmakeCommand.addArg("--experimental");
-
- qCInfo(cmakeServerMode)
- << "Preparing cmake:" << m_cmakeCommand.toUserOutput()
- << "in" << m_buildDirectory.toString();
- m_cmakeProcess->setCommand(m_cmakeCommand);
-
- // Delay start:
- QTimer::singleShot(0, this, [this] {
- emit message(tr("Running \"%1\" in %2.")
- .arg(m_cmakeCommand.toUserOutput())
- .arg(m_buildDirectory.toUserOutput()));
-
- m_cmakeProcess->start();
- });
-}
-
-ServerMode::~ServerMode()
-{
- if (m_cmakeProcess)
- m_cmakeProcess->disconnect();
- if (m_cmakeSocket) {
- m_cmakeSocket->disconnect();
- m_cmakeSocket->abort();
- delete(m_cmakeSocket);
- }
- m_cmakeSocket = nullptr;
- Core::Reaper::reap(m_cmakeProcess.release());
-
- qCDebug(cmakeServerMode) << "Server-Mode closed.";
-}
-
-void ServerMode::sendRequest(const QString &type, const QVariantMap &extra, const QVariant &cookie)
-{
- QTC_ASSERT(m_cmakeSocket, return);
- ++m_requestCounter;
-
- qCInfo(cmakeServerMode) << "Sending Request" << type << "(" << cookie << ")";
-
- QVariantMap data = extra;
- data.insert(TYPE_KEY, type);
- const QVariant realCookie = cookie.isNull() ? QVariant(m_requestCounter) : cookie;
- data.insert(COOKIE_KEY, realCookie);
- m_expectedReplies.push_back({type, realCookie});
-
- QJsonObject object = QJsonObject::fromVariantMap(data);
- QJsonDocument document;
- document.setObject(object);
-
- const QByteArray rawData = START_MAGIC + document.toJson(QJsonDocument::Compact) + END_MAGIC;
- qCDebug(cmakeServerMode) << ">>>" << rawData;
- m_cmakeSocket->write(rawData);
- m_cmakeSocket->flush();
-}
-
-bool ServerMode::isConnected()
-{
- return m_cmakeSocket && m_isConnected;
-}
-
-void ServerMode::connectToServer()
-{
- QTC_ASSERT(m_cmakeProcess, return);
- if (m_cmakeSocket)
- return; // We connected in the meantime...
-
- static int counter = 0;
- ++counter;
-
- if (counter > 50) {
- counter = 0;
- m_cmakeProcess->disconnect();
- qCInfo(cmakeServerMode) << "Timeout waiting for pipe" << m_socketName;
- reportError(tr("Running \"%1\" failed: Timeout waiting for pipe \"%2\".")
- .arg(m_cmakeCommand.toUserOutput())
- .arg(m_socketName));
-
- Core::Reaper::reap(m_cmakeProcess.release());
- emit disconnected();
- return;
- }
-
- QTC_ASSERT(!m_cmakeSocket, return);
-
- auto socket = new QLocalSocket(m_cmakeProcess.get());
- connect(socket, &QLocalSocket::readyRead, this, &ServerMode::handleRawCMakeServerData);
-
- constexpr void (QLocalSocket::*LocalSocketErrorFunction)(QLocalSocket::LocalSocketError)
-#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
- = &QLocalSocket::error;
-#else
- = &QLocalSocket::errorOccurred;
-#endif
-
- connect(socket, LocalSocketErrorFunction, this, [this, socket]() {
- reportError(socket->errorString());
- m_cmakeSocket = nullptr;
- socket->disconnect();
- socket->deleteLater();
- });
- connect(socket, &QLocalSocket::connected, this, [this, socket]() { m_cmakeSocket = socket; });
- connect(socket, &QLocalSocket::disconnected, this, [this, socket]() {
- if (m_cmakeSocket)
- emit disconnected();
- m_cmakeSocket = nullptr;
- socket->disconnect();
- socket->deleteLater();
- });
-
- socket->connectToServer(m_socketName);
- m_connectionTimer.start();
-}
-
-void ServerMode::handleCMakeFinished(int code, QProcess::ExitStatus status)
-{
- qCInfo(cmakeServerMode) << "CMake has finished" << code << status;
- QString msg;
- if (status != QProcess::NormalExit)
- msg = tr("CMake process \"%1\" crashed.").arg(m_cmakeCommand.toUserOutput());
- else if (code != 0)
- msg = tr("CMake process \"%1\" quit with exit code %2.").arg(m_cmakeCommand.toUserOutput()).arg(code);
-
- if (!msg.isEmpty()) {
- reportError(msg);
- } else {
- emit message(tr("CMake process \"%1\" quit normally.").arg(m_cmakeCommand.toUserOutput()));
- }
-
- if (m_cmakeSocket) {
- m_cmakeSocket->disconnect();
- delete m_cmakeSocket;
- m_cmakeSocket = nullptr;
- }
-
- if (!HostOsInfo::isWindowsHost())
- QFile::remove(m_socketName);
-
- emit disconnected();
-}
-
-void ServerMode::handleRawCMakeServerData()
-{
- const static QByteArray startNeedle(START_MAGIC);
- const static QByteArray endNeedle(END_MAGIC);
-
- if (!m_cmakeSocket) // might happen during shutdown
- return;
-
- m_buffer.append(m_cmakeSocket->readAll());
-
- while (true) {
- const int startPos = m_buffer.indexOf(startNeedle);
- if (startPos >= 0) {
- const int afterStartNeedle = startPos + startNeedle.count();
- const int endPos = m_buffer.indexOf(endNeedle, afterStartNeedle);
- if (endPos > afterStartNeedle) {
- // Process JSON, remove junk and JSON-part, continue to loop with shorter buffer
- parseBuffer(m_buffer.mid(afterStartNeedle, endPos - afterStartNeedle));
- m_buffer.remove(0, endPos + endNeedle.count());
- } else {
- // Remove junk up to the start needle and break out of the loop
- if (startPos > 0)
- m_buffer.remove(0, startPos);
- break;
- }
- } else {
- // Keep at last startNeedle.count() characters (as that might be a
- // partial startNeedle), break out of the loop
- if (m_buffer.count() > startNeedle.count())
- m_buffer.remove(0, m_buffer.count() - startNeedle.count());
- break;
- }
- }
-}
-
-void ServerMode::parseBuffer(const QByteArray &buffer)
-{
- qCDebug(cmakeServerMode) << "<<<" << buffer;
- QJsonDocument document = QJsonDocument::fromJson(buffer);
- if (document.isNull()) {
- reportError(tr("Failed to parse JSON from CMake server."));
- return;
- }
- QJsonObject rootObject = document.object();
- if (rootObject.isEmpty()) {
- reportError(tr("JSON data from CMake server was not a JSON object."));
- return;
- }
-
- parseJson(rootObject.toVariantMap());
-}
-
-void ServerMode::parseJson(const QVariantMap &data)
-{
- QString type = data.value(TYPE_KEY).toString();
- if (type == "hello") {
- qCInfo(cmakeServerMode) << "Got \"hello\" message.";
- if (m_gotHello) {
- reportError(tr("Unexpected hello received from CMake server."));
- return;
- } else {
- handleHello(data);
- m_gotHello = true;
- return;
- }
- }
- if (!m_gotHello && type != ERROR_TYPE) {
- reportError(tr("Unexpected type \"%1\" received while waiting for \"hello\".").arg(type));
- return;
- }
-
- if (type == "reply") {
- if (m_expectedReplies.empty()) {
- reportError(tr("Received a reply even though no request is open."));
- return;
- }
- const QString replyTo = data.value(IN_REPLY_TO_KEY).toString();
- const QVariant cookie = data.value(COOKIE_KEY);
- qCInfo(cmakeServerMode) << "Got \"reply\" message." << replyTo << "(" << cookie << ")";
-
- const auto expected = m_expectedReplies.begin();
- if (expected->type != replyTo) {
- reportError(tr("Received a reply to a request of type \"%1\", when a request of type \"%2\" was sent.")
- .arg(replyTo).arg(expected->type));
- return;
- }
- if (expected->cookie != cookie) {
- reportError(tr("Received a reply with cookie \"%1\", when \"%2\" was expected.")
- .arg(cookie.toString()).arg(expected->cookie.toString()));
- return;
- }
-
- m_expectedReplies.erase(expected);
- if (replyTo != HANDSHAKE_TYPE)
- emit cmakeReply(data, replyTo, cookie);
- else {
- m_isConnected = true;
- emit connected();
- }
- return;
- }
- if (type == "error") {
- if (m_expectedReplies.empty()) {
- reportError(tr("An error was reported even though no request is open."));
- return;
- }
- const QString replyTo = data.value(IN_REPLY_TO_KEY).toString();
- const QVariant cookie = data.value(COOKIE_KEY);
- qCInfo(cmakeServerMode) << "Got \"error\" message." << replyTo << "(" << cookie << ")";
-
- const auto expected = m_expectedReplies.begin();
- if (expected->type != replyTo) {
- reportError(tr("Received an error in response to a request of type \"%1\", when a request of type \"%2\" was sent.")
- .arg(replyTo).arg(expected->type));
- return;
- }
- if (expected->cookie != cookie) {
- reportError(tr("Received an error with cookie \"%1\", when \"%2\" was expected.")
- .arg(cookie.toString()).arg(expected->cookie.toString()));
- return;
- }
-
- m_expectedReplies.erase(expected);
-
- emit cmakeError(data.value("errorMessage").toString(), replyTo, cookie);
- if (replyTo == HANDSHAKE_TYPE) {
- Core::Reaper::reap(m_cmakeProcess.release());
- m_cmakeSocket->disconnect();
- m_cmakeSocket->disconnectFromServer();
- m_cmakeSocket = nullptr;
- emit disconnected();
- }
- return;
- }
- if (type == "message") {
- const QString replyTo = data.value(IN_REPLY_TO_KEY).toString();
- const QVariant cookie = data.value(COOKIE_KEY);
- qCInfo(cmakeServerMode) << "Got \"message\" message." << replyTo << "(" << cookie << ")";
-
- const auto expected = m_expectedReplies.begin();
- if (expected->type != replyTo) {
- reportError(tr("Received a message in response to a request of type \"%1\", when a request of type \"%2\" was sent.")
- .arg(replyTo).arg(expected->type));
- return;
- }
- if (expected->cookie != cookie) {
- reportError(tr("Received a message with cookie \"%1\", when \"%2\" was expected.")
- .arg(cookie.toString()).arg(expected->cookie.toString()));
- return;
- }
-
- emit cmakeMessage(data.value("message").toString(), replyTo, cookie);
- return;
- }
- if (type == "progress") {
- const QString replyTo = data.value(IN_REPLY_TO_KEY).toString();
- const QVariant cookie = data.value(COOKIE_KEY);
- qCInfo(cmakeServerMode) << "Got \"progress\" message." << replyTo << "(" << cookie << ")";
-
- const auto expected = m_expectedReplies.begin();
- if (expected->type != replyTo) {
- reportError(tr("Received a progress report in response to a request of type \"%1\", when a request of type \"%2\" was sent.")
- .arg(replyTo).arg(expected->type));
- return;
- }
- if (expected->cookie != cookie) {
- reportError(tr("Received a progress report with cookie \"%1\", when \"%2\" was expected.")
- .arg(cookie.toString()).arg(expected->cookie.toString()));
- return;
- }
-
- emit cmakeProgress(data.value("progressMinimum").toInt(),
- data.value("progressCurrent").toInt(),
- data.value("progressMaximum").toInt(), replyTo, cookie);
- return;
- }
- if (type == "signal") {
- const QString replyTo = data.value(IN_REPLY_TO_KEY).toString();
- const QString cookie = data.value(COOKIE_KEY).toString();
- const QString name = data.value(NAME_KEY).toString();
- qCInfo(cmakeServerMode) << "Got \"signal\" message." << name << replyTo << "(" << cookie << ")";
-
- if (name.isEmpty()) {
- reportError(tr("Received a signal without a name."));
- return;
- }
- if (!replyTo.isEmpty() || isValid(cookie)) {
- reportError(tr("Received a signal in reply to a request."));
- return;
- }
-
- emit cmakeSignal(name, data);
- return;
- }
- reportError("Got a message of an unknown type.");
-}
-
-void ServerMode::handleHello(const QVariantMap &data)
-{
- Q_UNUSED(data)
- QVariantMap extra;
- QVariantMap version;
- version.insert("major", m_majorProtocol);
- if (m_minorProtocol >= 0)
- version.insert("minor", m_minorProtocol);
- extra.insert("protocolVersion", version);
- extra.insert("sourceDirectory", m_sourceDirectory.toString());
- extra.insert("buildDirectory", m_buildDirectory.toString());
- extra.insert("generator", m_generator);
- if (!m_platform.isEmpty())
- extra.insert("platform", m_platform);
- if (!m_toolset.isEmpty())
- extra.insert("toolset", m_toolset);
- if (!m_extraGenerator.isEmpty())
- extra.insert("extraGenerator", m_extraGenerator);
- if (!m_platform.isEmpty())
- extra.insert("platform", m_platform);
- if (!m_toolset.isEmpty())
- extra.insert("toolset", m_toolset);
-
- sendRequest(HANDSHAKE_TYPE, extra);
-}
-
-void ServerMode::reportError(const QString &msg)
-{
- qCWarning(cmakeServerMode) << "Report Error:" << msg;
- emit message(msg);
- emit errorOccured(msg);
-}
-
-} // namespace Internal
-} // namespace CMakeProjectManager
diff --git a/src/plugins/cmakeprojectmanager/servermode.h b/src/plugins/cmakeprojectmanager/servermode.h
deleted file mode 100644
index dc22825153..0000000000
--- a/src/plugins/cmakeprojectmanager/servermode.h
+++ /dev/null
@@ -1,125 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 <utils/qtcprocess.h>
-
-#include <QLoggingCategory>
-#include <QTimer>
-#include <QVariantMap>
-#include <QTemporaryDir>
-
-#include <memory>
-
-QT_FORWARD_DECLARE_CLASS(QLocalSocket);
-
-namespace Utils { class QtcProcess; }
-
-namespace CMakeProjectManager {
-namespace Internal {
-
-class ServerMode final : public QObject
-{
- Q_OBJECT
-
-public:
- ServerMode(const Utils::Environment &env,
- const Utils::FilePath &sourceDirectory, const Utils::FilePath &buildDirectory,
- const Utils::FilePath &cmakeExecutable,
- const QString &generator, const QString &extraGenerator,
- const QString &platform, const QString &toolset,
- bool experimental, int major, int minor = -1,
- QObject *parent = nullptr);
- ~ServerMode() final;
-
- void sendRequest(const QString &type, const QVariantMap &extra = QVariantMap(),
- const QVariant &cookie = QVariant());
-
- bool isConnected();
-
-signals:
- void connected();
- void disconnected();
- void message(const QString &msg);
- void errorOccured(const QString &msg);
-
- // Forward stuff from the server
- void cmakeReply(const QVariantMap &data, const QString &inResponseTo, const QVariant &cookie);
- void cmakeError(const QString &errorMessage, const QString &inResponseTo, const QVariant &cookie);
- void cmakeMessage(const QString &message, const QString &inResponseTo, const QVariant &cookie);
- void cmakeProgress(int min, int cur, int max, const QString &inResponseTo, const QVariant &cookie);
- void cmakeSignal(const QString &name, const QVariantMap &data);
-
-private:
- void connectToServer();
- void handleCMakeFinished(int code, QProcess::ExitStatus status);
-
- void handleRawCMakeServerData();
- void parseBuffer(const QByteArray &buffer);
- void parseJson(const QVariantMap &data);
-
- void handleHello(const QVariantMap &data);
-
- void reportError(const QString &msg);
-
-#if defined(Q_OS_UNIX)
- QTemporaryDir m_socketDir;
-#endif
- std::unique_ptr<Utils::QtcProcess> m_cmakeProcess;
- QLocalSocket *m_cmakeSocket = nullptr;
- QTimer m_connectionTimer;
-
- Utils::FilePath m_sourceDirectory;
- Utils::FilePath m_buildDirectory;
- Utils::CommandLine m_cmakeCommand;
-
- QByteArray m_buffer;
-
- struct ExpectedReply {
- QString type;
- QVariant cookie;
- };
- std::vector<ExpectedReply> m_expectedReplies;
-
- const QString m_generator;
- const QString m_extraGenerator;
- const QString m_platform;
- const QString m_toolset;
- QString m_socketName;
- const bool m_useExperimental;
- bool m_gotHello = false;
- bool m_isConnected = false;
- const int m_majorProtocol = -1;
- const int m_minorProtocol = -1;
-
- int m_requestCounter = 0;
-
-};
-
-} // namespace Internal
-} // namespace CMakeProjectManager
-
-Q_DECLARE_LOGGING_CATEGORY(cmakeServerMode);
diff --git a/src/plugins/cmakeprojectmanager/servermodereader.cpp b/src/plugins/cmakeprojectmanager/servermodereader.cpp
deleted file mode 100644
index f86081bd38..0000000000
--- a/src/plugins/cmakeprojectmanager/servermodereader.cpp
+++ /dev/null
@@ -1,935 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "servermodereader.h"
-
-#include "cmakebuildconfiguration.h"
-#include "cmakeprojectconstants.h"
-#include "cmakeprojectmanager.h"
-#include "cmakeprojectnodes.h"
-#include "servermode.h"
-#include "projecttreehelper.h"
-
-#include <coreplugin/editormanager/editormanager.h>
-#include <coreplugin/messagemanager.h>
-#include <coreplugin/progressmanager/progressmanager.h>
-#include <projectexplorer/projectexplorerconstants.h>
-#include <projectexplorer/toolchain.h>
-#include <projectexplorer/task.h>
-#include <projectexplorer/taskhub.h>
-
-#include <utils/algorithm.h>
-#include <utils/qtcassert.h>
-#include <utils/qtcprocess.h>
-
-#include <QVector>
-
-using namespace ProjectExplorer;
-using namespace Utils;
-
-namespace CMakeProjectManager {
-namespace Internal {
-
-const char CACHE_TYPE[] = "cache";
-const char CODEMODEL_TYPE[] = "codemodel";
-const char CONFIGURE_TYPE[] = "configure";
-const char CMAKE_INPUTS_TYPE[] = "cmakeInputs";
-const char COMPUTE_TYPE[] = "compute";
-
-const char BACKTRACE_KEY[] = "backtrace";
-const char LINE_KEY[] = "line";
-const char NAME_KEY[] = "name";
-const char PATH_KEY[] = "path";
-const char SOURCE_DIRECTORY_KEY[] = "sourceDirectory";
-const char SOURCES_KEY[] = "sources";
-
-const int MAX_PROGRESS = 1400;
-
-// --------------------------------------------------------------------
-// ServerModeReader:
-// --------------------------------------------------------------------
-
-ServerModeReader::ServerModeReader()
-{
- connect(&m_parser, &CMakeParser::addOutput,
- this, [](const QString &m) { Core::MessageManager::write(m); });
- connect(&m_parser, &CMakeParser::addTask, this, [this](const Task &t) {
- Task editable(t);
- if (!editable.file.isEmpty()) {
- QDir srcDir(m_parameters.sourceDirectory.toString());
- editable.file = FilePath::fromString(srcDir.absoluteFilePath(editable.file.toString()));
- }
- TaskHub::addTask(editable);
- });
-}
-
-ServerModeReader::~ServerModeReader()
-{
- stop();
-}
-
-void ServerModeReader::setParameters(const BuildDirParameters &p)
-{
- CMakeTool *cmake = p.cmakeTool();
- QTC_ASSERT(cmake, return);
-
- m_parameters = p;
-
- m_parser.setSourceDirectory(m_parameters.sourceDirectory.toString());
- createNewServer();
-}
-
-bool ServerModeReader::isCompatible(const BuildDirParameters &p)
-{
- CMakeTool *newCmake = p.cmakeTool();
- if (newCmake->readerType() != CMakeTool::FileApi)
- return false;
-
- CMakeTool *oldCmake = m_parameters.cmakeTool();
- if (!newCmake || !oldCmake)
- return false;
-
- // Server mode connection got lost, reset...
- if (!oldCmake && oldCmake->cmakeExecutable().isEmpty() && !m_cmakeServer)
- return false;
-
- return newCmake->hasServerMode()
- && newCmake->cmakeExecutable() == oldCmake->cmakeExecutable()
- && p.environment == m_parameters.environment
- && p.generator == m_parameters.generator
- && p.extraGenerator == m_parameters.extraGenerator
- && p.platform == m_parameters.platform
- && p.toolset == m_parameters.toolset
- && p.sourceDirectory == m_parameters.sourceDirectory
- && p.workDirectory == m_parameters.workDirectory;
-}
-
-void ServerModeReader::resetData()
-{
- m_cmakeConfiguration.clear();
- // m_cmakeFiles: Keep these!
- m_cmakeInputsFileNodes.clear();
- qDeleteAll(m_projects); // Also deletes targets and filegroups that are its children!
- m_projects.clear();
- m_targets.clear();
- m_fileGroups.clear();
-}
-
-void ServerModeReader::parse(bool forceCMakeRun, bool forceConfiguration)
-{
- emit configurationStarted();
-
- QTC_ASSERT(m_cmakeServer, return);
- QVariantMap extra;
-
- bool delayConfigurationRun = false;
- if (forceCMakeRun && m_cmakeServer->isConnected()) {
- createNewServer();
- delayConfigurationRun = true;
- }
-
- if (forceConfiguration) {
- QStringList cacheArguments = transform(m_parameters.configuration,
- [this](const CMakeConfigItem &i) {
- return i.toArgument(m_parameters.expander);
- });
- Core::MessageManager::write(tr("Starting to parse CMake project, using: \"%1\".")
- .arg(cacheArguments.join("\", \"")));
- cacheArguments.prepend(QString()); // Work around a bug in CMake 3.7.0 and 3.7.1 where
- // the first argument gets lost!
- extra.insert("cacheArguments", QVariant(cacheArguments));
- } else {
- Core::MessageManager::write(tr("Starting to parse CMake project."));
- }
-
- m_future.reset(new QFutureInterface<void>());
- m_future->setProgressRange(0, MAX_PROGRESS);
- m_progressStepMinimum = 0;
- m_progressStepMaximum = 1000;
- Core::ProgressManager::addTask(m_future->future(),
- tr("Configuring \"%1\"").arg(m_parameters.projectName),
- "CMake.Configure");
-
- if (!delayConfigurationRun) {
- sendConfigureRequest(extra);
- } else {
- m_delayedConfigurationData = extra;
- }
-}
-
-void ServerModeReader::stop()
-{
- if (m_future) {
- m_future->reportCanceled();
- m_future->reportFinished();
- m_future.reset();
- }
- m_parser.flush();
-}
-
-bool ServerModeReader::isParsing() const
-{
- return static_cast<bool>(m_future);
-}
-
-QList<CMakeBuildTarget> ServerModeReader::takeBuildTargets(QString &errorMessage)
-{
- Q_UNUSED(errorMessage)
- QDir topSourceDir(m_parameters.sourceDirectory.toString());
- const QList<CMakeBuildTarget> result
- = transform(m_targets, [&topSourceDir](const Target *t) -> CMakeBuildTarget {
- CMakeBuildTarget ct;
- ct.title = t->name;
- ct.executable = t->artifacts.isEmpty() ? FilePath() : t->artifacts.at(0);
- TargetType type = UtilityType;
- if (t->type == "EXECUTABLE")
- type = ExecutableType;
- else if (t->type == "STATIC_LIBRARY")
- type = StaticLibraryType;
- else if (t->type == "OBJECT_LIBRARY")
- type = ObjectLibraryType;
- else if (t->type == "MODULE_LIBRARY" || t->type == "SHARED_LIBRARY"
- || t->type == "INTERFACE_LIBRARY")
- type = DynamicLibraryType;
- else
- type = UtilityType;
- ct.targetType = type;
- if (t->artifacts.isEmpty()) {
- ct.workingDirectory = t->buildDirectory;
- } else {
- ct.workingDirectory = Utils::FilePath::fromString(
- t->artifacts.at(0).toFileInfo().absolutePath());
- }
- ct.sourceDirectory = FilePath::fromString(
- QDir::cleanPath(topSourceDir.absoluteFilePath(t->sourceDirectory.toString())));
- return ct;
- });
- m_targets.clear();
- return result;
-}
-
-CMakeConfig ServerModeReader::takeParsedConfiguration(QString &errorMessage)
-{
- Q_UNUSED(errorMessage)
- CMakeConfig config = m_cmakeConfiguration;
- m_cmakeConfiguration.clear();
- return config;
-}
-
-std::unique_ptr<CMakeProjectNode> ServerModeReader::generateProjectTree(const QList<const FileNode *> &allFiles,
- QString &errorMessage)
-{
- Q_UNUSED(errorMessage)
- auto root = std::make_unique<CMakeProjectNode>(m_parameters.sourceDirectory);
-
- // Split up cmake inputs into useful chunks:
- std::vector<std::unique_ptr<FileNode>> cmakeFilesSource;
- std::vector<std::unique_ptr<FileNode>> cmakeFilesBuild;
- std::vector<std::unique_ptr<FileNode>> cmakeFilesOther;
- std::vector<std::unique_ptr<FileNode>> cmakeLists;
-
- for (std::unique_ptr<FileNode> &fn : m_cmakeInputsFileNodes) {
- const FilePath path = fn->filePath();
- if (path.fileName().compare("CMakeLists.txt", HostOsInfo::fileNameCaseSensitivity()) == 0)
- cmakeLists.emplace_back(std::move(fn));
- else if (path.isChildOf(m_parameters.workDirectory))
- cmakeFilesBuild.emplace_back(std::move(fn));
- else if (path.isChildOf(m_parameters.sourceDirectory))
- cmakeFilesSource.emplace_back(std::move(fn));
- else
- cmakeFilesOther.emplace_back(std::move(fn));
- }
- m_cmakeInputsFileNodes.clear(); // Clean out, they are not going to be used anymore!
-
- const Project *topLevel = Utils::findOrDefault(m_projects, [this](const Project *p) {
- return m_parameters.sourceDirectory == p->sourceDirectory;
- });
- if (topLevel)
- root->setDisplayName(topLevel->name);
-
- QHash<Utils::FilePath, ProjectNode *> cmakeListsNodes = addCMakeLists(root.get(),
- std::move(cmakeLists));
- QSet<FilePath> knownHeaders;
- addProjects(cmakeListsNodes, m_projects, knownHeaders);
-
- addHeaderNodes(root.get(), knownHeaders, allFiles);
-
- if (cmakeFilesSource.size() > 0 || cmakeFilesBuild.size() > 0 || cmakeFilesOther.size() > 0)
- addCMakeInputs(root.get(),
- m_parameters.sourceDirectory,
- m_parameters.workDirectory,
- std::move(cmakeFilesSource),
- std::move(cmakeFilesBuild),
- std::move(cmakeFilesOther));
-
- return root;
-}
-
-RawProjectParts ServerModeReader::createRawProjectParts(QString &errorMessage)
-{
- Q_UNUSED(errorMessage)
- RawProjectParts rpps;
-
- int counter = 0;
- for (const FileGroup *fg : qAsConst(m_fileGroups)) {
- // CMake users worked around Creator's inability of listing header files by creating
- // custom targets with all the header files. This target breaks the code model, so
- // keep quiet about it:-)
- if (fg->macros.isEmpty()
- && fg->includePaths.isEmpty()
- && !fg->isGenerated
- && Utils::allOf(fg->sources, [](const Utils::FilePath &source) {
- return Node::fileTypeForFileName(source) == FileType::Header;
- })) {
- qWarning() << "Not reporting all-header file group of target" << fg->target << "to code model.";
- continue;
- }
-
- ++counter;
- const QStringList flags = QtcProcess::splitArgs(fg->compileFlags);
- const QStringList includes = transform(fg->includePaths, [](const IncludePath *ip) { return ip->path.toString(); });
-
- RawProjectPart rpp;
- rpp.setProjectFileLocation(fg->target->sourceDirectory.toString() + "/CMakeLists.txt");
- rpp.setBuildSystemTarget(fg->target->name);
- rpp.setDisplayName(fg->target->name + QString::number(counter));
- rpp.setMacros(fg->macros);
- rpp.setIncludePaths(includes);
-
- RawProjectPartFlags cProjectFlags;
- cProjectFlags.commandLineFlags = flags;
- rpp.setFlagsForC(cProjectFlags);
-
- RawProjectPartFlags cxxProjectFlags;
- cxxProjectFlags.commandLineFlags = flags;
- rpp.setFlagsForCxx(cxxProjectFlags);
-
- rpp.setFiles(transform(fg->sources, &FilePath::toString));
-
- const bool isExecutable = fg->target->type == "EXECUTABLE";
- rpp.setBuildTargetType(isExecutable ? ProjectExplorer::BuildTargetType::Executable
- : ProjectExplorer::BuildTargetType::Library);
- rpps.append(rpp);
- }
-
- return rpps;
-}
-
-void ServerModeReader::createNewServer()
-{
- QTC_ASSERT(m_parameters.cmakeTool(), return);
- m_cmakeServer
- = std::make_unique<ServerMode>(
- m_parameters.environment,
- m_parameters.sourceDirectory, m_parameters.workDirectory,
- m_parameters.cmakeTool()->cmakeExecutable(),
- m_parameters.generator,
- m_parameters.extraGenerator,
- m_parameters.platform, m_parameters.toolset,
- true, 1);
-
- connect(m_cmakeServer.get(), &ServerMode::errorOccured,
- this, &ServerModeReader::errorOccured);
- connect(m_cmakeServer.get(), &ServerMode::cmakeReply,
- this, &ServerModeReader::handleReply);
- connect(m_cmakeServer.get(), &ServerMode::cmakeError,
- this, &ServerModeReader::handleError);
- connect(m_cmakeServer.get(), &ServerMode::cmakeProgress,
- this, &ServerModeReader::handleProgress);
- connect(m_cmakeServer.get(), &ServerMode::cmakeSignal,
- this, &ServerModeReader::handleSignal);
- connect(m_cmakeServer.get(), &ServerMode::cmakeMessage, [this](const QString &m) {
- const QStringList lines = m.split('\n');
- for (const QString &l : lines) {
- m_parser.stdError(l);
- Core::MessageManager::write(l);
- }
- });
- connect(m_cmakeServer.get(), &ServerMode::message,
- this, [](const QString &m) { Core::MessageManager::write(m); });
- connect(m_cmakeServer.get(),
- &ServerMode::connected,
- this,
- &ServerModeReader::handleServerConnected,
- Qt::QueuedConnection); // Delay
- connect(m_cmakeServer.get(), &ServerMode::disconnected,
- this, [this]() {
- stop();
- Core::MessageManager::write(tr("Parsing of CMake project failed: Connection to CMake server lost."));
- m_cmakeServer.reset();
- }, Qt::QueuedConnection); // Delay
-
-}
-
-void ServerModeReader::handleReply(const QVariantMap &data, const QString &inReplyTo)
-{
- if (!m_delayedErrorMessage.isEmpty()) {
- // Handle reply to cache after error:
- if (inReplyTo == CACHE_TYPE)
- extractCacheData(data);
- reportError();
- } else {
- // No error yet:
- if (inReplyTo == CONFIGURE_TYPE) {
- m_cmakeServer->sendRequest(COMPUTE_TYPE);
- if (m_future)
- m_future->setProgressValue(1000);
- m_progressStepMinimum = m_progressStepMaximum;
- m_progressStepMaximum = 1100;
- } else if (inReplyTo == COMPUTE_TYPE) {
- m_cmakeServer->sendRequest(CODEMODEL_TYPE);
- if (m_future)
- m_future->setProgressValue(1100);
- m_progressStepMinimum = m_progressStepMaximum;
- m_progressStepMaximum = 1200;
- } else if (inReplyTo == CODEMODEL_TYPE) {
- extractCodeModelData(data);
- m_cmakeServer->sendRequest(CMAKE_INPUTS_TYPE);
- if (m_future)
- m_future->setProgressValue(1200);
- m_progressStepMinimum = m_progressStepMaximum;
- m_progressStepMaximum = 1300;
- } else if (inReplyTo == CMAKE_INPUTS_TYPE) {
- extractCMakeInputsData(data);
- m_cmakeServer->sendRequest(CACHE_TYPE);
- if (m_future)
- m_future->setProgressValue(1300);
- m_progressStepMinimum = m_progressStepMaximum;
- m_progressStepMaximum = 1400;
- } else if (inReplyTo == CACHE_TYPE) {
- extractCacheData(data);
- if (m_future) {
- m_future->setProgressValue(MAX_PROGRESS);
- m_future->reportFinished();
- m_future.reset();
- }
- Core::MessageManager::write(tr("CMake Project was parsed successfully."));
- emit dataAvailable();
- }
- }
-}
-
-void ServerModeReader::handleError(const QString &message)
-{
- TaskHub::addTask(BuildSystemTask(Task::Error, message));
-
- if (!m_delayedErrorMessage.isEmpty()) {
- reportError();
- return;
- }
-
- m_delayedErrorMessage = message;
-
- // Always try to read CMakeCache, even after an error!
- m_cmakeServer->sendRequest(CACHE_TYPE);
- if (m_future)
- m_future->setProgressValue(1300);
-}
-
-void ServerModeReader::handleProgress(int min, int cur, int max, const QString &inReplyTo)
-{
- Q_UNUSED(inReplyTo)
-
- if (!m_future)
- return;
- const int progress = calculateProgress(m_progressStepMinimum, min, cur, max, m_progressStepMaximum);
- m_future->setProgressValue(progress);
-}
-
-void ServerModeReader::handleSignal(const QString &signal, const QVariantMap &data)
-{
- Q_UNUSED(signal)
- Q_UNUSED(data)
- // We do not need to act on fileChanged signals nor on dirty signals!
-}
-
-void ServerModeReader::handleServerConnected()
-{
- if (m_delayedConfigurationData) {
- sendConfigureRequest(*m_delayedConfigurationData);
- m_delayedConfigurationData.reset();
- } else {
- emit isReadyNow();
- }
-}
-
-void ServerModeReader::sendConfigureRequest(const QVariantMap &extra)
-{
- m_delayedErrorMessage.clear();
- m_cmakeServer->sendRequest(CONFIGURE_TYPE, extra);
-}
-
-void ServerModeReader::reportError()
-{
- stop();
- Core::MessageManager::write(tr("CMake Project parsing failed."));
- emit errorOccured(m_delayedErrorMessage);
-
- if (m_future)
- m_future->reportCanceled();
-
- m_delayedErrorMessage.clear();
-}
-
-int ServerModeReader::calculateProgress(const int minRange, const int min, const int cur, const int max, const int maxRange)
-{
- if (minRange == maxRange || min == max)
- return minRange;
- const int clampedCur = std::min(std::max(cur, min), max);
- return minRange + ((clampedCur - min) / (max - min)) * (maxRange - minRange);
-}
-
-void ServerModeReader::extractCodeModelData(const QVariantMap &data)
-{
- const QVariantList configs = data.value("configurations").toList();
- for (const QVariant &c : configs) {
- const QVariantMap &cData = c.toMap();
- extractConfigurationData(cData);
- }
-}
-
-void ServerModeReader::extractConfigurationData(const QVariantMap &data)
-{
- const QString name = data.value(NAME_KEY).toString();
- Q_UNUSED(name)
- QSet<QString> knownTargets; // To filter duplicate target names:-/
- const QVariantList projects = data.value("projects").toList();
- for (const QVariant &p : projects) {
- const QVariantMap pData = p.toMap();
- m_projects.append(extractProjectData(pData, knownTargets));
- }
-}
-
-ServerModeReader::Project *ServerModeReader::extractProjectData(const QVariantMap &data,
- QSet<QString> &knownTargets)
-{
- auto project = new Project;
- project->name = data.value(NAME_KEY).toString();
- project->sourceDirectory = FilePath::fromString(data.value(SOURCE_DIRECTORY_KEY).toString());
-
- const QVariantList targets = data.value("targets").toList();
- for (const QVariant &t : targets) {
- const QVariantMap tData = t.toMap();
- Target *tp = extractTargetData(tData, project, knownTargets);
- if (tp)
- project->targets.append(tp);
- }
- return project;
-}
-
-ServerModeReader::Target *ServerModeReader::extractTargetData(const QVariantMap &data, Project *p,
- QSet<QString> &knownTargets)
-{
- const QString targetName = data.value(NAME_KEY).toString();
-
- // Remove duplicate targets: CMake unfortunately does duplicate targets for all projects that
- // contain them. Keep at least till cmake 3.9 is deprecated.
- const int count = knownTargets.count();
- knownTargets.insert(targetName);
- if (knownTargets.count() == count)
- return nullptr;
-
- auto target = new Target;
- target->project = p;
- target->name = targetName;
- target->sourceDirectory = FilePath::fromString(data.value(SOURCE_DIRECTORY_KEY).toString());
- target->buildDirectory = FilePath::fromString(data.value("buildDirectory").toString());
-
- target->crossReferences = extractCrossReferences(data.value("crossReferences").toMap());
-
- QDir srcDir(target->sourceDirectory.toString());
-
- target->type = data.value("type").toString();
- const QStringList artifacts = data.value("artifacts").toStringList();
- target->artifacts = transform(artifacts, [&srcDir](const QString &a) { return FilePath::fromString(srcDir.absoluteFilePath(a)); });
-
- const QVariantList fileGroups = data.value("fileGroups").toList();
- for (const QVariant &fg : fileGroups) {
- const QVariantMap fgData = fg.toMap();
- target->fileGroups.append(extractFileGroupData(fgData, srcDir, target));
- }
-
- fixTarget(target);
-
- m_targets.append(target);
- return target;
-}
-
-ServerModeReader::FileGroup *ServerModeReader::extractFileGroupData(const QVariantMap &data,
- const QDir &srcDir,
- Target *t)
-{
- auto fileGroup = new FileGroup;
- fileGroup->target = t;
- fileGroup->compileFlags = data.value("compileFlags").toString();
- fileGroup->macros = Utils::transform<QVector>(data.value("defines").toStringList(), [](const QString &s) {
- return ProjectExplorer::Macro::fromKeyValue(s);
- });
- fileGroup->includePaths = transform(data.value("includePath").toList(),
- [](const QVariant &i) -> IncludePath* {
- const QVariantMap iData = i.toMap();
- auto result = new IncludePath;
- result->path = FilePath::fromString(iData.value("path").toString());
- result->isSystem = iData.value("isSystem", false).toBool();
- return result;
- });
- fileGroup->isGenerated = data.value("isGenerated", false).toBool();
- fileGroup->sources = transform(data.value(SOURCES_KEY).toStringList(),
- [&srcDir](const QString &s) {
- return FilePath::fromString(QDir::cleanPath(srcDir.absoluteFilePath(s)));
- });
-
- m_fileGroups.append(fileGroup);
- return fileGroup;
-}
-
-QList<ServerModeReader::CrossReference *> ServerModeReader::extractCrossReferences(const QVariantMap &data)
-{
- QList<CrossReference *> crossReferences;
-
- if (data.isEmpty())
- return crossReferences;
-
- auto cr = std::make_unique<CrossReference>();
- cr->backtrace = extractBacktrace(data.value(BACKTRACE_KEY, QVariantList()).toList());
- QTC_ASSERT(!cr->backtrace.isEmpty(), return {});
- crossReferences.append(cr.release());
-
- const QVariantList related = data.value("relatedStatements", QVariantList()).toList();
- for (const QVariant &relatedData : related) {
- auto cr = std::make_unique<CrossReference>();
-
- // extract information:
- const QVariantMap map = relatedData.toMap();
- const QString typeString = map.value("type", QString()).toString();
- if (typeString.isEmpty())
- cr->type = CrossReference::TARGET;
- else if (typeString == "target_link_libraries")
- cr->type = CrossReference::LIBRARIES;
- else if (typeString == "target_compile_defines")
- cr->type = CrossReference::DEFINES;
- else if (typeString == "target_include_directories")
- cr->type = CrossReference::INCLUDES;
- else
- cr->type = CrossReference::UNKNOWN;
- cr->backtrace = extractBacktrace(map.value(BACKTRACE_KEY, QVariantList()).toList());
-
- // sanity check:
- if (cr->backtrace.isEmpty())
- continue;
-
- // store information:
- crossReferences.append(cr.release());
- }
- return crossReferences;
-}
-
-ServerModeReader::BacktraceItem *ServerModeReader::extractBacktraceItem(const QVariantMap &data)
-{
- QTC_ASSERT(!data.isEmpty(), return nullptr);
- auto item = std::make_unique<BacktraceItem>();
-
- item->line = data.value(LINE_KEY, -1).toInt();
- item->name = data.value(NAME_KEY, QString()).toString();
- item->path = data.value(PATH_KEY, QString()).toString();
-
- QTC_ASSERT(!item->path.isEmpty(), return nullptr);
- return item.release();
-}
-
-QList<ServerModeReader::BacktraceItem *> ServerModeReader::extractBacktrace(const QVariantList &data)
-{
- QList<BacktraceItem *> btResult;
- for (const QVariant &bt : data) {
- BacktraceItem *btItem = extractBacktraceItem(bt.toMap());
- QTC_ASSERT(btItem, continue);
-
- btResult.append(btItem);
- }
- return btResult;
-}
-
-void ServerModeReader::extractCMakeInputsData(const QVariantMap &data)
-{
- const FilePath src = FilePath::fromString(data.value(SOURCE_DIRECTORY_KEY).toString());
- QTC_ASSERT(src == m_parameters.sourceDirectory, return);
- QDir srcDir(src.toString());
-
- m_cmakeFiles.clear();
-
- const QVariantList buildFiles = data.value("buildFiles").toList();
- for (const QVariant &bf : buildFiles) {
- const QVariantMap &section = bf.toMap();
- const QStringList sources = section.value(SOURCES_KEY).toStringList();
-
- const bool isTemporary = section.value("isTemporary").toBool(); // generated file
- const bool isCMake = section.value("isCMake").toBool(); // part of the cmake installation
-
- for (const QString &s : sources) {
- const FilePath sfn = FilePath::fromString(QDir::cleanPath(srcDir.absoluteFilePath(s)));
- const int oldCount = m_cmakeFiles.count();
- m_cmakeFiles.insert(sfn);
- if (oldCount < m_cmakeFiles.count()) {
- const bool isCMakeListsFile = sfn.toString().endsWith("/CMakeLists.txt");
-
- if (isCMake && !isCMakeListsFile)
- // Skip files that cmake considers to be part of the installation -- but include
- // CMakeLists.txt files. This unbreaks cmake binaries running from their own
- // build directory.
- continue;
-
- auto node = std::make_unique<FileNode>(sfn, FileType::Project);
- node->setIsGenerated(isTemporary && !isCMakeListsFile); // CMakeLists.txt are never
- // generated, independent
- // what cmake thinks:-)
-
- m_cmakeInputsFileNodes.emplace_back(std::move(node));
- }
- }
- }
-}
-
-void ServerModeReader::extractCacheData(const QVariantMap &data)
-{
- CMakeConfig config;
- const QVariantList entries = data.value("cache").toList();
- for (const QVariant &e : entries) {
- const QVariantMap eData = e.toMap();
- CMakeConfigItem item;
- item.key = eData.value("key").toByteArray();
- item.value = eData.value("value").toByteArray();
- item.type = CMakeConfigItem::typeStringToType(eData.value("type").toByteArray());
- const QVariantMap properties = eData.value("properties").toMap();
- item.isAdvanced = properties.value("ADVANCED", false).toBool();
- item.documentation = properties.value("HELPSTRING").toByteArray();
- item.values = CMakeConfigItem::cmakeSplitValue(properties.value("STRINGS").toString(), true);
- config.append(item);
- }
- m_cmakeConfiguration = config;
-}
-
-void ServerModeReader::fixTarget(ServerModeReader::Target *target) const
-{
- QHash<QString, const FileGroup *> languageFallbacks;
-
- for (const FileGroup *group : qAsConst(target->fileGroups)) {
- if (group->includePaths.isEmpty() && group->compileFlags.isEmpty()
- && group->macros.isEmpty())
- continue;
-
- const FileGroup *fallback = languageFallbacks.value(group->language);
- if (!fallback || fallback->sources.count() < group->sources.count())
- languageFallbacks.insert(group->language, group);
- }
-
- if (!languageFallbacks.value(""))
- return; // No empty language groups found, no need to proceed.
-
- const FileGroup *fallback = languageFallbacks.value("CXX");
- if (!fallback)
- fallback = languageFallbacks.value("C");
- if (!fallback)
- fallback = languageFallbacks.value("");
-
- if (!fallback)
- return;
-
- for (auto it = target->fileGroups.begin(); it != target->fileGroups.end(); ++it) {
- if (!(*it)->language.isEmpty())
- continue;
- (*it)->language = fallback->language.isEmpty() ? "CXX" : fallback->language;
-
- if (*it == fallback
- || !(*it)->includePaths.isEmpty() || !(*it)->macros.isEmpty()
- || !(*it)->compileFlags.isEmpty())
- continue;
-
- for (const IncludePath *ip : fallback->includePaths)
- (*it)->includePaths.append(new IncludePath(*ip));
- (*it)->macros = fallback->macros;
- (*it)->compileFlags = fallback->compileFlags;
- }
-}
-
-void ServerModeReader::addProjects(const QHash<Utils::FilePath, ProjectNode *> &cmakeListsNodes,
- const QList<Project *> &projects,
- QSet<FilePath> &knownHeaders)
-{
- for (const Project *p : projects) {
- createProjectNode(cmakeListsNodes, p->sourceDirectory, p->name);
- addTargets(cmakeListsNodes, p->targets, knownHeaders);
- }
-}
-
-void ServerModeReader::addTargets(
- const QHash<Utils::FilePath, ProjectExplorer::ProjectNode *> &cmakeListsNodes,
- const QList<Target *> &targets,
- QSet<Utils::FilePath> &knownHeaders)
-{
- for (const Target *t : targets) {
- CMakeTargetNode *tNode = createTargetNode(cmakeListsNodes, t->sourceDirectory, t->name);
- QTC_ASSERT(tNode, qDebug() << "No target node for" << t->sourceDirectory << t->name; continue);
- tNode->setTargetInformation(t->artifacts, t->type);
- tNode->setBuildDirectory(t->buildDirectory);
- QVector<FolderNode::LocationInfo> info;
- // Set up a default target path:
- FilePath targetPath = t->sourceDirectory.pathAppended("CMakeLists.txt");
- for (CrossReference *cr : qAsConst(t->crossReferences)) {
- BacktraceItem *bt = cr->backtrace.isEmpty() ? nullptr : cr->backtrace.at(0);
- if (bt) {
- const QString btName = bt->name.toLower();
- const FilePath path = Utils::FilePath::fromUserInput(bt->path);
- QString dn;
- if (cr->type != CrossReference::TARGET) {
- if (path == targetPath) {
- if (bt->line >= 0)
- dn = tr("%1 in line %2").arg(btName).arg(bt->line);
- else
- dn = tr("%1").arg(btName);
- } else {
- if (bt->line >= 0)
- dn = tr("%1 in %2:%3").arg(btName, path.toUserOutput()).arg(bt->line);
- else
- dn = tr("%1 in %2").arg(btName, path.toUserOutput());
- }
- } else {
- dn = tr("Target Definition");
- targetPath = path;
- }
- info.append(FolderNode::LocationInfo(dn, path, bt->line));
- }
- }
- tNode->setLocationInfo(info);
- addFileGroups(tNode, t->sourceDirectory, t->buildDirectory, t->fileGroups, knownHeaders);
- }
-}
-
-void ServerModeReader::addFileGroups(ProjectNode *targetRoot,
- const Utils::FilePath &sourceDirectory,
- const Utils::FilePath &buildDirectory,
- const QList<ServerModeReader::FileGroup *> &fileGroups,
- QSet<Utils::FilePath> &knownHeaders)
-{
- std::vector<std::unique_ptr<FileNode>> toList;
- QSet<Utils::FilePath> alreadyListed;
- // Files already added by other configurations:
- targetRoot->forEachGenericNode([&alreadyListed](const Node *n) {
- alreadyListed.insert(n->filePath());
- });
-
- for (const FileGroup *f : fileGroups) {
- const QList<FilePath> newSources = Utils::filtered(f->sources, [&alreadyListed](const Utils::FilePath &fn) {
- const int count = alreadyListed.count();
- alreadyListed.insert(fn);
- return count != alreadyListed.count();
- });
- std::vector<std::unique_ptr<FileNode>> newFileNodes = Utils::transform<std::vector>(
- newSources, [f, &knownHeaders](const Utils::FilePath &fn) {
- auto node = std::make_unique<FileNode>(fn, Node::fileTypeForFileName(fn));
- node->setIsGenerated(f->isGenerated);
- if (node->fileType() == FileType::Header)
- knownHeaders.insert(node->filePath());
- return node;
- });
- std::move(std::begin(newFileNodes), std::end(newFileNodes), std::back_inserter(toList));
- }
-
- // Split up files in groups (based on location):
- const bool inSourceBuild = (m_parameters.workDirectory == m_parameters.sourceDirectory);
- std::vector<std::unique_ptr<FileNode>> sourceFileNodes;
- std::vector<std::unique_ptr<FileNode>> buildFileNodes;
- std::vector<std::unique_ptr<FileNode>> otherFileNodes;
- for (std::unique_ptr<FileNode> &fn : toList) {
- if (fn->filePath().isChildOf(m_parameters.workDirectory) && !inSourceBuild)
- buildFileNodes.emplace_back(std::move(fn));
- else if (fn->filePath().isChildOf(m_parameters.sourceDirectory))
- sourceFileNodes.emplace_back(std::move(fn));
- else
- otherFileNodes.emplace_back(std::move(fn));
- }
-
- addCMakeVFolder(targetRoot, sourceDirectory, 1000, QString(), std::move(sourceFileNodes));
- addCMakeVFolder(targetRoot, buildDirectory, 100, tr("<Build Directory>"), std::move(buildFileNodes));
- addCMakeVFolder(targetRoot, Utils::FilePath(), 10, tr("<Other Locations>"), std::move(otherFileNodes));
-}
-
-} // namespace Internal
-} // namespace CMakeProjectManager
-
-#if defined(WITH_TESTS)
-
-#include "cmakeprojectplugin.h"
-#include <QTest>
-
-namespace CMakeProjectManager {
-namespace Internal {
-
-void CMakeProjectPlugin::testServerModeReaderProgress_data()
-{
- QTest::addColumn<int>("minRange");
- QTest::addColumn<int>("min");
- QTest::addColumn<int>("cur");
- QTest::addColumn<int>("max");
- QTest::addColumn<int>("maxRange");
- QTest::addColumn<int>("expected");
-
- QTest::newRow("empty range") << 100 << 10 << 11 << 20 << 100 << 100;
- QTest::newRow("one range (low)") << 0 << 10 << 11 << 20 << 1 << 0;
- QTest::newRow("one range (high)") << 20 << 10 << 19 << 20 << 20 << 20;
- QTest::newRow("large range") << 30 << 10 << 11 << 20 << 100000 << 30;
-
- QTest::newRow("empty progress") << -5 << 10 << 10 << 10 << 99995 << -5;
- QTest::newRow("one progress (low)") << 42 << 10 << 10 << 11 << 100042 << 42;
- QTest::newRow("one progress (high)") << 0 << 10 << 11 << 11 << 100000 << 100000;
- QTest::newRow("large progress") << 0 << 10 << 10 << 11 << 100000 << 0;
-
- QTest::newRow("cur too low") << 0 << 10 << 9 << 100 << 100000 << 0;
- QTest::newRow("cur too high") << 0 << 10 << 101 << 100 << 100000 << 100000;
- QTest::newRow("cur much too low") << 0 << 10 << -1000 << 100 << 100000 << 0;
- QTest::newRow("cur much too high") << 0 << 10 << 1110000 << 100 << 100000 << 100000;
-}
-
-void CMakeProjectPlugin::testServerModeReaderProgress()
-{
- QFETCH(int, minRange);
- QFETCH(int, min);
- QFETCH(int, cur);
- QFETCH(int, max);
- QFETCH(int, maxRange);
- QFETCH(int, expected);
-
- ServerModeReader reader;
- const int r = reader.calculateProgress(minRange, min, cur, max, maxRange);
-
- QCOMPARE(r, expected);
-
- QVERIFY(r <= maxRange);
- QVERIFY(r >= minRange);
-}
-
-} // namespace Internal
-} // namespace CMakeProjectManager
-
-#endif
diff --git a/src/plugins/cmakeprojectmanager/servermodereader.h b/src/plugins/cmakeprojectmanager/servermodereader.h
deleted file mode 100644
index 3910df1778..0000000000
--- a/src/plugins/cmakeprojectmanager/servermodereader.h
+++ /dev/null
@@ -1,191 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "builddirreader.h"
-#include "servermode.h"
-#include "cmakeparser.h"
-
-#include <QList>
-
-#include <memory>
-
-namespace ProjectExplorer { class ProjectNode; }
-
-namespace CMakeProjectManager {
-namespace Internal {
-
-class ServerModeReader final : public BuildDirReader
-{
- Q_OBJECT
-
-public:
- ServerModeReader();
- ~ServerModeReader() final;
-
- void setParameters(const BuildDirParameters &p) final;
-
- bool isCompatible(const BuildDirParameters &p) final;
- void resetData() final;
- void parse(bool forceCMakeRun, bool forceConfiguration) final;
- void stop() final;
-
- bool isParsing() const final;
-
- QSet<Utils::FilePath> projectFilesToWatch() const final { return {}; };
- QList<CMakeBuildTarget> takeBuildTargets(QString &errorMessage) final;
- CMakeConfig takeParsedConfiguration(QString &errorMessage) final;
- std::unique_ptr<CMakeProjectNode> generateProjectTree(
- const QList<const ProjectExplorer::FileNode *> &allFiles, QString &errorMessage) final;
- ProjectExplorer::RawProjectParts createRawProjectParts(QString &errorMessage) final;
-
-private:
- void createNewServer();
- void handleReply(const QVariantMap &data, const QString &inReplyTo);
- void handleError(const QString &message);
- void handleProgress(int min, int cur, int max, const QString &inReplyTo);
- void handleSignal(const QString &signal, const QVariantMap &data);
- void handleServerConnected();
-
- void sendConfigureRequest(const QVariantMap &extra);
-
- void reportError();
-
- int calculateProgress(const int minRange, const int min,
- const int cur,
- const int max, const int maxRange);
-
- struct Target;
- struct Project;
-
- struct IncludePath {
- Utils::FilePath path;
- bool isSystem;
- };
-
- struct FileGroup {
- ~FileGroup() { qDeleteAll(includePaths); includePaths.clear(); }
-
- Target *target = nullptr;
- QString compileFlags;
- ProjectExplorer::Macros macros;
- QList<IncludePath *> includePaths;
- QString language;
- QList<Utils::FilePath> sources;
- bool isGenerated;
- };
-
- struct BacktraceItem {
- int line = -1;
- QString path;
- QString name;
- };
-
- struct CrossReference {
- ~CrossReference() { qDeleteAll(backtrace); backtrace.clear(); }
- QList<BacktraceItem *> backtrace;
- enum Type { TARGET, LIBRARIES, DEFINES, INCLUDES, UNKNOWN };
- Type type;
- };
-
- struct Target {
- ~Target() {
- qDeleteAll(fileGroups);
- fileGroups.clear();
- qDeleteAll(crossReferences);
- crossReferences.clear();
- }
-
- Project *project = nullptr;
- QString name;
- QString type;
- QList<Utils::FilePath> artifacts;
- Utils::FilePath sourceDirectory;
- Utils::FilePath buildDirectory;
- QList<FileGroup *> fileGroups;
- QList<CrossReference *> crossReferences;
- };
-
- struct Project {
- ~Project() { qDeleteAll(targets); targets.clear(); }
- QString name;
- Utils::FilePath sourceDirectory;
- QList<Target *> targets;
- };
-
- void extractCodeModelData(const QVariantMap &data);
- void extractConfigurationData(const QVariantMap &data);
- Project *extractProjectData(const QVariantMap &data, QSet<QString> &knownTargets);
- Target *extractTargetData(const QVariantMap &data, Project *p, QSet<QString> &knownTargets);
- FileGroup *extractFileGroupData(const QVariantMap &data, const QDir &srcDir, Target *t);
- QList<CrossReference *> extractCrossReferences(const QVariantMap &data);
- QList<BacktraceItem *> extractBacktrace(const QVariantList &data);
- BacktraceItem *extractBacktraceItem(const QVariantMap &data);
- void extractCMakeInputsData(const QVariantMap &data);
- void extractCacheData(const QVariantMap &data);
-
- void fixTarget(Target *target) const;
-
- void addProjects(const QHash<Utils::FilePath, ProjectExplorer::ProjectNode *> &cmakeListsNodes,
- const QList<Project *> &projects,
- QSet<Utils::FilePath> &knownHeaders);
- void addTargets(const QHash<Utils::FilePath, ProjectExplorer::ProjectNode *> &cmakeListsNodes,
- const QList<Target *> &targets,
- QSet<Utils::FilePath> &knownHeaders);
- void addFileGroups(ProjectExplorer::ProjectNode *targetRoot,
- const Utils::FilePath &sourceDirectory,
- const Utils::FilePath &buildDirectory,
- const QList<FileGroup *> &fileGroups,
- QSet<Utils::FilePath> &knownHeaders);
-
- std::unique_ptr<ServerMode> m_cmakeServer;
- std::unique_ptr<QFutureInterface<void>> m_future;
-
- int m_progressStepMinimum = 0;
- int m_progressStepMaximum = 1000;
-
- Utils::optional<QVariantMap> m_delayedConfigurationData;
-
- QString m_delayedErrorMessage;
-
- CMakeConfig m_cmakeConfiguration;
-
- QSet<Utils::FilePath> m_cmakeFiles;
- std::vector<std::unique_ptr<ProjectExplorer::FileNode>> m_cmakeInputsFileNodes;
-
- QList<Project *> m_projects;
- QList<Target *> m_targets;
- QList<FileGroup *> m_fileGroups;
-
- CMakeParser m_parser;
-
-#if defined(WITH_TESTS)
- friend class CMakeProjectPlugin;
-#endif
-};
-
-} // namespace Internal
-} // namespace CMakeProjectManager
diff --git a/src/plugins/cmakeprojectmanager/tealeafreader.cpp b/src/plugins/cmakeprojectmanager/tealeafreader.cpp
deleted file mode 100644
index 8b03b33f60..0000000000
--- a/src/plugins/cmakeprojectmanager/tealeafreader.cpp
+++ /dev/null
@@ -1,528 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "tealeafreader.h"
-
-#include "builddirmanager.h"
-#include "cmakebuildconfiguration.h"
-#include "cmakecbpparser.h"
-#include "cmakekitinformation.h"
-#include "cmakeprocess.h"
-#include "cmakeprojectconstants.h"
-#include "cmakeprojectnodes.h"
-
-#include <coreplugin/documentmanager.h>
-#include <coreplugin/editormanager/editormanager.h>
-#include <coreplugin/idocument.h>
-#include <projectexplorer/headerpath.h>
-#include <projectexplorer/kitinformation.h>
-#include <projectexplorer/projectexplorerconstants.h>
-#include <projectexplorer/target.h>
-#include <projectexplorer/toolchain.h>
-#include <projectexplorer/toolchainmanager.h>
-
-#include <utils/algorithm.h>
-#include <utils/qtcassert.h>
-#include <utils/qtcprocess.h>
-
-#include <QDateTime>
-#include <QFileInfo>
-
-using namespace Core;
-using namespace ProjectExplorer;
-using namespace Utils;
-
-namespace CMakeProjectManager {
-namespace Internal {
-
-// --------------------------------------------------------------------
-// TeaLeafReader:
-// --------------------------------------------------------------------
-
-TeaLeafReader::TeaLeafReader()
-{
- connect(EditorManager::instance(), &EditorManager::aboutToSave,
- this, [this](const IDocument *document) {
- if (m_cmakeFiles.contains(document->filePath())
- || !m_parameters.cmakeTool()
- || !m_parameters.cmakeTool()->isAutoRun())
- emit dirty();
- });
-
- // Remove \' (quote) for function-style macrosses:
- // -D'MACRO()'=xxx
- // -D'MACRO()=xxx'
- // -D'MACRO()'
- // otherwise, compiler will fails
- m_macroFixupRe1.setPattern("^-D(\\s*)'([0-9a-zA-Z_\\(\\)]+)'=");
- m_macroFixupRe2.setPattern("^-D(\\s*)'([0-9a-zA-Z_\\(\\)]+)=(.+)'$");
- m_macroFixupRe3.setPattern("^-D(\\s*)'([0-9a-zA-Z_\\(\\)]+)'$");
-}
-
-TeaLeafReader::~TeaLeafReader()
-{
- stop();
- resetData();
-}
-
-void TeaLeafReader::setParameters(const BuildDirParameters &p)
-{
- m_parameters = p;
- emit isReadyNow();
-}
-
-bool TeaLeafReader::isCompatible(const BuildDirParameters &p)
-{
- return p.cmakeTool() && p.cmakeTool()->readerType() == CMakeTool::TeaLeaf;
-}
-
-void TeaLeafReader::resetData()
-{
- m_projectName.clear();
- m_buildTargets.clear();
- m_files.clear();
-}
-
-static QString findCbpFile(const QDir &directory)
-{
- // Find the cbp file
- // the cbp file is named like the project() command in the CMakeList.txt file
- // so this function below could find the wrong cbp file, if the user changes the project()
- // 2name
- QDateTime t;
- QString file;
- foreach (const QString &cbpFile , directory.entryList()) {
- if (cbpFile.endsWith(QLatin1String(".cbp"))) {
- QFileInfo fi(directory.path() + QLatin1Char('/') + cbpFile);
- if (t.isNull() || fi.lastModified() > t) {
- file = directory.path() + QLatin1Char('/') + cbpFile;
- t = fi.lastModified();
- }
- }
- }
- return file;
-}
-
-void TeaLeafReader::parse(bool forceCMakeRun, bool forceConfiguration)
-{
- emit configurationStarted();
-
- const QString cbpFile = findCbpFile(QDir(m_parameters.workDirectory.toString()));
- const QFileInfo cbpFileFi = cbpFile.isEmpty() ? QFileInfo() : QFileInfo(cbpFile);
- if (!cbpFileFi.exists() || forceConfiguration) {
- // Initial create:
- const FilePath path = m_parameters.workDirectory.pathAppended("qtcsettings.cmake");
- startCMake(QStringList({QString("-C"), path.toUserOutput()}));
- return;
- }
-
- const bool mustUpdate = forceCMakeRun || m_cmakeFiles.isEmpty()
- || anyOf(m_cmakeFiles, [&cbpFileFi](const FilePath &f) {
- return f.toFileInfo().lastModified() > cbpFileFi.lastModified();
- });
- if (mustUpdate) {
- startCMake(QStringList());
- } else {
- extractData();
- emit dataAvailable();
- }
-}
-
-void TeaLeafReader::stop()
-{
- m_cmakeProcess.reset();
-}
-
-bool TeaLeafReader::isParsing() const
-{
- return m_cmakeProcess && m_cmakeProcess->state() != QProcess::NotRunning;
-}
-
-QSet<FilePath> TeaLeafReader::projectFilesToWatch() const
-{
- return m_cmakeFiles;
-}
-
-QList<CMakeBuildTarget> TeaLeafReader::takeBuildTargets(QString &errorMessage)
-{
- Q_UNUSED(errorMessage)
- return m_buildTargets;
-}
-
-CMakeConfig TeaLeafReader::takeParsedConfiguration(QString &errorMessage)
-{
- const FilePath cacheFile = m_parameters.workDirectory.pathAppended("CMakeCache.txt");
-
- if (!cacheFile.exists())
- return { };
-
- CMakeConfig result = BuildDirManager::parseCMakeConfiguration(cacheFile, &errorMessage);
-
- if (!errorMessage.isEmpty()) {
- return { };
- }
-
- const FilePath sourceOfBuildDir
- = FilePath::fromUtf8(CMakeConfigItem::valueOf("CMAKE_HOME_DIRECTORY", result));
- const FilePath canonicalSourceOfBuildDir = sourceOfBuildDir.canonicalPath();
- const FilePath canonicalSourceDirectory = m_parameters.sourceDirectory.canonicalPath();
- if (canonicalSourceOfBuildDir != canonicalSourceDirectory) { // Uses case-insensitive compare where appropriate
- errorMessage = tr("The build directory is not for %1 but for %2")
- .arg(canonicalSourceOfBuildDir.toUserOutput(),
- canonicalSourceDirectory.toUserOutput());
- return { };
- }
- return result;
-}
-
-std::unique_ptr<CMakeProjectNode> TeaLeafReader::generateProjectTree(
- const QList<const FileNode *> &allFiles, QString &errorMessage)
-{
- Q_UNUSED(errorMessage)
- if (m_files.size() == 0)
- return {};
-
- auto root = std::make_unique<CMakeProjectNode>(m_parameters.sourceDirectory);
- root->setDisplayName(m_projectName);
-
- QSet<FilePath> allIncludePathSet;
- for (const CMakeBuildTarget &bt : m_buildTargets) {
- const QList<Utils::FilePath> targetIncludePaths
- = Utils::filtered(bt.includeFiles, [this](const Utils::FilePath &fn) {
- return fn.isChildOf(m_parameters.sourceDirectory);
- });
- allIncludePathSet.unite(Utils::toSet(targetIncludePaths));
- }
- const QList<FilePath> allIncludePaths = Utils::toList(allIncludePathSet);
-
- const QList<const FileNode *> missingHeaders
- = Utils::filtered(allFiles, [&allIncludePaths](const FileNode *fn) -> bool {
- if (fn->fileType() != FileType::Header)
- return false;
-
- return Utils::contains(allIncludePaths, [fn](const FilePath &inc) { return fn->filePath().isChildOf(inc); });
- });
-
- // filter duplicates:
- auto alreadySeen = Utils::transform<QSet>(m_files, &FileNode::filePath);
- const QList<const FileNode *> unseenMissingHeaders = Utils::filtered(missingHeaders, [&alreadySeen](const FileNode *fn) {
- const int count = alreadySeen.count();
- alreadySeen.insert(fn->filePath());
- return (alreadySeen.count() != count);
- });
-
- root->addNestedNodes(std::move(m_files), m_parameters.sourceDirectory);
-
- std::vector<std::unique_ptr<FileNode>> fileNodes
- = transform<std::vector>(unseenMissingHeaders, [](const FileNode *fn) {
- return std::unique_ptr<FileNode>(fn->clone());
- });
- root->addNestedNodes(std::move(fileNodes), m_parameters.sourceDirectory);
-
- return root;
-}
-
-static void processCMakeIncludes(const CMakeBuildTarget &cbt, const ToolChain *tc,
- const QStringList& flags, const FilePath &sysroot,
- QSet<FilePath> &tcIncludes, QStringList &includePaths)
-{
- if (!tc)
- return;
-
- foreach (const HeaderPath &hp, tc->builtInHeaderPaths(flags, sysroot,
- Environment::systemEnvironment())) {
- tcIncludes.insert(FilePath::fromString(hp.path));
- }
- foreach (const FilePath &i, cbt.includeFiles) {
- if (!tcIncludes.contains(i))
- includePaths.append(i.toString());
- }
-}
-
-RawProjectParts TeaLeafReader::createRawProjectParts(QString &errorMessage)
-{
- Q_UNUSED(errorMessage)
- const ToolChain *tcCxx = ToolChainManager::findToolChain(m_parameters.cxxToolChainId);
- const ToolChain *tcC = ToolChainManager::findToolChain(m_parameters.cToolChainId);
- const FilePath sysroot = m_parameters.sysRoot;
-
- RawProjectParts rpps;
- QHash<QString, QStringList> targetDataCacheCxx;
- QHash<QString, QStringList> targetDataCacheC;
- foreach (const CMakeBuildTarget &cbt, m_buildTargets) {
- if (cbt.targetType == UtilityType)
- continue;
-
- // CMake shuffles the include paths that it reports via the CodeBlocks generator
- // So remove the toolchain include paths, so that at least those end up in the correct
- // place.
- auto cxxflags = getFlagsFor(cbt, targetDataCacheCxx, ProjectExplorer::Constants::CXX_LANGUAGE_ID);
- auto cflags = getFlagsFor(cbt, targetDataCacheC, ProjectExplorer::Constants::C_LANGUAGE_ID);
- QSet<FilePath> tcIncludes;
- QStringList includePaths;
- if (tcCxx || tcC) {
- processCMakeIncludes(cbt, tcCxx, cxxflags, sysroot, tcIncludes, includePaths);
- processCMakeIncludes(cbt, tcC, cflags, sysroot, tcIncludes, includePaths);
- } else {
- includePaths = transform(cbt.includeFiles, &FilePath::toString);
- }
- includePaths += m_parameters.workDirectory.toString();
- RawProjectPart rpp;
- rpp.setProjectFileLocation(cbt.sourceDirectory.toString() + "/CMakeLists.txt");
- rpp.setBuildSystemTarget(cbt.title);
- rpp.setIncludePaths(includePaths);
-
- RawProjectPartFlags cProjectFlags;
- cProjectFlags.commandLineFlags = cflags;
- rpp.setFlagsForC(cProjectFlags);
-
- RawProjectPartFlags cxxProjectFlags;
- cxxProjectFlags.commandLineFlags = cxxflags;
- rpp.setFlagsForCxx(cxxProjectFlags);
-
- rpp.setMacros(cbt.macros);
- rpp.setDisplayName(cbt.title);
- rpp.setFiles(transform(cbt.files, &FilePath::toString));
-
- const bool isExecutable = cbt.targetType == ExecutableType;
- rpp.setBuildTargetType(isExecutable ? ProjectExplorer::BuildTargetType::Executable
- : ProjectExplorer::BuildTargetType::Library);
- rpps.append(rpp);
- }
-
- return rpps;
-}
-
-void TeaLeafReader::extractData()
-{
- CMakeTool *cmake = m_parameters.cmakeTool();
- QTC_ASSERT(m_parameters.isValid() && cmake, return);
-
- const FilePath srcDir = m_parameters.sourceDirectory;
- const FilePath bldDir = m_parameters.workDirectory;
- const FilePath topCMake = srcDir.pathAppended("CMakeLists.txt");
-
- resetData();
-
- m_projectName = m_parameters.projectName;
- m_files.emplace_back(std::make_unique<FileNode>(topCMake, FileType::Project));
- // Do not insert topCMake into m_cmakeFiles: The project already watches that!
-
- // Find cbp file
- FilePath cbpFile = FilePath::fromString(findCbpFile(bldDir.toString()));
- if (cbpFile.isEmpty())
- return;
- m_cmakeFiles.insert(cbpFile);
-
- // Add CMakeCache.txt file:
- const FilePath cacheFile = m_parameters.workDirectory.pathAppended("CMakeCache.txt");
- if (cacheFile.exists())
- m_cmakeFiles.insert(cacheFile);
-
- // setFolderName
- CMakeCbpParser cbpparser;
- // Parsing
- if (!cbpparser.parseCbpFile(cmake->pathMapper(), cbpFile, srcDir))
- return;
-
- m_projectName = cbpparser.projectName();
-
- m_files = cbpparser.takeFileList();
- if (cbpparser.hasCMakeFiles()) {
- std::vector<std::unique_ptr<FileNode>> cmakeNodes = cbpparser.takeCmakeFileList();
- for (const std::unique_ptr<FileNode> &node : cmakeNodes)
- m_cmakeFiles.insert(node->filePath());
-
- std::move(std::begin(cmakeNodes), std::end(cmakeNodes), std::back_inserter(m_files));
- }
-
- // Make sure the top cmakelists.txt file is always listed:
- if (!contains(m_files, [topCMake](const std::unique_ptr<FileNode> &fn) {
- return fn->filePath() == topCMake;
- }))
- m_files.emplace_back(std::make_unique<FileNode>(topCMake, FileType::Project));
-
- m_buildTargets = cbpparser.buildTargets();
-}
-
-void TeaLeafReader::startCMake(const QStringList &configurationArguments)
-{
- QTC_ASSERT(!m_cmakeProcess, return);
-
- m_cmakeProcess = std::make_unique<CMakeProcess>();
-
- connect(m_cmakeProcess.get(), &CMakeProcess::finished,
- this, &TeaLeafReader::cmakeFinished);
-
- m_cmakeProcess->run(m_parameters, configurationArguments);
-}
-
-void TeaLeafReader::cmakeFinished(int code, QProcess::ExitStatus status)
-{
- Q_UNUSED(code)
- Q_UNUSED(status)
-
- QTC_ASSERT(m_cmakeProcess, return);
- m_cmakeProcess.reset();
-
- extractData(); // try even if cmake failed...
-
- emit dataAvailable();
-}
-
-QStringList TeaLeafReader::getFlagsFor(const CMakeBuildTarget &buildTarget,
- QHash<QString, QStringList> &cache,
- Id lang) const
-{
- // check cache:
- auto it = cache.constFind(buildTarget.title);
- if (it != cache.constEnd())
- return *it;
-
- if (extractFlagsFromMake(buildTarget, cache, lang))
- return cache.value(buildTarget.title);
-
- if (extractFlagsFromNinja(buildTarget, cache, lang))
- return cache.value(buildTarget.title);
-
- cache.insert(buildTarget.title, QStringList());
- return QStringList();
-}
-
-bool TeaLeafReader::extractFlagsFromMake(const CMakeBuildTarget &buildTarget,
- QHash<QString, QStringList> &cache,
- Id lang) const
-{
- QString flagsPrefix;
-
- if (lang == ProjectExplorer::Constants::CXX_LANGUAGE_ID)
- flagsPrefix = QLatin1String("CXX_FLAGS =");
- else if (lang == ProjectExplorer::Constants::C_LANGUAGE_ID)
- flagsPrefix = QLatin1String("C_FLAGS =");
- else
- return false;
-
- QString makeCommand = buildTarget.makeCommand.toString();
- int startIndex = makeCommand.indexOf('\"');
- int endIndex = makeCommand.indexOf('\"', startIndex + 1);
- if (startIndex != -1 && endIndex != -1) {
- startIndex += 1;
- QString makefile = makeCommand.mid(startIndex, endIndex - startIndex);
- int slashIndex = makefile.lastIndexOf('/');
- makefile.truncate(slashIndex);
- makefile.append("/CMakeFiles/" + buildTarget.title + ".dir/flags.make");
- // Remove un-needed shell escaping:
- makefile = makefile.remove("\\");
- QFile file(makefile);
- if (file.exists()) {
- if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
- return false;
- QTextStream stream(&file);
- while (!stream.atEnd()) {
- QString line = stream.readLine().trimmed();
- if (line.startsWith(flagsPrefix)) {
- // Skip past =
- auto flags =
- Utils::transform(line.mid(flagsPrefix.length()).trimmed().split(' ', QString::SkipEmptyParts), [this](QString flag) -> QString {
- // TODO: maybe Gcc-specific
- // Remove \' (quote) for function-style macrosses:
- // -D'MACRO()'=xxx
- // -D'MACRO()=xxx'
- // -D'MACRO()'
- // otherwise, compiler will fails
- return flag
- .replace(m_macroFixupRe1, "-D\\1\\2=")
- .replace(m_macroFixupRe2, "-D\\1\\2=\\3")
- .replace(m_macroFixupRe3, "-D\\1\\2");
- });
- cache.insert(buildTarget.title, flags);
- return true;
- }
- }
- }
- }
- return false;
-}
-
-bool TeaLeafReader::extractFlagsFromNinja(const CMakeBuildTarget &buildTarget,
- QHash<QString, QStringList> &cache,
- Id lang) const
-{
- Q_UNUSED(buildTarget)
- if (!cache.isEmpty()) // We fill the cache in one go!
- return false;
-
- QString compilerPrefix;
- if (lang == ProjectExplorer::Constants::CXX_LANGUAGE_ID)
- compilerPrefix = QLatin1String("CXX_COMPILER");
- else if (lang == ProjectExplorer::Constants::C_LANGUAGE_ID)
- compilerPrefix = QLatin1String("C_COMPILER");
- else
- return false;
-
- // Attempt to find build.ninja file and obtain FLAGS (CXX_FLAGS/C_FLAGS) from there if no suitable flags.make were
- // found
- // Get "all" target's working directory
- QByteArray ninjaFile;
- QString buildNinjaFile = m_buildTargets.at(0).workingDirectory.toString();
- buildNinjaFile += "/build.ninja";
- QFile buildNinja(buildNinjaFile);
- if (buildNinja.exists()) {
- if (!buildNinja.open(QIODevice::ReadOnly | QIODevice::Text))
- return false;
- ninjaFile = buildNinja.readAll();
- buildNinja.close();
- }
-
- if (ninjaFile.isEmpty())
- return false;
-
- QTextStream stream(ninjaFile);
- bool compilerFound = false;
- const QString targetSignature = "# Object build statements for ";
- QString currentTarget;
-
- while (!stream.atEnd()) {
- // 1. Look for a block that refers to the current target
- // 2. Look for a build rule which invokes CXX_COMPILER
- // 3. Return the FLAGS definition
- QString line = stream.readLine().trimmed();
- if (line.startsWith('#')) {
- if (line.startsWith(targetSignature)) {
- int pos = line.lastIndexOf(' ');
- currentTarget = line.mid(pos + 1);
- }
- } else if (!currentTarget.isEmpty() && line.startsWith("build")) {
- compilerFound = line.indexOf(compilerPrefix) != -1;
- } else if (compilerFound && line.startsWith("FLAGS =")) {
- // Skip past =
- cache.insert(currentTarget, line.mid(7).trimmed().split(' ', QString::SkipEmptyParts));
- }
- }
- return !cache.isEmpty();
-}
-
-} // namespace Internal
-} // namespace CMakeProjectManager
diff --git a/src/plugins/cmakeprojectmanager/tealeafreader.h b/src/plugins/cmakeprojectmanager/tealeafreader.h
deleted file mode 100644
index ae77afc47c..0000000000
--- a/src/plugins/cmakeprojectmanager/tealeafreader.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 <projectexplorer/toolchain.h>
-
-#include "builddirreader.h"
-#include "cmakeprocess.h"
-
-#include <QRegularExpression>
-
-namespace Utils { class QtcProcess; }
-
-namespace CMakeProjectManager {
-namespace Internal {
-
-class TeaLeafReader final : public BuildDirReader
-{
- Q_OBJECT
-
-public:
- TeaLeafReader();
- ~TeaLeafReader() final;
-
- void setParameters(const BuildDirParameters &p) final;
-
- bool isCompatible(const BuildDirParameters &p) final;
- void resetData() final;
- void parse(bool forceCMakeRun, bool forceConfiguration) final;
- void stop() final;
-
- bool isParsing() const final;
-
- QSet<Utils::FilePath> projectFilesToWatch() const final;
- QList<CMakeBuildTarget> takeBuildTargets(QString &errorMessage) final;
- CMakeConfig takeParsedConfiguration(QString &errorMessage) final;
- std::unique_ptr<CMakeProjectNode> generateProjectTree(
- const QList<const ProjectExplorer::FileNode *> &allFiles, QString &errorMessage) final;
- ProjectExplorer::RawProjectParts createRawProjectParts(QString &errorMessage) final;
-
-private:
- void extractData();
-
- void startCMake(const QStringList &configurationArguments);
-
- void cmakeFinished(int code, QProcess::ExitStatus status);
-
- QStringList getFlagsFor(const CMakeBuildTarget &buildTarget, QHash<QString, QStringList> &cache, Core::Id lang) const;
- bool extractFlagsFromMake(const CMakeBuildTarget &buildTarget, QHash<QString, QStringList> &cache, Core::Id lang) const;
- bool extractFlagsFromNinja(const CMakeBuildTarget &buildTarget, QHash<QString, QStringList> &cache, Core::Id lang) const;
-
- // Process data:
- std::unique_ptr<CMakeProcess> m_cmakeProcess;
-
- QSet<Utils::FilePath> m_cmakeFiles;
- QString m_projectName;
- QList<CMakeBuildTarget> m_buildTargets;
- std::vector<std::unique_ptr<ProjectExplorer::FileNode>> m_files;
-
- // RegExps for function-like macrosses names fixups
- QRegularExpression m_macroFixupRe1;
- QRegularExpression m_macroFixupRe2;
- QRegularExpression m_macroFixupRe3;
-
- friend class CMakeFile;
-};
-
-} // namespace Internal
-} // namespace CMakeProjectManager
diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.cpp b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.cpp
index ee3c329141..8b562a97e3 100644
--- a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.cpp
+++ b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.cpp
@@ -52,7 +52,6 @@
#include <utils/runextensions.h>
#include <QFileDialog>
-#include <QTimer>
#ifdef Q_OS_WIN
#include <Windows.h>
@@ -337,20 +336,15 @@ void createTree(std::unique_ptr<ProjectNode> &root,
CompilationDatabaseBuildSystem::CompilationDatabaseBuildSystem(Target *target)
: BuildSystem(target)
, m_cppCodeModelUpdater(std::make_unique<CppTools::CppProjectUpdater>())
- , m_parseDelay(new QTimer(this))
, m_deployFileWatcher(new FileSystemWatcher(this))
{
connect(target->project(), &CompilationDatabaseProject::rootProjectDirectoryChanged,
this, [this] {
m_projectFileHash.clear();
- m_parseDelay->start();
+ requestDelayedParse();
});
- connect(m_parseDelay, &QTimer::timeout, this, &CompilationDatabaseBuildSystem::reparseProject);
-
- m_parseDelay->setSingleShot(true);
- m_parseDelay->setInterval(1000);
- m_parseDelay->start();
+ requestDelayedParse();
connect(project(), &Project::projectFileIsDirty, this, &CompilationDatabaseBuildSystem::reparseProject);
@@ -373,8 +367,8 @@ void CompilationDatabaseBuildSystem::triggerParsing()
void CompilationDatabaseBuildSystem::buildTreeAndProjectParts()
{
- Kit *kit = target()->kit();
- ProjectExplorer::KitInfo kitInfo(kit);
+ Kit *k = kit();
+ ProjectExplorer::KitInfo kitInfo(k);
QTC_ASSERT(kitInfo.isValid(), return);
// Reset toolchains to pick them based on the database entries.
kitInfo.cToolChain = nullptr;
@@ -393,7 +387,7 @@ void CompilationDatabaseBuildSystem::buildTreeAndProjectParts()
prevEntry = &entry;
RawProjectPart rpp = makeRawProjectPart(projectFilePath(),
- kit,
+ k,
kitInfo,
entry.workingDir,
entry.fileName,
diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.h b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.h
index 34eec1d578..bb98f5213e 100644
--- a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.h
+++ b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.h
@@ -37,10 +37,6 @@
#include <QFutureWatcher>
-QT_BEGIN_NAMESPACE
-class QTimer;
-QT_END_NAMESPACE
-
namespace CppTools { class CppProjectUpdater; }
namespace ProjectExplorer { class Kit; }
namespace Utils { class FileSystemWatcher; }
@@ -77,7 +73,6 @@ public:
std::unique_ptr<CppTools::CppProjectUpdater> m_cppCodeModelUpdater;
MimeBinaryCache m_mimeBinaryCache;
QByteArray m_projectFileHash;
- QTimer * const m_parseDelay;
CompilationDbParser *m_parser = nullptr;
Utils::FileSystemWatcher * const m_deployFileWatcher;
};
diff --git a/src/plugins/coreplugin/CMakeLists.txt b/src/plugins/coreplugin/CMakeLists.txt
index 06194cddf5..10b580ba25 100644
--- a/src/plugins/coreplugin/CMakeLists.txt
+++ b/src/plugins/coreplugin/CMakeLists.txt
@@ -18,6 +18,7 @@ add_qtc_plugin(Core
coreplugin.cpp coreplugin.h
designmode.cpp designmode.h
dialogs/addtovcsdialog.cpp dialogs/addtovcsdialog.h dialogs/addtovcsdialog.ui
+ dialogs/codecselector.cpp dialogs/codecselector.h
dialogs/externaltoolconfig.cpp dialogs/externaltoolconfig.h dialogs/externaltoolconfig.ui
dialogs/filepropertiesdialog.cpp dialogs/filepropertiesdialog.h dialogs/filepropertiesdialog.ui
dialogs/ioptionspage.cpp dialogs/ioptionspage.h
@@ -179,9 +180,8 @@ extend_qtc_plugin(Core
)
extend_qtc_plugin(Core
- CONDITION TARGET Qt5::Script
+ CONDITION Qt5_VERSION VERSION_GREATER_EQUAL 5.14.0
FEATURE_INFO "Script Locator filter"
- DEPENDS Qt5::Script
DEFINES WITH_JAVASCRIPTFILTER
SOURCES
locator/javascriptfilter.cpp locator/javascriptfilter.h
diff --git a/src/plugins/coreplugin/actionmanager/actionmanager.cpp b/src/plugins/coreplugin/actionmanager/actionmanager.cpp
index 449a0040bc..3f0d05a302 100644
--- a/src/plugins/coreplugin/actionmanager/actionmanager.cpp
+++ b/src/plugins/coreplugin/actionmanager/actionmanager.cpp
@@ -30,6 +30,7 @@
#include <coreplugin/icore.h>
#include <coreplugin/id.h>
+#include <utils/algorithm.h>
#include <utils/fadingindicator.h>
#include <utils/qtcassert.h>
@@ -46,6 +47,7 @@ namespace {
}
static const char kKeyboardSettingsKey[] = "KeyboardShortcuts";
+static const char kKeyboardSettingsKeyV2[] = "KeyboardShortcutsV2";
using namespace Core;
using namespace Core::Internal;
@@ -58,86 +60,57 @@ using namespace Core::Internal;
\brief The ActionManager class is responsible for registration of menus and
menu items and keyboard shortcuts.
- The ActionManager is the central bookkeeper of actions and their shortcuts and layout.
- It is a singleton containing mostly static functions. If you need access to the instance,
- e.g. for connecting to signals, call its ActionManager::instance() function.
-
- The main reasons for the need of this class is to provide a central place where the users
- can specify all their keyboard shortcuts, and to provide a solution for actions that should
- behave differently in different contexts (like the copy/replace/undo/redo actions).
-
- \section1 Contexts
-
- All actions that are registered with the same Id (but different context lists)
- are considered to be overloads of the same command, represented by an instance
- of the Core::Command class.
- Exactly only one of the registered actions with the same ID is active at any time.
- Which action this is, is defined by the context list that the actions were registered
- with:
-
- If the current focus widget was registered via \l{ICore::addContextObject()},
- all the contexts returned by its IContext object are active. In addition all
- contexts set via \l{ICore::addAdditionalContext()} are active as well. If one
- of the actions was registered for one of these active contexts, it is the one
- active action, and receives \c triggered and \c toggled signals. Also the
- appearance of the visible action for this ID might be adapted to this
- active action (depending on the settings of the corresponding \l{Command} object).
-
- The action that is visible to the user is the one returned by Command::action().
- If you provide yourself a user visible representation of your action you need
- to use Command::action() for this.
- When this action is invoked by the user,
- the signal is forwarded to the registered action that is valid for the current context.
-
- \section1 Registering Actions
-
- To register a globally active action "My Action"
- put the following in your plugin's IPlugin::initialize function:
+ The action manager is the central bookkeeper of actions and their shortcuts
+ and layout. It is a singleton containing mostly static functions. If you
+ need access to the instance, for example for connecting to signals, call
+ its ActionManager::instance() function.
+
+ The action manager makes it possible to provide a central place where the
+ users can specify all their keyboard shortcuts, and provides a solution for
+ actions that should behave differently in different contexts (like the
+ copy/replace/undo/redo actions).
+
+ See \l{The Action Manager and Commands} for an overview of the interaction
+ between Core::ActionManager, Core::Command, and Core::Context.
+
+ Register a globally active action "My Action" by putting the following in
+ your plugin's ExtensionSystem::IPlugin::initialize() function.
+
\code
QAction *myAction = new QAction(tr("My Action"), this);
- Command *cmd = ActionManager::registerAction(myAction,
- "myplugin.myaction",
- Context(C_GLOBAL));
+ Command *cmd = ActionManager::registerAction(myAction, "myplugin.myaction", Context(C_GLOBAL));
cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Alt+u")));
connect(myAction, &QAction::triggered, this, &MyPlugin::performMyAction);
\endcode
- So the \c connect is done to your own QAction instance. If you create e.g.
- a tool button that should represent the action you add the action
- from Command::action() to it:
+ The \c connect is done to your own QAction instance. If you create for
+ example a tool button that should represent the action, add the action from
+ Command::action() to it.
+
\code
QToolButton *myButton = new QToolButton(someParentWidget);
myButton->setDefaultAction(cmd->action());
\endcode
- Also use the ActionManager to add items to registered
- action containers like the applications menu bar or menus in that menu bar.
- To do this, you register your action via the
- registerAction functions, get the action container for a specific ID (like specified in
- the Core::Constants namespace) with a call of
- actionContainer(const Id&) and add your command to this container.
+ Also use the action manager to add items to registered action containers
+ like the application's menu bar or menus in that menu bar. Register your
+ action via the Core::ActionManager::registerAction() function, get the
+ action container for a specific ID (as specified for example in the
+ Core::Constants namespace) with Core::ActionManager::actionContainer(), and
+ add your command to this container.
+
+ Building on the example, adding "My Action" to the "Tools" menu would be
+ done with
- Following the example adding "My Action" to the "Tools" menu would be done by
\code
- ActionManager::actionContainer(M_TOOLS)->addAction(cmd);
+ ActionManager::actionContainer(Core::Constants::M_TOOLS)->addAction(cmd);
\endcode
- \section1 Important Guidelines:
- \list
- \li Always register your actions and shortcuts!
- \li Register your actions and shortcuts during your plugin's \l{ExtensionSystem::IPlugin::initialize()}
- or \l{ExtensionSystem::IPlugin::extensionsInitialized()} functions, otherwise the shortcuts won't appear
- in the keyboard settings dialog from the beginning.
- \li When registering an action with \c{cmd=registerAction(action, id, contexts)} be sure to connect
- your own action \c{connect(action, SIGNAL...)} but make \c{cmd->action()} visible to the user, i.e.
- \c{widget->addAction(cmd->action())}.
- \li Use this class to add actions to the applications menus
- \endlist
-
\sa Core::ICore
\sa Core::Command
\sa Core::ActionContainer
\sa Core::IContext
+ \sa {The Action Manager and Commands}
*/
/*!
@@ -176,7 +149,7 @@ ActionManager::~ActionManager()
}
/*!
- Returns the pointer to the instance, which is only used for connecting to signals.
+ Returns the pointer to the instance. Only use for connecting to signals.
*/
ActionManager *ActionManager::instance()
{
@@ -184,13 +157,13 @@ ActionManager *ActionManager::instance()
}
/*!
- Creates a new menu with the given \a id.
+ Creates a new menu action container or returns an existing container with
+ the specified \a id. The ActionManager owns the returned ActionContainer.
+ Add your menu to some other menu or a menu bar via the actionContainer()
+ and ActionContainer::addMenu() functions.
- Returns a new ActionContainer that you can use to get the QMenu instance
- or to add menu items to the menu. The ActionManager owns
- the returned ActionContainer.
- Add your menu to some other menu or a menu bar via the
- ActionManager::actionContainer and ActionContainer::addMenu functions.
+ \sa actionContainer()
+ \sa ActionContainer::addMenu()
*/
ActionContainer *ActionManager::createMenu(Id id)
{
@@ -207,11 +180,12 @@ ActionContainer *ActionManager::createMenu(Id id)
}
/*!
- Creates a new menu bar with the given \a id.
+ Creates a new menu bar action container or returns an existing container
+ with the specified \a id. The ActionManager owns the returned
+ ActionContainer.
- Returns a new ActionContainer that you can use to get the QMenuBar instance
- or to add menus to the menu bar. The ActionManager owns
- the returned ActionContainer.
+ \sa createMenu()
+ \sa ActionContainer::addMenu()
*/
ActionContainer *ActionManager::createMenuBar(Id id)
{
@@ -232,13 +206,17 @@ ActionContainer *ActionManager::createMenuBar(Id id)
}
/*!
- Creates a touch bar with the given \a id.
+ Creates a new (sub) touch bar action container or returns an existing
+ container with the specified \a id. The ActionManager owns the returned
+ ActionContainer.
- Returns a new ActionContainer that you can use to add items to a (sub) touch bar.
Note that it is only possible to create a single level of sub touch bars.
- The sub touch bar will be represented as a button with \a icon and \a text (one can be left
- empty), which opens the sub touch bar when touched.
- The ActionManager owns the returned ActionContainer.
+ The sub touch bar will be represented as a button with \a icon and \a text
+ (either of which can be left empty), which opens the sub touch bar when
+ touched.
+
+ \sa actionContainer()
+ \sa ActionContainer::addMenu()
*/
ActionContainer *ActionManager::createTouchBar(Id id, const QIcon &icon, const QString &text)
{
@@ -255,15 +233,13 @@ ActionContainer *ActionManager::createTouchBar(Id id, const QIcon &icon, const Q
/*!
Makes an \a action known to the system under the specified \a id.
- Returns a command object that represents the action in the application and is
- owned by the ActionManager. You can register several actions with the
- same \a id as long as the \a context is different. In this case
- a trigger of the actual action is forwarded to the registered QAction
- for the currently active context.
- If the optional \a context argument is not specified, the global context
- will be assumed.
- A \a scriptable action can be called from a script without the need for the user
- to interact with it.
+ Returns a Command instance that represents the action in the application
+ and is owned by the ActionManager. You can register several actions with
+ the same \a id as long as the \a context is different. In this case
+ triggering the action is forwarded to the registered QAction for the
+ currently active context. If the optional \a context argument is not
+ specified, the global context will be assumed. A \a scriptable action can
+ be called from a script without the need for the user to interact with it.
*/
Command *ActionManager::registerAction(QAction *action, Id id, const Context &context, bool scriptable)
{
@@ -277,10 +253,10 @@ Command *ActionManager::registerAction(QAction *action, Id id, const Context &co
}
/*!
- Returns the Command object that is known to the system
- under the given \a id.
+ Returns the Command instance that has been created with registerAction()
+ for the specified \a id.
- \sa ActionManager::registerAction()
+ \sa registerAction()
*/
Command *ActionManager::command(Id id)
{
@@ -295,8 +271,15 @@ Command *ActionManager::command(Id id)
}
/*!
- Returns the IActionContainter object that is know to the system
- under the given \a id.
+ Returns the ActionContainter instance that has been created with
+ createMenu(), createMenuBar(), createTouchBar() for the specified \a id.
+
+ Use the ID \c{Core::Constants::MENU_BAR} to retrieve the main menu bar.
+
+ Use the IDs \c{Core::Constants::M_FILE}, \c{Core::Constants::M_EDIT}, and
+ similar constants to retrieve the various default menus.
+
+ Use the ID \c{Core::Constants::TOUCH_BAR} to retrieve the main touch bar.
\sa ActionManager::createMenu()
\sa ActionManager::createMenuBar()
@@ -314,7 +297,7 @@ ActionContainer *ActionManager::actionContainer(Id id)
}
/*!
- Returns all commands that have been registered.
+ Returns all registered commands.
*/
QList<Command *> ActionManager::commands()
{
@@ -355,9 +338,7 @@ void ActionManager::unregisterAction(QAction *action, Id id)
}
/*!
- Handles the display of the used shortcuts in the presentation mode. The presentation mode is
- \a enabled when starting \QC with the command line argument \c{-presentationMode}. In the
- presentation mode, \QC displays any pressed shortcut in a grey box.
+ \internal
*/
void ActionManager::setPresentationModeEnabled(bool enabled)
{
@@ -380,7 +361,9 @@ void ActionManager::setPresentationModeEnabled(bool enabled)
/*!
Returns whether presentation mode is enabled.
- \sa setPresentationModeEnabled
+ The presentation mode is enabled when starting \QC with the command line
+ argument \c{-presentationMode}. In presentation mode, \QC displays any
+ pressed shortcut in an overlay box.
*/
bool ActionManager::isPresentationModeEnabled()
{
@@ -388,7 +371,8 @@ bool ActionManager::isPresentationModeEnabled()
}
/*!
- \internal
+ Decorates the specified \a text with a numbered accelerator key \a number,
+ in the style of the \uicontrol {Recent Files} menu.
*/
QString ActionManager::withNumberAccelerator(const QString &text, const int number)
{
@@ -397,11 +381,17 @@ QString ActionManager::withNumberAccelerator(const QString &text, const int numb
return QString("&%1 | %2").arg(number).arg(text);
}
+/*!
+ \internal
+*/
void ActionManager::saveSettings()
{
d->saveSettings();
}
+/*!
+ \internal
+*/
void ActionManager::setContext(const Context &context)
{
d->setContext(context);
@@ -495,22 +485,50 @@ Action *ActionManagerPrivate::overridableAction(Id id)
void ActionManagerPrivate::readUserSettings(Id id, Action *cmd)
{
+ // TODO Settings V2 were introduced in Qt Creator 4.13, remove old settings at some point
QSettings *settings = ICore::settings();
- settings->beginGroup(QLatin1String(kKeyboardSettingsKey));
- if (settings->contains(id.toString()))
- cmd->setKeySequence(QKeySequence(settings->value(id.toString()).toString()));
+ // transfer from old settings if not done before
+ const QString group = settings->childGroups().contains(kKeyboardSettingsKeyV2)
+ ? QString(kKeyboardSettingsKeyV2)
+ : QString(kKeyboardSettingsKey);
+ settings->beginGroup(group);
+ if (settings->contains(id.toString())) {
+ const QVariant v = settings->value(id.toString());
+ if (QMetaType::Type(v.type()) == QMetaType::QStringList) {
+ cmd->setKeySequences(Utils::transform<QList>(v.toStringList(), [](const QString &s) {
+ return QKeySequence::fromString(s);
+ }));
+ } else {
+ cmd->setKeySequences({QKeySequence::fromString(v.toString())});
+ }
+ }
settings->endGroup();
}
void ActionManagerPrivate::saveSettings(Action *cmd)
{
- const QString settingsKey = QLatin1String(kKeyboardSettingsKey) + QLatin1Char('/')
- + cmd->id().toString();
- QKeySequence key = cmd->keySequence();
- if (key != cmd->defaultKeySequence())
- ICore::settings()->setValue(settingsKey, key.toString());
- else
+ const QString id = cmd->id().toString();
+ const QString settingsKey = QLatin1String(kKeyboardSettingsKeyV2) + '/' + id;
+ const QString compatSettingsKey = QLatin1String(kKeyboardSettingsKey) + '/' + id;
+ const QList<QKeySequence> keys = cmd->keySequences();
+ const QList<QKeySequence> defaultKeys = cmd->defaultKeySequences();
+ if (keys != defaultKeys) {
+ if (keys.isEmpty()) {
+ ICore::settings()->setValue(settingsKey, QString());
+ ICore::settings()->setValue(compatSettingsKey, QString());
+ } else if (keys.size() == 1) {
+ ICore::settings()->setValue(settingsKey, keys.first().toString());
+ ICore::settings()->setValue(compatSettingsKey, keys.first().toString());
+ } else {
+ ICore::settings()->setValue(settingsKey,
+ Utils::transform<QStringList>(keys,
+ [](const QKeySequence &k) {
+ return k.toString();
+ }));
+ }
+ } else {
ICore::settings()->remove(settingsKey);
+ }
}
void ActionManagerPrivate::saveSettings()
diff --git a/src/plugins/coreplugin/actionmanager/command.cpp b/src/plugins/coreplugin/actionmanager/command.cpp
index cd801c1ec2..49ecface97 100644
--- a/src/plugins/coreplugin/actionmanager/command.cpp
+++ b/src/plugins/coreplugin/actionmanager/command.cpp
@@ -50,11 +50,13 @@
action and its properties. If multiple actions are registered with the same ID (but
different contexts) the returned Command is the shared one between these actions.
- A Command has two basic properties: a default shortcut and a default text. The default
- shortcut is a key sequence that the user can use to trigger the active action that
- the Command represents. The default text is e.g. used for representing the Command
- in the keyboard shortcut preference pane. If the default text is empty, the text
- of the visible action is used.
+ A Command has two basic properties: a list of default shortcuts and a
+ default text. The default shortcuts are key sequence that the user can use
+ to trigger the active action that the Command represents. The first
+ shortcut in that list is the main shortcut that is for example also shown
+ in tool tips and menus. The default text is used for representing the
+ Command in the keyboard shortcut preference pane. If the default text is
+ empty, the text of the visible action is used.
The user visible action is updated to represent the state of the active action (if any).
For performance reasons only the enabled and visible state are considered by default though.
@@ -64,6 +66,12 @@
If there is no active action, the default behavior of the visible action is to be disabled.
You can change that behavior to make the visible action hide instead via the Command's
\l{Command::CommandAttribute}{attributes}.
+
+ See \l{The Action Manager and Commands} for an overview of how
+ Core::Command and Core::ActionManager interact.
+
+ \sa Core::ActionManager
+ \sa {The Action Manager and Commands}
*/
/*!
@@ -79,37 +87,56 @@
When there is no active action, hide the user-visible action, instead of just
disabling it.
\value CA_NonConfigurable
- Flag to indicate that the keyboard shortcut of this Command should not be
- configurable by the user.
+ Flag to indicate that the keyboard shortcuts of this Command should not
+ be configurable by the user.
*/
/*!
\fn void Core::Command::setDefaultKeySequence(const QKeySequence &key)
- Sets the default keyboard shortcut that can be used to activate this command to \a key.
- This is used if the user didn't customize the shortcut, or resets the shortcut
- to the default one.
+
+ Sets the default keyboard shortcut that can be used to activate this
+ command to \a key. This is used if the user didn't customize the shortcut,
+ or resets the shortcut to the default.
+*/
+
+/*!
+ \fn void Core::Command::setDefaultKeySequences(const QList<QKeySequence> &keys)
+
+ Sets the default keyboard shortcuts that can be used to activate this
+ command to \a keys. This is used if the user didn't customize the
+ shortcuts, or resets the shortcuts to the default.
*/
/*!
- \fn void Core::Command::defaultKeySequence() const
- Returns the default keyboard shortcut that can be used to activate this command.
- \sa setDefaultKeySequence()
+ \fn QList<QKeySequence> Core::Command::defaultKeySequences() const
+
+ Returns the default keyboard shortcuts that can be used to activate this
+ command.
+ \sa setDefaultKeySequences()
*/
/*!
\fn void Core::Command::keySequenceChanged()
- Sent when the keyboard shortcut assigned to this Command changes, e.g.
- when the user sets it in the keyboard shortcut settings dialog.
+ Sent when the keyboard shortcuts assigned to this Command change, e.g.
+ when the user sets them in the keyboard shortcut settings dialog.
+*/
+
+/*!
+ \fn QList<QKeySequence> Core::Command::keySequences() const
+
+ Returns the current keyboard shortcuts assigned to this Command.
+ \sa defaultKeySequences()
*/
/*!
\fn QKeySequence Core::Command::keySequence() const
- Returns the current keyboard shortcut assigned to this Command.
- \sa defaultKeySequence()
+
+ Returns the current main keyboard shortcut assigned to this Command.
+ \sa defaultKeySequences()
*/
/*!
- \fn void Core::Command::setKeySequence(const QKeySequence &key)
+ \fn void Core::Command::setKeySequences(const QList<QKeySequence> &keys)
\internal
*/
@@ -134,21 +161,20 @@
/*!
\fn QString Core::Command::stringWithAppendedShortcut(const QString &string) const
- Returns the \a string with an appended representation of the keyboard shortcut
- that is currently assigned to this Command.
+
+ Returns the \a string with an appended representation of the main keyboard
+ shortcut that is currently assigned to this Command.
*/
/*!
\fn QAction *Core::Command::action() const
- Returns the user visible action for this Command.
- If the Command represents a shortcut, it returns null.
- Use this action to put it on e.g. tool buttons. The action
- automatically forwards trigger and toggle signals to the
- action that is currently active for this Command.
- It also shows the current keyboard shortcut in its
- tool tip (in addition to the tool tip of the active action)
- and gets disabled/hidden when there is
- no active action for the current context.
+
+ Returns the user visible action for this Command. Use this action to put it
+ on e.g. tool buttons. The action automatically forwards \c triggered() and
+ \c toggled() signals to the action that is currently active for this
+ Command. It also shows the current main keyboard shortcut in its tool tip
+ (in addition to the tool tip of the active action) and gets disabled/hidden
+ when there is no active action for the current context.
*/
/*!
@@ -182,8 +208,8 @@
/*!
\fn bool Core::Command::isActive() const
- Returns whether the Command has an active action or shortcut for the current
- context.
+
+ Returns whether the Command has an active action for the current context.
*/
/*!
@@ -230,7 +256,7 @@
/*! \fn virtual QAction *Core::Command::touchBarAction() const
- Adds an action to the touch bar.
+ \internal
*/
namespace Core {
@@ -253,13 +279,20 @@ Id Action::id() const
void Action::setDefaultKeySequence(const QKeySequence &key)
{
if (!m_isKeyInitialized)
- setKeySequence(key);
- m_defaultKey = key;
+ setKeySequences({key});
+ m_defaultKeys = {key};
+}
+
+void Action::setDefaultKeySequences(const QList<QKeySequence> &keys)
+{
+ if (!m_isKeyInitialized)
+ setKeySequences(keys);
+ m_defaultKeys = keys;
}
-QKeySequence Action::defaultKeySequence() const
+QList<QKeySequence> Action::defaultKeySequences() const
{
- return m_defaultKey;
+ return m_defaultKeys;
}
QAction *Action::action() const
@@ -277,13 +310,18 @@ Context Action::context() const
return m_context;
}
-void Action::setKeySequence(const QKeySequence &key)
+void Action::setKeySequences(const QList<QKeySequence> &keys)
{
m_isKeyInitialized = true;
- m_action->setShortcut(key);
+ m_action->setShortcuts(keys);
emit keySequenceChanged();
}
+QList<QKeySequence> Action::keySequences() const
+{
+ return m_action->shortcuts();
+}
+
QKeySequence Action::keySequence() const
{
return m_action->shortcut();
@@ -491,8 +529,8 @@ QAction *Action::touchBarAction() const
} // namespace Internal
/*!
- Appends the keyboard shortcut that is currently assigned to the action \a a
- to its tool tip.
+ Appends the main keyboard shortcut that is currently assigned to the action
+ \a a to its tool tip.
*/
void Command::augmentActionWithShortcutToolTip(QAction *a) const
{
@@ -508,7 +546,7 @@ void Command::augmentActionWithShortcutToolTip(QAction *a) const
/*!
Returns a tool button for \a action.
- Appends the keyboard shortcut \a cmd to the tool tip of the action.
+ Appends the main keyboard shortcut \a cmd to the tool tip of the action.
*/
QToolButton *Command::toolButtonWithAppendedShortcut(QAction *action, Command *cmd)
{
diff --git a/src/plugins/coreplugin/actionmanager/command.h b/src/plugins/coreplugin/actionmanager/command.h
index 355507de12..d17ef0d266 100644
--- a/src/plugins/coreplugin/actionmanager/command.h
+++ b/src/plugins/coreplugin/actionmanager/command.h
@@ -58,7 +58,9 @@ public:
Q_DECLARE_FLAGS(CommandAttributes, CommandAttribute)
virtual void setDefaultKeySequence(const QKeySequence &key) = 0;
- virtual QKeySequence defaultKeySequence() const = 0;
+ virtual void setDefaultKeySequences(const QList<QKeySequence> &keys) = 0;
+ virtual QList<QKeySequence> defaultKeySequences() const = 0;
+ virtual QList<QKeySequence> keySequences() const = 0;
virtual QKeySequence keySequence() const = 0;
// explicitly set the description (used e.g. in shortcut settings)
// default is to use the action text for actions, or the whatsThis for shortcuts,
@@ -78,7 +80,7 @@ public:
virtual bool isActive() const = 0;
- virtual void setKeySequence(const QKeySequence &key) = 0;
+ virtual void setKeySequences(const QList<QKeySequence> &keys) = 0;
virtual QString stringWithAppendedShortcut(const QString &str) const = 0;
void augmentActionWithShortcutToolTip(QAction *action) const;
static QToolButton *toolButtonWithAppendedShortcut(QAction *action, Command *cmd);
diff --git a/src/plugins/coreplugin/actionmanager/command_p.h b/src/plugins/coreplugin/actionmanager/command_p.h
index 9811c88fb6..de722d41cf 100644
--- a/src/plugins/coreplugin/actionmanager/command_p.h
+++ b/src/plugins/coreplugin/actionmanager/command_p.h
@@ -52,9 +52,11 @@ public:
Id id() const override;
void setDefaultKeySequence(const QKeySequence &key) override;
- QKeySequence defaultKeySequence() const override;
+ void setDefaultKeySequences(const QList<QKeySequence> &key) override;
+ QList<QKeySequence> defaultKeySequences() const override;
- void setKeySequence(const QKeySequence &key) override;
+ void setKeySequences(const QList<QKeySequence> &keys) override;
+ QList<QKeySequence> keySequences() const override;
QKeySequence keySequence() const override;
void setDescription(const QString &text) override;
@@ -92,7 +94,7 @@ private:
Context m_context;
CommandAttributes m_attributes;
Id m_id;
- QKeySequence m_defaultKey;
+ QList<QKeySequence> m_defaultKeys;
QString m_defaultText;
QString m_touchBarText;
QIcon m_touchBarIcon;
diff --git a/src/plugins/coreplugin/actionmanager/commandmappings.cpp b/src/plugins/coreplugin/actionmanager/commandmappings.cpp
index 0280217dab..4cec7e69a4 100644
--- a/src/plugins/coreplugin/actionmanager/commandmappings.cpp
+++ b/src/plugins/coreplugin/actionmanager/commandmappings.cpp
@@ -74,11 +74,16 @@ public:
defaultButton = new QPushButton(CommandMappings::tr("Reset All"), groupBox);
defaultButton->setToolTip(CommandMappings::tr("Reset all to default."));
+ resetButton = new QPushButton(CommandMappings::tr("Reset"), groupBox);
+ resetButton->setToolTip(CommandMappings::tr("Reset to default."));
+ resetButton->setVisible(false);
+
importButton = new QPushButton(CommandMappings::tr("Import..."), groupBox);
exportButton = new QPushButton(CommandMappings::tr("Export..."), groupBox);
auto hboxLayout1 = new QHBoxLayout();
hboxLayout1->addWidget(defaultButton);
+ hboxLayout1->addWidget(resetButton);
hboxLayout1->addStretch();
hboxLayout1->addWidget(importButton);
hboxLayout1->addWidget(exportButton);
@@ -100,6 +105,7 @@ public:
q, &CommandMappings::importAction);
q->connect(defaultButton, &QPushButton::clicked,
q, &CommandMappings::defaultAction);
+ q->connect(resetButton, &QPushButton::clicked, q, &CommandMappings::resetRequested);
commandList->sortByColumn(0, Qt::AscendingOrder);
@@ -117,6 +123,7 @@ public:
FancyLineEdit *filterEdit;
QTreeWidget *commandList;
QPushButton *defaultButton;
+ QPushButton *resetButton;
QPushButton *importButton;
QPushButton *exportButton;
};
@@ -145,6 +152,11 @@ void CommandMappings::setImportExportEnabled(bool enabled)
d->exportButton->setVisible(enabled);
}
+void CommandMappings::setResetVisible(bool visible)
+{
+ d->resetButton->setVisible(visible);
+}
+
QTreeWidget *CommandMappings::commandList() const
{
return d->commandList;
diff --git a/src/plugins/coreplugin/actionmanager/commandmappings.h b/src/plugins/coreplugin/actionmanager/commandmappings.h
index b6e9af206a..2d8b8ac017 100644
--- a/src/plugins/coreplugin/actionmanager/commandmappings.h
+++ b/src/plugins/coreplugin/actionmanager/commandmappings.h
@@ -50,6 +50,7 @@ public:
signals:
void currentCommandChanged(QTreeWidgetItem *current);
+ void resetRequested();
protected:
virtual void defaultAction() = 0;
@@ -61,8 +62,9 @@ protected:
void filterChanged(const QString &f);
- // access to m_page
void setImportExportEnabled(bool enabled);
+ void setResetVisible(bool visible);
+
QTreeWidget *commandList() const;
QString filterText() const;
void setFilterText(const QString &text);
diff --git a/src/plugins/coreplugin/actionmanager/commandsfile.cpp b/src/plugins/coreplugin/actionmanager/commandsfile.cpp
index faeed00e07..8b03fee9e5 100644
--- a/src/plugins/coreplugin/actionmanager/commandsfile.cpp
+++ b/src/plugins/coreplugin/actionmanager/commandsfile.cpp
@@ -83,9 +83,9 @@ CommandsFile::CommandsFile(const QString &filename)
/*!
\internal
*/
-QMap<QString, QKeySequence> CommandsFile::importCommands() const
+QMap<QString, QList<QKeySequence>> CommandsFile::importCommands() const
{
- QMap<QString, QKeySequence> result;
+ QMap<QString, QList<QKeySequence>> result;
QFile file(m_filename);
if (!file.open(QIODevice::ReadOnly|QIODevice::Text))
@@ -101,19 +101,17 @@ QMap<QString, QKeySequence> CommandsFile::importCommands() const
case QXmlStreamReader::StartElement: {
const QStringRef name = r.name();
if (name == ctx.shortCutElement) {
- if (!currentId.isEmpty()) // shortcut element without key element == empty shortcut
- result.insert(currentId, QKeySequence());
currentId = r.attributes().value(ctx.idAttribute).toString();
+ if (!result.contains(currentId))
+ result.insert(currentId, {});
} else if (name == ctx.keyElement) {
- QTC_ASSERT(!currentId.isEmpty(), return result);
+ QTC_ASSERT(!currentId.isEmpty(), continue);
const QXmlStreamAttributes attributes = r.attributes();
if (attributes.hasAttribute(ctx.valueAttribute)) {
const QString keyString = attributes.value(ctx.valueAttribute).toString();
- result.insert(currentId, QKeySequence(keyString));
- } else {
- result.insert(currentId, QKeySequence());
+ QList<QKeySequence> keys = result.value(currentId);
+ result.insert(currentId, keys << QKeySequence(keyString));
}
- currentId.clear();
} // if key element
} // case QXmlStreamReader::StartElement
default:
@@ -144,14 +142,16 @@ bool CommandsFile::exportCommands(const QList<ShortcutItem *> &items)
w.writeStartElement(ctx.mappingElement);
foreach (const ShortcutItem *item, items) {
const Id id = item->m_cmd->id();
- if (item->m_key.isEmpty()) {
+ if (item->m_keys.isEmpty() || item->m_keys.first().isEmpty()) {
w.writeEmptyElement(ctx.shortCutElement);
w.writeAttribute(ctx.idAttribute, id.toString());
} else {
w.writeStartElement(ctx.shortCutElement);
w.writeAttribute(ctx.idAttribute, id.toString());
- w.writeEmptyElement(ctx.keyElement);
- w.writeAttribute(ctx.valueAttribute, item->m_key.toString());
+ for (const QKeySequence &k : item->m_keys) {
+ w.writeEmptyElement(ctx.keyElement);
+ w.writeAttribute(ctx.valueAttribute, k.toString());
+ }
w.writeEndElement(); // Shortcut
}
}
diff --git a/src/plugins/coreplugin/actionmanager/commandsfile.h b/src/plugins/coreplugin/actionmanager/commandsfile.h
index 891856383f..cd4bceeeeb 100644
--- a/src/plugins/coreplugin/actionmanager/commandsfile.h
+++ b/src/plugins/coreplugin/actionmanager/commandsfile.h
@@ -43,7 +43,7 @@ class CommandsFile : public QObject
public:
CommandsFile(const QString &filename);
- QMap<QString, QKeySequence> importCommands() const;
+ QMap<QString, QList<QKeySequence> > importCommands() const;
bool exportCommands(const QList<ShortcutItem *> &items);
private:
diff --git a/src/plugins/coreplugin/coreconstants.h b/src/plugins/coreplugin/coreconstants.h
index fd81737957..d34886632f 100644
--- a/src/plugins/coreplugin/coreconstants.h
+++ b/src/plugins/coreplugin/coreconstants.h
@@ -49,12 +49,13 @@ const char M_FILE[] = "QtCreator.Menu.File";
const char M_FILE_RECENTFILES[] = "QtCreator.Menu.File.RecentFiles";
const char M_EDIT[] = "QtCreator.Menu.Edit";
const char M_EDIT_ADVANCED[] = "QtCreator.Menu.Edit.Advanced";
+const char M_VIEW[] = "QtCreator.Menu.View";
+const char M_VIEW_MODESTYLES[] = "QtCreator.Menu.View.ModeStyles";
+const char M_VIEW_VIEWS[] = "QtCreator.Menu.View.Views";
+const char M_VIEW_PANES[] = "QtCreator.Menu.View.Panes";
const char M_TOOLS[] = "QtCreator.Menu.Tools";
const char M_TOOLS_EXTERNAL[] = "QtCreator.Menu.Tools.External";
const char M_WINDOW[] = "QtCreator.Menu.Window";
-const char M_WINDOW_PANES[] = "QtCreator.Menu.Window.Panes";
-const char M_WINDOW_MODESTYLES[] = "QtCreator.Menu.Window.ModeStyles";
-const char M_WINDOW_VIEWS[] = "QtCreator.Menu.Window.Views";
const char M_HELP[] = "QtCreator.Menu.Help";
// Contexts
@@ -174,12 +175,15 @@ const char G_EDIT_BLOCKS[] = "QtCreator.Group.Edit.Blocks";
const char G_EDIT_FONT[] = "QtCreator.Group.Edit.Font";
const char G_EDIT_EDITOR[] = "QtCreator.Group.Edit.Editor";
+// View menu groups
+const char G_VIEW_VIEWS[] = "QtCreator.Group.View.Views";
+const char G_VIEW_PANES[] = "QtCreator.Group.View.Panes";
+
+// Tools menu groups
const char G_TOOLS_OPTIONS[] = "QtCreator.Group.Tools.Options";
// Window menu groups
const char G_WINDOW_SIZE[] = "QtCreator.Group.Window.Size";
-const char G_WINDOW_PANES[] = "QtCreator.Group.Window.Panes";
-const char G_WINDOW_VIEWS[] = "QtCreator.Group.Window.Views";
const char G_WINDOW_SPLIT[] = "QtCreator.Group.Window.Split";
const char G_WINDOW_NAVIGATE[] = "QtCreator.Group.Window.Navigate";
const char G_WINDOW_LIST[] = "QtCreator.Group.Window.List";
diff --git a/src/plugins/coreplugin/coreplugin.cpp b/src/plugins/coreplugin/coreplugin.cpp
index 1b3a80d718..ba2b91cc6e 100644
--- a/src/plugins/coreplugin/coreplugin.cpp
+++ b/src/plugins/coreplugin/coreplugin.cpp
@@ -274,23 +274,23 @@ void CorePlugin::addToPathChooserContextMenu(Utils::PathChooser *pathChooser, QM
QList<QAction*> actions = menu->actions();
QAction *firstAction = actions.isEmpty() ? nullptr : actions.first();
- if (QDir().exists(pathChooser->path())) {
+ if (QDir().exists(pathChooser->filePath().toString())) {
auto *showInGraphicalShell = new QAction(Core::FileUtils::msgGraphicalShellAction(), menu);
connect(showInGraphicalShell, &QAction::triggered, pathChooser, [pathChooser]() {
- Core::FileUtils::showInGraphicalShell(pathChooser, pathChooser->path());
+ Core::FileUtils::showInGraphicalShell(pathChooser, pathChooser->filePath().toString());
});
menu->insertAction(firstAction, showInGraphicalShell);
auto *showInTerminal = new QAction(Core::FileUtils::msgTerminalHereAction(), menu);
connect(showInTerminal, &QAction::triggered, pathChooser, [pathChooser]() {
- Core::FileUtils::openTerminal(pathChooser->path());
+ Core::FileUtils::openTerminal(pathChooser->filePath().toString());
});
menu->insertAction(firstAction, showInTerminal);
} else {
auto *mkPathAct = new QAction(tr("Create Folder"), menu);
connect(mkPathAct, &QAction::triggered, pathChooser, [pathChooser]() {
- QDir().mkpath(pathChooser->path());
+ QDir().mkpath(pathChooser->filePath().toString());
pathChooser->triggerChanged();
});
menu->insertAction(firstAction, mkPathAct);
diff --git a/src/plugins/coreplugin/coreplugin.h b/src/plugins/coreplugin/coreplugin.h
index fee1458eab..04c0b1d117 100644
--- a/src/plugins/coreplugin/coreplugin.h
+++ b/src/plugins/coreplugin/coreplugin.h
@@ -76,6 +76,8 @@ private slots:
// Locator:
void test_basefilefilter();
void test_basefilefilter_data();
+
+ void testOutputFormatter();
#endif
private:
diff --git a/src/plugins/coreplugin/coreplugin.pro b/src/plugins/coreplugin/coreplugin.pro
index 0a11dafc56..495d02028a 100644
--- a/src/plugins/coreplugin/coreplugin.pro
+++ b/src/plugins/coreplugin/coreplugin.pro
@@ -112,7 +112,8 @@ SOURCES += corejsextensions.cpp \
coreicons.cpp \
diffservice.cpp \
menubarfilter.cpp \
- welcomepagehelper.cpp
+ welcomepagehelper.cpp \
+ dialogs/codecselector.cpp
HEADERS += corejsextensions.h \
mainwindow.h \
@@ -228,7 +229,8 @@ HEADERS += corejsextensions.h \
diffservice.h \
menubarfilter.h \
editormanager/ieditorfactory_p.h \
- welcomepagehelper.h
+ welcomepagehelper.h \
+ dialogs/codecselector.h
FORMS += dialogs/newdialog.ui \
dialogs/saveitemsdialog.ui \
diff --git a/src/plugins/coreplugin/coreplugin.qbs b/src/plugins/coreplugin/coreplugin.qbs
index 8afe2f0aa8..63dcd4ab6f 100644
--- a/src/plugins/coreplugin/coreplugin.qbs
+++ b/src/plugins/coreplugin/coreplugin.qbs
@@ -1,5 +1,6 @@
import qbs 1.0
import qbs.FileInfo
+import qbs.Utilities
Project {
name: "Core"
@@ -17,15 +18,13 @@ Project {
condition: qbs.targetOS.contains("windows")
}
- Depends { name: "Qt.script"; required: false }
-
Depends { name: "Utils" }
Depends { name: "Aggregation" }
Depends { name: "app_version_header" }
Properties {
- condition: Qt.script.present
+ condition: Utilities.versionCompare(Qt.qml.version, "5.14.0") >= 0
cpp.defines: base.concat("WITH_JAVASCRIPTFILTER")
}
@@ -209,6 +208,7 @@ Project {
prefix: "dialogs/"
files: [
"addtovcsdialog.cpp", "addtovcsdialog.h", "addtovcsdialog.ui",
+ "codecselector.cpp", "codecselector.h",
"externaltoolconfig.cpp", "externaltoolconfig.h", "externaltoolconfig.ui",
"filepropertiesdialog.cpp", "filepropertiesdialog.h", "filepropertiesdialog.ui",
"ioptionspage.cpp", "ioptionspage.h",
@@ -379,7 +379,7 @@ Project {
Group {
name: "Locator Javascript Filter"
- condition: Qt.script.present
+ condition: Utilities.versionCompare(Qt.qml.version, "5.14.0") >= 0
prefix: "locator/"
files: [
"javascriptfilter.cpp",
diff --git a/src/plugins/texteditor/codecselector.cpp b/src/plugins/coreplugin/dialogs/codecselector.cpp
index 0e90d3e00f..a84b0fa112 100644
--- a/src/plugins/texteditor/codecselector.cpp
+++ b/src/plugins/coreplugin/dialogs/codecselector.cpp
@@ -24,7 +24,7 @@
****************************************************************************/
#include "codecselector.h"
-#include "textdocument.h"
+#include <coreplugin/textdocument.h>
#include <utils/algorithm.h>
#include <utils/fileutils.h>
@@ -36,11 +36,7 @@
#include <QScrollBar>
#include <QVBoxLayout>
-using namespace TextEditor;
-using namespace TextEditor::Internal;
-
-namespace TextEditor {
-namespace Internal {
+namespace Core {
/* custom class to make sure the width is wide enough for the
* contents. Should be easier with Qt. */
@@ -54,11 +50,7 @@ public:
}
};
-} // namespace Internal
-} // namespace TextEditor
-
-
-CodecSelector::CodecSelector(QWidget *parent, TextDocument *doc)
+CodecSelector::CodecSelector(QWidget *parent, Core::BaseTextDocument *doc)
: QDialog(parent)
{
m_hasDecodingError = doc->hasDecodingError();
@@ -166,3 +158,4 @@ void CodecSelector::buttonClicked(QAbstractButton *button)
done(result);
}
+} // namespace Core
diff --git a/src/plugins/texteditor/codecselector.h b/src/plugins/coreplugin/dialogs/codecselector.h
index 64081ca349..f2495bcc05 100644
--- a/src/plugins/texteditor/codecselector.h
+++ b/src/plugins/coreplugin/dialogs/codecselector.h
@@ -25,26 +25,25 @@
#pragma once
+#include "../core_global.h"
+
#include <QDialog>
#include <QLabel>
#include <QDialogButtonBox>
#include <QListWidget>
namespace Utils { class ListWidget; }
+namespace Core { class BaseTextDocument; }
-namespace TextEditor {
-
-class TextDocument;
-
-namespace Internal {
+namespace Core {
-class CodecSelector : public QDialog
+class CORE_EXPORT CodecSelector : public QDialog
{
Q_OBJECT
public:
- CodecSelector(QWidget *parent, TextDocument *doc);
+ CodecSelector(QWidget *parent, Core::BaseTextDocument *doc);
~CodecSelector() override;
QTextCodec *selectedCodec() const;
@@ -67,5 +66,4 @@ private:
QAbstractButton *m_saveButton;
};
-} // namespace Internal
-} // namespace TextEditor
+} // namespace Core
diff --git a/src/plugins/coreplugin/dialogs/ioptionspage.cpp b/src/plugins/coreplugin/dialogs/ioptionspage.cpp
index be700875ad..80ce45d652 100644
--- a/src/plugins/coreplugin/dialogs/ioptionspage.cpp
+++ b/src/plugins/coreplugin/dialogs/ioptionspage.cpp
@@ -36,6 +36,7 @@
#include <QIcon>
#include <QLabel>
#include <QPushButton>
+#include <QRegularExpression>
using namespace Utils;
@@ -227,11 +228,11 @@ const QList<Core::IOptionsPage *> Core::IOptionsPage::allOptionsPages()
}
/*!
- Is used by the \uicontrol Options dialog search filter to match \a searchKeyWord to this options
+ Is used by the \uicontrol Options dialog search filter to match \a regexp to this options
page. This defaults to take the widget and then looks for all child labels, check boxes, push
buttons, and group boxes. Should return \c true when a match is found.
*/
-bool Core::IOptionsPage::matches(const QString &searchKeyWord) const
+bool Core::IOptionsPage::matches(const QRegularExpression &regexp) const
{
if (!m_keywordsInitialized) {
auto that = const_cast<IOptionsPage *>(this);
@@ -251,7 +252,7 @@ bool Core::IOptionsPage::matches(const QString &searchKeyWord) const
m_keywordsInitialized = true;
}
foreach (const QString &keyword, m_keywords)
- if (keyword.contains(searchKeyWord, Qt::CaseInsensitive))
+ if (keyword.contains(regexp))
return true;
return false;
}
diff --git a/src/plugins/coreplugin/dialogs/ioptionspage.h b/src/plugins/coreplugin/dialogs/ioptionspage.h
index e3ceab0fd0..bef965628d 100644
--- a/src/plugins/coreplugin/dialogs/ioptionspage.h
+++ b/src/plugins/coreplugin/dialogs/ioptionspage.h
@@ -64,7 +64,7 @@ public:
using WidgetCreator = std::function<IOptionsPageWidget *()>;
void setWidgetCreator(const WidgetCreator &widgetCreator);
- virtual bool matches(const QString &searchKeyWord) const;
+ virtual bool matches(const QRegularExpression &regexp) const;
virtual QWidget *widget();
virtual void apply();
virtual void finish();
@@ -112,7 +112,7 @@ public:
QIcon categoryIcon() const;
virtual QList<IOptionsPage *> pages() const = 0;
- virtual bool matches(const QString & /* searchKeyWord*/) const = 0;
+ virtual bool matches(const QRegularExpression &regexp) const = 0;
protected:
void setCategory(Id category) { m_category = category; }
diff --git a/src/plugins/coreplugin/dialogs/settingsdialog.cpp b/src/plugins/coreplugin/dialogs/settingsdialog.cpp
index 459af08a4a..192d0843ed 100644
--- a/src/plugins/coreplugin/dialogs/settingsdialog.cpp
+++ b/src/plugins/coreplugin/dialogs/settingsdialog.cpp
@@ -262,19 +262,18 @@ bool CategoryFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sou
if (QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent))
return true;
- const QString pattern = filterRegExp().pattern();
+ const QRegularExpression regex = filterRegularExpression();
const CategoryModel *cm = static_cast<CategoryModel*>(sourceModel());
const Category *category = cm->categories().at(sourceRow);
for (const IOptionsPage *page : category->pages) {
- if (page->displayCategory().contains(pattern, Qt::CaseInsensitive)
- || page->displayName().contains(pattern, Qt::CaseInsensitive)
- || page->matches(pattern))
+ if (page->displayCategory().contains(regex) || page->displayName().contains(regex)
+ || page->matches(regex))
return true;
}
if (!category->providerPagesCreated) {
for (const IOptionsPageProvider *provider : category->providers) {
- if (provider->matches(pattern))
+ if (provider->matches(regex))
return true;
}
}
@@ -469,8 +468,14 @@ SettingsDialog::SettingsDialog(QWidget *parent) :
// The order of the slot connection matters here, the filter slot
// opens the matching page after the model has filtered.
- connect(m_filterLineEdit, &Utils::FancyLineEdit::filterChanged,
- &m_proxyModel, &QSortFilterProxyModel::setFilterFixedString);
+ connect(m_filterLineEdit,
+ &Utils::FancyLineEdit::filterChanged,
+ &m_proxyModel,
+ [this](const QString &filter) {
+ m_proxyModel.setFilterRegularExpression(
+ QRegularExpression(QRegularExpression::escape(filter),
+ QRegularExpression::CaseInsensitiveOption));
+ });
connect(m_filterLineEdit, &Utils::FancyLineEdit::filterChanged,
this, &SettingsDialog::filter);
m_categoryList->setFocus();
@@ -631,12 +636,12 @@ void SettingsDialog::disconnectTabWidgets()
void SettingsDialog::updateEnabledTabs(Category *category, const QString &searchText)
{
int firstEnabledTab = -1;
+ const QRegularExpression regex(QRegularExpression::escape(searchText),
+ QRegularExpression::CaseInsensitiveOption);
for (int i = 0; i < category->pages.size(); ++i) {
const IOptionsPage *page = category->pages.at(i);
- const bool enabled = searchText.isEmpty()
- || page->category().toString().contains(searchText, Qt::CaseInsensitive)
- || page->displayName().contains(searchText, Qt::CaseInsensitive)
- || page->matches(searchText);
+ const bool enabled = searchText.isEmpty() || page->category().toString().contains(regex)
+ || page->displayName().contains(regex) || page->matches(regex);
category->tabWidget->setTabEnabled(i, enabled);
if (enabled && firstEnabledTab < 0)
firstEnabledTab = i;
diff --git a/src/plugins/coreplugin/dialogs/shortcutsettings.cpp b/src/plugins/coreplugin/dialogs/shortcutsettings.cpp
index 8f2cd60b50..a2b26cc701 100644
--- a/src/plugins/coreplugin/dialogs/shortcutsettings.cpp
+++ b/src/plugins/coreplugin/dialogs/shortcutsettings.cpp
@@ -33,6 +33,7 @@
#include <coreplugin/actionmanager/command_p.h>
#include <coreplugin/actionmanager/commandsfile.h>
+#include <utils/algorithm.h>
#include <utils/fancylineedit.h>
#include <utils/hostosinfo.h>
#include <utils/qtcassert.h>
@@ -50,6 +51,8 @@
Q_DECLARE_METATYPE(Core::Internal::ShortcutItem*)
+const char kSeparator[] = " | ";
+
static int translateModifiers(Qt::KeyboardModifiers state,
const QString &text)
{
@@ -70,6 +73,11 @@ static int translateModifiers(Qt::KeyboardModifiers state,
return result;
}
+static QList<QKeySequence> cleanKeys(const QList<QKeySequence> &ks)
+{
+ return Utils::filtered(ks, [](const QKeySequence &k) { return !k.isEmpty(); });
+}
+
static QString keySequenceToEditString(const QKeySequence &sequence)
{
QString text = sequence.toString(QKeySequence::PortableText);
@@ -82,9 +90,23 @@ static QString keySequenceToEditString(const QKeySequence &sequence)
return text;
}
+static QString keySequencesToEditString(const QList<QKeySequence> &sequence)
+{
+ return Utils::transform(cleanKeys(sequence), keySequenceToEditString).join(kSeparator);
+}
+
+static QString keySequencesToNativeString(const QList<QKeySequence> &sequence)
+{
+ return Utils::transform(cleanKeys(sequence),
+ [](const QKeySequence &k) {
+ return k.toString(QKeySequence::NativeText);
+ })
+ .join(kSeparator);
+}
+
static QKeySequence keySequenceFromEditString(const QString &editString)
{
- QString text = editString;
+ QString text = editString.trimmed();
if (Utils::HostOsInfo::isMacHost()) {
// adapt the modifier names
text.replace(QLatin1String("Opt"), QLatin1String("Alt"), Qt::CaseInsensitive);
@@ -238,85 +260,43 @@ private:
void initialize();
void handleCurrentCommandChanged(QTreeWidgetItem *current);
void resetToDefault();
- bool validateShortcutEdit() const;
- bool markCollisions(ShortcutItem *);
- void setKeySequence(const QKeySequence &key);
+ bool updateAndCheckForConflicts(const QKeySequence &key, int index) const;
+ bool markCollisions(ShortcutItem *, int index);
+ void markAllCollisions();
void showConflicts();
void clear();
+ void setupShortcutBox(ShortcutItem *scitem);
+
QList<ShortcutItem *> m_scitems;
QGroupBox *m_shortcutBox;
- Utils::FancyLineEdit *m_shortcutEdit;
- QLabel *m_warningLabel;
+ QGridLayout *m_shortcutLayout;
+ std::vector<std::unique_ptr<ShortcutInput>> m_shortcutInputs;
+ QPointer<QPushButton> m_addButton = nullptr;
};
ShortcutSettingsWidget::ShortcutSettingsWidget()
{
setPageTitle(tr("Keyboard Shortcuts"));
setTargetHeader(tr("Shortcut"));
+ setResetVisible(true);
connect(ActionManager::instance(), &ActionManager::commandListChanged,
this, &ShortcutSettingsWidget::initialize);
connect(this, &ShortcutSettingsWidget::currentCommandChanged,
this, &ShortcutSettingsWidget::handleCurrentCommandChanged);
+ connect(this,
+ &ShortcutSettingsWidget::resetRequested,
+ this,
+ &ShortcutSettingsWidget::resetToDefault);
m_shortcutBox = new QGroupBox(tr("Shortcut"), this);
m_shortcutBox->setEnabled(false);
- auto vboxLayout = new QVBoxLayout(m_shortcutBox);
- m_shortcutBox->setLayout(vboxLayout);
- auto hboxLayout = new QHBoxLayout;
- vboxLayout->addLayout(hboxLayout);
- m_shortcutEdit = new Utils::FancyLineEdit(m_shortcutBox);
- m_shortcutEdit->setFiltering(true);
- m_shortcutEdit->setPlaceholderText(tr("Enter key sequence as text"));
- auto shortcutLabel = new QLabel(tr("Key sequence:"));
- shortcutLabel->setToolTip(Utils::HostOsInfo::isMacHost()
- ? QLatin1String("<html><body>")
- + tr("Use \"Cmd\", \"Opt\", \"Ctrl\", and \"Shift\" for modifier keys. "
- "Use \"Escape\", \"Backspace\", \"Delete\", \"Insert\", \"Home\", and so on, for special keys. "
- "Combine individual keys with \"+\", "
- "and combine multiple shortcuts to a shortcut sequence with \",\". "
- "For example, if the user must hold the Ctrl and Shift modifier keys "
- "while pressing Escape, and then release and press A, "
- "enter \"Ctrl+Shift+Escape,A\".")
- + QLatin1String("</body></html>")
- : QLatin1String("<html><body>")
- + tr("Use \"Ctrl\", \"Alt\", \"Meta\", and \"Shift\" for modifier keys. "
- "Use \"Escape\", \"Backspace\", \"Delete\", \"Insert\", \"Home\", and so on, for special keys. "
- "Combine individual keys with \"+\", "
- "and combine multiple shortcuts to a shortcut sequence with \",\". "
- "For example, if the user must hold the Ctrl and Shift modifier keys "
- "while pressing Escape, and then release and press A, "
- "enter \"Ctrl+Shift+Escape,A\".")
- + QLatin1String("</body></html>"));
- auto shortcutButton = new ShortcutButton(m_shortcutBox);
- connect(shortcutButton, &ShortcutButton::keySequenceChanged,
- this, &ShortcutSettingsWidget::setKeySequence);
- auto resetButton = new QPushButton(tr("Reset"), m_shortcutBox);
- resetButton->setToolTip(tr("Reset to default."));
- connect(resetButton, &QPushButton::clicked,
- this, &ShortcutSettingsWidget::resetToDefault);
- hboxLayout->addWidget(shortcutLabel);
- hboxLayout->addWidget(m_shortcutEdit);
- hboxLayout->addWidget(shortcutButton);
- hboxLayout->addWidget(resetButton);
-
- m_warningLabel = new QLabel(m_shortcutBox);
- m_warningLabel->setTextFormat(Qt::RichText);
- QPalette palette = m_warningLabel->palette();
- palette.setColor(QPalette::Active, QPalette::WindowText,
- Utils::creatorTheme()->color(Utils::Theme::TextColorError));
- m_warningLabel->setPalette(palette);
- connect(m_warningLabel, &QLabel::linkActivated, this, &ShortcutSettingsWidget::showConflicts);
- vboxLayout->addWidget(m_warningLabel);
-
+ m_shortcutLayout = new QGridLayout(m_shortcutBox);
+ m_shortcutBox->setLayout(m_shortcutLayout);
layout()->addWidget(m_shortcutBox);
initialize();
-
- m_shortcutEdit->setValidationFunction([this](Utils::FancyLineEdit *, QString *) {
- return validateShortcutEdit();
- });
}
ShortcutSettingsWidget::~ShortcutSettingsWidget()
@@ -341,7 +321,7 @@ QWidget *ShortcutSettings::widget()
void ShortcutSettingsWidget::apply()
{
foreach (ShortcutItem *item, m_scitems)
- item->m_cmd->setKeySequence(item->m_key);
+ item->m_cmd->setKeySequences(item->m_keys);
}
void ShortcutSettings::apply()
@@ -366,60 +346,112 @@ void ShortcutSettingsWidget::handleCurrentCommandChanged(QTreeWidgetItem *curren
{
ShortcutItem *scitem = shortcutItem(current);
if (!scitem) {
- m_shortcutEdit->clear();
- m_warningLabel->clear();
+ m_shortcutInputs.clear();
+ delete m_addButton;
m_shortcutBox->setEnabled(false);
} else {
- setKeySequence(scitem->m_key);
- markCollisions(scitem);
+ // clean up before showing UI
+ scitem->m_keys = cleanKeys(scitem->m_keys);
+ setupShortcutBox(scitem);
m_shortcutBox->setEnabled(true);
}
}
-bool ShortcutSettingsWidget::validateShortcutEdit() const
+void ShortcutSettingsWidget::setupShortcutBox(ShortcutItem *scitem)
+{
+ const auto updateAddButton = [this] {
+ m_addButton->setEnabled(
+ !Utils::anyOf(m_shortcutInputs, [](const std::unique_ptr<ShortcutInput> &i) {
+ return i->keySequence().isEmpty();
+ }));
+ };
+ const auto addShortcutInput = [this, updateAddButton](int index, const QKeySequence &key) {
+ auto input = std::make_unique<ShortcutInput>();
+ input->addToLayout(m_shortcutLayout, index * 2);
+ input->setConflictChecker(
+ [this, index](const QKeySequence &k) { return updateAndCheckForConflicts(k, index); });
+ connect(input.get(),
+ &ShortcutInput::showConflictsRequested,
+ this,
+ &ShortcutSettingsWidget::showConflicts);
+ connect(input.get(), &ShortcutInput::changed, this, updateAddButton);
+ input->setKeySequence(key);
+ m_shortcutInputs.push_back(std::move(input));
+ };
+ const auto addButtonToLayout = [this, updateAddButton] {
+ m_shortcutLayout->addWidget(m_addButton,
+ m_shortcutInputs.size() * 2 - 1,
+ m_shortcutLayout->columnCount() - 1);
+ updateAddButton();
+ };
+ m_shortcutInputs.clear();
+ delete m_addButton;
+ m_addButton = new QPushButton(tr("Add"), this);
+ for (int i = 0; i < qMax(1, scitem->m_keys.size()); ++i)
+ addShortcutInput(i, scitem->m_keys.value(i));
+ connect(m_addButton, &QPushButton::clicked, this, [this, addShortcutInput, addButtonToLayout] {
+ addShortcutInput(m_shortcutInputs.size(), {});
+ addButtonToLayout();
+ });
+ addButtonToLayout();
+ updateAddButton();
+}
+
+static bool checkValidity(const QKeySequence &key, QString *warningMessage)
+{
+ if (key.isEmpty())
+ return true;
+ QTC_ASSERT(warningMessage, return true);
+ if (!keySequenceIsValid(key)) {
+ *warningMessage = ShortcutSettingsWidget::tr("Invalid key sequence.");
+ return false;
+ }
+ if (isTextKeySequence(key))
+ *warningMessage = ShortcutSettingsWidget::tr("Key sequence will not work in editor.");
+ return true;
+}
+
+bool ShortcutSettingsWidget::updateAndCheckForConflicts(const QKeySequence &key, int index) const
{
- m_warningLabel->clear();
QTreeWidgetItem *current = commandList()->currentItem();
ShortcutItem *item = shortcutItem(current);
if (!item)
- return true;
- bool valid = false;
-
- const QString text = m_shortcutEdit->text().trimmed();
- const QKeySequence currentKey = keySequenceFromEditString(text);
-
- if (keySequenceIsValid(currentKey) || text.isEmpty()) {
- item->m_key = currentKey;
- auto that = const_cast<ShortcutSettingsWidget *>(this);
- if (item->m_cmd->defaultKeySequence() != item->m_key)
- that->setModified(current, true);
- else
- that->setModified(current, false);
- current->setText(2, item->m_key.toString(QKeySequence::NativeText));
- valid = !that->markCollisions(item);
- if (!valid) {
- m_warningLabel->setText(
- tr("Key sequence has potential conflicts. <a href=\"#conflicts\">Show.</a>"));
- } else if (isTextKeySequence(currentKey)) {
- m_warningLabel->setText(tr("Key sequence will not work in editor."));
- }
- } else {
- m_warningLabel->setText(m_warningLabel->text() + tr("Invalid key sequence."));
- }
- return valid;
+ return false;
+
+ while (index >= item->m_keys.size())
+ item->m_keys.append(QKeySequence());
+ item->m_keys[index] = key;
+ auto that = const_cast<ShortcutSettingsWidget *>(this);
+ if (cleanKeys(item->m_keys) != item->m_cmd->defaultKeySequences())
+ that->setModified(current, true);
+ else
+ that->setModified(current, false);
+ current->setText(2, keySequencesToNativeString(item->m_keys));
+ return that->markCollisions(item, index);
}
bool ShortcutSettingsWidget::filterColumn(const QString &filterString, QTreeWidgetItem *item,
int column) const
{
- QString text;
- ShortcutItem *scitem = shortcutItem(item);
+ const ShortcutItem *scitem = shortcutItem(item);
if (column == item->columnCount() - 1) { // shortcut
// filter on the shortcut edit text
if (!scitem)
return true;
- text = keySequenceToEditString(scitem->m_key);
- } else if (column == 0 && scitem) { // command id
+ const QStringList filters = Utils::transform(filterString.split(kSeparator),
+ [](const QString &s) { return s.trimmed(); });
+ for (const QKeySequence &k : scitem->m_keys) {
+ const QString &keyString = keySequenceToEditString(k);
+ const bool found = Utils::anyOf(filters, [keyString](const QString &f) {
+ return keyString.contains(f, Qt::CaseInsensitive);
+ });
+ if (found)
+ return false;
+ }
+ return true;
+ }
+ QString text;
+ if (column == 0 && scitem) { // command id
text = scitem->m_cmd->id().toString();
} else {
text = item->text(column);
@@ -427,17 +459,12 @@ bool ShortcutSettingsWidget::filterColumn(const QString &filterString, QTreeWidg
return !text.contains(filterString, Qt::CaseInsensitive);
}
-void ShortcutSettingsWidget::setKeySequence(const QKeySequence &key)
-{
- m_shortcutEdit->setText(keySequenceToEditString(key));
-}
-
void ShortcutSettingsWidget::showConflicts()
{
QTreeWidgetItem *current = commandList()->currentItem();
ShortcutItem *scitem = shortcutItem(current);
if (scitem)
- setFilterText(keySequenceToEditString(scitem->m_key));
+ setFilterText(keySequencesToEditString(scitem->m_keys));
}
void ShortcutSettingsWidget::resetToDefault()
@@ -445,9 +472,9 @@ void ShortcutSettingsWidget::resetToDefault()
QTreeWidgetItem *current = commandList()->currentItem();
ShortcutItem *scitem = shortcutItem(current);
if (scitem) {
- setKeySequence(scitem->m_cmd->defaultKeySequence());
- foreach (ShortcutItem *item, m_scitems)
- markCollisions(item);
+ scitem->m_keys = scitem->m_cmd->defaultKeySequences();
+ setupShortcutBox(scitem);
+ markAllCollisions();
}
}
@@ -459,40 +486,35 @@ void ShortcutSettingsWidget::importAction()
if (!fileName.isEmpty()) {
CommandsFile cf(fileName);
- QMap<QString, QKeySequence> mapping = cf.importCommands();
-
- foreach (ShortcutItem *item, m_scitems) {
+ QMap<QString, QList<QKeySequence>> mapping = cf.importCommands();
+ for (ShortcutItem *item : qAsConst(m_scitems)) {
QString sid = item->m_cmd->id().toString();
if (mapping.contains(sid)) {
- item->m_key = mapping.value(sid);
- item->m_item->setText(2, item->m_key.toString(QKeySequence::NativeText));
+ item->m_keys = mapping.value(sid);
+ item->m_item->setText(2, keySequencesToNativeString(item->m_keys));
if (item->m_item == commandList()->currentItem())
emit currentCommandChanged(item->m_item);
- if (item->m_cmd->defaultKeySequence() != item->m_key)
+ if (item->m_keys != item->m_cmd->defaultKeySequences())
setModified(item->m_item, true);
else
setModified(item->m_item, false);
}
}
-
- foreach (ShortcutItem *item, m_scitems)
- markCollisions(item);
+ markAllCollisions();
}
}
void ShortcutSettingsWidget::defaultAction()
{
foreach (ShortcutItem *item, m_scitems) {
- item->m_key = item->m_cmd->defaultKeySequence();
- item->m_item->setText(2, item->m_key.toString(QKeySequence::NativeText));
+ item->m_keys = item->m_cmd->defaultKeySequences();
+ item->m_item->setText(2, keySequencesToNativeString(item->m_keys));
setModified(item->m_item, false);
if (item->m_item == commandList()->currentItem())
emit currentCommandChanged(item->m_item);
}
-
- foreach (ShortcutItem *item, m_scitems)
- markCollisions(item);
+ markAllCollisions();
}
void ShortcutSettingsWidget::exportAction()
@@ -549,54 +571,155 @@ void ShortcutSettingsWidget::initialize()
}
sections[section]->addChild(item);
- s->m_key = c->keySequence();
+ s->m_keys = c->keySequences();
item->setText(0, subId);
item->setText(1, c->description());
- item->setText(2, s->m_key.toString(QKeySequence::NativeText));
- if (s->m_cmd->defaultKeySequence() != s->m_key)
+ item->setText(2, keySequencesToNativeString(s->m_keys));
+ if (s->m_keys != s->m_cmd->defaultKeySequences())
setModified(item, true);
item->setData(0, Qt::UserRole, QVariant::fromValue(s));
-
- markCollisions(s);
}
+ markAllCollisions();
filterChanged(filterText());
}
-bool ShortcutSettingsWidget::markCollisions(ShortcutItem *item)
+bool ShortcutSettingsWidget::markCollisions(ShortcutItem *item, int index)
{
bool hasCollision = false;
- if (!item->m_key.isEmpty()) {
+ const QKeySequence key = item->m_keys.value(index);
+ if (!key.isEmpty()) {
Id globalId(Constants::C_GLOBAL);
const Context itemContext = item->m_cmd->context();
const bool itemHasGlobalContext = itemContext.contains(globalId);
- foreach (ShortcutItem *currentItem, m_scitems) {
- if (currentItem->m_key.isEmpty() || item == currentItem
- || item->m_key != currentItem->m_key)
+ for (ShortcutItem *currentItem : qAsConst(m_scitems)) {
+ if (item == currentItem)
+ continue;
+ if (!Utils::anyOf(currentItem->m_keys, Utils::equalTo(key)))
continue;
+ // check if contexts might conflict
const Context currentContext = currentItem->m_cmd->context();
bool currentIsConflicting = (itemHasGlobalContext && !currentContext.isEmpty());
if (!currentIsConflicting) {
- foreach (const Id &id, currentContext) {
- if ((id == globalId && !itemContext.isEmpty())
- || itemContext.contains(id)) {
+ for (const Id &id : currentContext) {
+ if ((id == globalId && !itemContext.isEmpty()) || itemContext.contains(id)) {
currentIsConflicting = true;
break;
}
}
}
if (currentIsConflicting) {
- currentItem->m_item->setForeground(
- 2, Utils::creatorTheme()->color(Utils::Theme::TextColorError));
+ currentItem->m_item->setForeground(2,
+ Utils::creatorTheme()->color(
+ Utils::Theme::TextColorError));
hasCollision = true;
}
}
}
- item->m_item->setForeground(2, hasCollision
- ? Utils::creatorTheme()->color(Utils::Theme::TextColorError)
- : commandList()->palette().windowText());
+ item->m_item->setForeground(2,
+ hasCollision
+ ? Utils::creatorTheme()->color(Utils::Theme::TextColorError)
+ : commandList()->palette().windowText());
return hasCollision;
}
+void ShortcutSettingsWidget::markAllCollisions()
+{
+ for (ShortcutItem *item : qAsConst(m_scitems))
+ for (int i = 0; i < item->m_keys.size(); ++i)
+ markCollisions(item, i);
+}
+
+ShortcutInput::ShortcutInput()
+{
+ m_shortcutLabel = new QLabel(tr("Key sequence:"));
+ m_shortcutLabel->setToolTip(
+ Utils::HostOsInfo::isMacHost()
+ ? QLatin1String("<html><body>")
+ + tr("Use \"Cmd\", \"Opt\", \"Ctrl\", and \"Shift\" for modifier keys. "
+ "Use \"Escape\", \"Backspace\", \"Delete\", \"Insert\", \"Home\", and so "
+ "on, for special keys. "
+ "Combine individual keys with \"+\", "
+ "and combine multiple shortcuts to a shortcut sequence with \",\". "
+ "For example, if the user must hold the Ctrl and Shift modifier keys "
+ "while pressing Escape, and then release and press A, "
+ "enter \"Ctrl+Shift+Escape,A\".")
+ + QLatin1String("</body></html>")
+ : QLatin1String("<html><body>")
+ + tr("Use \"Ctrl\", \"Alt\", \"Meta\", and \"Shift\" for modifier keys. "
+ "Use \"Escape\", \"Backspace\", \"Delete\", \"Insert\", \"Home\", and so "
+ "on, for special keys. "
+ "Combine individual keys with \"+\", "
+ "and combine multiple shortcuts to a shortcut sequence with \",\". "
+ "For example, if the user must hold the Ctrl and Shift modifier keys "
+ "while pressing Escape, and then release and press A, "
+ "enter \"Ctrl+Shift+Escape,A\".")
+ + QLatin1String("</body></html>"));
+
+ m_shortcutEdit = new Utils::FancyLineEdit;
+ m_shortcutEdit->setFiltering(true);
+ m_shortcutEdit->setPlaceholderText(tr("Enter key sequence as text"));
+ connect(m_shortcutEdit, &Utils::FancyLineEdit::textChanged, this, &ShortcutInput::changed);
+
+ m_shortcutButton = new ShortcutButton;
+ connect(m_shortcutButton,
+ &ShortcutButton::keySequenceChanged,
+ this,
+ [this](const QKeySequence &k) { setKeySequence(k); });
+
+ m_warningLabel = new QLabel;
+ m_warningLabel->setTextFormat(Qt::RichText);
+ QPalette palette = m_warningLabel->palette();
+ palette.setColor(QPalette::Active,
+ QPalette::WindowText,
+ Utils::creatorTheme()->color(Utils::Theme::TextColorError));
+ m_warningLabel->setPalette(palette);
+ connect(m_warningLabel, &QLabel::linkActivated, this, &ShortcutInput::showConflictsRequested);
+
+ m_shortcutEdit->setValidationFunction([this](Utils::FancyLineEdit *, QString *) {
+ QString warningMessage;
+ const QKeySequence key = keySequenceFromEditString(m_shortcutEdit->text());
+ const bool isValid = checkValidity(key, &warningMessage);
+ m_warningLabel->setText(warningMessage);
+ if (isValid && m_conflictChecker && m_conflictChecker(key)) {
+ m_warningLabel->setText(ShortcutSettingsWidget::tr(
+ "Key sequence has potential conflicts. <a href=\"#conflicts\">Show.</a>"));
+ }
+ return isValid;
+ });
+}
+
+ShortcutInput::~ShortcutInput()
+{
+ delete m_shortcutLabel;
+ delete m_shortcutEdit;
+ delete m_shortcutButton;
+ delete m_warningLabel;
+}
+
+void ShortcutInput::addToLayout(QGridLayout *layout, int row)
+{
+ layout->addWidget(m_shortcutLabel, row, 0);
+ layout->addWidget(m_shortcutEdit, row, 1);
+ layout->addWidget(m_shortcutButton, row, 2);
+
+ layout->addWidget(m_warningLabel, row + 1, 0, 1, 2);
+}
+
+void ShortcutInput::setKeySequence(const QKeySequence &key)
+{
+ m_shortcutEdit->setText(keySequenceToEditString(key));
+}
+
+QKeySequence ShortcutInput::keySequence() const
+{
+ return keySequenceFromEditString(m_shortcutEdit->text());
+}
+
+void ShortcutInput::setConflictChecker(const ShortcutInput::ConflictChecker &fun)
+{
+ m_conflictChecker = fun;
+}
+
} // namespace Internal
} // namespace Core
diff --git a/src/plugins/coreplugin/dialogs/shortcutsettings.h b/src/plugins/coreplugin/dialogs/shortcutsettings.h
index a49d45a615..cee7f55c0b 100644
--- a/src/plugins/coreplugin/dialogs/shortcutsettings.h
+++ b/src/plugins/coreplugin/dialogs/shortcutsettings.h
@@ -28,6 +28,7 @@
#include <coreplugin/actionmanager/commandmappings.h>
#include <coreplugin/dialogs/ioptionspage.h>
+#include <QGridLayout>
#include <QKeySequence>
#include <QPointer>
#include <QPushButton>
@@ -51,7 +52,7 @@ class ShortcutSettingsWidget;
struct ShortcutItem
{
Command *m_cmd;
- QKeySequence m_key;
+ QList<QKeySequence> m_keys;
QTreeWidgetItem *m_item;
};
@@ -80,6 +81,33 @@ private:
int m_keyNum = 0;
};
+class ShortcutInput : public QObject
+{
+ Q_OBJECT
+public:
+ ShortcutInput();
+ ~ShortcutInput();
+
+ void addToLayout(QGridLayout *layout, int row);
+
+ void setKeySequence(const QKeySequence &key);
+ QKeySequence keySequence() const;
+
+ using ConflictChecker = std::function<bool(QKeySequence)>;
+ void setConflictChecker(const ConflictChecker &fun);
+
+signals:
+ void changed();
+ void showConflictsRequested();
+
+private:
+ ConflictChecker m_conflictChecker;
+ QPointer<QLabel> m_shortcutLabel;
+ QPointer<Utils::FancyLineEdit> m_shortcutEdit;
+ QPointer<ShortcutButton> m_shortcutButton;
+ QPointer<QLabel> m_warningLabel;
+};
+
class ShortcutSettings final : public IOptionsPage
{
public:
diff --git a/src/plugins/coreplugin/documentmanager.cpp b/src/plugins/coreplugin/documentmanager.cpp
index f7a8340d9e..f769b2484b 100644
--- a/src/plugins/coreplugin/documentmanager.cpp
+++ b/src/plugins/coreplugin/documentmanager.cpp
@@ -30,6 +30,9 @@
#include "idocumentfactory.h"
#include "coreconstants.h"
+#include <coreplugin/actionmanager/actioncontainer.h>
+#include <coreplugin/actionmanager/actionmanager.h>
+#include <coreplugin/actionmanager/command.h>
#include <coreplugin/diffservice.h>
#include <coreplugin/dialogs/filepropertiesdialog.h>
#include <coreplugin/dialogs/readonlyfilesdialog.h>
@@ -165,6 +168,8 @@ public:
void checkOnNextFocusChange();
void onApplicationFocusChange();
+ void registerSaveAllAction();
+
QMap<QString, FileState> m_states; // filePathKey -> FileState
QSet<QString> m_changedFiles; // watched file paths collected from file watcher notifications
QList<IDocument *> m_documentsWithoutWatch;
@@ -188,6 +193,8 @@ public:
// signal
// That makes the code easier
IDocument *m_blockedIDocument = nullptr;
+
+ QAction *m_saveAllAction;
};
static DocumentManager *m_instance;
@@ -231,7 +238,20 @@ void DocumentManagerPrivate::onApplicationFocusChange()
m_instance->checkForReload();
}
-DocumentManagerPrivate::DocumentManagerPrivate()
+void DocumentManagerPrivate::registerSaveAllAction()
+{
+ ActionContainer *mfile = ActionManager::actionContainer(Constants::M_FILE);
+ Command *cmd = ActionManager::registerAction(m_saveAllAction, Constants::SAVEALL);
+ cmd->setDefaultKeySequence(QKeySequence(useMacShortcuts ? QString() : tr("Ctrl+Shift+S")));
+ mfile->addAction(cmd, Constants::G_FILE_SAVE);
+ m_saveAllAction->setEnabled(false);
+ connect(m_saveAllAction, &QAction::triggered, []() {
+ DocumentManager::saveAllModifiedDocumentsSilently();
+ });
+}
+
+DocumentManagerPrivate::DocumentManagerPrivate() :
+ m_saveAllAction(new QAction(tr("Save A&ll"), this))
{
// we do not want to do too much directly in the focus change event, so queue the connection
connect(qApp,
@@ -255,7 +275,7 @@ DocumentManager::DocumentManager(QObject *parent)
m_instance = this;
connect(Utils::GlobalFileChangeBlocker::instance(), &Utils::GlobalFileChangeBlocker::stateChanged,
- this, [this](bool blocked) {
+ this, [](bool blocked) {
d->m_postponeAutoReload = blocked;
if (!blocked)
QTimer::singleShot(500, m_instance, &DocumentManager::checkForReload);
@@ -348,6 +368,7 @@ void DocumentManager::addDocuments(const QList<IDocument *> &documents, bool add
m_instance, &DocumentManager::documentDestroyed);
connect(document, &IDocument::filePathChanged,
m_instance, &DocumentManager::filePathChanged);
+ connect(document, &IDocument::changed, m_instance, &DocumentManager::updateSaveAll);
d->m_documentsWithoutWatch.append(document);
}
}
@@ -360,6 +381,7 @@ void DocumentManager::addDocuments(const QList<IDocument *> &documents, bool add
connect(document, &QObject::destroyed, m_instance, &DocumentManager::documentDestroyed);
connect(document, &IDocument::filePathChanged,
m_instance, &DocumentManager::filePathChanged);
+ connect(document, &IDocument::changed, m_instance, &DocumentManager::updateSaveAll);
addFileInfo(document);
}
}
@@ -473,6 +495,11 @@ void DocumentManager::filePathChanged(const FilePath &oldName, const FilePath &n
emit m_instance->documentRenamed(doc, oldName.toString(), newName.toString());
}
+void DocumentManager::updateSaveAll()
+{
+ d->m_saveAllAction->setEnabled(!modifiedDocuments().empty());
+}
+
/*!
Adds \a document to the collection. If \a addWatcher is \c true
(the default), the document's file is added to a file system watcher
@@ -509,6 +536,7 @@ bool DocumentManager::removeDocument(IDocument *document)
disconnect(document, &IDocument::changed, m_instance, &DocumentManager::checkForNewFileName);
}
disconnect(document, &QObject::destroyed, m_instance, &DocumentManager::documentDestroyed);
+ disconnect(document, &IDocument::changed, m_instance, &DocumentManager::updateSaveAll);
return addWatcher;
}
@@ -640,7 +668,7 @@ static bool saveModifiedFilesHelper(const QList<IDocument *> &documents,
QList<IDocument *> modifiedDocuments;
foreach (IDocument *document, documents) {
- if (document && document->isModified()) {
+ if (document && document->isModified() && !document->isTemporary()) {
QString name = document->filePath().toString();
if (name.isEmpty())
name = document->fallbackSaveAsFileName();
@@ -739,6 +767,7 @@ bool DocumentManager::saveDocument(IDocument *document, const QString &fileName,
addDocument(document, addWatcher);
unexpectFileChange(effName);
+ m_instance->updateSaveAll();
return ret;
}
@@ -1501,6 +1530,11 @@ void DocumentManager::notifyFilesChangedInternally(const QStringList &files)
emit m_instance->filesChangedInternally(files);
}
+void DocumentManager::registerSaveAllAction()
+{
+ d->registerSaveAllAction();
+}
+
// -------------- FileChangeBlocker
/*!
diff --git a/src/plugins/coreplugin/documentmanager.h b/src/plugins/coreplugin/documentmanager.h
index 66ca54cd2e..9e11d7cf42 100644
--- a/src/plugins/coreplugin/documentmanager.h
+++ b/src/plugins/coreplugin/documentmanager.h
@@ -162,6 +162,8 @@ private:
void checkForReload();
void changedFile(const QString &file);
void filePathChanged(const Utils::FilePath &oldName, const Utils::FilePath &newName);
+ void updateSaveAll();
+ static void registerSaveAllAction();
friend class Core::Internal::MainWindow;
friend class Core::Internal::DocumentManagerPrivate;
diff --git a/src/plugins/coreplugin/find/searchresultwidget.cpp b/src/plugins/coreplugin/find/searchresultwidget.cpp
index 23b894ef9a..bfa941edae 100644
--- a/src/plugins/coreplugin/find/searchresultwidget.cpp
+++ b/src/plugins/coreplugin/find/searchresultwidget.cpp
@@ -176,8 +176,8 @@ SearchResultWidget::SearchResultWidget(QWidget *parent) :
m_preserveCaseCheck = new QCheckBox(m_topReplaceWidget);
m_preserveCaseCheck->setText(tr("Preser&ve case"));
m_preserveCaseCheck->setEnabled(false);
- m_renameFilesCheckBox = new QCheckBox(m_topReplaceWidget);
- m_renameFilesCheckBox->setVisible(false);
+ m_additionalReplaceWidget = new QWidget(m_topReplaceWidget);
+ m_additionalReplaceWidget->setVisible(false);
m_replaceButton = new QToolButton(m_topReplaceWidget);
m_replaceButton->setToolTip(tr("Replace all occurrences."));
m_replaceButton->setText(tr("&Replace"));
@@ -198,7 +198,7 @@ SearchResultWidget::SearchResultWidget(QWidget *parent) :
topReplaceLayout->addWidget(m_replaceLabel);
topReplaceLayout->addWidget(m_replaceTextEdit);
topReplaceLayout->addWidget(m_preserveCaseCheck);
- topReplaceLayout->addWidget(m_renameFilesCheckBox);
+ topReplaceLayout->addWidget(m_additionalReplaceWidget);
topReplaceLayout->addWidget(m_replaceButton);
topReplaceLayout->addStretch(2);
setShowReplaceUI(m_replaceSupported);
@@ -208,6 +208,8 @@ SearchResultWidget::SearchResultWidget(QWidget *parent) :
this, &SearchResultWidget::handleJumpToSearchResult);
connect(m_replaceTextEdit, &QLineEdit::returnPressed,
this, &SearchResultWidget::handleReplaceButton);
+ connect(m_replaceTextEdit, &QLineEdit::textChanged,
+ this, &SearchResultWidget::replaceTextChanged);
connect(m_replaceButton, &QAbstractButton::clicked,
this, &SearchResultWidget::handleReplaceButton);
}
@@ -229,7 +231,16 @@ void SearchResultWidget::setInfo(const QString &label, const QString &toolTip, c
QWidget *SearchResultWidget::additionalReplaceWidget() const
{
- return m_renameFilesCheckBox;
+ return m_additionalReplaceWidget;
+}
+
+void SearchResultWidget::setAdditionalReplaceWidget(QWidget *widget)
+{
+ if (QLayoutItem *item = m_topReplaceWidget->layout()->replaceWidget(m_additionalReplaceWidget,
+ widget))
+ delete item;
+ delete m_additionalReplaceWidget;
+ m_additionalReplaceWidget = widget;
}
void SearchResultWidget::addResult(const QString &fileName,
diff --git a/src/plugins/coreplugin/find/searchresultwidget.h b/src/plugins/coreplugin/find/searchresultwidget.h
index 22193a231e..ee91ded132 100644
--- a/src/plugins/coreplugin/find/searchresultwidget.h
+++ b/src/plugins/coreplugin/find/searchresultwidget.h
@@ -54,6 +54,7 @@ public:
void setInfo(const QString &label, const QString &toolTip, const QString &term);
QWidget *additionalReplaceWidget() const;
+ void setAdditionalReplaceWidget(QWidget *widget);
void addResult(const QString &fileName,
const QString &lineText,
@@ -97,6 +98,7 @@ public slots:
signals:
void activated(const Core::SearchResultItem &item);
void replaceButtonClicked(const QString &replaceText, const QList<Core::SearchResultItem> &checkedItems, bool preserveCase);
+ void replaceTextChanged(const QString &replaceText);
void searchAgainRequested();
void cancelled();
void paused(bool paused);
@@ -131,7 +133,7 @@ private:
QToolButton *m_replaceButton = nullptr;
QToolButton *m_searchAgainButton = nullptr;
QCheckBox *m_preserveCaseCheck = nullptr;
- QCheckBox *m_renameFilesCheckBox = nullptr;
+ QWidget *m_additionalReplaceWidget = nullptr;
QWidget *m_descriptionContainer = nullptr;
QLabel *m_label = nullptr;
QLabel *m_searchTerm = nullptr;
diff --git a/src/plugins/coreplugin/find/searchresultwindow.cpp b/src/plugins/coreplugin/find/searchresultwindow.cpp
index 8f973dbe4c..2b3723c4f6 100644
--- a/src/plugins/coreplugin/find/searchresultwindow.cpp
+++ b/src/plugins/coreplugin/find/searchresultwindow.cpp
@@ -708,6 +708,8 @@ SearchResult::SearchResult(SearchResultWidget *widget)
connect(widget, &SearchResultWidget::activated, this, &SearchResult::activated);
connect(widget, &SearchResultWidget::replaceButtonClicked,
this, &SearchResult::replaceButtonClicked);
+ connect(widget, &SearchResultWidget::replaceTextChanged,
+ this, &SearchResult::replaceTextChanged);
connect(widget, &SearchResultWidget::cancelled, this, &SearchResult::cancelled);
connect(widget, &SearchResultWidget::paused, this, &SearchResult::paused);
connect(widget, &SearchResultWidget::visibilityChanged,
@@ -770,6 +772,14 @@ QWidget *SearchResult::additionalReplaceWidget() const
}
/*!
+ Sets a UI for a global search and replace action.
+*/
+void SearchResult::setAdditionalReplaceWidget(QWidget *widget)
+{
+ m_widget->setAdditionalReplaceWidget(widget);
+}
+
+/*!
Adds a single result line to the \uicontrol {Search Results} output pane.
\a fileName, \a lineNumber, and \a lineText are shown on the result line.
diff --git a/src/plugins/coreplugin/find/searchresultwindow.h b/src/plugins/coreplugin/find/searchresultwindow.h
index 90f20b47b3..6a450cb596 100644
--- a/src/plugins/coreplugin/find/searchresultwindow.h
+++ b/src/plugins/coreplugin/find/searchresultwindow.h
@@ -60,6 +60,7 @@ public:
int count() const;
void setSearchAgainSupported(bool supported);
QWidget *additionalReplaceWidget() const;
+ void setAdditionalReplaceWidget(QWidget *widget);
public slots:
void addResult(const QString &fileName,
@@ -82,6 +83,7 @@ public slots:
signals:
void activated(const Core::SearchResultItem &item);
void replaceButtonClicked(const QString &replaceText, const QList<Core::SearchResultItem> &checkedItems, bool preserveCase);
+ void replaceTextChanged(const QString &replaceText);
void cancelled();
void paused(bool paused);
void visibilityChanged(bool visible);
diff --git a/src/plugins/coreplugin/generatedfile.h b/src/plugins/coreplugin/generatedfile.h
index 807f2f5166..7dd987d56f 100644
--- a/src/plugins/coreplugin/generatedfile.h
+++ b/src/plugins/coreplugin/generatedfile.h
@@ -36,18 +36,20 @@ class GeneratedFilePrivate;
class CORE_EXPORT GeneratedFile
{
public:
- enum Attribute { // Open this file in editor
- OpenEditorAttribute = 0x01,
- // Open project
- OpenProjectAttribute = 0x02,
- /* File is generated by external scripts, do not write out,
- * see BaseFileWizard::writeFiles() */
- CustomGeneratorAttribute = 0x4,
- /* File exists and the user indicated that he wants to keep it */
- KeepExistingFileAttribute = 0x8,
- /* Force overwriting of a file without asking the user to keep it */
- ForceOverwrite = 0x10
- };
+ enum Attribute {
+ // Open this file in editor
+ OpenEditorAttribute = 0x01,
+ // Open project
+ OpenProjectAttribute = 0x02,
+ // File is generated by external scripts, do not write out, see BaseFileWizard::writeFiles()
+ CustomGeneratorAttribute = 0x4,
+ // File exists and the user indicated that he wants to keep it
+ KeepExistingFileAttribute = 0x8,
+ // Force overwriting of a file without asking the user to keep it
+ ForceOverwrite = 0x10,
+ // Mark the document temporary after opening the file
+ TemporaryFile = 0x20
+ };
Q_DECLARE_FLAGS(Attributes, Attribute)
GeneratedFile();
diff --git a/src/plugins/coreplugin/helpitem.cpp b/src/plugins/coreplugin/helpitem.cpp
index 544c9be9c9..2a972cb98e 100644
--- a/src/plugins/coreplugin/helpitem.cpp
+++ b/src/plugins/coreplugin/helpitem.cpp
@@ -211,7 +211,7 @@ const HelpItem::Links &HelpItem::links() const
m_helpLinks.emplace(Links{{m_keyword, m_helpUrl}});
} else {
m_helpLinks.emplace(); // set a value even if there are no help IDs
- QMap<QString, QUrl> helpLinks;
+ QMultiMap<QString, QUrl> helpLinks;
for (const QString &id : m_helpIds) {
helpLinks = Core::HelpManager::linksForIdentifier(id);
if (!helpLinks.isEmpty()) {
diff --git a/src/plugins/coreplugin/helpmanager.cpp b/src/plugins/coreplugin/helpmanager.cpp
index 3e8e5b4003..4fbafd202b 100644
--- a/src/plugins/coreplugin/helpmanager.cpp
+++ b/src/plugins/coreplugin/helpmanager.cpp
@@ -86,14 +86,14 @@ void unregisterDocumentation(const QStringList &fileNames)
m_instance->unregisterDocumentation(fileNames);
}
-QMap<QString, QUrl> linksForIdentifier(const QString &id)
+QMultiMap<QString, QUrl> linksForIdentifier(const QString &id)
{
- return checkInstance() ? m_instance->linksForIdentifier(id) : QMap<QString, QUrl>();
+ return checkInstance() ? m_instance->linksForIdentifier(id) : QMultiMap<QString, QUrl>();
}
-QMap<QString, QUrl> linksForKeyword(const QString &keyword)
+QMultiMap<QString, QUrl> linksForKeyword(const QString &keyword)
{
- return checkInstance() ? m_instance->linksForKeyword(keyword) : QMap<QString, QUrl>();
+ return checkInstance() ? m_instance->linksForKeyword(keyword) : QMultiMap<QString, QUrl>();
}
QByteArray fileData(const QUrl &url)
diff --git a/src/plugins/coreplugin/helpmanager.h b/src/plugins/coreplugin/helpmanager.h
index 7b7e4f052e..ac948b633d 100644
--- a/src/plugins/coreplugin/helpmanager.h
+++ b/src/plugins/coreplugin/helpmanager.h
@@ -63,8 +63,8 @@ CORE_EXPORT QString documentationPath();
CORE_EXPORT void registerDocumentation(const QStringList &fileNames);
CORE_EXPORT void unregisterDocumentation(const QStringList &fileNames);
-CORE_EXPORT QMap<QString, QUrl> linksForIdentifier(const QString &id);
-CORE_EXPORT QMap<QString, QUrl> linksForKeyword(const QString &id);
+CORE_EXPORT QMultiMap<QString, QUrl> linksForIdentifier(const QString &id);
+CORE_EXPORT QMultiMap<QString, QUrl> linksForKeyword(const QString &id);
CORE_EXPORT QByteArray fileData(const QUrl &url);
CORE_EXPORT void showHelpUrl(const QUrl &url, HelpViewerLocation location = HelpModeAlways);
diff --git a/src/plugins/coreplugin/helpmanager_implementation.h b/src/plugins/coreplugin/helpmanager_implementation.h
index 9af4a49938..c317a95e36 100644
--- a/src/plugins/coreplugin/helpmanager_implementation.h
+++ b/src/plugins/coreplugin/helpmanager_implementation.h
@@ -40,8 +40,8 @@ protected:
public:
virtual void registerDocumentation(const QStringList &fileNames) = 0;
virtual void unregisterDocumentation(const QStringList &fileNames) = 0;
- virtual QMap<QString, QUrl> linksForIdentifier(const QString &id) = 0;
- virtual QMap<QString, QUrl> linksForKeyword(const QString &keyword) = 0;
+ virtual QMultiMap<QString, QUrl> linksForIdentifier(const QString &id) = 0;
+ virtual QMultiMap<QString, QUrl> linksForKeyword(const QString &keyword) = 0;
virtual QByteArray fileData(const QUrl &url) = 0;
virtual void showHelpUrl(const QUrl &url, HelpViewerLocation location = HelpModeAlways) = 0;
};
diff --git a/src/plugins/coreplugin/icontext.cpp b/src/plugins/coreplugin/icontext.cpp
index a0838e707f..30dbf87059 100644
--- a/src/plugins/coreplugin/icontext.cpp
+++ b/src/plugins/coreplugin/icontext.cpp
@@ -46,11 +46,218 @@ QDebug operator<<(QDebug debug, const Core::Context &context)
}
/*!
+ \class Core::Context
+ \inmodule QtCreator
+ \ingroup mainclasses
+ \brief The Context class implements a list of context IDs.
+
+ Contexts are used for registering actions with Core::ActionManager, and
+ when creating UI elements that provide a context for actions.
+
+ See \l{The Action Manager and Commands} for an overview of how contexts are
+ used.
+
+ \sa Core::IContext
+ \sa Core::ActionManager
+ \sa {The Action Manager and Commands}
+*/
+
+/*!
+ \typedef Core::Context::const_iterator
+
+ \brief The Context::const_iterator provides an STL-style const interator for
+ Context.
+*/
+
+/*!
+ \fn Core::Context::Context()
+
+ Creates a context list that represents the global context.
+*/
+
+/*!
+ \fn Core::Context::Context(Core::Id c1)
+
+ Creates a context list with a single ID \a c1.
+*/
+
+/*!
+ \fn Core::Context::Context(Core::Id c1, Core::Id c2)
+
+ Creates a context list with IDs \a c1 and \a c2.
+*/
+
+/*!
+ \fn Core::Context::Context(Core::Id c1, Core::Id c2, Core::Id c3)
+
+ Creates a context list with IDs \a c1, \a c2 and \a c3.
+*/
+
+/*!
+ \fn bool Core::Context::contains(Core::Id c) const
+
+ Returns whether this context list contains the ID \a c.
+*/
+
+/*!
+ \fn int Core::Context::size() const
+
+ Returns the number of IDs in the context list.
+*/
+
+/*!
+ \fn bool Core::Context::isEmpty() const
+
+ Returns whether this context list is empty and therefore default
+ constructed.
+*/
+
+/*!
+ \fn Core::Id Core::Context::at(int i) const
+
+ Returns the ID at index \a i in the context list.
+*/
+
+/*!
+ \fn Core::Context::const_iterator Core::Context::begin() const
+
+ Returns an STL-style iterator pointing to the first ID in the context list.
+*/
+
+/*!
+ \fn Core::Context::const_iterator Core::Context::end() const
+
+ Returns an STL-style iterator pointing to the imaginary item after the last
+ ID in the context list.
+*/
+
+/*!
+ \fn int Core::Context::indexOf(Core::Id c) const
+
+ Returns the index position of the ID \a c in the context list. Returns -1
+ if no item matched.
+*/
+
+/*!
+ \fn void Core::Context::removeAt(int i)
+
+ Removes the ID at index \a i from the context list.
+*/
+
+/*!
+ \fn void Core::Context::prepend(Core::Id c)
+
+ Adds the ID \a c as the first item to the context list.
+*/
+
+/*!
+ \fn void Core::Context::add(const Core::Context &c)
+
+ Adds the context list \a c at the end of this context list.
+*/
+
+/*!
+ \fn void Core::Context::add(Core::Id c)
+
+ Adds the ID \a c at the end of the context list.
+*/
+
+/*!
+ \fn bool Core::Context::operator==(const Core::Context &c) const
+ \internal
+*/
+
+/*!
\class Core::IContext
\inmodule QtCreator
\ingroup mainclasses
- \brief The IContext class holds the context for performing an action.
- The behavior of some actions depends on the context in which they are
- applied.
+ \brief The IContext class associates a widget with a context list and
+ context help.
+
+ An instance of IContext must be registered with
+ Core::ICore::addContextObject() to have an effect. For many subclasses of
+ IContext, like Core::IEditor and Core::IMode, this is done automatically.
+ But instances of IContext can be created manually to associate a context
+ and context help for an arbitrary widget, too. Mind that IContext instances
+ must be unregistered with Core::ICore::removeContextObject() as well.
+
+ Whenever the widget is part of the application wide focus widget's parent
+ chain, the associated context list is made active. This makes actions active
+ that were registered for any of the included context IDs. If the user
+ requests context help, the top-most IContext instance in the focus widget's
+ parent hierarchy is asked to provide it.
+
+ See \l{The Action Manager and Commands} for an overview of how contexts are
+ used for managing actions.
+
+ \sa Core::ICore
+ \sa Core::Context
+ \sa Core::ActionManager
+ \sa {The Action Manager and Commands}
+*/
+
+/*!
+ \fn Core::IContext::IContext(QObject *parent)
+
+ Creates an IContext with an optional \a parent.
+*/
+
+/*!
+ \fn Core::Context Core::IContext::context() const
+
+ Returns the context list associated with this IContext.
+
+ \sa setContext()
+*/
+
+/*!
+ \fn QWidget *Core::IContext::widget() const
+
+ Returns the widget associated with this IContext.
+
+ \sa setWidget()
+*/
+
+/*!
+ \typedef Core::IContext::HelpCallback
+
+ The HelpCallback class defines the callback function that is used to report
+ the help item to show when the user requests context help.
+*/
+
+/*!
+ \fn void Core::IContext::contextHelp(const Core::IContext::HelpCallback &callback) const
+
+ Called when the user requests context help and this IContext is the top-most
+ in the application focus widget's parent hierarchy. Implementations must
+ call the passed \a callback with the resulting help item.
+ The default implementation returns an help item with the help ID that was
+ set with setContextHelp().
+
+ \sa setContextHelp()
+*/
+
+/*!
+ \fn void Core::IContext::setContext(const Core::Context &context)
+
+ Sets the context list associated with this IContext to \a context.
+
+ \sa context()
+*/
+
+/*!
+ \fn void Core::IContext::setWidget(QWidget *widget)
+
+ Sets the widget associated with this IContext to \a widget.
+
+ \sa widget()
+*/
+
+/*!
+ \fn void Core::IContext::setContextHelp(const Core::HelpItem &id)
+
+ Sets the context help item associated with this IContext to \a id.
+
+ \sa contextHelp()
*/
diff --git a/src/plugins/coreplugin/icore.cpp b/src/plugins/coreplugin/icore.cpp
index 2ab0936300..b5986bd67c 100644
--- a/src/plugins/coreplugin/icore.cpp
+++ b/src/plugins/coreplugin/icore.cpp
@@ -356,8 +356,26 @@ QString ICore::cacheResourcePath()
QString ICore::installerResourcePath()
{
- return QFileInfo(settings(QSettings::SystemScope)->fileName()).path() + '/'
- + Constants::IDE_ID;
+ return QFileInfo(settings(QSettings::SystemScope)->fileName()).path() + '/' + Constants::IDE_ID;
+}
+
+QString ICore::pluginPath()
+{
+ return QDir::cleanPath(QCoreApplication::applicationDirPath() + '/' + RELATIVE_PLUGIN_PATH);
+}
+
+QString ICore::userPluginPath()
+{
+ QString pluginPath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation);
+ if (Utils::HostOsInfo::isAnyUnixHost() && !Utils::HostOsInfo::isMacHost())
+ pluginPath += "/data";
+ pluginPath += '/' + QLatin1String(Core::Constants::IDE_SETTINGSVARIANT_STR) + '/';
+ pluginPath += QLatin1String(Utils::HostOsInfo::isMacHost() ? Core::Constants::IDE_DISPLAY_NAME
+ : Core::Constants::IDE_ID);
+ pluginPath += "/plugins/";
+ pluginPath += QString::number(IDE_VERSION_MAJOR) + '.' + QString::number(IDE_VERSION_MINOR)
+ + '.' + QString::number(IDE_VERSION_RELEASE);
+ return pluginPath;
}
/*!
diff --git a/src/plugins/coreplugin/icore.h b/src/plugins/coreplugin/icore.h
index 487a971579..8610023e6a 100644
--- a/src/plugins/coreplugin/icore.h
+++ b/src/plugins/coreplugin/icore.h
@@ -97,6 +97,8 @@ public:
static QString userResourcePath();
static QString cacheResourcePath();
static QString installerResourcePath();
+ static QString pluginPath();
+ static QString userPluginPath();
static QString libexecPath();
static QString clangExecutable(const QString &clangBinDirectory);
static QString clangTidyExecutable(const QString &clangBinDirectory);
diff --git a/src/plugins/coreplugin/locator/javascriptfilter.cpp b/src/plugins/coreplugin/locator/javascriptfilter.cpp
index ab6727b8a2..b1f7f7719f 100644
--- a/src/plugins/coreplugin/locator/javascriptfilter.cpp
+++ b/src/plugins/coreplugin/locator/javascriptfilter.cpp
@@ -27,7 +27,7 @@
#include <QClipboard>
#include <QGuiApplication>
-#include <QScriptEngine>
+#include <QJSEngine>
namespace Core {
namespace Internal {
@@ -48,8 +48,8 @@ JavaScriptFilter::JavaScriptFilter()
m_abortTimer.setInterval(1000);
connect(&m_abortTimer, &QTimer::timeout, this, [this] {
m_aborted = true;
- if (m_engine && m_engine->isEvaluating())
- m_engine->abortEvaluation();
+ if (m_engine)
+ m_engine->setInterrupted(true);
});
}
@@ -63,6 +63,7 @@ void JavaScriptFilter::prepareSearch(const QString &entry)
if (!m_engine)
setupEngine();
+ m_engine->setInterrupted(false);
m_aborted = false;
m_abortTimer.start();
}
@@ -118,7 +119,7 @@ void JavaScriptFilter::refresh(QFutureInterface<void> &future)
void JavaScriptFilter::setupEngine()
{
- m_engine.reset(new QScriptEngine);
+ m_engine.reset(new QJSEngine);
m_engine->evaluate(
"function abs(x) { return Math.abs(x); }\n"
"function acos(x) { return Math.acos(x); }\n"
diff --git a/src/plugins/coreplugin/locator/javascriptfilter.h b/src/plugins/coreplugin/locator/javascriptfilter.h
index a11b9c0f21..28ef447604 100644
--- a/src/plugins/coreplugin/locator/javascriptfilter.h
+++ b/src/plugins/coreplugin/locator/javascriptfilter.h
@@ -32,7 +32,7 @@
#include <memory>
QT_BEGIN_NAMESPACE
-class QScriptEngine;
+class QJSEngine;
QT_END_NAMESPACE
namespace Core {
@@ -55,7 +55,7 @@ public:
private:
void setupEngine();
- mutable std::unique_ptr<QScriptEngine> m_engine;
+ mutable std::unique_ptr<QJSEngine> m_engine;
QTimer m_abortTimer;
bool m_aborted = false;
};
diff --git a/src/plugins/coreplugin/locator/locator.pri b/src/plugins/coreplugin/locator/locator.pri
index 2223836c19..ae5cf6e440 100644
--- a/src/plugins/coreplugin/locator/locator.pri
+++ b/src/plugins/coreplugin/locator/locator.pri
@@ -38,9 +38,7 @@ SOURCES += \
FORMS += \
$$PWD/urllocatorfilter.ui
-qtHaveModule(script) {
- QT *= script
-
+minQtVersion(5, 14, 0) {
DEFINES += WITH_JAVASCRIPTFILTER
HEADERS += \
diff --git a/src/plugins/coreplugin/mainwindow.cpp b/src/plugins/coreplugin/mainwindow.cpp
index ea2e8db147..2a9d4edeee 100644
--- a/src/plugins/coreplugin/mainwindow.cpp
+++ b/src/plugins/coreplugin/mainwindow.cpp
@@ -424,6 +424,12 @@ void MainWindow::registerDefaultContainers()
medit->appendGroup(Constants::G_EDIT_FIND);
medit->appendGroup(Constants::G_EDIT_OTHER);
+ ActionContainer *mview = ActionManager::createMenu(Constants::M_VIEW);
+ menubar->addMenu(mview, Constants::G_VIEW);
+ mview->menu()->setTitle(tr("&View"));
+ mview->appendGroup(Constants::G_VIEW_VIEWS);
+ mview->appendGroup(Constants::G_VIEW_PANES);
+
// Tools Menu
ActionContainer *ac = ActionManager::createMenu(Constants::M_TOOLS);
menubar->addMenu(ac, Constants::G_TOOLS);
@@ -434,8 +440,6 @@ void MainWindow::registerDefaultContainers()
menubar->addMenu(mwindow, Constants::G_WINDOW);
mwindow->menu()->setTitle(tr("&Window"));
mwindow->appendGroup(Constants::G_WINDOW_SIZE);
- mwindow->appendGroup(Constants::G_WINDOW_VIEWS);
- mwindow->appendGroup(Constants::G_WINDOW_PANES);
mwindow->appendGroup(Constants::G_WINDOW_SPLIT);
mwindow->appendGroup(Constants::G_WINDOW_NAVIGATE);
mwindow->appendGroup(Constants::G_WINDOW_LIST);
@@ -465,6 +469,7 @@ void MainWindow::registerDefaultActions()
{
ActionContainer *mfile = ActionManager::actionContainer(Constants::M_FILE);
ActionContainer *medit = ActionManager::actionContainer(Constants::M_EDIT);
+ ActionContainer *mview = ActionManager::actionContainer(Constants::M_VIEW);
ActionContainer *mtools = ActionManager::actionContainer(Constants::M_TOOLS);
ActionContainer *mwindow = ActionManager::actionContainer(Constants::M_WINDOW);
ActionContainer *mhelp = ActionManager::actionContainer(Constants::M_HELP);
@@ -544,11 +549,7 @@ void MainWindow::registerDefaultActions()
mfile->addAction(cmd, Constants::G_FILE_SAVE);
// SaveAll Action
- m_saveAllAction = new QAction(tr("Save A&ll"), this);
- cmd = ActionManager::registerAction(m_saveAllAction, Constants::SAVEALL);
- cmd->setDefaultKeySequence(QKeySequence(useMacShortcuts ? QString() : tr("Ctrl+Shift+S")));
- mfile->addAction(cmd, Constants::G_FILE_SAVE);
- connect(m_saveAllAction, &QAction::triggered, this, &MainWindow::saveAll);
+ DocumentManager::registerSaveAllAction();
// Print Action
icon = QIcon::fromTheme(QLatin1String("document-print"));
@@ -640,7 +641,10 @@ void MainWindow::registerDefaultActions()
: Utils::Icons::ZOOMOUT_TOOLBAR.icon();
tmpaction = new QAction(icon, tr("Zoom Out"), this);
cmd = ActionManager::registerAction(tmpaction, Constants::ZOOM_OUT);
- cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+-")));
+ if (useMacShortcuts)
+ cmd->setDefaultKeySequences({QKeySequence(tr("Ctrl+-")), QKeySequence(tr("Ctrl+Shift+-"))});
+ else
+ cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+-")));
tmpaction->setEnabled(false);
// Zoom Reset Action
@@ -714,7 +718,7 @@ void MainWindow::registerDefaultActions()
ProxyAction *toggleLeftSideBarProxyAction =
ProxyAction::proxyActionWithIcon(cmd->action(), Utils::Icons::TOGGLE_LEFT_SIDEBAR_TOOLBAR.icon());
m_toggleLeftSideBarButton->setDefaultAction(toggleLeftSideBarProxyAction);
- mwindow->addAction(cmd, Constants::G_WINDOW_VIEWS);
+ mview->addAction(cmd, Constants::G_VIEW_VIEWS);
m_toggleLeftSideBarAction->setEnabled(false);
// Show Right Sidebar Action
@@ -730,14 +734,14 @@ void MainWindow::registerDefaultActions()
ProxyAction *toggleRightSideBarProxyAction =
ProxyAction::proxyActionWithIcon(cmd->action(), Utils::Icons::TOGGLE_RIGHT_SIDEBAR_TOOLBAR.icon());
m_toggleRightSideBarButton->setDefaultAction(toggleRightSideBarProxyAction);
- mwindow->addAction(cmd, Constants::G_WINDOW_VIEWS);
+ mview->addAction(cmd, Constants::G_VIEW_VIEWS);
m_toggleRightSideBarButton->setEnabled(false);
registerModeSelectorStyleActions();
// Window->Views
- ActionContainer *mviews = ActionManager::createMenu(Constants::M_WINDOW_VIEWS);
- mwindow->addMenu(mviews, Constants::G_WINDOW_VIEWS);
+ ActionContainer *mviews = ActionManager::createMenu(Constants::M_VIEW_VIEWS);
+ mview->addMenu(mviews, Constants::G_VIEW_VIEWS);
mviews->menu()->setTitle(tr("&Views"));
// "Help" separators
@@ -781,7 +785,7 @@ void MainWindow::registerDefaultActions()
void MainWindow::registerModeSelectorStyleActions()
{
- ActionContainer *mwindow = ActionManager::actionContainer(Constants::M_WINDOW);
+ ActionContainer *mview = ActionManager::actionContainer(Constants::M_VIEW);
// Cycle Mode Selector Styles
m_cycleModeSelectorStyleAction = new QAction(tr("Cycle Mode Selector Styles"), this);
@@ -792,8 +796,8 @@ void MainWindow::registerModeSelectorStyleActions()
});
// Mode Selector Styles
- ActionContainer *mmodeLayouts = ActionManager::createMenu(Constants::M_WINDOW_MODESTYLES);
- mwindow->addMenu(mmodeLayouts, Constants::G_WINDOW_VIEWS);
+ ActionContainer *mmodeLayouts = ActionManager::createMenu(Constants::M_VIEW_MODESTYLES);
+ mview->addMenu(mmodeLayouts, Constants::G_VIEW_VIEWS);
QMenu *styleMenu = mmodeLayouts->menu();
styleMenu->setTitle(tr("Mode Selector Style"));
auto *stylesGroup = new QActionGroup(styleMenu);
@@ -889,11 +893,6 @@ void MainWindow::setFocusToEditor()
EditorManagerPrivate::doEscapeKeyFocusMoveMagic();
}
-void MainWindow::saveAll()
-{
- DocumentManager::saveAllModifiedDocumentsSilently();
-}
-
void MainWindow::exit()
{
// this function is most likely called from a user action
diff --git a/src/plugins/coreplugin/mainwindow.h b/src/plugins/coreplugin/mainwindow.h
index 0d7b533086..554e7b6206 100644
--- a/src/plugins/coreplugin/mainwindow.h
+++ b/src/plugins/coreplugin/mainwindow.h
@@ -121,7 +121,6 @@ private:
void openFile();
void aboutToShowRecentFiles();
void setFocusToEditor();
- void saveAll();
void aboutQtCreator();
void aboutPlugins();
void updateFocusWidget(QWidget *old, QWidget *now);
diff --git a/src/plugins/coreplugin/messageoutputwindow.cpp b/src/plugins/coreplugin/messageoutputwindow.cpp
index 1ea565705b..384b34c113 100644
--- a/src/plugins/coreplugin/messageoutputwindow.cpp
+++ b/src/plugins/coreplugin/messageoutputwindow.cpp
@@ -111,7 +111,7 @@ void MessageOutputWindow::visibilityChanged(bool /*b*/)
void MessageOutputWindow::append(const QString &text)
{
- m_widget->appendText(text);
+ m_widget->appendMessage(text, Utils::DebugFormat);
}
int MessageOutputWindow::priorityInStatusBar() const
diff --git a/src/plugins/coreplugin/outputpanemanager.cpp b/src/plugins/coreplugin/outputpanemanager.cpp
index 6b17180d42..c0d96ef961 100644
--- a/src/plugins/coreplugin/outputpanemanager.cpp
+++ b/src/plugins/coreplugin/outputpanemanager.cpp
@@ -391,11 +391,11 @@ OutputPaneManager::OutputPaneManager(QWidget *parent) :
StatusBarManager::addStatusBarWidget(m_buttonsWidget, StatusBarManager::Second);
- ActionContainer *mwindow = ActionManager::actionContainer(Constants::M_WINDOW);
+ ActionContainer *mview = ActionManager::actionContainer(Constants::M_VIEW);
// Window->Output Panes
- ActionContainer *mpanes = ActionManager::createMenu(Constants::M_WINDOW_PANES);
- mwindow->addMenu(mpanes, Constants::G_WINDOW_PANES);
+ ActionContainer *mpanes = ActionManager::createMenu(Constants::M_VIEW_PANES);
+ mview->addMenu(mpanes, Constants::G_VIEW_PANES);
mpanes->menu()->setTitle(tr("Output &Panes"));
mpanes->appendGroup("Coreplugin.OutputPane.ActionsGroup");
mpanes->appendGroup("Coreplugin.OutputPane.PanesGroup");
diff --git a/src/plugins/coreplugin/outputwindow.cpp b/src/plugins/coreplugin/outputwindow.cpp
index 149c7189fd..344d117e4f 100644
--- a/src/plugins/coreplugin/outputwindow.cpp
+++ b/src/plugins/coreplugin/outputwindow.cpp
@@ -26,19 +26,31 @@
#include "outputwindow.h"
#include "actionmanager/actionmanager.h"
+#include "editormanager/editormanager.h"
#include "coreconstants.h"
+#include "coreplugin.h"
#include "icore.h"
#include <utils/outputformatter.h>
-#include <utils/synchronousprocess.h>
+#include <utils/qtcassert.h>
#include <QAction>
#include <QCursor>
+#include <QElapsedTimer>
#include <QMimeData>
#include <QPointer>
#include <QRegularExpression>
#include <QScrollBar>
#include <QTextBlock>
+#include <QTimer>
+
+#ifdef WITH_TESTS
+#include <QtTest>
+#endif
+
+#include <numeric>
+
+const int chunkSize = 10000;
using namespace Utils;
@@ -61,11 +73,12 @@ public:
}
IContext *outputWindowContext = nullptr;
- QPointer<Utils::OutputFormatter> formatter;
QString settingsKey;
+ OutputFormatter formatter;
+ QList<QPair<QString, OutputFormat>> queuedOutput;
+ QTimer queueTimer;
- bool enforceNewline = false;
- bool prependCarriageReturn = false;
+ bool flushRequested = false;
bool scrollToBottom = true;
bool linksActive = true;
bool zoomEnabled = false;
@@ -78,6 +91,8 @@ public:
int lastFilteredBlockNumber = -1;
QPalette originalPalette;
OutputWindow::FilterModeFlags filterMode = OutputWindow::FilterModeFlag::Default;
+ QTimer scrollTimer;
+ QElapsedTimer lastMessage;
};
} // namespace Internal
@@ -93,6 +108,11 @@ OutputWindow::OutputWindow(Context context, const QString &settingsKey, QWidget
setFrameShape(QFrame::NoFrame);
setMouseTracking(true);
setUndoRedoEnabled(false);
+ d->formatter.setPlainTextEdit(this);
+
+ d->queueTimer.setSingleShot(true);
+ d->queueTimer.setInterval(10);
+ connect(&d->queueTimer, &QTimer::timeout, this, &OutputWindow::handleNextOutputChunk);
d->settingsKey = settingsKey;
@@ -135,16 +155,21 @@ OutputWindow::OutputWindow(Context context, const QString &settingsKey, QWidget
Core::ICore::settings()->setValue(d->settingsKey, fontZoom());
});
+ connect(outputFormatter(), &OutputFormatter::openInEditorRequested, this,
+ [](const Utils::FilePath &fp, int line, int column) {
+ EditorManager::openEditorAt(fp.toString(), line, column);
+ });
+
undoAction->setEnabled(false);
redoAction->setEnabled(false);
cutAction->setEnabled(false);
copyAction->setEnabled(false);
- m_scrollTimer.setInterval(10);
- m_scrollTimer.setSingleShot(true);
- connect(&m_scrollTimer, &QTimer::timeout,
+ d->scrollTimer.setInterval(10);
+ d->scrollTimer.setSingleShot(true);
+ connect(&d->scrollTimer, &QTimer::timeout,
this, &OutputWindow::scrollToBottom);
- m_lastMessage.start();
+ d->lastMessage.start();
d->originalFontSize = font().pointSizeF();
@@ -169,8 +194,7 @@ void OutputWindow::mouseReleaseEvent(QMouseEvent *e)
{
if (d->linksActive && d->mouseButtonPressed == Qt::LeftButton) {
const QString href = anchorAt(e->pos());
- if (d->formatter)
- d->formatter->handleLink(href);
+ d->formatter.handleLink(href);
}
// Mouse was released, activate links again
@@ -214,16 +238,15 @@ void OutputWindow::keyPressEvent(QKeyEvent *ev)
verticalScrollBar()->triggerAction(QAbstractSlider::SliderToMaximum);
}
-OutputFormatter *OutputWindow::formatter() const
+void OutputWindow::setLineParsers(const QList<OutputLineParser *> &parsers)
{
- return d->formatter;
+ reset();
+ d->formatter.setLineParsers(parsers);
}
-void OutputWindow::setFormatter(OutputFormatter *formatter)
+OutputFormatter *OutputWindow::outputFormatter() const
{
- d->formatter = formatter;
- if (d->formatter)
- d->formatter->setPlainTextEdit(this);
+ return &d->formatter;
}
void OutputWindow::showEvent(QShowEvent *e)
@@ -364,47 +387,28 @@ void OutputWindow::filterNewContent()
scrollToBottom();
}
-QString OutputWindow::doNewlineEnforcement(const QString &out)
+void OutputWindow::handleNextOutputChunk()
{
- d->scrollToBottom = true;
- QString s = out;
- if (d->enforceNewline) {
- s.prepend('\n');
- d->enforceNewline = false;
+ QTC_ASSERT(!d->queuedOutput.isEmpty(), return);
+ auto &chunk = d->queuedOutput.first();
+ if (chunk.first.size() <= chunkSize) {
+ handleOutputChunk(chunk.first, chunk.second);
+ d->queuedOutput.removeFirst();
+ } else {
+ handleOutputChunk(chunk.first.left(chunkSize), chunk.second);
+ chunk.first.remove(0, chunkSize);
}
-
- if (s.endsWith('\n')) {
- d->enforceNewline = true; // make appendOutputInline put in a newline next time
- s.chop(1);
+ if (!d->queuedOutput.isEmpty())
+ d->queueTimer.start();
+ else if (d->flushRequested) {
+ d->formatter.flush();
+ d->flushRequested = false;
}
-
- return s;
-}
-
-void OutputWindow::setMaxCharCount(int count)
-{
- d->maxCharCount = count;
- setMaximumBlockCount(count / 100);
-}
-
-int OutputWindow::maxCharCount() const
-{
- return d->maxCharCount;
}
-void OutputWindow::appendMessage(const QString &output, OutputFormat format)
+void OutputWindow::handleOutputChunk(const QString &output, OutputFormat format)
{
QString out = output;
- if (d->prependCarriageReturn) {
- d->prependCarriageReturn = false;
- out.prepend('\r');
- }
- out = SynchronousProcess::normalizeNewlines(out);
- if (out.endsWith('\r')) {
- d->prependCarriageReturn = true;
- out.chop(1);
- }
-
if (out.size() > d->maxCharCount) {
// Current line alone exceeds limit, we need to cut it.
out.truncate(d->maxCharCount);
@@ -426,86 +430,42 @@ void OutputWindow::appendMessage(const QString &output, OutputFormat format)
}
}
- const bool atBottom = isScrollbarAtBottom() || m_scrollTimer.isActive();
-
- if (format == ErrorMessageFormat || format == NormalMessageFormat) {
- if (d->formatter)
- d->formatter->appendMessage(doNewlineEnforcement(out), format);
- } else {
-
- bool sameLine = format == StdOutFormatSameLine
- || format == StdErrFormatSameLine;
-
- if (sameLine) {
- d->scrollToBottom = true;
-
- bool enforceNewline = d->enforceNewline;
- d->enforceNewline = false;
-
- if (enforceNewline) {
- out.prepend('\n');
- } else {
- const int newline = out.indexOf('\n');
- moveCursor(QTextCursor::End);
- if (newline != -1) {
- if (d->formatter)
- d->formatter->appendMessage(out.left(newline), format);// doesn't enforce new paragraph like appendPlainText
- out = out.mid(newline);
- }
- }
-
- if (out.isEmpty()) {
- d->enforceNewline = true;
- } else {
- if (out.endsWith('\n')) {
- d->enforceNewline = true;
- out.chop(1);
- }
- if (d->formatter)
- d->formatter->appendMessage(out, format);
- }
- } else {
- if (d->formatter)
- d->formatter->appendMessage(doNewlineEnforcement(out), format);
- }
- }
+ const bool atBottom = isScrollbarAtBottom() || d->scrollTimer.isActive();
+ d->scrollToBottom = true;
+ d->formatter.appendMessage(out, format);
if (atBottom) {
- if (m_lastMessage.elapsed() < 5) {
- m_scrollTimer.start();
+ if (d->lastMessage.elapsed() < 5) {
+ d->scrollTimer.start();
} else {
- m_scrollTimer.stop();
+ d->scrollTimer.stop();
scrollToBottom();
}
}
- m_lastMessage.start();
+ d->lastMessage.start();
enableUndoRedo();
}
-// TODO rename
-void OutputWindow::appendText(const QString &textIn, const QTextCharFormat &format)
+void OutputWindow::setMaxCharCount(int count)
{
- const QString text = SynchronousProcess::normalizeNewlines(textIn);
- if (d->maxCharCount > 0 && document()->characterCount() >= d->maxCharCount)
- return;
- const bool atBottom = isScrollbarAtBottom();
- if (!d->cursor.atEnd())
- d->cursor.movePosition(QTextCursor::End);
- d->cursor.beginEditBlock();
- d->cursor.insertText(doNewlineEnforcement(text), format);
-
- if (d->maxCharCount > 0 && document()->characterCount() >= d->maxCharCount) {
- QTextCharFormat tmp;
- tmp.setFontWeight(QFont::Bold);
- d->cursor.insertText(doNewlineEnforcement(tr("Additional output omitted. You can increase "
- "the limit in the \"Build & Run\" settings.")
- + '\n'), tmp);
- }
+ d->maxCharCount = count;
+ setMaximumBlockCount(count / 100);
+}
- d->cursor.endEditBlock();
- if (atBottom)
- scrollToBottom();
+int OutputWindow::maxCharCount() const
+{
+ return d->maxCharCount;
+}
+
+void OutputWindow::appendMessage(const QString &output, OutputFormat format)
+{
+ if (d->queuedOutput.isEmpty() || d->queuedOutput.last().second != format)
+ d->queuedOutput << qMakePair(output, format);
+ else
+ d->queuedOutput.last().first.append(output);
+ if (!d->queueTimer.isActive())
+ d->queueTimer.start();
}
bool OutputWindow::isScrollbarAtBottom() const
@@ -542,11 +502,35 @@ QMimeData *OutputWindow::createMimeDataFromSelection() const
void OutputWindow::clear()
{
- d->enforceNewline = false;
- d->prependCarriageReturn = false;
- QPlainTextEdit::clear();
- if (d->formatter)
- d->formatter->clear();
+ d->formatter.clear();
+}
+
+void OutputWindow::flush()
+{
+ const int totalQueuedSize = std::accumulate(d->queuedOutput.cbegin(), d->queuedOutput.cend(), 0,
+ [](int val, const QPair<QString, OutputFormat> &c) { return val + c.first.size(); });
+ if (totalQueuedSize > 5 * chunkSize) {
+ d->flushRequested = true;
+ return;
+ }
+ d->queueTimer.stop();
+ for (const auto &chunk : d->queuedOutput)
+ handleOutputChunk(chunk.first, chunk.second);
+ d->queuedOutput.clear();
+ d->formatter.flush();
+}
+
+void OutputWindow::reset()
+{
+ flush();
+ d->queueTimer.stop();
+ d->formatter.reset();
+ if (!d->queuedOutput.isEmpty()) {
+ d->queuedOutput.clear();
+ d->formatter.appendMessage(tr("[Discarding excessive amount of pending output.]\n"),
+ ErrorMessageFormat);
+ }
+ d->flushRequested = false;
}
void OutputWindow::scrollToBottom()
@@ -595,4 +579,83 @@ void OutputWindow::setWordWrapEnabled(bool wrap)
setWordWrapMode(QTextOption::NoWrap);
}
+#ifdef WITH_TESTS
+
+// Handles all lines starting with "A" and the following ones up to and including the next
+// one starting with "A".
+class TestFormatterA : public OutputLineParser
+{
+private:
+ Result handleLine(const QString &text, OutputFormat) override
+ {
+ static const QString replacement = "handled by A\n";
+ if (m_handling) {
+ if (text.startsWith("A")) {
+ m_handling = false;
+ return {Status::Done, {}, replacement};
+ }
+ return {Status::InProgress, {}, replacement};
+ }
+ if (text.startsWith("A")) {
+ m_handling = true;
+ return {Status::InProgress, {}, replacement};
+ }
+ return Status::NotHandled;
+ }
+
+ bool m_handling = false;
+};
+
+// Handles all lines starting with "B". No continuation logic.
+class TestFormatterB : public OutputLineParser
+{
+private:
+ Result handleLine(const QString &text, OutputFormat) override
+ {
+ if (text.startsWith("B"))
+ return {Status::Done, {}, QString("handled by B\n")};
+ return Status::NotHandled;
+ }
+};
+
+void Internal::CorePlugin::testOutputFormatter()
+{
+ const QString input =
+ "B to be handled by B\r\n"
+ "not to be handled\n"
+ "A to be handled by A\n"
+ "continuation for A\r\n"
+ "B looks like B, but still continuation for A\r\n"
+ "A end of A\n"
+ "A next A\n"
+ "A end of next A\n"
+ " A trick\r\n"
+ "line with \r embedded carriage return\n"
+ "B to be handled by B\n";
+ const QString output =
+ "handled by B\n"
+ "not to be handled\n"
+ "handled by A\n"
+ "handled by A\n"
+ "handled by A\n"
+ "handled by A\n"
+ "handled by A\n"
+ "handled by A\n"
+ " A trick\n"
+ " embedded carriage return\n"
+ "handled by B\n";
+
+ // Stress-test the implementation by providing the input in chunks, splitting at all possible
+ // offsets.
+ for (int i = 0; i < input.length(); ++i) {
+ OutputFormatter formatter;
+ QPlainTextEdit textEdit;
+ formatter.setPlainTextEdit(&textEdit);
+ formatter.setLineParsers({new TestFormatterB, new TestFormatterA});
+ formatter.appendMessage(input.left(i), StdOutFormat);
+ formatter.appendMessage(input.mid(i), StdOutFormat);
+ QCOMPARE(textEdit.toPlainText(), output);
+ }
+}
+#endif // WITH_TESTS
} // namespace Core
diff --git a/src/plugins/coreplugin/outputwindow.h b/src/plugins/coreplugin/outputwindow.h
index 509ae6dfab..91a69d2042 100644
--- a/src/plugins/coreplugin/outputwindow.h
+++ b/src/plugins/coreplugin/outputwindow.h
@@ -30,11 +30,12 @@
#include <utils/outputformat.h>
-#include <QElapsedTimer>
#include <QPlainTextEdit>
-#include <QTimer>
-namespace Utils { class OutputFormatter; }
+namespace Utils {
+class OutputFormatter;
+class OutputLineParser;
+}
namespace Core {
@@ -56,15 +57,15 @@ public:
OutputWindow(Context context, const QString &settingsKey, QWidget *parent = nullptr);
~OutputWindow() override;
- Utils::OutputFormatter *formatter() const;
- void setFormatter(Utils::OutputFormatter *formatter);
+ void setLineParsers(const QList<Utils::OutputLineParser *> &parsers);
+ Utils::OutputFormatter *outputFormatter() const;
void appendMessage(const QString &out, Utils::OutputFormat format);
- /// appends a \p text using \p format without using formater
- void appendText(const QString &text, const QTextCharFormat &format = QTextCharFormat());
void grayOutOldContent();
void clear();
+ void flush();
+ void reset();
void scrollToBottom();
@@ -103,11 +104,10 @@ private:
void wheelEvent(QWheelEvent *e) override;
using QPlainTextEdit::setFont; // call setBaseFont instead, which respects the zoom factor
- QTimer m_scrollTimer;
- QElapsedTimer m_lastMessage;
void enableUndoRedo();
- QString doNewlineEnforcement(const QString &out);
void filterNewContent();
+ void handleNextOutputChunk();
+ void handleOutputChunk(const QString &output, Utils::OutputFormat format);
Internal::OutputWindowPrivate *d = nullptr;
};
diff --git a/src/plugins/coreplugin/plugindialog.cpp b/src/plugins/coreplugin/plugindialog.cpp
index f3dceb73a8..7bca53412c 100644
--- a/src/plugins/coreplugin/plugindialog.cpp
+++ b/src/plugins/coreplugin/plugindialog.cpp
@@ -29,28 +29,239 @@
#include "dialogs/restartdialog.h"
-#include <extensionsystem/pluginmanager.h>
-#include <extensionsystem/pluginview.h>
+#include <app/app_version.h>
+
#include <extensionsystem/plugindetailsview.h>
#include <extensionsystem/pluginerrorview.h>
+#include <extensionsystem/pluginmanager.h>
#include <extensionsystem/pluginspec.h>
+#include <extensionsystem/pluginview.h>
+#include <utils/algorithm.h>
+#include <utils/checkablemessagebox.h>
+#include <utils/environment.h>
#include <utils/fancylineedit.h>
+#include <utils/infolabel.h>
+#include <utils/mimetypes/mimedatabase.h>
+#include <utils/pathchooser.h>
+#include <utils/qtcassert.h>
+#include <utils/synchronousprocess.h>
+#include <utils/wizard.h>
+#include <utils/wizardpage.h>
-#include <QVBoxLayout>
-#include <QHBoxLayout>
+#include <QButtonGroup>
#include <QCheckBox>
+#include <QDebug>
#include <QDialog>
#include <QDialogButtonBox>
-#include <QPushButton>
+#include <QDir>
+#include <QFileInfo>
+#include <QHBoxLayout>
#include <QLabel>
-#include <QDebug>
+#include <QPushButton>
+#include <QRadioButton>
+#include <QVBoxLayout>
+
+using namespace Utils;
namespace Core {
namespace Internal {
static bool s_isRestartRequired = false;
+const char kPath[] = "Path";
+const char kApplicationInstall[] = "ApplicationInstall";
+
+static bool hasLibSuffix(const QString &path)
+{
+ return (HostOsInfo().isWindowsHost() && path.endsWith(".dll", Qt::CaseInsensitive))
+ || (HostOsInfo().isLinuxHost() && QFileInfo(path).completeSuffix().startsWith(".so"))
+ || (HostOsInfo().isMacHost() && path.endsWith(".dylib"));
+}
+
+static bool isZipFile(const QString &path)
+{
+ const QList<MimeType> mimeType = mimeTypesForFileName(path);
+ return anyOf(mimeType, [](const MimeType &mt) { return mt.inherits("application/zip"); });
+}
+
+struct Tool
+{
+ FilePath executable;
+ QStringList arguments;
+};
+
+static Utils::optional<Tool> unzipTool(const FilePath &src, const FilePath &dest)
+{
+ const FilePath unzip = Utils::Environment::systemEnvironment().searchInPath(
+ Utils::HostOsInfo::withExecutableSuffix("unzip"));
+ if (!unzip.isEmpty())
+ return Tool{unzip, {"-o", src.toString(), "-d", dest.toString()}};
+
+ const FilePath sevenzip = Utils::Environment::systemEnvironment().searchInPath(
+ Utils::HostOsInfo::withExecutableSuffix("7z"));
+ if (!sevenzip.isEmpty())
+ return Tool{sevenzip, {"x", QString("-o") + dest.toString(), "-y", src.toString()}};
+
+ const FilePath cmake = Utils::Environment::systemEnvironment().searchInPath(
+ Utils::HostOsInfo::withExecutableSuffix("cmake"));
+ if (!cmake.isEmpty())
+ return Tool{cmake, {"-E", "tar", "xvf", src.toString()}};
+
+ return {};
+}
+
+class SourcePage : public WizardPage
+{
+public:
+ SourcePage(QWidget *parent)
+ : WizardPage(parent)
+ {
+ setTitle(PluginDialog::tr("Source"));
+ auto vlayout = new QVBoxLayout;
+ setLayout(vlayout);
+
+ auto label = new QLabel(
+ "<p>"
+ + PluginDialog::tr(
+ "Choose source location. This can be a plugin library file or a zip file.")
+ + "</p>");
+ label->setWordWrap(true);
+ vlayout->addWidget(label);
+
+ auto path = new PathChooser;
+ path->setExpectedKind(PathChooser::Any);
+ vlayout->addWidget(path);
+ registerFieldWithName(kPath, path, "path", SIGNAL(pathChanged(QString)));
+ connect(path, &PathChooser::pathChanged, this, &SourcePage::updateWarnings);
+
+ m_info = new InfoLabel;
+ m_info->setType(InfoLabel::Error);
+ m_info->setVisible(false);
+ vlayout->addWidget(m_info);
+ }
+
+ void updateWarnings()
+ {
+ m_info->setVisible(!isComplete());
+ emit completeChanged();
+ }
+
+ bool isComplete() const
+ {
+ const QString path = field(kPath).toString();
+ if (!QFile::exists(path)) {
+ m_info->setText(PluginDialog::tr("File does not exist."));
+ return false;
+ }
+ if (hasLibSuffix(path))
+ return true;
+
+ if (!isZipFile(path)) {
+ m_info->setText(PluginDialog::tr("File format not supported."));
+ return false;
+ }
+ if (!unzipTool({}, {})) {
+ m_info->setText(
+ PluginDialog::tr("Could not find unzip, 7z, or cmake executable in PATH."));
+ return false;
+ }
+ return true;
+ }
+
+ InfoLabel *m_info = nullptr;
+};
+
+class InstallLocationPage : public WizardPage
+{
+public:
+ InstallLocationPage(QWidget *parent)
+ : WizardPage(parent)
+ {
+ setTitle(PluginDialog::tr("Install Location"));
+ auto vlayout = new QVBoxLayout;
+ setLayout(vlayout);
+
+ auto label = new QLabel("<p>" + PluginDialog::tr("Choose install location.") + "</p>");
+ label->setWordWrap(true);
+ vlayout->addWidget(label);
+ vlayout->addSpacing(10);
+
+ auto localInstall = new QRadioButton(PluginDialog::tr("User plugins"));
+ localInstall->setChecked(true);
+ auto localLabel = new QLabel(
+ PluginDialog::tr("The plugin will be available to all compatible %1 "
+ "installations, but only for the current user.")
+ .arg(Constants::IDE_DISPLAY_NAME));
+ localLabel->setWordWrap(true);
+ localLabel->setAttribute(Qt::WA_MacSmallSize, true);
+
+ vlayout->addWidget(localInstall);
+ vlayout->addWidget(localLabel);
+ vlayout->addSpacing(10);
+
+ auto appInstall = new QRadioButton(
+ PluginDialog::tr("%1 installation").arg(Constants::IDE_DISPLAY_NAME));
+ auto appLabel = new QLabel(
+ PluginDialog::tr("The plugin will be available only to this %1 "
+ "installation, but for all users that can access it.")
+ .arg(Constants::IDE_DISPLAY_NAME));
+ appLabel->setWordWrap(true);
+ appLabel->setAttribute(Qt::WA_MacSmallSize, true);
+ vlayout->addWidget(appInstall);
+ vlayout->addWidget(appLabel);
+
+ auto group = new QButtonGroup(this);
+ group->addButton(localInstall);
+ group->addButton(appInstall);
+
+ registerFieldWithName(kApplicationInstall, this);
+ setField(kApplicationInstall, false);
+ connect(appInstall, &QRadioButton::toggled, this, [this](bool toggled) {
+ setField(kApplicationInstall, toggled);
+ });
+ }
+};
+
+static FilePath pluginInstallPath(QWizard *wizard)
+{
+ return FilePath::fromString(wizard->field(kApplicationInstall).toBool()
+ ? ICore::pluginPath()
+ : ICore::userPluginPath());
+}
+
+static FilePath pluginFilePath(QWizard *wizard)
+{
+ return FilePath::fromVariant(wizard->field(kPath));
+}
+
+class SummaryPage : public WizardPage
+{
+public:
+ SummaryPage(QWidget *parent)
+ : WizardPage(parent)
+ {
+ setTitle(PluginDialog::tr("Summary"));
+
+ auto vlayout = new QVBoxLayout;
+ setLayout(vlayout);
+
+ m_summaryLabel = new QLabel(this);
+ m_summaryLabel->setWordWrap(true);
+ vlayout->addWidget(m_summaryLabel);
+ }
+
+ void initializePage()
+ {
+ m_summaryLabel->setText(PluginDialog::tr("\"%1\" will be installed into \"%2\".")
+ .arg(pluginFilePath(wizard()).toUserOutput(),
+ pluginInstallPath(wizard()).toUserOutput()));
+ }
+
+private:
+ QLabel *m_summaryLabel;
+};
+
PluginDialog::PluginDialog(QWidget *parent)
: QDialog(parent),
m_view(new ExtensionSystem::PluginView(this))
@@ -78,6 +289,7 @@ PluginDialog::PluginDialog(QWidget *parent)
m_detailsButton = new QPushButton(tr("Details"), this);
m_errorDetailsButton = new QPushButton(tr("Error Details"), this);
m_closeButton = new QPushButton(tr("Close"), this);
+ m_installButton = new QPushButton(tr("Install Plugin..."), this);
m_detailsButton->setEnabled(false);
m_errorDetailsButton->setEnabled(false);
m_closeButton->setEnabled(true);
@@ -90,6 +302,7 @@ PluginDialog::PluginDialog(QWidget *parent)
auto hl = new QHBoxLayout;
hl->addWidget(m_detailsButton);
hl->addWidget(m_errorDetailsButton);
+ hl->addWidget(m_installButton);
hl->addSpacing(10);
hl->addWidget(m_restartRequired);
hl->addStretch(5);
@@ -110,8 +323,8 @@ PluginDialog::PluginDialog(QWidget *parent)
[this] { openDetails(m_view->currentPlugin()); });
connect(m_errorDetailsButton, &QAbstractButton::clicked,
this, &PluginDialog::openErrorDetails);
- connect(m_closeButton, &QAbstractButton::clicked,
- this, &PluginDialog::closeDialog);
+ connect(m_installButton, &QAbstractButton::clicked, this, &PluginDialog::showInstallWizard);
+ connect(m_closeButton, &QAbstractButton::clicked, this, &PluginDialog::closeDialog);
updateButtons();
}
@@ -126,6 +339,100 @@ void PluginDialog::closeDialog()
accept();
}
+static bool copyPluginFile(const FilePath &src, const FilePath &dest)
+{
+ const FilePath destFile = dest.pathAppended(src.fileName());
+ if (QFile::exists(destFile.toString())) {
+ QMessageBox box(QMessageBox::Question,
+ PluginDialog::tr("Overwrite File"),
+ PluginDialog::tr("The file \"%1\" exists. Overwrite?")
+ .arg(destFile.toUserOutput()),
+ QMessageBox::Cancel,
+ ICore::dialogParent());
+ QPushButton *acceptButton = box.addButton(PluginDialog::tr("Overwrite"), QMessageBox::AcceptRole);
+ box.setDefaultButton(acceptButton);
+ box.exec();
+ if (box.clickedButton() != acceptButton)
+ return false;
+ QFile::remove(destFile.toString());
+ }
+ QDir(dest.toString()).mkpath(".");
+ if (!QFile::copy(src.toString(), destFile.toString())) {
+ QMessageBox::warning(ICore::dialogParent(),
+ PluginDialog::tr("Failed to Write File"),
+ PluginDialog::tr("Failed to write file \"%1\".")
+ .arg(destFile.toUserOutput()));
+ return false;
+ }
+ return true;
+}
+
+static bool unzip(const FilePath &src, const FilePath &dest)
+{
+ const Utils::optional<Tool> tool = unzipTool(src, dest);
+ QTC_ASSERT(tool, return false);
+ const QString workingDirectory = dest.toFileInfo().absoluteFilePath();
+ QDir(workingDirectory).mkpath(".");
+ CheckableMessageBox box(ICore::dialogParent());
+ box.setIcon(QMessageBox::Information);
+ box.setWindowTitle(PluginDialog::tr("Unzipping File"));
+ box.setText(PluginDialog::tr("Unzipping \"%1\" to \"%2\".")
+ .arg(src.toUserOutput(), dest.toUserOutput()));
+ box.setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
+ box.button(QDialogButtonBox::Ok)->setEnabled(false);
+ box.setCheckBoxVisible(false);
+ box.setDetailedText(
+ PluginDialog::tr("Running %1\nin \"%2\".\n\n", "Running <cmd> in <workingdirectory>")
+ .arg(CommandLine(tool->executable, tool->arguments).toUserOutput(), workingDirectory));
+ QProcess process;
+ process.setProcessChannelMode(QProcess::MergedChannels);
+ QObject::connect(&process, &QProcess::readyReadStandardOutput, &box, [&box, &process]() {
+ box.setDetailedText(box.detailedText() + QString::fromUtf8(process.readAllStandardOutput()));
+ });
+ QObject::connect(&process,
+ QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
+ [&box](int, QProcess::ExitStatus) {
+ box.button(QDialogButtonBox::Ok)->setEnabled(true);
+ box.button(QDialogButtonBox::Cancel)->setEnabled(false);
+ });
+ QObject::connect(&box, &QMessageBox::rejected, &process, [&process] {
+ SynchronousProcess::stopProcess(process);
+ });
+ process.setProgram(tool->executable.toString());
+ process.setArguments(tool->arguments);
+ process.setWorkingDirectory(workingDirectory);
+ process.start(QProcess::ReadOnly);
+ box.exec();
+ return process.exitStatus() == QProcess::NormalExit && process.exitCode() == 0;
+}
+
+void PluginDialog::showInstallWizard()
+{
+ Wizard wizard(ICore::dialogParent());
+ wizard.setWindowTitle(tr("Install Plugin"));
+
+ auto filePage = new SourcePage(&wizard);
+ wizard.addPage(filePage);
+
+ auto installLocationPage = new InstallLocationPage(&wizard);
+ wizard.addPage(installLocationPage);
+
+ auto summaryPage = new SummaryPage(&wizard);
+ wizard.addPage(summaryPage);
+
+ if (wizard.exec()) {
+ const FilePath path = pluginFilePath(&wizard);
+ const FilePath installPath = pluginInstallPath(&wizard);
+ if (hasLibSuffix(path.toString())) {
+ if (copyPluginFile(path, installPath))
+ updateRestartRequired();
+ } else if (isZipFile(path.toString())) {
+ if (unzip(path, installPath))
+ updateRestartRequired();
+ }
+ }
+}
+
void PluginDialog::updateRestartRequired()
{
// just display the notice all the time after once changing something
diff --git a/src/plugins/coreplugin/plugindialog.h b/src/plugins/coreplugin/plugindialog.h
index 44e84637dd..7c237d8a1f 100644
--- a/src/plugins/coreplugin/plugindialog.h
+++ b/src/plugins/coreplugin/plugindialog.h
@@ -53,11 +53,13 @@ private:
void openDetails(ExtensionSystem::PluginSpec *spec);
void openErrorDetails();
void closeDialog();
+ void showInstallWizard();
ExtensionSystem::PluginView *m_view;
QPushButton *m_detailsButton;
QPushButton *m_errorDetailsButton;
+ QPushButton *m_installButton;
QPushButton *m_closeButton;
QLabel *m_restartRequired;
};
diff --git a/src/plugins/coreplugin/systemsettings.cpp b/src/plugins/coreplugin/systemsettings.cpp
index a0627359d8..59b2d518fc 100644
--- a/src/plugins/coreplugin/systemsettings.cpp
+++ b/src/plugins/coreplugin/systemsettings.cpp
@@ -182,7 +182,7 @@ void SystemSettingsWidget::apply()
m_ui.externalFileBrowserEdit->text());
}
}
- PatchTool::setPatchCommand(m_ui.patchChooser->path());
+ PatchTool::setPatchCommand(m_ui.patchChooser->filePath().toString());
EditorManagerPrivate::setAutoSaveEnabled(m_ui.autoSaveCheckBox->isChecked());
EditorManagerPrivate::setAutoSaveInterval(m_ui.autoSaveInterval->value());
EditorManagerPrivate::setAutoSuspendEnabled(m_ui.autoSuspendCheckBox->isChecked());
diff --git a/src/plugins/coreplugin/variablechooser.cpp b/src/plugins/coreplugin/variablechooser.cpp
index 5766818029..f196dabb37 100644
--- a/src/plugins/coreplugin/variablechooser.cpp
+++ b/src/plugins/coreplugin/variablechooser.cpp
@@ -90,8 +90,8 @@ public:
if (!index.isValid())
return false;
- const QRegExp regexp = filterRegExp();
- if (regexp.isEmpty() || sourceModel()->rowCount(index) > 0)
+ const QRegularExpression regexp = filterRegularExpression();
+ if (regexp.pattern().isEmpty() || sourceModel()->rowCount(index) > 0)
return true;
const QString displayText = index.data(Qt::DisplayRole).toString();
@@ -548,7 +548,7 @@ void VariableChooserPrivate::updatePositionAndShow(bool)
void VariableChooserPrivate::updateFilter(const QString &filterText)
{
- m_sortModel->setFilterWildcard(filterText);
+ m_sortModel->setFilterRegularExpression(QRegularExpression::wildcardToRegularExpression(filterText));
m_variableTree->expandAll();
}
diff --git a/src/plugins/coreplugin/welcomepagehelper.cpp b/src/plugins/coreplugin/welcomepagehelper.cpp
index a8eeb042b8..8e2b3c61a9 100644
--- a/src/plugins/coreplugin/welcomepagehelper.cpp
+++ b/src/plugins/coreplugin/welcomepagehelper.cpp
@@ -603,6 +603,10 @@ bool ListItemDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
if (!item)
return false;
auto mev = static_cast<QMouseEvent *>(event);
+
+ if (mev->button() != Qt::LeftButton) // do not react on right click
+ return false;
+
if (index.isValid()) {
const QPoint pos = mev->pos();
if (pos.y() > option.rect.y() + GridProxyModel::TagsSeparatorY) {
diff --git a/src/plugins/cpaster/CMakeLists.txt b/src/plugins/cpaster/CMakeLists.txt
index d631177c4e..39ab53da64 100644
--- a/src/plugins/cpaster/CMakeLists.txt
+++ b/src/plugins/cpaster/CMakeLists.txt
@@ -11,6 +11,7 @@ add_qtc_plugin(CodePaster
cpasterconstants.h
cpaster.qrc
cpasterplugin.cpp cpasterplugin.h
+ dpastedotcomprotocol.cpp dpastedotcomprotocol.h
fileshareprotocol.cpp fileshareprotocol.h
fileshareprotocolsettingspage.cpp fileshareprotocolsettingspage.h
fileshareprotocolsettingswidget.ui
@@ -18,7 +19,6 @@ add_qtc_plugin(CodePaster
frontend/main.cpp
pastebindotcomprotocol.cpp pastebindotcomprotocol.h
pastebindotcomsettings.ui
- pastecodedotxyzprotocol.cpp pastecodedotxyzprotocol.h
pasteselect.ui
pasteselectdialog.cpp pasteselectdialog.h
pasteview.cpp pasteview.h pasteview.ui
diff --git a/src/plugins/cpaster/cpaster.pro b/src/plugins/cpaster/cpaster.pro
index 3565f4d03f..c824caa681 100644
--- a/src/plugins/cpaster/cpaster.pro
+++ b/src/plugins/cpaster/cpaster.pro
@@ -1,12 +1,12 @@
QT += network
include(../../qtcreatorplugin.pri)
HEADERS += cpasterplugin.h \
+ dpastedotcomprotocol.h \
settingspage.h \
protocol.h \
pasteview.h \
cpasterconstants.h \
pastebindotcomprotocol.h \
- pastecodedotxyzprotocol.h \
settings.h \
pasteselectdialog.h \
columnindicatortextedit.h \
@@ -17,11 +17,11 @@ HEADERS += cpasterplugin.h \
codepasterservice.h
SOURCES += cpasterplugin.cpp \
+ dpastedotcomprotocol.cpp \
settingspage.cpp \
protocol.cpp \
pasteview.cpp \
pastebindotcomprotocol.cpp \
- pastecodedotxyzprotocol.cpp \
settings.cpp \
pasteselectdialog.cpp \
columnindicatortextedit.cpp \
diff --git a/src/plugins/cpaster/cpaster.qbs b/src/plugins/cpaster/cpaster.qbs
index 9547f8ad5e..e4aa433130 100644
--- a/src/plugins/cpaster/cpaster.qbs
+++ b/src/plugins/cpaster/cpaster.qbs
@@ -19,6 +19,8 @@ QtcPlugin {
"cpaster.qrc",
"cpasterplugin.cpp",
"cpasterplugin.h",
+ "dpastedotcomprotocol.cpp",
+ "dpastedotcomprotocol.h",
"fileshareprotocol.cpp",
"fileshareprotocol.h",
"fileshareprotocolsettingspage.cpp",
@@ -27,8 +29,6 @@ QtcPlugin {
"pastebindotcomprotocol.cpp",
"pastebindotcomprotocol.h",
"pastebindotcomsettings.ui",
- "pastecodedotxyzprotocol.cpp",
- "pastecodedotxyzprotocol.h",
"pasteselect.ui",
"pasteselectdialog.cpp",
"pasteselectdialog.h",
diff --git a/src/plugins/cpaster/cpasterplugin.cpp b/src/plugins/cpaster/cpasterplugin.cpp
index dcfd01dda5..49dcc1f085 100644
--- a/src/plugins/cpaster/cpasterplugin.cpp
+++ b/src/plugins/cpaster/cpasterplugin.cpp
@@ -25,11 +25,11 @@
#include "cpasterplugin.h"
-#include "pasteview.h"
-#include "pastebindotcomprotocol.h"
-#include "pastecodedotxyzprotocol.h"
+#include "dpastedotcomprotocol.h"
#include "fileshareprotocol.h"
+#include "pastebindotcomprotocol.h"
#include "pasteselectdialog.h"
+#include "pasteview.h"
#include "settingspage.h"
#include "settings.h"
#include "urlopenprotocol.h"
@@ -91,12 +91,12 @@ public:
PasteBinDotComProtocol pasteBinProto;
FileShareProtocol fileShareProto;
- PasteCodeDotXyzProtocol pasteCodeProto;
+ DPasteDotComProtocol dpasteProto;
const QList<Protocol *> m_protocols {
&pasteBinProto,
&fileShareProto,
- &pasteCodeProto
+ &dpasteProto
};
SettingsPage m_settingsPage {
@@ -275,8 +275,8 @@ void CodePasterPluginPrivate::post(QString data, const QString &mimeType)
const FileDataList diffChunks = splitDiffToFiles(data);
const int dialogResult = diffChunks.isEmpty() ?
- view.show(username, QString(), QString(), m_settings.expiryDays, data) :
- view.show(username, QString(), QString(), m_settings.expiryDays, diffChunks);
+ view.show(username, QString(), QString(), m_settings.expiryDays, m_settings.publicPaste, data) :
+ view.show(username, QString(), QString(), m_settings.expiryDays, m_settings.publicPaste, diffChunks);
// Save new protocol in case user changed it.
if (dialogResult == QDialog::Accepted && m_settings.protocol != view.protocol()) {
diff --git a/src/plugins/cpaster/dpastedotcomprotocol.cpp b/src/plugins/cpaster/dpastedotcomprotocol.cpp
new file mode 100644
index 0000000000..1a0d9c6194
--- /dev/null
+++ b/src/plugins/cpaster/dpastedotcomprotocol.cpp
@@ -0,0 +1,134 @@
+/****************************************************************************
+**
+** 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 "dpastedotcomprotocol.h"
+
+#include <coreplugin/messagemanager.h>
+
+#include <QNetworkReply>
+#include <QUrl>
+
+namespace CodePaster {
+
+static QString baseUrl() { return QString("http://dpaste.com"); }
+static QString apiUrl() { return baseUrl() + "/api/v2/"; }
+
+QString DPasteDotComProtocol::protocolName() { return QString("DPaste.Com"); }
+
+unsigned DPasteDotComProtocol::capabilities() const
+{
+ return PostDescriptionCapability | PostUserNameCapability;
+}
+
+void DPasteDotComProtocol::fetch(const QString &id)
+{
+ QNetworkReply * const reply = httpGet(baseUrl() + '/' + id + ".txt");
+ connect(reply, &QNetworkReply::finished, this, [this, id, reply] {
+ QString title;
+ QString content;
+ const bool error = reply->error();
+ if (error) {
+ content = reply->errorString();
+ } else {
+ title = name() + ": " + id;
+ content = QString::fromUtf8(reply->readAll());
+ }
+ reply->deleteLater();
+ emit fetchDone(title, content, error);
+ });
+}
+
+static QByteArray typeToString(Protocol::ContentType type)
+{
+ switch (type) {
+ case Protocol::C:
+ return "c";
+ case Protocol::Cpp:
+ return "cpp";
+ case Protocol::Diff:
+ return "diff";
+ case Protocol::JavaScript:
+ return "js";
+ case Protocol::Text:
+ return "text";
+ case Protocol::Xml:
+ return "xml";
+ }
+ return {}; // For dumb compilers.
+}
+
+void DPasteDotComProtocol::paste(
+ const QString &text,
+ ContentType ct,
+ int expiryDays,
+ bool publicPaste,
+ const QString &username,
+ const QString &comment,
+ const QString &description
+ )
+{
+ Q_UNUSED(publicPaste)
+ Q_UNUSED(comment)
+
+ // See http://dpaste.com/api/v2/
+ QByteArray data;
+ data += "content=" + QUrl::toPercentEncoding(fixNewLines(text));
+ data += "&expiry_days=" + QByteArray::number(expiryDays);
+ data += "&syntax=" + typeToString(ct);
+ data += "&title=" + QUrl::toPercentEncoding(description);
+ data += "&poster=" + QUrl::toPercentEncoding(username);
+
+ QNetworkReply * const reply = httpPost(apiUrl(), data);
+ connect(reply, &QNetworkReply::finished, this, [this, reply] {
+ QString data;
+ if (reply->error()) {
+ reportError(reply->errorString()); // FIXME: Why can't we properly emit an error here?
+ reportError(QString::fromUtf8(reply->readAll()));
+ } else {
+ data = QString::fromUtf8(reply->readAll());
+ if (!data.startsWith(baseUrl())) {
+ reportError(data);
+ data.clear();
+ }
+ }
+ reply->deleteLater();
+ emit pasteDone(data);
+ });
+}
+
+bool DPasteDotComProtocol::checkConfiguration(QString *errorMessage)
+{
+ if (!m_hostKnownOk)
+ m_hostKnownOk = httpStatus(baseUrl(), errorMessage);
+ return m_hostKnownOk;
+}
+
+void DPasteDotComProtocol::reportError(const QString &message)
+{
+ const QString fullMessage = tr("%1: %2").arg(protocolName(), message);
+ Core::MessageManager::write(fullMessage, Core::MessageManager::ModeSwitch);
+}
+
+} // namespace CodePaster
diff --git a/src/plugins/cpaster/pastecodedotxyzprotocol.h b/src/plugins/cpaster/dpastedotcomprotocol.h
index 7988ad9dc8..6f01649578 100644
--- a/src/plugins/cpaster/pastecodedotxyzprotocol.h
+++ b/src/plugins/cpaster/dpastedotcomprotocol.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2018 The Qt Company Ltd.
+** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -29,7 +29,7 @@
namespace CodePaster {
-class PasteCodeDotXyzProtocol : public NetworkProtocol
+class DPasteDotComProtocol : public NetworkProtocol
{
Q_OBJECT
public:
@@ -43,10 +43,10 @@ private:
void paste(const QString &text,
ContentType ct = Text,
int expiryDays = 1,
+ bool publicPaste = false,
const QString &username = QString(),
const QString &comment = QString(),
const QString &description = QString()) override;
- void list() override;
bool checkConfiguration(QString *errorMessage) override;
static void reportError(const QString &message);
diff --git a/src/plugins/cpaster/fileshareprotocol.cpp b/src/plugins/cpaster/fileshareprotocol.cpp
index 3b821db4e3..937165a3f2 100644
--- a/src/plugins/cpaster/fileshareprotocol.cpp
+++ b/src/plugins/cpaster/fileshareprotocol.cpp
@@ -177,11 +177,15 @@ void FileShareProtocol::list()
emit listDone(name(), entries);
}
-void FileShareProtocol::paste(const QString &text,
- ContentType /* ct */, int /* expiryDays */,
- const QString &username,
- const QString & /* comment */,
- const QString &description)
+void FileShareProtocol::paste(
+ const QString &text,
+ ContentType /* ct */,
+ int /* expiryDays */,
+ bool /* publicPaste */,
+ const QString &username,
+ const QString & /* comment */,
+ const QString &description
+ )
{
// Write out temp XML file
Utils::TempFileSaver saver(m_settings->path + QLatin1Char('/') + QLatin1String(tempPatternC));
diff --git a/src/plugins/cpaster/fileshareprotocol.h b/src/plugins/cpaster/fileshareprotocol.h
index ea89e41f2a..a22fa62a97 100644
--- a/src/plugins/cpaster/fileshareprotocol.h
+++ b/src/plugins/cpaster/fileshareprotocol.h
@@ -54,7 +54,7 @@ public:
void fetch(const QString &id) override;
void list() override;
void paste(const QString &text,
- ContentType ct = Text, int expiryDays = 1,
+ ContentType ct = Text, int expiryDays = 1, bool publicPaste = false,
const QString &username = QString(),
const QString &comment = QString(),
const QString &description = QString()) override;
diff --git a/src/plugins/cpaster/fileshareprotocolsettingspage.cpp b/src/plugins/cpaster/fileshareprotocolsettingspage.cpp
index a0b160176b..8d7737934f 100644
--- a/src/plugins/cpaster/fileshareprotocolsettingspage.cpp
+++ b/src/plugins/cpaster/fileshareprotocolsettingspage.cpp
@@ -84,7 +84,7 @@ void FileShareProtocolSettingsWidget::setSettings(const FileShareProtocolSetting
FileShareProtocolSettings FileShareProtocolSettingsWidget::settings() const
{
FileShareProtocolSettings rc;
- rc.path = m_ui.pathChooser->path();
+ rc.path = m_ui.pathChooser->filePath().toString();
rc.displayCount = m_ui.displayCountSpinBox->value();
return rc;
}
diff --git a/src/plugins/cpaster/frontend/CMakeLists.txt b/src/plugins/cpaster/frontend/CMakeLists.txt
index 9adc4e2e0c..58468f63d1 100644
--- a/src/plugins/cpaster/frontend/CMakeLists.txt
+++ b/src/plugins/cpaster/frontend/CMakeLists.txt
@@ -3,8 +3,8 @@ add_qtc_executable(cpaster
SOURCES
argumentscollector.cpp argumentscollector.h
main.cpp
+ ../dpastedotcomprotocol.cpp ../dpastedotcomprotocol.h
../pastebindotcomprotocol.cpp ../pastebindotcomprotocol.h
- ../pastecodedotxyzprotocol.cpp ../pastecodedotxyzprotocol.h
../protocol.cpp ../protocol.h
../urlopenprotocol.cpp ../urlopenprotocol.h
)
diff --git a/src/plugins/cpaster/frontend/frontend.pro b/src/plugins/cpaster/frontend/frontend.pro
index 69b6428a3f..cca00ec980 100644
--- a/src/plugins/cpaster/frontend/frontend.pro
+++ b/src/plugins/cpaster/frontend/frontend.pro
@@ -12,14 +12,14 @@ QT += network
HEADERS = ../protocol.h \
../cpasterconstants.h \
+ ../dpastedotcomprotocol.h \
../pastebindotcomprotocol.h \
- ../pastecodedotxyzprotocol.h \
../urlopenprotocol.h \
argumentscollector.h
SOURCES += ../protocol.cpp \
+ ../dpastedotcomprotocol.cpp \
../pastebindotcomprotocol.cpp \
- ../pastecodedotxyzprotocol.cpp \
../urlopenprotocol.cpp \
argumentscollector.cpp \
main.cpp
diff --git a/src/plugins/cpaster/frontend/frontend.qbs b/src/plugins/cpaster/frontend/frontend.qbs
index 2993953105..94153e93e3 100644
--- a/src/plugins/cpaster/frontend/frontend.qbs
+++ b/src/plugins/cpaster/frontend/frontend.qbs
@@ -23,8 +23,8 @@ QtcTool {
prefix: "../"
files: [
"cpasterconstants.h",
+ "dpastedotcomprotocol.h", "dpastedotcomprotocol.cpp",
"pastebindotcomprotocol.h", "pastebindotcomprotocol.cpp",
- "pastecodedotxyzprotocol.h", "pastecodedotxyzprotocol.cpp",
"protocol.h", "protocol.cpp",
"urlopenprotocol.h", "urlopenprotocol.cpp",
]
diff --git a/src/plugins/cpaster/frontend/main.cpp b/src/plugins/cpaster/frontend/main.cpp
index 50ae182334..afdfdd9166 100644
--- a/src/plugins/cpaster/frontend/main.cpp
+++ b/src/plugins/cpaster/frontend/main.cpp
@@ -24,8 +24,8 @@
****************************************************************************/
#include "argumentscollector.h"
+#include "../dpastedotcomprotocol.h"
#include "../pastebindotcomprotocol.h"
-#include "../pastecodedotxyzprotocol.h"
#include <QFile>
#include <QObject>
@@ -47,8 +47,8 @@ public:
{
if (protocol == PasteBinDotComProtocol::protocolName().toLower())
m_protocol.reset(new PasteBinDotComProtocol);
- else if (protocol == PasteCodeDotXyzProtocol::protocolName().toLower())
- m_protocol.reset(new PasteCodeDotXyzProtocol);
+ else if (protocol == DPasteDotComProtocol::protocolName().toLower())
+ m_protocol.reset(new DPasteDotComProtocol);
else
qFatal("Internal error: Invalid protocol.");
}
@@ -88,8 +88,8 @@ int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
- const QStringList protocols = {PasteBinDotComProtocol::protocolName().toLower(),
- PasteCodeDotXyzProtocol::protocolName().toLower()};
+ const QStringList protocols = {DPasteDotComProtocol::protocolName().toLower(),
+ PasteBinDotComProtocol::protocolName().toLower()};
ArgumentsCollector argsCollector(protocols);
QStringList arguments = QCoreApplication::arguments();
arguments.removeFirst();
diff --git a/src/plugins/cpaster/pastebindotcomprotocol.cpp b/src/plugins/cpaster/pastebindotcomprotocol.cpp
index fb3d60ba92..ed4db9cf46 100644
--- a/src/plugins/cpaster/pastebindotcomprotocol.cpp
+++ b/src/plugins/cpaster/pastebindotcomprotocol.cpp
@@ -99,11 +99,15 @@ static inline QByteArray expirySpecification(int expiryDays)
return QByteArray("N");
}
-void PasteBinDotComProtocol::paste(const QString &text,
- ContentType ct, int expiryDays,
- const QString & /* username */, // Not used unless registered user
- const QString &comment,
- const QString &description)
+void PasteBinDotComProtocol::paste(
+ const QString &text,
+ ContentType ct,
+ int expiryDays,
+ bool publicPaste,
+ const QString & /* username */, // Not used unless registered user
+ const QString &comment,
+ const QString &description
+ )
{
Q_UNUSED(comment)
Q_UNUSED(description)
@@ -118,6 +122,7 @@ void PasteBinDotComProtocol::paste(const QString &text,
pasteData += format(ct);
pasteData += "api_paste_name="; // Title or name.
pasteData += QUrl::toPercentEncoding(description);
+ pasteData.append("&api_paste_private=").append(QByteArray(publicPaste ? "0" : "1"));
pasteData += "&api_paste_code=";
pasteData += QUrl::toPercentEncoding(fixNewLines(text));
// fire request
diff --git a/src/plugins/cpaster/pastebindotcomprotocol.h b/src/plugins/cpaster/pastebindotcomprotocol.h
index f5f308a77b..7e2d1f5cdf 100644
--- a/src/plugins/cpaster/pastebindotcomprotocol.h
+++ b/src/plugins/cpaster/pastebindotcomprotocol.h
@@ -42,6 +42,7 @@ public:
void paste(const QString &text,
ContentType ct = Text,
int expiryDays = 1,
+ bool publicPaste = false,
const QString &username = QString(),
const QString &comment = QString(),
const QString &description = QString()) override;
diff --git a/src/plugins/cpaster/pastecodedotxyzprotocol.cpp b/src/plugins/cpaster/pastecodedotxyzprotocol.cpp
deleted file mode 100644
index 8ca7d5c547..0000000000
--- a/src/plugins/cpaster/pastecodedotxyzprotocol.cpp
+++ /dev/null
@@ -1,147 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 "pastecodedotxyzprotocol.h"
-
-#include <coreplugin/messagemanager.h>
-
-#include <QJsonArray>
-#include <QJsonDocument>
-#include <QJsonObject>
-#include <QJsonParseError>
-#include <QJsonValue>
-#include <QNetworkReply>
-#include <QUrl>
-
-namespace CodePaster {
-
-static QString baseUrl() { return QString("https://pastecode.xyz"); }
-static QString apiUrl() { return baseUrl() + "/api"; }
-
-QString PasteCodeDotXyzProtocol::protocolName() { return QString("Pastecode.Xyz"); }
-
-unsigned PasteCodeDotXyzProtocol::capabilities() const
-{
- return ListCapability | PostDescriptionCapability | PostUserNameCapability;
-}
-
-void PasteCodeDotXyzProtocol::fetch(const QString &id)
-{
- QNetworkReply * const reply = httpGet(baseUrl() + "/view/raw/" + id);
- connect(reply, &QNetworkReply::finished, this, [this, id, reply] {
- QString title;
- QString content;
- const bool error = reply->error();
- if (error) {
- content = reply->errorString();
- } else {
- title = name() + ": " + id;
- content = QString::fromUtf8(reply->readAll());
- }
- reply->deleteLater();
- emit fetchDone(title, content, error);
- });
-}
-
-void PasteCodeDotXyzProtocol::paste(const QString &text, Protocol::ContentType ct, int expiryDays,
- const QString &username, const QString &comment,
- const QString &description)
-{
- QByteArray data;
- data += "text=" + QUrl::toPercentEncoding(fixNewLines(text));
- data += "&expire=" + QUrl::toPercentEncoding(QString::number(expiryDays * 24 * 60));
- data += "&title=" + QUrl::toPercentEncoding(description);
- data += "&name=" + QUrl::toPercentEncoding(username);
- static const auto langValue = [](Protocol::ContentType type) -> QByteArray {
- switch (type) {
- case Protocol::Text: return "text";
- case Protocol::C: return "c";
- case Protocol::Cpp: return "cpp";
- case Protocol::JavaScript: return "javascript";
- case Protocol::Diff: return "diff";
- case Protocol::Xml: return "xml";
- }
- return QByteArray(); // Crutch for compiler.
- };
- data += "&lang=" + langValue(ct);
- Q_UNUSED(comment)
-
- QNetworkReply * const reply = httpPost(apiUrl() + "/create", data);
- connect(reply, &QNetworkReply::finished, this, [this, reply] {
- QString data;
- if (reply->error()) {
- reportError(reply->errorString()); // FIXME: Why can't we properly emit an error here?
- } else {
- data = QString::fromUtf8(reply->readAll());
- if (!data.startsWith(baseUrl())) {
- reportError(data);
- data.clear();
- }
- }
- reply->deleteLater();
- emit pasteDone(data);
- });
-}
-
-void PasteCodeDotXyzProtocol::list()
-{
- QNetworkReply * const reply = httpGet(apiUrl() + "/recent");
- connect(reply, &QNetworkReply::finished, this, [this, reply] {
- QStringList ids;
- if (reply->error()) {
- reportError(reply->errorString());
- } else {
- QJsonParseError parseError;
- const QJsonDocument jsonData = QJsonDocument::fromJson(reply->readAll(), &parseError);
- if (parseError.error != QJsonParseError::NoError) {
- reportError(parseError.errorString());
- } else {
- const QJsonArray jsonList = jsonData.array();
- for (auto it = jsonList.constBegin(); it != jsonList.constEnd(); ++it) {
- const QString id = it->toObject().value("pid").toString();
- if (!id.isEmpty())
- ids << id;
- }
- }
- }
- emit listDone(name(), ids);
- reply->deleteLater();
- });
-}
-
-bool PasteCodeDotXyzProtocol::checkConfiguration(QString *errorMessage)
-{
- if (!m_hostKnownOk)
- m_hostKnownOk = httpStatus(apiUrl(), errorMessage);
- return m_hostKnownOk;
-}
-
-void PasteCodeDotXyzProtocol::reportError(const QString &message)
-{
- const QString fullMessage = tr("%1: %2").arg(protocolName(), message);
- Core::MessageManager::write(fullMessage, Core::MessageManager::ModeSwitch);
-}
-
-} // namespace CodePaster
diff --git a/src/plugins/cpaster/pasteview.cpp b/src/plugins/cpaster/pasteview.cpp
index 17ad2abcfc..d5775adb5e 100644
--- a/src/plugins/cpaster/pasteview.cpp
+++ b/src/plugins/cpaster/pasteview.cpp
@@ -139,8 +139,14 @@ int PasteView::showDialog()
}
// Show up with checkable list of diff chunks.
-int PasteView::show(const QString &user, const QString &description,
- const QString &comment, int expiryDays, const FileDataList &parts)
+int PasteView::show(
+ const QString &user,
+ const QString &description,
+ const QString &comment,
+ int expiryDays,
+ bool makePublic,
+ const FileDataList &parts
+ )
{
setupDialog(user, description, comment);
m_ui.uiPatchList->clear();
@@ -156,18 +162,20 @@ int PasteView::show(const QString &user, const QString &description,
m_ui.stackedWidget->setCurrentIndex(0);
m_ui.uiPatchView->setPlainText(content);
setExpiryDays(expiryDays);
+ setMakePublic(makePublic);
return showDialog();
}
// Show up with editable plain text.
int PasteView::show(const QString &user, const QString &description,
- const QString &comment, int expiryDays, const QString &content)
+ const QString &comment, int expiryDays, bool makePublic, const QString &content)
{
setupDialog(user, description, comment);
m_mode = PlainTextMode;
m_ui.stackedWidget->setCurrentIndex(1);
m_ui.plainTextEdit->setPlainText(content);
setExpiryDays(expiryDays);
+ setMakePublic(makePublic);
return showDialog();
}
@@ -176,11 +184,21 @@ void PasteView::setExpiryDays(int d)
m_ui.expirySpinBox->setValue(d);
}
+void PasteView::setMakePublic(bool p)
+{
+ m_ui.makePublicCheckBox->setChecked(p);
+}
+
int PasteView::expiryDays() const
{
return m_ui.expirySpinBox->value();
}
+bool PasteView::makePublic() const
+{
+ return m_ui.makePublicCheckBox->isChecked();
+}
+
void PasteView::accept()
{
const int index = m_ui.protocolBox->currentIndex();
@@ -197,7 +215,7 @@ void PasteView::accept()
return;
const Protocol::ContentType ct = Protocol::contentType(m_mimeType);
- protocol->paste(data, ct, expiryDays(), user(), comment(), description());
+ protocol->paste(data, ct, expiryDays(), makePublic(), user(), comment(), description());
// Store settings and close
QSettings *settings = Core::ICore::settings();
settings->beginGroup(QLatin1String(groupC));
diff --git a/src/plugins/cpaster/pasteview.h b/src/plugins/cpaster/pasteview.h
index cdaf8db592..6a2b78c64e 100644
--- a/src/plugins/cpaster/pasteview.h
+++ b/src/plugins/cpaster/pasteview.h
@@ -52,10 +52,10 @@ public:
// Show up with checkable list of diff chunks.
int show(const QString &user, const QString &description, const QString &comment,
- int expiryDays, const FileDataList &parts);
+ int expiryDays, bool makePublic, const FileDataList &parts);
// Show up with editable plain text.
int show(const QString &user, const QString &description, const QString &comment,
- int expiryDays, const QString &content);
+ int expiryDays, bool makePublic, const QString &content);
void setProtocol(const QString &protocol);
@@ -65,7 +65,9 @@ public:
QString content() const;
QString protocol() const;
void setExpiryDays(int d);
+ void setMakePublic(bool p);
int expiryDays() const;
+ bool makePublic() const;
void accept() override;
diff --git a/src/plugins/cpaster/pasteview.ui b/src/plugins/cpaster/pasteview.ui
index 2575317920..c4719dded1 100644
--- a/src/plugins/cpaster/pasteview.ui
+++ b/src/plugins/cpaster/pasteview.ui
@@ -26,7 +26,7 @@
<item row="0" column="1">
<widget class="QComboBox" name="protocolBox"/>
</item>
- <item row="2" column="0">
+ <item row="3" column="0">
<widget class="QLabel" name="userLabel">
<property name="text">
<string>&amp;Username:</string>
@@ -36,14 +36,14 @@
</property>
</widget>
</item>
- <item row="2" column="1">
+ <item row="3" column="1">
<widget class="QLineEdit" name="uiUsername">
<property name="placeholderText">
<string>&lt;Username&gt;</string>
</property>
</widget>
</item>
- <item row="3" column="0">
+ <item row="4" column="0">
<widget class="QLabel" name="descriptionLabel">
<property name="text">
<string>&amp;Description:</string>
@@ -53,14 +53,14 @@
</property>
</widget>
</item>
- <item row="3" column="1">
+ <item row="4" column="1">
<widget class="QLineEdit" name="uiDescription">
<property name="placeholderText">
<string>&lt;Description&gt;</string>
</property>
</widget>
</item>
- <item row="1" column="1">
+ <item row="2" column="1">
<widget class="QSpinBox" name="expirySpinBox">
<property name="suffix">
<string> Days</string>
@@ -73,7 +73,7 @@
</property>
</widget>
</item>
- <item row="1" column="0">
+ <item row="2" column="0">
<widget class="QLabel" name="expiryLabel">
<property name="text">
<string>&amp;Expires after:</string>
@@ -83,6 +83,16 @@
</property>
</widget>
</item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="makePublicLabel">
+ <property name="text">
+ <string>Make public:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QCheckBox" name="makePublicCheckBox"/>
+ </item>
</layout>
</item>
<item>
diff --git a/src/plugins/cpaster/protocol.h b/src/plugins/cpaster/protocol.h
index c315a673d1..d9b66d7cc4 100644
--- a/src/plugins/cpaster/protocol.h
+++ b/src/plugins/cpaster/protocol.h
@@ -68,6 +68,7 @@ public:
virtual void paste(const QString &text,
ContentType ct = Text,
int expiryDays = 1,
+ bool publicPaste = false,
const QString &username = QString(),
const QString &comment = QString(),
const QString &description = QString()) = 0;
diff --git a/src/plugins/cpaster/settings.cpp b/src/plugins/cpaster/settings.cpp
index b29a1fa673..61508a201d 100644
--- a/src/plugins/cpaster/settings.cpp
+++ b/src/plugins/cpaster/settings.cpp
@@ -36,14 +36,15 @@ static const char expiryDaysKeyC[] = "ExpiryDays";
static const char defaultProtocolKeyC[] = "DefaultProtocol";
static const char copyToClipboardKeyC[] = "CopyToClipboard";
static const char displayOutputKeyC[] = "DisplayOutput";
+static const char publicPasteKeyC[] = "DisplayOutput";
namespace CodePaster {
bool Settings::equals(const Settings &rhs) const
{
return copyToClipboard == rhs.copyToClipboard && displayOutput == rhs.displayOutput
- && expiryDays == rhs.expiryDays && username == rhs.username
- && protocol == rhs.protocol;
+ && expiryDays == rhs.expiryDays && username == rhs.username
+ && protocol == rhs.protocol && publicPaste == rhs.publicPaste;
}
void Settings::toSettings(QSettings *settings) const
@@ -54,6 +55,7 @@ void Settings::toSettings(QSettings *settings) const
settings->setValue(QLatin1String(expiryDaysKeyC), expiryDays);
settings->setValue(QLatin1String(copyToClipboardKeyC), copyToClipboard);
settings->setValue(QLatin1String(displayOutputKeyC), displayOutput);
+ settings->setValue(publicPasteKeyC, publicPaste);
settings->endGroup();
}
@@ -66,6 +68,7 @@ void Settings::fromSettings(const QSettings *settings)
protocol = settings->value(rootKey + QLatin1String(defaultProtocolKeyC), PasteBinDotComProtocol::protocolName()).toString();
copyToClipboard = settings->value(rootKey + QLatin1String(copyToClipboardKeyC), true).toBool();
displayOutput = settings->value(rootKey + QLatin1String(displayOutputKeyC), true).toBool();
+ publicPaste = settings->value(rootKey + publicPasteKeyC, false).toBool();
}
} // namespace CodePaster
diff --git a/src/plugins/cpaster/settings.h b/src/plugins/cpaster/settings.h
index d47c2f7ce3..451f85e0f3 100644
--- a/src/plugins/cpaster/settings.h
+++ b/src/plugins/cpaster/settings.h
@@ -44,6 +44,7 @@ public:
int expiryDays = 1;
bool copyToClipboard = true;
bool displayOutput = true;
+ bool publicPaste = false;
};
inline bool operator==(const Settings &s1, const Settings &s2) { return s1.equals(s2); }
diff --git a/src/plugins/cpaster/settingspage.cpp b/src/plugins/cpaster/settingspage.cpp
index b9b70a9e73..c21b0fe485 100644
--- a/src/plugins/cpaster/settingspage.cpp
+++ b/src/plugins/cpaster/settingspage.cpp
@@ -56,6 +56,7 @@ SettingsWidget::SettingsWidget(const QStringList &protocols, Settings *settings)
const int index = m_ui.defaultProtocol->findText(m_settings->protocol);
m_ui.defaultProtocol->setCurrentIndex(index == -1 ? 0 : index);
m_ui.expirySpinBox->setValue(m_settings->expiryDays);
+ m_ui.publicCheckBox->setChecked(m_settings->publicPaste);
m_ui.clipboardBox->setChecked(m_settings->copyToClipboard);
m_ui.displayBox->setChecked(m_settings->displayOutput);
}
@@ -66,6 +67,7 @@ void SettingsWidget::apply()
rc.username = m_ui.userEdit->text();
rc.protocol = m_ui.defaultProtocol->currentText();
rc.expiryDays = m_ui.expirySpinBox->value();
+ rc.publicPaste = m_ui.publicCheckBox->isChecked();
rc.copyToClipboard = m_ui.clipboardBox->isChecked();
rc.displayOutput = m_ui.displayBox->isChecked();
diff --git a/src/plugins/cpaster/settingspage.ui b/src/plugins/cpaster/settingspage.ui
index 906f8de474..de4020433d 100644
--- a/src/plugins/cpaster/settingspage.ui
+++ b/src/plugins/cpaster/settingspage.ui
@@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
- <width>291</width>
+ <width>370</width>
<height>229</height>
</rect>
</property>
@@ -81,6 +81,13 @@
</property>
</widget>
</item>
+ <item row="6" column="0">
+ <widget class="QCheckBox" name="publicCheckBox">
+ <property name="text">
+ <string>Make pasted content public by default</string>
+ </property>
+ </widget>
+ </item>
</layout>
</widget>
<tabstops>
diff --git a/src/plugins/cpaster/stickynotespasteprotocol.cpp b/src/plugins/cpaster/stickynotespasteprotocol.cpp
index 9c8ad232eb..c4924a70c8 100644
--- a/src/plugins/cpaster/stickynotespasteprotocol.cpp
+++ b/src/plugins/cpaster/stickynotespasteprotocol.cpp
@@ -97,16 +97,21 @@ static inline QByteArray pasteLanguage(Protocol::ContentType ct)
return QByteArray("language=text");
}
-void StickyNotesPasteProtocol::paste(const QString &text,
- ContentType ct, int expiryDays,
- const QString &username,
- const QString &comment,
- const QString &description)
+void StickyNotesPasteProtocol::paste(
+ const QString &text,
+ ContentType ct,
+ int expiryDays,
+ bool publicPaste,
+ const QString &username,
+ const QString &comment,
+ const QString &description
+ )
{
enum { maxDescriptionLength = 30 }; // Length of description is limited.
Q_UNUSED(username)
Q_UNUSED(comment)
+ Q_UNUSED(publicPaste)
QTC_ASSERT(!m_pasteReply, return);
// Format body
diff --git a/src/plugins/cpaster/stickynotespasteprotocol.h b/src/plugins/cpaster/stickynotespasteprotocol.h
index 584c90a921..8c0b35e08c 100644
--- a/src/plugins/cpaster/stickynotespasteprotocol.h
+++ b/src/plugins/cpaster/stickynotespasteprotocol.h
@@ -39,6 +39,7 @@ public:
void paste(const QString &text,
ContentType ct = Text,
int expiryDays = 1,
+ bool publicPaste = false,
const QString &username = QString(),
const QString &comment = QString(),
const QString &description = QString()) override;
diff --git a/src/plugins/cpaster/urlopenprotocol.cpp b/src/plugins/cpaster/urlopenprotocol.cpp
index 64f416b19e..01e1cd58d8 100644
--- a/src/plugins/cpaster/urlopenprotocol.cpp
+++ b/src/plugins/cpaster/urlopenprotocol.cpp
@@ -63,7 +63,7 @@ void UrlOpenProtocol::fetchFinished()
emit fetchDone(title, content, error);
}
-void UrlOpenProtocol::paste(const QString &, ContentType, int, const QString &,
- const QString &, const QString &)
+void UrlOpenProtocol::paste(const QString &, ContentType, int, bool,
+ const QString &, const QString &, const QString &)
{
}
diff --git a/src/plugins/cpaster/urlopenprotocol.h b/src/plugins/cpaster/urlopenprotocol.h
index 65f1fcb504..161d2a16b2 100644
--- a/src/plugins/cpaster/urlopenprotocol.h
+++ b/src/plugins/cpaster/urlopenprotocol.h
@@ -36,7 +36,7 @@ public:
QString name() const override;
unsigned capabilities() const override;
void fetch(const QString &url) override;
- void paste(const QString &, ContentType, int, const QString &, const QString &, const QString &) override;
+ void paste(const QString &, ContentType, int, bool, const QString &, const QString &, const QString &) override;
private:
void fetchFinished();
diff --git a/src/plugins/cppcheck/cppcheckoptions.cpp b/src/plugins/cppcheck/cppcheckoptions.cpp
index a3070560bd..bb963c06e7 100644
--- a/src/plugins/cppcheck/cppcheckoptions.cpp
+++ b/src/plugins/cppcheck/cppcheckoptions.cpp
@@ -121,7 +121,7 @@ void OptionsWidget::load(const CppcheckOptions &options)
void OptionsWidget::save(CppcheckOptions &options) const
{
- options.binary = m_binary->path();
+ options.binary = m_binary->filePath().toString();
options.customArguments = m_customArguments->text();
options.ignoredPatterns = m_ignorePatterns->text();
options.warning = m_warning->isChecked();
diff --git a/src/plugins/cppcheck/cppcheckplugin.cpp b/src/plugins/cppcheck/cppcheckplugin.cpp
index 0bcbc952da..4bbab6a4de 100644
--- a/src/plugins/cppcheck/cppcheckplugin.cpp
+++ b/src/plugins/cppcheck/cppcheckplugin.cpp
@@ -147,7 +147,7 @@ void CppcheckPluginPrivate::updateManualRunAction()
const Target *target = SessionManager::startupTarget();
const Core::Id cxx = ProjectExplorer::Constants::CXX_LANGUAGE_ID;
const bool canRun = target && project->projectLanguages().contains(cxx)
- && ToolChainKitAspect::toolChain(target->kit(), cxx);
+ && ToolChainKitAspect::cxxToolChain(target->kit());
manualRunAction->setEnabled(canRun);
}
diff --git a/src/plugins/cppeditor/CMakeLists.txt b/src/plugins/cppeditor/CMakeLists.txt
index d2072fa5ba..d2a55ca8cf 100644
--- a/src/plugins/cppeditor/CMakeLists.txt
+++ b/src/plugins/cppeditor/CMakeLists.txt
@@ -43,5 +43,4 @@ extend_qtc_plugin(CppEditor
followsymbol_switchmethoddecldef_test.cpp
EXPLICIT_MOC
cppdoxygen_test.h
- cppquickfix_test.h
)
diff --git a/src/plugins/cppeditor/cppeditorconstants.h b/src/plugins/cppeditor/cppeditorconstants.h
index a6f3f9609f..d1fb5f1706 100644
--- a/src/plugins/cppeditor/cppeditorconstants.h
+++ b/src/plugins/cppeditor/cppeditorconstants.h
@@ -34,7 +34,6 @@ const char CPPEDITOR_ID[] = "CppEditor.C++Editor";
const char CPPEDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("OpenWith::Editors", "C++ Editor");
const char SWITCH_DECLARATION_DEFINITION[] = "CppEditor.SwitchDeclarationDefinition";
const char OPEN_DECLARATION_DEFINITION_IN_NEXT_SPLIT[] = "CppEditor.OpenDeclarationDefinitionInNextSplit";
-const char RENAME_SYMBOL_UNDER_CURSOR[] = "CppEditor.RenameSymbolUnderCursor";
const char OPEN_PREPROCESSOR_DIALOG[] = "CppEditor.OpenPreprocessorDialog";
const char ERRORS_IN_HEADER_FILES[] = "CppEditor.ErrorsInHeaderFiles";
const char MULTIPLE_PARSE_CONTEXTS_AVAILABLE[] = "CppEditor.MultipleParseContextsAvailable";
diff --git a/src/plugins/cppeditor/cppeditorplugin.cpp b/src/plugins/cppeditor/cppeditorplugin.cpp
index 1376843080..8eae62faa4 100644
--- a/src/plugins/cppeditor/cppeditorplugin.cpp
+++ b/src/plugins/cppeditor/cppeditorplugin.cpp
@@ -103,9 +103,10 @@ public:
setParenthesesMatchingEnabled(true);
setEditorActionHandlers(TextEditorActionHandler::Format
- | TextEditorActionHandler::UnCommentSelection
- | TextEditorActionHandler::UnCollapseAll
- | TextEditorActionHandler::FollowSymbolUnderCursor);
+ | TextEditorActionHandler::UnCommentSelection
+ | TextEditorActionHandler::UnCollapseAll
+ | TextEditorActionHandler::FollowSymbolUnderCursor
+ | TextEditorActionHandler::RenameSymbol);
}
};
@@ -118,7 +119,6 @@ public:
void onAllTasksFinished(Core::Id type);
void inspectCppCodeModel();
- QAction *m_renameSymbolUnderCursorAction = nullptr;
QAction *m_reparseExternallyChangedFiles = nullptr;
QAction *m_openTypeHierarchyAction = nullptr;
QAction *m_openIncludeHierarchyAction = nullptr;
@@ -245,16 +245,7 @@ bool CppEditorPlugin::initialize(const QStringList & /*arguments*/, QString *err
Command *sep = contextMenu->addSeparator();
sep->action()->setObjectName(QLatin1String(Constants::M_REFACTORING_MENU_INSERTION_POINT));
contextMenu->addSeparator();
-
- d->m_renameSymbolUnderCursorAction = new QAction(tr("Rename Symbol Under Cursor"),
- this);
- cmd = ActionManager::registerAction(d->m_renameSymbolUnderCursorAction,
- Constants::RENAME_SYMBOL_UNDER_CURSOR,
- context);
- cmd->setDefaultKeySequence(QKeySequence(tr("CTRL+SHIFT+R")));
- connect(d->m_renameSymbolUnderCursorAction, &QAction::triggered,
- this, &CppEditorPlugin::renameSymbolUnderCursor);
- cppToolsMenu->addAction(cmd);
+ cppToolsMenu->addAction(ActionManager::command(TextEditor::Constants::RENAME_SYMBOL));
// Update context in global context
cppToolsMenu->addSeparator(Core::Constants::G_DEFAULT_THREE);
@@ -342,8 +333,8 @@ void CppEditorPlugin::showPreProcessorDialog()
void CppEditorPluginPrivate::onTaskStarted(Id type)
{
if (type == CppTools::Constants::TASK_INDEX) {
- m_renameSymbolUnderCursorAction->setEnabled(false);
ActionManager::command(TextEditor::Constants::FIND_USAGES)->action()->setEnabled(false);
+ ActionManager::command(TextEditor::Constants::RENAME_SYMBOL)->action()->setEnabled(false);
m_reparseExternallyChangedFiles->setEnabled(false);
m_openTypeHierarchyAction->setEnabled(false);
m_openIncludeHierarchyAction->setEnabled(false);
@@ -353,8 +344,8 @@ void CppEditorPluginPrivate::onTaskStarted(Id type)
void CppEditorPluginPrivate::onAllTasksFinished(Id type)
{
if (type == CppTools::Constants::TASK_INDEX) {
- m_renameSymbolUnderCursorAction->setEnabled(true);
ActionManager::command(TextEditor::Constants::FIND_USAGES)->action()->setEnabled(true);
+ ActionManager::command(TextEditor::Constants::RENAME_SYMBOL)->action()->setEnabled(true);
m_reparseExternallyChangedFiles->setEnabled(true);
m_openTypeHierarchyAction->setEnabled(true);
m_openIncludeHierarchyAction->setEnabled(true);
diff --git a/src/plugins/cppeditor/cppeditorwidget.cpp b/src/plugins/cppeditor/cppeditorwidget.cpp
index 2ce2c1092b..f13d6d5a02 100644
--- a/src/plugins/cppeditor/cppeditorwidget.cpp
+++ b/src/plugins/cppeditor/cppeditorwidget.cpp
@@ -860,7 +860,7 @@ protected:
QMenu *CppEditorWidget::createRefactorMenu(QWidget *parent) const
{
auto *menu = new QMenu(tr("&Refactor"), parent);
- menu->addAction(ActionManager::command(Constants::RENAME_SYMBOL_UNDER_CURSOR)->action());
+ menu->addAction(ActionManager::command(TextEditor::Constants::RENAME_SYMBOL)->action());
// ### enable
// updateSemanticInfo(m_semanticHighlighter->semanticInfo(currentSource()));
diff --git a/src/plugins/cppeditor/cppeditorwidget.h b/src/plugins/cppeditor/cppeditorwidget.h
index 57fd9d0fd6..7bd9f4b4d3 100644
--- a/src/plugins/cppeditor/cppeditorwidget.h
+++ b/src/plugins/cppeditor/cppeditorwidget.h
@@ -81,7 +81,7 @@ public:
void findUsages(QTextCursor cursor);
void renameUsages(const QString &replacement = QString(),
QTextCursor cursor = QTextCursor());
- void renameSymbolUnderCursor();
+ void renameSymbolUnderCursor() override;
bool selectBlockUp() override;
bool selectBlockDown() override;
diff --git a/src/plugins/cpptools/baseeditordocumentprocessor.h b/src/plugins/cpptools/baseeditordocumentprocessor.h
index cf08f7b5c4..88a91158d5 100644
--- a/src/plugins/cpptools/baseeditordocumentprocessor.h
+++ b/src/plugins/cpptools/baseeditordocumentprocessor.h
@@ -41,6 +41,8 @@
#include <QTextEdit>
+#include <QVariant>
+
#include <functional>
namespace TextEditor {
@@ -57,6 +59,7 @@ struct CPPTOOLS_EXPORT ToolTipInfo {
QStringList qDocIdCandidates;
QString qDocMark;
Core::HelpItem::Category qDocCategory;
+ QVariant value;
QString sizeInBytes;
};
diff --git a/src/plugins/cpptools/cppclassesfilter.h b/src/plugins/cpptools/cppclassesfilter.h
index 1b68ac7e4b..638d9a1867 100644
--- a/src/plugins/cpptools/cppclassesfilter.h
+++ b/src/plugins/cpptools/cppclassesfilter.h
@@ -32,8 +32,7 @@
namespace CppTools {
class CppLocatorData;
-// TODO: un-export this
-class CPPTOOLS_EXPORT CppClassesFilter : public Internal::CppLocatorFilter
+class CppClassesFilter : public Internal::CppLocatorFilter
{
Q_OBJECT
diff --git a/src/plugins/cpptools/cppcodeformatter.cpp b/src/plugins/cpptools/cppcodeformatter.cpp
index 170bf4c61c..4d4cf6e795 100644
--- a/src/plugins/cpptools/cppcodeformatter.cpp
+++ b/src/plugins/cpptools/cppcodeformatter.cpp
@@ -783,7 +783,7 @@ bool CodeFormatter::tryExpression(bool alsoExpression)
newState = stream_op;
for (int i = m_currentState.size() - 1; i >= 0; --i) {
const int type = m_currentState.at(i).type;
- if (type == arglist_open) { // likely a left-shift instead
+ if (type == arglist_open || type == braceinit_open) { // likely a left-shift instead
newState = -1;
break;
}
@@ -1521,6 +1521,7 @@ void QtStyleCodeFormatter::adjustIndent(const Tokens &tokens, int lexerState, in
&& topState.type != block_open
&& topState.type != substatement_open
&& topState.type != brace_list_open
+ && topState.type != arglist_open
&& !topWasMaybeElse) {
*indentDepth = topState.savedIndentDepth;
*paddingDepth = 0;
diff --git a/src/plugins/cpptools/cppfilesettingspage.cpp b/src/plugins/cpptools/cppfilesettingspage.cpp
index a4763c3333..68f9242ceb 100644
--- a/src/plugins/cpptools/cppfilesettingspage.cpp
+++ b/src/plugins/cpptools/cppfilesettingspage.cpp
@@ -297,7 +297,7 @@ CppFileSettingsWidget::CppFileSettingsWidget(CppFileSettings *settings)
QString CppFileSettingsWidget::licenseTemplatePath() const
{
- return m_ui.licenseTemplatePathChooser->path();
+ return m_ui.licenseTemplatePathChooser->filePath().toString();
}
void CppFileSettingsWidget::setLicenseTemplatePath(const QString &lp)
diff --git a/src/plugins/cpptools/cppfindreferences.cpp b/src/plugins/cpptools/cppfindreferences.cpp
index 9e1dbd697d..131d0fca94 100644
--- a/src/plugins/cpptools/cppfindreferences.cpp
+++ b/src/plugins/cpptools/cppfindreferences.cpp
@@ -338,6 +338,9 @@ void CppFindReferences::findUsages(CPlusPlus::Symbol *symbol,
SearchResultWindow::PreserveCaseDisabled,
QLatin1String("CppEditor"));
search->setTextToReplace(replacement);
+ auto renameFilesCheckBox = new QCheckBox();
+ renameFilesCheckBox->setVisible(false);
+ search->setAdditionalReplaceWidget(renameFilesCheckBox);
connect(search, &SearchResult::replaceButtonClicked,
this, &CppFindReferences::onReplaceButtonClicked);
search->setSearchAgainSupported(true);
@@ -721,6 +724,9 @@ void CppFindReferences::findMacroUses(const CPlusPlus::Macro &macro, const QStri
QLatin1String("CppEditor"));
search->setTextToReplace(replacement);
+ auto renameFilesCheckBox = new QCheckBox();
+ renameFilesCheckBox->setVisible(false);
+ search->setAdditionalReplaceWidget(renameFilesCheckBox);
connect(search, &SearchResult::replaceButtonClicked,
this, &CppFindReferences::onReplaceButtonClicked);
diff --git a/src/plugins/cpptools/cpptoolsjsextension.cpp b/src/plugins/cpptools/cpptoolsjsextension.cpp
index 4c283fc644..03a0d3df99 100644
--- a/src/plugins/cpptools/cpptoolsjsextension.cpp
+++ b/src/plugins/cpptools/cpptoolsjsextension.cpp
@@ -29,10 +29,15 @@
#include <coreplugin/icore.h>
+#include <projectexplorer/project.h>
+#include <projectexplorer/projectnodes.h>
+#include <projectexplorer/session.h>
+
#include <utils/codegeneration.h>
#include <utils/fileutils.h>
#include <QFileInfo>
+#include <QStringList>
#include <QTextStream>
namespace CppTools {
@@ -113,5 +118,69 @@ QString CppToolsJsExtension::closeNamespaces(const QString &klass) const
return result;
}
+QString CppToolsJsExtension::includeStatement(
+ const QString &fullyQualifiedClassName,
+ const QString &suffix,
+ const QString &specialClasses,
+ const QString &pathOfIncludingFile
+ )
+{
+ if (fullyQualifiedClassName.isEmpty())
+ return {};
+ const QString className = parts(fullyQualifiedClassName).last();
+ if (className.isEmpty() || specialClasses.contains(className))
+ return {};
+ if (className.startsWith('Q') && className.length() > 2 && className.at(1).isUpper())
+ return "#include <" + className + ">\n";
+ const auto withUnderScores = [&className] {
+ QString baseName = className;
+ baseName[0] = baseName[0].toLower();
+ for (int i = 1; i < baseName.length(); ++i) {
+ if (baseName[i].isUpper()) {
+ baseName.insert(i, '_');
+ baseName[i + 1] = baseName[i + 1].toLower();
+ ++i;
+ }
+ }
+ return baseName;
+ };
+ QStringList candidates{className + '.' + suffix};
+ bool hasUpperCase = false;
+ bool hasLowerCase = false;
+ for (int i = 0; i < className.length() && (!hasUpperCase || !hasLowerCase); ++i) {
+ if (className.at(i).isUpper())
+ hasUpperCase = true;
+ if (className.at(i).isLower())
+ hasLowerCase = true;
+ }
+ if (hasUpperCase)
+ candidates << className.toLower() + '.' + suffix;
+ if (hasUpperCase && hasLowerCase)
+ candidates << withUnderScores() + '.' + suffix;
+ candidates.removeDuplicates();
+ using namespace ProjectExplorer;
+ const auto nodeMatchesFileName = [&candidates](Node *n) {
+ if (const FileNode * const fileNode = n->asFileNode()) {
+ if (fileNode->fileType() == FileType::Header
+ && candidates.contains(fileNode->filePath().fileName())) {
+ return true;
+ }
+ }
+ return false;
+ };
+ for (const Project * const p : SessionManager::projects()) {
+ const Node *theNode = p->rootProjectNode()->findNode(nodeMatchesFileName);
+ if (theNode) {
+ const bool sameDir = pathOfIncludingFile == theNode->filePath().toFileInfo().path();
+ return QString("#include ")
+ .append(sameDir ? '"' : '<')
+ .append(theNode->filePath().fileName())
+ .append(sameDir ? '"' : '>')
+ .append('\n');
+ }
+ }
+ return {};
+}
+
} // namespace Internal
} // namespace CppTools
diff --git a/src/plugins/cpptools/cpptoolsjsextension.h b/src/plugins/cpptools/cpptoolsjsextension.h
index b528191033..065e0ca8d5 100644
--- a/src/plugins/cpptools/cpptoolsjsextension.h
+++ b/src/plugins/cpptools/cpptoolsjsextension.h
@@ -55,6 +55,14 @@ public:
Q_INVOKABLE QString classToHeaderGuard(const QString &klass, const QString &extension) const;
Q_INVOKABLE QString openNamespaces(const QString &klass) const;
Q_INVOKABLE QString closeNamespaces(const QString &klass) const;
+
+ // Find header file for class.
+ Q_INVOKABLE QString includeStatement(
+ const QString &fullyQualifiedClassName,
+ const QString &suffix,
+ const QString &specialClasses,
+ const QString &pathOfIncludingFile
+ );
};
} // namespace Internal
diff --git a/src/plugins/debugger/breakhandler.cpp b/src/plugins/debugger/breakhandler.cpp
index 75782ae6d5..13db44f7ca 100644
--- a/src/plugins/debugger/breakhandler.cpp
+++ b/src/plugins/debugger/breakhandler.cpp
@@ -665,7 +665,7 @@ void BreakpointDialog::getParts(unsigned partsMask, BreakpointParameters *data)
if (partsMask & FileAndLinePart) {
data->lineNumber = m_lineEditLineNumber->text().toInt();
data->pathUsage = static_cast<BreakpointPathUsage>(m_comboBoxPathUsage->currentIndex());
- data->fileName = FilePath::fromUserInput(m_pathChooserFileName->path());
+ data->fileName = m_pathChooserFileName->filePath();
}
if (partsMask & FunctionPart)
data->functionName = m_lineEditFunction->text();
@@ -702,7 +702,7 @@ void BreakpointDialog::setParts(unsigned mask, const BreakpointParameters &data)
m_lineEditMessage->setText(data.message);
if (mask & FileAndLinePart) {
- m_pathChooserFileName->setFileName(data.fileName);
+ m_pathChooserFileName->setFilePath(data.fileName);
m_lineEditLineNumber->setText(QString::number(data.lineNumber));
}
@@ -1174,19 +1174,19 @@ void BreakHandler::removeAlienBreakpoint(const QString &rid)
void BreakHandler::requestBreakpointInsertion(const Breakpoint &bp)
{
bp->gotoState(BreakpointInsertionRequested, BreakpointNew);
- QTimer::singleShot(0, m_engine, [this, bp] { m_engine->insertBreakpoint(bp); });
+ m_engine->insertBreakpoint(bp);
}
void BreakHandler::requestBreakpointUpdate(const Breakpoint &bp)
{
bp->gotoState(BreakpointUpdateRequested, BreakpointInserted);
- QTimer::singleShot(0, m_engine, [this, bp] { m_engine->updateBreakpoint(bp); });
+ m_engine->updateBreakpoint(bp);
}
void BreakHandler::requestBreakpointRemoval(const Breakpoint &bp)
{
bp->gotoState(BreakpointRemoveRequested, BreakpointInserted);
- QTimer::singleShot(0, m_engine, [this, bp] { m_engine->removeBreakpoint(bp); });
+ m_engine->removeBreakpoint(bp);
}
void BreakHandler::requestBreakpointEnabling(const Breakpoint &bp, bool enabled)
@@ -1330,7 +1330,12 @@ void DebuggerEngine::notifyBreakpointInsertOk(const Breakpoint &bp)
void DebuggerEngine::notifyBreakpointInsertFailed(const Breakpoint &bp)
{
QTC_ASSERT(bp, return);
+ GlobalBreakpoint gbp = bp->globalBreakpoint();
bp->gotoState(BreakpointDead, BreakpointInsertionProceeding);
+ breakHandler()->removeDisassemblerMarker(bp);
+ breakHandler()->destroyItem(bp);
+ QTC_ASSERT(gbp, return);
+ gbp->updateMarker();
}
void DebuggerEngine::notifyBreakpointRemoveProceeding(const Breakpoint &bp)
@@ -1509,7 +1514,7 @@ bool BreakHandler::setData(const QModelIndex &idx, const QVariant &value, int ro
return contextMenuEvent(ev);
if (auto kev = ev.as<QKeyEvent>(QEvent::KeyPress)) {
- if (kev->key() == Qt::Key_Delete) {
+ if (kev->key() == Qt::Key_Delete || kev->key() == Qt::Key_Backspace) {
QModelIndexList si = ev.currentOrSelectedRows();
const Breakpoints bps = findBreakpointsByIndex(si);
for (Breakpoint bp : bps) {
@@ -2490,7 +2495,7 @@ GlobalBreakpoint BreakpointManager::findBreakpointFromContext(const ContextData
matchLevel = 2;
bestMatch = gbp;
} else if (matchLevel < 2) {
- for (const QPointer<DebuggerEngine> engine : EngineManager::engines()) {
+ for (const QPointer<DebuggerEngine> &engine : EngineManager::engines()) {
BreakHandler *handler = engine->breakHandler();
for (Breakpoint bp : handler->breakpoints()) {
if (bp->globalBreakpoint() == gbp) {
@@ -2547,7 +2552,7 @@ bool BreakpointManager::setData(const QModelIndex &idx, const QVariant &value, i
return contextMenuEvent(ev);
if (auto kev = ev.as<QKeyEvent>(QEvent::KeyPress)) {
- if (kev->key() == Qt::Key_Delete) {
+ if (kev->key() == Qt::Key_Delete || kev->key() == Qt::Key_Backspace) {
QModelIndexList si = ev.currentOrSelectedRows();
const GlobalBreakpoints gbps = findBreakpointsByIndex(si);
for (GlobalBreakpoint gbp : gbps)
diff --git a/src/plugins/debugger/breakhandler.h b/src/plugins/debugger/breakhandler.h
index 55a4bfd9bd..f0ee77b872 100644
--- a/src/plugins/debugger/breakhandler.h
+++ b/src/plugins/debugger/breakhandler.h
@@ -93,6 +93,7 @@ private:
friend class BreakHandler;
friend class BreakpointManager;
friend class BreakpointMarker;
+ friend class DebuggerEngine;
void updateMarker();
void updateMarkerIcon();
diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp
index a98ee3e9a7..056991b06b 100644
--- a/src/plugins/debugger/cdb/cdbengine.cpp
+++ b/src/plugins/debugger/cdb/cdbengine.cpp
@@ -966,6 +966,13 @@ void CdbEngine::executeDebuggerCommand(const QString &command)
// Post command to the cdb process
void CdbEngine::runCommand(const DebuggerCommand &dbgCmd)
{
+ constexpr int maxCommandLength = 4096;
+ constexpr int maxTokenLength = 4 /*" -t "*/
+ + 5 /* 99999 tokens should be enough for a single qc run time*/
+ + 1 /* token part splitter '.' */
+ + 3 /* 1000 parts should also be more than enough */
+ + 1 /* final space */;
+
QString cmd = dbgCmd.function + dbgCmd.argsToString();
if (!m_accessible) {
doInterruptInferior([this, dbgCmd](){
@@ -977,11 +984,26 @@ void CdbEngine::runCommand(const DebuggerCommand &dbgCmd)
return;
}
+ if (dbgCmd.flags == ScriptCommand) {
+ // repack script command into an extension command
+ DebuggerCommand newCmd("script", ExtensionCommand, dbgCmd.callback);
+ if (!dbgCmd.args.isNull())
+ newCmd.args = QString{dbgCmd.function + '(' + dbgCmd.argsToPython() + ')'};
+ else
+ newCmd.args = dbgCmd.function;
+ runCommand(newCmd);
+ return;
+ }
+
QString fullCmd;
if (dbgCmd.flags == NoFlags) {
- fullCmd = cmd;
+ fullCmd = cmd + '\n';
+ if (fullCmd.length() > maxCommandLength) {
+ showMessage("Command is longer than 4096 characters execution will likely fail.",
+ LogWarning);
+ }
} else {
- const int token = m_nextCommandToken++;
+ const int token = ++m_nextCommandToken;
StringInputStream str(fullCmd);
if (dbgCmd.flags == BuiltinCommand) {
// Post a built-in-command producing free-format output with a callback.
@@ -989,23 +1011,35 @@ void CdbEngine::runCommand(const DebuggerCommand &dbgCmd)
// printing a specially formatted token to be identifiable in the output.
str << ".echo \"" << m_tokenPrefix << token << "<\"\n"
<< cmd << "\n"
- << ".echo \"" << m_tokenPrefix << token << ">\"";
+ << ".echo \"" << m_tokenPrefix << token << ">\"" << '\n';
+ if (fullCmd.length() > maxCommandLength) {
+ showMessage("Command is longer than 4096 characters execution will likely fail.",
+ LogWarning);
+ }
} else if (dbgCmd.flags == ExtensionCommand) {
+
// Post an extension command producing one-line output with a callback,
// pass along token for identification in hash.
- str << m_extensionCommandPrefix << dbgCmd.function << "%1%2";
- if (dbgCmd.args.isString())
- str << ' ' << dbgCmd.argsToString();
- cmd = fullCmd.arg("", "");
- fullCmd = fullCmd.arg(" -t ").arg(token);
- } else if (dbgCmd.flags == ScriptCommand) {
- // Add extension prefix and quotes the script command
- // pass along token for identification in hash.
- str << m_extensionCommandPrefix + "script %1%2 " << dbgCmd.function;
- if (!dbgCmd.args.isNull())
- str << '(' << dbgCmd.argsToPython() << ')';
- cmd = fullCmd.arg("", "");
- fullCmd = fullCmd.arg(" -t ").arg(token);
+ const QString prefix = m_extensionCommandPrefix + dbgCmd.function;
+ QList<QStringRef> splittedArguments;
+ if (dbgCmd.args.isString()) {
+ const QString &arguments = dbgCmd.argsToString();
+ cmd = prefix + arguments;
+ int argumentSplitPos = 0;
+ QList<QStringRef> splittedArguments;
+ int maxArgumentSize = maxCommandLength - prefix.length() - maxTokenLength;
+ while (argumentSplitPos < arguments.size()) {
+ splittedArguments << arguments.midRef(argumentSplitPos, maxArgumentSize);
+ argumentSplitPos += splittedArguments.last().length();
+ }
+ QTC_CHECK(argumentSplitPos == arguments.size());
+ int tokenPart = splittedArguments.size();
+ for (const QStringRef &part : qAsConst(splittedArguments))
+ str << prefix << " -t " << token << '.' << --tokenPart << ' ' << part << '\n';
+ } else {
+ cmd = prefix;
+ str << prefix << " -t " << token << '.' << 0 << '\n';
+ }
}
m_commandForToken.insert(token, dbgCmd);
}
@@ -1018,7 +1052,7 @@ void CdbEngine::runCommand(const DebuggerCommand &dbgCmd)
qDebug("CdbEngine::postCommand: resulting command '%s'\n", qPrintable(fullCmd));
}
showMessage(cmd, LogInput);
- m_process.write(fullCmd.toLocal8Bit() + '\n');
+ m_process.write(fullCmd.toLocal8Bit());
}
void CdbEngine::activateFrame(int index)
diff --git a/src/plugins/debugger/cdb/stringinputstream.h b/src/plugins/debugger/cdb/stringinputstream.h
index 61c78c7a0a..21f4ccd14e 100644
--- a/src/plugins/debugger/cdb/stringinputstream.h
+++ b/src/plugins/debugger/cdb/stringinputstream.h
@@ -42,6 +42,7 @@ public:
StringInputStream &operator<<(char a) { m_target.append(a); return *this; }
StringInputStream &operator<<(const char *a) { m_target.append(QString::fromUtf8(a)); return *this; }
StringInputStream &operator<<(const QString &a) { m_target.append(a); return *this; }
+ StringInputStream &operator<<(const QStringRef &a) { m_target.append(a); return *this; }
StringInputStream &operator<<(int i) { appendInt(i); return *this; }
StringInputStream &operator<<(unsigned i) { appendInt(i); return *this; }
diff --git a/src/plugins/debugger/commonoptionspage.cpp b/src/plugins/debugger/commonoptionspage.cpp
index 2f21805d27..24138b192c 100644
--- a/src/plugins/debugger/commonoptionspage.cpp
+++ b/src/plugins/debugger/commonoptionspage.cpp
@@ -296,7 +296,7 @@ public:
label->setText("<html><head/><body>\n<p>"
+ tr("The debugging helpers are used to produce a nice "
"display of objects of certain types like QString or "
- "std::map in the &quot;Locals and Expressions&quot; view.")
+ "std::map in the &quot;Locals&quot; and &quot;Expressions&quot; views.")
+ "</p></body></html>");
auto groupBoxCustomDumperCommands = new QGroupBox(debuggingHelperGroupBox);
diff --git a/src/plugins/debugger/debuggeractions.cpp b/src/plugins/debugger/debuggeractions.cpp
index f47dc28937..9df57cb430 100644
--- a/src/plugins/debugger/debuggeractions.cpp
+++ b/src/plugins/debugger/debuggeractions.cpp
@@ -169,7 +169,7 @@ DebuggerSettings::DebuggerSettings()
item->setCheckable(true);
item->setDefaultValue(true);
item->setSettingsKey(debugModeGroup, "AutoDerefPointers");
- item->setToolTip(tr("<p>This switches the Locals and Expressions view to "
+ item->setToolTip(tr("<p>This switches the Locals and Expressions views to "
"automatically dereference pointers. This saves a level in the "
"tree view, but also loses data for the now-missing intermediate "
"level."));
@@ -587,7 +587,7 @@ DebuggerSettings::DebuggerSettings()
item = new SavedAction;
item->setSettingsKey(debugModeGroup, "DisplayStringLimit");
item->setToolTip(tr("<p>The maximum length of string entries in the "
- "Locals and Expressions pane. Longer than that are cut off "
+ "Locals and Expressions views. Longer than that are cut off "
"and displayed with an ellipsis attached."));
item->setDefaultValue(100);
insertItem(DisplayStringLimit, item);
diff --git a/src/plugins/debugger/debuggerdialogs.cpp b/src/plugins/debugger/debuggerdialogs.cpp
index 226026f99c..afaaf6af56 100644
--- a/src/plugins/debugger/debuggerdialogs.cpp
+++ b/src/plugins/debugger/debuggerdialogs.cpp
@@ -479,14 +479,14 @@ StartApplicationParameters StartApplicationDialog::parameters() const
StartApplicationParameters result;
result.serverPort = d->serverPortSpinBox->value();
result.serverAddress = d->channelOverrideEdit->text();
- result.runnable.executable = d->localExecutablePathChooser->fileName();
- result.serverStartScript = d->serverStartScriptPathChooser->fileName();
+ result.runnable.executable = d->localExecutablePathChooser->filePath();
+ result.serverStartScript = d->serverStartScriptPathChooser->filePath();
result.serverInitCommands = d->serverInitCommandsTextEdit->toPlainText();
result.serverResetCommands = d->serverResetCommandsTextEdit->toPlainText();
result.kitId = d->kitChooser->currentKitId();
- result.debugInfoLocation = d->debuginfoPathChooser->path();
+ result.debugInfoLocation = d->debuginfoPathChooser->filePath().toString();
result.runnable.commandLineArguments = d->arguments->text();
- result.runnable.workingDirectory = d->workingDirectory->path();
+ result.runnable.workingDirectory = d->workingDirectory->filePath().toString();
result.breakAtMain = d->breakAtMainCheckBox->isChecked();
result.runInTerminal = d->runInTerminalCheckBox->isChecked();
return result;
@@ -497,8 +497,8 @@ void StartApplicationDialog::setParameters(const StartApplicationParameters &p)
d->kitChooser->setCurrentKitId(p.kitId);
d->serverPortSpinBox->setValue(p.serverPort);
d->channelOverrideEdit->setText(p.serverAddress);
- d->localExecutablePathChooser->setFileName(p.runnable.executable);
- d->serverStartScriptPathChooser->setFileName(p.serverStartScript);
+ d->localExecutablePathChooser->setFilePath(p.runnable.executable);
+ d->serverStartScriptPathChooser->setFilePath(p.serverStartScript);
d->serverInitCommandsTextEdit->setPlainText(p.serverInitCommands);
d->serverResetCommandsTextEdit->setPlainText(p.serverResetCommands);
d->debuginfoPathChooser->setPath(p.debugInfoLocation);
diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp
index ff3bc70788..bda6442e6b 100644
--- a/src/plugins/debugger/debuggerengine.cpp
+++ b/src/plugins/debugger/debuggerengine.cpp
@@ -1760,11 +1760,11 @@ void DebuggerEngine::showMessage(const QString &msg, int channel, int timeout) c
case AppOutput:
case AppStuff:
d->m_logWindow->showOutput(channel, msg);
- emit appendMessageRequested(msg, StdOutFormatSameLine, false);
+ emit appendMessageRequested(msg, StdOutFormat, false);
break;
case AppError:
d->m_logWindow->showOutput(channel, msg);
- emit appendMessageRequested(msg, StdErrFormatSameLine, false);
+ emit appendMessageRequested(msg, StdErrFormat, false);
break;
default:
d->m_logWindow->showOutput(channel, msg);
diff --git a/src/plugins/debugger/debuggeritem.cpp b/src/plugins/debugger/debuggeritem.cpp
index bb31684a54..a0775c2da6 100644
--- a/src/plugins/debugger/debuggeritem.cpp
+++ b/src/plugins/debugger/debuggeritem.cpp
@@ -107,8 +107,8 @@ DebuggerItem::DebuggerItem(const QVariant &id)
DebuggerItem::DebuggerItem(const QVariantMap &data)
{
m_id = data.value(DEBUGGER_INFORMATION_ID).toString();
- m_command = FilePath::fromUserInput(data.value(DEBUGGER_INFORMATION_COMMAND).toString());
- m_workingDirectory = FilePath::fromUserInput(data.value(DEBUGGER_INFORMATION_WORKINGDIRECTORY).toString());
+ m_command = FilePath::fromVariant(data.value(DEBUGGER_INFORMATION_COMMAND));
+ m_workingDirectory = FilePath::fromVariant(data.value(DEBUGGER_INFORMATION_WORKINGDIRECTORY));
m_unexpandedDisplayName = data.value(DEBUGGER_INFORMATION_DISPLAYNAME).toString();
m_isAutoDetected = data.value(DEBUGGER_INFORMATION_AUTODETECTED, false).toBool();
m_version = data.value(DEBUGGER_INFORMATION_VERSION).toString();
@@ -309,8 +309,8 @@ QVariantMap DebuggerItem::toMap() const
QVariantMap data;
data.insert(DEBUGGER_INFORMATION_DISPLAYNAME, m_unexpandedDisplayName);
data.insert(DEBUGGER_INFORMATION_ID, m_id);
- data.insert(DEBUGGER_INFORMATION_COMMAND, m_command.toString());
- data.insert(DEBUGGER_INFORMATION_WORKINGDIRECTORY, m_workingDirectory.toString());
+ data.insert(DEBUGGER_INFORMATION_COMMAND, m_command.toVariant());
+ data.insert(DEBUGGER_INFORMATION_WORKINGDIRECTORY, m_workingDirectory.toVariant());
data.insert(DEBUGGER_INFORMATION_ENGINETYPE, int(m_engineType));
data.insert(DEBUGGER_INFORMATION_AUTODETECTED, m_isAutoDetected);
data.insert(DEBUGGER_INFORMATION_VERSION, m_version);
diff --git a/src/plugins/debugger/debuggeritemmanager.cpp b/src/plugins/debugger/debuggeritemmanager.cpp
index 34ea3b46cd..4be3de93a9 100644
--- a/src/plugins/debugger/debuggeritemmanager.cpp
+++ b/src/plugins/debugger/debuggeritemmanager.cpp
@@ -348,8 +348,8 @@ DebuggerItem DebuggerItemConfigWidget::item() const
{
DebuggerItem item(m_id);
item.setUnexpandedDisplayName(m_displayNameLineEdit->text());
- item.setCommand(m_binaryChooser->fileName());
- item.setWorkingDirectory(m_workingDirectoryChooser->fileName());
+ item.setCommand(m_binaryChooser->filePath());
+ item.setWorkingDirectory(m_workingDirectoryChooser->filePath());
item.setAutoDetected(m_autodetected);
Abis abiList;
const QStringList abis = m_abis->text().split(QRegExp("[^A-Za-z0-9-_]+"));
@@ -390,10 +390,10 @@ void DebuggerItemConfigWidget::load(const DebuggerItem *item)
m_typeLineEdit->setText(item->engineTypeName());
m_binaryChooser->setReadOnly(item->isAutoDetected());
- m_binaryChooser->setFileName(item->command());
+ m_binaryChooser->setFilePath(item->command());
m_workingDirectoryChooser->setReadOnly(item->isAutoDetected());
- m_workingDirectoryChooser->setFileName(item->workingDirectory());
+ m_workingDirectoryChooser->setFilePath(item->workingDirectory());
QString text;
QString versionCommand;
@@ -427,7 +427,7 @@ void DebuggerItemConfigWidget::binaryPathHasChanged()
return;
DebuggerItem tmp;
- QFileInfo fi = QFileInfo(m_binaryChooser->path());
+ QFileInfo fi = QFileInfo(m_binaryChooser->filePath().toString());
if (fi.isExecutable()) {
tmp = item();
tmp.reinitializeFromFile();
diff --git a/src/plugins/debugger/debuggermainwindow.cpp b/src/plugins/debugger/debuggermainwindow.cpp
index 1c404a22b2..53e37ecc1a 100644
--- a/src/plugins/debugger/debuggermainwindow.cpp
+++ b/src/plugins/debugger/debuggermainwindow.cpp
@@ -250,8 +250,8 @@ DebuggerMainWindowPrivate::DebuggerMainWindowPrivate(DebuggerMainWindow *parent)
m_toolBarDock = dock;
q->addDockWidget(Qt::BottomDockWidgetArea, m_toolBarDock);
- connect(viewButton, &QAbstractButton::clicked, this, [this, viewButton] {
- ActionContainer *viewsMenu = ActionManager::actionContainer(Core::Constants::M_WINDOW_VIEWS);
+ connect(viewButton, &QAbstractButton::clicked, this, [viewButton] {
+ ActionContainer *viewsMenu = ActionManager::actionContainer(Core::Constants::M_VIEW_VIEWS);
viewsMenu->menu()->exec(viewButton->mapToGlobal(QPoint()));
});
@@ -277,7 +277,7 @@ DebuggerMainWindow::DebuggerMainWindow()
Context debugcontext(Debugger::Constants::C_DEBUGMODE);
- ActionContainer *viewsMenu = ActionManager::actionContainer(Core::Constants::M_WINDOW_VIEWS);
+ ActionContainer *viewsMenu = ActionManager::actionContainer(Core::Constants::M_VIEW_VIEWS);
Command *cmd = ActionManager::registerAction(showCentralWidgetAction(),
"Debugger.Views.ShowCentralWidget", debugcontext);
cmd->setAttribute(Command::CA_Hide);
@@ -315,7 +315,7 @@ DebuggerMainWindow::~DebuggerMainWindow()
void DebuggerMainWindow::contextMenuEvent(QContextMenuEvent *ev)
{
- ActionContainer *viewsMenu = ActionManager::actionContainer(Core::Constants::M_WINDOW_VIEWS);
+ ActionContainer *viewsMenu = ActionManager::actionContainer(Core::Constants::M_VIEW_VIEWS);
viewsMenu->menu()->exec(ev->globalPos());
}
@@ -896,7 +896,7 @@ void Perspective::addWindow(QWidget *widget,
Command *cmd = ActionManager::registerAction(op.toggleViewAction, op.commandId, d->context());
cmd->setAttribute(Command::CA_Hide);
- ActionManager::actionContainer(Core::Constants::M_WINDOW_VIEWS)->addAction(cmd);
+ ActionManager::actionContainer(Core::Constants::M_VIEW_VIEWS)->addAction(cmd);
}
d->m_dockOperations.append(op);
diff --git a/src/plugins/debugger/debuggerrunconfigurationaspect.cpp b/src/plugins/debugger/debuggerrunconfigurationaspect.cpp
index 91c32a15c1..076fd9723d 100644
--- a/src/plugins/debugger/debuggerrunconfigurationaspect.cpp
+++ b/src/plugins/debugger/debuggerrunconfigurationaspect.cpp
@@ -27,17 +27,18 @@
#include "debuggerconstants.h"
+#include <coreplugin/helpmanager.h>
#include <coreplugin/icontext.h>
#include <coreplugin/icore.h>
-#include <coreplugin/helpmanager.h>
+#include <projectexplorer/buildconfiguration.h>
+#include <projectexplorer/buildstep.h>
+#include <projectexplorer/buildsteplist.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/project.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/runconfiguration.h>
#include <projectexplorer/target.h>
-#include <projectexplorer/buildconfiguration.h>
-#include <projectexplorer/buildstep.h>
-#include <projectexplorer/buildsteplist.h>
+#include <qtsupport/qtbuildaspects.h>
#include <QCheckBox>
#include <QDebug>
@@ -243,12 +244,9 @@ bool DebuggerRunConfigurationAspect::useQmlDebugger() const
//
// Try to find a build configuration to check whether qml debugging is enabled there
- // (Using the Qt metatype system to avoid a hard build system dependency)
- //
if (BuildConfiguration *bc = m_target->activeBuildConfiguration()) {
- const QVariant linkProperty = bc->property("linkQmlDebuggingLibrary");
- if (linkProperty.isValid() && linkProperty.canConvert(QVariant::Bool))
- return linkProperty.toBool();
+ const auto aspect = bc->aspect<QtSupport::QmlDebuggingAspect>();
+ return aspect && aspect->setting() == TriState::Enabled;
}
return !languages.contains(ProjectExplorer::Constants::CXX_LANGUAGE_ID);
diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp
index 463342357b..ee7c5dab36 100644
--- a/src/plugins/debugger/debuggerruncontrol.cpp
+++ b/src/plugins/debugger/debuggerruncontrol.cpp
@@ -128,14 +128,14 @@ public:
{
const QByteArray ba = m_proc.readAllStandardOutput();
const QString msg = QString::fromLocal8Bit(ba, ba.length());
- m_runTool->appendMessage(msg, StdOutFormatSameLine);
+ m_runTool->appendMessage(msg, StdOutFormat);
}
void handleStandardError()
{
const QByteArray ba = m_proc.readAllStandardError();
const QString msg = QString::fromLocal8Bit(ba, ba.length());
- m_runTool->appendMessage(msg, StdErrFormatSameLine);
+ m_runTool->appendMessage(msg, StdErrFormat);
}
void handleFinished()
@@ -508,6 +508,11 @@ void DebuggerRunTool::addQmlServerInferiorCommandLineArgumentIfNeeded()
d->addQmlServerInferiorCommandLineArgumentIfNeeded = true;
}
+void DebuggerRunTool::modifyDebuggerEnvironment(const EnvironmentItems &items)
+{
+ m_runParameters.debugger.environment.modify(items);
+}
+
void DebuggerRunTool::setCrashParameter(const QString &event)
{
m_runParameters.crashParameter = event;
@@ -689,10 +694,10 @@ void DebuggerRunTool::start()
if (m_runParameters.startMode == StartInternal) {
QStringList unhandledIds;
- for (const GlobalBreakpoint bp : BreakpointManager::globalBreakpoints()) {
+// for (const GlobalBreakpoint &bp : BreakpointManager::globalBreakpoints()) {
// if (bp->isEnabled() && !m_engine->acceptsBreakpoint(bp))
// unhandledIds.append(bp.id().toString());
- }
+// }
if (!unhandledIds.isEmpty()) {
QString warningMessage =
DebuggerPlugin::tr("Some breakpoints cannot be handled by the debugger "
@@ -895,6 +900,11 @@ Internal::TerminalRunner *DebuggerRunTool::terminalRunner() const
return d->terminalRunner;
}
+DebuggerEngineType DebuggerRunTool::cppEngineType() const
+{
+ return m_runParameters.cppEngineType;
+}
+
DebuggerRunTool::DebuggerRunTool(RunControl *runControl, AllowTerminal allowTerminal)
: RunWorker(runControl), d(new DebuggerRunToolPrivate)
{
@@ -972,7 +982,7 @@ DebuggerRunTool::DebuggerRunTool(RunControl *runControl, AllowTerminal allowTerm
const Tasks tasks = DebuggerKitAspect::validateDebugger(kit);
for (const Task &t : tasks) {
if (t.type != Task::Warning)
- m_runParameters.validationErrors.append(t.description);
+ m_runParameters.validationErrors.append(t.description());
}
RunConfiguration *runConfig = runControl->runConfiguration();
@@ -1030,10 +1040,10 @@ void DebuggerRunTool::showMessage(const QString &msg, int channel, int timeout)
m_engine->showMessage(msg, channel, timeout);
switch (channel) {
case AppOutput:
- appendMessage(msg, StdOutFormatSameLine);
+ appendMessage(msg, StdOutFormat);
break;
case AppError:
- appendMessage(msg, StdErrFormatSameLine);
+ appendMessage(msg, StdErrFormat);
break;
case AppStuff:
appendMessage(msg, DebugFormat);
diff --git a/src/plugins/debugger/debuggerruncontrol.h b/src/plugins/debugger/debuggerruncontrol.h
index adc9de8fef..a971c25807 100644
--- a/src/plugins/debugger/debuggerruncontrol.h
+++ b/src/plugins/debugger/debuggerruncontrol.h
@@ -33,6 +33,8 @@
#include <projectexplorer/runconfiguration.h>
#include <projectexplorer/devicesupport/deviceusedportsgatherer.h>
+#include <utils/environmentfwd.h>
+
namespace Debugger {
namespace Internal {
@@ -78,7 +80,7 @@ public:
void setRunControlName(const QString &name);
void setStartMessage(const QString &msg);
void addQmlServerInferiorCommandLineArgumentIfNeeded();
-
+ void modifyDebuggerEnvironment(const Utils::EnvironmentItems &item);
void setCrashParameter(const QString &event);
void addExpectedSignal(const QString &signal);
@@ -127,6 +129,7 @@ public:
void setAbi(const ProjectExplorer::Abi &abi);
Internal::TerminalRunner *terminalRunner() const;
+ DebuggerEngineType cppEngineType() const;
private:
bool fixupParameters();
diff --git a/src/plugins/debugger/debuggertooltipmanager.cpp b/src/plugins/debugger/debuggertooltipmanager.cpp
index 49aa316571..58ec3663ab 100644
--- a/src/plugins/debugger/debuggertooltipmanager.cpp
+++ b/src/plugins/debugger/debuggertooltipmanager.cpp
@@ -586,7 +586,8 @@ DebuggerToolTipWidget::DebuggerToolTipWidget()
<< item->name << '\t' << item->value << '\t' << item->type << '\n';
});
QClipboard *clipboard = QApplication::clipboard();
- clipboard->setText(text, QClipboard::Selection);
+ if (clipboard->supportsSelection())
+ clipboard->setText(text, QClipboard::Selection);
clipboard->setText(text, QClipboard::Clipboard);
});
diff --git a/src/plugins/debugger/disassembleragent.cpp b/src/plugins/debugger/disassembleragent.cpp
index 97e08b47fe..baa5e7c84d 100644
--- a/src/plugins/debugger/disassembleragent.cpp
+++ b/src/plugins/debugger/disassembleragent.cpp
@@ -337,7 +337,7 @@ void DisassemblerAgent::setContentsToDocument(const DisassemblerLines &contents)
.arg(d->location.functionName()));
const Breakpoints bps = d->engine->breakHandler()->breakpoints();
- for (const Breakpoint bp : bps)
+ for (const Breakpoint &bp : bps)
updateBreakpointMarker(bp);
updateLocationMarker();
diff --git a/src/plugins/debugger/enginemanager.cpp b/src/plugins/debugger/enginemanager.cpp
index 8c2bbca146..1770758b11 100644
--- a/src/plugins/debugger/enginemanager.cpp
+++ b/src/plugins/debugger/enginemanager.cpp
@@ -310,7 +310,7 @@ bool EngineItem::setData(int row, const QVariant &value, int role)
}
if (auto kev = ev.as<QKeyEvent>(QEvent::KeyPress)) {
- if (kev->key() == Qt::Key_Delete && m_engine) {
+ if ((kev->key() == Qt::Key_Delete || kev->key() == Qt::Key_Backspace) && m_engine) {
m_engine->quitDebugger();
} else if (kev->key() == Qt::Key_Return || kev->key() == Qt::Key_Enter) {
d->activateEngineByIndex(row);
diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp
index 0fadcc150a..c1cb8c7bad 100644
--- a/src/plugins/debugger/gdb/gdbengine.cpp
+++ b/src/plugins/debugger/gdb/gdbengine.cpp
@@ -3637,7 +3637,6 @@ void GdbEngine::setupEngine()
//runCommand("define hookpost-stop\nprint 5\nend");
//runCommand("define hook-call\nprint 6\nend");
//runCommand("define hookpost-call\nprint 7\nend");
- runCommand({"set print object on"});
//runCommand("set step-mode on"); // we can't work with that yes
//runCommand("set exec-done-display on");
//runCommand("set print pretty on");
diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp
index 61d9012ccb..03c6bdf7fa 100644
--- a/src/plugins/debugger/lldb/lldbengine.cpp
+++ b/src/plugins/debugger/lldb/lldbengine.cpp
@@ -314,6 +314,11 @@ void LldbEngine::setupEngine()
const bool success = response.data["success"].toInt();
if (success) {
BreakpointManager::claimBreakpointsForEngine(this);
+ // Some extra roundtrip to make sure we end up behind all commands triggered
+ // from claimBreakpointsForEngine().
+ DebuggerCommand cmd3("executeRoundtrip");
+ cmd3.callback = [this](const DebuggerResponse &) { notifyEngineSetupOk(); };
+ runCommand(cmd3);
} else {
notifyEngineSetupFailed();
}
@@ -402,6 +407,8 @@ void LldbEngine::handleResponse(const QString &response)
notifyInferiorPid(item.toProcessHandle());
else if (name == "breakpointmodified")
handleInterpreterBreakpointModified(item);
+ else if (name == "bridgemessage")
+ showMessage(item["msg"].data(), item["channel"].toInt());
}
}
@@ -673,7 +680,7 @@ void LldbEngine::requestModuleSymbols(const QString &moduleName)
{
DebuggerCommand cmd("fetchSymbols");
cmd.arg("module", moduleName);
- cmd.callback = [this, moduleName](const DebuggerResponse &response) {
+ cmd.callback = [moduleName](const DebuggerResponse &response) {
const GdbMi &symbols = response.data["symbols"];
QString moduleName = response.data["module"].data();
Symbols syms;
@@ -903,8 +910,6 @@ void LldbEngine::handleStateNotification(const GdbMi &item)
notifyInferiorStopFailed();
else if (newState == "inferiorill")
notifyInferiorIll();
- else if (newState == "enginesetupok")
- notifyEngineSetupOk();
else if (newState == "enginesetupfailed") {
Core::AsynchronousMessageBox::critical(adapterStartFailed(),
item["error"].data());
diff --git a/src/plugins/debugger/loadcoredialog.cpp b/src/plugins/debugger/loadcoredialog.cpp
index d4af42714d..550fdc2d20 100644
--- a/src/plugins/debugger/loadcoredialog.cpp
+++ b/src/plugins/debugger/loadcoredialog.cpp
@@ -370,9 +370,9 @@ void AttachCoreDialog::coreFileChanged(const QString &core)
Runnable debugger = DebuggerKitAspect::runnable(k);
CoreInfo cinfo = CoreInfo::readExecutableNameFromCore(debugger, core);
if (!cinfo.foundExecutableName.isEmpty())
- d->symbolFileName->setFileName(FilePath::fromString(cinfo.foundExecutableName));
+ d->symbolFileName->setFilePath(FilePath::fromString(cinfo.foundExecutableName));
else if (!d->symbolFileName->isValid() && !cinfo.rawStringFromCore.isEmpty())
- d->symbolFileName->setFileName(FilePath::fromString(cinfo.rawStringFromCore));
+ d->symbolFileName->setFilePath(FilePath::fromString(cinfo.rawStringFromCore));
}
changed();
}
@@ -412,12 +412,12 @@ void AttachCoreDialog::selectRemoteCoreFile()
QString AttachCoreDialog::localCoreFile() const
{
- return d->localCoreFileName->path();
+ return d->localCoreFileName->filePath().toString();
}
FilePath AttachCoreDialog::symbolFile() const
{
- return d->symbolFileName->fileName();
+ return d->symbolFileName->filePath();
}
void AttachCoreDialog::setSymbolFile(const QString &symbolFileName)
@@ -462,7 +462,7 @@ Kit *AttachCoreDialog::kit() const
QString AttachCoreDialog::overrideStartScript() const
{
- return d->overrideStartScriptFileName->path();
+ return d->overrideStartScriptFileName->filePath().toString();
}
void AttachCoreDialog::setOverrideStartScript(const QString &scriptName)
diff --git a/src/plugins/debugger/shared/cdbsymbolpathlisteditor.cpp b/src/plugins/debugger/shared/cdbsymbolpathlisteditor.cpp
index 0bd667f457..ae5e38366c 100644
--- a/src/plugins/debugger/shared/cdbsymbolpathlisteditor.cpp
+++ b/src/plugins/debugger/shared/cdbsymbolpathlisteditor.cpp
@@ -75,7 +75,7 @@ void CacheDirectoryDialog::setPath(const QString &p)
QString CacheDirectoryDialog::path() const
{
- return m_chooser->path();
+ return m_chooser->filePath().toString();
}
void CacheDirectoryDialog::accept()
diff --git a/src/plugins/debugger/shared/symbolpathsdialog.cpp b/src/plugins/debugger/shared/symbolpathsdialog.cpp
index eb396c2c9b..db0354cca4 100644
--- a/src/plugins/debugger/shared/symbolpathsdialog.cpp
+++ b/src/plugins/debugger/shared/symbolpathsdialog.cpp
@@ -56,7 +56,7 @@ bool SymbolPathsDialog::useSymbolServer() const
QString SymbolPathsDialog::path() const
{
- return ui->pathChooser->path();
+ return ui->pathChooser->filePath().toString();
}
void SymbolPathsDialog::setUseSymbolCache(bool useSymbolCache)
diff --git a/src/plugins/debugger/stackhandler.cpp b/src/plugins/debugger/stackhandler.cpp
index 51d27228d1..d1af61e2c7 100644
--- a/src/plugins/debugger/stackhandler.cpp
+++ b/src/plugins/debugger/stackhandler.cpp
@@ -479,7 +479,8 @@ void StackHandler::copyContentsToClipboard()
});
QClipboard *clipboard = QApplication::clipboard();
- clipboard->setText(str, QClipboard::Selection);
+ if (clipboard->supportsSelection())
+ clipboard->setText(str, QClipboard::Selection);
clipboard->setText(str, QClipboard::Clipboard);
}
diff --git a/src/plugins/debugger/unstartedappwatcherdialog.cpp b/src/plugins/debugger/unstartedappwatcherdialog.cpp
index c27ff5f72e..2ef8c67588 100644
--- a/src/plugins/debugger/unstartedappwatcherdialog.cpp
+++ b/src/plugins/debugger/unstartedappwatcherdialog.cpp
@@ -121,7 +121,7 @@ UnstartedAppWatcherDialog::UnstartedAppWatcherDialog(QWidget *parent)
if (isLocal(runConfig)) {
resetExecutable->setEnabled(true);
connect(resetExecutable, &QPushButton::clicked, this, [this, runnable] {
- m_pathChooser->setFileName(runnable.executable);
+ m_pathChooser->setFilePath(runnable.executable);
});
}
}
@@ -256,7 +256,7 @@ void UnstartedAppWatcherDialog::startStopTimer(bool start)
void UnstartedAppWatcherDialog::findProcess()
{
- const QString &appName = Utils::FileUtils::normalizePathName(m_pathChooser->path());
+ const QString &appName = Utils::FileUtils::normalizePathName(m_pathChooser->filePath().toString());
DeviceProcessItem fallback;
foreach (const DeviceProcessItem &p, DeviceProcessList::localProcesses()) {
if (Utils::FileUtils::normalizePathName(p.exe) == appName) {
@@ -291,8 +291,8 @@ void UnstartedAppWatcherDialog::kitChanged()
bool UnstartedAppWatcherDialog::checkExecutableString() const
{
- if (!m_pathChooser->path().isEmpty()) {
- QFileInfo fileInfo(m_pathChooser->path());
+ if (!m_pathChooser->filePath().toString().isEmpty()) {
+ QFileInfo fileInfo(m_pathChooser->filePath().toString());
return (fileInfo.exists() && fileInfo.isFile());
}
return false;
diff --git a/src/plugins/debugger/uvsc/uvscclient.cpp b/src/plugins/debugger/uvsc/uvscclient.cpp
index 33889646ed..3b4aa43765 100644
--- a/src/plugins/debugger/uvsc/uvscclient.cpp
+++ b/src/plugins/debugger/uvsc/uvscclient.cpp
@@ -43,7 +43,7 @@ constexpr int kMaximumRegisterGroupsCount = 128;
constexpr int kMaximumRegisterEnumsCount = 512;
constexpr int kMaximumVarinfosCount = 256;
constexpr int kMaximumValueBitsSize = 32;
-constexpr int kMaximumBreakpointResponseSize = 1024;
+constexpr int kMaximumBreakpointEnumsCount = 128;
constexpr int kMaximumDisassembledBytesCount = 1024;
const QEvent::Type kUvscMsgEventType = static_cast<QEvent::Type>(QEvent::User + 1);
@@ -691,6 +691,41 @@ bool UvscClient::inspectWatcher(const QStringList &expandedWatcherINames,
return true;
}
+bool UvscClient::fetchMemory(quint64 address, QByteArray &data)
+{
+ if (data.isEmpty())
+ data.resize(sizeof(quint8));
+
+ QByteArray amem = UvscUtils::encodeAmem(address, data);
+ const auto amemPtr = reinterpret_cast<AMEM *>(amem.data());
+ const UVSC_STATUS st = ::UVSC_DBG_MEM_READ(m_descriptor, amemPtr, amem.size());
+ if (st != UVSC_STATUS_SUCCESS) {
+ setError(RuntimeError);
+ return false;
+ }
+
+ data = QByteArray(reinterpret_cast<char *>(&amemPtr->bytes),
+ amemPtr->bytesCount);
+ return true;
+}
+
+bool UvscClient::changeMemory(quint64 address, const QByteArray &data)
+{
+ if (data.isEmpty()) {
+ setError(RuntimeError);
+ return false;
+ }
+
+ QByteArray amem = UvscUtils::encodeAmem(address, data);
+ const auto amemPtr = reinterpret_cast<AMEM *>(amem.data());
+ const UVSC_STATUS st = ::UVSC_DBG_MEM_WRITE(m_descriptor, amemPtr, amem.size());
+ if (st != UVSC_STATUS_SUCCESS) {
+ setError(RuntimeError);
+ return false;
+ }
+ return true;
+}
+
bool UvscClient::disassemblyAddress(quint64 address, QByteArray &result)
{
if (!checkConnection())
@@ -764,22 +799,32 @@ bool UvscClient::createBreakpoint(const QString &exp, quint32 &tickMark, quint64
if (!checkConnection())
return false;
- QByteArray bkparm = UvscUtils::encodeBreakPoint(BRKTYPE_EXEC, exp);
- QByteArray bkrsp(kMaximumBreakpointResponseSize, 0);
- qint32 bkrspLength = bkrsp.size();
- const UVSC_STATUS st = ::UVSC_DBG_CREATE_BP(m_descriptor,
- reinterpret_cast<BKPARM *>(bkparm.data()),
- bkparm.size(),
- reinterpret_cast<BKRSP *>(bkrsp.data()),
- &bkrspLength);
- if (st != UVSC_STATUS_SUCCESS) {
- setError(RuntimeError);
+ // Magic workaround to prevent the stalling.
+ if (!controlHiddenBreakpoint(exp))
+ return false;
+
+ // Execute command to create the BP.
+ const QString setCmd = QStringLiteral("BS %1").arg(exp);
+ QString setCmdOutput;
+ if (!executeCommand(setCmd, setCmdOutput))
+ return false;
+
+ std::vector<BKRSP> bpenums;
+ if (!enumerateBreakpoints(bpenums))
+ return false;
+
+ const auto bpenumBegin = bpenums.cbegin();
+ const auto bpenumEnd = bpenums.cend();
+ const auto bpenumIt = std::find_if(bpenumBegin, bpenumEnd, [exp](const BKRSP &bpenum) {
+ const QString bpexp = QString::fromLatin1(reinterpret_cast<const char *>(bpenum.expressionBuffer),
+ bpenum.expressionLength).trimmed();
+ return bpexp.contains(exp);
+ });
+ if (bpenumIt == bpenumEnd)
return false;
- }
- const auto bkrspPtr = reinterpret_cast<const BKRSP *>(bkrsp.constData());
- tickMark = bkrspPtr->tickMark;
- address = bkrspPtr->address;
+ tickMark = bpenumIt->tickMark;
+ address = bpenumIt->address;
if (!addressToFileLine(address, fileName, function, line))
return false;
@@ -794,11 +839,9 @@ bool UvscClient::deleteBreakpoint(quint32 tickMark)
BKCHG bkchg = {};
bkchg.type = CHG_KILLBP;
bkchg.tickMark = tickMark;
- QByteArray bkrsp(kMaximumBreakpointResponseSize, 0);
- qint32 bkrspLength = bkrsp.size();
- const UVSC_STATUS st = ::UVSC_DBG_CHANGE_BP(m_descriptor, &bkchg, sizeof(bkchg),
- reinterpret_cast<BKRSP *>(bkrsp.data()),
- &bkrspLength);
+ BKRSP bkrsp = {};
+ qint32 bkrspLength = sizeof(bkrsp);
+ const UVSC_STATUS st = ::UVSC_DBG_CHANGE_BP(m_descriptor, &bkchg, sizeof(bkchg), &bkrsp, &bkrspLength);
if (st != UVSC_STATUS_SUCCESS) {
setError(RuntimeError);
return false;
@@ -814,11 +857,9 @@ bool UvscClient::enableBreakpoint(quint32 tickMark)
BKCHG bkchg = {};
bkchg.type = CHG_ENABLEBP;
bkchg.tickMark = tickMark;
- QByteArray bkrsp(kMaximumBreakpointResponseSize, 0);
- qint32 bkrspLength = bkrsp.size();
- const UVSC_STATUS st = ::UVSC_DBG_CHANGE_BP(m_descriptor, &bkchg, sizeof(bkchg),
- reinterpret_cast<BKRSP *>(bkrsp.data()),
- &bkrspLength);
+ BKRSP bkrsp = {};
+ qint32 bkrspLength = sizeof(bkrsp);
+ const UVSC_STATUS st = ::UVSC_DBG_CHANGE_BP(m_descriptor, &bkchg, sizeof(bkchg), &bkrsp, &bkrspLength);
if (st != UVSC_STATUS_SUCCESS) {
setError(RuntimeError);
return false;
@@ -834,11 +875,9 @@ bool UvscClient::disableBreakpoint(quint32 tickMark)
BKCHG bkchg = {};
bkchg.type = CHG_DISABLEBP;
bkchg.tickMark = tickMark;
- QByteArray bkrsp(kMaximumBreakpointResponseSize, 0);
- qint32 bkrspLength = bkrsp.size();
- const UVSC_STATUS st = ::UVSC_DBG_CHANGE_BP(m_descriptor, &bkchg, sizeof(bkchg),
- reinterpret_cast<BKRSP *>(bkrsp.data()),
- &bkrspLength);
+ BKRSP bkrsp = {};
+ qint32 bkrspLength = sizeof(bkrsp);
+ const UVSC_STATUS st = ::UVSC_DBG_CHANGE_BP(m_descriptor, &bkchg, sizeof(bkchg), &bkrsp, &bkrspLength);
if (st != UVSC_STATUS_SUCCESS) {
setError(RuntimeError);
return false;
@@ -846,6 +885,69 @@ bool UvscClient::disableBreakpoint(quint32 tickMark)
return true;
}
+bool UvscClient::controlHiddenBreakpoint(const QString &exp)
+{
+ if (!checkConnection())
+ return false;
+
+ // It is a magic workaround to prevent the UVSC bug when the break-point
+ // creation may stall. A problem is that sometime the UVSC_DBG_CREATE_BP
+ // function blocks and returns then with the timeout error when the original
+ // break-point contains the full expression including the line number.
+ //
+ // It can be avoided with helps of creation and then deletion of the
+ // 'fake hidden' break-point with the same expression excluding the line
+ // number, before creation of an original break-point.
+
+ const int slashIndex = exp.lastIndexOf('\\');
+ if (slashIndex == -1 || (slashIndex + 1) == exp.size())
+ return true;
+
+ BKRSP bkrsp = {};
+
+ const QString hiddenExp = exp.mid(0, slashIndex);
+ QByteArray bkparm = UvscUtils::encodeBreakPoint(BRKTYPE_EXEC, hiddenExp);
+ qint32 bkrspLength = sizeof(bkrsp);
+ UVSC_STATUS st = ::UVSC_DBG_CREATE_BP(m_descriptor,
+ reinterpret_cast<BKPARM *>(bkparm.data()),
+ bkparm.size(),
+ &bkrsp, &bkrspLength);
+ if (st != UVSC_STATUS_SUCCESS) {
+ setError(RuntimeError);
+ return false;
+ }
+
+ BKCHG bkchg = {};
+ bkchg.type = CHG_KILLBP;
+ bkchg.tickMark = bkrsp.tickMark;
+ bkrspLength = sizeof(bkrsp);
+ st = ::UVSC_DBG_CHANGE_BP(m_descriptor, &bkchg, sizeof(bkchg), &bkrsp, &bkrspLength);
+ if (st != UVSC_STATUS_SUCCESS) {
+ setError(RuntimeError);
+ return false;
+ }
+
+ return true;
+}
+
+bool UvscClient::enumerateBreakpoints(std::vector<BKRSP> &bpenums)
+{
+ if (!checkConnection())
+ return false;
+
+ bpenums.resize(kMaximumBreakpointEnumsCount);
+ qint32 bpenumsCount = kMaximumBreakpointEnumsCount;
+ std::vector<qint32> indexes(bpenumsCount, 0);
+ const UVSC_STATUS st = ::UVSC_DBG_ENUMERATE_BP(m_descriptor, bpenums.data(),
+ indexes.data(), &bpenumsCount);
+ if (st != UVSC_STATUS_SUCCESS) {
+ setError(RuntimeError);
+ return false;
+ }
+ bpenums.resize(bpenumsCount);
+ return true;
+}
+
bool UvscClient::calculateExpression(const QString &exp, QByteArray &)
{
if (!checkConnection())
@@ -1097,5 +1199,36 @@ bool UvscClient::addressToFileLine(quint64 address, QString &fileName,
return true;
}
+bool UvscClient::executeCommand(const QString &cmd, QString &output)
+{
+ if (!checkConnection())
+ return false;
+
+ EXECCMD exeCmd = UvscUtils::encodeCommand(cmd);
+ UVSC_STATUS st = ::UVSC_DBG_EXEC_CMD(m_descriptor, &exeCmd, sizeof(exeCmd.command));
+ if (st != UVSC_STATUS_SUCCESS) {
+ setError(RuntimeError);
+ return false;
+ }
+
+ qint32 outputLength = 0;
+ st = ::UVSC_GetCmdOutputSize(m_descriptor, &outputLength);
+ if (st != UVSC_STATUS_SUCCESS) {
+ setError(RuntimeError);
+ return false;
+ }
+
+ QByteArray data(outputLength, 0);
+ st = UVSC_GetCmdOutput(m_descriptor, reinterpret_cast<qint8 *>(data.data()), data.size());
+ if (st != UVSC_STATUS_SUCCESS) {
+ setError(RuntimeError);
+ return false;
+ }
+
+ // Note: UVSC API support only ASCII!
+ output = QString::fromLatin1(data);
+ return true;
+}
+
} // namespace Internal
} // namespace Debugger
diff --git a/src/plugins/debugger/uvsc/uvscclient.h b/src/plugins/debugger/uvsc/uvscclient.h
index a602622a2b..98b001ac4e 100644
--- a/src/plugins/debugger/uvsc/uvscclient.h
+++ b/src/plugins/debugger/uvsc/uvscclient.h
@@ -36,6 +36,7 @@ QT_END_NAMESPACE
// From UVSC api.
struct STACKENUM;
+struct BKRSP;
namespace Utils { class FilePath; }
@@ -87,6 +88,9 @@ public:
bool fetchWatchers(const QStringList &expandedWatcherINames,
const std::vector<std::pair<QString, QString>> &rootWatchers, GdbMi &data);
+ bool fetchMemory(quint64 address, QByteArray &data);
+ bool changeMemory(quint64 address, const QByteArray &data);
+
bool disassemblyAddress(quint64 address, QByteArray &result);
bool setRegisterValue(int index, const QString &value);
@@ -138,6 +142,10 @@ private:
void updateLocation(const QByteArray &bpreason);
bool addressToFileLine(quint64 address, QString &fileName, QString &function, quint32 &line);
+ bool controlHiddenBreakpoint(const QString &exp);
+ bool enumerateBreakpoints(std::vector<BKRSP> &bpenums);
+ bool executeCommand(const QString &cmd, QString &output);
+
qint32 m_descriptor = -1;
quint64 m_exitAddress = 0;
UvscError m_error = NoError;
diff --git a/src/plugins/debugger/uvsc/uvscdatatypes.h b/src/plugins/debugger/uvsc/uvscdatatypes.h
index c2ef9d7712..4392d81644 100644
--- a/src/plugins/debugger/uvsc/uvscdatatypes.h
+++ b/src/plugins/debugger/uvsc/uvscdatatypes.h
@@ -610,9 +610,9 @@ struct BKRSP {
quint32 tickMark;
quint64 address;
quint32 expressionLength;
- qint8 expressionBuffer[1];
+ qint8 expressionBuffer[512];
};
-static_assert(sizeof(BKRSP) == 29, "BKRSP size is not 29 bytes");
+static_assert(sizeof(BKRSP) == 540, "BKRSP size is not 540 bytes");
// Breakpoint change data.
struct BKCHG {
diff --git a/src/plugins/debugger/uvsc/uvscengine.cpp b/src/plugins/debugger/uvsc/uvscengine.cpp
index bc796172c1..23b657ac58 100644
--- a/src/plugins/debugger/uvsc/uvscengine.cpp
+++ b/src/plugins/debugger/uvsc/uvscengine.cpp
@@ -32,6 +32,7 @@
#include <debugger/disassemblerlines.h>
#include <debugger/memoryagent.h>
#include <debugger/moduleshandler.h>
+#include <debugger/peripheralregisterhandler.h>
#include <debugger/registerhandler.h>
#include <debugger/stackhandler.h>
#include <debugger/threadshandler.h>
@@ -162,6 +163,9 @@ void UvscEngine::setupEngine()
if (!configureProject(rp))
return;
+
+ // Reload peripheral register description.
+ peripheralRegisterHandler()->updateRegisterGroups();
}
void UvscEngine::runEngine()
@@ -231,6 +235,14 @@ void UvscEngine::setRegisterValue(const QString &name, const QString &value)
reloadRegisters();
}
+void UvscEngine::setPeripheralRegisterValue(quint64 address, quint64 value)
+{
+ const QByteArray data = UvscUtils::encodeU32(value);
+ if (!m_client->changeMemory(address, data))
+ return;
+ reloadPeripheralRegisters();
+}
+
void UvscEngine::executeStepOver(bool byInstruction)
{
notifyInferiorRunRequested();
@@ -332,6 +344,7 @@ void UvscEngine::activateFrame(int index)
gotoCurrentLocation();
updateLocals();
reloadRegisters();
+ reloadPeripheralRegisters();
}
bool UvscEngine::stateAcceptsBreakpointChanges() const
@@ -469,6 +482,17 @@ void UvscEngine::reloadRegisters()
handleReloadRegisters();
}
+void UvscEngine::reloadPeripheralRegisters()
+{
+ if (!isPeripheralRegistersWindowVisible())
+ return;
+
+ const QList<quint64> addresses = peripheralRegisterHandler()->activeRegisters();
+ if (addresses.isEmpty())
+ return; // Nothing to update.
+ handleReloadPeripheralRegisters(addresses);
+}
+
void UvscEngine::reloadFullStack()
{
resetLocation();
@@ -496,6 +520,7 @@ void UvscEngine::updateAll()
handleThreadInfo();
reloadRegisters();
+ reloadPeripheralRegisters();
updateLocals();
}
@@ -608,6 +633,8 @@ void UvscEngine::handleUpdateLocation(quint64 address)
void UvscEngine::handleStartExecution()
{
+ if (state() != InferiorRunRequested)
+ notifyInferiorRunRequested();
notifyInferiorRunOk();
}
@@ -653,6 +680,7 @@ void UvscEngine::handleReloadStack(bool isFull)
if (!m_client->fetchStackFrames(taskId, m_address, data)) {
m_address = 0;
reloadRegisters();
+ reloadPeripheralRegisters();
return;
}
@@ -678,6 +706,19 @@ void UvscEngine::handleReloadRegisters()
}
}
+void UvscEngine::handleReloadPeripheralRegisters(const QList<quint64> &addresses)
+{
+ for (const quint64 address : addresses) {
+ QByteArray data = UvscUtils::encodeU32(0);
+ if (!m_client->fetchMemory(address, data)) {
+ showMessage(tr("UVSC: Fetching peripheral register failed"), LogMisc);
+ } else {
+ const quint32 value = UvscUtils::decodeU32(data);
+ peripheralRegisterHandler()->updateRegister(address, value);
+ }
+ }
+}
+
void UvscEngine::handleUpdateLocals(bool partial)
{
m_inUpdateLocals = false;
diff --git a/src/plugins/debugger/uvsc/uvscengine.h b/src/plugins/debugger/uvsc/uvscengine.h
index 97f843f44c..ace70fd5c5 100644
--- a/src/plugins/debugger/uvsc/uvscengine.h
+++ b/src/plugins/debugger/uvsc/uvscengine.h
@@ -49,6 +49,7 @@ public:
bool hasCapability(unsigned cap) const final;
void setRegisterValue(const QString &name, const QString &value) final;
+ void setPeripheralRegisterValue(quint64 address, quint64 value) final;
void executeStepOver(bool byInstruction) final;
void executeStepIn(bool byInstruction) final;
@@ -72,6 +73,8 @@ public:
void fetchDisassembler(DisassemblerAgent *agent) final;
void reloadRegisters() final;
+ void reloadPeripheralRegisters() final;
+
void reloadFullStack() final;
private slots:
@@ -84,6 +87,7 @@ private slots:
void handleThreadInfo();
void handleReloadStack(bool isFull);
void handleReloadRegisters();
+ void handleReloadPeripheralRegisters(const QList<quint64> &addresses);
void handleUpdateLocals(bool partial);
void handleInsertBreakpoint(const QString &exp, const Breakpoint &bp);
void handleRemoveBreakpoint(const Breakpoint &bp);
diff --git a/src/plugins/debugger/uvsc/uvscutils.cpp b/src/plugins/debugger/uvsc/uvscutils.cpp
index e3b7e8799a..a8e7d97e62 100644
--- a/src/plugins/debugger/uvsc/uvscutils.cpp
+++ b/src/plugins/debugger/uvsc/uvscutils.cpp
@@ -110,6 +110,24 @@ QByteArray encodeAmem(quint64 address, quint32 bytesCount)
return buffer;
}
+QByteArray encodeAmem(quint64 address, const QByteArray &data)
+{
+ QByteArray buffer(sizeof(AMEM) - 1, 0);
+ buffer.append(data);
+ const auto amem = reinterpret_cast<AMEM *>(buffer.data());
+ amem->address = address;
+ amem->bytesCount = data.size();
+ return buffer;
+}
+
+EXECCMD encodeCommand(const QString &cmd)
+{
+ EXECCMD exeCmd = {};
+ exeCmd.useEcho = false;
+ exeCmd.command = encodeSstr(cmd);
+ return exeCmd;
+}
+
TVAL encodeVoidTval()
{
TVAL tval = {};
@@ -238,6 +256,24 @@ QString adjustHexValue(QString hex, const QString &type)
return {};
}
+QByteArray encodeU32(quint32 value)
+{
+ QByteArray data;
+ QDataStream out(&data, QIODevice::WriteOnly);
+ out.setByteOrder(QDataStream::LittleEndian);
+ out << value;
+ return data;
+}
+
+quint32 decodeU32(const QByteArray &data)
+{
+ QDataStream in(data);
+ in.setByteOrder(QDataStream::LittleEndian);
+ quint32 value = 0;
+ in >> value;
+ return value;
+}
+
QString buildLocalId(const VARINFO &varinfo)
{
return QString::number(varinfo.id);
diff --git a/src/plugins/debugger/uvsc/uvscutils.h b/src/plugins/debugger/uvsc/uvscutils.h
index 6295912839..61778f11e5 100644
--- a/src/plugins/debugger/uvsc/uvscutils.h
+++ b/src/plugins/debugger/uvsc/uvscutils.h
@@ -56,6 +56,8 @@ QString decodeAscii(const qint8 *ascii);
QByteArray encodeProjectData(const QStringList &someNames);
QByteArray encodeBreakPoint(BKTYPE type, const QString &exp, const QString &cmd = QString());
QByteArray encodeAmem(quint64 address, quint32 bytesCount);
+QByteArray encodeAmem(quint64 address, const QByteArray &data);
+EXECCMD encodeCommand(const QString &cmd);
TVAL encodeVoidTval();
TVAL encodeIntTval(int value);
TVAL encodeU64Tval(quint64 value);
@@ -65,6 +67,9 @@ VSET encodeU64Vset(quint64 index, const QString &value);
bool isKnownRegister(int type);
QString adjustHexValue(QString hex, const QString &type);
+QByteArray encodeU32(quint32 value);
+quint32 decodeU32(const QByteArray &data);
+
QString buildLocalId(const VARINFO &varinfo);
QString buildLocalEditable(const VARINFO &varinfo);
QString buildLocalNumchild(const VARINFO &varinfo);
diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp
index 066f9be23b..bd473776ef 100644
--- a/src/plugins/debugger/watchhandler.cpp
+++ b/src/plugins/debugger/watchhandler.cpp
@@ -1108,7 +1108,8 @@ bool WatchModel::setData(const QModelIndex &idx, const QVariant &value, int role
}
if (auto kev = ev.as<QKeyEvent>(QEvent::KeyPress)) {
- if (item && kev->key() == Qt::Key_Delete && item->isWatcher()) {
+ if (item && (kev->key() == Qt::Key_Delete || kev->key() == Qt::Key_Backspace)
+ && item->isWatcher()) {
foreach (const QModelIndex &idx, ev.selectedRows())
removeWatchItem(itemForIndex(idx));
return true;
@@ -1595,7 +1596,8 @@ static QString removeWatchActionText(QString exp)
static void copyToClipboard(const QString &clipboardText)
{
QClipboard *clipboard = QApplication::clipboard();
- clipboard->setText(clipboardText, QClipboard::Selection);
+ if (clipboard->supportsSelection())
+ clipboard->setText(clipboardText, QClipboard::Selection);
clipboard->setText(clipboardText, QClipboard::Clipboard);
}
@@ -1909,12 +1911,18 @@ QMenu *WatchModel::createFormatMenu(WatchItem *item, QWidget *parent)
});
}
+ addAction(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);
addCheckableAction(menu, spacer + tr("Automatic"), true, typeFormat == AutomaticFormat,
[this, item] {
- //const QModelIndexList active = activeRows();
+ //const QModelIndexList active = activeRows();
//for (const QModelIndex &idx : active)
// setModelData(LocalsTypeFormatRole, AutomaticFormat, idx);
setTypeFormat(item->type, AutomaticFormat);
@@ -1924,11 +1932,17 @@ QMenu *WatchModel::createFormatMenu(WatchItem *item, QWidget *parent)
for (int format : alternativeFormats) {
addCheckableAction(menu, spacer + nameForFormat(format), true, format == typeFormat,
[this, format, item] {
- setTypeFormat(item->type, format);
- m_engine->updateLocals();
+ setTypeFormat(item->type, format);
+ m_engine->updateLocals();
});
}
+ addAction(menu, tr("Reset All Formats for Types"), true, [this]() {
+ theTypeFormats.clear();
+ saveFormats();
+ m_engine->updateLocals();
+ });
+
return menu;
}
diff --git a/src/plugins/designer/cpp/newclasswidget.cpp b/src/plugins/designer/cpp/newclasswidget.cpp
index 2cd400e666..249b91048a 100644
--- a/src/plugins/designer/cpp/newclasswidget.cpp
+++ b/src/plugins/designer/cpp/newclasswidget.cpp
@@ -174,7 +174,7 @@ QString NewClassWidget::formFileName() const
QString NewClassWidget::path() const
{
- return d->m_ui.pathChooser->path();
+ return d->m_ui.pathChooser->filePath().toString();
}
void NewClassWidget::setPath(const QString &path)
diff --git a/src/plugins/designer/formeditorw.cpp b/src/plugins/designer/formeditorw.cpp
index d7df1c8e85..ad5cb8c97b 100644
--- a/src/plugins/designer/formeditorw.cpp
+++ b/src/plugins/designer/formeditorw.cpp
@@ -313,7 +313,7 @@ void FormEditorData::addDockViewAction(ActionContainer *viewMenu,
void FormEditorData::setupViewActions()
{
// Populate "View" menu of form editor menu
- ActionContainer *viewMenu = ActionManager::actionContainer(Core::Constants::M_WINDOW_VIEWS);
+ ActionContainer *viewMenu = ActionManager::actionContainer(Core::Constants::M_VIEW_VIEWS);
QTC_ASSERT(viewMenu, return);
addDockViewAction(viewMenu, WidgetBoxSubWindow, m_contexts,
diff --git a/src/plugins/designer/settingspage.cpp b/src/plugins/designer/settingspage.cpp
index f038b7a4db..0c51d80ab3 100644
--- a/src/plugins/designer/settingspage.cpp
+++ b/src/plugins/designer/settingspage.cpp
@@ -85,7 +85,7 @@ QList<Core::IOptionsPage *> SettingsPageProvider::pages() const
return FormEditorW::optionsPages();
}
-bool SettingsPageProvider::matches(const QString &searchKeyWord) const
+bool SettingsPageProvider::matches(const QRegularExpression &regex) const
{
// to avoid fully initializing designer when typing something in the options' filter edit
// we hardcode matching of UI text from the designer pages, which are taken if the designer pages
@@ -119,7 +119,7 @@ bool SettingsPageProvider::matches(const QString &searchKeyWord) const
m_keywords << Utils::stripAccelerator(QCoreApplication::translate(uitext[i].context, uitext[i].value));
}
for (const QString &key : qAsConst(m_keywords)) {
- if (key.contains(searchKeyWord, Qt::CaseInsensitive))
+ if (key.contains(regex))
return true;
}
return false;
diff --git a/src/plugins/designer/settingspage.h b/src/plugins/designer/settingspage.h
index 13de3c2808..5086a879d6 100644
--- a/src/plugins/designer/settingspage.h
+++ b/src/plugins/designer/settingspage.h
@@ -63,7 +63,7 @@ public:
SettingsPageProvider();
QList<Core::IOptionsPage *> pages() const override;
- bool matches(const QString &searchKeyWord) const override;
+ bool matches(const QRegularExpression &regex) const override;
private:
mutable bool m_initialized = false;
diff --git a/src/plugins/diffeditor/diffeditorconstants.h b/src/plugins/diffeditor/diffeditorconstants.h
index e1c9870c98..8d5d635fa6 100644
--- a/src/plugins/diffeditor/diffeditorconstants.h
+++ b/src/plugins/diffeditor/diffeditorconstants.h
@@ -38,6 +38,7 @@ const char DIFF_EDITOR_MIMETYPE[] = "text/x-patch";
const char C_DIFF_EDITOR_DESCRIPTION[] = "DiffEditor.Description";
const char SIDE_BY_SIDE_VIEW_ID[] = "DiffEditor.SideBySide";
const char UNIFIED_VIEW_ID[] = "DiffEditor.Unified";
+const char SELECT_ENCODING[] = "DiffEditor.SelectEncoding";
const char G_TOOLS_DIFF[] = "QtCreator.Group.Tools.Options";
diff --git a/src/plugins/diffeditor/diffeditordocument.cpp b/src/plugins/diffeditor/diffeditordocument.cpp
index f68143bbba..546fe9e27e 100644
--- a/src/plugins/diffeditor/diffeditordocument.cpp
+++ b/src/plugins/diffeditor/diffeditordocument.cpp
@@ -31,7 +31,9 @@
#include <utils/fileutils.h>
#include <utils/qtcassert.h>
+#include <coreplugin/dialogs/codecselector.h>
#include <coreplugin/editormanager/editormanager.h>
+#include <coreplugin/icore.h>
#include <QCoreApplication>
#include <QFile>
@@ -314,10 +316,10 @@ Core::IDocument::OpenResult DiffEditorDocument::open(QString *errorString, const
beginReload();
QString patch;
ReadResult readResult = read(fileName, &patch, errorString);
- if (readResult == TextFileFormat::ReadEncodingError)
- return OpenResult::CannotHandle;
- else if (readResult != TextFileFormat::ReadSuccess)
+ if (readResult == TextFileFormat::ReadIOError
+ || readResult == TextFileFormat::ReadMemoryAllocationError) {
return OpenResult::ReadError;
+ }
bool ok = false;
QList<FileData> fileDataList = DiffUtils::readPatch(patch, &ok);
@@ -333,9 +335,29 @@ Core::IDocument::OpenResult DiffEditorDocument::open(QString *errorString, const
setDiffFiles(fileDataList, fi.absolutePath());
}
endReload(ok);
+ if (!ok && readResult == TextFileFormat::ReadEncodingError)
+ ok = selectEncoding();
return ok ? OpenResult::Success : OpenResult::CannotHandle;
}
+bool DiffEditorDocument::selectEncoding()
+{
+ Core::CodecSelector codecSelector(Core::ICore::dialogParent(), this);
+ switch (codecSelector.exec()) {
+ case Core::CodecSelector::Reload: {
+ setCodec(codecSelector.selectedCodec());
+ QString errorMessage;
+ return reload(&errorMessage, Core::IDocument::FlagReload, Core::IDocument::TypeContents);
+ }
+ case Core::CodecSelector::Save:
+ setCodec(codecSelector.selectedCodec());
+ return Core::EditorManager::saveDocument(this);
+ case Core::CodecSelector::Cancel:
+ break;
+ }
+ return false;
+}
+
QString DiffEditorDocument::fallbackSaveAsFileName() const
{
const int maxSubjectLength = 50;
diff --git a/src/plugins/diffeditor/diffeditordocument.h b/src/plugins/diffeditor/diffeditordocument.h
index dce1106260..a034feb439 100644
--- a/src/plugins/diffeditor/diffeditordocument.h
+++ b/src/plugins/diffeditor/diffeditordocument.h
@@ -86,6 +86,7 @@ public:
bool reload(QString *errorString, ReloadFlag flag, ChangeType type) override;
OpenResult open(QString *errorString, const QString &fileName,
const QString &realFileName) override;
+ bool selectEncoding();
State state() const { return m_state; }
QString plainText() const;
diff --git a/src/plugins/diffeditor/diffeditorwidgetcontroller.cpp b/src/plugins/diffeditor/diffeditorwidgetcontroller.cpp
index c4f0ab5cb5..8c408ae389 100644
--- a/src/plugins/diffeditor/diffeditorwidgetcontroller.cpp
+++ b/src/plugins/diffeditor/diffeditorwidgetcontroller.cpp
@@ -30,6 +30,7 @@
#include <coreplugin/documentmanager.h>
#include <coreplugin/editormanager/editormanager.h>
+#include <coreplugin/infobar.h>
#include <coreplugin/patchtool.h>
#include <texteditor/fontsettings.h>
@@ -76,7 +77,7 @@ void DiffEditorWidgetController::setDocument(DiffEditorDocument *document)
if (m_document) {
disconnect(m_document, &IDocument::aboutToReload, this, &DiffEditorWidgetController::scheduleShowProgress);
- disconnect(m_document, &IDocument::reloadFinished, this, &DiffEditorWidgetController::hideProgress);
+ disconnect(m_document, &IDocument::reloadFinished, this, &DiffEditorWidgetController::onDocumentReloadFinished);
}
const bool wasRunning = m_document && m_document->state() == DiffEditorDocument::Reloading;
@@ -85,7 +86,8 @@ void DiffEditorWidgetController::setDocument(DiffEditorDocument *document)
if (m_document) {
connect(m_document, &IDocument::aboutToReload, this, &DiffEditorWidgetController::scheduleShowProgress);
- connect(m_document, &IDocument::reloadFinished, this, &DiffEditorWidgetController::hideProgress);
+ connect(m_document, &IDocument::reloadFinished, this, &DiffEditorWidgetController::onDocumentReloadFinished);
+ updateCannotDecodeInfo();
}
const bool isRunning = m_document && m_document->state() == DiffEditorDocument::Reloading;
@@ -123,6 +125,12 @@ void DiffEditorWidgetController::hideProgress()
m_progressIndicator->hide();
}
+void DiffEditorWidgetController::onDocumentReloadFinished()
+{
+ updateCannotDecodeInfo();
+ hideProgress();
+}
+
void DiffEditorWidgetController::patch(bool revert, int fileIndex, int chunkIndex)
{
if (!m_document)
@@ -294,6 +302,27 @@ void DiffEditorWidgetController::addExtraActions(QMenu *menu, int fileIndex, int
controller->requestChunkActions(menu, fileIndex, chunkIndex, selection);
}
+void DiffEditorWidgetController::updateCannotDecodeInfo()
+{
+ if (!m_document)
+ return;
+
+ InfoBar *infoBar = m_document->infoBar();
+ Id selectEncodingId(Constants::SELECT_ENCODING);
+ if (m_document->hasDecodingError()) {
+ if (!infoBar->canInfoBeAdded(selectEncodingId))
+ return;
+ InfoBarEntry info(selectEncodingId,
+ tr("<b>Error:</b> Could not decode \"%1\" with \"%2\"-encoding.")
+ .arg(m_document->displayName(),
+ QString::fromLatin1(m_document->codec()->name())));
+ info.setCustomButtonInfo(tr("Select Encoding"), [this]() { m_document->selectEncoding(); });
+ infoBar->addInfo(info);
+ } else {
+ infoBar->removeInfo(selectEncodingId);
+ }
+}
+
void DiffEditorWidgetController::sendChunkToCodePaster(int fileIndex, int chunkIndex)
{
if (!m_document)
diff --git a/src/plugins/diffeditor/diffeditorwidgetcontroller.h b/src/plugins/diffeditor/diffeditorwidgetcontroller.h
index 4951ec1cb4..70c6aa4cae 100644
--- a/src/plugins/diffeditor/diffeditorwidgetcontroller.h
+++ b/src/plugins/diffeditor/diffeditorwidgetcontroller.h
@@ -61,6 +61,7 @@ public:
void addApplyAction(QMenu *menu, int fileIndex, int chunkIndex);
void addRevertAction(QMenu *menu, int fileIndex, int chunkIndex);
void addExtraActions(QMenu *menu, int fileIndex, int chunkIndex, const ChunkSelection &selection);
+ void updateCannotDecodeInfo();
ChunkData chunkData(int fileIndex, int chunkIndex) const;
@@ -83,6 +84,7 @@ private:
void scheduleShowProgress();
void showProgress();
void hideProgress();
+ void onDocumentReloadFinished();
QWidget *m_diffEditorWidget = nullptr;
diff --git a/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp b/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp
index 274241d426..6ac614aad4 100644
--- a/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp
+++ b/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp
@@ -87,6 +87,7 @@ public:
void clearAll(const QString &message);
void clearAllData();
void saveState();
+ using TextEditor::TextEditorWidget::restoreState;
void restoreState();
void setFolded(int blockNumber, bool folded);
diff --git a/src/plugins/diffeditor/unifieddiffeditorwidget.h b/src/plugins/diffeditor/unifieddiffeditorwidget.h
index 993d6cba20..8d1dbd2ad5 100644
--- a/src/plugins/diffeditor/unifieddiffeditorwidget.h
+++ b/src/plugins/diffeditor/unifieddiffeditorwidget.h
@@ -60,6 +60,8 @@ public:
void setCurrentDiffFileIndex(int diffFileIndex);
void saveState();
+
+ using TextEditor::TextEditorWidget::restoreState;
void restoreState();
void clear(const QString &message = QString());
diff --git a/src/plugins/emacskeys/emacskeysplugin.cpp b/src/plugins/emacskeys/emacskeysplugin.cpp
index d1259d7eb7..300326f21d 100644
--- a/src/plugins/emacskeys/emacskeysplugin.cpp
+++ b/src/plugins/emacskeys/emacskeysplugin.cpp
@@ -49,6 +49,14 @@ QT_END_NAMESPACE
using namespace Core;
+namespace {
+QString plainSelectedText(const QTextCursor &cursor)
+{
+ // selectedText() returns U+2029 (PARAGRAPH SEPARATOR) instead of newline
+ return cursor.selectedText().replace(QChar::ParagraphSeparator, QLatin1Char('\n'));
+}
+}
+
namespace EmacsKeys {
namespace Internal {
@@ -216,7 +224,7 @@ void EmacsKeysPlugin::copy()
m_currentState->beginOwnAction();
QTextCursor cursor = m_currentEditorWidget->textCursor();
- QApplication::clipboard()->setText(cursor.selectedText());
+ QApplication::clipboard()->setText(plainSelectedText(cursor));
cursor.clearSelection();
m_currentEditorWidget->setTextCursor(cursor);
m_currentState->setMark(-1);
@@ -230,7 +238,7 @@ void EmacsKeysPlugin::cut()
m_currentState->beginOwnAction();
QTextCursor cursor = m_currentEditorWidget->textCursor();
- QApplication::clipboard()->setText(cursor.selectedText());
+ QApplication::clipboard()->setText(plainSelectedText(cursor));
cursor.removeSelectedText();
m_currentState->setMark(-1);
m_currentState->endOwnAction(KeysActionOther);
@@ -268,9 +276,9 @@ void EmacsKeysPlugin::killWord()
cursor.movePosition(QTextCursor::NextWord, QTextCursor::KeepAnchor);
if (m_currentState->lastAction() == KeysActionKillWord) {
QApplication::clipboard()->setText(
- QApplication::clipboard()->text() + cursor.selectedText());
+ QApplication::clipboard()->text() + plainSelectedText(cursor));
} else {
- QApplication::clipboard()->setText(cursor.selectedText());
+ QApplication::clipboard()->setText(plainSelectedText(cursor));
}
cursor.removeSelectedText();
m_currentState->endOwnAction(KeysActionKillWord);
@@ -291,9 +299,9 @@ void EmacsKeysPlugin::killLine()
}
if (m_currentState->lastAction() == KeysActionKillLine) {
QApplication::clipboard()->setText(
- QApplication::clipboard()->text() + cursor.selectedText());
+ QApplication::clipboard()->text() + plainSelectedText(cursor));
} else {
- QApplication::clipboard()->setText(cursor.selectedText());
+ QApplication::clipboard()->setText(plainSelectedText(cursor));
}
cursor.removeSelectedText();
m_currentState->endOwnAction(KeysActionKillLine);
diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp
index 601377ed69..542c558cf7 100644
--- a/src/plugins/fakevim/fakevimhandler.cpp
+++ b/src/plugins/fakevim/fakevimhandler.cpp
@@ -893,6 +893,11 @@ static bool isOnlyControlModifier(const Qt::KeyboardModifiers &mods)
return (mods ^ ControlModifier) == Qt::NoModifier;
}
+static bool hasControlModifier(const Qt::KeyboardModifiers &mods)
+{
+ return mods.testFlag(ControlModifier);
+}
+
Range::Range(int b, int e, RangeMode m)
: beginPos(qMin(b, e)), endPos(qMax(b, e)), rangemode(m)
@@ -1065,7 +1070,7 @@ public:
bool is(int c) const
{
- return m_xkey == c && !isControl();
+ return m_xkey == c && !hasControlModifier(m_modifiers);
}
bool isControl() const
diff --git a/src/plugins/genericprojectmanager/genericmakestep.cpp b/src/plugins/genericprojectmanager/genericmakestep.cpp
index e66a938ab3..f987ac6586 100644
--- a/src/plugins/genericprojectmanager/genericmakestep.cpp
+++ b/src/plugins/genericprojectmanager/genericmakestep.cpp
@@ -34,6 +34,12 @@ using namespace ProjectExplorer;
namespace GenericProjectManager {
namespace Internal {
+class GenericMakeStep : public ProjectExplorer::MakeStep
+{
+public:
+ explicit GenericMakeStep(BuildStepList *parent, Core::Id id);
+};
+
GenericMakeStep::GenericMakeStep(BuildStepList *parent, Core::Id id)
: MakeStep(parent, id)
{
diff --git a/src/plugins/genericprojectmanager/genericmakestep.h b/src/plugins/genericprojectmanager/genericmakestep.h
index 5e83216f49..85d312646d 100644
--- a/src/plugins/genericprojectmanager/genericmakestep.h
+++ b/src/plugins/genericprojectmanager/genericmakestep.h
@@ -27,20 +27,10 @@
#include <projectexplorer/makestep.h>
-QT_FORWARD_DECLARE_CLASS(QListWidgetItem);
-
namespace GenericProjectManager {
namespace Internal {
-class GenericMakeStep : public ProjectExplorer::MakeStep
-{
- Q_OBJECT
-
-public:
- explicit GenericMakeStep(ProjectExplorer::BuildStepList *parent, Core::Id id);
-};
-
-class GenericMakeStepFactory : public ProjectExplorer::BuildStepFactory
+class GenericMakeStepFactory final : public ProjectExplorer::BuildStepFactory
{
public:
GenericMakeStepFactory();
diff --git a/src/plugins/genericprojectmanager/genericproject.cpp b/src/plugins/genericprojectmanager/genericproject.cpp
index e5f735f711..3289564e25 100644
--- a/src/plugins/genericprojectmanager/genericproject.cpp
+++ b/src/plugins/genericprojectmanager/genericproject.cpp
@@ -173,8 +173,6 @@ private:
CppTools::CppProjectUpdaterInterface *m_cppCodeModelUpdater = nullptr;
Utils::FileSystemWatcher m_deployFileWatcher;
-
- ParseGuard m_guard;
};
@@ -263,7 +261,6 @@ GenericBuildSystem::~GenericBuildSystem()
void GenericBuildSystem::triggerParsing()
{
- m_guard = guardParsingRun();
refresh(Everything);
}
diff --git a/src/plugins/git/branchview.cpp b/src/plugins/git/branchview.cpp
index 87c4e09753..3019756c0c 100644
--- a/src/plugins/git/branchview.cpp
+++ b/src/plugins/git/branchview.cpp
@@ -106,7 +106,7 @@ BranchView::BranchView() :
auto filterEdit = new Utils::FancyLineEdit(this);
filterEdit->setFiltering(true);
connect(filterEdit, &Utils::FancyLineEdit::textChanged,
- m_filterModel, QOverload<const QString &>::of(&BranchFilterModel::setFilterRegExp));
+ m_filterModel, QOverload<const QString &>::of(&BranchFilterModel::setFilterRegularExpression));
auto layout = new QVBoxLayout(this);
layout->addWidget(filterEdit);
layout->addWidget(m_repositoryLabel);
@@ -319,19 +319,11 @@ bool BranchView::add()
const QStringList localNames = m_model->localBranchNames();
- QString suggestedName;
+ BranchAddDialog branchAddDialog(localNames, BranchAddDialog::Type::AddBranch, this);
if (isTracked) {
- const QString suggestedNameBase = trackedBranch.mid(trackedBranch.lastIndexOf('/') + 1);
- suggestedName = suggestedNameBase;
- int i = 2;
- while (localNames.contains(suggestedName)) {
- suggestedName = suggestedNameBase + QString::number(i);
- ++i;
- }
+ const QString suggestedName = GitClient::suggestedLocalBranchName(localNames, trackedBranch);
+ branchAddDialog.setBranchName(suggestedName);
}
-
- BranchAddDialog branchAddDialog(localNames, BranchAddDialog::Type::AddBranch, this);
- branchAddDialog.setBranchName(suggestedName);
branchAddDialog.setTrackedBranchName(isTracked ? trackedBranch : QString(), !isLocal);
branchAddDialog.setCheckoutVisible(true);
@@ -498,7 +490,7 @@ bool BranchView::reset(const QByteArray &resetType)
return false;
if (QMessageBox::question(this, tr("Git Reset"), tr("Reset branch \"%1\" to \"%2\"?")
- .arg(currentName).arg(branchName),
+ .arg(currentName, branchName),
QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) {
GitClient::instance()->reset(m_repository, QLatin1String("--" + resetType), branchName);
return true;
diff --git a/src/plugins/git/changeselectiondialog.cpp b/src/plugins/git/changeselectiondialog.cpp
index 52f8c4762f..9872112bdf 100644
--- a/src/plugins/git/changeselectiondialog.cpp
+++ b/src/plugins/git/changeselectiondialog.cpp
@@ -74,15 +74,15 @@ ChangeSelectionDialog::ChangeSelectionDialog(const QString &workingDirectory, Co
connect(m_ui->selectFromHistoryButton, &QPushButton::clicked,
this, &ChangeSelectionDialog::selectCommitFromRecentHistory);
connect(m_ui->showButton, &QPushButton::clicked,
- this, std::bind(&ChangeSelectionDialog::accept, this, Show));
+ this, std::bind(&ChangeSelectionDialog::acceptCommand, this, Show));
connect(m_ui->cherryPickButton, &QPushButton::clicked,
- this, std::bind(&ChangeSelectionDialog::accept, this, CherryPick));
+ this, std::bind(&ChangeSelectionDialog::acceptCommand, this, CherryPick));
connect(m_ui->revertButton, &QPushButton::clicked,
- this, std::bind(&ChangeSelectionDialog::accept, this, Revert));
+ this, std::bind(&ChangeSelectionDialog::acceptCommand, this, Revert));
connect(m_ui->checkoutButton, &QPushButton::clicked,
- this, std::bind(&ChangeSelectionDialog::accept, this, Checkout));
+ this, std::bind(&ChangeSelectionDialog::acceptCommand, this, Checkout));
connect(m_ui->archiveButton, &QPushButton::clicked,
- this, std::bind(&ChangeSelectionDialog::accept, this, Archive));
+ this, std::bind(&ChangeSelectionDialog::acceptCommand, this, Archive));
if (id == "Git.Revert")
m_ui->revertButton->setDefault(true);
@@ -137,7 +137,7 @@ void ChangeSelectionDialog::selectCommitFromRecentHistory()
QString ChangeSelectionDialog::workingDirectory() const
{
- const QString workingDir = m_ui->workingDirectoryChooser->path();
+ const QString workingDir = m_ui->workingDirectoryChooser->filePath().toString();
if (workingDir.isEmpty() || !QDir(workingDir).exists())
return QString();
@@ -149,7 +149,7 @@ ChangeCommand ChangeSelectionDialog::command() const
return m_command;
}
-void ChangeSelectionDialog::accept(ChangeCommand command)
+void ChangeSelectionDialog::acceptCommand(ChangeCommand command)
{
m_command = command;
QDialog::accept();
diff --git a/src/plugins/git/changeselectiondialog.h b/src/plugins/git/changeselectiondialog.h
index 84e888756b..b7714cece6 100644
--- a/src/plugins/git/changeselectiondialog.h
+++ b/src/plugins/git/changeselectiondialog.h
@@ -69,7 +69,7 @@ private:
void recalculateCompletion();
void recalculateDetails();
void changeTextChanged(const QString &text);
- void accept(ChangeCommand command);
+ void acceptCommand(ChangeCommand command);
void enableButtons(bool b);
void terminateProcess();
diff --git a/src/plugins/git/gerrit/gerritoptionspage.cpp b/src/plugins/git/gerrit/gerritoptionspage.cpp
index 21d273312c..99985c8ba2 100644
--- a/src/plugins/git/gerrit/gerritoptionspage.cpp
+++ b/src/plugins/git/gerrit/gerritoptionspage.cpp
@@ -124,8 +124,8 @@ GerritParameters GerritOptionsWidget::parameters() const
static_cast<unsigned short>(m_portSpinBox->value()),
m_userLineEdit->text().trimmed(),
GerritServer::Ssh);
- result.ssh = m_sshChooser->path();
- result.curl = m_curlChooser->path();
+ result.ssh = m_sshChooser->filePath().toString();
+ result.curl = m_curlChooser->filePath().toString();
result.https = m_httpsCheckBox->isChecked();
return result;
}
diff --git a/src/plugins/git/gerrit/gerritparameters.cpp b/src/plugins/git/gerrit/gerritparameters.cpp
index 7cbe62dbab..75ff383545 100644
--- a/src/plugins/git/gerrit/gerritparameters.cpp
+++ b/src/plugins/git/gerrit/gerritparameters.cpp
@@ -73,7 +73,7 @@ static inline QString detectApp(const char *defaultExe)
const QStringList entries = dir.entryList({"mingw*"});
if (entries.isEmpty())
return QString();
- path = path.pathAppended(entries.first()).pathAppended("bin").pathAppended(defaultApp);
+ path = path / entries.first() / "bin" / defaultApp;
if (path.exists())
return path.toString();
return QString();
diff --git a/src/plugins/git/gerrit/gerritpushdialog.cpp b/src/plugins/git/gerrit/gerritpushdialog.cpp
index ddd45134f7..63d05614bd 100644
--- a/src/plugins/git/gerrit/gerritpushdialog.cpp
+++ b/src/plugins/git/gerrit/gerritpushdialog.cpp
@@ -37,7 +37,7 @@
#include <QDateTime>
#include <QDir>
#include <QPushButton>
-#include <QRegExpValidator>
+#include <QRegularExpressionValidator>
#include <QVersionNumber>
using namespace Git::Internal;
@@ -156,7 +156,7 @@ GerritPushDialog::GerritPushDialog(const QString &workingDir, const QString &rev
updateCommits(m_ui->localBranchComboBox->currentIndex());
onRemoteChanged(true);
- QRegExpValidator *noSpaceValidator = new QRegExpValidator(QRegExp("^\\S+$"), this);
+ QRegularExpressionValidator *noSpaceValidator = new QRegularExpressionValidator(QRegularExpression("^\\S+$"), this);
m_ui->reviewersLineEdit->setText(reviewerList);
m_ui->reviewersLineEdit->setValidator(noSpaceValidator);
m_ui->topicLineEdit->setValidator(noSpaceValidator);
diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp
index 369dc06708..ed5b4f8745 100644
--- a/src/plugins/git/gitclient.cpp
+++ b/src/plugins/git/gitclient.cpp
@@ -84,12 +84,14 @@
#include <QTextCodec>
const char GIT_DIRECTORY[] = ".git";
-const char graphLogFormatC[] = "%h %d %an %s %ci";
const char HEAD[] = "HEAD";
const char CHERRY_PICK_HEAD[] = "CHERRY_PICK_HEAD";
const char BRANCHES_PREFIX[] = "Branches: ";
const char stashNamePrefix[] = "stash@{";
const char noColorOption[] = "--no-color";
+const char colorOption[] = "--color=always";
+const char patchOption[] = "--patch";
+const char graphOption[] = "--graph";
const char decorateOption[] = "--decorate";
const char showFormatC[] =
"--pretty=format:commit %H%d%n"
@@ -265,37 +267,68 @@ void DescriptionWidgetDecorator::removeWatch(TextEditor::TextEditorWidget *widge
///////////////////////////////
-class GitDiffEditorController : public VcsBaseDiffEditorController
+class GitBaseDiffEditorController : public VcsBaseDiffEditorController
{
Q_OBJECT
-public:
- explicit GitDiffEditorController(IDocument *document);
+protected:
+ explicit GitBaseDiffEditorController(IDocument *document,
+ const QString &leftCommit,
+ const QString &rightCommit);
protected:
void runCommand(const QList<QStringList> &args, QTextCodec *codec = nullptr);
QStringList addConfigurationArguments(const QStringList &args) const;
- QStringList addHeadWhenCommandInProgress() const;
+ QStringList baseArguments() const;
private:
void updateBranchList();
DescriptionWidgetWatcher m_watcher;
DescriptionWidgetDecorator m_decorator;
+ QString m_leftCommit;
+ QString m_rightCommit;
};
-GitDiffEditorController::GitDiffEditorController(IDocument *document) :
+class GitDiffEditorController : public GitBaseDiffEditorController
+{
+public:
+ explicit GitDiffEditorController(IDocument *document,
+ const QString &leftCommit,
+ const QString &rightCommit,
+ const QStringList &extraArgs)
+ : GitBaseDiffEditorController(document, leftCommit, rightCommit)
+ {
+ setReloader([this, extraArgs] {
+ runCommand({addConfigurationArguments(baseArguments() << extraArgs)});
+ });
+ }
+};
+
+GitBaseDiffEditorController::GitBaseDiffEditorController(IDocument *document,
+ const QString &leftCommit,
+ const QString &rightCommit) :
VcsBaseDiffEditorController(document),
m_watcher(this),
- m_decorator(&m_watcher)
+ m_decorator(&m_watcher),
+ m_leftCommit(leftCommit),
+ m_rightCommit(rightCommit)
{
connect(&m_decorator, &DescriptionWidgetDecorator::branchListRequested,
- this, &GitDiffEditorController::updateBranchList);
+ this, &GitBaseDiffEditorController::updateBranchList);
setDisplayName("Git Diff");
+ if (rightCommit.isEmpty()) {
+ // This is workaround for lack of support for merge commits and resolving conflicts,
+ // we compare the current state of working tree to the HEAD of current branch
+ // instead of showing unsupported combined diff format.
+ GitClient::CommandInProgress commandInProgress = m_instance->checkCommandInProgress(workingDirectory());
+ if (commandInProgress != GitClient::NoCommand)
+ m_rightCommit = HEAD;
+ }
}
-void GitDiffEditorController::updateBranchList()
+void GitBaseDiffEditorController::updateBranchList()
{
const QString revision = description().mid(7, 12);
if (revision.isEmpty())
@@ -347,12 +380,12 @@ void GitDiffEditorController::updateBranchList()
///////////////////////////////
-void GitDiffEditorController::runCommand(const QList<QStringList> &args, QTextCodec *codec)
+void GitBaseDiffEditorController::runCommand(const QList<QStringList> &args, QTextCodec *codec)
{
VcsBaseDiffEditorController::runCommand(args, diffExecutionFlags(), codec);
}
-QStringList GitDiffEditorController::addConfigurationArguments(const QStringList &args) const
+QStringList GitBaseDiffEditorController::addConfigurationArguments(const QStringList &args) const
{
QTC_ASSERT(!args.isEmpty(), return args);
@@ -372,66 +405,32 @@ QStringList GitDiffEditorController::addConfigurationArguments(const QStringList
return realArgs;
}
-QStringList GitDiffEditorController::addHeadWhenCommandInProgress() const
+QStringList GitBaseDiffEditorController::baseArguments() const
{
- // This is workaround for lack of support for merge commits and resolving conflicts,
- // we compare the current state of working tree to the HEAD of current branch
- // instead of showing unsupported combined diff format.
- GitClient::CommandInProgress commandInProgress = m_instance->checkCommandInProgress(workingDirectory());
- if (commandInProgress != GitClient::NoCommand)
- return {HEAD};
- return QStringList();
+ QStringList res = {"diff"};
+ if (!m_leftCommit.isEmpty())
+ res << m_leftCommit;
+ if (!m_rightCommit.isEmpty())
+ res << m_rightCommit;
+ return res;
}
-class RepositoryDiffController : public GitDiffEditorController
-{
-public:
- explicit RepositoryDiffController(IDocument *document) :
- GitDiffEditorController(document)
- {
- setReloader([this] {
- QStringList args = {"diff"};
- args.append(addHeadWhenCommandInProgress());
- runCommand({addConfigurationArguments(args)});
- });
- }
-};
-
-class FileDiffController : public GitDiffEditorController
-{
-public:
- FileDiffController(IDocument *document, const QString &fileName) :
- GitDiffEditorController(document)
- {
- setReloader([this, fileName] {
- QStringList args = {"diff"};
- args.append(addHeadWhenCommandInProgress());
- args << "--" << fileName;
- runCommand({addConfigurationArguments(args)});
- });
- }
-};
-
-class FileListDiffController : public GitDiffEditorController
+class FileListDiffController : public GitBaseDiffEditorController
{
public:
FileListDiffController(IDocument *document,
const QStringList &stagedFiles, const QStringList &unstagedFiles) :
- GitDiffEditorController(document)
+ GitBaseDiffEditorController(document, {}, {})
{
setReloader([this, stagedFiles, unstagedFiles] {
QList<QStringList> argLists;
if (!stagedFiles.isEmpty()) {
- QStringList stagedArgs = {"diff", "--cached", "--"};
- stagedArgs << stagedFiles;
+ QStringList stagedArgs = QStringList({"diff", "--cached", "--"}) << stagedFiles;
argLists << addConfigurationArguments(stagedArgs);
}
- if (!unstagedFiles.isEmpty()) {
- QStringList unstagedArgs = {"diff"};
- unstagedArgs << addHeadWhenCommandInProgress() << "--" << unstagedFiles;
- argLists << addConfigurationArguments(unstagedArgs);
- }
+ if (!unstagedFiles.isEmpty())
+ argLists << addConfigurationArguments(baseArguments() << "--" << unstagedFiles);
if (!argLists.isEmpty())
runCommand(argLists);
@@ -439,40 +438,12 @@ public:
}
};
-class ProjectDiffController : public GitDiffEditorController
-{
-public:
- ProjectDiffController(IDocument *document, const QStringList &projectPaths) :
- GitDiffEditorController(document)
- {
- setReloader([this, projectPaths] {
- QStringList args = {"diff"};
- args << addHeadWhenCommandInProgress() << "--" << projectPaths;
- runCommand({addConfigurationArguments(args)});
- });
- }
-};
-
-class BranchDiffController : public GitDiffEditorController
-{
-public:
- BranchDiffController(IDocument *document, const QString &branch) :
- GitDiffEditorController(document)
- {
- setReloader([this, branch] {
- QStringList args = {"diff"};
- args << addHeadWhenCommandInProgress() << branch;
- runCommand({addConfigurationArguments(args)});
- });
- }
-};
-
-class ShowController : public GitDiffEditorController
+class ShowController : public GitBaseDiffEditorController
{
Q_OBJECT
public:
ShowController(IDocument *document, const QString &id) :
- GitDiffEditorController(document),
+ GitBaseDiffEditorController(document, {}, {}),
m_id(id),
m_state(Idle)
{
@@ -505,7 +476,7 @@ void ShowController::processCommandOutput(const QString &output)
runCommand(QList<QStringList>() << addConfigurationArguments(args));
} else if (m_state == GettingDiff) {
m_state = Idle;
- GitDiffEditorController::processCommandOutput(output);
+ GitBaseDiffEditorController::processCommandOutput(output);
}
}
@@ -571,7 +542,7 @@ public:
BaseGitDiffArgumentsWidget(settings, editor->toolBar())
{
QToolBar *toolBar = editor->toolBar();
- QAction *diffButton = addToggleButton("--patch", tr("Diff"),
+ QAction *diffButton = addToggleButton(patchOption, tr("Diff"),
tr("Show difference."));
mapSetting(diffButton, settings.boolPointer(GitSettings::logDiffKey));
connect(diffButton, &QAction::toggled, m_patienceButton, &QAction::setVisible);
@@ -586,6 +557,12 @@ public:
}
};
+static bool gitHasRgbColors()
+{
+ const unsigned gitVersion = GitClient::instance()->gitVersion();
+ return gitVersion >= 0x020300U;
+}
+
class GitLogArgumentsWidget : public BaseGitLogArgumentsWidget
{
Q_OBJECT
@@ -599,14 +576,14 @@ public:
tr("First Parent"),
tr("Follow only the first parent on merge commits."));
mapSetting(firstParentButton, settings.boolPointer(GitSettings::firstParentKey));
- const QStringList graphArguments = {
- "--graph", "--oneline", "--topo-order",
- QLatin1String("--pretty=format:") + graphLogFormatC
- };
- QAction *graphButton = addToggleButton(graphArguments, tr("Graph"),
+ QAction *graphButton = addToggleButton(graphArguments(), tr("Graph"),
tr("Show textual graph log."));
mapSetting(graphButton, settings.boolPointer(GitSettings::graphLogKey));
+ QAction *colorButton = addToggleButton(QStringList{colorOption},
+ tr("Color"), tr("Use colors in log."));
+ mapSetting(colorButton, settings.boolPointer(GitSettings::colorLogKey));
+
if (fileRelated) {
QAction *followButton = addToggleButton(
"--follow", tr("Follow"),
@@ -616,6 +593,34 @@ public:
addReloadButton();
}
+
+ QStringList graphArguments() const
+ {
+ auto colorName = [](Theme::Color color) { return creatorTheme()->color(color).name(); };
+ const QString authorName = colorName(Theme::Git_AuthorName_TextColor);
+ const QString commitDate = colorName(Theme::Git_CommitDate_TextColor);
+ const QString commitHash = colorName(Theme::Git_CommitHash_TextColor);
+ const QString commitSubject = colorName(Theme::Git_CommitSubject_TextColor);
+ const QString decoration = colorName(Theme::Git_Decoration_TextColor);
+
+ const QString formatArg = QStringLiteral(
+ "--pretty=format:"
+ "%C(%1)%h%Creset "
+ "%C(%2)%d%Creset "
+ "%C(%3)%an%Creset "
+ "%C(%4)%s%Creset "
+ "%C(%5)%ci%Creset"
+ ).arg(commitHash, decoration, authorName, commitSubject, commitDate);
+
+ QStringList graphArgs = {graphOption, "--oneline", "--topo-order"};
+
+ if (gitHasRgbColors())
+ graphArgs << formatArg;
+ else
+ graphArgs << "--pretty=format:%h %d %an %s %ci";
+
+ return graphArgs;
+ }
};
class GitRefLogArgumentsWidget : public BaseGitLogArgumentsWidget
@@ -978,17 +983,20 @@ void GitClient::diffProject(const QString &workingDirectory, const QString &proj
requestReload(documentId,
workingDirectory, tr("Git Diff Project"), workingDirectory,
[projectDirectory](IDocument *doc){
- return new ProjectDiffController(doc, {projectDirectory});
+ return new GitDiffEditorController(doc, {}, {}, {"--", projectDirectory});
});
}
-void GitClient::diffRepository(const QString &workingDirectory)
+void GitClient::diffRepository(const QString &workingDirectory,
+ const QString &leftCommit,
+ const QString &rightCommit) const
{
const QString documentId = QLatin1String(Constants::GIT_PLUGIN)
+ QLatin1String(".DiffRepository.") + workingDirectory;
- requestReload(documentId,
- workingDirectory, tr("Git Diff Repository"), workingDirectory,
- [](IDocument *doc) { return new RepositoryDiffController(doc); });
+ requestReload(documentId, workingDirectory, tr("Git Diff Repository"), workingDirectory,
+ [&leftCommit, &rightCommit](IDocument *doc) {
+ return new GitDiffEditorController(doc, leftCommit, rightCommit, {});
+ });
}
void GitClient::diffFile(const QString &workingDirectory, const QString &fileName) const
@@ -998,7 +1006,9 @@ void GitClient::diffFile(const QString &workingDirectory, const QString &fileNam
const QString documentId = QLatin1String(Constants::GIT_PLUGIN)
+ QLatin1String(".DifFile.") + sourceFile;
requestReload(documentId, sourceFile, title, workingDirectory,
- [fileName](IDocument *doc) { return new FileDiffController(doc, fileName); });
+ [&fileName](IDocument *doc) {
+ return new GitDiffEditorController(doc, {}, {}, {"--", fileName});
+ });
}
void GitClient::diffBranch(const QString &workingDirectory, const QString &branchName) const
@@ -1007,7 +1017,9 @@ void GitClient::diffBranch(const QString &workingDirectory, const QString &branc
const QString documentId = QLatin1String(Constants::GIT_PLUGIN)
+ QLatin1String(".DiffBranch.") + branchName;
requestReload(documentId, workingDirectory, title, workingDirectory,
- [branchName](IDocument *doc) { return new BranchDiffController(doc, branchName); });
+ [branchName](IDocument *doc) {
+ return new GitDiffEditorController(doc, branchName, {}, {});
+ });
}
void GitClient::merge(const QString &workingDirectory,
@@ -1018,7 +1030,7 @@ void GitClient::merge(const QString &workingDirectory,
delete mergeTool;
}
-void GitClient::status(const QString &workingDirectory)
+void GitClient::status(const QString &workingDirectory) const
{
VcsOutputWindow::setRepository(workingDirectory);
VcsCommand *command = vcsExec(workingDirectory, {"status", "-u"}, nullptr, true);
@@ -1026,6 +1038,29 @@ void GitClient::status(const QString &workingDirectory)
Qt::QueuedConnection);
}
+static QStringList normalLogArguments()
+{
+ if (!gitHasRgbColors())
+ return {};
+
+ auto colorName = [](Theme::Color color) { return creatorTheme()->color(color).name(); };
+ const QString authorName = colorName(Theme::Git_AuthorName_TextColor);
+ const QString commitDate = colorName(Theme::Git_CommitDate_TextColor);
+ const QString commitHash = colorName(Theme::Git_CommitHash_TextColor);
+ const QString commitSubject = colorName(Theme::Git_CommitSubject_TextColor);
+ const QString decoration = colorName(Theme::Git_Decoration_TextColor);
+
+ const QString logArgs = QStringLiteral(
+ "--pretty=format:"
+ "commit %C(%1)%H%Creset %C(%2)%d%Creset%n"
+ "Author: %C(%3)%an <%ae>%Creset%n"
+ "Date: %C(%4)%cD%Creset%n%n"
+ "%C(%5)%s%Creset%n%n%b%n"
+ ).arg(commitHash, decoration, authorName, commitDate, commitSubject);
+
+ return {logArgs};
+}
+
void GitClient::log(const QString &workingDirectory, const QString &fileName,
bool enableAnnotationContextMenu, const QStringList &args)
{
@@ -1055,12 +1090,21 @@ void GitClient::log(const QString &workingDirectory, const QString &fileName,
editor->setFileLogAnnotateEnabled(enableAnnotationContextMenu);
editor->setWorkingDirectory(workingDir);
- QStringList arguments = {"log", noColorOption, decorateOption};
+ QStringList arguments = {"log", decorateOption};
int logCount = settings().intValue(GitSettings::logCountKey);
if (logCount > 0)
arguments << "-n" << QString::number(logCount);
arguments << argWidget->arguments();
+ if (arguments.contains(patchOption)) {
+ arguments.removeAll(colorOption);
+ editor->setHighlightingEnabled(true);
+ } else if (gitHasRgbColors()) {
+ editor->setHighlightingEnabled(false);
+ }
+ if (!arguments.contains(graphOption) && !arguments.contains(patchOption))
+ arguments << normalLogArguments();
+
const QString grepValue = editor->grepValue();
if (!grepValue.isEmpty())
arguments << "--grep=" + grepValue;
@@ -1285,7 +1329,9 @@ QStringList GitClient::setupCheckoutArguments(const QString &workingDirectory,
}
}
+ const QString suggestedName = suggestedLocalBranchName(localBranches, remoteBranch);
BranchAddDialog branchAddDialog(localBranches, BranchAddDialog::Type::AddBranch, ICore::dialogParent());
+ branchAddDialog.setBranchName(suggestedName);
branchAddDialog.setTrackedBranchName(remoteBranch, true);
if (branchAddDialog.exec() != QDialog::Accepted)
@@ -2431,7 +2477,7 @@ QStringList GitClient::synchronousRepositoryBranches(const QString &repositoryUR
return branches;
}
-void GitClient::launchGitK(const QString &workingDirectory, const QString &fileName)
+void GitClient::launchGitK(const QString &workingDirectory, const QString &fileName) const
{
const QFileInfo binaryInfo = vcsBinary().toFileInfo();
QDir foundBinDir(binaryInfo.dir());
@@ -2467,7 +2513,7 @@ void GitClient::launchGitK(const QString &workingDirectory, const QString &fileN
VcsOutputWindow::appendError(msgCannotLaunch("gitk"));
}
-void GitClient::launchRepositoryBrowser(const QString &workingDirectory)
+void GitClient::launchRepositoryBrowser(const QString &workingDirectory) const
{
const QString repBrowserBinary = settings().stringValue(GitSettings::repositoryBrowserCmd);
if (!repBrowserBinary.isEmpty())
@@ -2477,7 +2523,7 @@ void GitClient::launchRepositoryBrowser(const QString &workingDirectory)
bool GitClient::tryLauchingGitK(const QProcessEnvironment &env,
const QString &workingDirectory,
const QString &fileName,
- const QString &gitBinDirectory)
+ const QString &gitBinDirectory) const
{
QString binary = gitBinDirectory + "/gitk";
QStringList arguments;
@@ -2499,7 +2545,7 @@ bool GitClient::tryLauchingGitK(const QProcessEnvironment &env,
// the child), but that does not have an environment parameter.
bool success = false;
if (!settings().stringValue(GitSettings::pathKey).isEmpty()) {
- auto process = new QProcess(this);
+ auto process = new QProcess;
process->setWorkingDirectory(workingDirectory);
process->setProcessEnvironment(env);
process->start(binary, arguments);
@@ -2559,6 +2605,24 @@ FilePath GitClient::gitBinDirectory() const
return FilePath::fromString(path);
}
+bool GitClient::launchGitBash(const QString &workingDirectory)
+{
+ bool success = true;
+ const QString git = vcsBinary().toString();
+
+ if (git.isEmpty()) {
+ success = false;
+ } else {
+ const QString gitBash = QFileInfo(git).absolutePath() + "/../git-bash.exe";
+ success = QProcess::startDetached(gitBash, {}, workingDirectory);
+ }
+
+ if (!success)
+ VcsOutputWindow::appendError(msgCannotLaunch("git-bash"));
+
+ return success;
+}
+
FilePath GitClient::vcsBinary() const
{
bool ok;
@@ -3116,7 +3180,7 @@ void GitClient::addFuture(const QFuture<void> &future)
}
// Subversion: git svn
-void GitClient::synchronousSubversionFetch(const QString &workingDirectory)
+void GitClient::synchronousSubversionFetch(const QString &workingDirectory) const
{
// Disable UNIX terminals to suppress SSH prompting.
const unsigned flags = VcsCommand::SshPasswordPrompt
@@ -3125,7 +3189,7 @@ void GitClient::synchronousSubversionFetch(const QString &workingDirectory)
vcsSynchronousExec(workingDirectory, {"svn", "fetch"}, flags);
}
-void GitClient::subversionLog(const QString &workingDirectory)
+void GitClient::subversionLog(const QString &workingDirectory) const
{
QStringList arguments = {"svn", "log"};
int logCount = settings().intValue(GitSettings::logCountKey);
@@ -3142,7 +3206,7 @@ void GitClient::subversionLog(const QString &workingDirectory)
vcsExec(workingDirectory, arguments, editor);
}
-void GitClient::subversionDeltaCommit(const QString &workingDirectory)
+void GitClient::subversionDeltaCommit(const QString &workingDirectory) const
{
vcsExec(workingDirectory, {"svn", "dcommit"}, nullptr, true,
VcsCommand::ShowSuccessMessage);
@@ -3596,6 +3660,20 @@ GitRemote::GitRemote(const QString &location) : Core::IVersionControl::RepoUrl(l
isValid = QDir(path).exists() || QDir(path + ".git").exists();
}
+QString GitClient::suggestedLocalBranchName(const QStringList localNames,
+ const QString trackedBranch)
+{
+ const QString suggestedNameBase = trackedBranch.mid(trackedBranch.lastIndexOf('/') + 1);
+ QString suggestedName = suggestedNameBase;
+ int i = 2;
+ while (localNames.contains(suggestedName)) {
+ suggestedName = suggestedNameBase + QString::number(i);
+ ++i;
+ }
+
+ return suggestedName;
+}
+
void GitClient::addChangeActions(QMenu *menu, const QString &workingDir, const QString &change)
{
QTC_ASSERT(!change.isEmpty(), return);
@@ -3646,6 +3724,21 @@ void GitClient::addChangeActions(QMenu *menu, const QString &workingDir, const Q
resetMenu->addAction(tr("&Mixed"), std::bind(resetChange, "mixed"));
resetMenu->addAction(tr("&Soft"), std::bind(resetChange, "soft"));
menu->addMenu(resetMenu);
+
+ menu->addAction(tr("Di&ff Against %1").arg(change),
+ [workingDir, change] {
+ m_instance->diffRepository(workingDir, change, {});
+ });
+ if (!m_instance->m_diffCommit.isEmpty()) {
+ menu->addAction(tr("Diff &Against Saved %1").arg(m_instance->m_diffCommit),
+ [workingDir, change] {
+ m_instance->diffRepository(workingDir, m_instance->m_diffCommit, change);
+ m_instance->m_diffCommit.clear();
+ });
+ }
+ menu->addAction(tr("&Save for Diff"), [change] {
+ m_instance->m_diffCommit = change;
+ });
}
} // namespace Internal
diff --git a/src/plugins/git/gitclient.h b/src/plugins/git/gitclient.h
index c159fb3137..72ca26455f 100644
--- a/src/plugins/git/gitclient.h
+++ b/src/plugins/git/gitclient.h
@@ -160,12 +160,18 @@ public:
const QStringList &stagedFileNames) const;
void diffProject(const QString &workingDirectory,
const QString &projectDirectory) const;
- void diffRepository(const QString &workingDirectory);
+ void diffRepository(const QString &workingDirectory) const
+ {
+ return diffRepository(workingDirectory, {}, {});
+ }
+ void diffRepository(const QString &workingDirectory,
+ const QString &leftCommit,
+ const QString &rightCommit) const;
void diffBranch(const QString &workingDirectory,
const QString &branchName) const;
void merge(const QString &workingDirectory, const QStringList &unmergedFileNames = QStringList());
- void status(const QString &workingDirectory);
+ void status(const QString &workingDirectory) const;
void log(const QString &workingDirectory, const QString &fileName = QString(),
bool enableAnnotationContextMenu = false, const QStringList &args = QStringList());
void reflog(const QString &workingDirectory, const QString &branch = {});
@@ -284,9 +290,9 @@ public:
const QString &tracking);
// git svn support (asynchronous).
- void synchronousSubversionFetch(const QString &workingDirectory);
- void subversionLog(const QString &workingDirectory);
- void subversionDeltaCommit(const QString &workingDirectory);
+ void synchronousSubversionFetch(const QString &workingDirectory) const;
+ void subversionLog(const QString &workingDirectory) const;
+ void subversionDeltaCommit(const QString &workingDirectory) const;
void stashPop(const QString &workingDirectory, const QString &stash = QString());
void revert(const QStringList &files, bool revertStaging);
@@ -326,12 +332,13 @@ public:
QString extendedShowDescription(const QString &workingDirectory, const QString &text) const;
- void launchGitK(const QString &workingDirectory, const QString &fileName);
- void launchGitK(const QString &workingDirectory) { launchGitK(workingDirectory, QString()); }
+ void launchGitK(const QString &workingDirectory, const QString &fileName) const;
+ void launchGitK(const QString &workingDirectory) const { launchGitK(workingDirectory, QString()); }
bool launchGitGui(const QString &workingDirectory);
Utils::FilePath gitBinDirectory() const;
+ bool launchGitBash(const QString &workingDirectory);
- void launchRepositoryBrowser(const QString &workingDirectory);
+ void launchRepositoryBrowser(const QString &workingDirectory) const;
QStringList synchronousRepositoryBranches(const QString &repositoryURL,
const QString &workingDirectory = QString()) const;
@@ -354,6 +361,8 @@ public:
VcsBase::VcsCommand *asyncUpstreamStatus(const QString &workingDirectory,
const QString &branch, const QString &upstream);
+ static QString suggestedLocalBranchName(const QStringList existingLocalNames,
+ const QString trackedBranch);
static void addChangeActions(QMenu *menu, const QString &workingDir, const QString &change);
private:
@@ -386,7 +395,7 @@ private:
bool tryLauchingGitK(const QProcessEnvironment &env,
const QString &workingDirectory,
const QString &fileName,
- const QString &gitBinDirectory);
+ const QString &gitBinDirectory) const;
bool cleanList(const QString &workingDirectory, const QString &modulePath, const QString &flag, QStringList *files, QString *errorMessage);
enum ContinueCommandMode {
@@ -405,6 +414,7 @@ private:
QString m_gitQtcEditor;
QMap<QString, StashInfo> m_stashInfo;
QString m_pushFallbackCommand;
+ QString m_diffCommit;
QStringList m_updatedSubmodules;
bool m_disableEditor;
QFutureSynchronizer<void> m_synchronizer; // for commit updates
diff --git a/src/plugins/git/giteditor.cpp b/src/plugins/git/giteditor.cpp
index 24acb25861..77d07d1258 100644
--- a/src/plugins/git/giteditor.cpp
+++ b/src/plugins/git/giteditor.cpp
@@ -38,6 +38,7 @@
#include <vcsbase/vcsbaseeditorconfig.h>
#include <vcsbase/vcsoutputwindow.h>
+#include <utils/ansiescapecodehandler.h>
#include <utils/qtcassert.h>
#include <utils/temporaryfile.h>
@@ -205,6 +206,20 @@ void GitEditorWidget::setPlainText(const QString &text)
// If desired, filter out the date from annotation
switch (contentType())
{
+ case LogOutput: {
+ Utils::AnsiEscapeCodeHandler handler;
+ const QList<Utils::FormattedText> formattedTextList
+ = handler.parseText(Utils::FormattedText(text));
+
+ clear();
+ QTextCursor cursor = textCursor();
+ cursor.beginEditBlock();
+ for (auto formattedChunk : formattedTextList)
+ cursor.insertText(formattedChunk.text, formattedChunk.format);
+ cursor.endEditBlock();
+
+ return;
+ }
case AnnotateOutput:
modText = sanitizeBlameOutput(text);
break;
diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp
index dfaeb44f45..82647053b7 100644
--- a/src/plugins/git/gitplugin.cpp
+++ b/src/plugins/git/gitplugin.cpp
@@ -103,7 +103,7 @@ using namespace std::placeholders;
namespace Git {
namespace Internal {
-using GitClientMemberFunc = void (GitClient::*)(const QString &);
+using GitClientMemberFunc = void (GitClient::*)(const QString &) const;
class GitTopicCache : public Core::IVersionControl::TopicCache
{
@@ -303,6 +303,7 @@ public:
void gitkForCurrentFile();
void gitkForCurrentFolder();
void gitGui();
+ void gitBash();
void cleanProject();
void cleanRepository();
void updateSubmodules();
@@ -962,6 +963,14 @@ GitPluginPrivate::GitPluginPrivate()
= createRepositoryAction(gitToolsMenu, tr("Merge Tool"), "Git.MergeTool",
context, true, std::bind(&GitPluginPrivate::startMergeTool, this));
+ // --------------
+ if (Utils::HostOsInfo::isWindowsHost()) {
+ gitToolsMenu->addSeparator(context);
+
+ createRepositoryAction(gitToolsMenu, tr("Git Bash"), "Git.GitBash",
+ context, true, std::bind(&GitPluginPrivate::gitBash, this));
+ }
+
/* \"Git Tools" menu */
// --------------
@@ -1201,7 +1210,9 @@ void GitPluginPrivate::startChangeRelatedAction(const Id &id)
if (dialog.command() == Show) {
m_gitClient.show(workingDirectory, change);
return;
- } else if (dialog.command() == Archive) {
+ }
+
+ if (dialog.command() == Archive) {
m_gitClient.archive(workingDirectory, change);
return;
}
@@ -1282,6 +1293,13 @@ void GitPluginPrivate::gitGui()
m_gitClient.launchGitGui(state.topLevel());
}
+void GitPluginPrivate::gitBash()
+{
+ const VcsBasePluginState state = currentState();
+ QTC_ASSERT(state.hasTopLevel(), return);
+ m_gitClient.launchGitBash(state.topLevel());
+}
+
void GitPluginPrivate::startCommit(CommitType commitType)
{
if (!promptBeforeCommit())
diff --git a/src/plugins/git/gitsettings.cpp b/src/plugins/git/gitsettings.cpp
index 030fe848cc..39b0cbaffe 100644
--- a/src/plugins/git/gitsettings.cpp
+++ b/src/plugins/git/gitsettings.cpp
@@ -44,6 +44,7 @@ const QLatin1String GitSettings::gitkOptionsKey("GitKOptions");
const QLatin1String GitSettings::logDiffKey("LogDiff");
const QLatin1String GitSettings::repositoryBrowserCmd("RepositoryBrowserCmd");
const QLatin1String GitSettings::graphLogKey("GraphLog");
+const QLatin1String GitSettings::colorLogKey("ColorLog");
const QLatin1String GitSettings::firstParentKey("FirstParent");
const QLatin1String GitSettings::followRenamesKey("FollowRenames");
const QLatin1String GitSettings::lastResetIndexKey("LastResetIndex");
@@ -67,6 +68,7 @@ GitSettings::GitSettings()
declareKey(logDiffKey, false);
declareKey(repositoryBrowserCmd, QString());
declareKey(graphLogKey, false);
+ declareKey(colorLogKey, true);
declareKey(firstParentKey, false);
declareKey(followRenamesKey, true);
declareKey(lastResetIndexKey, 0);
diff --git a/src/plugins/git/gitsettings.h b/src/plugins/git/gitsettings.h
index 8117011b2d..521bb91dbf 100644
--- a/src/plugins/git/gitsettings.h
+++ b/src/plugins/git/gitsettings.h
@@ -55,6 +55,7 @@ public:
static const QLatin1String logDiffKey;
static const QLatin1String repositoryBrowserCmd;
static const QLatin1String graphLogKey;
+ static const QLatin1String colorLogKey;
static const QLatin1String firstParentKey;
static const QLatin1String followRenamesKey;
static const QLatin1String lastResetIndexKey;
diff --git a/src/plugins/git/gitsubmiteditorwidget.cpp b/src/plugins/git/gitsubmiteditorwidget.cpp
index 32ffe106f6..308b34fba6 100644
--- a/src/plugins/git/gitsubmiteditorwidget.cpp
+++ b/src/plugins/git/gitsubmiteditorwidget.cpp
@@ -33,7 +33,7 @@
#include <utils/theme/theme.h>
#include <utils/utilsicons.h>
-#include <QRegExpValidator>
+#include <QRegularExpressionValidator>
#include <QTextEdit>
#include <QDir>
@@ -52,7 +52,7 @@ GitSubmitEditorWidget::GitSubmitEditorWidget() :
m_gitSubmitPanelUi.setupUi(m_gitSubmitPanel);
new GitSubmitHighlighter(descriptionEdit());
- m_emailValidator = new QRegExpValidator(QRegExp("[^@ ]+@[^@ ]+\\.[a-zA-Z]+"), this);
+ m_emailValidator = new QRegularExpressionValidator(QRegularExpression("[^@ ]+@[^@ ]+\\.[a-zA-Z]+"), this);
const QPixmap error = Utils::Icons::CRITICAL.pixmap();
m_gitSubmitPanelUi.invalidAuthorLabel->setPixmap(error);
m_gitSubmitPanelUi.invalidEmailLabel->setToolTip(tr("Provide a valid email to commit."));
diff --git a/src/plugins/git/remotedialog.cpp b/src/plugins/git/remotedialog.cpp
index 912c1be4d9..6d211e0c7c 100644
--- a/src/plugins/git/remotedialog.cpp
+++ b/src/plugins/git/remotedialog.cpp
@@ -53,6 +53,7 @@ public:
m_remoteNames(remoteNames)
{
m_ui.setupUi(this);
+ m_ui.nameEdit->setHistoryCompleter("Git.RemoteNames");
m_ui.nameEdit->setValidationFunction([this](Utils::FancyLineEdit *edit, QString *errorMessage) {
if (!edit)
return false;
@@ -84,6 +85,7 @@ public:
m_ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(m_ui.nameEdit->isValid());
});
+ m_ui.urlEdit->setHistoryCompleter("Git.RemoteUrls");
m_ui.urlEdit->setValidationFunction([](Utils::FancyLineEdit *edit, QString *errorMessage) {
if (!edit || edit->text().isEmpty())
return false;
diff --git a/src/plugins/help/CMakeLists.txt b/src/plugins/help/CMakeLists.txt
index a671186263..4d5fd23283 100644
--- a/src/plugins/help/CMakeLists.txt
+++ b/src/plugins/help/CMakeLists.txt
@@ -27,6 +27,11 @@ add_qtc_plugin(Help
)
extend_qtc_plugin(Help
+ CONDITION Qt5_VERSION VERSION_GREATER_EQUAL 5.15.0
+ DEFINES HELP_NEW_FILTER_ENGINE
+)
+
+extend_qtc_plugin(Help
CONDITION FWWebKit AND FWAppKit
FEATURE_INFO "Native WebKit help viewer"
DEPENDS ${FWWebKit} ${FWAppKit}
diff --git a/src/plugins/help/docsettingspage.cpp b/src/plugins/help/docsettingspage.cpp
index 86cf3b6515..66fba5f211 100644
--- a/src/plugins/help/docsettingspage.cpp
+++ b/src/plugins/help/docsettingspage.cpp
@@ -291,6 +291,7 @@ bool DocSettingsPageWidget::eventFilter(QObject *object, QEvent *event)
if (event->type() == QEvent::KeyPress) {
auto ke = static_cast<const QKeyEvent*>(event);
switch (ke->key()) {
+ case Qt::Key_Backspace:
case Qt::Key_Delete:
removeDocumentation(currentSelection());
break;
diff --git a/src/plugins/help/filtersettingspage.cpp b/src/plugins/help/filtersettingspage.cpp
index cfd184dfc9..805ab844ed 100644
--- a/src/plugins/help/filtersettingspage.cpp
+++ b/src/plugins/help/filtersettingspage.cpp
@@ -24,8 +24,10 @@
****************************************************************************/
#include "filtersettingspage.h"
-
#include "helpconstants.h"
+
+#ifndef HELP_NEW_FILTER_ENGINE
+
#include "helpmanager.h"
#include <filternamedialog.h>
@@ -38,6 +40,15 @@
#include <QFileDialog>
#include <QMessageBox>
+#else
+
+#include <QtCore/QVersionNumber>
+#include <QtHelp/QHelpFilterEngine>
+#include <QtHelp/QHelpFilterSettingsWidget>
+#include "localhelpmanager.h"
+
+#endif
+
using namespace Help::Internal;
FilterSettingsPage::FilterSettingsPage()
@@ -47,6 +58,8 @@ FilterSettingsPage::FilterSettingsPage()
setCategory(Help::Constants::HELP_CATEGORY);
}
+#ifndef HELP_NEW_FILTER_ENGINE
+
QWidget *FilterSettingsPage::widget()
{
if (!m_widget) {
@@ -254,3 +267,48 @@ void FilterSettingsPage::updateFilterDescription(const QString &filter)
{
m_ui.label->setText(msgFilterLabel(filter));
}
+
+#else
+
+QWidget *FilterSettingsPage::widget()
+{
+ if (!m_widget) {
+ LocalHelpManager::setupGuiHelpEngine();
+ m_widget = new QHelpFilterSettingsWidget(nullptr);
+ m_widget->readSettings(LocalHelpManager::filterEngine());
+
+ connect(Core::HelpManager::Signals::instance(),
+ &Core::HelpManager::Signals::documentationChanged,
+ this,
+ &FilterSettingsPage::updateFilterPage);
+
+ updateFilterPage();
+ }
+ return m_widget;
+}
+
+void FilterSettingsPage::apply()
+{
+ if (m_widget->applySettings(LocalHelpManager::filterEngine()))
+ emit filtersChanged();
+
+ m_widget->readSettings(LocalHelpManager::filterEngine());
+}
+
+void FilterSettingsPage::finish()
+{
+ disconnect(Core::HelpManager::Signals::instance(),
+ &Core::HelpManager::Signals::documentationChanged,
+ this,
+ &FilterSettingsPage::updateFilterPage);
+ delete m_widget;
+}
+
+void FilterSettingsPage::updateFilterPage()
+{
+ m_widget->setAvailableComponents(LocalHelpManager::filterEngine()->availableComponents());
+ m_widget->setAvailableVersions(LocalHelpManager::filterEngine()->availableVersions());
+}
+
+#endif
+
diff --git a/src/plugins/help/filtersettingspage.h b/src/plugins/help/filtersettingspage.h
index 4d5d102107..6d98f096d8 100644
--- a/src/plugins/help/filtersettingspage.h
+++ b/src/plugins/help/filtersettingspage.h
@@ -25,11 +25,16 @@
#pragma once
-#include "ui_filtersettingspage.h"
#include <coreplugin/dialogs/ioptionspage.h>
#include <QPointer>
+#ifndef HELP_NEW_FILTER_ENGINE
+#include "ui_filtersettingspage.h"
+#else
+class QHelpFilterSettingsWidget;
+#endif
+
namespace Help {
namespace Internal {
@@ -48,9 +53,11 @@ signals:
void filtersChanged();
private:
+
+ void updateFilterPage();
+#ifndef HELP_NEW_FILTER_ENGINE
void updateAttributes(QListWidgetItem *item);
void updateFilterMap();
- void updateFilterPage();
void addFilter();
void removeFilter();
void updateFilterDescription(const QString &filter);
@@ -64,6 +71,10 @@ private:
FilterMap m_filterMapBackup;
QStringList m_removedFilters;
+#else
+ QPointer<QHelpFilterSettingsWidget> m_widget;
+#endif
+
};
} // namespace Help
diff --git a/src/plugins/help/help.pro b/src/plugins/help/help.pro
index 7b58578ef1..1299eb6384 100644
--- a/src/plugins/help/help.pro
+++ b/src/plugins/help/help.pro
@@ -4,6 +4,10 @@ INCLUDEPATH += $$PWD
include(../../qtcreatorplugin.pri)
+minQtVersion(5, 15, 0) {
+DEFINES += HELP_NEW_FILTER_ENGINE
+}
+
DEFINES += \
QT_CLUCENE_SUPPORT \
HELP_LIBRARY
diff --git a/src/plugins/help/help.qbs b/src/plugins/help/help.qbs
index e1268e729d..2eea437473 100644
--- a/src/plugins/help/help.qbs
+++ b/src/plugins/help/help.qbs
@@ -1,4 +1,4 @@
-import qbs 1.0
+import qbs.Utilities
Project {
name: "Help"
@@ -28,6 +28,8 @@ Project {
defines.push("QTC_WEBENGINE_HELPVIEWER");
if (qlitehtml.present)
defines.push("QTC_LITEHTML_HELPVIEWER")
+ if (Utilities.versionCompare(Qt.core.version, "5.15") >= 0)
+ defines.push("HELP_NEW_FILTER_ENGINE");
return defines;
}
diff --git a/src/plugins/help/helpindexfilter.cpp b/src/plugins/help/helpindexfilter.cpp
index c58c654320..7b51f8812c 100644
--- a/src/plugins/help/helpindexfilter.cpp
+++ b/src/plugins/help/helpindexfilter.cpp
@@ -32,15 +32,27 @@
#include <coreplugin/icore.h>
#include <coreplugin/helpmanager.h>
#include <extensionsystem/pluginmanager.h>
-#include <utils/algorithm.h>
#include <utils/utilsicons.h>
#include <QIcon>
+
+#ifndef HELP_NEW_FILTER_ENGINE
+
+#include <utils/algorithm.h>
+
#include <QSqlDatabase>
#include <QSqlDriver>
#include <QSqlError>
#include <QSqlQuery>
+#else
+
+#include "localhelpmanager.h"
+#include <QtHelp/QHelpEngine>
+#include <QtHelp/QHelpFilterEngine>
+#include <QtHelp/QHelpLink>
+
+#endif
using namespace Core;
using namespace Help;
@@ -66,6 +78,8 @@ HelpIndexFilter::HelpIndexFilter()
HelpIndexFilter::~HelpIndexFilter() = default;
+#ifndef HELP_NEW_FILTER_ENGINE
+
void HelpIndexFilter::prepareSearch(const QString &entry)
{
Q_UNUSED(entry)
@@ -133,6 +147,70 @@ QList<LocatorFilterEntry> HelpIndexFilter::matchesFor(QFutureInterface<LocatorFi
return entries;
}
+#else
+
+bool HelpIndexFilter::updateCache(QFutureInterface<LocatorFilterEntry> &future,
+ const QStringList &cache, const QString &entry)
+{
+ const Qt::CaseSensitivity cs = caseSensitivity(entry);
+ QStringList bestKeywords;
+ QStringList worseKeywords;
+ bestKeywords.reserve(cache.size());
+ worseKeywords.reserve(cache.size());
+ for (const QString &keyword : cache) {
+ if (future.isCanceled())
+ return false;
+ if (keyword.startsWith(entry, cs))
+ bestKeywords.append(keyword);
+ else if (keyword.contains(entry, cs))
+ worseKeywords.append(keyword);
+ }
+ bestKeywords << worseKeywords;
+ m_lastIndicesCache = bestKeywords;
+ m_lastEntry = entry;
+
+ return true;
+}
+
+QList<LocatorFilterEntry> HelpIndexFilter::matchesFor(QFutureInterface<LocatorFilterEntry> &future, const QString &entry)
+{
+ m_mutex.lock(); // guard m_needsUpdate
+ bool forceUpdate = m_needsUpdate;
+ m_mutex.unlock();
+
+ if (forceUpdate) {
+ QStringList indices;
+ QMetaObject::invokeMethod(this, "allIndices", Qt::BlockingQueuedConnection,
+ Q_RETURN_ARG(QStringList, indices));
+ m_mutex.lock(); // guard m_needsUpdate
+ m_needsUpdate = false;
+ m_mutex.unlock();
+ m_allIndicesCache = indices;
+ // force updating the cache taking the m_allIndicesCache
+ m_lastIndicesCache = QStringList();
+ m_lastEntry = QString();
+ }
+
+ const QStringList cacheBase = m_lastEntry.isEmpty() || !entry.contains(m_lastEntry)
+ ? m_allIndicesCache : m_lastIndicesCache;
+
+ if (!updateCache(future, cacheBase, entry))
+ return QList<LocatorFilterEntry>();
+
+ const Qt::CaseSensitivity cs = caseSensitivity(entry);
+ QList<LocatorFilterEntry> entries;
+ for (const QString &keyword : qAsConst(m_lastIndicesCache)) {
+ const int index = keyword.indexOf(entry, 0, cs);
+ LocatorFilterEntry filterEntry(this, keyword, QVariant(), m_icon);
+ filterEntry.highlightInfo = {index, entry.length()};
+ entries.append(filterEntry);
+ }
+
+ return entries;
+}
+
+#endif
+
void HelpIndexFilter::accept(LocatorFilterEntry selection,
QString *newText, int *selectionStart, int *selectionLength) const
{
@@ -140,7 +218,14 @@ void HelpIndexFilter::accept(LocatorFilterEntry selection,
Q_UNUSED(selectionStart)
Q_UNUSED(selectionLength)
const QString &key = selection.displayName;
- const QMap<QString, QUrl> &links = HelpManager::instance()->linksForKeyword(key);
+#ifndef HELP_NEW_FILTER_ENGINE
+ const QMultiMap<QString, QUrl> &links = HelpManager::instance()->linksForKeyword(key);
+#else
+ QMultiMap<QString, QUrl> links;
+ const QList<QHelpLink> docs = LocalHelpManager::helpEngine().documentsForKeyword(key, QString());
+ for (const auto doc : docs)
+ links.insert(doc.title, doc.url);
+#endif
emit linksActivated(links, key);
}
@@ -150,6 +235,8 @@ void HelpIndexFilter::refresh(QFutureInterface<void> &future)
invalidateCache();
}
+#ifndef HELP_NEW_FILTER_ENGINE
+
QSet<QString> HelpIndexFilter::searchMatches(const QString &databaseFilePath,
const QString &term, int limit)
{
@@ -180,6 +267,16 @@ QSet<QString> HelpIndexFilter::searchMatches(const QString &databaseFilePath,
return keywords;
}
+#else
+
+QStringList HelpIndexFilter::allIndices() const
+{
+ LocalHelpManager::setupGuiHelpEngine();
+ return LocalHelpManager::filterEngine()->indices(QString());
+}
+
+#endif
+
void HelpIndexFilter::invalidateCache()
{
m_mutex.lock();
diff --git a/src/plugins/help/helpindexfilter.h b/src/plugins/help/helpindexfilter.h
index 04873fe958..40c19d54a8 100644
--- a/src/plugins/help/helpindexfilter.h
+++ b/src/plugins/help/helpindexfilter.h
@@ -42,24 +42,38 @@ public:
~HelpIndexFilter() final;
// ILocatorFilter
- void prepareSearch(const QString &entry) override;
QList<Core::LocatorFilterEntry> matchesFor(QFutureInterface<Core::LocatorFilterEntry> &future,
const QString &entry) override;
void accept(Core::LocatorFilterEntry selection,
QString *newText, int *selectionStart, int *selectionLength) const override;
void refresh(QFutureInterface<void> &future) override;
+#ifndef HELP_NEW_FILTER_ENGINE
+ void prepareSearch(const QString &entry) override;
Q_INVOKABLE QSet<QString> searchMatches(const QString &databaseFilePath,
const QString &term, int limit);
+#else
+ Q_INVOKABLE QStringList allIndices() const;
+#endif
+
signals:
- void linksActivated(const QMap<QString, QUrl> &links, const QString &key) const;
+ void linksActivated(const QMultiMap<QString, QUrl> &links, const QString &key) const;
private:
void invalidateCache();
+#ifndef HELP_NEW_FILTER_ENGINE
QStringList m_helpDatabases;
QSet<QString> m_keywordCache;
QString m_searchTermCache;
+#else
+ bool updateCache(QFutureInterface<Core::LocatorFilterEntry> &future,
+ const QStringList &cache, const QString &entry);
+
+ QStringList m_allIndicesCache;
+ QStringList m_lastIndicesCache;
+ QString m_lastEntry;
+#endif
bool m_needsUpdate = true;
QMutex m_mutex;
QIcon m_icon;
diff --git a/src/plugins/help/helpmanager.cpp b/src/plugins/help/helpmanager.cpp
index 09fdc041fe..4fff954512 100644
--- a/src/plugins/help/helpmanager.cpp
+++ b/src/plugins/help/helpmanager.cpp
@@ -43,10 +43,15 @@
#include <QHelpEngineCore>
#include <QMutexLocker>
+
+#ifndef HELP_NEW_FILTER_ENGINE
#include <QSqlDatabase>
#include <QSqlDriver>
#include <QSqlError>
#include <QSqlQuery>
+#else
+#include <QtHelp/QHelpLink>
+#endif
using namespace Core;
@@ -84,6 +89,8 @@ struct HelpManagerPrivate
static HelpManager *m_instance = nullptr;
static HelpManagerPrivate *d = nullptr;
+#ifndef HELP_NEW_FILTER_ENGINE
+
// -- DbCleaner
struct DbCleaner
@@ -93,6 +100,8 @@ struct DbCleaner
QString name;
};
+#endif
+
// -- HelpManager
HelpManager::HelpManager(QObject *parent) :
@@ -225,20 +234,36 @@ QSet<QString> HelpManager::userDocumentationPaths()
}
// This should go into Qt 4.8 once we start using it for Qt Creator
-QMap<QString, QUrl> HelpManager::linksForKeyword(const QString &key)
+QMultiMap<QString, QUrl> HelpManager::linksForKeyword(const QString &key)
{
QTC_ASSERT(!d->m_needsSetup, return {});
if (key.isEmpty())
return {};
+#ifndef HELP_NEW_FILTER_ENGINE
return d->m_helpEngine->linksForKeyword(key);
+#else
+ QMultiMap<QString, QUrl> links;
+ const QList<QHelpLink> docs = d->m_helpEngine->documentsForKeyword(key, QString());
+ for (const auto doc : docs)
+ links.insert(doc.title, doc.url);
+ return links;
+#endif
}
-QMap<QString, QUrl> HelpManager::linksForIdentifier(const QString &id)
+QMultiMap<QString, QUrl> HelpManager::linksForIdentifier(const QString &id)
{
QTC_ASSERT(!d->m_needsSetup, return {});
if (id.isEmpty())
return {};
+#ifndef HELP_NEW_FILTER_ENGINE
return d->m_helpEngine->linksForIdentifier(id);
+#else
+ QMultiMap<QString, QUrl> links;
+ const QList<QHelpLink> docs = d->m_helpEngine->documentsForIdentifier(id, QString());
+ for (const auto doc : docs)
+ links.insert(doc.title, doc.url);
+ return links;
+#endif
}
QUrl HelpManager::findFile(const QUrl &url)
@@ -292,6 +317,8 @@ QVariant HelpManager::customValue(const QString &key, const QVariant &value)
return d->m_helpEngine->customValue(key, value);
}
+#ifndef HELP_NEW_FILTER_ENGINE
+
HelpManager::Filters HelpManager::filters()
{
QTC_ASSERT(!d->m_needsSetup, return {});
@@ -358,6 +385,8 @@ void HelpManager::addUserDefinedFilter(const QString &filter, const QStringList
emit m_instance->collectionFileChanged();
}
+#endif
+
void HelpManager::aboutToShutdown()
{
if (d && d->m_registerFuture.isRunning()) {
@@ -378,6 +407,9 @@ void HelpManager::setupHelpManager()
// create the help engine
d->m_helpEngine = new QHelpEngineCore(collectionFilePath(), m_instance);
+#ifdef HELP_NEW_FILTER_ENGINE
+ d->m_helpEngine->setUsesFilterEngine(true);
+#endif
d->m_helpEngine->setupData();
for (const QString &filePath : d->documentationFromInstaller())
diff --git a/src/plugins/help/helpmanager.h b/src/plugins/help/helpmanager.h
index bcde6b794c..6edaae859b 100644
--- a/src/plugins/help/helpmanager.h
+++ b/src/plugins/help/helpmanager.h
@@ -40,8 +40,6 @@ class HelpManager : public QObject, public Core::HelpManager::Implementation
Q_OBJECT
public:
- using Filters = QHash<QString, QStringList>;
-
explicit HelpManager(QObject *parent = nullptr);
~HelpManager() override;
@@ -56,8 +54,8 @@ public:
static void registerUserDocumentation(const QStringList &filePaths);
static QSet<QString> userDocumentationPaths();
- QMap<QString, QUrl> linksForIdentifier(const QString &id) override;
- QMap<QString, QUrl> linksForKeyword(const QString &key) override;
+ QMultiMap<QString, QUrl> linksForIdentifier(const QString &id) override;
+ QMultiMap<QString, QUrl> linksForKeyword(const QString &key) override;
static QUrl findFile(const QUrl &url);
QByteArray fileData(const QUrl &url) override;
@@ -69,12 +67,16 @@ public:
static void setCustomValue(const QString &key, const QVariant &value);
static QVariant customValue(const QString &key, const QVariant &value = QVariant());
+#ifndef HELP_NEW_FILTER_ENGINE
+ using Filters = QHash<QString, QStringList>;
+
static Filters filters();
static Filters fixedFilters();
static Filters userDefinedFilters();
static void removeUserDefinedFilter(const QString &filter);
static void addUserDefinedFilter(const QString &filter, const QStringList &attr);
+#endif
static void aboutToShutdown();
diff --git a/src/plugins/help/helpplugin.cpp b/src/plugins/help/helpplugin.cpp
index 9542a457c4..6ec180e09d 100644
--- a/src/plugins/help/helpplugin.cpp
+++ b/src/plugins/help/helpplugin.cpp
@@ -116,7 +116,7 @@ public:
void activateContents();
void saveExternalWindowSettings();
- void showLinksInCurrentViewer(const QMap<QString, QUrl> &links, const QString &key);
+ void showLinksInCurrentViewer(const QMultiMap<QString, QUrl> &links, const QString &key);
void setupHelpEngineIfNeeded();
@@ -124,7 +124,10 @@ public:
void slotSystemInformation();
+#ifndef HELP_NEW_FILTER_ENGINE
void resetFilter();
+#endif
+
static void activateHelpMode() { ModeManager::activateMode(Constants::ID_MODE_HELP); }
static bool canShowHelpSideBySide();
@@ -314,6 +317,8 @@ ExtensionSystem::IPlugin::ShutdownFlag HelpPlugin::aboutToShutdown()
return SynchronousShutdown;
}
+#ifndef HELP_NEW_FILTER_ENGINE
+
void HelpPluginPrivate::resetFilter()
{
const QString &filterInternal = QString::fromLatin1("Qt Creator %1.%2.%3")
@@ -348,6 +353,8 @@ void HelpPluginPrivate::resetFilter()
LocalHelpManager::instance(), &LocalHelpManager::updateFilterModel);
}
+#endif
+
void HelpPluginPrivate::saveExternalWindowSettings()
{
if (!m_externalWindow)
@@ -366,7 +373,7 @@ HelpWidget *HelpPluginPrivate::createHelpWidget(const Context &context, HelpWidg
&LocalHelpManager::returnOnCloseChanged,
widget,
&HelpWidget::updateCloseButton);
- connect(widget, &HelpWidget::closeButtonClicked, this, [this, widget] {
+ connect(widget, &HelpWidget::closeButtonClicked, this, [widget] {
if (widget->widgetStyle() == HelpWidget::SideBarWidget)
RightPaneWidget::instance()->setShown(false);
else if (widget->viewerCount() == 1 && LocalHelpManager::returnOnClose())
@@ -436,7 +443,7 @@ HelpWidget *HelpPlugin::modeHelpWidget()
return dd->m_centralWidget;
}
-void HelpPluginPrivate::showLinksInCurrentViewer(const QMap<QString, QUrl> &links, const QString &key)
+void HelpPluginPrivate::showLinksInCurrentViewer(const QMultiMap<QString, QUrl> &links, const QString &key)
{
if (links.size() < 1)
return;
@@ -577,7 +584,7 @@ void HelpPluginPrivate::showContextHelp(const HelpItem &contextHelp)
} else if (links.size() == 1 && !contextHelp.isFuzzyMatch()) {
showHelpUrl(links.front().second, LocalHelpManager::contextHelpOption());
} else {
- QMap<QString, QUrl> map;
+ QMultiMap<QString, QUrl> map;
for (const HelpItem::Link &link : links)
map.insert(link.first, link.second);
auto tc = new TopicChooser(ICore::dialogParent(), contextHelp.keyword(), map);
@@ -683,7 +690,9 @@ void HelpPluginPrivate::doSetupIfNeeded()
{
LocalHelpManager::setupGuiHelpEngine();
if (m_setupNeeded) {
+#ifndef HELP_NEW_FILTER_ENGINE
resetFilter();
+#endif
m_setupNeeded = false;
m_centralWidget->openPagesManager()->setupInitialPages();
LocalHelpManager::bookmarkManager().setupBookmarkModels();
diff --git a/src/plugins/help/helpwidget.cpp b/src/plugins/help/helpwidget.cpp
index e8d85caa18..09e2560e10 100644
--- a/src/plugins/help/helpwidget.cpp
+++ b/src/plugins/help/helpwidget.cpp
@@ -61,6 +61,11 @@
#include <QStatusBar>
#include <QToolButton>
+#ifdef HELP_NEW_FILTER_ENGINE
+#include <QtHelp/QHelpEngine>
+#include <QtHelp/QHelpFilterEngine>
+#endif
+
static const char kWindowSideBarSettingsKey[] = "Help/WindowSideBar";
static const char kModeSideBarSettingsKey[] = "Help/ModeSideBar";
@@ -359,15 +364,24 @@ HelpWidget::HelpWidget(const Core::Context &context, WidgetStyle style, QWidget
m_filterComboBox = new QComboBox;
m_filterComboBox->setMinimumContentsLength(15);
+ layout->addWidget(m_filterComboBox);
+#ifndef HELP_NEW_FILTER_ENGINE
m_filterComboBox->setModel(LocalHelpManager::filterModel());
m_filterComboBox->setCurrentIndex(LocalHelpManager::filterIndex());
- layout->addWidget(m_filterComboBox);
connect(m_filterComboBox, QOverload<int>::of(&QComboBox::activated),
LocalHelpManager::instance(), &LocalHelpManager::setFilterIndex);
connect(LocalHelpManager::instance(),
&LocalHelpManager::filterIndexChanged,
m_filterComboBox,
&QComboBox::setCurrentIndex);
+#else
+ connect(&LocalHelpManager::helpEngine(), &QHelpEngine::setupFinished,
+ this, &HelpWidget::setupFilterCombo, Qt::QueuedConnection);
+ connect(m_filterComboBox, QOverload<int>::of(&QComboBox::activated),
+ this, &HelpWidget::filterDocumentation);
+ connect(LocalHelpManager::filterEngine(), &QHelpFilterEngine::filterActivated,
+ this, &HelpWidget::currentFilterChanged);
+#endif
Core::ActionContainer *windowMenu = Core::ActionManager::actionContainer(
Core::Constants::M_WINDOW);
@@ -487,6 +501,41 @@ HelpWidget::HelpWidget(const Core::Context &context, WidgetStyle style, QWidget
}
}
+#ifdef HELP_NEW_FILTER_ENGINE
+
+void HelpWidget::setupFilterCombo()
+{
+ const QString currentFilter = LocalHelpManager::filterEngine()->activeFilter();
+ m_filterComboBox->clear();
+ m_filterComboBox->addItem(tr("Unfiltered"));
+ const QStringList allFilters = LocalHelpManager::filterEngine()->filters();
+ if (!allFilters.isEmpty())
+ m_filterComboBox->insertSeparator(1);
+ for (const QString &filter : allFilters)
+ m_filterComboBox->addItem(filter, filter);
+
+ int idx = m_filterComboBox->findData(currentFilter);
+ if (idx < 0)
+ idx = 0;
+ m_filterComboBox->setCurrentIndex(idx);
+}
+
+void HelpWidget::filterDocumentation(int filterIndex)
+{
+ const QString filter = m_filterComboBox->itemData(filterIndex).toString();
+ LocalHelpManager::filterEngine()->setActiveFilter(filter);
+}
+
+void HelpWidget::currentFilterChanged(const QString &filter)
+{
+ int index = m_filterComboBox->findData(filter);
+ if (index < 0)
+ index = 0;
+ m_filterComboBox->setCurrentIndex(index);
+}
+
+#endif
+
HelpWidget::~HelpWidget()
{
saveState();
@@ -753,7 +802,7 @@ HelpViewer *HelpWidget::openNewPage(const QUrl &url)
return page;
}
-void HelpWidget::showLinks(const QMap<QString, QUrl> &links,
+void HelpWidget::showLinks(const QMultiMap<QString, QUrl> &links,
const QString &keyword, bool newPage)
{
if (links.size() < 1)
diff --git a/src/plugins/help/helpwidget.h b/src/plugins/help/helpwidget.h
index 40cca45e3d..e79314d940 100644
--- a/src/plugins/help/helpwidget.h
+++ b/src/plugins/help/helpwidget.h
@@ -96,7 +96,7 @@ public:
void open(const QUrl &url, bool newPage = false);
HelpViewer *openNewPage(const QUrl &url);
void openFromSearch(const QUrl &url, const QStringList &searchTerms, bool newPage = false);
- void showLinks(const QMap<QString, QUrl> &links, const QString &key,
+ void showLinks(const QMultiMap<QString, QUrl> &links, const QString &key,
bool newPage = false);
void activateSideBarItem(const QString &id);
@@ -142,6 +142,12 @@ private:
void addSideBar();
QString sideBarSettingsKey() const;
+#ifdef HELP_NEW_FILTER_ENGINE
+ void setupFilterCombo();
+ void filterDocumentation(int filterIndex);
+ void currentFilterChanged(const QString &filter);
+#endif
+
OpenPagesModel m_model;
OpenPagesManager *m_openPagesManager = nullptr;
Core::IContext *m_context = nullptr;
diff --git a/src/plugins/help/localhelpmanager.cpp b/src/plugins/help/localhelpmanager.cpp
index f8a02eb7cc..100fe940c8 100644
--- a/src/plugins/help/localhelpmanager.cpp
+++ b/src/plugins/help/localhelpmanager.cpp
@@ -70,10 +70,14 @@ QHelpEngine* LocalHelpManager::m_guiEngine = nullptr;
QMutex LocalHelpManager::m_bkmarkMutex;
BookmarkManager* LocalHelpManager::m_bookmarkManager = nullptr;
+#ifndef HELP_NEW_FILTER_ENGINE
+
QStandardItemModel *LocalHelpManager::m_filterModel = nullptr;
QString LocalHelpManager::m_currentFilter = QString();
int LocalHelpManager::m_currentFilterIndex = -1;
+#endif
+
static const char kHelpHomePageKey[] = "Help/HomePage";
static const char kFontFamilyKey[] = "Help/FallbackFontFamily";
static const char kFontStyleNameKey[] = "Help/FallbackFontStyleName";
@@ -123,7 +127,9 @@ LocalHelpManager::LocalHelpManager(QObject *parent)
{
m_instance = this;
qRegisterMetaType<Help::Internal::LocalHelpManager::HelpData>("Help::Internal::LocalHelpManager::HelpData");
+#ifndef HELP_NEW_FILTER_ENGINE
m_filterModel = new QStandardItemModel(this);
+#endif
}
LocalHelpManager::~LocalHelpManager()
@@ -396,8 +402,12 @@ QHelpEngine &LocalHelpManager::helpEngine()
{
if (!m_guiEngine) {
QMutexLocker _(&m_guiMutex);
- if (!m_guiEngine)
+ if (!m_guiEngine) {
m_guiEngine = new QHelpEngine(QString());
+#ifdef HELP_NEW_FILTER_ENGINE
+ m_guiEngine->setUsesFilterEngine(true);
+#endif
+ }
}
return *m_guiEngine;
}
@@ -495,6 +505,8 @@ LocalHelpManager::HelpData LocalHelpManager::helpData(const QUrl &url)
return data;
}
+#ifndef HELP_NEW_FILTER_ENGINE
+
QAbstractItemModel *LocalHelpManager::filterModel()
{
return m_filterModel;
@@ -544,6 +556,15 @@ void LocalHelpManager::updateFilterModel()
emit m_instance->filterIndexChanged(m_currentFilterIndex);
}
+#else
+
+QHelpFilterEngine *LocalHelpManager::filterEngine()
+{
+ return helpEngine().filterEngine();
+}
+
+#endif
+
bool LocalHelpManager::canOpenOnlineHelp(const QUrl &url)
{
const QString address = url.toString();
diff --git a/src/plugins/help/localhelpmanager.h b/src/plugins/help/localhelpmanager.h
index c2f5284f59..aac3a46871 100644
--- a/src/plugins/help/localhelpmanager.h
+++ b/src/plugins/help/localhelpmanager.h
@@ -31,9 +31,12 @@
#include <QMutex>
#include <QObject>
#include <QUrl>
+#ifndef HELP_NEW_FILTER_ENGINE
#include <QStandardItemModel>
-
#include <functional>
+#else
+QT_FORWARD_DECLARE_CLASS(QHelpFilterEngine)
+#endif
QT_FORWARD_DECLARE_CLASS(QHelpEngine)
@@ -116,17 +119,23 @@ public:
static QByteArray loadErrorMessage(const QUrl &url, const QString &errorString);
Q_INVOKABLE static Help::Internal::LocalHelpManager::HelpData helpData(const QUrl &url);
+#ifndef HELP_NEW_FILTER_ENGINE
static QAbstractItemModel *filterModel();
static void setFilterIndex(int index);
static int filterIndex();
static void updateFilterModel();
+#else
+ static QHelpFilterEngine *filterEngine();
+#endif
static bool canOpenOnlineHelp(const QUrl &url);
static bool openOnlineHelp(const QUrl &url);
signals:
+#ifndef HELP_NEW_FILTER_ENGINE
void filterIndexChanged(int index);
+#endif
void fallbackFontChanged(const QFont &font);
void returnOnCloseChanged();
void scrollWheelZoomingEnabledChanged(bool enabled);
@@ -136,9 +145,11 @@ private:
static bool m_guiNeedsSetup;
static bool m_needsCollectionFile;
+#ifndef HELP_NEW_FILTER_ENGINE
static QStandardItemModel *m_filterModel;
static QString m_currentFilter;
static int m_currentFilterIndex;
+#endif
static QMutex m_guiMutex;
static QHelpEngine *m_guiEngine;
diff --git a/src/plugins/help/qlitehtml/CMakeLists.txt b/src/plugins/help/qlitehtml/CMakeLists.txt
index 70a630d4c8..31ed481e49 100644
--- a/src/plugins/help/qlitehtml/CMakeLists.txt
+++ b/src/plugins/help/qlitehtml/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.9)
+cmake_minimum_required(VERSION 3.10)
project(QLiteHtml)
diff --git a/src/plugins/help/searchtaskhandler.cpp b/src/plugins/help/searchtaskhandler.cpp
index 2971d7bff4..8df2a71565 100644
--- a/src/plugins/help/searchtaskhandler.cpp
+++ b/src/plugins/help/searchtaskhandler.cpp
@@ -36,15 +36,12 @@ using namespace Help::Internal;
bool SearchTaskHandler::canHandle(const ProjectExplorer::Task &task) const
{
- return !task.description.isEmpty()
- && !task.description.startsWith(QLatin1Char('\n'));
+ return !task.summary.isEmpty();
}
void SearchTaskHandler::handle(const ProjectExplorer::Task &task)
{
- const int eol = task.description.indexOf(QLatin1Char('\n'));
- const QUrl url(QLatin1String("https://www.google.com/search?q=") + task.description.left(eol));
- emit search(url);
+ emit search(QUrl("https://www.google.com/search?q=" + task.summary));
}
QAction *SearchTaskHandler::createAction(QObject *parent) const
diff --git a/src/plugins/imageviewer/exportdialog.cpp b/src/plugins/imageviewer/exportdialog.cpp
index 37a59b9625..c96475659e 100644
--- a/src/plugins/imageviewer/exportdialog.cpp
+++ b/src/plugins/imageviewer/exportdialog.cpp
@@ -187,12 +187,12 @@ void ExportDialog::exportHeightChanged(int height)
QString ExportDialog::exportFileName() const
{
- return m_pathChooser->fileName().toString();
+ return m_pathChooser->filePath().toString();
}
void ExportDialog::setExportFileName(const QString &f)
{
- m_pathChooser->setFileName(Utils::FilePath::fromString(f));
+ m_pathChooser->setFilePath(Utils::FilePath::fromString(f));
}
ExportData ExportDialog::exportData() const
diff --git a/src/plugins/imageviewer/multiexportdialog.cpp b/src/plugins/imageviewer/multiexportdialog.cpp
index b377cc7243..8e09033e27 100644
--- a/src/plugins/imageviewer/multiexportdialog.cpp
+++ b/src/plugins/imageviewer/multiexportdialog.cpp
@@ -329,7 +329,7 @@ void MultiExportDialog::accept()
QString MultiExportDialog::exportFileName() const
{
- return m_pathChooser->fileName().toString();
+ return m_pathChooser->filePath().toString();
}
void MultiExportDialog::setExportFileName(QString f)
@@ -337,7 +337,7 @@ void MultiExportDialog::setExportFileName(QString f)
const int lastDot = f.lastIndexOf('.');
if (lastDot != -1)
f.insert(lastDot, "-%1");
- m_pathChooser->setFileName(Utils::FilePath::fromString(f));
+ m_pathChooser->setFilePath(Utils::FilePath::fromString(f));
}
} // namespace Internal
diff --git a/src/plugins/ios/iosbuildstep.cpp b/src/plugins/ios/iosbuildstep.cpp
index c881e62267..9fbe292299 100644
--- a/src/plugins/ios/iosbuildstep.cpp
+++ b/src/plugins/ios/iosbuildstep.cpp
@@ -38,6 +38,7 @@
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/toolchain.h>
#include <projectexplorer/gcctoolchain.h>
+#include <projectexplorer/abstractprocessstep.h>
#include <qtsupport/qtkitinformation.h>
#include <qtsupport/qtparser.h>
@@ -61,18 +62,42 @@ namespace Ios {
namespace Internal {
const char IOS_BUILD_STEP_ID[] = "Ios.IosBuildStep";
-const char IOS_BUILD_STEP_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("Ios::Internal::IosBuildStep",
- "xcodebuild");
-
const char BUILD_USE_DEFAULT_ARGS_KEY[] = "Ios.IosBuildStep.XcodeArgumentsUseDefault";
const char BUILD_ARGUMENTS_KEY[] = "Ios.IosBuildStep.XcodeArguments";
const char CLEAN_KEY[] = "Ios.IosBuildStep.Clean";
+class IosBuildStep final : public AbstractProcessStep
+{
+ Q_DECLARE_TR_FUNCTIONS(Ios::Internal::IosBuildStep)
+
+public:
+ IosBuildStep(BuildStepList *parent, Core::Id id);
+
+ BuildStepConfigWidget *createConfigWidget() final;
+ void setBaseArguments(const QStringList &args);
+ void setExtraArguments(const QStringList &extraArgs);
+ QStringList baseArguments() const;
+ QStringList allArguments() const;
+ QStringList defaultArguments() const;
+ Utils::FilePath buildCommand() const;
+
+ bool init() final;
+ void setupOutputFormatter(Utils::OutputFormatter *formatter);
+ void doRun() final;
+ bool fromMap(const QVariantMap &map) final;
+ QVariantMap toMap() const final;
+
+ QStringList m_baseBuildArguments;
+ QStringList m_extraArguments;
+ bool m_useDefaultArguments = true;
+ bool m_clean = false;
+};
+
//
// IosBuildStepConfigWidget
//
-class IosBuildStepConfigWidget : public ProjectExplorer::BuildStepConfigWidget
+class IosBuildStepConfigWidget final : public BuildStepConfigWidget
{
public:
IosBuildStepConfigWidget(IosBuildStep *buildStep)
@@ -145,12 +170,10 @@ private:
void updateDetails()
{
- BuildConfiguration *bc = m_buildStep->buildConfiguration();
-
ProcessParameters param;
- param.setMacroExpander(bc->macroExpander());
- param.setWorkingDirectory(bc->buildDirectory());
- param.setEnvironment(bc->environment());
+ param.setMacroExpander(m_buildStep->macroExpander());
+ param.setWorkingDirectory(m_buildStep->buildDirectory());
+ param.setEnvironment(m_buildStep->buildEnvironment());
param.setCommandLine({m_buildStep->buildCommand(), m_buildStep->allArguments()});
setSummaryText(param.summary(displayName()));
@@ -166,8 +189,8 @@ private:
IosBuildStep::IosBuildStep(BuildStepList *parent, Id id)
: AbstractProcessStep(parent, id)
{
- setDefaultDisplayName(QCoreApplication::translate("GenericProjectManager::Internal::IosBuildStep",
- IOS_BUILD_STEP_DISPLAY_NAME));
+ setDefaultDisplayName(tr("xcodebuild"));
+
if (parent->id() == ProjectExplorer::Constants::BUILDSTEPS_CLEAN) {
m_clean = true;
setExtraArguments(QStringList("clean"));
@@ -177,10 +200,8 @@ IosBuildStep::IosBuildStep(BuildStepList *parent, Id id)
bool IosBuildStep::init()
{
BuildConfiguration *bc = buildConfiguration();
- if (!bc)
- emit addTask(Task::buildConfigurationMissingTask());
- ToolChain *tc = ToolChainKitAspect::toolChain(target()->kit(), ProjectExplorer::Constants::CXX_LANGUAGE_ID);
+ ToolChain *tc = ToolChainKitAspect::cxxToolChain(target()->kit());
if (!tc)
emit addTask(Task::compilerMissingTask());
@@ -202,15 +223,17 @@ bool IosBuildStep::init()
// That is mostly so that rebuild works on an already clean project
setIgnoreReturnValue(m_clean);
- setOutputParser(new GnuMakeParser());
- IOutputParser *parser = target()->kit()->createOutputParser();
- if (parser)
- appendOutputParser(parser);
- outputParser()->setWorkingDirectory(pp->effectiveWorkingDirectory());
-
return AbstractProcessStep::init();
}
+void IosBuildStep::setupOutputFormatter(OutputFormatter *formatter)
+{
+ formatter->addLineParser(new GnuMakeParser);
+ formatter->addLineParsers(target()->kit()->createOutputParsers());
+ formatter->addSearchDir(processParameters()->effectiveWorkingDirectory());
+ AbstractProcessStep::setupOutputFormatter(formatter);
+}
+
QVariantMap IosBuildStep::toMap() const
{
QVariantMap map(AbstractProcessStep::toMap());
@@ -240,7 +263,7 @@ QStringList IosBuildStep::defaultArguments() const
{
QStringList res;
Kit *kit = target()->kit();
- ToolChain *tc = ToolChainKitAspect::toolChain(kit, ProjectExplorer::Constants::CXX_LANGUAGE_ID);
+ ToolChain *tc = ToolChainKitAspect::cxxToolChain(kit);
switch (buildConfiguration()->buildType()) {
case BuildConfiguration::Debug :
res << "-configuration" << "Debug";
@@ -252,8 +275,7 @@ QStringList IosBuildStep::defaultArguments() const
case BuildConfiguration::Unknown :
break;
default:
- qCWarning(iosLog) << "IosBuildStep had an unknown buildType "
- << buildConfiguration()->buildType();
+ qCWarning(iosLog) << "IosBuildStep had an unknown buildType " << buildType();
}
if (tc->typeId() == ProjectExplorer::Constants::GCC_TOOLCHAIN_TYPEID
|| tc->typeId() == ProjectExplorer::Constants::CLANG_TOOLCHAIN_TYPEID) {
@@ -262,7 +284,7 @@ QStringList IosBuildStep::defaultArguments() const
}
if (!SysRootKitAspect::sysRoot(kit).isEmpty())
res << "-sdk" << SysRootKitAspect::sysRoot(kit).toString();
- res << "SYMROOT=" + buildConfiguration()->buildDirectory().toString();
+ res << "SYMROOT=" + buildDirectory().toString();
return res;
}
@@ -310,8 +332,7 @@ IosBuildStepFactory::IosBuildStepFactory()
Constants::IOS_SIMULATOR_TYPE});
setSupportedStepLists({ProjectExplorer::Constants::BUILDSTEPS_CLEAN,
ProjectExplorer::Constants::BUILDSTEPS_BUILD});
- setDisplayName(QCoreApplication::translate("GenericProjectManager::Internal::IosBuildStep",
- IOS_BUILD_STEP_DISPLAY_NAME));
+ setDisplayName(IosBuildStep::tr("xcodebuild"));
}
} // namespace Internal
diff --git a/src/plugins/ios/iosbuildstep.h b/src/plugins/ios/iosbuildstep.h
index 3f6145202c..3a27b20960 100644
--- a/src/plugins/ios/iosbuildstep.h
+++ b/src/plugins/ios/iosbuildstep.h
@@ -25,49 +25,12 @@
#pragma once
-#include <projectexplorer/abstractprocessstep.h>
-
-QT_BEGIN_NAMESPACE
-class QListWidgetItem;
-QT_END_NAMESPACE
+#include <projectexplorer/buildstep.h>
namespace Ios {
namespace Internal {
-class IosBuildStepConfigWidget;
-class IosBuildStepFactory;
-
-class IosBuildStep : public ProjectExplorer::AbstractProcessStep
-{
- Q_OBJECT
-
- friend class IosBuildStepConfigWidget;
- friend class IosBuildStepFactory;
-
-public:
- IosBuildStep(ProjectExplorer::BuildStepList *parent, Core::Id id);
-
- ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override;
- void setBaseArguments(const QStringList &args);
- void setExtraArguments(const QStringList &extraArgs);
- QStringList baseArguments() const;
- QStringList allArguments() const;
- QStringList defaultArguments() const;
- Utils::FilePath buildCommand() const;
-
-private:
- bool init() override;
- void doRun() override;
- bool fromMap(const QVariantMap &map) override;
- QVariantMap toMap() const override;
-
- QStringList m_baseBuildArguments;
- QStringList m_extraArguments;
- bool m_useDefaultArguments = true;
- bool m_clean = false;
-};
-
-class IosBuildStepFactory : public ProjectExplorer::BuildStepFactory
+class IosBuildStepFactory final : public ProjectExplorer::BuildStepFactory
{
public:
IosBuildStepFactory();
diff --git a/src/plugins/ios/iosconfigurations.cpp b/src/plugins/ios/iosconfigurations.cpp
index 158805c53d..b90787ff63 100644
--- a/src/plugins/ios/iosconfigurations.cpp
+++ b/src/plugins/ios/iosconfigurations.cpp
@@ -288,8 +288,8 @@ void IosConfigurations::updateAutomaticKitList()
// we do not compare the sdk (thus automatically upgrading it in place if a
// new Xcode is used). Change?
return DeviceTypeKitAspect::deviceTypeId(kit) == pDeviceType
- && ToolChainKitAspect::toolChain(kit, ProjectExplorer::Constants::CXX_LANGUAGE_ID) == platformToolchains.second
- && ToolChainKitAspect::toolChain(kit, ProjectExplorer::Constants::C_LANGUAGE_ID) == platformToolchains.first
+ && ToolChainKitAspect::cxxToolChain(kit) == platformToolchains.second
+ && ToolChainKitAspect::cToolChain(kit) == platformToolchains.first
&& QtKitAspect::qtVersion(kit) == qtVersion;
});
QTC_ASSERT(!resultingKits.contains(kit), continue);
diff --git a/src/plugins/ios/iosconfigurations.h b/src/plugins/ios/iosconfigurations.h
index cddf0a5806..d041ac3f21 100644
--- a/src/plugins/ios/iosconfigurations.h
+++ b/src/plugins/ios/iosconfigurations.h
@@ -95,8 +95,6 @@ using DevelopmentTeams = QList<DevelopmentTeamPtr>;
class IosToolChainFactory : public ProjectExplorer::ToolChainFactory
{
- Q_OBJECT
-
public:
IosToolChainFactory();
diff --git a/src/plugins/ios/iosdeploystep.cpp b/src/plugins/ios/iosdeploystep.cpp
index 329fab7bfd..7bd5a87944 100644
--- a/src/plugins/ios/iosdeploystep.cpp
+++ b/src/plugins/ios/iosdeploystep.cpp
@@ -24,13 +24,15 @@
****************************************************************************/
#include "iosdeploystep.h"
+
#include "iosbuildstep.h"
+#include "iosconfigurations.h"
#include "iosconstants.h"
+#include "iosdevice.h"
#include "iosrunconfiguration.h"
+#include "iossimulator.h"
#include "iostoolhandler.h"
-#include <coreplugin/messagemanager.h>
-
#include <projectexplorer/buildconfiguration.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/target.h>
@@ -39,22 +41,64 @@
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/devicesupport/devicemanager.h>
-#include <qtsupport/qtkitinformation.h>
-
#include <utils/temporaryfile.h>
#include <QDir>
#include <QFile>
#include <QSettings>
-#define ASSERT_STATE(state) ASSERT_STATE_GENERIC(State, state, m_state)
-
using namespace ProjectExplorer;
using namespace Utils;
namespace Ios {
namespace Internal {
+class IosDeployStep final : public BuildStep
+{
+ Q_DECLARE_TR_FUNCTIONS(Ios::Internal::IosDeployStep)
+
+public:
+ enum TransferStatus {
+ NoTransfer,
+ TransferInProgress,
+ TransferOk,
+ TransferFailed
+ };
+
+ IosDeployStep(BuildStepList *bc, Core::Id id);
+
+private:
+ void cleanup();
+
+ void doRun() final;
+ void doCancel() final;
+
+ void handleIsTransferringApp(IosToolHandler *handler, const QString &bundlePath,
+ const QString &deviceId, int progress, int maxProgress,
+ const QString &info);
+ void handleDidTransferApp(IosToolHandler *handler, const QString &bundlePath, const QString &deviceId,
+ IosToolHandler::OpStatus status);
+ void handleFinished(IosToolHandler *handler);
+ void handleErrorMsg(IosToolHandler *handler, const QString &msg);
+ void updateDisplayNames();
+
+ bool init() final;
+ BuildStepConfigWidget *createConfigWidget() final;
+ IDevice::ConstPtr device() const;
+ IosDevice::ConstPtr iosdevice() const;
+ IosSimulator::ConstPtr iossimulator() const;
+
+ QString deviceId() const;
+ void checkProvisioningProfile();
+
+ TransferStatus m_transferStatus = NoTransfer;
+ IosToolHandler *m_toolHandler = nullptr;
+ IDevice::ConstPtr m_device;
+ FilePath m_bundlePath;
+ IosDeviceType m_deviceType;
+ bool m_expectFail = false;
+};
+
IosDeployStep::IosDeployStep(BuildStepList *parent, Core::Id id)
: BuildStep(parent, id)
{
@@ -66,15 +110,9 @@ IosDeployStep::IosDeployStep(BuildStepList *parent, Core::Id id)
this, &IosDeployStep::updateDisplayNames);
}
-Core::Id IosDeployStep::stepId()
-{
- return "Qt4ProjectManager.IosDeployStep";
-}
-
void IosDeployStep::updateDisplayNames()
{
- IDevice::ConstPtr dev =
- DeviceKitAspect::device(target()->kit());
+ IDevice::ConstPtr dev = DeviceKitAspect::device(target()->kit());
const QString devName = dev.isNull() ? IosDevice::name() : dev->displayName();
setDefaultDisplayName(tr("Deploy to %1").arg(devName));
setDisplayName(tr("Deploy to %1").arg(devName));
@@ -95,7 +133,7 @@ bool IosDeployStep::init()
m_deviceType = runConfig->deviceType();
} else {
emit addOutput(tr("Error: no device available, deploy failed."),
- BuildStep::OutputFormat::ErrorMessage);
+ OutputFormat::ErrorMessage);
return false;
}
return true;
@@ -104,7 +142,7 @@ bool IosDeployStep::init()
void IosDeployStep::doRun()
{
QTC_CHECK(m_transferStatus == NoTransfer);
- if (device().isNull()) {
+ if (m_device.isNull()) {
TaskHub::addTask(
DeploymentTask(Task::Error, tr("Deployment failed. No iOS device found.")));
emit finished(!iossimulator().isNull());
@@ -190,7 +228,7 @@ void IosDeployStep::handleErrorMsg(IosToolHandler *handler, const QString &msg)
if (msg.contains(QLatin1String("AMDeviceInstallApplication returned -402653103")))
TaskHub::addTask(DeploymentTask(Task::Warning, tr("The Info.plist might be incorrect.")));
- emit addOutput(msg, BuildStep::OutputFormat::ErrorMessage);
+ emit addOutput(msg, OutputFormat::ErrorMessage);
}
BuildStepConfigWidget *IosDeployStep::createConfigWidget()
@@ -236,7 +274,7 @@ void IosDeployStep::checkProvisioningProfile()
return;
end += 8;
- Utils::TemporaryFile f("iosdeploy");
+ TemporaryFile f("iosdeploy");
if (!f.open())
return;
f.write(provisionData.mid(start, end - start));
@@ -245,9 +283,9 @@ void IosDeployStep::checkProvisioningProfile()
if (!provisionPlist.contains(QLatin1String("ProvisionedDevices")))
return;
- QStringList deviceIds = provisionPlist.value(QLatin1String("ProvisionedDevices")).toStringList();
- QString targetId = device->uniqueDeviceID();
- foreach (const QString &deviceId, deviceIds) {
+ const QStringList deviceIds = provisionPlist.value("ProvisionedDevices").toStringList();
+ const QString targetId = device->uniqueDeviceID();
+ for (const QString &deviceId : deviceIds) {
if (deviceId == targetId)
return;
}
@@ -263,11 +301,6 @@ void IosDeployStep::checkProvisioningProfile()
emit addTask(task);
}
-IDevice::ConstPtr IosDeployStep::device() const
-{
- return m_device;
-}
-
IosDevice::ConstPtr IosDeployStep::iosdevice() const
{
return m_device.dynamicCast<const IosDevice>();
@@ -278,5 +311,21 @@ IosSimulator::ConstPtr IosDeployStep::iossimulator() const
return m_device.dynamicCast<const IosSimulator>();
}
+// IosDeployStepFactory
+
+IosDeployStepFactory::IosDeployStepFactory()
+{
+ registerStep<IosDeployStep>(stepId());
+ setDisplayName(IosDeployStep::tr("Deploy to iOS device or emulator"));
+ setSupportedStepList(ProjectExplorer::Constants::BUILDSTEPS_DEPLOY);
+ setSupportedDeviceTypes({Constants::IOS_DEVICE_TYPE, Constants::IOS_SIMULATOR_TYPE});
+ setRepeatable(false);
+}
+
+Core::Id IosDeployStepFactory::stepId()
+{
+ return "Qt4ProjectManager.IosDeployStep";
+}
+
} // namespace Internal
} // namespace Ios
diff --git a/src/plugins/ios/iosdeploystep.h b/src/plugins/ios/iosdeploystep.h
index 909aae4f4d..bdd23a74f7 100644
--- a/src/plugins/ios/iosdeploystep.h
+++ b/src/plugins/ios/iosdeploystep.h
@@ -25,64 +25,17 @@
#pragma once
-#include "iosconfigurations.h"
-#include "iosdevice.h"
-#include "iossimulator.h"
-
#include <projectexplorer/buildstep.h>
-#include <projectexplorer/devicesupport/idevice.h>
-
-#include <QProcess>
namespace Ios {
-class IosToolHandler;
namespace Internal {
-class IosDeployStep : public ProjectExplorer::BuildStep
+class IosDeployStepFactory final : public ProjectExplorer::BuildStepFactory
{
- Q_OBJECT
public:
- enum TransferStatus {
- NoTransfer,
- TransferInProgress,
- TransferOk,
- TransferFailed
- };
+ IosDeployStepFactory();
- friend class IosDeployStepFactory;
- IosDeployStep(ProjectExplorer::BuildStepList *bc, Core::Id id);
static Core::Id stepId();
-
- void cleanup();
-private:
- void doRun() override;
- void doCancel() override;
-
- void handleIsTransferringApp(Ios::IosToolHandler *handler, const QString &bundlePath,
- const QString &deviceId, int progress, int maxProgress,
- const QString &info);
- void handleDidTransferApp(Ios::IosToolHandler *handler, const QString &bundlePath, const QString &deviceId,
- Ios::IosToolHandler::OpStatus status);
- void handleFinished(Ios::IosToolHandler *handler);
- void handleErrorMsg(Ios::IosToolHandler *handler, const QString &msg);
- void updateDisplayNames();
-
- bool init() override;
- ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override;
- ProjectExplorer::IDevice::ConstPtr device() const;
- IosDevice::ConstPtr iosdevice() const;
- IosSimulator::ConstPtr iossimulator() const;
-
- QString deviceId() const;
- void checkProvisioningProfile();
-
- TransferStatus m_transferStatus = NoTransfer;
- IosToolHandler *m_toolHandler = nullptr;
- ProjectExplorer::IDevice::ConstPtr m_device;
- Utils::FilePath m_bundlePath;
- IosDeviceType m_deviceType;
- static const Core::Id Id;
- bool m_expectFail = false;
};
} // namespace Internal
diff --git a/src/plugins/ios/iosdsymbuildstep.cpp b/src/plugins/ios/iosdsymbuildstep.cpp
index a597f9b0d6..3b11d06922 100644
--- a/src/plugins/ios/iosdsymbuildstep.cpp
+++ b/src/plugins/ios/iosdsymbuildstep.cpp
@@ -67,12 +67,10 @@ IosDsymBuildStep::IosDsymBuildStep(BuildStepList *parent, Id id) :
bool IosDsymBuildStep::init()
{
- BuildConfiguration *bc = buildConfiguration();
-
ProcessParameters *pp = processParameters();
- pp->setMacroExpander(bc->macroExpander());
- pp->setWorkingDirectory(bc->buildDirectory());
- Utils::Environment env = bc->environment();
+ pp->setMacroExpander(macroExpander());
+ pp->setWorkingDirectory(buildDirectory());
+ Utils::Environment env = buildEnvironment();
Utils::Environment::setupEnglishOutput(&env);
pp->setEnvironment(env);
pp->setCommandLine({command(), arguments()});
@@ -82,10 +80,6 @@ bool IosDsymBuildStep::init()
// That is mostly so that rebuild works on an already clean project
setIgnoreReturnValue(m_clean);
- setOutputParser(target()->kit()->createOutputParser());
- if (outputParser())
- outputParser()->setWorkingDirectory(pp->effectiveWorkingDirectory());
-
return AbstractProcessStep::init();
}
@@ -192,6 +186,13 @@ void IosDsymBuildStep::doRun()
AbstractProcessStep::doRun();
}
+void IosDsymBuildStep::setupOutputFormatter(OutputFormatter *formatter)
+{
+ formatter->setLineParsers(target()->kit()->createOutputParsers());
+ formatter->addSearchDir(processParameters()->effectiveWorkingDirectory());
+ AbstractProcessStep::setupOutputFormatter(formatter);
+}
+
BuildStepConfigWidget *IosDsymBuildStep::createConfigWidget()
{
return new IosDsymBuildStepConfigWidget(this);
@@ -255,12 +256,10 @@ IosDsymBuildStepConfigWidget::~IosDsymBuildStepConfigWidget()
void IosDsymBuildStepConfigWidget::updateDetails()
{
- BuildConfiguration *bc = m_buildStep->buildConfiguration();
-
ProcessParameters param;
- param.setMacroExpander(bc->macroExpander());
- param.setWorkingDirectory(bc->buildDirectory());
- param.setEnvironment(bc->environment());
+ param.setMacroExpander(m_buildStep->macroExpander());
+ param.setWorkingDirectory(m_buildStep->buildDirectory());
+ param.setEnvironment(m_buildStep->buildEnvironment());
param.setCommandLine({m_buildStep->command(), m_buildStep->arguments()});
setSummaryText(param.summary(displayName()));
diff --git a/src/plugins/ios/iosdsymbuildstep.h b/src/plugins/ios/iosdsymbuildstep.h
index effc6e5f91..7e08b1a6ad 100644
--- a/src/plugins/ios/iosdsymbuildstep.h
+++ b/src/plugins/ios/iosdsymbuildstep.h
@@ -56,6 +56,7 @@ public:
private:
bool init() override;
void doRun() override;
+ void setupOutputFormatter(Utils::OutputFormatter *formatter) override;
QVariantMap toMap() const override;
bool fromMap(const QVariantMap &map) override;
diff --git a/src/plugins/ios/iosplugin.cpp b/src/plugins/ios/iosplugin.cpp
index 50540c331f..a112364735 100644
--- a/src/plugins/ios/iosplugin.cpp
+++ b/src/plugins/ios/iosplugin.cpp
@@ -53,19 +53,6 @@ namespace Internal {
Q_LOGGING_CATEGORY(iosLog, "qtc.ios.common", QtWarningMsg)
-class IosDeployStepFactory : public BuildStepFactory
-{
-public:
- IosDeployStepFactory()
- {
- registerStep<IosDeployStep>(IosDeployStep::stepId());
- setDisplayName(IosDeployStep::tr("Deploy to iOS device or emulator"));
- setSupportedStepList(ProjectExplorer::Constants::BUILDSTEPS_DEPLOY);
- setSupportedDeviceTypes({Constants::IOS_DEVICE_TYPE, Constants::IOS_SIMULATOR_TYPE});
- setRepeatable(false);
- }
-};
-
class IosDeployConfigurationFactory : public DeployConfigurationFactory
{
public:
@@ -76,7 +63,7 @@ public:
addSupportedTargetDeviceType(Constants::IOS_DEVICE_TYPE);
addSupportedTargetDeviceType(Constants::IOS_SIMULATOR_TYPE);
setDefaultDisplayName(QCoreApplication::translate("Ios::Internal", "Deploy on iOS"));
- addInitialStep(IosDeployStep::stepId());
+ addInitialStep(IosDeployStepFactory::stepId());
}
};
diff --git a/src/plugins/ios/iosqtversion.cpp b/src/plugins/ios/iosqtversion.cpp
index 23fb2c5dde..35ca7f39b4 100644
--- a/src/plugins/ios/iosqtversion.cpp
+++ b/src/plugins/ios/iosqtversion.cpp
@@ -72,12 +72,6 @@ Abis IosQtVersion::detectQtAbis() const
return abis;
}
-void IosQtVersion::addToEnvironment(const Kit *k, Utils::Environment &env) const
-{
- Q_UNUSED(k)
- Q_UNUSED(env)
-}
-
QString IosQtVersion::description() const
{
//: Qt Version is meant for Ios
diff --git a/src/plugins/ios/iosqtversion.h b/src/plugins/ios/iosqtversion.h
index fa119d2f6f..5f82e94569 100644
--- a/src/plugins/ios/iosqtversion.h
+++ b/src/plugins/ios/iosqtversion.h
@@ -45,8 +45,6 @@ public:
ProjectExplorer::Abis detectQtAbis() const override;
- void addToEnvironment(const ProjectExplorer::Kit *k, Utils::Environment &env) const override;
-
QSet<Core::Id> availableFeatures() const override;
QSet<Core::Id> targetDeviceTypes() const override;
diff --git a/src/plugins/ios/iosrunconfiguration.cpp b/src/plugins/ios/iosrunconfiguration.cpp
index 674710df57..d1079ebec7 100644
--- a/src/plugins/ios/iosrunconfiguration.cpp
+++ b/src/plugins/ios/iosrunconfiguration.cpp
@@ -179,7 +179,7 @@ FilePath IosRunConfiguration::bundleDirectory() const
case BuildConfiguration::Debug :
case BuildConfiguration::Unknown :
if (isDevice)
- res = res.pathAppended("Debug-iphoneos");
+ res = res / "Debug-iphoneos";
else
res = res.pathAppended("Debug-iphonesimulator");
break;
diff --git a/src/plugins/ios/iossettingswidget.cpp b/src/plugins/ios/iossettingswidget.cpp
index d5612712cb..609a3a9ce9 100644
--- a/src/plugins/ios/iossettingswidget.cpp
+++ b/src/plugins/ios/iossettingswidget.cpp
@@ -73,7 +73,7 @@ IosSettingsWidget::IosSettingsWidget()
m_ui->deviceView->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
m_ui->pathWidget->setExpectedKind(Utils::PathChooser::ExistingDirectory);
m_ui->pathWidget->lineEdit()->setReadOnly(true);
- m_ui->pathWidget->setFileName(IosConfigurations::screenshotDir());
+ m_ui->pathWidget->setFilePath(IosConfigurations::screenshotDir());
m_ui->pathWidget->addButton(tr("Screenshot"), this,
std::bind(&IosSettingsWidget::onScreenshot, this));
@@ -280,7 +280,7 @@ void IosSettingsWidget::onScreenshot()
const auto generatePath = [this](const SimulatorInfo &info) {
const QString fileName = QString("%1_%2_%3.png").arg(info.name).arg(info.runtimeName)
.arg(QDateTime::currentDateTime().toString("yyyy-MM-dd_HH-mm-ss-z")).replace(' ', '_');
- return m_ui->pathWidget->fileName().pathAppended(fileName).toString();
+ return m_ui->pathWidget->filePath().pathAppended(fileName).toString();
};
QPointer<SimulatorOperationDialog> statusDialog = new SimulatorOperationDialog(this);
@@ -318,7 +318,7 @@ void IosSettingsWidget::onSelectionChanged()
void IosSettingsWidget::saveSettings()
{
IosConfigurations::setIgnoreAllDevices(!m_ui->deviceAskCheckBox->isChecked());
- IosConfigurations::setScreenshotDir(m_ui->pathWidget->fileName());
+ IosConfigurations::setScreenshotDir(m_ui->pathWidget->filePath());
}
} // namespace Internal
diff --git a/src/plugins/ios/iossettingswidget.h b/src/plugins/ios/iossettingswidget.h
index ee944a55ba..e99afb448d 100644
--- a/src/plugins/ios/iossettingswidget.h
+++ b/src/plugins/ios/iossettingswidget.h
@@ -58,7 +58,6 @@ private:
private:
Ui::IosSettingsWidget *m_ui = nullptr;
- bool m_saveSettingsRequested = false;
SimulatorControl *m_simControl = nullptr;
};
diff --git a/src/plugins/languageclient/CMakeLists.txt b/src/plugins/languageclient/CMakeLists.txt
index 9d04e7df1b..85d2227e12 100644
--- a/src/plugins/languageclient/CMakeLists.txt
+++ b/src/plugins/languageclient/CMakeLists.txt
@@ -16,6 +16,7 @@ add_qtc_plugin(LanguageClient
languageclientplugin.cpp languageclientplugin.h
languageclientquickfix.cpp languageclientquickfix.h
languageclientsettings.cpp languageclientsettings.h
+ languageclientsymbolsupport.cpp languageclientsymbolsupport.h
languageclientutils.cpp languageclientutils.h
languageclient_global.h
locatorfilter.cpp locatorfilter.h
diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp
index e3b8adc6d5..dcd19fd5c1 100644
--- a/src/plugins/languageclient/client.cpp
+++ b/src/plugins/languageclient/client.cpp
@@ -40,6 +40,7 @@
#include <projectexplorer/project.h>
#include <projectexplorer/session.h>
#include <texteditor/codeassist/documentcontentcompletion.h>
+#include <texteditor/codeassist/iassistprocessor.h>
#include <texteditor/syntaxhighlighter.h>
#include <texteditor/tabsettings.h>
#include <texteditor/textdocument.h>
@@ -99,6 +100,7 @@ Client::Client(BaseClientInterface *clientInterface)
, m_clientInterface(clientInterface)
, m_documentSymbolCache(this)
, m_hoverHandler(this)
+ , m_symbolSupport(this)
{
m_clientProviders.completionAssistProvider = new LanguageClientCompletionAssistProvider(this);
m_clientProviders.functionHintProvider = new FunctionHintAssistProvider(this);
@@ -146,6 +148,8 @@ Client::~Client()
highlighter->clearAllExtraFormats();
}
}
+ for (IAssistProcessor *processor : m_runningAssistProcessors)
+ processor->setAsyncProposalAvailable(nullptr);
updateEditorToolBar(m_openedDocument.keys());
}
@@ -250,6 +254,7 @@ void Client::initialize()
InitializeRequest initRequest;
auto params = initRequest.params().value_or(InitializeParams());
params.setCapabilities(generateClientCapabilities());
+ params.setInitializationOptions(m_initializationOptions);
if (m_project) {
params.setRootUri(DocumentUri::fromFilePath(m_project->projectDirectory()));
params.setWorkSpaceFolders(Utils::transform(SessionManager::projects(), [](Project *pro){
@@ -325,8 +330,11 @@ void Client::openDocument(TextEditor::TextDocument *document)
item.setVersion(document->document()->revision());
sendContent(DidOpenTextDocumentNotification(DidOpenTextDocumentParams(item)));
- if (LanguageClientManager::clientForDocument(document) == this)
+ const Client *currentClient = LanguageClientManager::clientForDocument(document);
+ if (currentClient == this) // this is the active client for the document so directly activate it
activateDocument(document);
+ else if (currentClient == nullptr) // there is no client for this document so assign it to this server
+ LanguageClientManager::openDocumentWithClient(document, this);
}
void Client::sendContent(const IContent &content)
@@ -374,15 +382,17 @@ void Client::activateDocument(TextEditor::TextDocument *document)
auto uri = DocumentUri::fromFilePath(document->filePath());
showDiagnostics(uri);
SemanticHighligtingSupport::applyHighlight(document, m_highlights.value(uri), capabilities());
- // only replace the assist provider if the completion provider is the default one or null
- if (!document->completionAssistProvider()
- || qobject_cast<TextEditor::DocumentContentCompletionProvider *>(
- document->completionAssistProvider())) {
- m_resetAssistProvider[document] = {document->completionAssistProvider(),
- document->functionHintAssistProvider(),
- document->quickFixAssistProvider()};
+ // only replace the assist provider if the language server support it
+ if (m_serverCapabilities.completionProvider()) {
+ m_resetAssistProvider[document].completionAssistProvider = document->completionAssistProvider();
document->setCompletionAssistProvider(m_clientProviders.completionAssistProvider);
+ }
+ if (m_serverCapabilities.signatureHelpProvider()) {
+ m_resetAssistProvider[document].functionHintProvider = document->functionHintAssistProvider();
document->setFunctionHintAssistProvider(m_clientProviders.functionHintProvider);
+ }
+ if (m_serverCapabilities.codeActionProvider()) {
+ m_resetAssistProvider[document].quickFixAssistProvider = document->quickFixAssistProvider();
document->setQuickFixAssistProvider(m_clientProviders.quickFixAssistProvider);
}
document->setFormatter(new LanguageClientFormatter(document, this));
@@ -506,7 +516,14 @@ void Client::documentContentsChanged(TextEditor::TextDocument *document,
DidChangeTextDocumentParams::TextDocumentContentChangeEvent change;
QTextDocument oldDoc(m_openedDocument[document]);
QTextCursor cursor(&oldDoc);
- cursor.setPosition(position + charsRemoved);
+ // Workaround https://bugreports.qt.io/browse/QTBUG-80662
+ // The contentsChanged gives a character count that can be wrong for QTextCursor
+ // when there are special characters removed/added (like formating characters).
+ // Also, characterCount return the number of characters + 1 because of the hidden
+ // paragraph separator character.
+ // This implementation is based on QWidgetTextControlPrivate::_q_contentsChanged.
+ // For charsAdded, textAt handles the case itself.
+ cursor.setPosition(qMin(oldDoc.characterCount() - 1, position + charsRemoved));
cursor.setPosition(position, QTextCursor::KeepAnchor);
change.setRange(Range(cursor));
change.setRangeLength(cursor.selectionEnd() - cursor.selectionStart());
@@ -537,43 +554,6 @@ void Client::unregisterCapabilities(const QList<Unregistration> &unregistrations
m_dynamicCapabilities.unregisterCapability(unregistrations);
}
-template <typename Request>
-static bool sendTextDocumentPositionParamsRequest(Client *client,
- const Request &request,
- const DynamicCapabilities &dynamicCapabilities,
- const optional<bool> &serverCapability)
-{
- if (!request.isValid(nullptr))
- return false;
- const DocumentUri uri = request.params().value().textDocument().uri();
- const bool supportedFile = client->isSupportedUri(uri);
- bool sendMessage = dynamicCapabilities.isRegistered(Request::methodName).value_or(false);
- if (sendMessage) {
- const TextDocumentRegistrationOptions option(dynamicCapabilities.option(Request::methodName));
- if (option.isValid(nullptr))
- sendMessage = option.filterApplies(FilePath::fromString(QUrl(uri).adjusted(QUrl::PreferLocalFile).toString()));
- else
- sendMessage = supportedFile;
- } else {
- sendMessage = serverCapability.value_or(sendMessage) && supportedFile;
- }
- if (sendMessage)
- client->sendContent(request);
- return sendMessage;
-}
-
-bool Client::findLinkAt(GotoDefinitionRequest &request)
-{
- return LanguageClient::sendTextDocumentPositionParamsRequest(
- this, request, m_dynamicCapabilities, m_serverCapabilities.definitionProvider());
-}
-
-bool Client::findUsages(FindReferencesRequest &request)
-{
- return LanguageClient::sendTextDocumentPositionParamsRequest(
- this, request, m_dynamicCapabilities, m_serverCapabilities.referencesProvider());
-}
-
TextEditor::HighlightingResult createHighlightingResult(const SymbolInformation &info)
{
if (!info.isValid(nullptr))
@@ -636,6 +616,11 @@ void Client::cursorPositionChanged(TextEditor::TextEditorWidget *widget)
sendContent(request);
}
+SymbolSupport &Client::symbolSupport()
+{
+ return m_symbolSupport;
+}
+
void Client::requestCodeActions(const DocumentUri &uri, const QList<Diagnostic> &diagnostics)
{
const Utils::FilePath fileName = uri.toFilePath();
@@ -829,7 +814,12 @@ const ProjectExplorer::Project *Client::project() const
void Client::setCurrentProject(ProjectExplorer::Project *project)
{
+ using namespace ProjectExplorer;
+ if (m_project)
+ disconnect(m_project, &Project::fileListChanged, this, &Client::projectFileListChanged);
m_project = project;
+ if (m_project)
+ connect(m_project, &Project::fileListChanged, this, &Client::projectFileListChanged);
}
void Client::projectOpened(ProjectExplorer::Project *project)
@@ -865,11 +855,26 @@ void Client::projectClosed(ProjectExplorer::Project *project)
sendContent(change);
}
+void Client::projectFileListChanged()
+{
+ for (Core::IDocument *doc : Core::DocumentModel::openedDocuments()) {
+ if (m_project->isKnownFile(doc->filePath())) {
+ if (auto textDocument = qobject_cast<TextEditor::TextDocument *>(doc))
+ openDocument(textDocument);
+ }
+ }
+}
+
void Client::setSupportedLanguage(const LanguageFilter &filter)
{
m_languagFilter = filter;
}
+void Client::setInitializationOptions(const QJsonObject &initializationOptions)
+{
+ m_initializationOptions = initializationOptions;
+}
+
bool Client::isSupportedDocument(const TextEditor::TextDocument *document) const
{
QTC_ASSERT(document, return false);
@@ -887,11 +892,22 @@ bool Client::isSupportedUri(const DocumentUri &uri) const
Utils::mimeTypeForFile(uri.toFilePath().fileName()).name());
}
+void Client::addAssistProcessor(TextEditor::IAssistProcessor *processor)
+{
+ m_runningAssistProcessors.insert(processor);
+}
+
+void Client::removeAssistProcessor(TextEditor::IAssistProcessor *processor)
+{
+ m_runningAssistProcessors.remove(processor);
+}
+
bool Client::needsRestart(const BaseSettings *settings) const
{
QTC_ASSERT(settings, return false);
return m_languagFilter.mimeTypes != settings->m_languageFilter.mimeTypes
- || m_languagFilter.filePattern != settings->m_languageFilter.filePattern;
+ || m_languagFilter.filePattern != settings->m_languageFilter.filePattern
+ || m_initializationOptions != settings->initializationOptions();
}
QList<Diagnostic> Client::diagnosticsAt(const DocumentUri &uri, const Range &range) const
@@ -926,6 +942,9 @@ bool Client::reset()
document->disconnect(this);
for (TextEditor::TextDocument *document : m_resetAssistProvider.keys())
resetAssistProviders(document);
+ for (TextEditor::IAssistProcessor *processor : m_runningAssistProcessors)
+ processor->setAsyncProposalAvailable(nullptr);
+ m_runningAssistProcessors.clear();
return true;
}
@@ -1029,13 +1048,52 @@ void Client::showMessageBox(const ShowMessageRequestParams &message, const Messa
box->show();
}
+static void addDiagnosticsSelections(const Diagnostic &diagnostic,
+ QTextDocument *textDocument,
+ QList<QTextEdit::ExtraSelection> &extraSelections)
+{
+ QTextCursor cursor(textDocument);
+ cursor.setPosition(::Utils::Text::positionInText(textDocument,
+ diagnostic.range().start().line() + 1,
+ diagnostic.range().start().character() + 1));
+ cursor.setPosition(::Utils::Text::positionInText(textDocument,
+ diagnostic.range().end().line() + 1,
+ diagnostic.range().end().character() + 1),
+ QTextCursor::KeepAnchor);
+
+ QTextCharFormat format;
+ const TextEditor::FontSettings& fontSettings = TextEditor::TextEditorSettings::instance()->fontSettings();
+ DiagnosticSeverity severity = diagnostic.severity().value_or(DiagnosticSeverity::Warning);
+
+ if (severity == DiagnosticSeverity::Error) {
+ format = fontSettings.toTextCharFormat(TextEditor::C_ERROR);
+ } else {
+ format = fontSettings.toTextCharFormat(TextEditor::C_WARNING);
+ }
+
+ extraSelections.push_back(std::move(QTextEdit::ExtraSelection{cursor, format}));
+}
+
void Client::showDiagnostics(const DocumentUri &uri)
{
const FilePath &filePath = uri.toFilePath();
if (TextEditor::TextDocument *doc = TextEditor::TextDocument::textDocumentForFilePath(
- uri.toFilePath())) {
- for (const Diagnostic &diagnostic : m_diagnostics.value(uri))
+ filePath)) {
+ QList<QTextEdit::ExtraSelection> extraSelections;
+
+ for (const Diagnostic &diagnostic : m_diagnostics.value(uri)) {
doc->addMark(new TextMark(filePath, diagnostic, id()));
+ addDiagnosticsSelections(diagnostic, doc->document(), extraSelections);
+ }
+
+ for (Core::IEditor *editor : Core::DocumentModel::editorsForDocument(doc)) {
+ if (auto textEditor = qobject_cast<TextEditor::BaseTextEditor *>(editor)) {
+ TextEditor::TextEditorWidget *widget = textEditor->editorWidget();
+
+ widget->setExtraSelections(TextEditor::TextEditorWidget::CodeWarningsSelection,
+ extraSelections);
+ }
+ }
}
}
@@ -1048,11 +1106,17 @@ void Client::removeDiagnostics(const DocumentUri &uri)
void Client::resetAssistProviders(TextEditor::TextDocument *document)
{
const AssistProviders providers = m_resetAssistProvider.take(document);
- if (document->completionAssistProvider() == m_clientProviders.completionAssistProvider)
+
+ if (document->completionAssistProvider() == m_clientProviders.completionAssistProvider &&
+ providers.completionAssistProvider)
document->setCompletionAssistProvider(providers.completionAssistProvider);
- if (document->functionHintAssistProvider() == m_clientProviders.functionHintProvider)
+
+ if (document->functionHintAssistProvider() == m_clientProviders.functionHintProvider &&
+ providers.functionHintProvider)
document->setFunctionHintAssistProvider(providers.functionHintProvider);
- if (document->quickFixAssistProvider() == m_clientProviders.quickFixAssistProvider)
+
+ if (document->quickFixAssistProvider() == m_clientProviders.quickFixAssistProvider &&
+ providers.quickFixAssistProvider)
document->setQuickFixAssistProvider(providers.quickFixAssistProvider);
}
@@ -1169,9 +1233,18 @@ void Client::handleDiagnostics(const PublishDiagnosticsParams &params)
void Client::handleSemanticHighlight(const SemanticHighlightingParams &params)
{
- const DocumentUri &uri = params.textDocument().uri();
+ DocumentUri uri;
+ LanguageClientValue<int> version;
+ auto textDocument = params.textDocument();
+
+ if (Utils::holds_alternative<VersionedTextDocumentIdentifier>(textDocument)) {
+ uri = Utils::get<VersionedTextDocumentIdentifier>(textDocument).uri();
+ version = Utils::get<VersionedTextDocumentIdentifier>(textDocument).version();
+ } else {
+ uri = Utils::get<TextDocumentIdentifier>(textDocument).uri();
+ }
+
m_highlights[uri].clear();
- const LanguageClientValue<int> &version = params.textDocument().version();
TextEditor::TextDocument *doc = TextEditor::TextDocument::textDocumentForFilePath(
uri.toFilePath());
diff --git a/src/plugins/languageclient/client.h b/src/plugins/languageclient/client.h
index b2a91307f1..97078e12d2 100644
--- a/src/plugins/languageclient/client.h
+++ b/src/plugins/languageclient/client.h
@@ -34,6 +34,7 @@
#include "languageclienthoverhandler.h"
#include "languageclientquickfix.h"
#include "languageclientsettings.h"
+#include "languageclientsymbolsupport.h"
#include <coreplugin/id.h>
#include <coreplugin/messagemanager.h>
@@ -59,6 +60,7 @@ namespace Core { class IDocument; }
namespace ProjectExplorer { class Project; }
namespace TextEditor
{
+class IAssistProcessor;
class TextDocument;
class TextEditorWidget;
class TextMark;
@@ -110,10 +112,10 @@ public:
int charsAdded);
void registerCapabilities(const QList<LanguageServerProtocol::Registration> &registrations);
void unregisterCapabilities(const QList<LanguageServerProtocol::Unregistration> &unregistrations);
- bool findLinkAt(LanguageServerProtocol::GotoDefinitionRequest &request);
- bool findUsages(LanguageServerProtocol::FindReferencesRequest &request);
void cursorPositionChanged(TextEditor::TextEditorWidget *widget);
+ SymbolSupport &symbolSupport();
+
void requestCodeActions(const LanguageServerProtocol::DocumentUri &uri,
const QList<LanguageServerProtocol::Diagnostic> &diagnostics);
void requestCodeActions(const LanguageServerProtocol::CodeActionRequest &request);
@@ -129,6 +131,7 @@ public:
const ProjectExplorer::Project *project() const;
void projectOpened(ProjectExplorer::Project *project);
void projectClosed(ProjectExplorer::Project *project);
+ void projectFileListChanged();
void sendContent(const LanguageServerProtocol::IContent &content);
void sendContent(const LanguageServerProtocol::DocumentUri &uri,
@@ -136,10 +139,14 @@ public:
void cancelRequest(const LanguageServerProtocol::MessageId &id);
void setSupportedLanguage(const LanguageFilter &filter);
+ void setInitializationOptions(const QJsonObject& initializationOptions);
bool isSupportedDocument(const TextEditor::TextDocument *document) const;
bool isSupportedFile(const Utils::FilePath &filePath, const QString &mimeType) const;
bool isSupportedUri(const LanguageServerProtocol::DocumentUri &uri) const;
+ void addAssistProcessor(TextEditor::IAssistProcessor *processor);
+ void removeAssistProcessor(TextEditor::IAssistProcessor *processor);
+
void setName(const QString &name) { m_displayName = name; }
QString name() const { return m_displayName; }
@@ -210,6 +217,7 @@ private:
QHash<QByteArray, ContentHandler> m_contentHandler;
QString m_displayName;
LanguageFilter m_languagFilter;
+ QJsonObject m_initializationOptions;
QMap<TextEditor::TextDocument *, QString> m_openedDocument;
Core::Id m_id;
LanguageServerProtocol::ServerCapabilities m_serverCapabilities;
@@ -231,6 +239,8 @@ private:
HoverHandler m_hoverHandler;
QHash<LanguageServerProtocol::DocumentUri, TextEditor::HighlightingResults> m_highlights;
const ProjectExplorer::Project *m_project = nullptr;
+ QSet<TextEditor::IAssistProcessor *> m_runningAssistProcessors;
+ SymbolSupport m_symbolSupport;
};
} // namespace LanguageClient
diff --git a/src/plugins/languageclient/languageclient.pro b/src/plugins/languageclient/languageclient.pro
index f6a2930d71..25fe9b5fcc 100644
--- a/src/plugins/languageclient/languageclient.pro
+++ b/src/plugins/languageclient/languageclient.pro
@@ -17,6 +17,7 @@ HEADERS += \
languageclientplugin.h \
languageclientquickfix.h \
languageclientsettings.h \
+ languageclientsymbolsupport.h \
languageclientutils.h \
locatorfilter.h \
lsplogger.h \
@@ -37,6 +38,7 @@ SOURCES += \
languageclientplugin.cpp \
languageclientquickfix.cpp \
languageclientsettings.cpp \
+ languageclientsymbolsupport.cpp \
languageclientutils.cpp \
locatorfilter.cpp \
lsplogger.cpp \
diff --git a/src/plugins/languageclient/languageclient.qbs b/src/plugins/languageclient/languageclient.qbs
index 0502921b9e..18b34c963c 100644
--- a/src/plugins/languageclient/languageclient.qbs
+++ b/src/plugins/languageclient/languageclient.qbs
@@ -42,6 +42,8 @@ QtcPlugin {
"languageclientquickfix.h",
"languageclientsettings.cpp",
"languageclientsettings.h",
+ "languageclientsymbolsupport.cpp",
+ "languageclientsymbolsupport.h",
"languageclientutils.cpp",
"languageclientutils.h",
"locatorfilter.cpp",
diff --git a/src/plugins/languageclient/languageclientcompletionassist.cpp b/src/plugins/languageclient/languageclientcompletionassist.cpp
index 8b5aa94dba..0bccccbff6 100644
--- a/src/plugins/languageclient/languageclientcompletionassist.cpp
+++ b/src/plugins/languageclient/languageclientcompletionassist.cpp
@@ -285,7 +285,7 @@ private:
QPointer<QTextDocument> m_document;
QPointer<Client> m_client;
- MessageId m_currentRequest;
+ Utils::optional<MessageId> m_currentRequest;
int m_pos = -1;
};
@@ -318,9 +318,14 @@ IAssistProposal *LanguageClientCompletionAssistProcessor::perform(const AssistIn
}
CompletionRequest completionRequest;
CompletionParams::CompletionContext context;
- context.setTriggerKind(interface->reason() == ActivationCharacter
- ? CompletionParams::TriggerCharacter
- : CompletionParams::Invoked);
+ if (interface->reason() == ActivationCharacter) {
+ context.setTriggerKind(CompletionParams::TriggerCharacter);
+ QChar triggerCharacter = interface->characterAt(interface->position() - 1);
+ if (!triggerCharacter.isNull())
+ context.setTriggerCharacter(triggerCharacter);
+ } else {
+ context.setTriggerKind(CompletionParams::Invoked);
+ }
auto params = completionRequest.params().value_or(CompletionParams());
int line;
int column;
@@ -337,6 +342,7 @@ IAssistProposal *LanguageClientCompletionAssistProcessor::perform(const AssistIn
});
completionRequest.setParams(params);
m_client->sendContent(completionRequest);
+ m_client->addAssistProcessor(this);
m_currentRequest = completionRequest.id();
m_document = interface->textDocument();
qCDebug(LOGLSPCOMPLETION) << QTime::currentTime()
@@ -347,14 +353,15 @@ IAssistProposal *LanguageClientCompletionAssistProcessor::perform(const AssistIn
bool LanguageClientCompletionAssistProcessor::running()
{
- return m_currentRequest.isValid();
+ return m_currentRequest.has_value();
}
void LanguageClientCompletionAssistProcessor::cancel()
{
if (running()) {
- m_client->cancelRequest(m_currentRequest);
- m_currentRequest = MessageId();
+ m_client->cancelRequest(m_currentRequest.value());
+ m_client->removeAssistProcessor(this);
+ m_currentRequest.reset();
}
}
@@ -363,7 +370,7 @@ void LanguageClientCompletionAssistProcessor::handleCompletionResponse(
{
// We must report back to the code assistant under all circumstances
qCDebug(LOGLSPCOMPLETION) << QTime::currentTime() << " : got completions";
- m_currentRequest = MessageId();
+ m_currentRequest.reset();
QTC_ASSERT(m_client, setAsyncProposalAvailable(nullptr); return);
if (auto error = response.error())
m_client->log(error.value());
@@ -371,6 +378,7 @@ void LanguageClientCompletionAssistProcessor::handleCompletionResponse(
const Utils::optional<CompletionResult> &result = response.result();
if (!result || Utils::holds_alternative<std::nullptr_t>(*result)) {
setAsyncProposalAvailable(nullptr);
+ m_client->removeAssistProcessor(this);
return;
}
@@ -391,6 +399,7 @@ void LanguageClientCompletionAssistProcessor::handleCompletionResponse(
proposal->setFragile(true);
proposal->setSupportsPrefix(false);
setAsyncProposalAvailable(proposal);
+ m_client->removeAssistProcessor(this);
qCDebug(LOGLSPCOMPLETION) << QTime::currentTime() << " : "
<< items.count() << " completions handled";
}
diff --git a/src/plugins/languageclient/languageclientfunctionhint.cpp b/src/plugins/languageclient/languageclientfunctionhint.cpp
index 3361864973..37635799e8 100644
--- a/src/plugins/languageclient/languageclientfunctionhint.cpp
+++ b/src/plugins/languageclient/languageclientfunctionhint.cpp
@@ -57,7 +57,9 @@ private:
QString FunctionHintProposalModel::text(int index) const
{
- return m_sigis.signatures().size() > index ? m_sigis.signatures().at(index).label() : QString();
+ if (index < 0 || m_sigis.signatures().size() >= index)
+ return {};
+ return m_sigis.signatures().at(index).label();
}
class FunctionHintProcessor : public IAssistProcessor
@@ -65,7 +67,7 @@ class FunctionHintProcessor : public IAssistProcessor
public:
explicit FunctionHintProcessor(Client *client) : m_client(client) {}
IAssistProposal *perform(const AssistInterface *interface) override;
- bool running() override { return m_currentRequest.isValid(); }
+ bool running() override { return m_currentRequest.has_value(); }
bool needsRestart() const override { return true; }
void cancel() override;
@@ -73,7 +75,7 @@ private:
void handleSignatureResponse(const SignatureHelpRequest::Response &response);
QPointer<Client> m_client;
- MessageId m_currentRequest;
+ Utils::optional<MessageId> m_currentRequest;
int m_pos = -1;
};
@@ -95,19 +97,25 @@ IAssistProposal *FunctionHintProcessor::perform(const AssistInterface *interface
void FunctionHintProcessor::cancel()
{
if (running()) {
- m_client->cancelRequest(m_currentRequest);
- m_currentRequest = MessageId();
+ m_client->cancelRequest(m_currentRequest.value());
+ m_client->removeAssistProcessor(this);
+ m_currentRequest.reset();
}
}
void FunctionHintProcessor::handleSignatureResponse(const SignatureHelpRequest::Response &response)
{
- m_currentRequest = MessageId();
+ m_currentRequest.reset();
if (auto error = response.error())
m_client->log(error.value());
- FunctionHintProposalModelPtr model(
- new FunctionHintProposalModel(response.result().value().value()));
- setAsyncProposalAvailable(new FunctionHintProposal(m_pos, model));
+ m_client->removeAssistProcessor(this);
+ const SignatureHelp &signatureHelp = response.result().value().value();
+ if (signatureHelp.signatures().isEmpty()) {
+ setAsyncProposalAvailable(nullptr);
+ } else {
+ FunctionHintProposalModelPtr model(new FunctionHintProposalModel(signatureHelp));
+ setAsyncProposalAvailable(new FunctionHintProposal(m_pos, model));
+ }
}
FunctionHintAssistProvider::FunctionHintAssistProvider(Client *client)
diff --git a/src/plugins/languageclient/languageclienthoverhandler.cpp b/src/plugins/languageclient/languageclienthoverhandler.cpp
index a7ffb54978..619473364f 100644
--- a/src/plugins/languageclient/languageclienthoverhandler.cpp
+++ b/src/plugins/languageclient/languageclienthoverhandler.cpp
@@ -65,6 +65,16 @@ void HoverHandler::identifyMatch(TextEditor::TextEditorWidget *editorWidget,
report(Priority_None);
return;
}
+ auto uri = DocumentUri::fromFilePath(editorWidget->textDocument()->filePath());
+ QTextCursor tc = editorWidget->textCursor();
+ tc.setPosition(pos);
+ QList<Diagnostic> diagnostics = m_client->diagnosticsAt(uri, Range(Position(tc), Position(tc)));
+ if (!diagnostics.isEmpty()) {
+ const QStringList messages = Utils::transform(diagnostics, &Diagnostic::message);
+ setToolTip(messages.join('\n'));
+ report(Priority_Diagnostic);
+ return;
+ }
bool sendMessage = m_client->capabilities().hoverProvider().value_or(false);
if (Utils::optional<bool> registered = m_client->dynamicCapabilities().isRegistered(
@@ -86,7 +96,6 @@ void HoverHandler::identifyMatch(TextEditor::TextEditorWidget *editorWidget,
}
m_report = report;
- auto uri = DocumentUri::fromFilePath(editorWidget->textDocument()->filePath());
QTextCursor cursor = editorWidget->textCursor();
cursor.setPosition(pos);
TextDocumentPositionParams params(uri, Position(cursor));
diff --git a/src/plugins/languageclient/languageclientmanager.cpp b/src/plugins/languageclient/languageclientmanager.cpp
index b2c65f511b..41dc0f31b4 100644
--- a/src/plugins/languageclient/languageclientmanager.cpp
+++ b/src/plugins/languageclient/languageclientmanager.cpp
@@ -35,6 +35,7 @@
#include <languageserverprotocol/messages.h>
#include <projectexplorer/session.h>
#include <projectexplorer/project.h>
+#include <projectexplorer/projectexplorer.h>
#include <texteditor/texteditor.h>
#include <texteditor/textmark.h>
#include <texteditor/textdocument.h>
@@ -244,11 +245,8 @@ void LanguageClientManager::applySettings()
}
if (!documents.isEmpty()) {
Client *client = startClient(setting);
- for (TextEditor::TextDocument *document : documents) {
- if (managerInstance->m_clientForDocument.value(document).isNull())
- managerInstance->m_clientForDocument[document] = client;
+ for (TextEditor::TextDocument *document : documents)
client->openDocument(document);
- }
}
break;
}
@@ -331,13 +329,21 @@ Client *LanguageClientManager::clientForUri(const DocumentUri &uri)
return clientForFilePath(uri.toFilePath());
}
-void LanguageClientManager::reOpenDocumentWithClient(TextEditor::TextDocument *document, Client *client)
+void LanguageClientManager::openDocumentWithClient(TextEditor::TextDocument *document, Client *client)
{
- Utils::ExecuteOnDestruction outlineUpdater(&TextEditor::IOutlineWidgetFactory::updateOutline);
- if (Client *currentClient = clientForDocument(document))
+ Client *currentClient = clientForDocument(document);
+ if (client == currentClient)
+ return;
+ if (currentClient)
currentClient->deactivateDocument(document);
managerInstance->m_clientForDocument[document] = client;
- client->activateDocument(document);
+ if (client) {
+ if (!client->documentOpen(document))
+ client->openDocument(document);
+ else
+ client->activateDocument(document);
+ }
+ TextEditor::IOutlineWidgetFactory::updateOutline();
}
void LanguageClientManager::logBaseMessage(const LspLogMessage::MessageSender sender,
@@ -399,13 +405,15 @@ void LanguageClientManager::editorOpened(Core::IEditor *editor)
if (auto *textEditor = qobject_cast<BaseTextEditor *>(editor)) {
if (TextEditorWidget *widget = textEditor->editorWidget()) {
connect(widget, &TextEditorWidget::requestLinkAt, this,
- [this, document = textEditor->textDocument()]
+ [document = textEditor->textDocument()]
(const QTextCursor &cursor, Utils::ProcessLinkCallback &callback, bool resolveTarget) {
- findLinkAt(document, cursor, callback, resolveTarget);
+ if (auto client = clientForDocument(document))
+ client->symbolSupport().findLinkAt(document, cursor, callback, resolveTarget);
});
connect(widget, &TextEditorWidget::requestUsages, this,
- [this, document = textEditor->textDocument()](const QTextCursor &cursor) {
- findUsages(document, cursor);
+ [document = textEditor->textDocument()](const QTextCursor &cursor) {
+ if (auto client = clientForDocument(document))
+ client->symbolSupport().findUsages(document, cursor);
});
connect(widget, &TextEditorWidget::cursorPositionChanged, this, [this, widget]() {
// TODO This would better be a compressing timer
@@ -457,22 +465,12 @@ void LanguageClientManager::documentOpened(Core::IDocument *document)
} else if (setting->m_startBehavior == BaseSettings::RequiresFile && clients.isEmpty()) {
clients << startClient(setting);
}
- for (auto client : clients) {
- openDocumentWithClient(textDocument, client);
- if (!m_clientForDocument.contains(textDocument))
- m_clientForDocument[textDocument] = client;
- }
+ for (auto client : clients)
+ client->openDocument(textDocument);
}
}
}
-void LanguageClientManager::openDocumentWithClient(TextEditor::TextDocument *document,
- Client *client)
-{
- if (client && client->state() != Client::Error)
- client->openDocument(document);
-}
-
void LanguageClientManager::documentClosed(Core::IDocument *document)
{
if (auto textDocument = qobject_cast<TextEditor::TextDocument *>(document)) {
@@ -498,117 +496,7 @@ void LanguageClientManager::documentWillSave(Core::IDocument *document)
}
}
-void LanguageClientManager::findLinkAt(TextEditor::TextDocument *document,
- const QTextCursor &cursor,
- Utils::ProcessLinkCallback callback,
- bool resolveTarget)
-{
- const DocumentUri uri = DocumentUri::fromFilePath(document->filePath());
- const TextDocumentIdentifier documentId(uri);
- const Position pos(cursor);
- TextDocumentPositionParams params(documentId, pos);
- GotoDefinitionRequest request(params);
- request.setResponseCallback([callback, filePath = document->filePath(), cursor, resolveTarget]
- (const GotoDefinitionRequest::Response &response) {
- if (Utils::optional<GotoResult> _result = response.result()) {
- const GotoResult result = _result.value();
- if (Utils::holds_alternative<std::nullptr_t>(result))
- return;
- auto wordUnderCursor = [cursor, filePath]() {
- QTextCursor linkCursor = cursor;
- linkCursor.select(QTextCursor::WordUnderCursor);
- Utils::Link link(filePath.toString(),
- linkCursor.blockNumber() + 1,
- linkCursor.positionInBlock());
- link.linkTextStart = linkCursor.selectionStart();
- link.linkTextEnd = linkCursor.selectionEnd();
- return link;
- };
- if (auto ploc = Utils::get_if<Location>(&result)) {
- callback(resolveTarget ? ploc->toLink() : wordUnderCursor());
- } else if (auto plloc = Utils::get_if<QList<Location>>(&result)) {
- if (!plloc->isEmpty())
- callback(resolveTarget ? plloc->value(0).toLink() : wordUnderCursor());
- }
- }
- });
- if (Client *client = clientForUri(uri)) {
- if (client->reachable())
- client->findLinkAt(request);
- }
-}
-
-QList<Core::SearchResultItem> generateSearchResultItems(const LanguageClientArray<Location> &locations)
-{
- auto convertPosition = [](const Position &pos){
- return Core::Search::TextPosition(pos.line() + 1, pos.character());
- };
- auto convertRange = [convertPosition](const Range &range){
- return Core::Search::TextRange(convertPosition(range.start()), convertPosition(range.end()));
- };
- QList<Core::SearchResultItem> result;
- if (locations.isNull())
- return result;
- QMap<QString, QList<Core::Search::TextRange>> rangesInDocument;
- for (const Location &location : locations.toList())
- rangesInDocument[location.uri().toFilePath().toString()] << convertRange(location.range());
- for (auto it = rangesInDocument.begin(); it != rangesInDocument.end(); ++it) {
- const QString &fileName = it.key();
- QFile file(fileName);
- file.open(QFile::ReadOnly);
-
- Core::SearchResultItem item;
- item.path = QStringList() << fileName;
- item.useTextEditorFont = true;
-
- QStringList lines = QString::fromLocal8Bit(file.readAll()).split(QChar::LineFeed);
- for (const Core::Search::TextRange &range : it.value()) {
- item.mainRange = range;
- if (file.isOpen() && range.begin.line > 0 && range.begin.line <= lines.size())
- item.text = lines[range.begin.line - 1];
- else
- item.text.clear();
- result << item;
- }
- }
- return result;
-}
-
-void LanguageClientManager::findUsages(TextEditor::TextDocument *document, const QTextCursor &cursor)
-{
- const DocumentUri uri = DocumentUri::fromFilePath(document->filePath());
- const TextDocumentIdentifier documentId(uri);
- const Position pos(cursor);
- QTextCursor termCursor(cursor);
- termCursor.select(QTextCursor::WordUnderCursor);
- ReferenceParams params(TextDocumentPositionParams(documentId, pos));
- params.setContext(ReferenceParams::ReferenceContext(true));
- FindReferencesRequest request(params);
- auto callback = [this, wordUnderCursor = termCursor.selectedText()]
- (const QString &clientName, const FindReferencesRequest::Response &response){
- if (auto result = response.result()) {
- Core::SearchResult *search = Core::SearchResultWindow::instance()->startNewSearch(
- tr("Find References with %1 for:").arg(clientName), "", wordUnderCursor);
- search->addResults(generateSearchResultItems(result.value()), Core::SearchResult::AddOrdered);
- QObject::connect(search, &Core::SearchResult::activated,
- [](const Core::SearchResultItem& item) {
- Core::EditorManager::openEditorAtSearchResult(item);
- });
- search->finishSearch(false);
- search->popup();
- }
- };
- for (Client *client : reachableClients()) {
- request.setResponseCallback([callback, clientName = client->name()]
- (const FindReferencesRequest::Response &response){
- callback(clientName, response);
- });
- if (client->findUsages(request))
- m_exclusiveRequests[request.id()] << client;
- }
-}
-
-void LanguageClientManager::projectAdded(ProjectExplorer::Project *project)
+void LanguageClientManager::updateProject(ProjectExplorer::Project *project)
{
for (BaseSettings *setting : m_currentSettings) {
if (setting->isValid()
@@ -618,11 +506,18 @@ void LanguageClientManager::projectAdded(ProjectExplorer::Project *project)
[project](QPointer<Client> client) {
return client->project() == project;
})
- == nullptr) {
+ == nullptr) {
+ Client *newClient = nullptr;
for (Core::IDocument *doc : Core::DocumentModel::openedDocuments()) {
- if (setting->m_languageFilter.isSupported(doc)) {
- if (project->isKnownFile(doc->filePath()))
- startClient(setting, project);
+ if (setting->m_languageFilter.isSupported(doc)
+ && project->isKnownFile(doc->filePath())) {
+ if (auto textDoc = qobject_cast<TextEditor::TextDocument *>(doc)) {
+ if (!newClient)
+ newClient = startClient(setting, project);
+ if (!newClient)
+ break;
+ newClient->openDocument(textDoc);
+ }
}
}
}
@@ -632,8 +527,16 @@ void LanguageClientManager::projectAdded(ProjectExplorer::Project *project)
interface->projectOpened(project);
}
+void LanguageClientManager::projectAdded(ProjectExplorer::Project *project)
+{
+ connect(project, &ProjectExplorer::Project::fileListChanged, this, [this, project]() {
+ updateProject(project);
+ });
+}
+
void LanguageClientManager::projectRemoved(ProjectExplorer::Project *project)
{
+ project->disconnect(this);
for (Client *interface : m_clients)
interface->projectClosed(project);
}
diff --git a/src/plugins/languageclient/languageclientmanager.h b/src/plugins/languageclient/languageclientmanager.h
index ae30540f44..aece267d0d 100644
--- a/src/plugins/languageclient/languageclientmanager.h
+++ b/src/plugins/languageclient/languageclientmanager.h
@@ -83,7 +83,13 @@ public:
static Client *clientForDocument(TextEditor::TextDocument *document);
static Client *clientForFilePath(const Utils::FilePath &filePath);
static Client *clientForUri(const LanguageServerProtocol::DocumentUri &uri);
- static void reOpenDocumentWithClient(TextEditor::TextDocument *document, Client *client);
+
+ ///
+ /// \brief openDocumentWithClient
+ /// makes sure the document is opened and activated with the client and
+ /// deactivates the document for a potential previous active client
+ ///
+ static void openDocumentWithClient(TextEditor::TextDocument *document, Client *client);
static void logBaseMessage(const LspLogMessage::MessageSender sender,
const QString &clientName,
@@ -98,14 +104,11 @@ private:
void editorOpened(Core::IEditor *editor);
void documentOpened(Core::IDocument *document);
- void openDocumentWithClient(TextEditor::TextDocument *document, Client *client);
void documentClosed(Core::IDocument *document);
void documentContentsSaved(Core::IDocument *document);
void documentWillSave(Core::IDocument *document);
- void findLinkAt(TextEditor::TextDocument *document, const QTextCursor &cursor,
- Utils::ProcessLinkCallback callback, const bool resolveTarget);
- void findUsages(TextEditor::TextDocument *document, const QTextCursor &cursor);
+ void updateProject(ProjectExplorer::Project *project);
void projectAdded(ProjectExplorer::Project *project);
void projectRemoved(ProjectExplorer::Project *project);
diff --git a/src/plugins/languageclient/languageclientoutline.cpp b/src/plugins/languageclient/languageclientoutline.cpp
index 9655509229..89f19b04a5 100644
--- a/src/plugins/languageclient/languageclientoutline.cpp
+++ b/src/plugins/languageclient/languageclientoutline.cpp
@@ -187,6 +187,9 @@ void LanguageClientOutlineWidget::handleResponse(const DocumentUri &uri,
m_model.setInfo(Utils::get<QList<DocumentSymbol>>(result));
else
m_model.clear();
+
+ // The list has changed, update the current items
+ updateSelectionInTree(m_editor->textCursor());
}
void LanguageClientOutlineWidget::updateTextCursor(const QModelIndex &proxyIndex)
@@ -313,6 +316,9 @@ void OutlineComboBox::updateModel(const DocumentUri &resultUri, const DocumentSy
m_model.setInfo(Utils::get<QList<DocumentSymbol>>(result));
else
m_model.clear();
+
+ // The list has changed, update the current item
+ updateEntry();
}
void OutlineComboBox::updateEntry()
diff --git a/src/plugins/languageclient/languageclientquickfix.cpp b/src/plugins/languageclient/languageclientquickfix.cpp
index f3b86377ae..6556947dba 100644
--- a/src/plugins/languageclient/languageclientquickfix.cpp
+++ b/src/plugins/languageclient/languageclientquickfix.cpp
@@ -84,7 +84,7 @@ class LanguageClientQuickFixAssistProcessor : public IAssistProcessor
{
public:
explicit LanguageClientQuickFixAssistProcessor(Client *client) : m_client(client) {}
- bool running() override { return m_currentRequest.isValid(); }
+ bool running() override { return m_currentRequest.has_value(); }
IAssistProposal *perform(const AssistInterface *interface) override;
void cancel() override;
@@ -93,7 +93,7 @@ private:
QSharedPointer<const AssistInterface> m_assistInterface;
Client *m_client = nullptr; // not owned
- MessageId m_currentRequest;
+ Utils::optional<MessageId> m_currentRequest;
};
IAssistProposal *LanguageClientQuickFixAssistProcessor::perform(const AssistInterface *interface)
@@ -131,15 +131,16 @@ IAssistProposal *LanguageClientQuickFixAssistProcessor::perform(const AssistInte
void LanguageClientQuickFixAssistProcessor::cancel()
{
if (running()) {
- m_client->cancelRequest(m_currentRequest);
- m_currentRequest = MessageId();
+ m_client->cancelRequest(m_currentRequest.value());
+ m_client->removeAssistProcessor(this);
+ m_currentRequest.reset();
}
}
void LanguageClientQuickFixAssistProcessor::handleCodeActionResponse(
const CodeActionRequest::Response &response)
{
- m_currentRequest = MessageId();
+ m_currentRequest.reset();
if (const Utils::optional<CodeActionRequest::Response::Error> &error = response.error())
m_client->log(*error);
QuickFixOperations ops;
@@ -154,6 +155,7 @@ void LanguageClientQuickFixAssistProcessor::handleCodeActionResponse(
}
}
}
+ m_client->removeAssistProcessor(this);
setAsyncProposalAvailable(GenericProposal::createProposal(m_assistInterface.data(), ops));
}
diff --git a/src/plugins/languageclient/languageclientsettings.cpp b/src/plugins/languageclient/languageclientsettings.cpp
index c27a8f599a..decbfdca76 100644
--- a/src/plugins/languageclient/languageclientsettings.cpp
+++ b/src/plugins/languageclient/languageclientsettings.cpp
@@ -52,6 +52,7 @@
#include <QDir>
#include <QFileInfo>
#include <QHeaderView>
+#include <QJsonDocument>
#include <QLabel>
#include <QListView>
#include <QMimeData>
@@ -68,6 +69,7 @@ constexpr char enabledKey[] = "enabled";
constexpr char startupBehaviorKey[] = "startupBehavior";
constexpr char mimeTypeKey[] = "mimeType";
constexpr char filePatternKey[] = "filePattern";
+constexpr char initializationOptionsKey[] = "initializationOptions";
constexpr char executableKey[] = "executable";
constexpr char argumentsKey[] = "arguments";
constexpr char settingsGroupKey[] = "LanguageClient";
@@ -465,12 +467,19 @@ QModelIndex LanguageClientSettingsModel::indexForSetting(BaseSettings *setting)
return index < 0 ? QModelIndex() : createIndex(index, 0, setting);
}
+QJsonObject BaseSettings::initializationOptions() const
+{
+ return QJsonDocument::fromJson(Utils::globalMacroExpander()->
+ expand(m_initializationOptions).toUtf8()).object();
+}
+
void BaseSettings::applyFromSettingsWidget(QWidget *widget)
{
if (auto settingsWidget = qobject_cast<BaseSettingsWidget *>(widget)) {
m_name = settingsWidget->name();
m_languageFilter = settingsWidget->filter();
m_startBehavior = settingsWidget->startupBehavior();
+ m_initializationOptions = settingsWidget->initializationOptions();
}
}
@@ -505,6 +514,7 @@ Client *BaseSettings::createClient()
auto *client = new Client(interface);
client->setName(Utils::globalMacroExpander()->expand(m_name));
client->setSupportedLanguage(m_languageFilter);
+ client->setInitializationOptions(initializationOptions());
return client;
}
@@ -517,6 +527,7 @@ QVariantMap BaseSettings::toMap() const
map.insert(startupBehaviorKey, m_startBehavior);
map.insert(mimeTypeKey, m_languageFilter.mimeTypes);
map.insert(filePatternKey, m_languageFilter.filePattern);
+ map.insert(initializationOptionsKey, m_initializationOptions);
return map;
}
@@ -530,6 +541,7 @@ void BaseSettings::fromMap(const QVariantMap &map)
m_languageFilter.mimeTypes = map[mimeTypeKey].toStringList();
m_languageFilter.filePattern = map[filePatternKey].toStringList();
m_languageFilter.filePattern.removeAll({}); // remove empty entries
+ m_initializationOptions = map[initializationOptionsKey].toString();
}
static LanguageClientSettingsPage &settingsPage()
@@ -706,13 +718,16 @@ BaseSettingsWidget::BaseSettingsWidget(const BaseSettings *settings, QWidget *pa
, m_mimeTypes(new QLabel(settings->m_languageFilter.mimeTypes.join(filterSeparator), this))
, m_filePattern(new QLineEdit(settings->m_languageFilter.filePattern.join(filterSeparator), this))
, m_startupBehavior(new QComboBox)
+ , m_initializationOptions(new Utils::FancyLineEdit(this))
{
int row = 0;
auto *mainLayout = new QGridLayout;
+
mainLayout->addWidget(new QLabel(tr("Name:")), row, 0);
mainLayout->addWidget(m_name, row, 1);
auto chooser = new Core::VariableChooser(this);
chooser->addSupportedWidget(m_name);
+
mainLayout->addWidget(new QLabel(tr("Language:")), ++row, 0);
auto mimeLayout = new QHBoxLayout;
mimeLayout->addWidget(m_mimeTypes);
@@ -722,6 +737,7 @@ BaseSettingsWidget::BaseSettingsWidget(const BaseSettings *settings, QWidget *pa
mainLayout->addLayout(mimeLayout, row, 1);
m_filePattern->setPlaceholderText(tr("File pattern"));
mainLayout->addWidget(m_filePattern, ++row, 1);
+
mainLayout->addWidget(new QLabel(tr("Startup behavior:")), ++row, 0);
for (int behavior = 0; behavior < BaseSettings::LastSentinel ; ++behavior)
m_startupBehavior->addItem(startupBehaviorString(BaseSettings::StartBehavior(behavior)));
@@ -757,6 +773,33 @@ BaseSettingsWidget::BaseSettingsWidget(const BaseSettings *settings, QWidget *pa
mainLayout->addWidget(createCapabilitiesView(QJsonValue(capabilities)), row, 1);
});
}
+
+ mainLayout->addWidget(new QLabel(tr("Initialization options:")), ++row, 0);
+ mainLayout->addWidget(m_initializationOptions, row, 1);
+ chooser->addSupportedWidget(m_initializationOptions);
+ m_initializationOptions->setValidationFunction([](Utils::FancyLineEdit *edit, QString *errorMessage) {
+ const QString value = Utils::globalMacroExpander()->expand(edit->text());
+
+ if (value.isEmpty())
+ return true;
+
+ QJsonParseError parseInfo;
+ const QJsonDocument json = QJsonDocument::fromJson(value.toUtf8(), &parseInfo);
+
+ if (json.isNull()) {
+ if (errorMessage)
+ *errorMessage = tr("Failed to parse JSON at %1: %2")
+ .arg(parseInfo.offset)
+ .arg(parseInfo.errorString());
+ return false;
+ }
+ return true;
+ });
+ m_initializationOptions->setText(settings->m_initializationOptions);
+ m_initializationOptions->setPlaceholderText(tr("Language server-specific JSON to pass via "
+ "\"initializationOptions\" field of \"initialize\" "
+ "request."));
+
setLayout(mainLayout);
}
@@ -776,6 +819,11 @@ BaseSettings::StartBehavior BaseSettingsWidget::startupBehavior() const
return BaseSettings::StartBehavior(m_startupBehavior->currentIndex());
}
+QString BaseSettingsWidget::initializationOptions() const
+{
+ return m_initializationOptions->text();
+}
+
class MimeTypeModel : public QStringListModel
{
public:
@@ -890,7 +938,7 @@ StdIOSettingsWidget::StdIOSettingsWidget(const StdIOSettings *settings, QWidget
QString StdIOSettingsWidget::executable() const
{
- return m_executable->path();
+ return m_executable->filePath().toString();
}
QString StdIOSettingsWidget::arguments() const
diff --git a/src/plugins/languageclient/languageclientsettings.h b/src/plugins/languageclient/languageclientsettings.h
index 579a2e36e9..6e7b5589ef 100644
--- a/src/plugins/languageclient/languageclientsettings.h
+++ b/src/plugins/languageclient/languageclientsettings.h
@@ -32,6 +32,7 @@
#include <utils/fileutils.h>
#include <QAbstractItemModel>
+#include <QJsonObject>
#include <QLabel>
#include <QPointer>
#include <QUuid>
@@ -45,6 +46,7 @@ QT_END_NAMESPACE
namespace Utils {
class FilePath;
class PathChooser;
+class FancyLineEdit;
} // namespace Utils
namespace Core { class IDocument; }
@@ -82,6 +84,9 @@ public:
bool m_enabled = true;
StartBehavior m_startBehavior = RequiresFile;
LanguageFilter m_languageFilter;
+ QString m_initializationOptions;
+
+ QJsonObject initializationOptions() const;
virtual void applyFromSettingsWidget(QWidget *widget);
virtual QWidget *createSettingsWidget(QWidget *parent = nullptr) const;
@@ -155,6 +160,7 @@ public:
BaseSettings::StartBehavior startupBehavior() const;
bool alwaysOn() const;
bool requiresProject() const;
+ QString initializationOptions() const;
private:
void showAddMimeTypeDialog();
@@ -163,6 +169,7 @@ private:
QLabel *m_mimeTypes = nullptr;
QLineEdit *m_filePattern = nullptr;
QComboBox *m_startupBehavior = nullptr;
+ Utils::FancyLineEdit *m_initializationOptions = nullptr;
static constexpr char filterSeparator = ';';
};
diff --git a/src/plugins/languageclient/languageclientsymbolsupport.cpp b/src/plugins/languageclient/languageclientsymbolsupport.cpp
new file mode 100644
index 0000000000..db065ed061
--- /dev/null
+++ b/src/plugins/languageclient/languageclientsymbolsupport.cpp
@@ -0,0 +1,198 @@
+/****************************************************************************
+**
+** 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 "languageclientsymbolsupport.h"
+
+#include "client.h"
+
+#include <coreplugin/editormanager/editormanager.h>
+#include <coreplugin/find/searchresultwindow.h>
+
+using namespace LanguageServerProtocol;
+
+namespace LanguageClient {
+
+SymbolSupport::SymbolSupport(Client *client) : m_client(client)
+{}
+
+template<typename Request>
+static void sendTextDocumentPositionParamsRequest(Client *client,
+ const Request &request,
+ const DynamicCapabilities &dynamicCapabilities,
+ const Utils::optional<bool> &serverCapability)
+{
+ if (!request.isValid(nullptr))
+ return;
+ const DocumentUri uri = request.params().value().textDocument().uri();
+ const bool supportedFile = client->isSupportedUri(uri);
+ bool sendMessage = dynamicCapabilities.isRegistered(Request::methodName).value_or(false);
+ if (sendMessage) {
+ const TextDocumentRegistrationOptions option(
+ dynamicCapabilities.option(Request::methodName));
+ if (option.isValid(nullptr))
+ sendMessage = option.filterApplies(
+ Utils::FilePath::fromString(QUrl(uri).adjusted(QUrl::PreferLocalFile).toString()));
+ else
+ sendMessage = supportedFile;
+ } else {
+ sendMessage = serverCapability.value_or(sendMessage) && supportedFile;
+ }
+ if (sendMessage)
+ client->sendContent(request);
+}
+
+static void handleGotoDefinitionResponse(const GotoDefinitionRequest::Response &response,
+ Utils::ProcessLinkCallback callback,
+ Utils::optional<Utils::Link> linkUnderCursor)
+{
+ if (Utils::optional<GotoResult> _result = response.result()) {
+ const GotoResult result = _result.value();
+ if (Utils::holds_alternative<std::nullptr_t>(result))
+ return;
+ if (auto ploc = Utils::get_if<Location>(&result)) {
+ callback(linkUnderCursor.value_or(ploc->toLink()));
+ } else if (auto plloc = Utils::get_if<QList<Location>>(&result)) {
+ if (!plloc->isEmpty())
+ callback(linkUnderCursor.value_or(plloc->value(0).toLink()));
+ }
+ }
+}
+
+static TextDocumentPositionParams generateDocPosParams(TextEditor::TextDocument *document,
+ const QTextCursor &cursor)
+{
+ const DocumentUri uri = DocumentUri::fromFilePath(document->filePath());
+ const TextDocumentIdentifier documentId(uri);
+ const Position pos(cursor);
+ return TextDocumentPositionParams(documentId, pos);
+}
+
+void SymbolSupport::findLinkAt(TextEditor::TextDocument *document,
+ const QTextCursor &cursor,
+ Utils::ProcessLinkCallback callback,
+ const bool resolveTarget)
+{
+ if (!m_client->reachable())
+ return;
+ GotoDefinitionRequest request(generateDocPosParams(document, cursor));
+ Utils::optional<Utils::Link> linkUnderCursor;
+ if (!resolveTarget) {
+ QTextCursor linkCursor = cursor;
+ linkCursor.select(QTextCursor::WordUnderCursor);
+ Utils::Link link(document->filePath().toString(),
+ linkCursor.blockNumber() + 1,
+ linkCursor.positionInBlock());
+ link.linkTextStart = linkCursor.selectionStart();
+ link.linkTextEnd = linkCursor.selectionEnd();
+ linkUnderCursor = link;
+ }
+ request.setResponseCallback(
+ [callback, linkUnderCursor](const GotoDefinitionRequest::Response &response) {
+ handleGotoDefinitionResponse(response, callback, linkUnderCursor);
+ });
+
+ sendTextDocumentPositionParamsRequest(m_client,
+ request,
+ m_client->dynamicCapabilities(),
+ m_client->capabilities().referencesProvider());
+
+}
+
+QList<Core::SearchResultItem> generateSearchResultItems(
+ const LanguageClientArray<Location> &locations)
+{
+ auto convertPosition = [](const Position &pos) {
+ return Core::Search::TextPosition(pos.line() + 1, pos.character());
+ };
+ auto convertRange = [convertPosition](const Range &range) {
+ return Core::Search::TextRange(convertPosition(range.start()), convertPosition(range.end()));
+ };
+ QList<Core::SearchResultItem> result;
+ if (locations.isNull())
+ return result;
+ QMap<QString, QList<Core::Search::TextRange>> rangesInDocument;
+ for (const Location &location : locations.toList())
+ rangesInDocument[location.uri().toFilePath().toString()] << convertRange(location.range());
+ for (auto it = rangesInDocument.begin(); it != rangesInDocument.end(); ++it) {
+ const QString &fileName = it.key();
+ QFile file(fileName);
+ file.open(QFile::ReadOnly);
+
+ Core::SearchResultItem item;
+ item.path = QStringList() << fileName;
+ item.useTextEditorFont = true;
+
+ QStringList lines = QString::fromLocal8Bit(file.readAll()).split(QChar::LineFeed);
+ for (const Core::Search::TextRange &range : it.value()) {
+ item.mainRange = range;
+ if (file.isOpen() && range.begin.line > 0 && range.begin.line <= lines.size())
+ item.text = lines[range.begin.line - 1];
+ else
+ item.text.clear();
+ result << item;
+ }
+ }
+ return result;
+}
+
+void SymbolSupport::handleFindReferencesResponse(const FindReferencesRequest::Response &response,
+ const QString &wordUnderCursor)
+{
+ if (auto result = response.result()) {
+ Core::SearchResult *search = Core::SearchResultWindow::instance()->startNewSearch(
+ tr("Find References with %1 for:").arg(m_client->name()), "", wordUnderCursor);
+ search->addResults(generateSearchResultItems(result.value()),
+ Core::SearchResult::AddOrdered);
+ QObject::connect(search,
+ &Core::SearchResult::activated,
+ [](const Core::SearchResultItem &item) {
+ Core::EditorManager::openEditorAtSearchResult(item);
+ });
+ search->finishSearch(false);
+ search->popup();
+ }
+}
+
+void SymbolSupport::findUsages(TextEditor::TextDocument *document, const QTextCursor &cursor)
+{
+ if (!m_client->reachable())
+ return;
+ ReferenceParams params(generateDocPosParams(document, cursor));
+ params.setContext(ReferenceParams::ReferenceContext(true));
+ FindReferencesRequest request(params);
+ QTextCursor termCursor(cursor);
+ termCursor.select(QTextCursor::WordUnderCursor);
+ request.setResponseCallback([this, wordUnderCursor = termCursor.selectedText()](
+ const FindReferencesRequest::Response &response) {
+ handleFindReferencesResponse(response, wordUnderCursor);
+ });
+
+ sendTextDocumentPositionParamsRequest(m_client,
+ request,
+ m_client->dynamicCapabilities(),
+ m_client->capabilities().referencesProvider());
+}
+
+} // namespace LanguageClient
diff --git a/src/plugins/languageclient/languageclientsymbolsupport.h b/src/plugins/languageclient/languageclientsymbolsupport.h
new file mode 100644
index 0000000000..7d09545e7f
--- /dev/null
+++ b/src/plugins/languageclient/languageclientsymbolsupport.h
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** 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 <texteditor/textdocument.h>
+
+#include <languageserverprotocol/languagefeatures.h>
+
+namespace LanguageClient {
+
+class Client;
+
+class SymbolSupport
+{
+ Q_DECLARE_TR_FUNCTIONS(SymbolSupport)
+public:
+ explicit SymbolSupport(Client *client);
+
+ void findLinkAt(TextEditor::TextDocument *document,
+ const QTextCursor &cursor,
+ Utils::ProcessLinkCallback callback,
+ const bool resolveTarget);
+ void findUsages(TextEditor::TextDocument *document, const QTextCursor &cursor);
+
+private:
+ void handleFindReferencesResponse(
+ const LanguageServerProtocol::FindReferencesRequest::Response &response,
+ const QString &wordUnderCursor);
+
+ Client *m_client = nullptr;
+};
+
+} // namespace LanguageClient
diff --git a/src/plugins/languageclient/languageclientutils.cpp b/src/plugins/languageclient/languageclientutils.cpp
index 72bb015757..d6f6c1676b 100644
--- a/src/plugins/languageclient/languageclientutils.cpp
+++ b/src/plugins/languageclient/languageclientutils.cpp
@@ -231,7 +231,7 @@ void updateEditorToolBar(Core::IEditor *editor)
auto reopen = [action, client = QPointer<Client>(client), document]() {
if (!client)
return;
- LanguageClientManager::reOpenDocumentWithClient(document, client);
+ LanguageClientManager::openDocumentWithClient(document, client);
action->setChecked(true);
};
action->setCheckable(true);
diff --git a/src/plugins/languageclient/lsplogger.cpp b/src/plugins/languageclient/lsplogger.cpp
index 76a50a138f..a633d5c84c 100644
--- a/src/plugins/languageclient/lsplogger.cpp
+++ b/src/plugins/languageclient/lsplogger.cpp
@@ -251,10 +251,10 @@ void LspLoggerWidget::selectMatchingMessage(LspLogMessage::MessageSender sender,
[&](const LspLogMessage &message) { return matches(sender, id, message); });
if (!matchingMessage)
return;
- auto item = m_model.findItemByData(
+ auto index = m_model.findIndex(
[&](const LspLogMessage &message) { return &message == matchingMessage; });
- m_messages->selectionModel()->select(m_model.indexForItem(item), QItemSelectionModel::Select);
+ m_messages->selectionModel()->select(index, QItemSelectionModel::Select);
if (matchingMessage->sender == LspLogMessage::ServerMessage)
m_serverDetails->setMessage(matchingMessage->message);
else
@@ -265,7 +265,7 @@ void LspLoggerWidget::saveLog()
{
QString contents;
QTextStream stream(&contents);
- m_model.forItems([&](const LspLogMessage &message) {
+ m_model.forAllData([&](const LspLogMessage &message) {
stream << message.time.toString("hh:mm:ss.zzz") << ' ';
stream << (message.sender == LspLogMessage::ClientMessage ? QString{"Client"}
: QString{"Server"});
diff --git a/src/plugins/languageclient/semantichighlightsupport.cpp b/src/plugins/languageclient/semantichighlightsupport.cpp
index 8f333ea183..591280fa34 100644
--- a/src/plugins/languageclient/semantichighlightsupport.cpp
+++ b/src/plugins/languageclient/semantichighlightsupport.cpp
@@ -66,6 +66,8 @@ static Utils::optional<TextEditor::TextStyle> styleForScopes(const QList<QString
static const QMap<QString, TextEditor::TextStyle> styleForScopes = {
{"entity.name", TextEditor::C_TYPE},
{"entity.name.function", TextEditor::C_FUNCTION},
+ {"entity.name.function.method.static", TextEditor::C_GLOBAL},
+ {"entity.name.function.preprocessor", TextEditor::C_PREPROCESSOR},
{"entity.name.label", TextEditor::C_LABEL},
{"keyword", TextEditor::C_KEYWORD},
{"storage.type", TextEditor::C_KEYWORD},
@@ -76,6 +78,8 @@ static Utils::optional<TextEditor::TextStyle> styleForScopes(const QList<QString
{"variable.function", TextEditor::C_FUNCTION},
{"variable.other", TextEditor::C_LOCAL},
{"variable.other.member", TextEditor::C_FIELD},
+ {"variable.other.field", TextEditor::C_FIELD},
+ {"variable.other.field.static", TextEditor::C_GLOBAL},
{"variable.parameter", TextEditor::C_LOCAL},
};
diff --git a/src/plugins/macros/savedialog.cpp b/src/plugins/macros/savedialog.cpp
index 38b71883d7..d85e544670 100644
--- a/src/plugins/macros/savedialog.cpp
+++ b/src/plugins/macros/savedialog.cpp
@@ -28,7 +28,7 @@
#include <QLineEdit>
#include <QCheckBox>
-#include <QRegExpValidator>
+#include <QRegularExpressionValidator>
using namespace Macros::Internal;
@@ -37,7 +37,7 @@ SaveDialog::SaveDialog(QWidget *parent) :
ui(new Ui::SaveDialog)
{
ui->setupUi(this);
- ui->name->setValidator(new QRegExpValidator(QRegExp(QLatin1String("\\w*")), this));
+ ui->name->setValidator(new QRegularExpressionValidator(QRegularExpression(QLatin1String("\\w*")), this));
}
SaveDialog::~SaveDialog()
diff --git a/src/plugins/marketplace/productlistmodel.cpp b/src/plugins/marketplace/productlistmodel.cpp
index cded10ee37..bceb6595fa 100644
--- a/src/plugins/marketplace/productlistmodel.cpp
+++ b/src/plugins/marketplace/productlistmodel.cpp
@@ -32,20 +32,100 @@
#include <utils/networkaccessmanager.h>
#include <utils/qtcassert.h>
+#include <QDesktopServices>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
+#include <QLabel>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QPixmapCache>
#include <QRegularExpression>
+#include <QScrollArea>
#include <QTimer>
#include <QUrl>
+#include <QVBoxLayout>
namespace Marketplace {
namespace Internal {
+/**
+ * @brief AllProductsModel does not own its items. Using this model only to display
+ * the same items stored inside other models without the need to duplicate the items.
+ */
+class AllProductsModel : public ProductListModel
+{
+public:
+ explicit AllProductsModel(QObject *parent) : ProductListModel(parent) {}
+ ~AllProductsModel() override { m_items.clear(); }
+};
+
+class ProductGridView : public Core::GridView
+{
+public:
+ ProductGridView(QWidget *parent) : Core::GridView(parent) {}
+ QSize viewportSizeHint() const override
+ {
+ if (!model())
+ return Core::GridView::viewportSizeHint();
+
+ static int gridW = Core::GridProxyModel::GridItemWidth + Core::GridProxyModel::GridItemGap;
+ static int gridH = Core::GridProxyModel::GridItemHeight + Core::GridProxyModel::GridItemGap;
+ return QSize(model()->columnCount() * gridW, model()->rowCount() * gridH);
+ }
+
+ void setColumnCount(int columnCount)
+ {
+ if (columnCount < 1)
+ columnCount = 1;
+
+ auto gridProxyModel = static_cast<Core::GridProxyModel *>(model());
+ gridProxyModel->setColumnCount(columnCount);
+ }
+};
+
+class ProductItemDelegate : public Core::ListItemDelegate
+{
+public:
+ QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override
+ {
+ const Core::ListItem *item = index.data(Core::ListModel::ItemRole).value<Core::ListItem *>();
+
+ // "empty" items (last row of a section)
+ if (!item)
+ return Core::ListItemDelegate::sizeHint(option, index);
+
+ return QSize(Core::GridProxyModel::GridItemWidth + Core::GridProxyModel::GridItemGap,
+ Core::GridProxyModel::GridItemHeight + Core::GridProxyModel::GridItemGap);
+ }
+
+ void clickAction(const Core::ListItem *item) const override
+ {
+ QTC_ASSERT(item, return);
+ auto productItem = static_cast<const ProductItem *>(item);
+ const QUrl url(QString("https://marketplace.qt.io/products/").append(productItem->handle));
+ QDesktopServices::openUrl(url);
+ }
+};
+
+ProductListModel::ProductListModel(QObject *parent)
+ : Core::ListModel(parent)
+{
+}
+
+void ProductListModel::appendItems(const QList<Core::ListItem *> &items)
+{
+ beginInsertRows(QModelIndex(), m_items.size(), m_items.size() + items.size());
+ m_items.append(items);
+ endInsertRows();
+}
+
+const QList<Core::ListItem *> ProductListModel::items() const
+{
+ return m_items;
+}
+
static const QNetworkRequest constructRequest(const QString &collection)
{
QString url("https://marketplace.qt.io");
@@ -71,12 +151,52 @@ static const QString plainTextFromHtml(const QString &original)
return (plainText.length() > 157) ? plainText.left(157).append("...") : plainText;
}
-ProductListModel::ProductListModel(QObject *parent)
- : Core::ListModel(parent)
+static int priority(const QString &collection)
+{
+ if (collection == "featured")
+ return 10;
+ if (collection == "from-qt-partners")
+ return 20;
+ return 50;
+}
+
+SectionedProducts::SectionedProducts(QWidget *parent)
+ : QStackedWidget(parent)
+ , m_allProductsView(new ProductGridView(this))
+ , m_filteredAllProductsModel(new Core::ListModelFilter(new AllProductsModel(this), this))
+ , m_productDelegate(new ProductItemDelegate)
+{
+ auto area = new QScrollArea(this);
+ area->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ area->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
+ area->setFrameShape(QFrame::NoFrame);
+ area->setWidgetResizable(true);
+
+ auto sectionedView = new QWidget;
+ auto layout = new QVBoxLayout;
+ layout->addStretch();
+ sectionedView->setLayout(layout);
+ area->setWidget(sectionedView);
+
+ addWidget(area);
+
+ auto gridModel = new Core::GridProxyModel;
+ gridModel->setSourceModel(m_filteredAllProductsModel);
+ m_allProductsView->setItemDelegate(m_productDelegate);
+ m_allProductsView->setModel(gridModel);
+ addWidget(m_allProductsView);
+
+ connect(m_productDelegate, &ProductItemDelegate::tagClicked,
+ this, &SectionedProducts::onTagClicked);
+}
+
+SectionedProducts::~SectionedProducts()
{
+ qDeleteAll(m_gridViews.values());
+ delete m_productDelegate;
}
-void ProductListModel::updateCollections()
+void SectionedProducts::updateCollections()
{
emit toggleProgressIndicator(true);
QNetworkReply *reply = Utils::NetworkAccessManager::instance()->get(constructRequest({}));
@@ -86,11 +206,12 @@ void ProductListModel::updateCollections()
QPixmap ProductListModel::fetchPixmapAndUpdatePixmapCache(const QString &url) const
{
- const_cast<ProductListModel *>(this)->queueImageForDownload(url);
+ if (auto sectionedProducts = qobject_cast<SectionedProducts *>(parent()))
+ sectionedProducts->queueImageForDownload(url);
return QPixmap();
}
-void ProductListModel::onFetchCollectionsFinished(QNetworkReply *reply)
+void SectionedProducts::onFetchCollectionsFinished(QNetworkReply *reply)
{
QTC_ASSERT(reply, return);
Utils::ExecuteOnDestruction replyDeleter([reply]() { reply->deleteLater(); });
@@ -106,21 +227,23 @@ void ProductListModel::onFetchCollectionsFinished(QNetworkReply *reply)
const auto handle = obj.value("handle").toString();
const int productsCount = obj.value("products_count").toInt();
- if (productsCount > 0 && handle != "all-products" && handle != "qt-education-1")
+ if (productsCount > 0 && handle != "all-products" && handle != "qt-education-1") {
+ m_collectionTitles.insert(handle, obj.value("title").toString());
m_pendingCollections.append(handle);
+ }
}
if (!m_pendingCollections.isEmpty())
fetchCollectionsContents();
} else {
QVariant status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
if (status.isValid() && status.toInt() == 430)
- QTimer::singleShot(30000, this, &ProductListModel::updateCollections);
+ QTimer::singleShot(30000, this, &SectionedProducts::updateCollections);
else
emit errorOccurred(reply->error(), reply->errorString());
}
}
-void ProductListModel::onFetchSingleCollectionFinished(QNetworkReply *reply)
+void SectionedProducts::onFetchSingleCollectionFinished(QNetworkReply *reply)
{
emit toggleProgressIndicator(false);
@@ -133,12 +256,19 @@ void ProductListModel::onFetchSingleCollectionFinished(QNetworkReply *reply)
if (doc.isNull())
return;
+ QString collectionHandle = reply->url().path();
+ if (QTC_GUARD(collectionHandle.endsWith("/products.json"))) {
+ collectionHandle.chop(14);
+ collectionHandle = collectionHandle.mid(collectionHandle.lastIndexOf('/') + 1);
+ }
+
+ const QList<Core::ListItem *> presentItems = items();
const QJsonArray products = doc.object().value("products").toArray();
for (int i = 0, end = products.size(); i < end; ++i) {
const QJsonObject obj = products.at(i).toObject();
const QString handle = obj.value("handle").toString();
- bool foundItem = Utils::findOrDefault(m_items, [handle](const Core::ListItem *it) {
+ bool foundItem = Utils::findOrDefault(presentItems, [handle](const Core::ListItem *it) {
return static_cast<const ProductItem *>(it)->handle == handle;
});
if (foundItem)
@@ -164,9 +294,8 @@ void ProductListModel::onFetchSingleCollectionFinished(QNetworkReply *reply)
}
if (!productsForCollection.isEmpty()) {
- beginInsertRows(QModelIndex(), m_items.size(), m_items.size() + productsForCollection.size());
- m_items.append(productsForCollection);
- endInsertRows();
+ Section section{m_collectionTitles.value(collectionHandle), priority(collectionHandle)};
+ addNewSection(section, productsForCollection);
}
} else {
// bad.. but we still might be able to fetch another collection
@@ -175,11 +304,11 @@ void ProductListModel::onFetchSingleCollectionFinished(QNetworkReply *reply)
if (!m_pendingCollections.isEmpty()) // more collections? go ahead..
fetchCollectionsContents();
- else if (m_items.isEmpty())
+ else if (m_productModels.isEmpty())
emit errorOccurred(0, "Failed to fetch any collection.");
}
-void ProductListModel::fetchCollectionsContents()
+void SectionedProducts::fetchCollectionsContents()
{
QTC_ASSERT(!m_pendingCollections.isEmpty(), return);
const QString collection = m_pendingCollections.dequeue();
@@ -190,14 +319,34 @@ void ProductListModel::fetchCollectionsContents()
this, [this, reply]() { onFetchSingleCollectionFinished(reply); });
}
-void ProductListModel::queueImageForDownload(const QString &url)
+void SectionedProducts::queueImageForDownload(const QString &url)
{
m_pendingImages.insert(url);
if (!m_isDownloadingImage)
fetchNextImage();
}
-void ProductListModel::fetchNextImage()
+void SectionedProducts::setColumnCount(int columns)
+{
+ if (columns < 1)
+ columns = 1;
+ m_columnCount = columns;
+ for (ProductGridView *view : m_gridViews.values()) {
+ view->setColumnCount(columns);
+ view->setFixedSize(view->viewportSizeHint());
+ }
+ m_allProductsView->setColumnCount(columns);
+}
+
+void SectionedProducts::setSearchString(const QString &searchString)
+{
+ int view = searchString.isEmpty() ? 0 // sectioned view
+ : 1; // search view
+ setCurrentIndex(view);
+ m_filteredAllProductsModel->setSearchString(searchString);
+}
+
+void SectionedProducts::fetchNextImage()
{
if (m_pendingImages.isEmpty()) {
m_isDownloadingImage = false;
@@ -208,8 +357,10 @@ void ProductListModel::fetchNextImage()
const QString nextUrl = *it;
m_pendingImages.erase(it);
- if (QPixmapCache::find(nextUrl, nullptr)) { // this image is already cached
- updateModelIndexesForUrl(nextUrl); // it might have been added while downloading
+ if (QPixmapCache::find(nextUrl, nullptr)) {
+ // this image is already cached it might have been added while downloading
+ for (ProductListModel *model : m_productModels.values())
+ model->updateModelIndexesForUrl(nextUrl);
fetchNextImage();
return;
}
@@ -220,7 +371,7 @@ void ProductListModel::fetchNextImage()
this, [this, reply]() { onImageDownloadFinished(reply); });
}
-void ProductListModel::onImageDownloadFinished(QNetworkReply *reply)
+void SectionedProducts::onImageDownloadFinished(QNetworkReply *reply)
{
QTC_ASSERT(reply, return);
Utils::ExecuteOnDestruction replyDeleter([reply]() { reply->deleteLater(); });
@@ -232,13 +383,66 @@ void ProductListModel::onImageDownloadFinished(QNetworkReply *reply)
const QString url = reply->request().url().toString();
QPixmapCache::insert(url, pixmap.scaled(ProductListModel::defaultImageSize,
Qt::KeepAspectRatio, Qt::SmoothTransformation));
- updateModelIndexesForUrl(url);
+ for (ProductListModel *model : m_productModels.values())
+ model->updateModelIndexesForUrl(url);
}
} // handle error not needed - it's okay'ish to have no images as long as the rest works
fetchNextImage();
}
+void SectionedProducts::addNewSection(const Section &section, const QList<Core::ListItem *> &items)
+{
+ QTC_ASSERT(!items.isEmpty(), return);
+ ProductListModel *productModel = new ProductListModel(this);
+ productModel->appendItems(items);
+ auto filteredModel = new Core::ListModelFilter(productModel, this);
+ Core::GridProxyModel *gridModel = new Core::GridProxyModel;
+ gridModel->setSourceModel(filteredModel);
+ auto gridView = new ProductGridView(this);
+ gridView->setItemDelegate(m_productDelegate);
+ gridView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ gridView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ gridView->setModel(gridModel);
+ gridModel->setColumnCount(m_columnCount);
+
+ m_productModels.insert(section, productModel);
+ m_gridViews.insert(section, gridView);
+
+ QFont f = font();
+ f.setPixelSize(16);
+ auto sectionLabel = new QLabel(section.name);
+ sectionLabel->setFont(f);
+ auto scrollArea = qobject_cast<QScrollArea *>(widget(0));
+ auto vbox = qobject_cast<QVBoxLayout *>(scrollArea->widget()->layout());
+
+ // insert new section depending on its priority, but before the last (stretch) item
+ int position = m_gridViews.keys().indexOf(section) * 2; // a section has a label and a grid
+ QTC_ASSERT(position <= vbox->count() - 1, position = vbox->count() - 1);
+ vbox->insertWidget(position, sectionLabel);
+ vbox->insertWidget(position + 1, gridView);
+ gridView->setFixedSize(gridView->viewportSizeHint());
+
+ // add the items also to the all products model to be able to search correctly
+ auto allProducts = static_cast<ProductListModel *>(m_filteredAllProductsModel->sourceModel());
+ allProducts->appendItems(items);
+ m_allProductsView->setColumnCount(m_columnCount);
+}
+
+void SectionedProducts::onTagClicked(const QString &tag)
+{
+ setCurrentIndex(1 /* search */);
+ emit tagClicked(tag);
+}
+
+QList<Core::ListItem *> SectionedProducts::items()
+{
+ QList<Core::ListItem *> result;
+ for (const ProductListModel *model : m_productModels.values())
+ result.append(model->items());
+ return result;
+}
+
void ProductListModel::updateModelIndexesForUrl(const QString &url)
{
for (int row = 0, end = m_items.size(); row < end; ++row) {
diff --git a/src/plugins/marketplace/productlistmodel.h b/src/plugins/marketplace/productlistmodel.h
index 032008d6f7..cda47b52da 100644
--- a/src/plugins/marketplace/productlistmodel.h
+++ b/src/plugins/marketplace/productlistmodel.h
@@ -28,6 +28,7 @@
#include <coreplugin/welcomepagehelper.h>
#include <QQueue>
+#include <QStackedWidget>
QT_BEGIN_NAMESPACE
class QNetworkReply;
@@ -36,6 +37,9 @@ QT_END_NAMESPACE
namespace Marketplace {
namespace Internal {
+class ProductGridView;
+class ProductItemDelegate;
+
class ProductItem : public Core::ListItem
{
public:
@@ -44,31 +48,72 @@ public:
class ProductListModel : public Core::ListModel
{
- Q_OBJECT
public:
explicit ProductListModel(QObject *parent);
+ void appendItems(const QList<Core::ListItem *> &items);
+ const QList<Core::ListItem *> items() const;
+ void updateModelIndexesForUrl(const QString &url);
+
+protected:
+ QPixmap fetchPixmapAndUpdatePixmapCache(const QString &url) const override;
+};
+
+struct Section
+{
+ QString name;
+ int priority;
+};
+
+inline bool operator<(const Section &lhs, const Section &rhs)
+{
+ if (lhs.priority < rhs.priority)
+ return true;
+ return lhs.priority > rhs.priority ? false : lhs.name < rhs.name;
+}
+
+inline bool operator==(const Section &lhs, const Section &rhs)
+{
+ return lhs.priority == rhs.priority && lhs.name == rhs.name;
+}
+
+class SectionedProducts : public QStackedWidget
+{
+ Q_OBJECT
+public:
+ explicit SectionedProducts(QWidget *parent);
+ ~SectionedProducts() override;
void updateCollections();
+ void queueImageForDownload(const QString &url);
+ void setColumnCount(int columns);
+ void setSearchString(const QString &searchString);
signals:
void errorOccurred(int errorCode, const QString &errorString);
void toggleProgressIndicator(bool show);
-
-protected:
- QPixmap fetchPixmapAndUpdatePixmapCache(const QString &url) const override;
+ void tagClicked(const QString &tag);
private:
void onFetchCollectionsFinished(QNetworkReply *reply);
void onFetchSingleCollectionFinished(QNetworkReply *reply);
void fetchCollectionsContents();
- void queueImageForDownload(const QString &url);
void fetchNextImage();
void onImageDownloadFinished(QNetworkReply *reply);
- void updateModelIndexesForUrl(const QString &url);
+ void addNewSection(const Section &section, const QList<Core::ListItem *> &items);
+ void onTagClicked(const QString &tag);
+
+ QList<Core::ListItem *> items();
QQueue<QString> m_pendingCollections;
QSet<QString> m_pendingImages;
+ QMap<QString, QString> m_collectionTitles;
+ QMap<Section, ProductListModel *> m_productModels;
+ QMap<Section, ProductGridView *> m_gridViews;
+ ProductGridView *m_allProductsView = nullptr;
+ Core::ListModelFilter *m_filteredAllProductsModel = nullptr;
+ ProductItemDelegate *m_productDelegate = nullptr;
bool m_isDownloadingImage = false;
+ int m_columnCount = 1;
};
} // namespace Internal
diff --git a/src/plugins/marketplace/qtmarketplacewelcomepage.cpp b/src/plugins/marketplace/qtmarketplacewelcomepage.cpp
index 9e54b7b62f..beea69f670 100644
--- a/src/plugins/marketplace/qtmarketplacewelcomepage.cpp
+++ b/src/plugins/marketplace/qtmarketplacewelcomepage.cpp
@@ -60,27 +60,12 @@ Core::Id QtMarketplaceWelcomePage::id() const
return "Marketplace";
}
-class ProductItemDelegate : public Core::ListItemDelegate
-{
-public:
- void clickAction(const Core::ListItem *item) const override
- {
- QTC_ASSERT(item, return);
- auto productItem = static_cast<const ProductItem *>(item);
- const QUrl url(QString("https://marketplace.qt.io/products/").append(productItem->handle));
- QDesktopServices::openUrl(url);
- }
-};
-
class QtMarketplacePageWidget : public QWidget
{
public:
QtMarketplacePageWidget()
- : m_productModel(new ProductListModel(this))
{
const int sideMargin = 27;
- auto filteredModel = new Core::ListModelFilter(m_productModel, this);
-
auto searchBox = new Core::SearchBox(this);
m_searcher = searchBox->m_lineEdit;
m_searcher->setPlaceholderText(QtMarketplaceWelcomePage::tr("Search in Marketplace..."));
@@ -96,21 +81,18 @@ public:
m_errorLabel->setVisible(false);
vbox->addWidget(m_errorLabel);
- m_gridModel.setSourceModel(filteredModel);
-
- auto gridView = new Core::GridView(this);
- gridView->setModel(&m_gridModel);
- gridView->setItemDelegate(&m_productDelegate);
- vbox->addWidget(gridView);
-
+ m_sectionedProducts = new SectionedProducts(this);
auto progressIndicator = new Utils::ProgressIndicator(ProgressIndicatorSize::Large, this);
- progressIndicator->attachToWidget(gridView);
+ progressIndicator->attachToWidget(m_sectionedProducts);
progressIndicator->hide();
+ vbox->addWidget(m_sectionedProducts);
- connect(m_productModel, &ProductListModel::toggleProgressIndicator,
+ connect(m_sectionedProducts, &SectionedProducts::toggleProgressIndicator,
progressIndicator, &Utils::ProgressIndicator::setVisible);
- connect(m_productModel, &ProductListModel::errorOccurred,
- [this, searchBox](int, const QString &message) {
+ connect(m_sectionedProducts, &SectionedProducts::errorOccurred,
+ [this, progressIndicator, searchBox](int, const QString &message) {
+ progressIndicator->hide();
+ progressIndicator->deleteLater();
m_errorLabel->setAlignment(Qt::AlignHCenter);
QFont f(m_errorLabel->font());
f.setPixelSize(20);
@@ -126,17 +108,18 @@ public:
connect(m_errorLabel, &QLabel::linkActivated,
this, []() { QDesktopServices::openUrl(QUrl("https://marketplace.qt.io")); });
});
- connect(&m_productDelegate, &ProductItemDelegate::tagClicked,
- this, &QtMarketplacePageWidget::onTagClicked);
+
connect(m_searcher, &QLineEdit::textChanged,
- filteredModel, &Core::ListModelFilter::setSearchString);
+ m_sectionedProducts, &SectionedProducts::setSearchString);
+ connect(m_sectionedProducts, &SectionedProducts::tagClicked,
+ this, &QtMarketplacePageWidget::onTagClicked);
}
void showEvent(QShowEvent *event) override
{
if (!m_initialized) {
m_initialized = true;
- m_productModel->updateCollections();
+ m_sectionedProducts->updateCollections();
}
QWidget::showEvent(event);
}
@@ -144,7 +127,7 @@ public:
void resizeEvent(QResizeEvent *ev) final
{
QWidget::resizeEvent(ev);
- m_gridModel.setColumnCount(bestColumnCount());
+ m_sectionedProducts->setColumnCount(bestColumnCount());
}
int bestColumnCount() const
@@ -160,11 +143,9 @@ public:
}
private:
- ProductItemDelegate m_productDelegate;
- ProductListModel *m_productModel = nullptr;
+ SectionedProducts *m_sectionedProducts = nullptr;
QLabel *m_errorLabel = nullptr;
QLineEdit *m_searcher = nullptr;
- Core::GridProxyModel m_gridModel;
bool m_initialized = false;
};
diff --git a/src/plugins/mcusupport/mcusupportoptions.cpp b/src/plugins/mcusupport/mcusupportoptions.cpp
index 894eb9cb4c..ff7304de6d 100644
--- a/src/plugins/mcusupport/mcusupportoptions.cpp
+++ b/src/plugins/mcusupport/mcusupportoptions.cpp
@@ -85,7 +85,7 @@ McuPackage::McuPackage(const QString &label, const QString &defaultPath,
QString McuPackage::path() const
{
- return QFileInfo(m_fileChooser->path() + m_relativePathModifier).absoluteFilePath();
+ return QFileInfo(m_fileChooser->filePath().toString() + m_relativePathModifier).absoluteFilePath();
}
QString McuPackage::label() const
@@ -185,7 +185,7 @@ void McuPackage::updateStatus()
m_path = m_fileChooser->rawPath();
const bool validPath = m_fileChooser->isValid();
const Utils::FilePath detectionPath = Utils::FilePath::fromString(
- m_fileChooser->path() + "/" + m_detectionPath);
+ m_fileChooser->filePath().toString() + "/" + m_detectionPath);
const QString displayDetectionPath = Utils::FilePath::fromString(m_detectionPath).toUserOutput();
const bool validPackage = m_detectionPath.isEmpty() || detectionPath.exists();
diff --git a/src/plugins/mcusupport/mcusupportoptionspage.cpp b/src/plugins/mcusupport/mcusupportoptionspage.cpp
index 56db70972a..0eac2b096c 100644
--- a/src/plugins/mcusupport/mcusupportoptionspage.cpp
+++ b/src/plugins/mcusupport/mcusupportoptionspage.cpp
@@ -93,7 +93,7 @@ McuSupportOptionsWidget::McuSupportOptionsWidget()
mainLayout->addWidget(m_statusInfoLabel);
connect(m_statusInfoLabel, &QLabel::linkActivated, this, []{
Core::ICore::showOptionsDialog(
- CMakeProjectManager::Constants::CMAKE_SETTINGSPAGE_ID,
+ CMakeProjectManager::Constants::CMAKE_SETTINGS_PAGE_ID,
Core::ICore::mainWindow());
});
}
diff --git a/src/plugins/mcusupport/mcusupportsdk.cpp b/src/plugins/mcusupport/mcusupportsdk.cpp
index fec1033d25..7586daf92c 100644
--- a/src/plugins/mcusupport/mcusupportsdk.cpp
+++ b/src/plugins/mcusupport/mcusupportsdk.cpp
@@ -250,7 +250,7 @@ static QVector<McuTarget *> targetsFromDescriptions(const QList<McuTargetDescrip
QHash<QString, McuPackage *> freeRTOSPkgs;
QVector<McuTarget *> mcuTargets;
- for (auto desc : descriptions) {
+ for (const auto &desc : descriptions) {
McuToolChainPackage *tcPkg = tcPkgs.value(desc.toolchainId);
if (desc.toolchainId == "desktop") {
auto mcuTarget = new McuTarget(desc.platformVendor, desc.platform,
diff --git a/src/plugins/mercurial/srcdestdialog.cpp b/src/plugins/mercurial/srcdestdialog.cpp
index a1aec460fe..34d9339110 100644
--- a/src/plugins/mercurial/srcdestdialog.cpp
+++ b/src/plugins/mercurial/srcdestdialog.cpp
@@ -86,7 +86,7 @@ QString SrcDestDialog::getRepositoryString() const
return repoUrl.toString();
}
if (m_ui->localButton->isChecked())
- return m_ui->localPathChooser->path();
+ return m_ui->localPathChooser->filePath().toString();
return m_ui->urlLineEdit->text();
}
diff --git a/src/plugins/modeleditor/CMakeLists.txt b/src/plugins/modeleditor/CMakeLists.txt
index 69ff243b5c..0e19bdb24f 100644
--- a/src/plugins/modeleditor/CMakeLists.txt
+++ b/src/plugins/modeleditor/CMakeLists.txt
@@ -32,5 +32,4 @@ add_qtc_plugin(ModelEditor
EXPLICIT_MOC
actionhandler.h
modeleditor.h
- modeleditorfactory.h
)
diff --git a/src/plugins/modeleditor/componentviewcontroller.cpp b/src/plugins/modeleditor/componentviewcontroller.cpp
index 82c5290a1e..bb1d3c387f 100644
--- a/src/plugins/modeleditor/componentviewcontroller.cpp
+++ b/src/plugins/modeleditor/componentviewcontroller.cpp
@@ -190,7 +190,7 @@ void UpdateIncludeDependenciesVisitor::visitMComponent(qmt::MComponent *componen
if (!m_modelUtilities->haveDependency(component, includeComponent)) {
auto dependency = new qmt::MDependency;
dependency->setFlags(qmt::MElement::ReverseEngineered);
- dependency->setStereotypes(QStringList() << "include");
+ dependency->setStereotypes({"include"});
dependency->setDirection(qmt::MDependency::AToB);
dependency->setSource(component->uid());
dependency->setTarget(includeComponent->uid());
diff --git a/src/plugins/modeleditor/modeleditor.cpp b/src/plugins/modeleditor/modeleditor.cpp
index 08facc1c48..1f665ed352 100644
--- a/src/plugins/modeleditor/modeleditor.cpp
+++ b/src/plugins/modeleditor/modeleditor.cpp
@@ -1119,11 +1119,11 @@ void ModelEditor::initToolbars()
if (!tool.m_stereotype.isEmpty() && stereotypeIconElement != qmt::StereotypeIcon::ElementAny) {
const qmt::Style *style = documentController->styleController()->adaptStyle(styleEngineElementType);
icon = stereotypeController->createIcon(
- stereotypeIconElement, QStringList() << tool.m_stereotype,
+ stereotypeIconElement, {tool.m_stereotype},
QString(), style, QSize(128, 128), QMarginsF(6.0, 4.0, 6.0, 8.0), 8.0);
if (!icon.isNull()) {
QString stereotypeIconId = stereotypeController->findStereotypeIconId(
- stereotypeIconElement, QStringList() << tool.m_stereotype);
+ stereotypeIconElement, {tool.m_stereotype});
qmt::StereotypeIcon stereotypeIcon = stereotypeController->findStereotypeIcon(stereotypeIconId);
if (stereotypeIcon.hasName())
newElementName = stereotypeIcon.name();
diff --git a/src/plugins/modeleditor/packageviewcontroller.cpp b/src/plugins/modeleditor/packageviewcontroller.cpp
index 8b45a2443c..7f57a5a7e8 100644
--- a/src/plugins/modeleditor/packageviewcontroller.cpp
+++ b/src/plugins/modeleditor/packageviewcontroller.cpp
@@ -104,7 +104,7 @@ void PackageViewController::createAncestorDependencies(qmt::MObject *object1, qm
auto dependency = new qmt::MDependency;
dependency->setFlags(qmt::MElement::ReverseEngineered);
// TODO set stereotype for testing purpose
- dependency->setStereotypes(QStringList() << "same stereotype");
+ dependency->setStereotypes({"same stereotype"});
dependency->setDirection(qmt::MDependency::AToB);
dependency->setSource(componentAncestors.at(index1)->uid());
dependency->setTarget(includeComponentAncestors.at(index2)->uid());
@@ -125,7 +125,7 @@ void PackageViewController::createAncestorDependencies(qmt::MObject *object1, qm
auto dependency = new qmt::MDependency;
dependency->setFlags(qmt::MElement::ReverseEngineered);
// TODO set stereotype for testing purpose
- dependency->setStereotypes(QStringList() << "ancestor");
+ dependency->setStereotypes({"ancestor"});
dependency->setDirection(qmt::MDependency::AToB);
dependency->setSource(componentAncestors.at(componentHighestAncestorIndex)->uid());
dependency->setTarget(includeComponentAncestors.at(includeComponentHighestAncestorIndex)->uid());
@@ -140,7 +140,7 @@ void PackageViewController::createAncestorDependencies(qmt::MObject *object1, qm
auto dependency = new qmt::MDependency;
dependency->setFlags(qmt::MElement::ReverseEngineered);
// TODO set stereotype for testing purpose
- dependency->setStereotypes(QStringList() << "parents");
+ dependency->setStereotypes({"parents"});
dependency->setDirection(qmt::MDependency::AToB);
dependency->setSource(componentAncestors.at(0)->uid());
dependency->setTarget(includeComponentAncestors.at(0)->uid());
diff --git a/src/plugins/modeleditor/pxnodecontroller.cpp b/src/plugins/modeleditor/pxnodecontroller.cpp
index c30b1df9e5..fba2f1c8ca 100644
--- a/src/plugins/modeleditor/pxnodecontroller.cpp
+++ b/src/plugins/modeleditor/pxnodecontroller.cpp
@@ -302,7 +302,7 @@ void PxNodeController::onMenuActionTriggered(PxNodeController::MenuAction *actio
package->setFlags(qmt::MElement::ReverseEngineered);
package->setName(action->elementName);
if (!action->packageStereotype.isEmpty())
- package->setStereotypes(QStringList() << action->packageStereotype);
+ package->setStereotypes({action->packageStereotype});
newObject = package;
if (action->type == MenuAction::TYPE_ADD_PACKAGE_AND_DIAGRAM) {
auto diagram = new qmt::MCanvasDiagram();
@@ -317,7 +317,7 @@ void PxNodeController::onMenuActionTriggered(PxNodeController::MenuAction *actio
package->setFlags(qmt::MElement::ReverseEngineered);
package->setName(action->elementName);
if (!action->packageStereotype.isEmpty())
- package->setStereotypes(QStringList() << action->packageStereotype);
+ package->setStereotypes({action->packageStereotype});
d->diagramSceneController->modelController()->undoController()->beginMergeSequence(tr("Create Component Model"));
QStringList relativeElements = qmt::NameController::buildElementsPath(
d->pxnodeUtilities->calcRelativePath(filePath, d->anchorFolder), true);
diff --git a/src/plugins/nim/project/nimblebuildstep.cpp b/src/plugins/nim/project/nimblebuildstep.cpp
index 43fb20da23..1d29fbb1aa 100644
--- a/src/plugins/nim/project/nimblebuildstep.cpp
+++ b/src/plugins/nim/project/nimblebuildstep.cpp
@@ -43,24 +43,11 @@ using namespace Utils;
namespace {
-class NimParser : public IOutputParser
+class NimParser : public OutputTaskParser
{
-public:
- void stdOutput(const QString &line) final
- {
- parseLine(line.trimmed());
- IOutputParser::stdOutput(line);
- }
-
- void stdError(const QString &line) final
- {
- parseLine(line.trimmed());
- IOutputParser::stdError(line);
- }
-
-private:
- void parseLine(const QString &line)
+ Result handleLine(const QString &lne, Utils::OutputFormat) override
{
+ const QString line = lne.trimmed();
static QRegularExpression regex("(.+.nim)\\((\\d+), (\\d+)\\) (.+)",
QRegularExpression::OptimizeOnFirstUsageOption);
static QRegularExpression warning("(Warning):(.*)",
@@ -70,13 +57,13 @@ private:
QRegularExpressionMatch match = regex.match(line);
if (!match.hasMatch())
- return;
+ return Status::NotHandled;
const QString filename = match.captured(1);
bool lineOk = false;
const int lineNumber = match.captured(2).toInt(&lineOk);
const QString message = match.captured(4);
if (!lineOk)
- return;
+ return Status::NotHandled;
Task::TaskType type = Task::Unknown;
@@ -85,9 +72,14 @@ private:
else if (error.match(message).hasMatch())
type = Task::Error;
else
- return;
-
- emit addTask(CompileTask(type, message, FilePath::fromUserInput(filename), lineNumber));
+ return Status::NotHandled;
+
+ const CompileTask t(type, message, absoluteFilePath(FilePath::fromUserInput(filename)),
+ lineNumber);
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, t.file, t.line, match, 1);
+ scheduleTask(t, 1);
+ return {Status::Done, linkSpecs};
}
};
@@ -106,18 +98,22 @@ NimbleBuildStep::NimbleBuildStep(BuildStepList *parentList, Core::Id id)
bool NimbleBuildStep::init()
{
- auto parser = new NimParser();
- parser->setWorkingDirectory(project()->projectDirectory());
- setOutputParser(parser);
-
ProcessParameters* params = processParameters();
- params->setEnvironment(buildConfiguration()->environment());
- params->setMacroExpander(buildConfiguration()->macroExpander());
+ params->setEnvironment(buildEnvironment());
+ params->setMacroExpander(macroExpander());
params->setWorkingDirectory(project()->projectDirectory());
params->setCommandLine({QStandardPaths::findExecutable("nimble"), {"build", m_arguments}});
return AbstractProcessStep::init();
}
+void NimbleBuildStep::setupOutputFormatter(OutputFormatter *formatter)
+{
+ const auto parser = new NimParser();
+ parser->addSearchDir(project()->projectDirectory());
+ formatter->addLineParser(parser);
+ AbstractProcessStep::setupOutputFormatter(formatter);
+}
+
BuildStepConfigWidget *NimbleBuildStep::createConfigWidget()
{
return new NimbleBuildStepWidget(this);
@@ -156,13 +152,12 @@ QVariantMap NimbleBuildStep::toMap() const
QString NimbleBuildStep::defaultArguments() const
{
- QTC_ASSERT(buildConfiguration(), return {}; );
- switch (buildConfiguration()->buildType()) {
- case ProjectExplorer::BuildConfiguration::Debug:
+ switch (buildType()) {
+ case BuildConfiguration::Debug:
return {"--debugger:native"};
- case ProjectExplorer::BuildConfiguration::Unknown:
- case ProjectExplorer::BuildConfiguration::Profile:
- case ProjectExplorer::BuildConfiguration::Release:
+ case BuildConfiguration::Unknown:
+ case BuildConfiguration::Profile:
+ case BuildConfiguration::Release:
default:
return {};
}
diff --git a/src/plugins/nim/project/nimblebuildstep.h b/src/plugins/nim/project/nimblebuildstep.h
index 3a3af51046..7d903e5135 100644
--- a/src/plugins/nim/project/nimblebuildstep.h
+++ b/src/plugins/nim/project/nimblebuildstep.h
@@ -37,7 +37,7 @@ public:
NimbleBuildStep(ProjectExplorer::BuildStepList *parentList, Core::Id id);
bool init() override;
-
+ void setupOutputFormatter(Utils::OutputFormatter *formatter) override;
ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override;
QString arguments() const;
diff --git a/src/plugins/nim/project/nimblebuildsystem.cpp b/src/plugins/nim/project/nimblebuildsystem.cpp
index 537000e357..19f21878e7 100644
--- a/src/plugins/nim/project/nimblebuildsystem.cpp
+++ b/src/plugins/nim/project/nimblebuildsystem.cpp
@@ -41,7 +41,6 @@ using namespace Utils;
namespace Nim {
const char C_NIMBLEPROJECT_TASKS[] = "Nim.NimbleProject.Tasks";
-const char C_NIMBLEPROJECT_METADATA[] = "Nim.NimbleProject.Metadata";
static std::vector<NimbleTask> parseTasks(const QString &nimblePath, const QString &workingDirectory)
{
@@ -134,7 +133,12 @@ NimbleBuildSystem::NimbleBuildSystem(Target *target)
void NimbleBuildSystem::triggerParsing()
{
- m_guard = guardParsingRun();
+ // Only allow one parsing run at the same time:
+ auto guard = guardParsingRun();
+ if (!guard.guardsProject())
+ return;
+ m_guard = std::move(guard);
+
m_projectScanner.startScan();
}
diff --git a/src/plugins/nim/project/nimbletaskstep.cpp b/src/plugins/nim/project/nimbletaskstep.cpp
index 61cfb8f66e..f5f95160d3 100644
--- a/src/plugins/nim/project/nimbletaskstep.cpp
+++ b/src/plugins/nim/project/nimbletaskstep.cpp
@@ -31,6 +31,8 @@
#include <projectexplorer/buildstep.h>
#include <projectexplorer/buildconfiguration.h>
#include <projectexplorer/processparameters.h>
+#include <projectexplorer/projectexplorerconstants.h>
+
#include <utils/fileutils.h>
#include <QStandardPaths>
@@ -47,7 +49,7 @@ NimbleTaskStep::NimbleTaskStep(BuildStepList *parentList, Core::Id id)
bool NimbleTaskStep::init()
{
- processParameters()->setEnvironment(buildConfiguration()->environment());
+ processParameters()->setEnvironment(buildEnvironment());
processParameters()->setWorkingDirectory(project()->projectDirectory());
return validate() && AbstractProcessStep::init();
}
diff --git a/src/plugins/nim/project/nimbletaskstep.h b/src/plugins/nim/project/nimbletaskstep.h
index f8e7d375d4..15e67885cd 100644
--- a/src/plugins/nim/project/nimbletaskstep.h
+++ b/src/plugins/nim/project/nimbletaskstep.h
@@ -25,7 +25,7 @@
#pragma once
-#include <projectexplorer/processstep.h>
+#include <projectexplorer/abstractprocessstep.h>
namespace Nim {
diff --git a/src/plugins/nim/project/nimcompilerbuildstep.cpp b/src/plugins/nim/project/nimcompilerbuildstep.cpp
index 5159e45946..9015a2002d 100644
--- a/src/plugins/nim/project/nimcompilerbuildstep.cpp
+++ b/src/plugins/nim/project/nimcompilerbuildstep.cpp
@@ -45,24 +45,11 @@ using namespace Utils;
namespace Nim {
-class NimParser : public ProjectExplorer::IOutputParser
+class NimParser : public ProjectExplorer::OutputTaskParser
{
-public:
- void stdOutput(const QString &line) final
- {
- parseLine(line.trimmed());
- IOutputParser::stdOutput(line);
- }
-
- void stdError(const QString &line) final
- {
- parseLine(line.trimmed());
- IOutputParser::stdError(line);
- }
-
-private:
- void parseLine(const QString &line)
+ Result handleLine(const QString &lne, Utils::OutputFormat) override
{
+ const QString line = lne.trimmed();
static QRegularExpression regex("(.+.nim)\\((\\d+), (\\d+)\\) (.+)",
QRegularExpression::OptimizeOnFirstUsageOption);
static QRegularExpression warning("(Warning):(.*)",
@@ -72,13 +59,13 @@ private:
QRegularExpressionMatch match = regex.match(line);
if (!match.hasMatch())
- return;
+ return Status::NotHandled;
const QString filename = match.captured(1);
bool lineOk = false;
const int lineNumber = match.captured(2).toInt(&lineOk);
const QString message = match.captured(4);
if (!lineOk)
- return;
+ return Status::NotHandled;
Task::TaskType type = Task::Unknown;
@@ -87,9 +74,14 @@ private:
else if (error.match(message).hasMatch())
type = Task::Error;
else
- return;
-
- emit addTask(CompileTask(type, message, FilePath::fromUserInput(filename), lineNumber));
+ return Status::NotHandled;
+
+ const CompileTask t(type, message, absoluteFilePath(FilePath::fromUserInput(filename)),
+ lineNumber);
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, t.file, t.line, match, 1);
+ scheduleTask(t, 1);
+ return {Status::Done, linkSpecs};
}
};
@@ -106,18 +98,17 @@ NimCompilerBuildStep::NimCompilerBuildStep(BuildStepList *parentList, Core::Id i
this, &NimCompilerBuildStep::updateProcessParameters);
connect(this, &NimCompilerBuildStep::outFilePathChanged,
bc, &NimBuildConfiguration::outFilePathChanged);
- connect(bc->target()->project(), &ProjectExplorer::Project::fileListChanged,
+ connect(project(), &ProjectExplorer::Project::fileListChanged,
this, &NimCompilerBuildStep::updateTargetNimFile);
updateProcessParameters();
}
-bool NimCompilerBuildStep::init()
+void NimCompilerBuildStep::setupOutputFormatter(OutputFormatter *formatter)
{
- setOutputParser(new NimParser());
- if (IOutputParser *parser = target()->kit()->createOutputParser())
- appendOutputParser(parser);
- outputParser()->setWorkingDirectory(processParameters()->effectiveWorkingDirectory());
- return AbstractProcessStep::init();
+ formatter->addLineParser(new NimParser);
+ formatter->addLineParsers(target()->kit()->createOutputParsers());
+ formatter->addSearchDir(processParameters()->effectiveWorkingDirectory());
+ AbstractProcessStep::setupOutputFormatter(formatter);
}
BuildStepConfigWidget *NimCompilerBuildStep::createConfigWidget()
@@ -208,17 +199,13 @@ void NimCompilerBuildStep::updateProcessParameters()
void NimCompilerBuildStep::updateOutFilePath()
{
- auto bc = qobject_cast<NimBuildConfiguration *>(buildConfiguration());
- QTC_ASSERT(bc, return);
const QString targetName = Utils::HostOsInfo::withExecutableSuffix(m_targetNimFile.toFileInfo().baseName());
- setOutFilePath(bc->buildDirectory().pathAppended(targetName));
+ setOutFilePath(buildDirectory().pathAppended(targetName));
}
void NimCompilerBuildStep::updateWorkingDirectory()
{
- auto bc = qobject_cast<NimBuildConfiguration *>(buildConfiguration());
- QTC_ASSERT(bc, return);
- processParameters()->setWorkingDirectory(bc->buildDirectory());
+ processParameters()->setWorkingDirectory(buildDirectory());
}
void NimCompilerBuildStep::updateCommand()
@@ -257,9 +244,7 @@ void NimCompilerBuildStep::updateCommand()
void NimCompilerBuildStep::updateEnvironment()
{
- auto bc = qobject_cast<NimBuildConfiguration *>(buildConfiguration());
- QTC_ASSERT(bc, return);
- processParameters()->setEnvironment(bc->environment());
+ processParameters()->setEnvironment(buildEnvironment());
}
void NimCompilerBuildStep::updateTargetNimFile()
@@ -321,7 +306,7 @@ void NimPlugin::testNimParser_data()
QTest::newRow("Parse error string")
<< QString::fromLatin1("main.nim(23, 1) Error: undeclared identifier: 'x'")
<< OutputParserTester::STDERR
- << QString("") << QString("main.nim(23, 1) Error: undeclared identifier: 'x'\n")
+ << QString() << QString()
<< Tasks({CompileTask(Task::Error,
"Error: undeclared identifier: 'x'",
FilePath::fromUserInput("main.nim"), 23)})
@@ -330,7 +315,7 @@ void NimPlugin::testNimParser_data()
QTest::newRow("Parse warning string")
<< QString::fromLatin1("lib/pure/parseopt.nim(56, 34) Warning: quoteIfContainsWhite is deprecated [Deprecated]")
<< OutputParserTester::STDERR
- << QString("") << QString("lib/pure/parseopt.nim(56, 34) Warning: quoteIfContainsWhite is deprecated [Deprecated]\n")
+ << QString() << QString()
<< Tasks({CompileTask(Task::Warning,
"Warning: quoteIfContainsWhite is deprecated [Deprecated]",
FilePath::fromUserInput("lib/pure/parseopt.nim"), 56)})
@@ -340,7 +325,7 @@ void NimPlugin::testNimParser_data()
void NimPlugin::testNimParser()
{
OutputParserTester testbench;
- testbench.appendOutputParser(new NimParser);
+ testbench.addLineParser(new NimParser);
QFETCH(QString, input);
QFETCH(OutputParserTester::Channel, inputChannel);
QFETCH(Tasks, tasks);
diff --git a/src/plugins/nim/project/nimcompilerbuildstep.h b/src/plugins/nim/project/nimcompilerbuildstep.h
index aca8750c06..cd194e06ea 100644
--- a/src/plugins/nim/project/nimcompilerbuildstep.h
+++ b/src/plugins/nim/project/nimcompilerbuildstep.h
@@ -41,7 +41,7 @@ public:
NimCompilerBuildStep(ProjectExplorer::BuildStepList *parentList, Core::Id id);
- bool init() override;
+ void setupOutputFormatter(Utils::OutputFormatter *formatter) override;
ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override;
bool fromMap(const QVariantMap &map) override;
diff --git a/src/plugins/nim/project/nimcompilercleanstep.cpp b/src/plugins/nim/project/nimcompilercleanstep.cpp
index 570df83e58..3fce967a34 100644
--- a/src/plugins/nim/project/nimcompilercleanstep.cpp
+++ b/src/plugins/nim/project/nimcompilercleanstep.cpp
@@ -40,6 +40,24 @@ using namespace Utils;
namespace Nim {
+class NimCompilerCleanStep final : public BuildStep
+{
+ Q_DECLARE_TR_FUNCTIONS(Nim::NimCompilerCleanStep)
+
+public:
+ NimCompilerCleanStep(BuildStepList *parentList, Core::Id id);
+
+private:
+ bool init() final;
+ void doRun() final;
+ void doCancel() final {} // Can be left empty. The run() function hardly does anything.
+
+ bool removeCacheDirectory();
+ bool removeOutFilePath();
+
+ Utils::FilePath m_buildDir;
+};
+
NimCompilerCleanStep::NimCompilerCleanStep(BuildStepList *parentList, Core::Id id)
: BuildStep(parentList, id)
{
@@ -51,14 +69,14 @@ NimCompilerCleanStep::NimCompilerCleanStep(BuildStepList *parentList, Core::Id i
workingDirectory->setDisplayStyle(BaseStringAspect::LineEditDisplay);
setSummaryUpdater([this, workingDirectory] {
- workingDirectory->setFilePath(buildConfiguration()->buildDirectory());
+ workingDirectory->setFilePath(buildDirectory());
return displayName();
});
}
bool NimCompilerCleanStep::init()
{
- FilePath buildDir = buildConfiguration()->buildDirectory();
+ FilePath buildDir = buildDirectory();
bool result = buildDir.exists();
if (result)
m_buildDir = buildDir;
@@ -68,32 +86,27 @@ bool NimCompilerCleanStep::init()
void NimCompilerCleanStep::doRun()
{
if (!m_buildDir.exists()) {
- emit addOutput(tr("Build directory \"%1\" does not exist.").arg(m_buildDir.toUserOutput()), BuildStep::OutputFormat::ErrorMessage);
+ emit addOutput(tr("Build directory \"%1\" does not exist.").arg(m_buildDir.toUserOutput()), OutputFormat::ErrorMessage);
emit finished(false);
return;
}
if (!removeCacheDirectory()) {
- emit addOutput(tr("Failed to delete the cache directory."), BuildStep::OutputFormat::ErrorMessage);
+ emit addOutput(tr("Failed to delete the cache directory."), OutputFormat::ErrorMessage);
emit finished(false);
return;
}
if (!removeOutFilePath()) {
- emit addOutput(tr("Failed to delete the out file."), BuildStep::OutputFormat::ErrorMessage);
+ emit addOutput(tr("Failed to delete the out file."), OutputFormat::ErrorMessage);
emit finished(false);
return;
}
- emit addOutput(tr("Clean step completed successfully."), BuildStep::OutputFormat::NormalMessage);
+ emit addOutput(tr("Clean step completed successfully."), OutputFormat::NormalMessage);
emit finished(true);
}
-void NimCompilerCleanStep::doCancel()
-{
- // Can be left empty. The run() function hardly does anything.
-}
-
bool NimCompilerCleanStep::removeCacheDirectory()
{
auto bc = qobject_cast<NimBuildConfiguration*>(buildConfiguration());
diff --git a/src/plugins/nim/project/nimcompilercleanstep.h b/src/plugins/nim/project/nimcompilercleanstep.h
index 483d627b9e..4086cf7275 100644
--- a/src/plugins/nim/project/nimcompilercleanstep.h
+++ b/src/plugins/nim/project/nimcompilercleanstep.h
@@ -26,30 +26,10 @@
#pragma once
#include <projectexplorer/buildstep.h>
-#include <projectexplorer/buildsteplist.h>
-#include <utils/fileutils.h>
namespace Nim {
-class NimCompilerCleanStep : public ProjectExplorer::BuildStep
-{
- Q_OBJECT
-
-public:
- NimCompilerCleanStep(ProjectExplorer::BuildStepList *parentList, Core::Id id);
-
-private:
- bool init() override;
- void doRun() override;
- void doCancel() override;
-
- bool removeCacheDirectory();
- bool removeOutFilePath();
-
- Utils::FilePath m_buildDir;
-};
-
-class NimCompilerCleanStepFactory : public ProjectExplorer::BuildStepFactory
+class NimCompilerCleanStepFactory final : public ProjectExplorer::BuildStepFactory
{
public:
NimCompilerCleanStepFactory();
diff --git a/src/plugins/nim/project/nimtoolchain.cpp b/src/plugins/nim/project/nimtoolchain.cpp
index 6a922f9553..1d1cf4e1a7 100644
--- a/src/plugins/nim/project/nimtoolchain.cpp
+++ b/src/plugins/nim/project/nimtoolchain.cpp
@@ -49,7 +49,7 @@ NimToolChain::NimToolChain(Core::Id typeId)
, m_version(std::make_tuple(-1,-1,-1))
{
setLanguage(Constants::C_NIMLANGUAGE_ID);
- setTypeDisplayName(NimToolChainFactory::tr("Nim"));
+ setTypeDisplayName(tr("Nim"));
}
Abi NimToolChain::targetAbi() const
@@ -120,9 +120,9 @@ void NimToolChain::setCompilerCommand(const FilePath &compilerCommand)
parseVersion(compilerCommand, m_version);
}
-IOutputParser *NimToolChain::outputParser() const
+QList<Utils::OutputLineParser *> NimToolChain::createOutputParsers() const
{
- return nullptr;
+ return {};
}
std::unique_ptr<ProjectExplorer::ToolChainConfigWidget> NimToolChain::createConfigurationWidget()
diff --git a/src/plugins/nim/project/nimtoolchain.h b/src/plugins/nim/project/nimtoolchain.h
index 84b449d11d..d61448e6a0 100644
--- a/src/plugins/nim/project/nimtoolchain.h
+++ b/src/plugins/nim/project/nimtoolchain.h
@@ -32,6 +32,8 @@ namespace Nim {
class NimToolChain : public ProjectExplorer::ToolChain
{
+ Q_DECLARE_TR_FUNCTIONS(Nim::NimToolChain)
+
public:
NimToolChain();
explicit NimToolChain(Core::Id typeId);
@@ -54,7 +56,7 @@ public:
Utils::FilePath compilerCommand() const final;
QString compilerVersion() const;
void setCompilerCommand(const Utils::FilePath &compilerCommand);
- ProjectExplorer::IOutputParser *outputParser() const final;
+ QList<Utils::OutputLineParser *> createOutputParsers() const final;
std::unique_ptr<ProjectExplorer::ToolChainConfigWidget> createConfigurationWidget() final;
QVariantMap toMap() const final;
diff --git a/src/plugins/nim/project/nimtoolchainfactory.cpp b/src/plugins/nim/project/nimtoolchainfactory.cpp
index 7467ab7789..7bf2377121 100644
--- a/src/plugins/nim/project/nimtoolchainfactory.cpp
+++ b/src/plugins/nim/project/nimtoolchainfactory.cpp
@@ -42,7 +42,7 @@ namespace Nim {
NimToolChainFactory::NimToolChainFactory()
{
- setDisplayName(tr("Nim"));
+ setDisplayName(NimToolChain::tr("Nim"));
setSupportedToolChainType(Constants::C_NIMTOOLCHAIN_TYPEID);
setSupportedLanguages({Constants::C_NIMLANGUAGE_ID});
setToolchainConstructor([] { return new NimToolChain; });
@@ -111,7 +111,7 @@ void NimToolChainConfigWidget::applyImpl()
Q_ASSERT(tc);
if (tc->isAutoDetected())
return;
- tc->setCompilerCommand(m_compilerCommand->fileName());
+ tc->setCompilerCommand(m_compilerCommand->filePath());
}
void NimToolChainConfigWidget::discardImpl()
@@ -123,7 +123,7 @@ bool NimToolChainConfigWidget::isDirtyImpl() const
{
auto tc = static_cast<NimToolChain *>(toolChain());
Q_ASSERT(tc);
- return tc->compilerCommand().toString() != m_compilerCommand->path();
+ return tc->compilerCommand().toString() != m_compilerCommand->filePath().toString();
}
void NimToolChainConfigWidget::makeReadOnlyImpl()
diff --git a/src/plugins/nim/project/nimtoolchainfactory.h b/src/plugins/nim/project/nimtoolchainfactory.h
index 0b79653400..1e9e219e97 100644
--- a/src/plugins/nim/project/nimtoolchainfactory.h
+++ b/src/plugins/nim/project/nimtoolchainfactory.h
@@ -36,8 +36,6 @@ class NimToolChain;
class NimToolChainFactory : public ProjectExplorer::ToolChainFactory
{
- Q_OBJECT
-
public:
NimToolChainFactory();
diff --git a/src/plugins/nim/settings/nimtoolssettingspage.cpp b/src/plugins/nim/settings/nimtoolssettingspage.cpp
index 129e4c24c0..a77aaf1c70 100644
--- a/src/plugins/nim/settings/nimtoolssettingspage.cpp
+++ b/src/plugins/nim/settings/nimtoolssettingspage.cpp
@@ -32,9 +32,7 @@
namespace Nim {
-NimToolsSettingsWidget::NimToolsSettingsWidget(NimSettings *settings)
- : ui(new Ui::NimToolsSettingsWidget)
- , m_settings(settings)
+NimToolsSettingsWidget::NimToolsSettingsWidget() : ui(new Ui::NimToolsSettingsWidget)
{
ui->setupUi(this);
ui->pathWidget->setExpectedKind(Utils::PathChooser::ExistingCommand);
@@ -47,7 +45,7 @@ NimToolsSettingsWidget::~NimToolsSettingsWidget()
QString NimToolsSettingsWidget::command() const
{
- return ui->pathWidget->path();
+ return ui->pathWidget->filePath().toString();
}
void NimToolsSettingsWidget::setCommand(const QString &filename)
@@ -70,7 +68,7 @@ NimToolsSettingsPage::~NimToolsSettingsPage() = default;
QWidget *NimToolsSettingsPage::widget()
{
if (!m_widget)
- m_widget.reset(new NimToolsSettingsWidget(m_settings));
+ m_widget.reset(new NimToolsSettingsWidget);
m_widget->setCommand(m_settings->nimSuggestPath());
return m_widget.get();
}
diff --git a/src/plugins/nim/settings/nimtoolssettingspage.h b/src/plugins/nim/settings/nimtoolssettingspage.h
index 3dbe3ea566..9a8e0df19c 100644
--- a/src/plugins/nim/settings/nimtoolssettingspage.h
+++ b/src/plugins/nim/settings/nimtoolssettingspage.h
@@ -43,7 +43,7 @@ class NimToolsSettingsWidget : public QWidget
Q_DECLARE_TR_FUNCTIONS(Nim::ToolSettingsPage)
public:
- explicit NimToolsSettingsWidget(NimSettings *settings);
+ NimToolsSettingsWidget();
~NimToolsSettingsWidget();
@@ -52,7 +52,6 @@ public:
private:
Ui::NimToolsSettingsWidget *ui;
- NimSettings *m_settings = nullptr;
};
class NimToolsSettingsPage final : public Core::IOptionsPage
diff --git a/src/plugins/perfprofiler/perfdatareader.cpp b/src/plugins/perfprofiler/perfdatareader.cpp
index 4902c1fd20..48dcaf645f 100644
--- a/src/plugins/perfprofiler/perfdatareader.cpp
+++ b/src/plugins/perfprofiler/perfdatareader.cpp
@@ -54,6 +54,8 @@
#include <QTextStream>
#include <QtEndian>
+using namespace ProjectExplorer;
+
namespace PerfProfiler {
namespace Internal {
@@ -289,15 +291,14 @@ bool PerfDataReader::acceptsSamples() const
return m_recording;
}
-QStringList PerfDataReader::collectArguments(const QString &executableDirPath,
- const ProjectExplorer::Kit *kit) const
+QStringList PerfDataReader::collectArguments(const QString &executableDirPath, const Kit *kit) const
{
QStringList arguments;
if (!executableDirPath.isEmpty())
- arguments << QLatin1String("--app") << executableDirPath;
+ arguments << "--app" << executableDirPath;
if (QtSupport::BaseQtVersion *qt = QtSupport::QtKitAspect::qtVersion(kit)) {
- arguments << QLatin1String("--extra") << QString::fromLatin1("%1%5%2%5%3%5%4")
+ arguments << "--extra" << QString("%1%5%2%5%3%5%4")
.arg(QDir::toNativeSeparators(qt->libraryPath().toString()))
.arg(QDir::toNativeSeparators(qt->pluginPath().toString()))
.arg(QDir::toNativeSeparators(qt->hostBinPath().toString()))
@@ -305,20 +306,18 @@ QStringList PerfDataReader::collectArguments(const QString &executableDirPath,
.arg(QDir::listSeparator());
}
- if (auto toolChain = ProjectExplorer::ToolChainKitAspect::toolChain(
- kit, ProjectExplorer::Constants::CXX_LANGUAGE_ID)) {
- ProjectExplorer::Abi::Architecture architecture = toolChain->targetAbi().architecture();
- if (architecture == ProjectExplorer::Abi::ArmArchitecture &&
- toolChain->targetAbi().wordWidth() == 64) {
- arguments << QLatin1String("--arch") << QLatin1String("aarch64");
- } else if (architecture != ProjectExplorer::Abi::UnknownArchitecture) {
- arguments << QLatin1String("--arch") << ProjectExplorer::Abi::toString(architecture);
+ if (auto toolChain = ToolChainKitAspect::cxxToolChain(kit)) {
+ Abi::Architecture architecture = toolChain->targetAbi().architecture();
+ if (architecture == Abi::ArmArchitecture && toolChain->targetAbi().wordWidth() == 64) {
+ arguments << "--arch" << "aarch64";
+ } else if (architecture != Abi::UnknownArchitecture) {
+ arguments << "--arch" << Abi::toString(architecture);
}
}
- QString sysroot = ProjectExplorer::SysRootKitAspect::sysRoot(kit).toString();
+ QString sysroot = SysRootKitAspect::sysRoot(kit).toString();
if (!sysroot.isEmpty())
- arguments << QLatin1String("--sysroot") << sysroot;
+ arguments << "--sysroot" << sysroot;
return arguments;
}
diff --git a/src/plugins/perfprofiler/perfprofilerstatisticsview.cpp b/src/plugins/perfprofiler/perfprofilerstatisticsview.cpp
index d023444b2e..78e9b57e7e 100644
--- a/src/plugins/perfprofiler/perfprofilerstatisticsview.cpp
+++ b/src/plugins/perfprofiler/perfprofilerstatisticsview.cpp
@@ -204,7 +204,8 @@ QString StatisticsView::rowToString(int row) const
static void sendToClipboard(const QString &str)
{
QClipboard *clipboard = QApplication::clipboard();
- clipboard->setText(str, QClipboard::Selection);
+ if (clipboard->supportsSelection())
+ clipboard->setText(str, QClipboard::Selection);
clipboard->setText(str, QClipboard::Clipboard);
}
diff --git a/src/plugins/perfprofiler/perfprofilertool.cpp b/src/plugins/perfprofiler/perfprofilertool.cpp
index 8176432c17..4cd4256096 100644
--- a/src/plugins/perfprofiler/perfprofilertool.cpp
+++ b/src/plugins/perfprofiler/perfprofilertool.cpp
@@ -421,7 +421,8 @@ void PerfProfilerTool::onReaderFinished()
tr("The profiler did not produce any samples. "
"Make sure that you are running a recent Linux kernel and that "
"the \"perf\" utility is available and generates useful call "
- "graphs."));
+ "graphs.\nYou might find further explanations in the Application "
+ "Output view."));
clear();
} else {
m_traceManager->finalize();
diff --git a/src/plugins/plugins.qbs b/src/plugins/plugins.qbs
index 35b6cb8629..4a5428fa21 100644
--- a/src/plugins/plugins.qbs
+++ b/src/plugins/plugins.qbs
@@ -70,6 +70,7 @@ Project {
"scxmleditor/scxmleditor.qbs",
"serialterminal/serialterminal.qbs",
"silversearcher/silversearcher.qbs",
+ "studiowelcome/studiowelcome.qbs",
"subversion/subversion.qbs",
"tasklist/tasklist.qbs",
"texteditor/texteditor.qbs",
diff --git a/src/plugins/projectexplorer/CMakeLists.txt b/src/plugins/projectexplorer/CMakeLists.txt
index a7aa76ae50..81559e66f8 100644
--- a/src/plugins/projectexplorer/CMakeLists.txt
+++ b/src/plugins/projectexplorer/CMakeLists.txt
@@ -8,7 +8,6 @@ add_qtc_plugin(ProjectExplorer
addrunconfigdialog.cpp addrunconfigdialog.h
allprojectsfilter.cpp allprojectsfilter.h
allprojectsfind.cpp allprojectsfind.h
- ansifilterparser.cpp ansifilterparser.h
applicationlauncher.cpp applicationlauncher.h
appoutputpane.cpp appoutputpane.h
baseprojectwizarddialog.cpp baseprojectwizarddialog.h
@@ -16,7 +15,6 @@ add_qtc_plugin(ProjectExplorer
buildpropertiessettings.h
buildpropertiessettingspage.cpp buildpropertiessettingspage.h
buildconfiguration.cpp buildconfiguration.h
- buildenvironmentwidget.cpp buildenvironmentwidget.h
buildinfo.cpp buildinfo.h
buildmanager.cpp buildmanager.h
buildprogress.cpp buildprogress.h
@@ -37,6 +35,7 @@ add_qtc_plugin(ProjectExplorer
customexecutablerunconfiguration.cpp customexecutablerunconfiguration.h
customparser.cpp customparser.h
customparserconfigdialog.cpp customparserconfigdialog.h customparserconfigdialog.ui
+ customparserssettingspage.cpp customparserssettingspage.h
customtoolchain.cpp customtoolchain.h
customwizard/customwizard.cpp customwizard/customwizard.h
customwizard/customwizardpage.cpp customwizard/customwizardpage.h
diff --git a/src/plugins/projectexplorer/abi.cpp b/src/plugins/projectexplorer/abi.cpp
index fec9f69fd9..131c739bbd 100644
--- a/src/plugins/projectexplorer/abi.cpp
+++ b/src/plugins/projectexplorer/abi.cpp
@@ -159,6 +159,8 @@ static Abi::Architecture architectureFromQt()
return Abi::PowerPCArchitecture;
if (arch.startsWith("sh")) // Not in Qt documentation!
return Abi::ShArchitecture;
+ if (arch.startsWith("avr32")) // Not in Qt documentation!
+ return Abi::Avr32Architecture;
if (arch.startsWith("avr")) // Not in Qt documentation!
return Abi::AvrArchitecture;
if (arch.startsWith("asmjs"))
@@ -491,6 +493,12 @@ Abi Abi::abiFromTargetTriplet(const QString &triple)
flavor = GenericFlavor;
format = ElfFormat;
width = 16;
+ } else if (p == "avr32") {
+ arch = Avr32Architecture;
+ os = BareMetalOS;
+ flavor = GenericFlavor;
+ format = ElfFormat;
+ width = 32;
} else if (p == "msp430") {
arch = Msp430Architecture;
os = BareMetalOS;
@@ -503,6 +511,30 @@ Abi Abi::abiFromTargetTriplet(const QString &triple)
flavor = GenericFlavor;
format = ElfFormat;
width = 16;
+ } else if (p == "v850") {
+ arch = V850Architecture;
+ os = BareMetalOS;
+ flavor = GenericFlavor;
+ format = ElfFormat;
+ width = 32;
+ } else if (p == "m68k") {
+ arch = M68KArchitecture;
+ os = BareMetalOS;
+ flavor = GenericFlavor;
+ format = ElfFormat;
+ width = 16;
+ } else if (p == "m32c") {
+ arch = M32CArchitecture;
+ os = BareMetalOS;
+ flavor = GenericFlavor;
+ format = ElfFormat;
+ width = 16;
+ } else if (p.startsWith("riscv")) {
+ arch = RiscVArchitecture;
+ os = BareMetalOS;
+ flavor = GenericFlavor;
+ format = ElfFormat;
+ width = p.contains("64") ? 64 : 32;
} else if (p.startsWith("mips")) {
arch = MipsArchitecture;
width = p.contains("64") ? 64 : 32;
@@ -699,12 +731,16 @@ QString Abi::toString(const Architecture &a)
return QLatin1String("arm");
case AvrArchitecture:
return QLatin1String("avr");
+ case Avr32Architecture:
+ return QLatin1String("avr32");
case XtensaArchitecture:
return QLatin1String("xtensa");
case X86Architecture:
return QLatin1String("x86");
case Mcs51Architecture:
return QLatin1String("mcs51");
+ case Mcs251Architecture:
+ return QLatin1String("mcs251");
case MipsArchitecture:
return QLatin1String("mips");
case PowerPCArchitecture:
@@ -721,6 +757,22 @@ QString Abi::toString(const Architecture &a)
return QLatin1String("msp430");
case Rl78Architecture:
return QLatin1String("rl78");
+ case C166Architecture:
+ return QLatin1String("c166");
+ case V850Architecture:
+ return QLatin1String("v850");
+ case Rh850Architecture:
+ return QLatin1String("rh850");
+ case RxArchitecture:
+ return QLatin1String("rx");
+ case K78Architecture:
+ return QLatin1String("78k");
+ case M68KArchitecture:
+ return QLatin1String("m68k");
+ case M32CArchitecture:
+ return QLatin1String("m32c");
+ case RiscVArchitecture:
+ return QLatin1String("riscv");
case UnknownArchitecture:
Q_FALLTHROUGH();
default:
@@ -845,10 +897,14 @@ Abi::Architecture Abi::architectureFromString(const QStringRef &a)
return ArmArchitecture;
if (a == "avr")
return AvrArchitecture;
+ if (a == "avr32")
+ return Avr32Architecture;
if (a == "x86")
return X86Architecture;
if (a == "mcs51")
return Mcs51Architecture;
+ if (a == "mcs251")
+ return Mcs251Architecture;
if (a == "mips")
return MipsArchitecture;
if (a == "ppc")
@@ -863,6 +919,22 @@ Abi::Architecture Abi::architectureFromString(const QStringRef &a)
return Msp430Architecture;
if (a == "rl78")
return Rl78Architecture;
+ if (a == "c166")
+ return C166Architecture;
+ if (a == "v850")
+ return V850Architecture;
+ if (a == "rh850")
+ return Rh850Architecture;
+ if (a == "rx")
+ return RxArchitecture;
+ if (a == "78k")
+ return K78Architecture;
+ if (a == "m68k")
+ return M68KArchitecture;
+ if (a == "m32c")
+ return M32CArchitecture;
+ if (a == "riscv")
+ return RiscVArchitecture;
else if (a == "xtensa")
return XtensaArchitecture;
if (a == "asmjs")
@@ -1410,6 +1482,10 @@ void ProjectExplorer::ProjectExplorerPlugin::testAbiFromTargetTriplet_data()
<< int(Abi::BareMetalOS) << int(Abi::GenericFlavor)
<< int(Abi::ElfFormat) << 16;
+ QTest::newRow("avr32") << int(Abi::Avr32Architecture)
+ << int(Abi::BareMetalOS) << int(Abi::GenericFlavor)
+ << int(Abi::ElfFormat) << 32;
+
QTest::newRow("asmjs-unknown-emscripten") << int(Abi::AsmJsArchitecture)
<< int(Abi::UnknownOS) << int(Abi::UnknownFlavor)
<< int(Abi::EmscriptenFormat) << 32;
diff --git a/src/plugins/projectexplorer/abi.h b/src/plugins/projectexplorer/abi.h
index 3da9334e2e..ecbb1cbf88 100644
--- a/src/plugins/projectexplorer/abi.h
+++ b/src/plugins/projectexplorer/abi.h
@@ -56,12 +56,22 @@ public:
PowerPCArchitecture,
ShArchitecture,
AvrArchitecture,
+ Avr32Architecture,
XtensaArchitecture,
Mcs51Architecture,
+ Mcs251Architecture,
AsmJsArchitecture,
Stm8Architecture,
Msp430Architecture,
Rl78Architecture,
+ C166Architecture,
+ V850Architecture,
+ Rh850Architecture,
+ RxArchitecture,
+ K78Architecture,
+ M68KArchitecture,
+ M32CArchitecture,
+ RiscVArchitecture,
UnknownArchitecture
};
diff --git a/src/plugins/projectexplorer/abstractprocessstep.cpp b/src/plugins/projectexplorer/abstractprocessstep.cpp
index f3027eb609..1a9d18a937 100644
--- a/src/plugins/projectexplorer/abstractprocessstep.cpp
+++ b/src/plugins/projectexplorer/abstractprocessstep.cpp
@@ -24,7 +24,6 @@
****************************************************************************/
#include "abstractprocessstep.h"
-#include "ansifilterparser.h"
#include "buildconfiguration.h"
#include "buildstep.h"
#include "ioutputparser.h"
@@ -37,14 +36,15 @@
#include <coreplugin/reaper.h>
-#include <utils/fileinprojectfinder.h>
#include <utils/fileutils.h>
+#include <utils/outputformatter.h>
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
#include <QDir>
#include <QHash>
#include <QPair>
+#include <QTextDecoder>
#include <QUrl>
#include <algorithm>
@@ -105,18 +105,12 @@ public:
AbstractProcessStep *q;
std::unique_ptr<Utils::QtcProcess> m_process;
- std::unique_ptr<IOutputParser> m_outputParserChain;
ProcessParameters m_param;
- Utils::FileInProjectFinder m_fileFinder;
- QByteArray deferredText;
bool m_ignoreReturnValue = false;
- bool m_skipFlush = false;
bool m_lowPriority = false;
-
- void readData(void (AbstractProcessStep::*func)(const QString &), bool isUtf8 = false);
- void processLine(const QByteArray &data,
- void (AbstractProcessStep::*func)(const QString &),
- bool isUtf8 = false);
+ std::unique_ptr<QTextDecoder> stdoutStream;
+ std::unique_ptr<QTextDecoder> stderrStream;
+ OutputFormatter *outputFormatter = nullptr;
};
AbstractProcessStep::AbstractProcessStep(BuildStepList *bsl, Core::Id id) :
@@ -130,39 +124,6 @@ AbstractProcessStep::~AbstractProcessStep()
delete d;
}
-/*!
- Deletes all existing output parsers and starts a new chain with the
- given parser.
-
- Derived classes need to call this function.
-*/
-
-void AbstractProcessStep::setOutputParser(IOutputParser *parser)
-{
- d->m_outputParserChain.reset(new AnsiFilterParser);
- d->m_outputParserChain->appendOutputParser(parser);
-
- connect(d->m_outputParserChain.get(), &IOutputParser::addOutput, this, &AbstractProcessStep::outputAdded);
- connect(d->m_outputParserChain.get(), &IOutputParser::addTask, this, &AbstractProcessStep::taskAdded);
-}
-
-/*!
- Appends the given output parser to the existing chain of parsers.
-*/
-void AbstractProcessStep::appendOutputParser(IOutputParser *parser)
-{
- if (!parser)
- return;
-
- QTC_ASSERT(d->m_outputParserChain, return);
- d->m_outputParserChain->appendOutputParser(parser);
-}
-
-IOutputParser *AbstractProcessStep::outputParser() const
-{
- return d->m_outputParserChain.get();
-}
-
void AbstractProcessStep::emitFaultyConfigurationMessage()
{
emit addOutput(tr("Configuration is faulty. Check the Issues view for details."),
@@ -193,11 +154,16 @@ void AbstractProcessStep::setIgnoreReturnValue(bool b)
bool AbstractProcessStep::init()
{
- d->m_fileFinder.setProjectDirectory(project()->projectDirectory());
- d->m_fileFinder.setProjectFiles(project()->files(Project::AllFiles));
return !d->m_process;
}
+void AbstractProcessStep::setupOutputFormatter(OutputFormatter *formatter)
+{
+ formatter->setDemoteErrorsToWarnings(d->m_ignoreReturnValue);
+ d->outputFormatter = formatter;
+ BuildStep::setupOutputFormatter(formatter);
+}
+
/*!
Reimplemented from BuildStep::init(). You need to call this from
YourBuildStep::run().
@@ -225,10 +191,19 @@ void AbstractProcessStep::doRun()
return;
}
+ d->stdoutStream = std::make_unique<QTextDecoder>(buildEnvironment().hasKey("VSLANG")
+ ? QTextCodec::codecForName("UTF-8") : QTextCodec::codecForLocale());
+ d->stderrStream = std::make_unique<QTextDecoder>(QTextCodec::codecForLocale());
+
d->m_process.reset(new Utils::QtcProcess());
d->m_process->setUseCtrlCStub(Utils::HostOsInfo::isWindowsHost());
d->m_process->setWorkingDirectory(wd.absolutePath());
- d->m_process->setEnvironment(d->m_param.environment());
+ // Enforce PWD in the environment because some build tools use that.
+ // PWD can be different from getcwd in case of symbolic links (getcwd resolves symlinks).
+ // For example Clang uses PWD for paths in debug info, see QTCREATORBUG-23788
+ Environment envWithPwd = d->m_param.environment();
+ envWithPwd.set("PWD", d->m_process->workingDirectory());
+ d->m_process->setEnvironment(envWithPwd);
d->m_process->setCommand(effectiveCommand);
if (d->m_lowPriority && ProjectExplorerPlugin::projectExplorerSettings().lowBuildPriority)
d->m_process->setLowPriority();
@@ -244,7 +219,6 @@ void AbstractProcessStep::doRun()
if (!d->m_process->waitForStarted()) {
processStartupFailed();
d->m_process.reset();
- d->m_outputParserChain.reset();
finish(false);
return;
}
@@ -272,7 +246,6 @@ void AbstractProcessStep::cleanUp(QProcess *process)
processFinished(process->exitCode(), process->exitStatus());
const bool returnValue = processSucceeded(process->exitCode(), process->exitStatus()) || d->m_ignoreReturnValue;
- d->m_outputParserChain.reset();
d->m_process.reset();
// Report result
@@ -302,9 +275,6 @@ void AbstractProcessStep::processStarted()
void AbstractProcessStep::processFinished(int exitCode, QProcess::ExitStatus status)
{
- if (d->m_outputParserChain)
- d->m_outputParserChain->flush();
-
QString command = QDir::toNativeSeparators(d->m_param.effectiveCommand().toString());
if (status == QProcess::NormalExit && exitCode == 0) {
emit addOutput(tr("The process \"%1\" exited normally.").arg(command),
@@ -338,7 +308,7 @@ void AbstractProcessStep::processStartupFailed()
bool AbstractProcessStep::processSucceeded(int exitCode, QProcess::ExitStatus status)
{
- if (outputParser() && outputParser()->hasFatalErrors())
+ if (d->outputFormatter->hasFatalErrors())
return false;
return exitCode == 0 && status == QProcess::NormalExit;
@@ -348,43 +318,7 @@ void AbstractProcessStep::processReadyReadStdOutput()
{
if (!d->m_process)
return;
- d->m_process->setReadChannel(QProcess::StandardOutput);
- BuildConfiguration *bc = buildConfiguration();
- if (!bc)
- bc = target()->activeBuildConfiguration();
- const bool utf8Output = bc && bc->environment().hasKey("VSLANG");
- d->readData(&AbstractProcessStep::stdOutput, utf8Output);
-}
-
-void AbstractProcessStep::Private::readData(void (AbstractProcessStep::*func)(const QString &),
- bool isUtf8)
-{
- while (m_process->bytesAvailable()) {
- const bool hasLine = m_process->canReadLine();
- const QByteArray data = hasLine ? m_process->readLine() : m_process->readAll();
- int startPos = 0;
- int crPos = -1;
- while ((crPos = data.indexOf('\r', startPos)) >= 0) {
- if (data.size() > crPos + 1 && data.at(crPos + 1) == '\n')
- break;
- processLine(data.mid(startPos, crPos - startPos + 1), func, isUtf8);
- startPos = crPos + 1;
- }
- if (hasLine)
- processLine(data.mid(startPos), func, isUtf8);
- else if (startPos < data.count())
- deferredText += data.mid(startPos);
- }
-}
-
-void AbstractProcessStep::Private::processLine(const QByteArray &data,
- void (AbstractProcessStep::*func)(const QString &),
- bool isUtf8)
-{
- const QByteArray text = deferredText + data;
- deferredText.clear();
- const QString line = isUtf8 ? QString::fromUtf8(text) : QString::fromLocal8Bit(text);
- (q->*func)(line);
+ stdOutput(d->stdoutStream->toUnicode(d->m_process->readAllStandardOutput()));
}
/*!
@@ -393,19 +327,16 @@ void AbstractProcessStep::Private::processLine(const QByteArray &data,
The default implementation adds the line to the application output window.
*/
-void AbstractProcessStep::stdOutput(const QString &line)
+void AbstractProcessStep::stdOutput(const QString &output)
{
- if (d->m_outputParserChain)
- d->m_outputParserChain->stdOutput(line);
- emit addOutput(line, BuildStep::OutputFormat::Stdout, BuildStep::DontAppendNewline);
+ emit addOutput(output, BuildStep::OutputFormat::Stdout, BuildStep::DontAppendNewline);
}
void AbstractProcessStep::processReadyReadStdError()
{
if (!d->m_process)
return;
- d->m_process->setReadChannel(QProcess::StandardError);
- d->readData(&AbstractProcessStep::stdError);
+ stdError(d->stderrStream->toUnicode(d->m_process->readAllStandardError()));
}
/*!
@@ -414,11 +345,9 @@ void AbstractProcessStep::processReadyReadStdError()
The default implementation adds the line to the application output window.
*/
-void AbstractProcessStep::stdError(const QString &line)
+void AbstractProcessStep::stdError(const QString &output)
{
- if (d->m_outputParserChain)
- d->m_outputParserChain->stdError(line);
- emit addOutput(line, BuildStep::OutputFormat::Stderr, BuildStep::DontAppendNewline);
+ emit addOutput(output, BuildStep::OutputFormat::Stderr, BuildStep::DontAppendNewline);
}
void AbstractProcessStep::finish(bool success)
@@ -426,37 +355,6 @@ void AbstractProcessStep::finish(bool success)
emit finished(success);
}
-void AbstractProcessStep::taskAdded(const Task &task, int linkedOutputLines, int skipLines)
-{
- // Do not bother to report issues if we do not care about the results of
- // the buildstep anyway:
- if (d->m_ignoreReturnValue)
- return;
-
- // flush out any pending tasks before proceeding:
- if (!d->m_skipFlush && d->m_outputParserChain) {
- d->m_skipFlush = true;
- d->m_outputParserChain->flush();
- d->m_skipFlush = false;
- }
-
- Task editable(task);
- QString filePath = task.file.toString();
- if (!filePath.isEmpty() && !filePath.startsWith('<') && !QDir::isAbsolutePath(filePath)) {
- while (filePath.startsWith("../"))
- filePath.remove(0, 3);
- bool found = false;
- const Utils::FilePaths candidates
- = d->m_fileFinder.findFile(QUrl::fromLocalFile(filePath), &found);
- if (found && candidates.size() == 1)
- editable.file = candidates.first();
- else
- qWarning() << "Could not find absolute location of file " << filePath;
- }
-
- emit addTask(editable, linkedOutputLines, skipLines);
-}
-
void AbstractProcessStep::outputAdded(const QString &string, BuildStep::OutputFormat format)
{
emit addOutput(string, format, BuildStep::DontAppendNewline);
@@ -467,15 +365,10 @@ void AbstractProcessStep::slotProcessFinished(int, QProcess::ExitStatus)
QProcess *process = d->m_process.get();
if (!process) // Happens when the process was canceled and handed over to the Reaper.
process = qobject_cast<QProcess *>(sender()); // The process was canceled!
-
- const QString stdErrLine = process ? QString::fromLocal8Bit(process->readAllStandardError()) : QString();
- for (const QString &l : stdErrLine.split('\n'))
- stdError(l);
-
- const QString stdOutLine = process ? QString::fromLocal8Bit(process->readAllStandardOutput()) : QString();
- for (const QString &l : stdOutLine.split('\n'))
- stdOutput(l);
-
+ if (process) {
+ stdError(d->stderrStream->toUnicode(process->readAllStandardError()));
+ stdOutput(d->stdoutStream->toUnicode(process->readAllStandardOutput()));
+ }
cleanUp(process);
}
diff --git a/src/plugins/projectexplorer/abstractprocessstep.h b/src/plugins/projectexplorer/abstractprocessstep.h
index 3cc7aa8bf5..9431c3a97c 100644
--- a/src/plugins/projectexplorer/abstractprocessstep.h
+++ b/src/plugins/projectexplorer/abstractprocessstep.h
@@ -31,8 +31,7 @@
namespace Utils { class FilePath; }
namespace ProjectExplorer {
-
-class IOutputParser;
+class OutputTaskParser;
class ProcessParameters;
// Documentation inside.
@@ -46,16 +45,13 @@ public:
bool ignoreReturnValue();
void setIgnoreReturnValue(bool b);
- void setOutputParser(IOutputParser *parser);
- void appendOutputParser(IOutputParser *parser);
- IOutputParser *outputParser() const;
-
void emitFaultyConfigurationMessage();
protected:
AbstractProcessStep(BuildStepList *bsl, Core::Id id);
~AbstractProcessStep() override;
bool init() override;
+ void setupOutputFormatter(Utils::OutputFormatter *formatter) override;
void doRun() override;
void setLowPriority();
virtual void finish(bool success);
@@ -64,8 +60,8 @@ protected:
virtual void processFinished(int exitCode, QProcess::ExitStatus status);
virtual void processStartupFailed();
virtual bool processSucceeded(int exitCode, QProcess::ExitStatus status);
- virtual void stdOutput(const QString &line);
- virtual void stdError(const QString &line);
+ virtual void stdOutput(const QString &output);
+ virtual void stdError(const QString &output);
void doCancel() override;
@@ -77,8 +73,6 @@ private:
void cleanUp(QProcess *process);
- void taskAdded(const Task &task, int linkedOutputLines = 0, int skipLines = 0);
-
void outputAdded(const QString &string, BuildStep::OutputFormat format);
class Private;
diff --git a/src/plugins/projectexplorer/addrunconfigdialog.cpp b/src/plugins/projectexplorer/addrunconfigdialog.cpp
index 647959eb15..bc57e1c544 100644
--- a/src/plugins/projectexplorer/addrunconfigdialog.cpp
+++ b/src/plugins/projectexplorer/addrunconfigdialog.cpp
@@ -154,7 +154,7 @@ AddRunConfigDialog::AddRunConfigDialog(Target *target, QWidget *parent)
buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Create"));
connect(filterEdit, &QLineEdit::textChanged, this, [proxyModel](const QString &text) {
- proxyModel->setFilterRegExp(QRegExp(text, Qt::CaseInsensitive));
+ proxyModel->setFilterRegularExpression(QRegularExpression(text, QRegularExpression::CaseInsensitiveOption));
});
connect(m_view, &TreeView::doubleClicked, this, [this] { accept(); });
const auto updateOkButton = [buttonBox, this] {
diff --git a/src/plugins/projectexplorer/ansifilterparser.cpp b/src/plugins/projectexplorer/ansifilterparser.cpp
deleted file mode 100644
index a2db2c1a6f..0000000000
--- a/src/plugins/projectexplorer/ansifilterparser.cpp
+++ /dev/null
@@ -1,175 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "ansifilterparser.h"
-
-namespace {
-enum AnsiState {
- PLAIN,
- ANSI_START,
- ANSI_CSI,
- ANSI_SEQUENCE,
- ANSI_WAITING_FOR_ST,
- ANSI_ST_STARTED
-};
-} // namespace
-
-using namespace ProjectExplorer;
-
-AnsiFilterParser::AnsiFilterParser()
-{
- setObjectName(QLatin1String("AnsiFilterParser"));
-}
-
-void AnsiFilterParser::stdOutput(const QString &line)
-{
- IOutputParser::stdOutput(filterLine(line));
-}
-
-void AnsiFilterParser::stdError(const QString &line)
-{
- IOutputParser::stdError(filterLine(line));
-}
-
-QString AnsiFilterParser::filterLine(const QString &line)
-{
- QString result;
- result.reserve(line.count());
-
- static AnsiState state = PLAIN;
- foreach (const QChar c, line) {
- unsigned int val = c.unicode();
- switch (state) {
- case PLAIN:
- if (val == 27) // 'ESC'
- state = ANSI_START;
- else if (val == 155) // equivalent to 'ESC'-'['
- state = ANSI_CSI;
- else
- result.append(c);
- break;
- case ANSI_START:
- if (val == 91) // [
- state = ANSI_CSI;
- else if (val == 80 || val == 93 || val == 94 || val == 95) // 'P', ']', '^' and '_'
- state = ANSI_WAITING_FOR_ST;
- else if (val >= 64 && val <= 95)
- state = PLAIN;
- else
- state = ANSI_SEQUENCE;
- break;
- case ANSI_CSI:
- if (val >= 64 && val <= 126) // Anything between '@' and '~'
- state = PLAIN;
- break;
- case ANSI_SEQUENCE:
- if (val >= 64 && val <= 95) // Anything between '@' and '_'
- state = PLAIN;
- break;
- case ANSI_WAITING_FOR_ST:
- if (val == 7) // 'BEL'
- state = PLAIN;
- if (val == 27) // 'ESC'
- state = ANSI_ST_STARTED;
- break;
- case ANSI_ST_STARTED:
- if (val == 92) // '\'
- state = PLAIN;
- else
- state = ANSI_WAITING_FOR_ST;
- break;
- }
- }
- return result;
-}
-
-// Unit tests:
-#ifdef WITH_TESTS
-# include <QTest>
-
-# include "projectexplorer.h"
-# include "outputparser_test.h"
-# include "task.h"
-
-void ProjectExplorerPlugin::testAnsiFilterOutputParser_data()
-{
- QTest::addColumn<QString>("input");
- QTest::addColumn<OutputParserTester::Channel>("inputChannel");
- QTest::addColumn<QString>("childStdOutLines");
- QTest::addColumn<QString>("childStdErrLines");
- QTest::addColumn<QString>("outputLines");
-
- QTest::newRow("pass-through stdout")
- << QString::fromLatin1("Sometext") << OutputParserTester::STDOUT
- << QString::fromLatin1("Sometext\n") << QString();
- QTest::newRow("pass-through stderr")
- << QString::fromLatin1("Sometext") << OutputParserTester::STDERR
- << QString() << QString::fromLatin1("Sometext\n");
-
- QString input = QString::fromLatin1("te") + QChar(27) + QString::fromLatin1("Nst");
- QTest::newRow("ANSI: ESC-N")
- << input << OutputParserTester::STDOUT
- << QString::fromLatin1("test\n") << QString();
- input = QString::fromLatin1("te") + QChar(27) + QLatin1String("^ignored") + QChar(27) + QLatin1String("\\st");
- QTest::newRow("ANSI: ESC-^ignoredESC-\\")
- << input << OutputParserTester::STDOUT
- << QString::fromLatin1("test\n") << QString();
- input = QString::fromLatin1("te") + QChar(27) + QLatin1String("]0;ignored") + QChar(7) + QLatin1String("st");
- QTest::newRow("ANSI: window title change")
- << input << OutputParserTester::STDOUT
- << QString::fromLatin1("test\n") << QString();
- input = QString::fromLatin1("te") + QChar(27) + QLatin1String("[Ast");
- QTest::newRow("ANSI: cursor up")
- << input << OutputParserTester::STDOUT
- << QString::fromLatin1("test\n") << QString();
- input = QString::fromLatin1("te") + QChar(27) + QLatin1String("[2Ast");
- QTest::newRow("ANSI: cursor up (with int parameter)")
- << input << OutputParserTester::STDOUT
- << QString::fromLatin1("test\n") << QString();
- input = QString::fromLatin1("te") + QChar(27) + QLatin1String("[2;3Hst");
- QTest::newRow("ANSI: position cursor")
- << input << OutputParserTester::STDOUT
- << QString::fromLatin1("test\n") << QString();
- input = QString::fromLatin1("te") + QChar(27) + QLatin1String("[31;1mst");
- QTest::newRow("ANSI: bold red")
- << input << OutputParserTester::STDOUT
- << QString::fromLatin1("test\n") << QString();
-}
-
-void ProjectExplorerPlugin::testAnsiFilterOutputParser()
-{
- OutputParserTester testbench;
- testbench.appendOutputParser(new AnsiFilterParser);
- QFETCH(QString, input);
- QFETCH(OutputParserTester::Channel, inputChannel);
- QFETCH(QString, childStdOutLines);
- QFETCH(QString, childStdErrLines);
-
- testbench.testParsing(input, inputChannel,
- Tasks(), childStdOutLines, childStdErrLines,
- QString());
-}
-
-#endif
diff --git a/src/plugins/projectexplorer/applicationlauncher.cpp b/src/plugins/projectexplorer/applicationlauncher.cpp
index e0a725716a..a7ef576661 100644
--- a/src/plugins/projectexplorer/applicationlauncher.cpp
+++ b/src/plugins/projectexplorer/applicationlauncher.cpp
@@ -305,7 +305,7 @@ void ApplicationLauncherPrivate::readLocalStandardOutput()
QByteArray data = m_guiProcess.readAllStandardOutput();
QString msg = m_outputCodec->toUnicode(
data.constData(), data.length(), &m_outputCodecState);
- emit q->appendMessage(msg, StdOutFormatSameLine, false);
+ emit q->appendMessage(msg, StdOutFormat, false);
}
void ApplicationLauncherPrivate::readLocalStandardError()
@@ -313,7 +313,7 @@ void ApplicationLauncherPrivate::readLocalStandardError()
QByteArray data = m_guiProcess.readAllStandardError();
QString msg = m_outputCodec->toUnicode(
data.constData(), data.length(), &m_errorCodecState);
- emit q->appendMessage(msg, StdErrFormatSameLine, false);
+ emit q->appendMessage(msg, StdErrFormat, false);
}
void ApplicationLauncherPrivate::cannotRetrieveLocalDebugOutput()
diff --git a/src/plugins/projectexplorer/appoutputpane.cpp b/src/plugins/projectexplorer/appoutputpane.cpp
index 42975294b3..de92f588cb 100644
--- a/src/plugins/projectexplorer/appoutputpane.cpp
+++ b/src/plugins/projectexplorer/appoutputpane.cpp
@@ -60,6 +60,7 @@
#include <QSpinBox>
#include <QTabBar>
#include <QTabWidget>
+#include <QTimer>
#include <QToolButton>
#include <QVBoxLayout>
@@ -83,15 +84,6 @@ static QString msgAttachDebuggerTooltip(const QString &handleDescription = QStri
AppOutputPane::tr("Attach debugger to %1").arg(handleDescription);
}
-static void replaceAllChildWidgets(QLayout *layout, const QList<QWidget *> &newChildren)
-{
- while (QLayoutItem *child = layout->takeAt(0))
- delete child;
-
- for (QWidget *widget : newChildren)
- layout->addWidget(widget);
-}
-
namespace {
const char SETTINGS_KEY[] = "ProjectExplorer/AppOutput/Zoom";
const char C_APP_OUTPUT[] = "ProjectExplorer.ApplicationOutput";
@@ -163,7 +155,7 @@ AppOutputPane::RunControlTab::RunControlTab(RunControl *runControl, Core::Output
runControl(runControl), window(w)
{
if (runControl && w)
- w->setFormatter(runControl->outputFormatter());
+ w->setLineParsers(runControl->createOutputParsers());
}
AppOutputPane::AppOutputPane() :
@@ -413,7 +405,7 @@ void AppOutputPane::createNewOutputWindow(RunControl *rc)
if (tab.runControl)
tab.runControl->initiateFinish();
tab.runControl = rc;
- tab.window->setFormatter(rc->outputFormatter());
+ tab.window->setLineParsers(rc->createOutputParsers());
handleOldOutput(tab.window);
@@ -700,10 +692,6 @@ void AppOutputPane::enableButtons(const RunControl *rc)
m_attachButton->setToolTip(msgAttachDebuggerTooltip());
}
setZoomButtonsEnabled(true);
-
- replaceAllChildWidgets(m_formatterWidget->layout(), rc->outputFormatter() ?
- rc->outputFormatter()->toolbarWidgets() :
- QList<QWidget *>());
} else {
m_reRunButton->setEnabled(false);
m_reRunButton->setIcon(Utils::Icons::RUN_SMALL_TOOLBAR.icon());
@@ -756,8 +744,12 @@ void AppOutputPane::slotRunControlFinished()
{
auto *rc = qobject_cast<RunControl *>(sender());
QTimer::singleShot(0, this, [this, rc]() { slotRunControlFinished2(rc); });
- if (rc->outputFormatter())
- rc->outputFormatter()->flush();
+ for (const RunControlTab &t : m_runControlTabs) {
+ if (t.runControl == rc) {
+ t.window->flush();
+ break;
+ }
+ }
}
void AppOutputPane::slotRunControlFinished2(RunControl *sender)
diff --git a/src/plugins/projectexplorer/buildaspects.cpp b/src/plugins/projectexplorer/buildaspects.cpp
index 968dba7093..912f885755 100644
--- a/src/plugins/projectexplorer/buildaspects.cpp
+++ b/src/plugins/projectexplorer/buildaspects.cpp
@@ -51,7 +51,7 @@ BuildDirectoryAspect::BuildDirectoryAspect() : d(new Private)
setSettingsKey("ProjectExplorer.BuildConfiguration.BuildDirectory");
setLabelText(tr("Build directory:"));
setDisplayStyle(PathChooserDisplay);
- setExpectedKind(Utils::PathChooser::Directory);
+ setExpectedKind(Utils::PathChooser::ExistingDirectory);
}
BuildDirectoryAspect::~BuildDirectoryAspect()
diff --git a/src/plugins/projectexplorer/buildaspects.h b/src/plugins/projectexplorer/buildaspects.h
index 8e5674f209..2933b5447f 100644
--- a/src/plugins/projectexplorer/buildaspects.h
+++ b/src/plugins/projectexplorer/buildaspects.h
@@ -43,10 +43,11 @@ public:
bool isShadowBuild() const;
void setProblem(const QString &description);
+ void addToLayout(LayoutBuilder &builder) override;
+
private:
void toMap(QVariantMap &map) const override;
void fromMap(const QVariantMap &map) override;
- void addToLayout(LayoutBuilder &builder) override;
void updateProblemLabel();
diff --git a/src/plugins/projectexplorer/buildconfiguration.cpp b/src/plugins/projectexplorer/buildconfiguration.cpp
index c7269480ce..de8ac4dbe4 100644
--- a/src/plugins/projectexplorer/buildconfiguration.cpp
+++ b/src/plugins/projectexplorer/buildconfiguration.cpp
@@ -26,22 +26,23 @@
#include "buildconfiguration.h"
#include "buildaspects.h"
-#include "buildenvironmentwidget.h"
#include "buildinfo.h"
#include "buildsteplist.h"
#include "buildstepspage.h"
#include "buildsystem.h"
-#include "namedwidget.h"
+#include "customparser.h"
+#include "environmentwidget.h"
#include "kit.h"
#include "kitinformation.h"
#include "kitmanager.h"
-#include "project.h"
-#include "projectexplorer.h"
+#include "namedwidget.h"
#include "projectexplorerconstants.h"
+#include "projectexplorer.h"
+#include "project.h"
#include "projectmacroexpander.h"
#include "projecttree.h"
-#include "target.h"
#include "session.h"
+#include "target.h"
#include "toolchain.h"
#include <coreplugin/idocument.h>
@@ -54,8 +55,10 @@
#include <utils/mimetypes/mimetype.h>
#include <utils/qtcassert.h>
+#include <QCheckBox>
#include <QDebug>
#include <QFormLayout>
+#include <QVBoxLayout>
using namespace Utils;
@@ -63,10 +66,69 @@ const char BUILD_STEP_LIST_COUNT[] = "ProjectExplorer.BuildConfiguration.BuildSt
const char BUILD_STEP_LIST_PREFIX[] = "ProjectExplorer.BuildConfiguration.BuildStepList.";
const char CLEAR_SYSTEM_ENVIRONMENT_KEY[] = "ProjectExplorer.BuildConfiguration.ClearSystemEnvironment";
const char USER_ENVIRONMENT_CHANGES_KEY[] = "ProjectExplorer.BuildConfiguration.UserEnvironmentChanges";
+const char CUSTOM_PARSERS_KEY[] = "ProjectExplorer.BuildConfiguration.CustomParsers";
namespace ProjectExplorer {
namespace Internal {
+class BuildEnvironmentWidget : public NamedWidget
+{
+ Q_DECLARE_TR_FUNCTIONS(ProjectExplorer::Internal::BuildEnvironmentWidget)
+
+public:
+ explicit BuildEnvironmentWidget(BuildConfiguration *bc)
+ : NamedWidget(tr("Build Environment"))
+ {
+ auto clearBox = new QCheckBox(tr("Clear system environment"), this);
+ clearBox->setChecked(!bc->useSystemEnvironment());
+
+ auto envWidget = new EnvironmentWidget(this, EnvironmentWidget::TypeLocal, clearBox);
+ envWidget->setBaseEnvironment(bc->baseEnvironment());
+ envWidget->setBaseEnvironmentText(bc->baseEnvironmentText());
+ envWidget->setUserChanges(bc->userEnvironmentChanges());
+
+ connect(envWidget, &EnvironmentWidget::userChangesChanged, this, [bc, envWidget] {
+ bc->setUserEnvironmentChanges(envWidget->userChanges());
+ });
+
+ connect(clearBox, &QAbstractButton::toggled, this, [bc, envWidget](bool checked) {
+ bc->setUseSystemEnvironment(!checked);
+ envWidget->setBaseEnvironment(bc->baseEnvironment());
+ envWidget->setBaseEnvironmentText(bc->baseEnvironmentText());
+ });
+
+ connect(bc, &BuildConfiguration::environmentChanged, this, [bc, envWidget] {
+ envWidget->setBaseEnvironment(bc->baseEnvironment());
+ envWidget->setBaseEnvironmentText(bc->baseEnvironmentText());
+ });
+
+ auto vbox = new QVBoxLayout(this);
+ vbox->setContentsMargins(0, 0, 0, 0);
+ vbox->addWidget(clearBox);
+ vbox->addWidget(envWidget);
+ }
+};
+
+class CustomParsersBuildWidget : public NamedWidget
+{
+ Q_DECLARE_TR_FUNCTIONS(ProjectExplorer::Internal::CustomParsersBuildWidget)
+public:
+ CustomParsersBuildWidget(BuildConfiguration *bc) : NamedWidget(tr("Custom Output Parsers"))
+ {
+ const auto selectionWidget = new CustomParsersSelectionWidget(this);
+ const auto layout = new QVBoxLayout(this);
+ layout->setContentsMargins(0, 0, 0, 0);
+ layout->addWidget(selectionWidget);
+
+ connect(selectionWidget, &CustomParsersSelectionWidget::selectionChanged,
+ [selectionWidget, bc] {
+ bc->setCustomParsers(selectionWidget->selectedParsers());
+ });
+ selectionWidget->setSelectedParsers(bc->customParsers());
+ }
+};
+
+
class BuildConfigurationPrivate
{
public:
@@ -86,6 +148,8 @@ public:
bool m_configWidgetHasFrame = false;
QList<Core::Id> m_initialBuildSteps;
QList<Core::Id> m_initialCleanSteps;
+ Utils::MacroExpander m_macroExpander;
+ QList<Core::Id> m_customParsers;
// FIXME: Remove.
BuildConfiguration::BuildType m_initialBuildType = BuildConfiguration::Unknown;
@@ -130,7 +194,7 @@ BuildConfiguration::BuildConfiguration(Target *target, Core::Id id)
d->m_buildDirectoryAspect->setEnvironment(environment());
d->m_buildDirectoryAspect->setMacroExpanderProvider([this] { return macroExpander(); });
connect(d->m_buildDirectoryAspect, &BaseStringAspect::changed,
- this, &BuildConfiguration::buildDirectoryChanged);
+ this, &BuildConfiguration::emitBuildDirectoryChanged);
connect(this, &BuildConfiguration::environmentChanged, this, [this] {
d->m_buildDirectoryAspect->setEnvironment(environment());
this->target()->buildEnvironmentChanged(this);
@@ -204,6 +268,19 @@ void BuildConfiguration::doInitialize(const BuildInfo &info)
d->m_initializer(info);
}
+MacroExpander *BuildConfiguration::macroExpander() const
+{
+ return &d->m_macroExpander;
+}
+
+bool BuildConfiguration::createBuildDirectory()
+{
+ QDir dir;
+ const auto result = dir.mkpath(buildDirectory().toString());
+ buildDirectoryAspect()->validateInput();
+ return result;
+}
+
void BuildConfiguration::setInitializer(const std::function<void(const BuildInfo &)> &initializer)
{
d->m_initializer = initializer;
@@ -239,7 +316,10 @@ NamedWidget *BuildConfiguration::createConfigWidget()
QList<NamedWidget *> BuildConfiguration::createSubConfigWidgets()
{
- return {new BuildEnvironmentWidget(this)};
+ return {
+ new Internal::BuildEnvironmentWidget(this),
+ new Internal::CustomParsersBuildWidget(this)
+ };
}
BuildSystem *BuildConfiguration::buildSystem() const
@@ -279,6 +359,8 @@ QVariantMap BuildConfiguration::toMap() const
map.insert(QLatin1String(BUILD_STEP_LIST_PREFIX) + QString::number(0), d->m_buildSteps.toMap());
map.insert(QLatin1String(BUILD_STEP_LIST_PREFIX) + QString::number(1), d->m_cleanSteps.toMap());
+ map.insert(CUSTOM_PARSERS_KEY, transform(d->m_customParsers,&Core::Id::toSetting));
+
return map;
}
@@ -311,6 +393,8 @@ bool BuildConfiguration::fromMap(const QVariantMap &map)
}
}
+ d->m_customParsers = transform(map.value(CUSTOM_PARSERS_KEY).toList(), &Core::Id::fromSetting);
+
return ProjectConfiguration::fromMap(map);
}
@@ -394,6 +478,16 @@ void BuildConfiguration::addToEnvironment(Environment &env) const
Q_UNUSED(env)
}
+const QList<Core::Id> BuildConfiguration::customParsers() const
+{
+ return d->m_customParsers;
+}
+
+void BuildConfiguration::setCustomParsers(const QList<Core::Id> &parsers)
+{
+ d->m_customParsers = parsers;
+}
+
bool BuildConfiguration::useSystemEnvironment() const
{
return !d->m_clearSystemEnvironment;
@@ -470,8 +564,7 @@ bool BuildConfiguration::isActive() const
void BuildConfiguration::prependCompilerPathToEnvironment(Kit *k, Environment &env)
{
- const ToolChain *tc
- = ToolChainKitAspect::toolChain(k, ProjectExplorer::Constants::CXX_LANGUAGE_ID);
+ const ToolChain *tc = ToolChainKitAspect::cxxToolChain(k);
if (!tc)
return;
diff --git a/src/plugins/projectexplorer/buildconfiguration.h b/src/plugins/projectexplorer/buildconfiguration.h
index 04058f4aa7..5e7bf1d03a 100644
--- a/src/plugins/projectexplorer/buildconfiguration.h
+++ b/src/plugins/projectexplorer/buildconfiguration.h
@@ -32,6 +32,8 @@
#include <utils/environment.h>
#include <utils/fileutils.h>
+namespace Utils { class MacroExpander; }
+
namespace ProjectExplorer {
namespace Internal { class BuildConfigurationPrivate; }
@@ -77,6 +79,9 @@ public:
virtual void addToEnvironment(Utils::Environment &env) const;
+ const QList<Core::Id> customParsers() const;
+ void setCustomParsers(const QList<Core::Id> &parsers);
+
BuildStepList *buildSteps() const;
BuildStepList *cleanSteps() const;
@@ -118,6 +123,10 @@ public:
void doInitialize(const BuildInfo &info);
+ Utils::MacroExpander *macroExpander() const;
+
+ bool createBuildDirectory();
+
signals:
void environmentChanged();
void buildDirectoryChanged();
diff --git a/src/plugins/projectexplorer/buildenvironmentwidget.cpp b/src/plugins/projectexplorer/buildenvironmentwidget.cpp
deleted file mode 100644
index 68211385e8..0000000000
--- a/src/plugins/projectexplorer/buildenvironmentwidget.cpp
+++ /dev/null
@@ -1,82 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "buildenvironmentwidget.h"
-
-#include "buildconfiguration.h"
-#include "environmentwidget.h"
-
-#include <projectexplorer/target.h>
-
-#include <QVBoxLayout>
-#include <QCheckBox>
-
-namespace ProjectExplorer {
-
-BuildEnvironmentWidget::BuildEnvironmentWidget(BuildConfiguration *bc)
- : NamedWidget(tr("Build Environment")), m_buildConfiguration(bc)
-{
- auto vbox = new QVBoxLayout(this);
- vbox->setContentsMargins(0, 0, 0, 0);
- m_clearSystemEnvironmentCheckBox = new QCheckBox(this);
- m_clearSystemEnvironmentCheckBox->setText(tr("Clear system environment"));
-
- m_buildEnvironmentWidget = new EnvironmentWidget(this, EnvironmentWidget::TypeLocal,
- m_clearSystemEnvironmentCheckBox);
- vbox->addWidget(m_buildEnvironmentWidget);
-
- connect(m_buildEnvironmentWidget, &EnvironmentWidget::userChangesChanged,
- this, &BuildEnvironmentWidget::environmentModelUserChangesChanged);
- connect(m_clearSystemEnvironmentCheckBox, &QAbstractButton::toggled,
- this, &BuildEnvironmentWidget::clearSystemEnvironmentCheckBoxClicked);
-
- connect(m_buildConfiguration, &BuildConfiguration::environmentChanged,
- this, &BuildEnvironmentWidget::environmentChanged);
-
- m_clearSystemEnvironmentCheckBox->setChecked(!m_buildConfiguration->useSystemEnvironment());
- m_buildEnvironmentWidget->setBaseEnvironment(m_buildConfiguration->baseEnvironment());
- m_buildEnvironmentWidget->setBaseEnvironmentText(m_buildConfiguration->baseEnvironmentText());
- m_buildEnvironmentWidget->setUserChanges(m_buildConfiguration->userEnvironmentChanges());
-}
-
-void BuildEnvironmentWidget::environmentModelUserChangesChanged()
-{
- m_buildConfiguration->setUserEnvironmentChanges(m_buildEnvironmentWidget->userChanges());
-}
-
-void BuildEnvironmentWidget::clearSystemEnvironmentCheckBoxClicked(bool checked)
-{
- m_buildConfiguration->setUseSystemEnvironment(!checked);
- m_buildEnvironmentWidget->setBaseEnvironment(m_buildConfiguration->baseEnvironment());
- m_buildEnvironmentWidget->setBaseEnvironmentText(m_buildConfiguration->baseEnvironmentText());
-}
-
-void BuildEnvironmentWidget::environmentChanged()
-{
- m_buildEnvironmentWidget->setBaseEnvironment(m_buildConfiguration->baseEnvironment());
- m_buildEnvironmentWidget->setBaseEnvironmentText(m_buildConfiguration->baseEnvironmentText());
-}
-
-} // ProjectExplorer
diff --git a/src/plugins/projectexplorer/buildmanager.cpp b/src/plugins/projectexplorer/buildmanager.cpp
index 08bfa57de0..ce39023c7a 100644
--- a/src/plugins/projectexplorer/buildmanager.cpp
+++ b/src/plugins/projectexplorer/buildmanager.cpp
@@ -46,6 +46,7 @@
#include <coreplugin/progressmanager/futureprogress.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <extensionsystem/pluginmanager.h>
+#include <utils/outputformatter.h>
#include <utils/runextensions.h>
#include <utils/stringutils.h>
@@ -441,6 +442,20 @@ const Internal::CompileOutputSettings &BuildManager::compileOutputSettings()
return d->m_outputWindow->settings();
}
+QString BuildManager::displayNameForStepId(Id stepId)
+{
+ if (stepId == Constants::BUILDSTEPS_CLEAN) {
+ //: Displayed name for a "cleaning" build step
+ return tr("Clean");
+ }
+ if (stepId == Constants::BUILDSTEPS_DEPLOY) {
+ //: Displayed name for a deploy step
+ return tr("Deploy");
+ }
+ //: Displayed name for a normal build step
+ return tr("Build");
+}
+
void BuildManager::cancel()
{
if (d->m_running) {
@@ -680,14 +695,16 @@ void BuildManager::nextStep()
}
static const auto finishedHandler = [](bool success) {
+ d->m_outputWindow->outputFormatter()->flush();
d->m_lastStepSucceeded = success;
disconnect(d->m_currentBuildStep, nullptr, instance(), nullptr);
BuildManager::nextBuildQueue();
};
- connect(d->m_currentBuildStep, &BuildStep::finished, instance(), finishedHandler,
- Qt::QueuedConnection);
+ connect(d->m_currentBuildStep, &BuildStep::finished, instance(), finishedHandler);
connect(d->m_currentBuildStep, &BuildStep::progress,
instance(), &BuildManager::progressChanged);
+ d->m_outputWindow->reset();
+ d->m_currentBuildStep->setupOutputFormatter(d->m_outputWindow->outputFormatter());
d->m_currentBuildStep->run();
} else {
d->m_running = false;
@@ -771,7 +788,7 @@ bool BuildManager::buildLists(const QList<BuildStepList *> bsls, const QStringLi
QStringList stepListNames;
for (BuildStepList *list : bsls) {
steps.append(list->steps());
- stepListNames.append(ProjectExplorerPlugin::displayNameForStepId(list->id()));
+ stepListNames.append(displayNameForStepId(list->id()));
d->m_isDeploying = d->m_isDeploying || list->id() == Constants::BUILDSTEPS_DEPLOY;
}
diff --git a/src/plugins/projectexplorer/buildmanager.h b/src/plugins/projectexplorer/buildmanager.h
index d62786ed81..f50b458b23 100644
--- a/src/plugins/projectexplorer/buildmanager.h
+++ b/src/plugins/projectexplorer/buildmanager.h
@@ -91,6 +91,8 @@ public:
static void setCompileOutputSettings(const Internal::CompileOutputSettings &settings);
static const Internal::CompileOutputSettings &compileOutputSettings();
+ static QString displayNameForStepId(Core::Id stepId);
+
public slots:
static void cancel();
// Shows without focus
diff --git a/src/plugins/projectexplorer/buildstep.cpp b/src/plugins/projectexplorer/buildstep.cpp
index 959e91d23c..4a56d805c4 100644
--- a/src/plugins/projectexplorer/buildstep.cpp
+++ b/src/plugins/projectexplorer/buildstep.cpp
@@ -27,14 +27,19 @@
#include "buildconfiguration.h"
#include "buildsteplist.h"
+#include "customparser.h"
#include "deployconfiguration.h"
#include "kitinformation.h"
#include "project.h"
+#include "projectexplorer.h"
+#include "projectexplorerconstants.h"
#include "target.h"
#include <coreplugin/variablechooser.h>
#include <utils/algorithm.h>
+#include <utils/fileinprojectfinder.h>
+#include <utils/outputformatter.h>
#include <utils/qtcassert.h>
#include <utils/runextensions.h>
@@ -117,6 +122,8 @@
This signal needs to be emitted if the build step runs in the GUI thread.
*/
+using namespace Utils;
+
static const char buildStepEnabledKey[] = "ProjectExplorer.BuildStep.Enabled";
namespace ProjectExplorer {
@@ -127,10 +134,11 @@ BuildStep::BuildStep(BuildStepList *bsl, Core::Id id) :
ProjectConfiguration(bsl, id)
{
QTC_CHECK(bsl->target() && bsl->target() == this->target());
- Utils::MacroExpander *expander = macroExpander();
- expander->setDisplayName(tr("Build Step"));
- expander->setAccumulating(true);
- expander->registerSubProvider([this] { return projectConfiguration()->macroExpander(); });
+}
+
+BuildStep::~BuildStep()
+{
+ emit finished(false);
}
void BuildStep::run()
@@ -186,6 +194,13 @@ BuildConfiguration *BuildStep::buildConfiguration() const
auto config = qobject_cast<BuildConfiguration *>(parent()->parent());
if (config)
return config;
+
+ // This situation should be avoided, as the step returned below is almost
+ // always not the right one, but the fallback is best we can do.
+ // A potential currently still valid path is accessing a build configuration
+ // from a BuildStep in a DeployConfiguration. Let's hunt those down and
+ // replace with explicit code there.
+ QTC_CHECK(false);
// step is not part of a build configuration, use active build configuration of step's target
return target()->activeBuildConfiguration();
}
@@ -195,6 +210,8 @@ DeployConfiguration *BuildStep::deployConfiguration() const
auto config = qobject_cast<DeployConfiguration *>(parent()->parent());
if (config)
return config;
+ // See comment in buildConfiguration()
+ QTC_CHECK(false);
// step is not part of a deploy configuration, use active deploy configuration of step's target
return target()->activeDeployConfiguration();
}
@@ -211,6 +228,53 @@ BuildSystem *BuildStep::buildSystem() const
return target()->buildSystem();
}
+Environment BuildStep::buildEnvironment() const
+{
+ if (auto bc = buildConfiguration())
+ return bc->environment();
+ return Environment::systemEnvironment();
+}
+
+FilePath BuildStep::buildDirectory() const
+{
+ if (auto bc = buildConfiguration())
+ return bc->buildDirectory();
+ return {};
+}
+
+BuildConfiguration::BuildType BuildStep::buildType() const
+{
+ if (auto bc = buildConfiguration())
+ return bc->buildType();
+ return BuildConfiguration::Unknown;
+}
+
+Utils::MacroExpander *BuildStep::macroExpander() const
+{
+ if (auto bc = buildConfiguration())
+ return bc->macroExpander();
+ return Utils::globalMacroExpander();
+}
+
+QString BuildStep::fallbackWorkingDirectory() const
+{
+ if (buildConfiguration())
+ return {Constants::DEFAULT_WORKING_DIR};
+ return {Constants::DEFAULT_WORKING_DIR_ALTERNATE};
+}
+
+void BuildStep::setupOutputFormatter(OutputFormatter *formatter)
+{
+ for (const Core::Id id : buildConfiguration()->customParsers()) {
+ if (Internal::CustomParser * const parser = Internal::CustomParser::createFromId(id))
+ formatter->addLineParser(parser);
+ }
+ Utils::FileInProjectFinder fileFinder;
+ fileFinder.setProjectDirectory(project()->projectDirectory());
+ fileFinder.setProjectFiles(project()->files(Project::AllFiles));
+ formatter->setFileFinder(fileFinder);
+}
+
void BuildStep::reportRunResult(QFutureInterface<bool> &fi, bool success)
{
fi.reportResult(success);
diff --git a/src/plugins/projectexplorer/buildstep.h b/src/plugins/projectexplorer/buildstep.h
index 2b2cfe64a2..03a88c8b1a 100644
--- a/src/plugins/projectexplorer/buildstep.h
+++ b/src/plugins/projectexplorer/buildstep.h
@@ -26,6 +26,8 @@
#pragma once
#include "projectconfiguration.h"
+
+#include "buildconfiguration.h"
#include "projectexplorer_export.h"
#include <utils/optional.h>
@@ -38,6 +40,13 @@
#include <functional>
#include <memory>
+namespace Utils {
+class Environment;
+class FilePath;
+class MacroExpander;
+class OutputFormatter;
+} // Utils
+
namespace ProjectExplorer {
class BuildConfiguration;
@@ -59,6 +68,7 @@ protected:
explicit BuildStep(BuildStepList *bsl, Core::Id id);
public:
+ ~BuildStep() override;
virtual bool init() = 0;
void run();
void cancel();
@@ -77,6 +87,13 @@ public:
ProjectConfiguration *projectConfiguration() const;
BuildSystem *buildSystem() const;
+ Utils::Environment buildEnvironment() const;
+ Utils::FilePath buildDirectory() const;
+ BuildConfiguration::BuildType buildType() const;
+ Utils::MacroExpander *macroExpander() const;
+ QString fallbackWorkingDirectory() const;
+
+ virtual void setupOutputFormatter(Utils::OutputFormatter *formatter);
enum class OutputFormat {
Stdout, Stderr, // These are for forwarded output from external tools
@@ -104,8 +121,8 @@ public:
signals:
/// Adds a \p task to the Issues pane.
- /// Do note that for linking compile output with tasks, you should first emit the task
- /// and then emit the output. \p linkedOutput lines will be linked. And the last \p skipLines will
+ /// Do note that for linking compile output with tasks, you should first emit the output
+ /// and then emit the task. \p linkedOutput lines will be linked. And the last \p skipLines will
/// be skipped.
void addTask(const ProjectExplorer::Task &task, int linkedOutputLines = 0, int skipLines = 0);
diff --git a/src/plugins/projectexplorer/buildsystem.cpp b/src/plugins/projectexplorer/buildsystem.cpp
index ea299cd522..7b6f4bbf5a 100644
--- a/src/plugins/projectexplorer/buildsystem.cpp
+++ b/src/plugins/projectexplorer/buildsystem.cpp
@@ -30,6 +30,8 @@
#include "runcontrol.h"
#include "target.h"
+#include <projectexplorer/buildaspects.h>
+
#include <utils/qtcassert.h>
#include <QTimer>
@@ -95,6 +97,11 @@ Kit *BuildSystem::kit() const
return d->m_target->kit();
}
+BuildConfiguration *BuildSystem::buildConfiguration() const
+{
+ return d->m_buildConfiguration;
+}
+
void BuildSystem::emitParsingStarted()
{
QTC_ASSERT(!d->m_isParsing, return);
@@ -142,6 +149,26 @@ void BuildSystem::requestDelayedParse()
requestParseHelper(1000);
}
+void BuildSystem::requestParseWithCustomDelay(int delayInMs)
+{
+ requestParseHelper(delayInMs);
+}
+
+void BuildSystem::cancelDelayedParseRequest()
+{
+ d->m_delayedParsingTimer.stop();
+}
+
+void BuildSystem::setParseDelay(int delayInMs)
+{
+ d->m_delayedParsingTimer.setInterval(delayInMs);
+}
+
+int BuildSystem::parseDelay() const
+{
+ return d->m_delayedParsingTimer.interval();
+}
+
bool BuildSystem::isParsing() const
{
return d->m_isParsing;
@@ -314,6 +341,20 @@ void BuildSystem::emitBuildSystemUpdated()
target()->buildSystemUpdated(this);
}
+void BuildSystem::setExtraData(const QString &buildKey, Core::Id dataKey, const QVariant &data)
+{
+ const ProjectNode *node = d->m_target->project()->findNodeForBuildKey(buildKey);
+ QTC_ASSERT(node, return);
+ node->setData(dataKey, data);
+}
+
+QVariant BuildSystem::extraData(const QString &buildKey, Core::Id dataKey) const
+{
+ const ProjectNode *node = d->m_target->project()->findNodeForBuildKey(buildKey);
+ QTC_ASSERT(node, return {});
+ return node->data(dataKey);
+}
+
QString BuildSystem::disabledReason(const QString &buildKey) const
{
if (!hasParsingData()) {
diff --git a/src/plugins/projectexplorer/buildsystem.h b/src/plugins/projectexplorer/buildsystem.h
index 551f83ac00..af69ca29e4 100644
--- a/src/plugins/projectexplorer/buildsystem.h
+++ b/src/plugins/projectexplorer/buildsystem.h
@@ -54,6 +54,7 @@ public:
Project *project() const;
Target *target() const;
Kit *kit() const;
+ BuildConfiguration *buildConfiguration() const;
Utils::FilePath projectFilePath() const;
Utils::FilePath projectDirectory() const;
@@ -62,6 +63,10 @@ public:
void requestParse();
void requestDelayedParse();
+ void requestParseWithCustomDelay(int delayInMs = 1000);
+ void cancelDelayedParseRequest();
+ void setParseDelay(int delayInMs);
+ int parseDelay() const;
bool isParsing() const;
bool hasParsingData() const;
@@ -116,6 +121,9 @@ public:
void emitBuildSystemUpdated();
+ void setExtraData(const QString &buildKey, Core::Id dataKey, const QVariant &data);
+ QVariant extraData(const QString &buildKey, Core::Id dataKey) const;
+
public:
// FIXME: Make this private and the BuildSystem a friend
ParseGuard guardParsingRun() { return ParseGuard(this); }
diff --git a/src/plugins/projectexplorer/clangparser.cpp b/src/plugins/projectexplorer/clangparser.cpp
index cc62f32cf7..4c34209671 100644
--- a/src/plugins/projectexplorer/clangparser.cpp
+++ b/src/plugins/projectexplorer/clangparser.cpp
@@ -25,6 +25,7 @@
#include "clangparser.h"
#include "ldparser.h"
+#include "lldparser.h"
#include "projectexplorerconstants.h"
using namespace ProjectExplorer;
@@ -54,31 +55,39 @@ ClangParser::ClangParser() :
setObjectName(QLatin1String("ClangParser"));
}
-void ClangParser::stdError(const QString &line)
+QList<OutputLineParser *> ClangParser::clangParserSuite()
{
+ return {new ClangParser, new Internal::LldParser, new LdParser};
+}
+
+OutputLineParser::Result ClangParser::handleLine(const QString &line, OutputFormat type)
+{
+ if (type != StdErrFormat)
+ return Status::NotHandled;
const QString lne = rightTrimmed(line);
QRegularExpressionMatch match = m_summaryRegExp.match(lne);
if (match.hasMatch()) {
- doFlush();
+ flush();
m_expectSnippet = false;
- return;
+ return Status::Done;
}
match = m_commandRegExp.match(lne);
if (match.hasMatch()) {
m_expectSnippet = true;
- newTask(CompileTask(taskType(match.captured(3)), match.captured(4)));
- return;
+ createOrAmendTask(taskType(match.captured(3)), match.captured(4), lne);
+ return Status::InProgress;
}
match = m_inLineRegExp.match(lne);
if (match.hasMatch()) {
m_expectSnippet = true;
- newTask(CompileTask(Task::Unknown,
- lne.trimmed(),
- FilePath::fromUserInput(match.captured(2)), /* filename */
- match.captured(3).toInt() /* line */));
- return;
+ const FilePath filePath = absoluteFilePath(FilePath::fromUserInput(match.captured(2)));
+ const int lineNo = match.captured(3).toInt();
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, lineNo, match, 2);
+ createOrAmendTask(Task::Unknown, lne.trimmed(), lne, false, filePath, lineNo, linkSpecs);
+ return {Status::InProgress, linkSpecs};
}
match = m_messageRegExp.match(lne);
@@ -88,26 +97,27 @@ void ClangParser::stdError(const QString &line)
int lineNo = match.captured(4).toInt(&ok);
if (!ok)
lineNo = match.captured(5).toInt(&ok);
- newTask(CompileTask(taskType(match.captured(7)),
- match.captured(8),
- FilePath::fromUserInput(match.captured(1)), /* filename */
- lineNo));
- return;
+ const FilePath filePath = absoluteFilePath(FilePath::fromUserInput(match.captured(1)));
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, lineNo, match, 1);
+ createOrAmendTask(taskType(match.captured(7)), match.captured(8), lne, false,
+ filePath, lineNo, linkSpecs);
+ return {Status::InProgress, linkSpecs};
}
match = m_codesignRegExp.match(lne);
if (match.hasMatch()) {
m_expectSnippet = true;
- newTask(CompileTask(Task::Error, match.captured(1)));
- return;
+ createOrAmendTask(Task::Error, match.captured(1), lne, false);
+ return Status::InProgress;
}
if (m_expectSnippet) {
- amendDescription(lne, true);
- return;
+ createOrAmendTask(Task::Unknown, lne, lne, true);
+ return Status::InProgress;
}
- IOutputParser::stdError(line);
+ return Status::NotHandled;
}
Core::Id ClangParser::id()
@@ -169,17 +179,15 @@ void ProjectExplorerPlugin::testClangOutputParser_data()
" ^")
<< OutputParserTester::STDERR
<< QString() << QString()
- << (Tasks()
- << CompileTask(Task::Unknown,
- "In file included from ..\\..\\..\\QtSDK1.1\\Desktop\\Qt\\4.7.3\\mingw\\include/QtCore/qnamespace.h:45:",
- FilePath::fromUserInput("..\\..\\..\\QtSDK1.1\\Desktop\\Qt\\4.7.3\\mingw\\include/QtCore/qnamespace.h"),
- 45)
- << CompileTask(Task::Warning,
- "unknown attribute 'dllimport' ignored [-Wunknown-attributes]\n"
- "class Q_CORE_EXPORT QSysInfo {\n"
- " ^",
- FilePath::fromUserInput("..\\..\\..\\QtSDK1.1\\Desktop\\Qt\\4.7.3\\mingw\\include/QtCore/qglobal.h"),
- 1425))
+ << Tasks{CompileTask(
+ Task::Warning,
+ "unknown attribute 'dllimport' ignored [-Wunknown-attributes]\n"
+ "In file included from ..\\..\\..\\QtSDK1.1\\Desktop\\Qt\\4.7.3\\mingw\\include/QtCore/qnamespace.h:45:\n"
+ "..\\..\\..\\QtSDK1.1\\Desktop\\Qt\\4.7.3\\mingw\\include/QtCore/qglobal.h(1425) : warning: unknown attribute 'dllimport' ignored [-Wunknown-attributes]\n"
+ "class Q_CORE_EXPORT QSysInfo {\n"
+ " ^",
+ FilePath::fromUserInput("..\\..\\..\\QtSDK1.1\\Desktop\\Qt\\4.7.3\\mingw\\include/QtCore/qglobal.h"),
+ 1425)}
<< QString();
QTest::newRow("note")
@@ -191,6 +199,7 @@ void ProjectExplorerPlugin::testClangOutputParser_data()
<< (Tasks()
<< CompileTask(Task::Unknown,
"instantiated from:\n"
+ "..\\..\\..\\QtSDK1.1\\Desktop\\Qt\\4.7.3\\mingw\\include/QtCore/qglobal.h:1289:27: note: instantiated from:\n"
"# define Q_CORE_EXPORT Q_DECL_IMPORT\n"
" ^",
FilePath::fromUserInput("..\\..\\..\\QtSDK1.1\\Desktop\\Qt\\4.7.3\\mingw\\include/QtCore/qglobal.h"),
@@ -206,6 +215,7 @@ void ProjectExplorerPlugin::testClangOutputParser_data()
<< (Tasks()
<< CompileTask(Task::Error,
"'bits/c++config.h' file not found\n"
+ "/usr/include/c++/4.6/utility:68:10: fatal error: 'bits/c++config.h' file not found\n"
"#include <bits/c++config.h>\n"
" ^",
FilePath::fromUserInput("/usr/include/c++/4.6/utility"),
@@ -221,6 +231,7 @@ void ProjectExplorerPlugin::testClangOutputParser_data()
<< (Tasks()
<< CompileTask(Task::Warning,
"?: has lower precedence than +; + will be evaluated first [-Wparentheses]\n"
+ "/home/code/src/creator/src/plugins/coreplugin/manhattanstyle.cpp:567:51: warning: ?: has lower precedence than +; + will be evaluated first [-Wparentheses]\n"
" int x = option->rect.x() + horizontal ? 2 : 6;\n"
" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^",
FilePath::fromUserInput("/home/code/src/creator/src/plugins/coreplugin/manhattanstyle.cpp"),
@@ -247,15 +258,14 @@ void ProjectExplorerPlugin::testClangOutputParser_data()
<< (Tasks()
<< CompileTask(Task::Unknown,
"Note: No relevant classes found. No output generated.",
- FilePath::fromUserInput("/home/qtwebkithelpviewer.h"),
- 0))
+ FilePath::fromUserInput("/home/qtwebkithelpviewer.h")))
<< QString();
}
void ProjectExplorerPlugin::testClangOutputParser()
{
OutputParserTester testbench;
- testbench.appendOutputParser(new ClangParser);
+ testbench.setLineParsers(ClangParser::clangParserSuite());
QFETCH(QString, input);
QFETCH(OutputParserTester::Channel, inputChannel);
QFETCH(Tasks, tasks);
diff --git a/src/plugins/projectexplorer/clangparser.h b/src/plugins/projectexplorer/clangparser.h
index 0c7adaba8d..5b61d0cbaa 100644
--- a/src/plugins/projectexplorer/clangparser.h
+++ b/src/plugins/projectexplorer/clangparser.h
@@ -38,11 +38,14 @@ class PROJECTEXPLORER_EXPORT ClangParser : public ProjectExplorer::GccParser
public:
ClangParser();
- void stdError(const QString &line) override;
+
+ static QList<Utils::OutputLineParser *> clangParserSuite();
static Core::Id id();
private:
+ Result handleLine(const QString &line, Utils::OutputFormat type) override;
+
QRegularExpression m_commandRegExp;
QRegularExpression m_inLineRegExp;
QRegularExpression m_messageRegExp;
diff --git a/src/plugins/projectexplorer/compileoutputwindow.cpp b/src/plugins/projectexplorer/compileoutputwindow.cpp
index 3eeedee281..97ab9b69be 100644
--- a/src/plugins/projectexplorer/compileoutputwindow.cpp
+++ b/src/plugins/projectexplorer/compileoutputwindow.cpp
@@ -24,12 +24,14 @@
****************************************************************************/
#include "compileoutputwindow.h"
+
#include "buildmanager.h"
-#include "showoutputtaskhandler.h"
-#include "task.h"
+#include "ioutputparser.h"
#include "projectexplorer.h"
#include "projectexplorericons.h"
#include "projectexplorersettings.h"
+#include "showoutputtaskhandler.h"
+#include "task.h"
#include "taskhub.h"
#include <coreplugin/outputwindow.h>
@@ -40,6 +42,7 @@
#include <texteditor/texteditorsettings.h>
#include <texteditor/fontsettings.h>
#include <texteditor/behaviorsettings.h>
+#include <utils/algorithm.h>
#include <utils/outputformatter.h>
#include <utils/proxyaction.h>
#include <utils/theme/theme.h>
@@ -67,75 +70,28 @@ const char WRAP_OUTPUT_KEY[] = "ProjectExplorer/Settings/WrapBuildOutput";
const char MAX_LINES_KEY[] = "ProjectExplorer/Settings/MaxBuildOutputLines";
const char OPTIONS_PAGE_ID[] = "C.ProjectExplorer.CompileOutputOptions";
-class CompileOutputTextEdit : public Core::OutputWindow
-{
- Q_OBJECT
-public:
- CompileOutputTextEdit(const Core::Context &context) : Core::OutputWindow(context, SETTINGS_KEY)
- {
- setMouseTracking(true);
- }
-
- void addTask(const Task &task, int blocknumber)
- {
- m_taskids.insert(blocknumber, task.taskId);
- }
-
- void clearTasks()
- {
- m_taskids.clear();
- }
-
-protected:
- void mouseMoveEvent(QMouseEvent *ev) override
- {
- const int line = cursorForPosition(ev->pos()).block().blockNumber();
- if (m_taskids.contains(line) && m_mousePressButton == Qt::NoButton)
- viewport()->setCursor(Qt::PointingHandCursor);
- else
- viewport()->setCursor(Qt::IBeamCursor);
- QPlainTextEdit::mouseMoveEvent(ev);
- }
-
- void mousePressEvent(QMouseEvent *ev) override
- {
- m_mousePressPosition = ev->pos();
- m_mousePressButton = ev->button();
- QPlainTextEdit::mousePressEvent(ev);
- }
-
- void mouseReleaseEvent(QMouseEvent *ev) override
- {
- if ((m_mousePressPosition - ev->pos()).manhattanLength() < 4
- && m_mousePressButton == Qt::LeftButton) {
- int line = cursorForPosition(ev->pos()).block().blockNumber();
- if (unsigned taskid = m_taskids.value(line, 0))
- TaskHub::showTaskInEditor(taskid);
- }
-
- m_mousePressButton = Qt::NoButton;
- QPlainTextEdit::mouseReleaseEvent(ev);
- }
-
-private:
- QHash<int, unsigned int> m_taskids; //Map blocknumber to taskId
- QPoint m_mousePressPosition;
- Qt::MouseButton m_mousePressButton = Qt::NoButton;
-};
-
CompileOutputWindow::CompileOutputWindow(QAction *cancelBuildAction) :
m_cancelBuildButton(new QToolButton),
- m_settingsButton(new QToolButton),
- m_formatter(new Utils::OutputFormatter)
+ m_settingsButton(new QToolButton)
{
Core::Context context(C_COMPILE_OUTPUT);
- m_outputWindow = new CompileOutputTextEdit(context);
+ m_outputWindow = new Core::OutputWindow(context, SETTINGS_KEY);
m_outputWindow->setWindowTitle(displayName());
m_outputWindow->setWindowIcon(Icons::WINDOW.icon());
m_outputWindow->setReadOnly(true);
m_outputWindow->setUndoRedoEnabled(false);
m_outputWindow->setMaxCharCount(Core::Constants::DEFAULT_MAX_CHAR_COUNT);
- m_outputWindow->setFormatter(m_formatter);
+
+ outputFormatter()->overridePostPrintAction([this](Utils::OutputLineParser *parser) {
+ if (const auto taskParser = qobject_cast<OutputTaskParser *>(parser)) {
+ int offset = 0;
+ Utils::reverseForeach(taskParser->taskInfo(), [this, &offset](const OutputTaskParser::TaskInfo &ti) {
+ registerPositionOf(ti.task, ti.linkedLines, ti.skippedLines, offset);
+ offset += ti.linkedLines;
+ });
+ }
+ parser->runPostPrintActions();
+ });
// Let selected text be colored as if the text edit was editable,
// otherwise the highlight for searching is too light
@@ -198,7 +154,6 @@ CompileOutputWindow::~CompileOutputWindow()
delete m_handler;
delete m_cancelBuildButton;
delete m_settingsButton;
- delete m_formatter;
}
void CompileOutputWindow::updateFromSettings()
@@ -257,7 +212,6 @@ void CompileOutputWindow::appendText(const QString &text, BuildStep::OutputForma
void CompileOutputWindow::clearContents()
{
m_outputWindow->clear();
- m_outputWindow->clearTasks();
m_taskPositions.clear();
}
@@ -290,22 +244,17 @@ bool CompileOutputWindow::canNavigate() const
return false;
}
-void CompileOutputWindow::registerPositionOf(const Task &task, int linkedOutputLines, int skipLines)
+void CompileOutputWindow::registerPositionOf(const Task &task, int linkedOutputLines, int skipLines,
+ int offset)
{
if (linkedOutputLines <= 0)
return;
- const int charNumber = m_outputWindow->document()->characterCount();
- if (charNumber > m_outputWindow->maxCharCount())
- return;
-
- const int blocknumber = m_outputWindow->document()->blockCount();
- const int startLine = blocknumber - linkedOutputLines + 1 - skipLines;
- const int endLine = blocknumber - skipLines;
- m_taskPositions.insert(task.taskId, qMakePair(startLine, endLine));
+ const int blocknumber = m_outputWindow->document()->blockCount() - offset - 1;
+ const int firstLine = blocknumber - linkedOutputLines - skipLines;
+ const int lastLine = firstLine + linkedOutputLines - 1;
- for (int i = startLine; i <= endLine; ++i)
- m_outputWindow->addTask(task, i);
+ m_taskPositions.insert(task.taskId, qMakePair(firstLine, lastLine));
}
bool CompileOutputWindow::knowsPositionOf(const Task &task)
@@ -333,7 +282,12 @@ void CompileOutputWindow::showPositionOf(const Task &task)
void CompileOutputWindow::flush()
{
- m_formatter->flush();
+ m_outputWindow->flush();
+}
+
+void CompileOutputWindow::reset()
+{
+ m_outputWindow->reset();
}
void CompileOutputWindow::setSettings(const CompileOutputSettings &settings)
@@ -343,6 +297,11 @@ void CompileOutputWindow::setSettings(const CompileOutputSettings &settings)
updateFromSettings();
}
+Utils::OutputFormatter *CompileOutputWindow::outputFormatter() const
+{
+ return m_outputWindow->outputFormatter();
+}
+
void CompileOutputWindow::updateFilter()
{
m_outputWindow->updateFilterProperties(filterText(), filterCaseSensitivity(),
@@ -418,5 +377,3 @@ CompileOutputSettingsPage::CompileOutputSettingsPage()
} // Internal
} // ProjectExplorer
-
-#include "compileoutputwindow.moc"
diff --git a/src/plugins/projectexplorer/compileoutputwindow.h b/src/plugins/projectexplorer/compileoutputwindow.h
index 71a619a76a..a146ea16cb 100644
--- a/src/plugins/projectexplorer/compileoutputwindow.h
+++ b/src/plugins/projectexplorer/compileoutputwindow.h
@@ -34,20 +34,16 @@
#include <QPair>
QT_BEGIN_NAMESPACE
-class QPlainTextEdit;
-class QTextCharFormat;
class QToolButton;
QT_END_NAMESPACE
+namespace Core { class OutputWindow; }
namespace Utils { class OutputFormatter; }
namespace ProjectExplorer {
-
-class BuildManager;
class Task;
namespace Internal {
-
class ShowOutputTaskHandler;
class CompileOutputTextEdit;
@@ -77,15 +73,18 @@ public:
void appendText(const QString &text, BuildStep::OutputFormat format);
- void registerPositionOf(const Task &task, int linkedOutputLines, int skipLines);
+ void registerPositionOf(const Task &task, int linkedOutputLines, int skipLines, int offset = 0);
bool knowsPositionOf(const Task &task);
void showPositionOf(const Task &task);
void flush();
+ void reset();
const CompileOutputSettings &settings() const { return m_settings; }
void setSettings(const CompileOutputSettings &settings);
+ Utils::OutputFormatter *outputFormatter() const;
+
private:
void updateFilter() override;
@@ -93,12 +92,11 @@ private:
void storeSettings() const;
void updateFromSettings();
- CompileOutputTextEdit *m_outputWindow;
+ Core::OutputWindow *m_outputWindow;
QHash<unsigned int, QPair<int, int>> m_taskPositions;
ShowOutputTaskHandler *m_handler;
QToolButton *m_cancelBuildButton;
QToolButton * const m_settingsButton;
- Utils::OutputFormatter *m_formatter;
CompileOutputSettings m_settings;
};
diff --git a/src/plugins/projectexplorer/configtaskhandler.cpp b/src/plugins/projectexplorer/configtaskhandler.cpp
index e3c5ed58d5..e7daf060c2 100644
--- a/src/plugins/projectexplorer/configtaskhandler.cpp
+++ b/src/plugins/projectexplorer/configtaskhandler.cpp
@@ -44,7 +44,7 @@ ConfigTaskHandler::ConfigTaskHandler(const Task &pattern, Core::Id page) :
bool ConfigTaskHandler::canHandle(const Task &task) const
{
- return task.description == m_pattern.description
+ return task.description() == m_pattern.description()
&& task.category == m_pattern.category;
}
diff --git a/src/plugins/projectexplorer/copytaskhandler.cpp b/src/plugins/projectexplorer/copytaskhandler.cpp
index 1896eb2f7d..574cad4b90 100644
--- a/src/plugins/projectexplorer/copytaskhandler.cpp
+++ b/src/plugins/projectexplorer/copytaskhandler.cpp
@@ -54,7 +54,7 @@ void CopyTaskHandler::handle(const Task &task)
QApplication::clipboard()->setText(task.file.toUserOutput() + QLatin1Char(':') +
QString::number(task.line) + QLatin1String(": ")
- + type + task.description);
+ + type + task.description());
}
Core::Id CopyTaskHandler::actionManagerId() const
diff --git a/src/plugins/projectexplorer/customparser.cpp b/src/plugins/projectexplorer/customparser.cpp
index afb73b4cbc..03eee63c30 100644
--- a/src/plugins/projectexplorer/customparser.cpp
+++ b/src/plugins/projectexplorer/customparser.cpp
@@ -24,16 +24,42 @@
****************************************************************************/
#include "customparser.h"
-#include "task.h"
+
#include "projectexplorerconstants.h"
-#include "buildmanager.h"
+#include "projectexplorer.h"
+#include "task.h"
+#include <coreplugin/icore.h>
#include <utils/qtcassert.h>
+#include <QCheckBox>
+#include <QLabel>
+#include <QPair>
#include <QString>
+#include <QVBoxLayout>
+
+#ifdef WITH_TESTS
+# include <QTest>
+
+# include "projectexplorer.h"
+# include "outputparser_test.h"
+#endif
using namespace Utils;
-using namespace ProjectExplorer;
+
+const char idKey[] = "Id";
+const char nameKey[] = "Name";
+const char errorKey[] = "Error";
+const char warningKey[] = "Warning";
+const char patternKey[] = "Pattern";
+const char lineNumberCapKey[] = "LineNumberCap";
+const char fileNameCapKey[] = "FileNameCap";
+const char messageCapKey[] = "MessageCap";
+const char channelKey[] = "Channel";
+const char exampleKey[] = "Example";
+
+namespace ProjectExplorer {
+namespace Internal {
bool CustomParserExpression::operator ==(const CustomParserExpression &other) const
{
@@ -47,7 +73,7 @@ QString CustomParserExpression::pattern() const
return m_regExp.pattern();
}
-void ProjectExplorer::CustomParserExpression::setPattern(const QString &pattern)
+void CustomParserExpression::setPattern(const QString &pattern)
{
m_regExp.setPattern(pattern);
QTC_CHECK(m_regExp.isValid());
@@ -60,9 +86,8 @@ CustomParserExpression::CustomParserChannel CustomParserExpression::channel() co
void CustomParserExpression::setChannel(CustomParserExpression::CustomParserChannel channel)
{
- QTC_ASSERT(channel > ParseNoChannel && channel <= ParseBothChannels,
- channel = ParseBothChannels);
-
+ if (channel == ParseNoChannel || channel > ParseBothChannels)
+ channel = ParseBothChannels;
m_channel = channel;
}
@@ -86,6 +111,28 @@ void CustomParserExpression::setMessageCap(int messageCap)
m_messageCap = messageCap;
}
+QVariantMap CustomParserExpression::toMap() const
+{
+ QVariantMap map;
+ map.insert(patternKey, pattern());
+ map.insert(messageCapKey, messageCap());
+ map.insert(fileNameCapKey, fileNameCap());
+ map.insert(lineNumberCapKey, lineNumberCap());
+ map.insert(exampleKey, example());
+ map.insert(channelKey, channel());
+ return map;
+}
+
+void CustomParserExpression::fromMap(const QVariantMap &map)
+{
+ setPattern(map.value(patternKey).toString());
+ setMessageCap(map.value(messageCapKey).toInt());
+ setFileNameCap(map.value(fileNameCapKey).toInt());
+ setLineNumberCap(map.value(lineNumberCapKey).toInt());
+ setExample(map.value(exampleKey).toString());
+ setChannel(static_cast<CustomParserChannel>(map.value(channelKey).toInt()));
+}
+
int CustomParserExpression::lineNumberCap() const
{
return m_lineNumberCap;
@@ -108,35 +155,33 @@ void CustomParserExpression::setFileNameCap(int fileNameCap)
bool CustomParserSettings::operator ==(const CustomParserSettings &other) const
{
- return error == other.error && warning == other.warning;
+ return id == other.id && displayName == other.displayName
+ && error == other.error && warning == other.warning;
}
-CustomParser::CustomParser(const CustomParserSettings &settings)
+QVariantMap CustomParserSettings::toMap() const
{
- setObjectName("CustomParser");
-
- setSettings(settings);
+ QVariantMap map;
+ map.insert(idKey, id.toSetting());
+ map.insert(nameKey, displayName);
+ map.insert(errorKey, error.toMap());
+ map.insert(warningKey, warning.toMap());
+ return map;
}
-void CustomParser::stdError(const QString &line)
+void CustomParserSettings::fromMap(const QVariantMap &map)
{
- if (parseLine(line, CustomParserExpression::ParseStdErrChannel))
- return;
-
- IOutputParser::stdError(line);
+ id = Core::Id::fromSetting(map.value(idKey));
+ displayName = map.value(nameKey).toString();
+ error.fromMap(map.value(errorKey).toMap());
+ warning.fromMap(map.value(warningKey).toMap());
}
-void CustomParser::stdOutput(const QString &line)
+CustomParser::CustomParser(const CustomParserSettings &settings)
{
- if (parseLine(line, CustomParserExpression::ParseStdOutChannel))
- return;
-
- IOutputParser::stdOutput(line);
-}
+ setObjectName("CustomParser");
-void CustomParser::setWorkingDirectory(const QString &workingDirectory)
-{
- m_workingDirectory = workingDirectory;
+ setSettings(settings);
}
void CustomParser::setSettings(const CustomParserSettings &settings)
@@ -145,57 +190,195 @@ void CustomParser::setSettings(const CustomParserSettings &settings)
m_warning = settings.warning;
}
+CustomParser *CustomParser::createFromId(Core::Id id)
+{
+ const Internal::CustomParserSettings parser = findOrDefault(ProjectExplorerPlugin::customParsers(),
+ [id](const Internal::CustomParserSettings &p) { return p.id == id; });
+ if (parser.id.isValid())
+ return new CustomParser(parser);
+ return nullptr;
+}
+
Core::Id CustomParser::id()
{
return Core::Id("ProjectExplorer.OutputParser.Custom");
}
-FilePath CustomParser::absoluteFilePath(const QString &filePath) const
+OutputLineParser::Result CustomParser::handleLine(const QString &line, OutputFormat type)
{
- if (m_workingDirectory.isEmpty())
- return FilePath::fromUserInput(filePath);
-
- return FilePath::fromString(m_workingDirectory).resolvePath(filePath);
+ const CustomParserExpression::CustomParserChannel channel = type == StdErrFormat
+ ? CustomParserExpression::ParseStdErrChannel
+ : CustomParserExpression::ParseStdOutChannel;
+ return parseLine(line, channel);
}
-bool CustomParser::hasMatch(const QString &line, CustomParserExpression::CustomParserChannel channel,
- const CustomParserExpression &expression, Task::TaskType taskType)
+OutputLineParser::Result CustomParser::hasMatch(
+ const QString &line,
+ CustomParserExpression::CustomParserChannel channel,
+ const CustomParserExpression &expression,
+ Task::TaskType taskType
+ )
{
if (!(channel & expression.channel()))
- return false;
+ return Status::NotHandled;
if (expression.pattern().isEmpty())
- return false;
+ return Status::NotHandled;
const QRegularExpressionMatch match = expression.match(line);
if (!match.hasMatch())
- return false;
+ return Status::NotHandled;
- const FilePath fileName = absoluteFilePath(match.captured(expression.fileNameCap()));
+ const FilePath fileName = absoluteFilePath(FilePath::fromString(
+ match.captured(expression.fileNameCap())));
const int lineNumber = match.captured(expression.lineNumberCap()).toInt();
const QString message = match.captured(expression.messageCap());
-
- emit addTask(CompileTask(taskType, message, fileName, lineNumber), 1);
- return true;
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, fileName, lineNumber, match,
+ expression.fileNameCap());
+ scheduleTask(CompileTask(taskType, message, fileName, lineNumber), 1);
+ return {Status::Done, linkSpecs};
}
-bool CustomParser::parseLine(const QString &rawLine, CustomParserExpression::CustomParserChannel channel)
+OutputLineParser::Result CustomParser::parseLine(
+ const QString &rawLine,
+ CustomParserExpression::CustomParserChannel channel
+ )
{
const QString line = rawLine.trimmed();
+ const Result res = hasMatch(line, channel, m_error, Task::Error);
+ if (res.status != Status::NotHandled)
+ return res;
+ return hasMatch(line, channel, m_warning, Task::Warning);
+}
+
+namespace {
+class SelectionWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ SelectionWidget(QWidget *parent = nullptr) : QWidget(parent)
+ {
+ const auto layout = new QVBoxLayout(this);
+ const auto explanatoryLabel = new QLabel(tr(
+ "Custom output parsers scan command line output for user-provided error patterns<br>"
+ "in order to create entries in the issues pane.<br>"
+ "The parsers can be configured <a href=\"dummy\">here</a>."));
+ layout->addWidget(explanatoryLabel);
+ connect(explanatoryLabel, &QLabel::linkActivated, [] {
+ Core::ICore::showOptionsDialog(Constants::CUSTOM_PARSERS_SETTINGS_PAGE_ID);
+ });
+ updateUi();
+ connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::customParsersChanged,
+ this, &SelectionWidget::updateUi);
+ }
+
+ void setSelectedParsers(const QList<Core::Id> &parsers)
+ {
+ for (const auto &p : qAsConst(parserCheckBoxes))
+ p.first->setChecked(parsers.contains(p.second));
+ emit selectionChanged();
+ }
+
+ QList<Core::Id> selectedParsers() const
+ {
+ QList<Core::Id> parsers;
+ for (const auto &p : qAsConst(parserCheckBoxes)) {
+ if (p.first->isChecked())
+ parsers << p.second;
+ }
+ return parsers;
+ }
+
+signals:
+ void selectionChanged();
+
+private:
+ void updateUi()
+ {
+ const auto layout = qobject_cast<QVBoxLayout *>(this->layout());
+ QTC_ASSERT(layout, return);
+ const QList<Core::Id> parsers = selectedParsers();
+ for (const auto &p : qAsConst(parserCheckBoxes))
+ delete p.first;
+ parserCheckBoxes.clear();
+ for (const CustomParserSettings &s : ProjectExplorerPlugin::customParsers()) {
+ const auto checkBox = new QCheckBox(s.displayName, this);
+ connect(checkBox, &QCheckBox::stateChanged,
+ this, &SelectionWidget::selectionChanged);
+ parserCheckBoxes << qMakePair(checkBox, s.id);
+ layout->addWidget(checkBox);
+ }
+ setSelectedParsers(parsers);
+ }
+
+ QList<QPair<QCheckBox *, Core::Id>> parserCheckBoxes;
+};
+} // anonymous namespace
+
+CustomParsersSelectionWidget::CustomParsersSelectionWidget(QWidget *parent) : DetailsWidget(parent)
+{
+ const auto widget = new SelectionWidget(this);
+ connect(widget, &SelectionWidget::selectionChanged, [this] {
+ updateSummary();
+ emit selectionChanged();
+ });
+ setWidget(widget);
+ updateSummary();
+}
- if (hasMatch(line, channel, m_error, Task::Error))
- return true;
+void CustomParsersSelectionWidget::setSelectedParsers(const QList<Core::Id> &parsers)
+{
+ qobject_cast<SelectionWidget *>(widget())->setSelectedParsers(parsers);
+}
- return hasMatch(line, channel, m_warning, Task::Warning);
+QList<Core::Id> CustomParsersSelectionWidget::selectedParsers() const
+{
+ return qobject_cast<SelectionWidget *>(widget())->selectedParsers();
+}
+
+void CustomParsersSelectionWidget::updateSummary()
+{
+ const QList<Core::Id> parsers
+ = qobject_cast<SelectionWidget *>(widget())->selectedParsers();
+ if (parsers.isEmpty())
+ setSummaryText(tr("There are no custom parsers active"));
+ else
+ setSummaryText(tr("There are %n custom parsers active", nullptr, parsers.count()));
}
+CustomParsersAspect::CustomParsersAspect(Target *target)
+{
+ Q_UNUSED(target)
+ setId("CustomOutputParsers");
+ setSettingsKey("CustomOutputParsers");
+ setDisplayName(tr("Custom Output Parsers"));
+ setConfigWidgetCreator([this] {
+ const auto widget = new CustomParsersSelectionWidget;
+ widget->setSelectedParsers(m_parsers);
+ connect(widget, &CustomParsersSelectionWidget::selectionChanged,
+ this, [this, widget] { m_parsers = widget->selectedParsers(); });
+ return widget;
+ });
+}
+
+void CustomParsersAspect::fromMap(const QVariantMap &map)
+{
+ m_parsers = transform(map.value(settingsKey()).toList(), &Core::Id::fromSetting);
+}
+
+void CustomParsersAspect::toMap(QVariantMap &map) const
+{
+ map.insert(settingsKey(), transform(m_parsers, &Core::Id::toSetting));
+}
+
+} // namespace Internal
+
// Unit tests:
#ifdef WITH_TESTS
-# include <QTest>
-# include "projectexplorer.h"
-# include "outputparser_test.h"
+using namespace Internal;
void ProjectExplorerPlugin::testCustomOutputParsers_data()
{
@@ -481,12 +664,18 @@ void ProjectExplorerPlugin::testCustomOutputParsers()
CustomParser *parser = new CustomParser;
parser->setSettings(settings);
- parser->setWorkingDirectory(workDir);
+ parser->addSearchDir(FilePath::fromString(workDir));
+ parser->skipFileExistsCheck();
OutputParserTester testbench;
- testbench.appendOutputParser(parser);
+ testbench.addLineParser(parser);
testbench.testParsing(input, inputChannel,
tasks, childStdOutLines, childStdErrLines,
outputLines);
}
+
#endif
+
+} // namespace ProjectExplorer
+
+#include <customparser.moc>
diff --git a/src/plugins/projectexplorer/customparser.h b/src/plugins/projectexplorer/customparser.h
index dafb0e8da1..48a88096d2 100644
--- a/src/plugins/projectexplorer/customparser.h
+++ b/src/plugins/projectexplorer/customparser.h
@@ -26,12 +26,18 @@
#pragma once
#include "ioutputparser.h"
+#include "projectconfiguration.h"
#include <projectexplorer/task.h>
+#include <utils/detailswidget.h>
#include <QRegularExpression>
+#include <QVariantMap>
namespace ProjectExplorer {
+class Target;
+
+namespace Internal {
class CustomParserExpression
{
@@ -62,6 +68,9 @@ public:
int messageCap() const;
void setMessageCap(int messageCap);
+ QVariantMap toMap() const;
+ void fromMap(const QVariantMap &map);
+
private:
QRegularExpression m_regExp;
CustomParserExpression::CustomParserChannel m_channel = ParseBothChannels;
@@ -77,36 +86,69 @@ public:
bool operator ==(const CustomParserSettings &other) const;
bool operator !=(const CustomParserSettings &other) const { return !operator==(other); }
+ QVariantMap toMap() const;
+ void fromMap(const QVariantMap &map);
+
+ Core::Id id;
+ QString displayName;
CustomParserExpression error;
CustomParserExpression warning;
};
-class CustomParser : public ProjectExplorer::IOutputParser
+class CustomParser : public ProjectExplorer::OutputTaskParser
{
public:
CustomParser(const CustomParserSettings &settings = CustomParserSettings());
- void stdError(const QString &line) override;
- void stdOutput(const QString &line) override;
-
- void setWorkingDirectory(const QString &workingDirectory) override;
-
void setSettings(const CustomParserSettings &settings);
+ static CustomParser *createFromId(Core::Id id);
static Core::Id id();
private:
- Utils::FilePath absoluteFilePath(const QString &filePath) const;
- bool hasMatch(const QString &line, CustomParserExpression::CustomParserChannel channel,
- const CustomParserExpression &expression, Task::TaskType taskType);
- bool parseLine(const QString &rawLine, CustomParserExpression::CustomParserChannel channel);
+ Result handleLine(const QString &line, Utils::OutputFormat type) override;
+
+ Result hasMatch(const QString &line, CustomParserExpression::CustomParserChannel channel,
+ const CustomParserExpression &expression, Task::TaskType taskType);
+ Result parseLine(const QString &rawLine, CustomParserExpression::CustomParserChannel channel);
CustomParserExpression m_error;
CustomParserExpression m_warning;
+};
+
+class CustomParsersSelectionWidget : public Utils::DetailsWidget
+{
+ Q_OBJECT
+public:
+ CustomParsersSelectionWidget(QWidget *parent = nullptr);
+
+ void setSelectedParsers(const QList<Core::Id> &parsers);
+ QList<Core::Id> selectedParsers() const;
+
+signals:
+ void selectionChanged();
+
+private:
+ void updateSummary();
+};
+
+class CustomParsersAspect : public ProjectConfigurationAspect
+{
+ Q_OBJECT
+public:
+ CustomParsersAspect(Target *target);
+
+ void setParsers(const QList<Core::Id> &parsers) { m_parsers = parsers; }
+ const QList<Core::Id> parsers() const { return m_parsers; }
+
+private:
+ void fromMap(const QVariantMap &map) override;
+ void toMap(QVariantMap &map) const override;
- QString m_workingDirectory;
+ QList<Core::Id> m_parsers;
};
+} // namespace Internal
} // namespace ProjectExplorer
-Q_DECLARE_METATYPE(ProjectExplorer::CustomParserExpression::CustomParserChannel);
+Q_DECLARE_METATYPE(ProjectExplorer::Internal::CustomParserExpression::CustomParserChannel);
diff --git a/src/plugins/projectexplorer/customparserconfigdialog.cpp b/src/plugins/projectexplorer/customparserconfigdialog.cpp
index 7e6bb28ee2..5584ae480a 100644
--- a/src/plugins/projectexplorer/customparserconfigdialog.cpp
+++ b/src/plugins/projectexplorer/customparserconfigdialog.cpp
@@ -35,7 +35,7 @@
namespace ProjectExplorer {
namespace Internal {
-CustomParserConfigDialog::CustomParserConfigDialog(QDialog *parent) :
+CustomParserConfigDialog::CustomParserConfigDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::CustomParserConfigDialog)
{
diff --git a/src/plugins/projectexplorer/customparserconfigdialog.h b/src/plugins/projectexplorer/customparserconfigdialog.h
index c34dbfbf4e..fc787a72b6 100644
--- a/src/plugins/projectexplorer/customparserconfigdialog.h
+++ b/src/plugins/projectexplorer/customparserconfigdialog.h
@@ -43,7 +43,7 @@ class CustomParserConfigDialog : public QDialog
Q_OBJECT
public:
- explicit CustomParserConfigDialog(QDialog *parent = nullptr);
+ explicit CustomParserConfigDialog(QWidget *parent = nullptr);
~CustomParserConfigDialog() override;
void setExampleSettings();
diff --git a/src/plugins/projectexplorer/customparserssettingspage.cpp b/src/plugins/projectexplorer/customparserssettingspage.cpp
new file mode 100644
index 0000000000..78163555db
--- /dev/null
+++ b/src/plugins/projectexplorer/customparserssettingspage.cpp
@@ -0,0 +1,144 @@
+/****************************************************************************
+**
+** 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 "customparserssettingspage.h"
+
+#include "customparser.h"
+#include "customparserconfigdialog.h"
+#include "projectexplorer.h"
+#include "projectexplorerconstants.h"
+
+#include <utils/algorithm.h>
+#include <utils/qtcassert.h>
+
+#include <QHBoxLayout>
+#include <QList>
+#include <QListWidget>
+#include <QPushButton>
+#include <QUuid>
+#include <QVBoxLayout>
+
+namespace ProjectExplorer {
+namespace Internal {
+
+class CustomParsersSettingsWidget final : public Core::IOptionsPageWidget
+{
+ Q_DECLARE_TR_FUNCTIONS(ProjectExplorer::Internal::CustomParsersSettingsPage)
+
+public:
+ CustomParsersSettingsWidget()
+ {
+ m_customParsers = ProjectExplorerPlugin::customParsers();
+ resetListView();
+
+ const auto mainLayout = new QVBoxLayout(this);
+ const auto widgetLayout = new QHBoxLayout;
+ mainLayout->addLayout(widgetLayout);
+ widgetLayout->addWidget(&m_parserListView);
+ const auto buttonLayout = new QVBoxLayout;
+ widgetLayout->addLayout(buttonLayout);
+ const auto addButton = new QPushButton(tr("Add..."));
+ const auto removeButton = new QPushButton(tr("Remove"));
+ const auto editButton = new QPushButton("Edit...");
+ buttonLayout->addWidget(addButton);
+ buttonLayout->addWidget(removeButton);
+ buttonLayout->addWidget(editButton);
+ buttonLayout->addStretch(1);
+
+ connect(addButton, &QPushButton::clicked, [this] {
+ CustomParserConfigDialog dlg(this);
+ dlg.setSettings(CustomParserSettings());
+ if (dlg.exec() != QDialog::Accepted)
+ return;
+ CustomParserSettings newParser = dlg.settings();
+ newParser.id = Core::Id::fromString(QUuid::createUuid().toString());
+ newParser.displayName = tr("New Parser");
+ m_customParsers << newParser;
+ resetListView();
+ });
+ connect(removeButton, &QPushButton::clicked, [this] {
+ const QList<QListWidgetItem *> sel = m_parserListView.selectedItems();
+ QTC_ASSERT(sel.size() == 1, return);
+ m_customParsers.removeAt(m_parserListView.row(sel.first()));
+ delete sel.first();
+ });
+ connect(editButton, &QPushButton::clicked, [this] {
+ const QList<QListWidgetItem *> sel = m_parserListView.selectedItems();
+ QTC_ASSERT(sel.size() == 1, return);
+ CustomParserSettings &s = m_customParsers[m_parserListView.row(sel.first())];
+ CustomParserConfigDialog dlg(this);
+ dlg.setSettings(s);
+ if (dlg.exec() != QDialog::Accepted)
+ return;
+ s.error = dlg.settings().error;
+ s.warning = dlg.settings().warning;
+ });
+
+ connect(&m_parserListView, &QListWidget::itemChanged, [this](QListWidgetItem *item) {
+ m_customParsers[m_parserListView.row(item)].displayName = item->text();
+ resetListView();
+ });
+
+ const auto updateButtons = [this, removeButton, editButton] {
+ const bool enable = !m_parserListView.selectedItems().isEmpty();
+ removeButton->setEnabled(enable);
+ editButton->setEnabled(enable);
+ };
+ updateButtons();
+ connect(m_parserListView.selectionModel(), &QItemSelectionModel::selectionChanged,
+ updateButtons);
+ }
+
+private:
+ void apply() override { ProjectExplorerPlugin::setCustomParsers(m_customParsers); }
+
+ void resetListView()
+ {
+ m_parserListView.clear();
+ Utils::sort(m_customParsers,
+ [](const CustomParserSettings &s1, const CustomParserSettings &s2) {
+ return s1.displayName < s2.displayName;
+ });
+ for (const CustomParserSettings &s : qAsConst(m_customParsers)) {
+ const auto item = new QListWidgetItem(s.displayName);
+ item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable);
+ m_parserListView.addItem(item);
+ }
+ }
+
+ QListWidget m_parserListView;
+ QList<CustomParserSettings> m_customParsers;
+};
+
+CustomParsersSettingsPage::CustomParsersSettingsPage()
+{
+ setId(Constants::CUSTOM_PARSERS_SETTINGS_PAGE_ID);
+ setDisplayName(CustomParsersSettingsWidget::tr("Custom Output Parsers"));
+ setCategory(Constants::BUILD_AND_RUN_SETTINGS_CATEGORY);
+ setWidgetCreator([] { return new CustomParsersSettingsWidget; });
+}
+
+} // namespace Internal
+} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/ansifilterparser.h b/src/plugins/projectexplorer/customparserssettingspage.h
index 6e19915a58..7790d947bc 100644
--- a/src/plugins/projectexplorer/ansifilterparser.h
+++ b/src/plugins/projectexplorer/customparserssettingspage.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -25,23 +25,16 @@
#pragma once
-#include "ioutputparser.h"
-
-#include "projectexplorer_export.h"
+#include <coreplugin/dialogs/ioptionspage.h>
namespace ProjectExplorer {
+namespace Internal {
-class PROJECTEXPLORER_EXPORT AnsiFilterParser : public IOutputParser
+class CustomParsersSettingsPage final : public Core::IOptionsPage
{
- Q_OBJECT
-
public:
- AnsiFilterParser();
- void stdOutput(const QString &line) override;
- void stdError(const QString &line) override;
-
-private:
- QString filterLine(const QString &line);
+ CustomParsersSettingsPage();
};
+} // namespace Internal
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/customtoolchain.cpp b/src/plugins/projectexplorer/customtoolchain.cpp
index 654337ab2c..2bada42658 100644
--- a/src/plugins/projectexplorer/customtoolchain.cpp
+++ b/src/plugins/projectexplorer/customtoolchain.cpp
@@ -30,7 +30,7 @@
#include "linuxiccparser.h"
#include "msvcparser.h"
#include "customparser.h"
-#include "customparserconfigdialog.h"
+#include "projectexplorer.h"
#include "projectexplorerconstants.h"
#include "projectmacro.h"
#include "toolchainmanager.h"
@@ -41,12 +41,12 @@
#include <utils/pathchooser.h>
#include <utils/qtcassert.h>
+#include <QComboBox>
#include <QFormLayout>
-#include <QPlainTextEdit>
-#include <QLineEdit>
#include <QHBoxLayout>
-#include <QComboBox>
-#include <QPushButton>
+#include <QLineEdit>
+#include <QPlainTextEdit>
+#include <QUuid>
using namespace Utils;
@@ -64,18 +64,6 @@ static const char headerPathsKeyC[] = "ProjectExplorer.CustomToolChain.HeaderPat
static const char cxx11FlagsKeyC[] = "ProjectExplorer.CustomToolChain.Cxx11Flags";
static const char mkspecsKeyC[] = "ProjectExplorer.CustomToolChain.Mkspecs";
static const char outputParserKeyC[] = "ProjectExplorer.CustomToolChain.OutputParser";
-static const char errorPatternKeyC[] = "ProjectExplorer.CustomToolChain.ErrorPattern";
-static const char errorLineNumberCapKeyC[] = "ProjectExplorer.CustomToolChain.ErrorLineNumberCap";
-static const char errorFileNameCapKeyC[] = "ProjectExplorer.CustomToolChain.ErrorFileNameCap";
-static const char errorMessageCapKeyC[] = "ProjectExplorer.CustomToolChain.ErrorMessageCap";
-static const char errorChannelKeyC[] = "ProjectExplorer.CustomToolChain.ErrorChannel";
-static const char errorExampleKeyC[] = "ProjectExplorer.CustomToolChain.ErrorExample";
-static const char warningPatternKeyC[] = "ProjectExplorer.CustomToolChain.WarningPattern";
-static const char warningLineNumberCapKeyC[] = "ProjectExplorer.CustomToolChain.WarningLineNumberCap";
-static const char warningFileNameCapKeyC[] = "ProjectExplorer.CustomToolChain.WarningFileNameCap";
-static const char warningMessageCapKeyC[] = "ProjectExplorer.CustomToolChain.WarningMessageCap";
-static const char warningChannelKeyC[] = "ProjectExplorer.CustomToolChain.WarningChannel";
-static const char warningExampleKeyC[] = "ProjectExplorer.CustomToolChain.WarningExample";
// --------------------------------------------------------------------------
// CustomToolChain
@@ -85,7 +73,15 @@ CustomToolChain::CustomToolChain() :
ToolChain(Constants::CUSTOM_TOOLCHAIN_TYPEID),
m_outputParserId(GccParser::id())
{
- setTypeDisplayName(Internal::CustomToolChainFactory::tr("Custom"));
+ setTypeDisplayName(tr("Custom"));
+}
+
+Internal::CustomParserSettings CustomToolChain::customParserSettings() const
+{
+ return findOrDefault(ProjectExplorerPlugin::customParsers(),
+ [this](const Internal::CustomParserSettings &s) {
+ return s.id == outputParserId();
+ });
}
Abi CustomToolChain::targetAbi() const
@@ -196,19 +192,18 @@ QStringList CustomToolChain::suggestedMkspecList() const
return m_mkspecs;
}
-IOutputParser *CustomToolChain::outputParser() const
+QList<Utils::OutputLineParser *> CustomToolChain::createOutputParsers() const
{
if (m_outputParserId == GccParser::id())
- return new GccParser;
+ return GccParser::gccParserSuite();
if (m_outputParserId == ClangParser::id())
- return new ClangParser;
+ return ClangParser::clangParserSuite();
if (m_outputParserId == LinuxIccParser::id())
- return new LinuxIccParser;
+ return LinuxIccParser::iccParserSuite();
if (m_outputParserId == MsvcParser::id())
- return new MsvcParser;
- if (m_outputParserId == CustomParser::id())
- return new CustomParser(m_customParserSettings);
- return nullptr;
+ return {new MsvcParser};
+ return {new Internal::CustomParser(customParserSettings())};
+ return {};
}
QStringList CustomToolChain::headerPathsList() const
@@ -293,18 +288,6 @@ QVariantMap CustomToolChain::toMap() const
data.insert(QLatin1String(cxx11FlagsKeyC), m_cxx11Flags);
data.insert(QLatin1String(mkspecsKeyC), mkspecs());
data.insert(QLatin1String(outputParserKeyC), m_outputParserId.toSetting());
- data.insert(QLatin1String(errorPatternKeyC), m_customParserSettings.error.pattern());
- data.insert(QLatin1String(errorFileNameCapKeyC), m_customParserSettings.error.fileNameCap());
- data.insert(QLatin1String(errorLineNumberCapKeyC), m_customParserSettings.error.lineNumberCap());
- data.insert(QLatin1String(errorMessageCapKeyC), m_customParserSettings.error.messageCap());
- data.insert(QLatin1String(errorChannelKeyC), m_customParserSettings.error.channel());
- data.insert(QLatin1String(errorExampleKeyC), m_customParserSettings.error.example());
- data.insert(QLatin1String(warningPatternKeyC), m_customParserSettings.warning.pattern());
- data.insert(QLatin1String(warningFileNameCapKeyC), m_customParserSettings.warning.fileNameCap());
- data.insert(QLatin1String(warningLineNumberCapKeyC), m_customParserSettings.warning.lineNumberCap());
- data.insert(QLatin1String(warningMessageCapKeyC), m_customParserSettings.warning.messageCap());
- data.insert(QLatin1String(warningChannelKeyC), m_customParserSettings.warning.channel());
- data.insert(QLatin1String(warningExampleKeyC), m_customParserSettings.warning.example());
return data;
}
@@ -323,20 +306,48 @@ bool CustomToolChain::fromMap(const QVariantMap &data)
m_cxx11Flags = data.value(QLatin1String(cxx11FlagsKeyC)).toStringList();
setMkspecs(data.value(QLatin1String(mkspecsKeyC)).toString());
setOutputParserId(Core::Id::fromSetting(data.value(QLatin1String(outputParserKeyC))));
- m_customParserSettings.error.setPattern(data.value(QLatin1String(errorPatternKeyC)).toString());
- m_customParserSettings.error.setFileNameCap(data.value(QLatin1String(errorFileNameCapKeyC)).toInt());
- m_customParserSettings.error.setLineNumberCap(data.value(QLatin1String(errorLineNumberCapKeyC)).toInt());
- m_customParserSettings.error.setMessageCap(data.value(QLatin1String(errorMessageCapKeyC)).toInt());
- m_customParserSettings.error.setChannel(
- static_cast<CustomParserExpression::CustomParserChannel>(data.value(QLatin1String(errorChannelKeyC)).toInt()));
- m_customParserSettings.error.setExample(data.value(QLatin1String(errorExampleKeyC)).toString());
- m_customParserSettings.warning.setPattern(data.value(QLatin1String(warningPatternKeyC)).toString());
- m_customParserSettings.warning.setFileNameCap(data.value(QLatin1String(warningFileNameCapKeyC)).toInt());
- m_customParserSettings.warning.setLineNumberCap(data.value(QLatin1String(warningLineNumberCapKeyC)).toInt());
- m_customParserSettings.warning.setMessageCap(data.value(QLatin1String(warningMessageCapKeyC)).toInt());
- m_customParserSettings.warning.setChannel(
- static_cast<CustomParserExpression::CustomParserChannel>(data.value(QLatin1String(warningChannelKeyC)).toInt()));
- m_customParserSettings.warning.setExample(data.value(QLatin1String(warningExampleKeyC)).toString());
+
+ // Restore Pre-4.13 settings.
+ if (outputParserId() == Internal::CustomParser::id()) {
+ Internal::CustomParserSettings customParserSettings;
+ customParserSettings.error.setPattern(
+ data.value("ProjectExplorer.CustomToolChain.ErrorPattern").toString());
+ customParserSettings.error.setFileNameCap(
+ data.value("ProjectExplorer.CustomToolChain.ErrorLineNumberCap").toInt());
+ customParserSettings.error.setLineNumberCap(
+ data.value("ProjectExplorer.CustomToolChain.ErrorFileNameCap").toInt());
+ customParserSettings.error.setMessageCap(
+ data.value("ProjectExplorer.CustomToolChain.ErrorMessageCap").toInt());
+ customParserSettings.error.setChannel(
+ static_cast<Internal::CustomParserExpression::CustomParserChannel>(
+ data.value("ProjectExplorer.CustomToolChain.ErrorChannel").toInt()));
+ customParserSettings.error.setExample(
+ data.value("ProjectExplorer.CustomToolChain.ErrorExample").toString());
+ customParserSettings.warning.setPattern(
+ data.value("ProjectExplorer.CustomToolChain.WarningPattern").toString());
+ customParserSettings.warning.setFileNameCap(
+ data.value("ProjectExplorer.CustomToolChain.WarningLineNumberCap").toInt());
+ customParserSettings.warning.setLineNumberCap(
+ data.value("ProjectExplorer.CustomToolChain.WarningFileNameCap").toInt());
+ customParserSettings.warning.setMessageCap(
+ data.value("ProjectExplorer.CustomToolChain.WarningMessageCap").toInt());
+ customParserSettings.warning.setChannel(
+ static_cast<Internal::CustomParserExpression::CustomParserChannel>(
+ data.value("ProjectExplorer.CustomToolChain.WarningChannel").toInt()));
+ customParserSettings.warning.setExample(
+ data.value("ProjectExplorer.CustomToolChain.WarningExample").toString());
+ if (!customParserSettings.error.pattern().isEmpty()
+ || !customParserSettings.error.pattern().isEmpty()) {
+ // Found custom parser in old settings, move to new place.
+ customParserSettings.id = Core::Id::fromString(QUuid::createUuid().toString());
+ setOutputParserId(customParserSettings.id);
+ customParserSettings.displayName = tr("Parser for toolchain %1").arg(displayName());
+ QList<Internal::CustomParserSettings> settings
+ = ProjectExplorerPlugin::customParsers();
+ settings << customParserSettings;
+ ProjectExplorerPlugin::setCustomParsers(settings);
+ }
+ }
return true;
}
@@ -367,19 +378,6 @@ void CustomToolChain::setOutputParserId(Core::Id parserId)
toolChainUpdated();
}
-CustomParserSettings CustomToolChain::customParserSettings() const
-{
- return m_customParserSettings;
-}
-
-void CustomToolChain::setCustomParserSettings(const CustomParserSettings &settings)
-{
- if (m_customParserSettings == settings)
- return;
- m_customParserSettings = settings;
- toolChainUpdated();
-}
-
QList<CustomToolChain::Parser> CustomToolChain::parsers()
{
QList<CustomToolChain::Parser> result;
@@ -387,8 +385,6 @@ QList<CustomToolChain::Parser> CustomToolChain::parsers()
result.append({ClangParser::id(), tr("Clang")});
result.append({LinuxIccParser::id(), tr("ICC")});
result.append({MsvcParser::id(), tr("MSVC")});
- result.append({CustomParser::id(), tr("Custom")});
-
return result;
}
@@ -405,7 +401,7 @@ namespace Internal {
CustomToolChainFactory::CustomToolChainFactory()
{
- setDisplayName(tr("Custom"));
+ setDisplayName(CustomToolChain::tr("Custom"));
setSupportedToolChainType(Constants::CUSTOM_TOOLCHAIN_TYPEID);
setSupportsAllLanguages(true);
setToolchainConstructor([] { return new CustomToolChain; });
@@ -472,14 +468,15 @@ CustomToolChainConfigWidget::CustomToolChainConfigWidget(CustomToolChain *tc) :
m_headerDetails(new TextEditDetailsWidget(m_headerPaths)),
m_cxx11Flags(new QLineEdit),
m_mkspecs(new QLineEdit),
- m_errorParserComboBox(new QComboBox),
- m_customParserSettingsButton(new QPushButton(tr("Custom Parser Settings...")))
+ m_errorParserComboBox(new QComboBox)
{
Q_ASSERT(tc);
const QList<CustomToolChain::Parser> parsers = CustomToolChain::parsers();
for (const auto &parser : parsers)
m_errorParserComboBox->addItem(parser.displayName, parser.parserId.toString());
+ for (const Internal::CustomParserSettings &s : ProjectExplorerPlugin::customParsers())
+ m_errorParserComboBox->addItem(s.displayName, s.id.toString());
auto parserLayoutWidget = new QWidget;
auto parserLayout = new QHBoxLayout(parserLayoutWidget);
@@ -503,7 +500,6 @@ CustomToolChainConfigWidget::CustomToolChainConfigWidget(CustomToolChain *tc) :
m_mainLayout->addRow(tr("C++11 &flags:"), m_cxx11Flags);
m_mainLayout->addRow(tr("&Qt mkspecs:"), m_mkspecs);
parserLayout->addWidget(m_errorParserComboBox);
- parserLayout->addWidget(m_customParserSettingsButton);
m_mainLayout->addRow(tr("&Error parser:"), parserLayoutWidget);
addErrorLabel();
@@ -522,8 +518,6 @@ CustomToolChainConfigWidget::CustomToolChainConfigWidget(CustomToolChain *tc) :
connect(m_mkspecs, &QLineEdit::textChanged, this, &ToolChainConfigWidget::dirty);
connect(m_errorParserComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &CustomToolChainConfigWidget::errorParserChanged);
- connect(m_customParserSettingsButton, &QAbstractButton::clicked,
- this, &CustomToolChainConfigWidget::openCustomParserSettingsDialog);
errorParserChanged();
}
@@ -538,23 +532,9 @@ void CustomToolChainConfigWidget::updateSummaries()
void CustomToolChainConfigWidget::errorParserChanged(int )
{
- const auto currentId = Core::Id::fromSetting(m_errorParserComboBox->currentData());
- m_customParserSettingsButton->setEnabled(currentId == CustomParser::id());
emit dirty();
}
-void CustomToolChainConfigWidget::openCustomParserSettingsDialog()
-{
- CustomParserConfigDialog dialog;
- dialog.setSettings(m_customParserSettings);
-
- if (dialog.exec() == QDialog::Accepted) {
- m_customParserSettings = dialog.settings();
- if (dialog.isDirty())
- emit dirty();
- }
-}
-
void CustomToolChainConfigWidget::applyImpl()
{
if (toolChain()->isAutoDetected())
@@ -563,8 +543,8 @@ void CustomToolChainConfigWidget::applyImpl()
auto tc = static_cast<CustomToolChain *>(toolChain());
Q_ASSERT(tc);
QString displayName = tc->displayName();
- tc->setCompilerCommand(m_compilerCommand->fileName());
- tc->setMakeCommand(m_makeCommand->fileName());
+ tc->setCompilerCommand(m_compilerCommand->filePath());
+ tc->setMakeCommand(m_makeCommand->filePath());
tc->setTargetAbi(m_abiWidget->currentAbi());
Macros macros = Utils::transform<QVector>(
m_predefinedDetails->text().split('\n', QString::SkipEmptyParts),
@@ -577,7 +557,6 @@ void CustomToolChainConfigWidget::applyImpl()
tc->setMkspecs(m_mkspecs->text());
tc->setDisplayName(displayName); // reset display name
tc->setOutputParserId(Core::Id::fromSetting(m_errorParserComboBox->currentData()));
- tc->setCustomParserSettings(m_customParserSettings);
setFromToolchain(); // Refresh with actual data from the toolchain. This shows what e.g. the
// macro parser did with the input.
@@ -588,8 +567,8 @@ void CustomToolChainConfigWidget::setFromToolchain()
// subwidgets are not yet connected!
QSignalBlocker blocker(this);
auto tc = static_cast<CustomToolChain *>(toolChain());
- m_compilerCommand->setFileName(tc->compilerCommand());
- m_makeCommand->setFileName(tc->makeCommand(Environment()));
+ m_compilerCommand->setFilePath(tc->compilerCommand());
+ m_makeCommand->setFilePath(tc->makeCommand(Environment()));
m_abiWidget->setAbis(Abis(), tc->targetAbi());
const QStringList macroLines = Utils::transform<QList>(tc->rawPredefinedMacros(), [](const Macro &m) {
return QString::fromUtf8(m.toKeyValue(QByteArray()));
@@ -600,22 +579,20 @@ void CustomToolChainConfigWidget::setFromToolchain()
m_mkspecs->setText(tc->mkspecs());
int index = m_errorParserComboBox->findData(tc->outputParserId().toSetting());
m_errorParserComboBox->setCurrentIndex(index);
- m_customParserSettings = tc->customParserSettings();
}
bool CustomToolChainConfigWidget::isDirtyImpl() const
{
auto tc = static_cast<CustomToolChain *>(toolChain());
Q_ASSERT(tc);
- return m_compilerCommand->fileName() != tc->compilerCommand()
- || m_makeCommand->path() != tc->makeCommand(Environment()).toString()
+ return m_compilerCommand->filePath() != tc->compilerCommand()
+ || m_makeCommand->filePath().toString() != tc->makeCommand(Environment()).toString()
|| m_abiWidget->currentAbi() != tc->targetAbi()
|| Macro::toMacros(m_predefinedDetails->text().toUtf8()) != tc->rawPredefinedMacros()
|| m_headerDetails->entries() != tc->headerPathsList()
|| m_cxx11Flags->text().split(QLatin1Char(',')) != tc->cxx11Flags()
|| m_mkspecs->text() != tc->mkspecs()
- || Core::Id::fromSetting(m_errorParserComboBox->currentData()) == tc->outputParserId()
- || m_customParserSettings != tc->customParserSettings();
+ || Core::Id::fromSetting(m_errorParserComboBox->currentData()) == tc->outputParserId();
}
void CustomToolChainConfigWidget::makeReadOnlyImpl()
diff --git a/src/plugins/projectexplorer/customtoolchain.h b/src/plugins/projectexplorer/customtoolchain.h
index c84d0bba1a..382cb3ebca 100644
--- a/src/plugins/projectexplorer/customtoolchain.h
+++ b/src/plugins/projectexplorer/customtoolchain.h
@@ -39,7 +39,6 @@ QT_BEGIN_NAMESPACE
class QPlainTextEdit;
class QTextEdit;
class QComboBox;
-class QPushButton;
QT_END_NAMESPACE
namespace Utils { class PathChooser; }
@@ -84,7 +83,7 @@ public:
const Utils::Environment &env) const override;
void addToEnvironment(Utils::Environment &env) const override;
QStringList suggestedMkspecList() const override;
- IOutputParser *outputParser() const override;
+ QList<Utils::OutputLineParser *> createOutputParsers() const override;
QStringList headerPathsList() const;
void setHeaderPaths(const QStringList &list);
@@ -108,13 +107,13 @@ public:
Core::Id outputParserId() const;
void setOutputParserId(Core::Id parserId);
- CustomParserSettings customParserSettings() const;
- void setCustomParserSettings(const CustomParserSettings &settings);
static QList<CustomToolChain::Parser> parsers();
private:
CustomToolChain();
+ Internal::CustomParserSettings customParserSettings() const;
+
Utils::FilePath m_compilerCommand;
Utils::FilePath m_makeCommand;
@@ -125,7 +124,6 @@ private:
QStringList m_mkspecs;
Core::Id m_outputParserId;
- CustomParserSettings m_customParserSettings;
friend class Internal::CustomToolChainFactory;
friend class ToolChainFactory;
@@ -135,8 +133,6 @@ namespace Internal {
class CustomToolChainFactory : public ToolChainFactory
{
- Q_OBJECT
-
public:
CustomToolChainFactory();
};
@@ -157,7 +153,6 @@ public:
private:
void updateSummaries();
void errorParserChanged(int index = -1);
- void openCustomParserSettingsDialog();
protected:
void applyImpl() override;
@@ -177,9 +172,6 @@ protected:
QLineEdit *m_cxx11Flags;
QLineEdit *m_mkspecs;
QComboBox *m_errorParserComboBox;
- QPushButton *m_customParserSettingsButton;
-
- CustomParserSettings m_customParserSettings;
};
} // namespace Internal
diff --git a/src/plugins/projectexplorer/customwizard/customwizardpage.cpp b/src/plugins/projectexplorer/customwizard/customwizardpage.cpp
index a17a242c73..d171ef05fd 100644
--- a/src/plugins/projectexplorer/customwizard/customwizardpage.cpp
+++ b/src/plugins/projectexplorer/customwizard/customwizardpage.cpp
@@ -42,7 +42,7 @@
#include <QVBoxLayout>
#include <QLineEdit>
#include <QLabel>
-#include <QRegExpValidator>
+#include <QRegularExpressionValidator>
#include <QComboBox>
#include <QTextEdit>
#include <QSpacerItem>
@@ -284,9 +284,9 @@ QWidget *CustomWizardFieldPage::registerLineEdit(const QString &fieldName,
const QString validationRegExp = field.controlAttributes.value(QLatin1String("validator"));
if (!validationRegExp.isEmpty()) {
- QRegExp re(validationRegExp);
+ QRegularExpression re(validationRegExp);
if (re.isValid())
- lineEdit->setValidator(new QRegExpValidator(re, lineEdit));
+ lineEdit->setValidator(new QRegularExpressionValidator(re, lineEdit));
else
qWarning("Invalid custom wizard field validator regular expression %s.", qPrintable(validationRegExp));
}
@@ -360,8 +360,8 @@ void CustomWizardFieldPage::cleanupPage()
PathChooserData &ped = m_pathChoosers[i];
QString defaultText = ped.defaultText;
CustomWizardContext::replaceFields(m_context->baseReplacements, &defaultText);
- if (ped.pathChooser->path() != ped.defaultText)
- ped.userChange = ped.pathChooser->path();
+ if (ped.pathChooser->filePath().toString() != ped.defaultText)
+ ped.userChange = ped.pathChooser->filePath().toString();
else
ped.userChange.clear();
}
@@ -435,7 +435,7 @@ CustomWizardPage::CustomWizardPage(const QSharedPointer<CustomWizardContext> &ct
QString CustomWizardPage::path() const
{
- return m_pathChooser->path();
+ return m_pathChooser->filePath().toString();
}
void CustomWizardPage::setPath(const QString &path)
diff --git a/src/plugins/projectexplorer/deployconfiguration.cpp b/src/plugins/projectexplorer/deployconfiguration.cpp
index f410003646..e5469e9e3b 100644
--- a/src/plugins/projectexplorer/deployconfiguration.cpp
+++ b/src/plugins/projectexplorer/deployconfiguration.cpp
@@ -47,14 +47,6 @@ DeployConfiguration::DeployConfiguration(Target *target, Core::Id id)
m_stepList(this, Constants::BUILDSTEPS_DEPLOY)
{
QTC_CHECK(target && target == this->target());
- Utils::MacroExpander *expander = macroExpander();
- expander->setDisplayName(tr("Deploy Settings"));
- expander->setAccumulating(true);
- expander->registerSubProvider([target] {
- BuildConfiguration *bc = target->activeBuildConfiguration();
- return bc ? bc->macroExpander() : target->macroExpander();
- });
-
//: Default DeployConfiguration display name
setDefaultDisplayName(tr("Deploy locally"));
}
diff --git a/src/plugins/projectexplorer/deploymentdata.cpp b/src/plugins/projectexplorer/deploymentdata.cpp
index 1d9943ae59..4d4aec4a12 100644
--- a/src/plugins/projectexplorer/deploymentdata.cpp
+++ b/src/plugins/projectexplorer/deploymentdata.cpp
@@ -87,11 +87,11 @@ QString DeploymentData::addFilesFromDeploymentFile(const QString &deploymentFile
QString line = deploymentStream.readLine();
if (!line.contains(':'))
continue;
- QStringList file = line.split(':');
- QString sourceFile = file.at(0);
+ int splitPoint = line.lastIndexOf(':');
+ QString sourceFile = line.left(splitPoint);
if (QFileInfo(sourceFile).isRelative())
sourceFile.prepend(sourcePrefix);
- QString targetFile = file.at(1);
+ QString targetFile = line.mid(splitPoint + 1);
if (QFileInfo(targetFile).isRelative())
targetFile.prepend(deploymentPrefix);
addFile(sourceFile, targetFile);
diff --git a/src/plugins/projectexplorer/desktoprunconfiguration.cpp b/src/plugins/projectexplorer/desktoprunconfiguration.cpp
index b30e4b5c8d..75df893db3 100644
--- a/src/plugins/projectexplorer/desktoprunconfiguration.cpp
+++ b/src/plugins/projectexplorer/desktoprunconfiguration.cpp
@@ -196,7 +196,7 @@ const char CMAKE_RUNCONFIG_ID[] = "CMakeProjectManager.CMakeRunConfiguration.";
CMakeRunConfigurationFactory::CMakeRunConfigurationFactory()
{
registerRunConfiguration<CMakeRunConfiguration>(CMAKE_RUNCONFIG_ID);
- addSupportedProjectType(CMakeProjectManager::Constants::CMAKEPROJECT_ID);
+ addSupportedProjectType(CMakeProjectManager::Constants::CMAKE_PROJECT_ID);
addSupportedTargetDeviceType(ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE);
}
diff --git a/src/plugins/projectexplorer/devicesupport/deviceprocessesdialog.cpp b/src/plugins/projectexplorer/devicesupport/deviceprocessesdialog.cpp
index 3734977c4b..bef4f16974 100644
--- a/src/plugins/projectexplorer/devicesupport/deviceprocessesdialog.cpp
+++ b/src/plugins/projectexplorer/devicesupport/deviceprocessesdialog.cpp
@@ -182,10 +182,10 @@ DeviceProcessesDialogPrivate::DeviceProcessesDialogPrivate(KitChooser *chooser,
// line->setFrameShape(QFrame::HLine);
// line->setFrameShadow(QFrame::Sunken);
- proxyModel.setFilterRegExp(processFilterLineEdit->text());
+ proxyModel.setFilterRegularExpression(processFilterLineEdit->text());
connect(processFilterLineEdit, QOverload<const QString &>::of(&FancyLineEdit::textChanged),
- &proxyModel, QOverload<const QString &>::of(&ProcessListFilterModel::setFilterRegExp));
+ &proxyModel, QOverload<const QString &>::of(&ProcessListFilterModel::setFilterRegularExpression));
connect(procView->selectionModel(), &QItemSelectionModel::selectionChanged,
this, &DeviceProcessesDialogPrivate::updateButtons);
connect(updateListButton, &QAbstractButton::clicked,
diff --git a/src/plugins/projectexplorer/devicesupport/sshsettingspage.cpp b/src/plugins/projectexplorer/devicesupport/sshsettingspage.cpp
index 71b64b7458..288a5f9cb4 100644
--- a/src/plugins/projectexplorer/devicesupport/sshsettingspage.cpp
+++ b/src/plugins/projectexplorer/devicesupport/sshsettingspage.cpp
@@ -109,13 +109,13 @@ void SshSettingsWidget::saveSettings()
SshSettings::setConnectionSharingEnabled(m_connectionSharingCheckBox.isChecked());
SshSettings::setConnectionSharingTimeout(m_connectionSharingSpinBox.value());
if (m_sshPathChanged)
- SshSettings::setSshFilePath(m_sshChooser.fileName());
+ SshSettings::setSshFilePath(m_sshChooser.filePath());
if (m_sftpPathChanged)
- SshSettings::setSftpFilePath(m_sftpChooser.fileName());
+ SshSettings::setSftpFilePath(m_sftpChooser.filePath());
if (m_askpassPathChanged)
- SshSettings::setAskpassFilePath(m_askpassChooser.fileName());
+ SshSettings::setAskpassFilePath(m_askpassChooser.filePath());
if (m_keygenPathChanged)
- SshSettings::setKeygenFilePath(m_keygenChooser.fileName());
+ SshSettings::setKeygenFilePath(m_keygenChooser.filePath());
SshSettings::storeSettings(Core::ICore::settings());
}
@@ -157,7 +157,7 @@ void SshSettingsWidget::setupPathChooser(PathChooser &chooser, const FilePath &i
bool &changedFlag)
{
chooser.setExpectedKind(PathChooser::ExistingCommand);
- chooser.setFileName(initialPath);
+ chooser.setFilePath(initialPath);
connect(&chooser, &PathChooser::pathChanged, [&changedFlag] { changedFlag = true; });
}
diff --git a/src/plugins/projectexplorer/environmentwidget.cpp b/src/plugins/projectexplorer/environmentwidget.cpp
index d89adccb45..517e840a95 100644
--- a/src/plugins/projectexplorer/environmentwidget.cpp
+++ b/src/plugins/projectexplorer/environmentwidget.cpp
@@ -36,22 +36,101 @@
#include <utils/hostosinfo.h>
#include <utils/itemviews.h>
#include <utils/namevaluevalidator.h>
+#include <utils/qtcassert.h>
#include <utils/tooltip/tooltip.h>
+#include <QDialogButtonBox>
#include <QDir>
#include <QFileDialog>
#include <QFileInfo>
-#include <QString>
+#include <QHBoxLayout>
+#include <QKeyEvent>
+#include <QLineEdit>
#include <QPushButton>
+#include <QString>
+#include <QStyledItemDelegate>
#include <QTreeView>
+#include <QTreeWidget>
+#include <QTreeWidgetItem>
#include <QVBoxLayout>
-#include <QKeyEvent>
-#include <QStyledItemDelegate>
-#include <QLineEdit>
-#include <QDebug>
namespace ProjectExplorer {
+class PathListDialog : public QDialog
+{
+ Q_DECLARE_TR_FUNCTIONS(EnvironmentWidget)
+public:
+ PathListDialog(const QString &varName, const QString &paths, QWidget *parent) : QDialog(parent)
+ {
+ const auto mainLayout = new QVBoxLayout(this);
+ const auto viewLayout = new QHBoxLayout;
+ const auto buttonsLayout = new QVBoxLayout;
+ const auto addButton = new QPushButton(tr("Add ..."));
+ const auto removeButton = new QPushButton(tr("Remove"));
+ const auto editButton = new QPushButton(tr("Edit..."));
+ buttonsLayout->addWidget(addButton);
+ buttonsLayout->addWidget(removeButton);
+ buttonsLayout->addWidget(editButton);
+ buttonsLayout->addStretch(1);
+ const auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok
+ | QDialogButtonBox::Cancel);
+ viewLayout->addWidget(&m_view);
+ viewLayout->addLayout(buttonsLayout);
+ mainLayout->addLayout(viewLayout);
+ mainLayout->addWidget(buttonBox);
+
+ m_view.setHeaderLabel(varName);
+ const QStringList pathList = paths.split(Utils::HostOsInfo::pathListSeparator(),
+ QString::SkipEmptyParts);
+ for (const QString &path : pathList)
+ addPath(path);
+
+ connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
+ connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
+ connect(addButton, &QPushButton::clicked, this, [this] {
+ const QString dir = QDir::toNativeSeparators(
+ QFileDialog::getExistingDirectory(this, tr("Choose Directory")));
+ if (!dir.isEmpty())
+ addPath(dir);
+ });
+ connect(removeButton, &QPushButton::clicked, this, [this] {
+ const QList<QTreeWidgetItem *> selected = m_view.selectedItems();
+ QTC_ASSERT(selected.count() == 1, return);
+ delete selected.first();
+ });
+ connect(editButton, &QPushButton::clicked, this, [this] {
+ const QList<QTreeWidgetItem *> selected = m_view.selectedItems();
+ QTC_ASSERT(selected.count() == 1, return);
+ m_view.editItem(selected.first(), 0);
+ });
+ const auto updateButtonStates = [this, removeButton, editButton] {
+ const bool hasSelection = !m_view.selectedItems().isEmpty();
+ removeButton->setEnabled(hasSelection);
+ editButton->setEnabled(hasSelection);
+ };
+ connect(m_view.selectionModel(), &QItemSelectionModel::selectionChanged,
+ this, updateButtonStates);
+ updateButtonStates();
+ }
+
+ QString paths() const
+ {
+ QStringList pathList;
+ for (int i = 0; i < m_view.topLevelItemCount(); ++i)
+ pathList << QDir::fromNativeSeparators(m_view.topLevelItem(i)->text(0));
+ return pathList.join(Utils::HostOsInfo::pathListSeparator());
+ }
+
+private:
+ void addPath(const QString &path)
+ {
+ const auto item = new QTreeWidgetItem(&m_view, {QDir::toNativeSeparators(path)});
+ item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable);
+ }
+
+ QTreeWidget m_view;
+};
+
class EnvironmentDelegate : public QStyledItemDelegate
{
public:
@@ -85,7 +164,7 @@ class EnvironmentWidgetPrivate
{
public:
Utils::EnvironmentModel *m_model;
-
+ EnvironmentWidget::Type m_type = EnvironmentWidget::TypeLocal;
QString m_baseEnvironmentText;
EnvironmentWidget::OpenTerminalFunc m_openTerminalFunc;
Utils::DetailsWidget *m_detailsContainer;
@@ -105,6 +184,7 @@ EnvironmentWidget::EnvironmentWidget(QWidget *parent, Type type, QWidget *additi
: QWidget(parent), d(std::make_unique<EnvironmentWidgetPrivate>())
{
d->m_model = new Utils::EnvironmentModel();
+ d->m_type = type;
connect(d->m_model, &Utils::EnvironmentModel::userChangesChanged,
this, &EnvironmentWidget::userChangesChanged);
connect(d->m_model, &QAbstractItemModel::modelReset,
@@ -377,7 +457,15 @@ void EnvironmentWidget::updateButtons()
void EnvironmentWidget::editEnvironmentButtonClicked()
{
- d->m_environmentView->edit(d->m_environmentView->currentIndex());
+ const QModelIndex current = d->m_environmentView->currentIndex();
+ if (current.column() == 1 && d->m_type == TypeLocal && currentEntryIsPathList(current)) {
+ PathListDialog dlg(d->m_model->indexToVariable(current),
+ d->m_model->data(current).toString(), this);
+ if (dlg.exec() == QDialog::Accepted)
+ d->m_model->setData(current, dlg.paths());
+ } else {
+ d->m_environmentView->edit(current);
+ }
}
void EnvironmentWidget::addEnvironmentButtonClicked()
diff --git a/src/plugins/projectexplorer/extracompiler.cpp b/src/plugins/projectexplorer/extracompiler.cpp
index bfb7164550..1a764712ca 100644
--- a/src/plugins/projectexplorer/extracompiler.cpp
+++ b/src/plugins/projectexplorer/extracompiler.cpp
@@ -292,7 +292,7 @@ void ExtraCompilerPrivate::updateIssues()
const auto fontSettings = TextEditor::TextEditorSettings::instance()->fontSettings();
selection.format = fontSettings.toTextCharFormat(issue.type == Task::Warning ?
TextEditor::C_WARNING : TextEditor::C_ERROR);
- selection.format.setToolTip(issue.description);
+ selection.format.setToolTip(issue.description());
selections.append(selection);
}
diff --git a/src/plugins/projectexplorer/gccparser.cpp b/src/plugins/projectexplorer/gccparser.cpp
index 2fc6c4da44..9a55283b97 100644
--- a/src/plugins/projectexplorer/gccparser.cpp
+++ b/src/plugins/projectexplorer/gccparser.cpp
@@ -30,10 +30,10 @@
#include "projectexplorerconstants.h"
#include "buildmanager.h"
-#include <texteditor/fontsettings.h>
-#include <texteditor/texteditorsettings.h>
#include <utils/qtcassert.h>
+#include <numeric>
+
using namespace ProjectExplorer;
using namespace Utils;
@@ -59,27 +59,96 @@ GccParser::GccParser()
// optional .exe postfix
m_regExpGccNames.setPattern(QLatin1String(COMMAND_PATTERN));
QTC_CHECK(m_regExpGccNames.isValid());
+}
+
+Core::Id GccParser::id()
+{
+ return Core::Id("ProjectExplorer.OutputParser.Gcc");
+}
+
+QList<OutputLineParser *> GccParser::gccParserSuite()
+{
+ return {new GccParser, new Internal::LldParser, new LdParser};
+}
+
+void GccParser::createOrAmendTask(
+ Task::TaskType type,
+ const QString &description,
+ const QString &originalLine,
+ bool forceAmend,
+ const FilePath &file,
+ int line,
+ const LinkSpecs &linkSpecs
+ )
+{
+ const bool amend = !m_currentTask.isNull() && (forceAmend || isContinuation(originalLine));
+ if (!amend) {
+ flush();
+ m_currentTask = CompileTask(type, description, file, line);
+ m_currentTask.details.append(originalLine);
+ m_linkSpecs = linkSpecs;
+ m_lines = 1;
+ return;
+ }
+
+ LinkSpecs adaptedLinkSpecs = linkSpecs;
+ const int offset = std::accumulate(m_currentTask.details.cbegin(), m_currentTask.details.cend(),
+ 0, [](int total, const QString &line) { return total + line.length() + 1;});
+ for (LinkSpec &ls : adaptedLinkSpecs)
+ ls.startPos += offset;
+ m_linkSpecs << adaptedLinkSpecs;
+ m_currentTask.details.append(originalLine);
+
+ // Check whether the new line is more relevant than the previous ones.
+ if ((m_currentTask.type != Task::Error && type == Task::Error)
+ || (m_currentTask.type == Task::Unknown && type != Task::Unknown)) {
+ m_currentTask.type = type;
+ m_currentTask.summary = description;
+ if (!file.isEmpty()) {
+ m_currentTask.setFile(file);
+ m_currentTask.line = line;
+ }
+ }
+ ++m_lines;
+}
+
+void GccParser::flush()
+{
+ if (m_currentTask.isNull())
+ return;
- appendOutputParser(new Internal::LldParser);
- appendOutputParser(new LdParser);
+ // If there is only one line of details, then it is the line that we generated
+ // the summary from. Remove it, because it does not add any information.
+ if (m_currentTask.details.count() == 1)
+ m_currentTask.details.clear();
+
+ setDetailsFormat(m_currentTask, m_linkSpecs);
+ Task t = m_currentTask;
+ m_currentTask.clear();
+ m_linkSpecs.clear();
+ scheduleTask(t, m_lines, 1);
+ m_lines = 0;
}
-void GccParser::stdError(const QString &line)
+OutputLineParser::Result GccParser::handleLine(const QString &line, OutputFormat type)
{
- QString lne = rightTrimmed(line);
+ if (type == StdOutFormat) {
+ flush();
+ return Status::NotHandled;
+ }
+
+ const QString lne = rightTrimmed(line);
// Blacklist some lines to not handle them:
if (lne.startsWith(QLatin1String("TeamBuilder ")) ||
lne.startsWith(QLatin1String("distcc["))) {
- IOutputParser::stdError(line);
- return;
+ return Status::NotHandled;
}
// Handle misc issues:
- if (lne.startsWith(QLatin1String("ERROR:")) ||
- lne == QLatin1String("* cpp failed")) {
- newTask(CompileTask(Task::Error, lne /* description */));
- return;
+ if (lne.startsWith(QLatin1String("ERROR:")) || lne == QLatin1String("* cpp failed")) {
+ createOrAmendTask(Task::Error, lne, lne);
+ return Status::InProgress;
}
QRegularExpressionMatch match = m_regExpGccNames.match(lne);
@@ -92,13 +161,22 @@ void GccParser::stdError(const QString &line)
} else if (description.startsWith(QLatin1String("fatal: "))) {
description = description.mid(7);
}
- newTask(CompileTask(type, description));
- return;
+ createOrAmendTask(type, description, lne);
+ return Status::InProgress;
+ }
+
+ match = m_regExpIncluded.match(lne);
+ if (match.hasMatch()) {
+ const FilePath filePath = absoluteFilePath(FilePath::fromUserInput(match.captured(1)));
+ const int lineNo = match.captured(3).toInt();
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, lineNo, match, 1);
+ createOrAmendTask(Task::Unknown, lne.trimmed(), lne, false, filePath, lineNo, linkSpecs);
+ return {Status::InProgress, linkSpecs};
}
match = m_regExp.match(lne);
if (match.hasMatch()) {
- Utils::FilePath filename = Utils::FilePath::fromUserInput(match.captured(1));
int lineno = match.captured(3).toInt();
Task::TaskType type = Task::Unknown;
QString description = match.captured(8);
@@ -113,71 +191,29 @@ void GccParser::stdError(const QString &line)
if (match.captured(5).startsWith(QLatin1Char('#')))
description = match.captured(5) + description;
- newTask(CompileTask(type, description, filename, lineno));
- return;
+ const FilePath filePath = absoluteFilePath(FilePath::fromUserInput(match.captured(1)));
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, lineno, match, 1);
+ createOrAmendTask(type, description, lne, false, filePath, lineno, linkSpecs);
+ return {Status::InProgress, linkSpecs};
}
- match = m_regExpIncluded.match(lne);
- if (match.hasMatch()) {
- newTask(CompileTask(Task::Unknown,
- lne.trimmed() /* description */,
- Utils::FilePath::fromUserInput(match.captured(1)) /* filename */,
- match.captured(3).toInt() /* linenumber */));
- return;
- } else if (lne.startsWith(' ') && !m_currentTask.isNull()) {
- amendDescription(lne, true);
- return;
+ if ((lne.startsWith(' ') && !m_currentTask.isNull()) || isContinuation(lne)) {
+ createOrAmendTask(Task::Unknown, lne, lne, true);
+ return Status::InProgress;
}
- doFlush();
- IOutputParser::stdError(line);
-}
-
-void GccParser::stdOutput(const QString &line)
-{
- doFlush();
- IOutputParser::stdOutput(line);
-}
-
-Core::Id GccParser::id()
-{
- return Core::Id("ProjectExplorer.OutputParser.Gcc");
-}
-
-void GccParser::newTask(const Task &task)
-{
- doFlush();
- m_currentTask = task;
- m_lines = 1;
+ flush();
+ return Status::NotHandled;
}
-void GccParser::doFlush()
+bool GccParser::isContinuation(const QString &newLine) const
{
- if (m_currentTask.isNull())
- return;
- Task t = m_currentTask;
- m_currentTask.clear();
- emit addTask(t, m_lines, 1);
- m_lines = 0;
-}
-
-void GccParser::amendDescription(const QString &desc, bool monospaced)
-{
- if (m_currentTask.isNull())
- return;
- int start = m_currentTask.description.count() + 1;
- m_currentTask.description.append(QLatin1Char('\n'));
- m_currentTask.description.append(desc);
- if (monospaced) {
- QTextLayout::FormatRange fr;
- fr.start = start;
- fr.length = desc.count() + 1;
- fr.format.setFont(TextEditor::TextEditorSettings::fontSettings().font());
- fr.format.setFontStyleHint(QFont::Monospace);
- m_currentTask.formats.append(fr);
- }
- ++m_lines;
- return;
+ return !m_currentTask.isNull()
+ && (m_currentTask.details.last().endsWith(':')
+ || m_currentTask.details.last().endsWith(',')
+ || newLine.contains("within this context")
+ || newLine.contains("note:"));
}
// Unit tests:
@@ -598,22 +634,14 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
"C:/Symbian_SDK/epoc32/include/e32cmn.inl:7094: warning: returning reference to temporary")
<< OutputParserTester::STDERR
<< QString() << QString()
- << (Tasks()
- << CompileTask(Task::Unknown,
- "In file included from C:/Symbian_SDK/epoc32/include/e32cmn.h:6792,",
- FilePath::fromUserInput("C:/Symbian_SDK/epoc32/include/e32cmn.h"),
- 6792)
- << CompileTask(Task::Unknown,
- "from C:/Symbian_SDK/epoc32/include/e32std.h:25,",
- FilePath::fromUserInput("C:/Symbian_SDK/epoc32/include/e32std.h"),
- 25)
- << CompileTask(Task::Unknown,
- "In member function 'SSecureId::operator const TSecureId&() const':",
- FilePath::fromUserInput("C:/Symbian_SDK/epoc32/include/e32cmn.inl"))
- << CompileTask(Task::Warning,
- "returning reference to temporary",
- FilePath::fromUserInput("C:/Symbian_SDK/epoc32/include/e32cmn.inl"),
- 7094))
+ << Tasks{CompileTask(Task::Warning,
+ "returning reference to temporary\n"
+ "In file included from C:/Symbian_SDK/epoc32/include/e32cmn.h:6792,\n"
+ " from C:/Symbian_SDK/epoc32/include/e32std.h:25,\n"
+ "C:/Symbian_SDK/epoc32/include/e32cmn.inl: In member function 'SSecureId::operator const TSecureId&() const':\n"
+ "C:/Symbian_SDK/epoc32/include/e32cmn.inl:7094: warning: returning reference to temporary",
+ FilePath::fromUserInput("C:/Symbian_SDK/epoc32/include/e32cmn.inl"),
+ 7094)}
<< QString();
QTest::newRow("QTCREATORBUG-2206")
@@ -632,19 +660,14 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
"/Symbian/SDK/epoc32/include/variant/Symbian_OS.hrh:1134:26: warning: no newline at end of file")
<< OutputParserTester::STDERR
<< QString() << QString()
- << (Tasks()
- << CompileTask(Task::Unknown,
- "In file included from /Symbian/SDK/EPOC32/INCLUDE/GCCE/GCCE.h:15,",
- FilePath::fromUserInput("/Symbian/SDK/EPOC32/INCLUDE/GCCE/GCCE.h"),
- 15)
- << CompileTask(Task::Unknown,
- "from <command line>:26:",
- FilePath::fromUserInput("<command line>"),
- 26)
- << CompileTask(Task::Warning,
- "no newline at end of file",
- FilePath::fromUserInput("/Symbian/SDK/epoc32/include/variant/Symbian_OS.hrh"),
- 1134))
+ << Tasks{CompileTask(
+ Task::Warning,
+ "no newline at end of file\n"
+ "In file included from /Symbian/SDK/EPOC32/INCLUDE/GCCE/GCCE.h:15,\n"
+ " from <command line>:26:\n"
+ "/Symbian/SDK/epoc32/include/variant/Symbian_OS.hrh:1134:26: warning: no newline at end of file",
+ FilePath::fromUserInput("/Symbian/SDK/epoc32/include/variant/Symbian_OS.hrh"),
+ 1134)}
<< QString();
QTest::newRow("Linker fail (release build)")
@@ -677,15 +700,12 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
"./mw.h:4:0: warning: \"STUPID_DEFINE\" redefined")
<< OutputParserTester::STDERR
<< QString() << QString()
- << (Tasks()
- << CompileTask(Task::Unknown,
- "In file included from <command-line>:0:0:",
- FilePath::fromUserInput("<command-line>"),
- 0)
- << CompileTask(Task::Warning,
- "\"STUPID_DEFINE\" redefined",
- FilePath::fromUserInput("./mw.h"),
- 4))
+ << Tasks{CompileTask(
+ Task::Warning,
+ "\"STUPID_DEFINE\" redefined\n"
+ "In file included from <command-line>:0:0:\n"
+ "./mw.h:4:0: warning: \"STUPID_DEFINE\" redefined",
+ FilePath::fromUserInput("./mw.h"), 4)}
<< QString();
QTest::newRow("instanciation with line:column info")
@@ -745,17 +765,14 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
" ^")
<< OutputParserTester::STDERR
<< QString() << QString()
- << (Tasks()
- << CompileTask(Task::Unknown,
- "In file included from /home/code/src/creator/src/libs/extensionsystem/pluginerrorview.cpp:31:0:",
- FilePath::fromUserInput("/home/code/src/creator/src/libs/extensionsystem/pluginerrorview.cpp"),
- 31)
- << CompileTask(Task::Error,
- "QtGui/QAction: No such file or directory\n"
- " #include <QtGui/QAction>\n"
- " ^",
- FilePath::fromUserInput(".uic/ui_pluginerrorview.h"),
- 14))
+ << Tasks{CompileTask(
+ Task::Error,
+ "QtGui/QAction: No such file or directory\n"
+ "In file included from /home/code/src/creator/src/libs/extensionsystem/pluginerrorview.cpp:31:0:\n"
+ ".uic/ui_pluginerrorview.h:14:25: fatal error: QtGui/QAction: No such file or directory\n"
+ " #include <QtGui/QAction>\n"
+ " ^",
+ FilePath::fromUserInput(".uic/ui_pluginerrorview.h"), 14)}
<< QString();
QTest::newRow("qtcreatorbug-9195")
@@ -766,26 +783,15 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
"main.cpp:7:22: error: within this context")
<< OutputParserTester::STDERR
<< QString() << QString()
- << (Tasks()
- << CompileTask(Task::Unknown,
- "In file included from /usr/include/qt4/QtCore/QString:1:0,",
- FilePath::fromUserInput("/usr/include/qt4/QtCore/QString"),
- 1)
- << CompileTask(Task::Unknown,
- "from main.cpp:3:",
- FilePath::fromUserInput("main.cpp"),
- 3)
- << CompileTask(Task::Unknown,
- "In function 'void foo()':",
- FilePath::fromUserInput("/usr/include/qt4/QtCore/qstring.h"))
- << CompileTask(Task::Error,
- "'QString::QString(const char*)' is private",
- FilePath::fromUserInput("/usr/include/qt4/QtCore/qstring.h"),
- 597)
- << CompileTask(Task::Error,
- "within this context",
- FilePath::fromUserInput("main.cpp"),
- 7))
+ << Tasks{CompileTask(
+ Task::Error,
+ "'QString::QString(const char*)' is private\n"
+ "In file included from /usr/include/qt4/QtCore/QString:1:0,\n"
+ " from main.cpp:3:\n"
+ "/usr/include/qt4/QtCore/qstring.h: In function 'void foo()':\n"
+ "/usr/include/qt4/QtCore/qstring.h:597:5: error: 'QString::QString(const char*)' is private\n"
+ "main.cpp:7:22: error: within this context",
+ FilePath::fromUserInput("/usr/include/qt4/QtCore/qstring.h"), 597)}
<< QString();
QTest::newRow("ld: Multiple definition error")
@@ -1008,8 +1014,7 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
<< (Tasks()
<< CompileTask(Task::Unknown,
"Note: No relevant classes found. No output generated.",
- FilePath::fromUserInput("/home/qtwebkithelpviewer.h"),
- 0))
+ FilePath::fromUserInput("/home/qtwebkithelpviewer.h")))
<< QString();
QTest::newRow("GCC 9 output")
@@ -1051,78 +1056,62 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
)
<< OutputParserTester::STDERR
<< QString() << QString()
- << Tasks({CompileTask(Task::Unknown,
- "In file included from /usr/include/qt/QtCore/qlocale.h:43,",
- FilePath::fromUserInput("/usr/include/qt/QtCore/qlocale.h"), 43),
- CompileTask(Task::Unknown,
- "from /usr/include/qt/QtCore/qtextstream.h:46,",
- FilePath::fromUserInput("/usr/include/qt/QtCore/qtextstream.h"), 46),
- CompileTask(Task::Unknown,
- "from /qtc/src/shared/proparser/proitems.cpp:31:",
- FilePath::fromUserInput("/qtc/src/shared/proparser/proitems.cpp"), 31),
- CompileTask(Task::Unknown,
- "In constructor ‘QVariant::QVariant(QVariant&&)’:",
- FilePath::fromUserInput("/usr/include/qt/QtCore/qvariant.h"), -1),
- CompileTask(Task::Warning,
- "implicitly-declared ‘constexpr QVariant::Private& QVariant::Private::operator=(const QVariant::Private&)’ is deprecated [-Wdeprecated-copy]\n"
- " 273 | { other.d = Private(); }\n"
- " | ^",
- FilePath::fromUserInput("/usr/include/qt/QtCore/qvariant.h"), 273),
- CompileTask(Task::Unknown,
- "because ‘QVariant::Private’ has user-provided ‘QVariant::Private::Private(const QVariant::Private&)’\n"
- " 399 | inline Private(const Private &other) Q_DECL_NOTHROW\n"
- " | ^~~~~~~)",
- FilePath::fromUserInput("/usr/include/qt/QtCore/qvariant.h"), 399),
- CompileTask(Task::Unknown,
- "In function ‘int test(const shape&, const shape&)’:",
- FilePath::fromUserInput("t.cc"), -1),
- CompileTask(Task::Error,
- "no match for ‘operator+’ (operand types are ‘boxed_value<double>’ and ‘boxed_value<double>’)\n"
- " 14 | return (width(s1) * height(s1)\n"
- " | ~~~~~~~~~~~~~~~~~~~~~~\n"
- " | |\n"
- " | boxed_value<[...]>\n"
- " 15 | + width(s2) * height(s2));\n"
- " | ^ ~~~~~~~~~~~~~~~~~~~~~~\n"
- " | |\n"
- " | boxed_value<[...]>",
- FilePath::fromUserInput("t.cc"),
- 15),
+ << Tasks{CompileTask(Task::Warning,
+ "implicitly-declared ‘constexpr QVariant::Private& QVariant::Private::operator=(const QVariant::Private&)’ is deprecated [-Wdeprecated-copy]\n"
+ "In file included from /usr/include/qt/QtCore/qlocale.h:43,\n"
+ " from /usr/include/qt/QtCore/qtextstream.h:46,\n"
+ " from /qtc/src/shared/proparser/proitems.cpp:31:\n"
+ "/usr/include/qt/QtCore/qvariant.h: In constructor ‘QVariant::QVariant(QVariant&&)’:\n"
+ "/usr/include/qt/QtCore/qvariant.h:273:25: warning: implicitly-declared ‘constexpr QVariant::Private& QVariant::Private::operator=(const QVariant::Private&)’ is deprecated [-Wdeprecated-copy]\n"
+ " 273 | { other.d = Private(); }\n"
+ " | ^\n"
+ "/usr/include/qt/QtCore/qvariant.h:399:16: note: because ‘QVariant::Private’ has user-provided ‘QVariant::Private::Private(const QVariant::Private&)’\n"
+ " 399 | inline Private(const Private &other) Q_DECL_NOTHROW\n"
+ " | ^~~~~~~)",
+ FilePath::fromUserInput("/usr/include/qt/QtCore/qvariant.h"), 273),
+ CompileTask(Task::Unknown, "In function ‘int test(const shape&, const shape&)’:", FilePath::fromUserInput("t.cc")), // TODO: should be matched by GccParser, rather than LdParser
+ CompileTask(Task::Error,
+ "no match for ‘operator+’ (operand types are ‘boxed_value<double>’ and ‘boxed_value<double>’)\n"
+ "t.cc:15:4: error: no match for ‘operator+’ (operand types are ‘boxed_value<double>’ and ‘boxed_value<double>’)\n"
+ " 14 | return (width(s1) * height(s1)\n"
+ " | ~~~~~~~~~~~~~~~~~~~~~~\n"
+ " | |\n"
+ " | boxed_value<[...]>\n"
+ " 15 | + width(s2) * height(s2));\n"
+ " | ^ ~~~~~~~~~~~~~~~~~~~~~~\n"
+ " | |\n"
+ " | boxed_value<[...]>",
+ FilePath::fromUserInput("t.cc"),
+ 15),
CompileTask(Task::Error,
"‘string’ in namespace ‘std’ does not name a type\n"
+ "incomplete.c:1:6: error: ‘string’ in namespace ‘std’ does not name a type\n"
" 1 | std::string test(void)\n"
- " | ^~~~~~",
- FilePath::fromUserInput("incomplete.c"),
- 1),
- CompileTask(Task::Unknown,
- "‘std::string’ is defined in header ‘<string>’; did you forget to ‘#include <string>’?\n"
+ " | ^~~~~~\n"
+ "incomplete.c:1:1: note: ‘std::string’ is defined in header ‘<string>’; did you forget to ‘#include <string>’?\n"
" +++ |+#include <string>\n"
" 1 | std::string test(void)",
FilePath::fromUserInput("incomplete.c"),
1),
- CompileTask(Task::Unknown,
- "In function ‘caller’:",
- FilePath::fromUserInput("param-type-mismatch.c"),
- -1),
+ CompileTask(Task::Unknown, "In function ‘caller’:", FilePath::fromUserInput("param-type-mismatch.c")), // TODO: should be matched by GccParser, rather than LdParser
CompileTask(Task::Warning,
"passing argument 2 of ‘callee’ makes pointer from integer without a cast [-Wint-conversion]\n"
+ "param-type-mismatch.c:5:24: warning: passing argument 2 of ‘callee’ makes pointer from integer without a cast [-Wint-conversion]\n"
" 5 | return callee(first, second, third);\n"
" | ^~~~~~\n"
" | |\n"
- " | int",
- FilePath::fromUserInput("param-type-mismatch.c"), 5),
- CompileTask(Task::Unknown,
- "expected ‘const char *’ but argument is of type ‘int’\n"
+ " | int\n"
+ "param-type-mismatch.c:1:40: note: expected ‘const char *’ but argument is of type ‘int’\n"
" 1 | extern int callee(int one, const char *two, float three);\n"
" | ~~~~~~~~~~~~^~~",
- FilePath::fromUserInput("param-type-mismatch.c"), 1)})
+ FilePath::fromUserInput("param-type-mismatch.c"), 5)}
<< QString();
}
void ProjectExplorerPlugin::testGccOutputParsers()
{
OutputParserTester testbench;
- testbench.appendOutputParser(new GccParser);
+ testbench.setLineParsers(GccParser::gccParserSuite());
QFETCH(QString, input);
QFETCH(OutputParserTester::Channel, inputChannel);
QFETCH(Tasks, tasks);
diff --git a/src/plugins/projectexplorer/gccparser.h b/src/plugins/projectexplorer/gccparser.h
index 87381a2bbc..346ddd8ede 100644
--- a/src/plugins/projectexplorer/gccparser.h
+++ b/src/plugins/projectexplorer/gccparser.h
@@ -33,30 +33,40 @@
namespace ProjectExplorer {
-class PROJECTEXPLORER_EXPORT GccParser : public ProjectExplorer::IOutputParser
+class PROJECTEXPLORER_EXPORT GccParser : public ProjectExplorer::OutputTaskParser
{
Q_OBJECT
public:
GccParser();
- void stdError(const QString &line) override;
- void stdOutput(const QString &line) override;
-
static Core::Id id();
-protected:
- void newTask(const Task &task);
- void doFlush() override;
+ static QList<OutputLineParser *> gccParserSuite();
- void amendDescription(const QString &desc, bool monospaced);
+protected:
+ void createOrAmendTask(
+ Task::TaskType type,
+ const QString &description,
+ const QString &originalLine,
+ bool forceAmend = false,
+ const Utils::FilePath &file = {},
+ int line = -1,
+ const LinkSpecs &linkSpecs = {}
+ );
+ void flush() override;
private:
+ Result handleLine(const QString &line, Utils::OutputFormat type) override;
+
+ bool isContinuation(const QString &newLine) const;
+
QRegularExpression m_regExp;
QRegularExpression m_regExpIncluded;
QRegularExpression m_regExpGccNames;
Task m_currentTask;
+ LinkSpecs m_linkSpecs;
int m_lines = 0;
};
diff --git a/src/plugins/projectexplorer/gcctoolchain.cpp b/src/plugins/projectexplorer/gcctoolchain.cpp
index eef0e9ad84..e1dd253be6 100644
--- a/src/plugins/projectexplorer/gcctoolchain.cpp
+++ b/src/plugins/projectexplorer/gcctoolchain.cpp
@@ -265,7 +265,7 @@ static Utils::FilePath gccInstallDir(const FilePath &path, const QStringList &en
GccToolChain::GccToolChain(Core::Id typeId) :
ToolChain(typeId)
{
- setTypeDisplayName(GccToolChainFactory::tr("GCC"));
+ setTypeDisplayName(tr("GCC"));
}
void GccToolChain::setCompilerCommand(const FilePath &path)
@@ -731,9 +731,9 @@ FilePath GccToolChain::makeCommand(const Environment &environment) const
return tmp.isEmpty() ? FilePath::fromString("make") : tmp;
}
-IOutputParser *GccToolChain::outputParser() const
+QList<OutputLineParser *> GccToolChain::createOutputParsers() const
{
- return new GccParser;
+ return GccParser::gccParserSuite();
}
void GccToolChain::resetToolChain(const FilePath &path)
@@ -1045,7 +1045,7 @@ static Utils::FilePaths renesasRl78SearchPathsFromRegistry()
GccToolChainFactory::GccToolChainFactory()
{
- setDisplayName(tr("GCC"));
+ setDisplayName(GccToolChain::tr("GCC"));
setSupportedToolChainType(Constants::GCC_TOOLCHAIN_TYPEID);
setSupportedLanguages({Constants::C_LANGUAGE_ID, Constants::CXX_LANGUAGE_ID});
setToolchainConstructor([] { return new GccToolChain(Constants::GCC_TOOLCHAIN_TYPEID); });
@@ -1274,7 +1274,7 @@ void GccToolChainConfigWidget::applyImpl()
auto tc = static_cast<GccToolChain *>(toolChain());
Q_ASSERT(tc);
QString displayName = tc->displayName();
- tc->setCompilerCommand(m_compilerCommand->fileName());
+ tc->setCompilerCommand(m_compilerCommand->filePath());
if (m_abiWidget) {
tc->setSupportedAbis(m_abiWidget->supportedAbis());
tc->setTargetAbi(m_abiWidget->currentAbi());
@@ -1300,12 +1300,12 @@ void GccToolChainConfigWidget::setFromToolchain()
// subwidgets are not yet connected!
QSignalBlocker blocker(this);
auto tc = static_cast<GccToolChain *>(toolChain());
- m_compilerCommand->setFileName(tc->compilerCommand());
+ m_compilerCommand->setFilePath(tc->compilerCommand());
m_platformCodeGenFlagsLineEdit->setText(QtcProcess::joinArgs(tc->platformCodeGenFlags()));
m_platformLinkerFlagsLineEdit->setText(QtcProcess::joinArgs(tc->platformLinkerFlags()));
if (m_abiWidget) {
m_abiWidget->setAbis(tc->supportedAbis(), tc->targetAbi());
- if (!m_isReadOnly && !m_compilerCommand->path().isEmpty())
+ if (!m_isReadOnly && !m_compilerCommand->filePath().toString().isEmpty())
m_abiWidget->setEnabled(true);
}
}
@@ -1314,7 +1314,7 @@ bool GccToolChainConfigWidget::isDirtyImpl() const
{
auto tc = static_cast<GccToolChain *>(toolChain());
Q_ASSERT(tc);
- return m_compilerCommand->fileName() != tc->compilerCommand()
+ return m_compilerCommand->filePath() != tc->compilerCommand()
|| m_platformCodeGenFlagsLineEdit->text()
!= QtcProcess::joinArgs(tc->platformCodeGenFlags())
|| m_platformLinkerFlagsLineEdit->text()
@@ -1332,22 +1332,6 @@ void GccToolChainConfigWidget::makeReadOnlyImpl()
m_isReadOnly = true;
}
-QStringList GccToolChainConfigWidget::splitString(const QString &s)
-{
- QtcProcess::SplitError splitError;
- const OsType osType = HostOsInfo::hostOs();
- QStringList res = QtcProcess::splitArgs(s, osType, false, &splitError);
- if (splitError != QtcProcess::SplitOk){
- res = QtcProcess::splitArgs(s + '\\', osType, false, &splitError);
- if (splitError != QtcProcess::SplitOk){
- res = QtcProcess::splitArgs(s + '"', osType, false, &splitError);
- if (splitError != QtcProcess::SplitOk)
- res = QtcProcess::splitArgs(s + '\'', osType, false, &splitError);
- }
- }
- return res;
-}
-
void GccToolChainConfigWidget::handleCompilerCommandChange()
{
if (!m_abiWidget)
@@ -1356,7 +1340,7 @@ void GccToolChainConfigWidget::handleCompilerCommandChange()
bool haveCompiler = false;
Abi currentAbi = m_abiWidget->currentAbi();
bool customAbi = m_abiWidget->isCustomAbi() && m_abiWidget->isEnabled();
- FilePath path = m_compilerCommand->fileName();
+ FilePath path = m_compilerCommand->filePath();
Abis abiList;
if (!path.isEmpty()) {
@@ -1472,7 +1456,7 @@ ClangToolChain::ClangToolChain() :
ClangToolChain::ClangToolChain(Core::Id typeId) :
GccToolChain(typeId)
{
- setTypeDisplayName(ClangToolChainFactory::tr("Clang"));
+ setTypeDisplayName(tr("Clang"));
syncAutodetectedWithParentToolchains();
}
@@ -1628,9 +1612,9 @@ LanguageExtensions ClangToolChain::defaultLanguageExtensions() const
return LanguageExtension::Gnu;
}
-IOutputParser *ClangToolChain::outputParser() const
+QList<OutputLineParser *> ClangToolChain::createOutputParsers() const
{
- return new ClangParser;
+ return ClangParser::clangParserSuite();
}
// --------------------------------------------------------------------------
@@ -1639,7 +1623,7 @@ IOutputParser *ClangToolChain::outputParser() const
ClangToolChainFactory::ClangToolChainFactory()
{
- setDisplayName(tr("Clang"));
+ setDisplayName(ClangToolChain::tr("Clang"));
setSupportedToolChainType(Constants::CLANG_TOOLCHAIN_TYPEID);
setSupportedLanguages({Constants::CXX_LANGUAGE_ID, Constants::C_LANGUAGE_ID});
setToolchainConstructor([] { return new ClangToolChain; });
@@ -1798,7 +1782,7 @@ void ClangToolChainConfigWidget::makeReadOnlyImpl()
MingwToolChain::MingwToolChain() :
GccToolChain(Constants::MINGW_TOOLCHAIN_TYPEID)
{
- setTypeDisplayName(MingwToolChainFactory::tr("MinGW"));
+ setTypeDisplayName(MingwToolChain::tr("MinGW"));
}
QStringList MingwToolChain::suggestedMkspecList() const
@@ -1833,7 +1817,7 @@ FilePath MingwToolChain::makeCommand(const Environment &environment) const
MingwToolChainFactory::MingwToolChainFactory()
{
- setDisplayName(tr("MinGW"));
+ setDisplayName(MingwToolChain::tr("MinGW"));
setSupportedToolChainType(Constants::MINGW_TOOLCHAIN_TYPEID);
setSupportedLanguages({Constants::CXX_LANGUAGE_ID, Constants::C_LANGUAGE_ID});
setToolchainConstructor([] { return new MingwToolChain; });
@@ -1873,7 +1857,7 @@ QList<ToolChain *> MingwToolChainFactory::detectForImport(const ToolChainDescrip
LinuxIccToolChain::LinuxIccToolChain() :
GccToolChain(Constants::LINUXICC_TOOLCHAIN_TYPEID)
{
- setTypeDisplayName(LinuxIccToolChainFactory::tr("ICC"));
+ setTypeDisplayName(LinuxIccToolChain::tr("ICC"));
}
/**
@@ -1898,9 +1882,9 @@ LanguageExtensions LinuxIccToolChain::languageExtensions(const QStringList &cxxf
return extensions;
}
-IOutputParser *LinuxIccToolChain::outputParser() const
+QList<OutputLineParser *> LinuxIccToolChain::createOutputParsers() const
{
- return new LinuxIccParser;
+ return LinuxIccParser::iccParserSuite();
}
QStringList LinuxIccToolChain::suggestedMkspecList() const
@@ -1914,7 +1898,7 @@ QStringList LinuxIccToolChain::suggestedMkspecList() const
LinuxIccToolChainFactory::LinuxIccToolChainFactory()
{
- setDisplayName(tr("ICC"));
+ setDisplayName(LinuxIccToolChain::tr("ICC"));
setSupportedToolChainType(Constants::LINUXICC_TOOLCHAIN_TYPEID);
setSupportedLanguages({Constants::CXX_LANGUAGE_ID, Constants::C_LANGUAGE_ID});
setToolchainConstructor([] { return new LinuxIccToolChain; });
diff --git a/src/plugins/projectexplorer/gcctoolchain.h b/src/plugins/projectexplorer/gcctoolchain.h
index 8ecf7aa375..72c693ea2c 100644
--- a/src/plugins/projectexplorer/gcctoolchain.h
+++ b/src/plugins/projectexplorer/gcctoolchain.h
@@ -66,6 +66,8 @@ inline const QStringList gccPredefinedMacrosOptions(Core::Id languageId)
class PROJECTEXPLORER_EXPORT GccToolChain : public ToolChain
{
+ Q_DECLARE_TR_FUNCTIONS(ProjectExplorer::GccToolChain)
+
public:
GccToolChain(Core::Id typeId);
@@ -92,7 +94,7 @@ public:
void addToEnvironment(Utils::Environment &env) const override;
Utils::FilePath makeCommand(const Utils::Environment &environment) const override;
QStringList suggestedMkspecList() const override;
- IOutputParser *outputParser() const override;
+ QList<Utils::OutputLineParser *> createOutputParsers() const override;
QVariantMap toMap() const override;
bool fromMap(const QVariantMap &data) override;
@@ -212,6 +214,8 @@ private:
class PROJECTEXPLORER_EXPORT ClangToolChain : public GccToolChain
{
+ Q_DECLARE_TR_FUNCTIONS(ProjectExplorer::ClangToolChain)
+
public:
ClangToolChain();
explicit ClangToolChain(Core::Id typeId);
@@ -222,7 +226,7 @@ public:
Utils::LanguageExtensions languageExtensions(const QStringList &cxxflags) const override;
Utils::WarningFlags warningFlags(const QStringList &cflags) const override;
- IOutputParser *outputParser() const override;
+ QList<Utils::OutputLineParser *> createOutputParsers() const override;
QStringList suggestedMkspecList() const override;
void addToEnvironment(Utils::Environment &env) const override;
@@ -258,6 +262,8 @@ private:
class PROJECTEXPLORER_EXPORT MingwToolChain : public GccToolChain
{
+ Q_DECLARE_TR_FUNCTIONS(ProjectExplorer::MingwToolChain)
+
public:
Utils::FilePath makeCommand(const Utils::Environment &environment) const override;
@@ -276,9 +282,11 @@ private:
class PROJECTEXPLORER_EXPORT LinuxIccToolChain : public GccToolChain
{
+ Q_DECLARE_TR_FUNCTIONS(ProjectExplorer::LinuxIccToolChain)
+
public:
Utils::LanguageExtensions languageExtensions(const QStringList &cxxflags) const override;
- IOutputParser *outputParser() const override;
+ QList<Utils::OutputLineParser *> createOutputParsers() const override;
QStringList suggestedMkspecList() const override;
diff --git a/src/plugins/projectexplorer/gcctoolchainfactories.h b/src/plugins/projectexplorer/gcctoolchainfactories.h
index c714a5ce16..9708596834 100644
--- a/src/plugins/projectexplorer/gcctoolchainfactories.h
+++ b/src/plugins/projectexplorer/gcctoolchainfactories.h
@@ -49,8 +49,6 @@ namespace Internal {
class GccToolChainFactory : public ToolChainFactory
{
- Q_OBJECT
-
public:
GccToolChainFactory();
@@ -79,7 +77,6 @@ class GccToolChainConfigWidget : public ToolChainConfigWidget
public:
explicit GccToolChainConfigWidget(GccToolChain *tc);
- static QStringList splitString(const QString &s);
protected:
void handleCompilerCommandChange();
@@ -132,8 +129,6 @@ private:
class ClangToolChainFactory : public GccToolChainFactory
{
- Q_OBJECT
-
public:
ClangToolChainFactory();
@@ -147,8 +142,6 @@ public:
class MingwToolChainFactory : public GccToolChainFactory
{
- Q_OBJECT
-
public:
MingwToolChainFactory();
@@ -162,8 +155,6 @@ public:
class LinuxIccToolChainFactory : public GccToolChainFactory
{
- Q_OBJECT
-
public:
LinuxIccToolChainFactory();
diff --git a/src/plugins/projectexplorer/gnumakeparser.cpp b/src/plugins/projectexplorer/gnumakeparser.cpp
index 506f0cfe2d..6bb7442e0c 100644
--- a/src/plugins/projectexplorer/gnumakeparser.cpp
+++ b/src/plugins/projectexplorer/gnumakeparser.cpp
@@ -29,7 +29,7 @@
#include "task.h"
#include <utils/qtcassert.h>
-#include <utils/temporarydirectory.h>
+#include <utils/temporaryfile.h>
#include <QDir>
#include <QFile>
@@ -56,33 +56,6 @@ GnuMakeParser::GnuMakeParser()
QTC_CHECK(m_errorInMakefile.isValid());
}
-void GnuMakeParser::setWorkingDirectory(const QString &workingDirectory)
-{
- addDirectory(workingDirectory);
- IOutputParser::setWorkingDirectory(workingDirectory);
-}
-
-bool GnuMakeParser::hasFatalErrors() const
-{
- return (m_fatalErrorCount > 0) || IOutputParser::hasFatalErrors();
-}
-
-void GnuMakeParser::stdOutput(const QString &line)
-{
- const QString lne = rightTrimmed(line);
-
- QRegularExpressionMatch match = m_makeDir.match(lne);
- if (match.hasMatch()) {
- if (match.captured(6) == QLatin1String("Leaving"))
- removeDirectory(match.captured(7));
- else
- addDirectory(match.captured(7));
- return;
- }
-
- IOutputParser::stdOutput(line);
-}
-
class Result {
public:
Result() = default;
@@ -123,78 +96,57 @@ static Result parseDescription(const QString &description)
return result;
}
-void GnuMakeParser::stdError(const QString &line)
+void GnuMakeParser::emitTask(const ProjectExplorer::Task &task)
{
- const QString lne = rightTrimmed(line);
+ if (task.type == Task::Error) // Assume that all make errors will be follow up errors.
+ m_suppressIssues = true;
+ scheduleTask(task, 1, 0);
+}
+OutputLineParser::Result GnuMakeParser::handleLine(const QString &line, OutputFormat type)
+{
+ const QString lne = rightTrimmed(line);
+ if (type == StdOutFormat) {
+ QRegularExpressionMatch match = m_makeDir.match(lne);
+ if (match.hasMatch()) {
+ if (match.captured(6) == QLatin1String("Leaving"))
+ emit searchDirExpired(FilePath::fromString(match.captured(7)));
+ else
+ emit newSearchDir(FilePath::fromString(match.captured(7)));
+ return Status::Done;
+ }
+ return Status::NotHandled;
+ }
QRegularExpressionMatch match = m_errorInMakefile.match(lne);
if (match.hasMatch()) {
- flush();
- Result res = parseDescription(match.captured(5));
+ ProjectExplorer::Result res = parseDescription(match.captured(5));
if (res.isFatal)
++m_fatalErrorCount;
+ LinkSpecs linkSpecs;
if (!m_suppressIssues) {
- taskAdded(BuildSystemTask(res.type, res.description,
- FilePath::fromUserInput(match.captured(1)) /* filename */,
- match.captured(4).toInt() /* line */),
- 1, 0);
+ const FilePath file = absoluteFilePath(FilePath::fromUserInput(match.captured(1)));
+ const int lineNo = match.captured(4).toInt();
+ addLinkSpecForAbsoluteFilePath(linkSpecs, file, lineNo, match, 1);
+ emitTask(BuildSystemTask(res.type, res.description, file, lineNo));
}
- return;
+ return {Status::Done, linkSpecs};
}
match = m_makeLine.match(lne);
if (match.hasMatch()) {
- flush();
- Result res = parseDescription(match.captured(6));
+ ProjectExplorer::Result res = parseDescription(match.captured(6));
if (res.isFatal)
++m_fatalErrorCount;
if (!m_suppressIssues)
- taskAdded(BuildSystemTask(res.type, res.description), 1, 0);
- return;
+ emitTask(BuildSystemTask(res.type, res.description));
+ return Status::Done;
}
- IOutputParser::stdError(line);
+ return Status::NotHandled;
}
-void GnuMakeParser::addDirectory(const QString &dir)
-{
- if (dir.isEmpty())
- return;
- m_directories.append(dir);
-}
-
-void GnuMakeParser::removeDirectory(const QString &dir)
-{
- m_directories.removeOne(dir);
-}
-
-void GnuMakeParser::taskAdded(const Task &task, int linkedLines, int skippedLines)
+bool GnuMakeParser::hasFatalErrors() const
{
- Task editable(task);
-
- if (task.type == Task::Error) {
- // assume that all make errors will be follow up errors:
- m_suppressIssues = true;
- }
-
- QString filePath(task.file.toString());
-
- if (!filePath.isEmpty() && !QDir::isAbsolutePath(filePath)) {
- QFileInfoList possibleFiles;
- foreach (const QString &dir, m_directories) {
- QFileInfo candidate(dir + QLatin1Char('/') + filePath);
- if (candidate.exists()
- && !possibleFiles.contains(candidate)) {
- possibleFiles << candidate;
- }
- }
- if (possibleFiles.size() == 1)
- editable.file = Utils::FilePath::fromFileInfo(possibleFiles.first());
- // Let the Makestep apply additional heuristics (based on
- // files in ther project) if we cannot uniquely
- // identify the file!
- }
-
- IOutputParser::taskAdded(editable, linkedLines, skippedLines);
+ return m_fatalErrorCount > 0;
}
} // ProjectExplorer
@@ -210,11 +162,6 @@ void GnuMakeParser::taskAdded(const Task &task, int linkedLines, int skippedLine
namespace ProjectExplorer {
-QStringList GnuMakeParser::searchDirectories() const
-{
- return m_directories;
-}
-
GnuMakeParserTester::GnuMakeParserTester(GnuMakeParser *p, QObject *parent) :
QObject(parent),
parser(p)
@@ -410,7 +357,7 @@ void ProjectExplorerPlugin::testGnuMakeParserParsing()
connect(&testbench, &OutputParserTester::aboutToDeleteParser,
tester, &GnuMakeParserTester::parserIsAboutToBeDeleted);
- testbench.appendOutputParser(childParser);
+ testbench.addLineParser(childParser);
QFETCH(QStringList, extraSearchDirs);
QFETCH(QString, input);
QFETCH(OutputParserTester::Channel, inputChannel);
@@ -420,117 +367,52 @@ void ProjectExplorerPlugin::testGnuMakeParserParsing()
QFETCH(QString, outputLines);
QFETCH(QStringList, additionalSearchDirs);
- QStringList searchDirs = childParser->searchDirectories();
+ FilePaths searchDirs = childParser->searchDirectories();
// add extra directories:
foreach (const QString &dir, extraSearchDirs)
- childParser->addDirectory(dir);
+ testbench.addSearchDir(FilePath::fromString(dir));
testbench.testParsing(input, inputChannel,
tasks, childStdOutLines, childStdErrLines,
outputLines);
// make sure we still have all the original dirs
- QStringList newSearchDirs = tester->directories;
- foreach (const QString &dir, searchDirs) {
+ FilePaths newSearchDirs = tester->directories;
+ foreach (const FilePath &dir, searchDirs) {
QVERIFY(newSearchDirs.contains(dir));
newSearchDirs.removeOne(dir);
}
// make sure we have all additional dirs:
foreach (const QString &dir, additionalSearchDirs) {
- QVERIFY(newSearchDirs.contains(dir));
- newSearchDirs.removeOne(dir);
+ const FilePath fp = FilePath::fromString(dir);
+ QVERIFY(newSearchDirs.contains(fp));
+ newSearchDirs.removeOne(fp);
}
// make sure we have no extra cruft:
QVERIFY(newSearchDirs.isEmpty());
delete tester;
}
-void ProjectExplorerPlugin::testGnuMakeParserTaskMangling_data()
-{
- QTest::addColumn<QStringList>("files");
- QTest::addColumn<QStringList>("searchDirectories");
- QTest::addColumn<Task>("inputTask");
- QTest::addColumn<Task>("outputTask");
-
- QTest::newRow("no filename")
- << QStringList()
- << QStringList()
- << Task(CompileTask(Task::Error,
- "no filename, no mangling"))
- << Task(CompileTask(Task::Error,
- "no filename, no mangling"));
-
- QTest::newRow("no mangling")
- << QStringList()
- << QStringList()
- << Task(CompileTask(Task::Error,
- "unknown filename, no mangling",
- FilePath::fromUserInput("some/path/unknown.cpp")))
- << Task(CompileTask(Task::Error,
- "unknown filename, no mangling",
- FilePath::fromUserInput("some/path/unknown.cpp")));
-
- QTest::newRow("find file")
- << QStringList("test/file.cpp")
- << QStringList("test")
- << Task(CompileTask(Task::Error,
- "mangling",
- FilePath::fromUserInput("file.cpp"),
- 10))
- << Task(CompileTask(Task::Error,
- "mangling",
- FilePath::fromUserInput("$TMPDIR/test/file.cpp"),
- 10));
-}
-
void ProjectExplorerPlugin::testGnuMakeParserTaskMangling()
{
+ TemporaryFile theMakeFile("Makefile.XXXXXX");
+ QVERIFY2(theMakeFile.open(), qPrintable(theMakeFile.errorString()));
+ QFileInfo fi(theMakeFile);
+ QVERIFY2(fi.fileName().startsWith("Makefile"), qPrintable(theMakeFile.fileName()));
+
OutputParserTester testbench;
auto *childParser = new GnuMakeParser;
- testbench.appendOutputParser(childParser);
-
- QFETCH(QStringList, files);
- QFETCH(QStringList, searchDirectories);
- QFETCH(Task, inputTask);
- QFETCH(Task, outputTask);
-
- // setup files:
- const QString tempdir
- = Utils::TemporaryDirectory::masterDirectoryPath() + '/' + QUuid::createUuid().toString() + '/';
- QDir filedir(tempdir);
- foreach (const QString &file, files) {
- Q_ASSERT(!file.startsWith('/'));
- Q_ASSERT(!file.contains("../"));
-
- filedir.mkpath(file.left(file.lastIndexOf('/')));
-
- QFile tempfile(tempdir + file);
- if (!tempfile.open(QIODevice::WriteOnly))
- continue;
- tempfile.write("Delete me again!");
- tempfile.close();
- }
-
- // setup search dirs:
- foreach (const QString &dir, searchDirectories) {
- Q_ASSERT(!dir.startsWith(QLatin1Char('/')));
- Q_ASSERT(!dir.contains(QLatin1String("../")));
- childParser->addDirectory(tempdir + dir);
- }
-
- // fix up output task file:
- QString filePath = outputTask.file.toString();
- if (filePath.startsWith(QLatin1String("$TMPDIR/")))
- outputTask.file = Utils::FilePath::fromString(filePath.replace(QLatin1String("$TMPDIR/"), tempdir));
-
- // test mangling:
- testbench.testTaskMangling(inputTask, outputTask);
-
- // clean up:
- foreach (const QString &file, files)
- filedir.rmpath(tempdir + file);
+ testbench.addLineParser(childParser);
+ childParser->addSearchDir(FilePath::fromString(fi.absolutePath()));
+ testbench.testParsing(
+ fi.fileName() + ":360: *** missing separator (did you mean TAB instead of 8 spaces?). Stop.",
+ OutputParserTester::STDERR,
+ {BuildSystemTask(Task::Error,
+ "missing separator (did you mean TAB instead of 8 spaces?). Stop.",
+ FilePath::fromString(theMakeFile.fileName()), 360)},
+ QString(), QString(), QString());
}
} // ProjectExplorer
diff --git a/src/plugins/projectexplorer/gnumakeparser.h b/src/plugins/projectexplorer/gnumakeparser.h
index e509a7881a..21c77213b1 100644
--- a/src/plugins/projectexplorer/gnumakeparser.h
+++ b/src/plugins/projectexplorer/gnumakeparser.h
@@ -32,35 +32,24 @@
namespace ProjectExplorer {
-class PROJECTEXPLORER_EXPORT GnuMakeParser : public ProjectExplorer::IOutputParser
+class PROJECTEXPLORER_EXPORT GnuMakeParser : public ProjectExplorer::OutputTaskParser
{
Q_OBJECT
public:
explicit GnuMakeParser();
- void stdOutput(const QString &line) override;
- void stdError(const QString &line) override;
-
- void setWorkingDirectory(const QString &workingDirectory) override;
-
- QStringList searchDirectories() const;
-
+private:
+ Result handleLine(const QString &line, Utils::OutputFormat type) override;
bool hasFatalErrors() const override;
- void taskAdded(const ProjectExplorer::Task &task, int linkedLines, int skippedLines) override;
-
-private:
- void addDirectory(const QString &dir);
- void removeDirectory(const QString &dir);
+ void emitTask(const ProjectExplorer::Task &task);
QRegularExpression m_makeDir;
QRegularExpression m_makeLine;
QRegularExpression m_threeStarError;
QRegularExpression m_errorInMakefile;
- QStringList m_directories;
-
bool m_suppressIssues = false;
int m_fatalErrorCount = 0;
@@ -79,7 +68,7 @@ public:
explicit GnuMakeParserTester(GnuMakeParser *parser, QObject *parent = nullptr);
void parserIsAboutToBeDeleted();
- QStringList directories;
+ Utils::FilePaths directories;
GnuMakeParser *parser;
};
#endif
diff --git a/src/plugins/qbsprojectmanager/images/groups.png b/src/plugins/projectexplorer/images/fileoverlay_group.png
index 96388c0e22..96388c0e22 100644
--- a/src/plugins/qbsprojectmanager/images/groups.png
+++ b/src/plugins/projectexplorer/images/fileoverlay_group.png
Binary files differ
diff --git a/src/plugins/qbsprojectmanager/images/groups@2x.png b/src/plugins/projectexplorer/images/fileoverlay_group@2x.png
index d03831830f..d03831830f 100644
--- a/src/plugins/qbsprojectmanager/images/groups@2x.png
+++ b/src/plugins/projectexplorer/images/fileoverlay_group@2x.png
Binary files differ
diff --git a/src/plugins/qbsprojectmanager/images/productgear.png b/src/plugins/projectexplorer/images/fileoverlay_product.png
index 42fcf5f44c..42fcf5f44c 100644
--- a/src/plugins/qbsprojectmanager/images/productgear.png
+++ b/src/plugins/projectexplorer/images/fileoverlay_product.png
Binary files differ
diff --git a/src/plugins/qbsprojectmanager/images/productgear@2x.png b/src/plugins/projectexplorer/images/fileoverlay_product@2x.png
index 49d595f9d9..49d595f9d9 100644
--- a/src/plugins/qbsprojectmanager/images/productgear@2x.png
+++ b/src/plugins/projectexplorer/images/fileoverlay_product@2x.png
Binary files differ
diff --git a/src/plugins/projectexplorer/importwidget.cpp b/src/plugins/projectexplorer/importwidget.cpp
index e74d283bbc..b7516b5fd7 100644
--- a/src/plugins/projectexplorer/importwidget.cpp
+++ b/src/plugins/projectexplorer/importwidget.cpp
@@ -80,7 +80,7 @@ ImportWidget::ImportWidget(QWidget *parent) :
void ImportWidget::setCurrentDirectory(const Utils::FilePath &dir)
{
m_pathChooser->setBaseDirectory(dir);
- m_pathChooser->setFileName(dir);
+ m_pathChooser->setFilePath(dir);
}
bool ImportWidget::ownsReturnKey() const
@@ -90,10 +90,10 @@ bool ImportWidget::ownsReturnKey() const
void ImportWidget::handleImportRequest()
{
- Utils::FilePath dir = m_pathChooser->fileName();
+ Utils::FilePath dir = m_pathChooser->filePath();
emit importFrom(dir);
- m_pathChooser->setFileName(m_pathChooser->baseDirectory());
+ m_pathChooser->setFilePath(m_pathChooser->baseDirectory());
}
} // namespace Internal
diff --git a/src/plugins/projectexplorer/ioutputparser.cpp b/src/plugins/projectexplorer/ioutputparser.cpp
index 8dd6d99264..8c6e1c2b33 100644
--- a/src/plugins/projectexplorer/ioutputparser.cpp
+++ b/src/plugins/projectexplorer/ioutputparser.cpp
@@ -24,209 +24,100 @@
****************************************************************************/
#include "ioutputparser.h"
-#include "task.h"
-
-/*!
- \class ProjectExplorer::IOutputParser
-
- \brief The IOutputParser class provides an interface for an output parser
- that emits issues (tasks).
-
- \sa ProjectExplorer::Task
-*/
-
-/*!
- \fn void ProjectExplorer::IOutputParser::appendOutputParser(IOutputParser *parser)
- Appends a subparser to this parser, of which IOutputParser will take
- ownership.
-*/
+#include "task.h"
+#include "taskhub.h"
-/*!
- \fn IOutputParser *ProjectExplorer::IOutputParser::takeOutputParserChain()
+#include <texteditor/fontsettings.h>
+#include <texteditor/texteditorsettings.h>
+#include <utils/ansiescapecodehandler.h>
- Removes the appended outputparser chain from this parser, transferring
- ownership of the parser chain to the caller.
-*/
/*!
- \fn IOutputParser *ProjectExplorer::IOutputParser::childParser() const
+ \class ProjectExplorer::OutputTaskParser
- Returns the head of this parser's output parser children. IOutputParser
- keeps ownership.
-*/
-
-/*!
- \fn void ProjectExplorer::IOutputParser::stdOutput(const QString &line)
+ \brief The OutputTaskParser class provides an interface for an output parser
+ that emits issues (tasks).
- Called once for each line if standard output to parse.
+ \sa ProjectExplorer::Task
*/
/*!
- \fn void ProjectExplorer::IOutputParser::stdError(const QString &line)
+ \fn ProjectExplorer::OutputTaskParser::Status ProjectExplorer::OutputTaskParser::handleLine(const QString &line, Utils::OutputFormat type)
- Called once for each line if standard error to parse.
+ Called once for each line of standard output or standard error to parse.
*/
/*!
- \fn bool ProjectExplorer::IOutputParser::hasFatalErrors() const
+ \fn bool ProjectExplorer::OutputTaskParser::hasFatalErrors() const
This is mainly a Symbian specific quirk.
*/
/*!
- \fn void ProjectExplorer::IOutputParser::addOutput(const QString &string, ProjectExplorer::BuildStep::OutputFormat format)
-
- Should be emitted whenever some additional information should be added to the
- output.
-
- \note This is additional information. There is no need to add each line.
-*/
-
-/*!
- \fn void ProjectExplorer::IOutputParser::addTask(const ProjectExplorer::Task &task)
+ \fn void ProjectExplorer::OutputTaskParser::addTask(const ProjectExplorer::Task &task)
Should be emitted for each task seen in the output.
*/
/*!
- \fn void ProjectExplorer::IOutputParser::outputAdded(const QString &string, ProjectExplorer::BuildStep::OutputFormat format)
-
- Subparsers have their addOutput signal connected to this slot.
-*/
-
-/*!
- \fn void ProjectExplorer::IOutputParser::outputAdded(const QString &string, ProjectExplorer::BuildStep::OutputFormat format)
-
- This function can be overwritten to change the string.
-*/
-
-/*!
- \fn void ProjectExplorer::IOutputParser::taskAdded(const ProjectExplorer::Task &task)
-
- Subparsers have their addTask signal connected to this slot.
- This function can be overwritten to change the task.
-*/
-
-/*!
- \fn void ProjectExplorer::IOutputParser::doFlush()
+ \fn void ProjectExplorer::OutputTaskParser::flush()
Instructs a parser to flush its state.
Parsers may have state (for example, because they need to aggregate several
lines into one task). This
function is called when this state needs to be flushed out to be visible.
-
- doFlush() is called by flush(). flush() is called on child parsers
- whenever a new task is added.
- It is also called once when all input has been parsed.
*/
namespace ProjectExplorer {
-IOutputParser::~IOutputParser()
-{
- delete m_parser;
-}
-
-void IOutputParser::appendOutputParser(IOutputParser *parser)
-{
- if (!parser)
- return;
- if (m_parser) {
- m_parser->appendOutputParser(parser);
- return;
- }
-
- m_parser = parser;
- connect(parser, &IOutputParser::addOutput,
- this, &IOutputParser::outputAdded, Qt::DirectConnection);
- connect(parser, &IOutputParser::addTask,
- this, &IOutputParser::taskAdded, Qt::DirectConnection);
-}
-
-IOutputParser *IOutputParser::takeOutputParserChain()
+class OutputTaskParser::Private
{
- IOutputParser *parser = m_parser;
- disconnect(parser, &IOutputParser::addOutput, this, &IOutputParser::outputAdded);
- disconnect(parser, &IOutputParser::addTask, this, &IOutputParser::taskAdded);
- m_parser = nullptr;
- return parser;
-}
+public:
+ QList<TaskInfo> scheduledTasks;
+};
-IOutputParser *IOutputParser::childParser() const
-{
- return m_parser;
-}
+OutputTaskParser::OutputTaskParser() : d(new Private) { }
-void IOutputParser::setChildParser(IOutputParser *parser)
-{
- if (m_parser != parser)
- delete m_parser;
- m_parser = parser;
- if (parser) {
- connect(parser, &IOutputParser::addOutput,
- this, &IOutputParser::outputAdded, Qt::DirectConnection);
- connect(parser, &IOutputParser::addTask,
- this, &IOutputParser::taskAdded, Qt::DirectConnection);
- }
-}
+OutputTaskParser::~OutputTaskParser() { delete d; }
-void IOutputParser::stdOutput(const QString &line)
+const QList<OutputTaskParser::TaskInfo> OutputTaskParser::taskInfo() const
{
- if (m_parser)
- m_parser->stdOutput(line);
+ return d->scheduledTasks;
}
-void IOutputParser::stdError(const QString &line)
+void OutputTaskParser::scheduleTask(const Task &task, int outputLines, int skippedLines)
{
- if (m_parser)
- m_parser->stdError(line);
+ TaskInfo ts(task, outputLines, skippedLines);
+ if (ts.task.type == Task::Error && demoteErrorsToWarnings())
+ ts.task.type = Task::Warning;
+ d->scheduledTasks << ts;
+ QTC_CHECK(d->scheduledTasks.size() <= 2);
}
-void IOutputParser::outputAdded(const QString &string, BuildStep::OutputFormat format)
+void OutputTaskParser::setDetailsFormat(Task &task, const LinkSpecs &linkSpecs)
{
- emit addOutput(string, format);
-}
-
-void IOutputParser::taskAdded(const Task &task, int linkedOutputLines, int skipLines)
-{
- emit addTask(task, linkedOutputLines, skipLines);
-}
-
-void IOutputParser::doFlush()
-{ }
-
-bool IOutputParser::hasFatalErrors() const
-{
- return m_parser && m_parser->hasFatalErrors();
-}
-
-void IOutputParser::setWorkingDirectory(const QString &workingDirectory)
-{
- if (m_parser)
- m_parser->setWorkingDirectory(workingDirectory);
-}
-
-void IOutputParser::setWorkingDirectory(const Utils::FilePath &fn)
-{
- setWorkingDirectory(fn.toString());
-}
+ if (task.details.isEmpty())
+ return;
-void IOutputParser::flush()
-{
- doFlush();
- if (m_parser)
- m_parser->flush();
+ Utils::FormattedText monospacedText(task.details.join('\n'));
+ monospacedText.format.setFont(TextEditor::TextEditorSettings::fontSettings().font());
+ monospacedText.format.setFontStyleHint(QFont::Monospace);
+ const QList<Utils::FormattedText> linkifiedText =
+ Utils::OutputFormatter::linkifiedText({monospacedText}, linkSpecs);
+ task.formats.clear();
+ int offset = task.summary.length() + 1;
+ for (const Utils::FormattedText &ft : linkifiedText) {
+ task.formats << QTextLayout::FormatRange{offset, ft.text.length(), ft.format};
+ offset += ft.text.length();
+ }
}
-QString IOutputParser::rightTrimmed(const QString &in)
+void OutputTaskParser::runPostPrintActions()
{
- int pos = in.length();
- for (; pos > 0; --pos) {
- if (!in.at(pos - 1).isSpace())
- break;
- }
- return in.mid(0, pos);
+ for (const TaskInfo &t : qAsConst(d->scheduledTasks))
+ TaskHub::addTask(t.task);
+ d->scheduledTasks.clear();
}
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/ioutputparser.h b/src/plugins/projectexplorer/ioutputparser.h
index 1872461cbb..b4fb8ab73c 100644
--- a/src/plugins/projectexplorer/ioutputparser.h
+++ b/src/plugins/projectexplorer/ioutputparser.h
@@ -28,49 +28,39 @@
#include "projectexplorer_export.h"
#include "buildstep.h"
-#include <QString>
+#include <utils/outputformatter.h>
+
+#include <functional>
namespace ProjectExplorer {
class Task;
-// Documentation inside.
-class PROJECTEXPLORER_EXPORT IOutputParser : public QObject
+class PROJECTEXPLORER_EXPORT OutputTaskParser : public Utils::OutputLineParser
{
Q_OBJECT
public:
- IOutputParser() = default;
- ~IOutputParser() override;
-
- virtual void appendOutputParser(IOutputParser *parser);
-
- IOutputParser *takeOutputParserChain();
-
- IOutputParser *childParser() const;
- void setChildParser(IOutputParser *parser);
-
- virtual void stdOutput(const QString &line);
- virtual void stdError(const QString &line);
-
- virtual bool hasFatalErrors() const;
- virtual void setWorkingDirectory(const QString &workingDirectory);
- void setWorkingDirectory(const Utils::FilePath &fn);
-
- void flush(); // flush out pending tasks
-
- static QString rightTrimmed(const QString &in);
-
-signals:
- void addOutput(const QString &string, ProjectExplorer::BuildStep::OutputFormat format);
- void addTask(const ProjectExplorer::Task &task, int linkedOutputLines = 0, int skipLines = 0);
-
-public slots:
- virtual void outputAdded(const QString &string, ProjectExplorer::BuildStep::OutputFormat format);
- virtual void taskAdded(const ProjectExplorer::Task &task, int linkedOutputLines = 0, int skipLines = 0);
+ OutputTaskParser();
+ ~OutputTaskParser() override;
+
+ class TaskInfo
+ {
+ public:
+ TaskInfo(const Task &t, int l, int s) : task(t), linkedLines(l), skippedLines(s) {}
+ Task task;
+ int linkedLines = 0;
+ int skippedLines = 0;
+ };
+ const QList<TaskInfo> taskInfo() const;
+
+protected:
+ void scheduleTask(const Task &task, int outputLines, int skippedLines = 0);
+ void setDetailsFormat(Task &task, const LinkSpecs &linkSpecs = {});
private:
- virtual void doFlush();
+ void runPostPrintActions() override;
- IOutputParser *m_parser = nullptr;
+ class Private;
+ Private * const d;
};
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp b/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp
index dad78b5aa0..6a7ecbbcd6 100644
--- a/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp
+++ b/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp
@@ -493,7 +493,7 @@ bool LineEditField::parseData(const QVariant &data, QString *errorMessage)
m_disabledText = JsonWizardFactory::localizedString(consumeValue(tmp, "trDisabledText").toString());
m_placeholderText = JsonWizardFactory::localizedString(consumeValue(tmp, "trPlaceholder").toString());
m_historyId = consumeValue(tmp, "historyId").toString();
- m_restoreLastHistoryItem = consumeValue(tmp, "restoreLastHistoyItem", false).toBool();
+ m_restoreLastHistoryItem = consumeValue(tmp, "restoreLastHistoryItem", false).toBool();
QString pattern = consumeValue(tmp, "validator").toString();
if (!pattern.isEmpty()) {
m_validatorRegExp = QRegularExpression(pattern);
@@ -737,7 +737,7 @@ QWidget *PathChooserField::createWidget(const QString &displayName, JsonFieldPag
if (!m_historyId.isEmpty())
w->setHistoryCompleter(m_historyId);
QObject::connect(w, &PathChooser::pathChanged, [this, w] {
- if (w->path() != m_path)
+ if (w->filePath().toString() != m_path)
setHasUserChanges();
});
return w;
@@ -789,7 +789,7 @@ void PathChooserField::fromSettings(const QVariant &value)
QVariant PathChooserField::toSettings() const
{
- return qobject_cast<PathChooser *>(widget())->path();
+ return qobject_cast<PathChooser *>(widget())->filePath().toString();
}
// --------------------------------------------------------------------
diff --git a/src/plugins/projectexplorer/jsonwizard/jsonfilepage.cpp b/src/plugins/projectexplorer/jsonwizard/jsonfilepage.cpp
index 865ee82865..19615f929a 100644
--- a/src/plugins/projectexplorer/jsonwizard/jsonfilepage.cpp
+++ b/src/plugins/projectexplorer/jsonwizard/jsonfilepage.cpp
@@ -45,6 +45,7 @@ void JsonFilePage::initializePage()
setFileName(wiz->stringValue(QLatin1String("InitialFileName")));
if (path().isEmpty())
setPath(wiz->stringValue(QLatin1String("InitialPath")));
+ setDefaultSuffix(wiz->stringValue("DefaultSuffix"));
}
bool JsonFilePage::validatePage()
diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp
index 7684de0795..bf87834680 100644
--- a/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp
+++ b/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp
@@ -33,6 +33,7 @@
#include "../projectexplorerconstants.h"
#include "../projecttree.h"
#include <coreplugin/editormanager/editormanager.h>
+#include <coreplugin/editormanager/ieditor.h>
#include <coreplugin/messagemanager.h>
#include <utils/algorithm.h>
@@ -465,11 +466,14 @@ void JsonWizard::openFiles(const JsonWizard::GeneratorFiles &files)
openedSomething = true;
}
if (file.attributes() & Core::GeneratedFile::OpenEditorAttribute) {
- if (!Core::EditorManager::openEditor(file.path(), file.editorId())) {
+ Core::IEditor *editor = Core::EditorManager::openEditor(file.path(), file.editorId());
+ if (!editor) {
errorMessage = QCoreApplication::translate("ProjectExplorer::JsonWizard",
"Failed to open an editor for \"%1\".")
.arg(QDir::toNativeSeparators(file.path()));
break;
+ } else if (file.attributes() & Core::GeneratedFile::TemporaryFile) {
+ editor->document()->setTemporary(true);
}
openedSomething = true;
}
diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardfilegenerator.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizardfilegenerator.cpp
index 117369e10b..173e7a4b0d 100644
--- a/src/plugins/projectexplorer/jsonwizard/jsonwizardfilegenerator.cpp
+++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardfilegenerator.cpp
@@ -69,6 +69,7 @@ bool JsonWizardFileGenerator::setup(const QVariant &data, QString *errorMessage)
f.isBinary = tmp.value(QLatin1String("isBinary"), false);
f.overwrite = tmp.value(QLatin1String("overwrite"), false);
f.openInEditor = tmp.value(QLatin1String("openInEditor"), false);
+ f.isTemporary = tmp.value(QLatin1String("temporary"), false);
f.openAsProject = tmp.value(QLatin1String("openAsProject"), false);
f.options = JsonWizard::parseOptions(tmp.value(QLatin1String("options")), errorMessage);
@@ -148,6 +149,8 @@ Core::GeneratedFile JsonWizardFileGenerator::generateFile(const File &file,
attributes |= Core::GeneratedFile::OpenProjectAttribute;
if (JsonWizard::boolFromVariant(file.overwrite, expander))
attributes |= Core::GeneratedFile::ForceOverwrite;
+ if (JsonWizard::boolFromVariant(file.isTemporary, expander))
+ attributes |= Core::GeneratedFile::TemporaryFile;
if (file.keepExisting)
attributes |= Core::GeneratedFile::KeepExistingFileAttribute;
diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardfilegenerator.h b/src/plugins/projectexplorer/jsonwizard/jsonwizardfilegenerator.h
index 52bee65d6e..3606e43c31 100644
--- a/src/plugins/projectexplorer/jsonwizard/jsonwizardfilegenerator.h
+++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardfilegenerator.h
@@ -55,6 +55,7 @@ private:
QVariant overwrite = false;
QVariant openInEditor = false;
QVariant openAsProject = false;
+ QVariant isTemporary = false;
QList<JsonWizard::OptionDefinition> options;
};
diff --git a/src/plugins/projectexplorer/kit.cpp b/src/plugins/projectexplorer/kit.cpp
index 75f52ec1c8..e8ff3cab48 100644
--- a/src/plugins/projectexplorer/kit.cpp
+++ b/src/plugins/projectexplorer/kit.cpp
@@ -559,12 +559,12 @@ void Kit::addToEnvironment(Environment &env) const
aspect->addToEnvironment(this, env);
}
-IOutputParser *Kit::createOutputParser() const
+QList<OutputLineParser *> Kit::createOutputParsers() const
{
- auto first = new OsParser;
+ QList<OutputLineParser *> parsers{new OsParser};
for (KitAspect *aspect : KitManager::kitAspects())
- first->appendOutputParser(aspect->createOutputParser(this));
- return first;
+ parsers << aspect->createOutputParsers(this);
+ return parsers;
}
QString Kit::toHtml(const Tasks &additional, const QString &extraText) const
diff --git a/src/plugins/projectexplorer/kit.h b/src/plugins/projectexplorer/kit.h
index fe76b750dc..871e226568 100644
--- a/src/plugins/projectexplorer/kit.h
+++ b/src/plugins/projectexplorer/kit.h
@@ -38,10 +38,10 @@
namespace Utils {
class Environment;
class MacroExpander;
+class OutputLineParser;
} // namespace Utils
namespace ProjectExplorer {
-class IOutputParser;
namespace Internal {
class KitManagerPrivate;
@@ -116,7 +116,7 @@ public:
bool isEqual(const Kit *other) const;
void addToEnvironment(Utils::Environment &env) const;
- IOutputParser *createOutputParser() const;
+ QList<Utils::OutputLineParser *> createOutputParsers() const;
QString toHtml(const Tasks &additional = Tasks(), const QString &extraText = QString()) const;
Kit *clone(bool keepName = false) const;
diff --git a/src/plugins/projectexplorer/kitinformation.cpp b/src/plugins/projectexplorer/kitinformation.cpp
index 69383652c8..6dd4d8fae2 100644
--- a/src/plugins/projectexplorer/kitinformation.cpp
+++ b/src/plugins/projectexplorer/kitinformation.cpp
@@ -77,7 +77,7 @@ public:
m_chooser = new Utils::PathChooser;
m_chooser->setExpectedKind(Utils::PathChooser::ExistingDirectory);
m_chooser->setHistoryCompleter(QLatin1String("PE.SysRoot.History"));
- m_chooser->setFileName(SysRootKitAspect::sysRoot(k));
+ m_chooser->setFilePath(SysRootKitAspect::sysRoot(k));
connect(m_chooser, &Utils::PathChooser::pathChanged,
this, &SysRootKitAspectWidget::pathWasChanged);
}
@@ -92,13 +92,13 @@ private:
void refresh() override
{
if (!m_ignoreChange)
- m_chooser->setFileName(SysRootKitAspect::sysRoot(m_kit));
+ m_chooser->setFilePath(SysRootKitAspect::sysRoot(m_kit));
}
void pathWasChanged()
{
m_ignoreChange = true;
- SysRootKitAspect::setSysRoot(m_kit, m_chooser->fileName());
+ SysRootKitAspect::setSysRoot(m_kit, m_chooser->filePath());
m_ignoreChange = false;
}
@@ -511,19 +511,19 @@ KitAspectWidget *ToolChainKitAspect::createConfigWidget(Kit *k) const
QString ToolChainKitAspect::displayNamePostfix(const Kit *k) const
{
- ToolChain *tc = toolChain(k, Constants::CXX_LANGUAGE_ID);
+ ToolChain *tc = cxxToolChain(k);
return tc ? tc->displayName() : QString();
}
KitAspect::ItemList ToolChainKitAspect::toUserOutput(const Kit *k) const
{
- ToolChain *tc = toolChain(k, Constants::CXX_LANGUAGE_ID);
+ ToolChain *tc = cxxToolChain(k);
return {{tr("Compiler"), tc ? tc->displayName() : tr("None")}};
}
void ToolChainKitAspect::addToEnvironment(const Kit *k, Utils::Environment &env) const
{
- ToolChain *tc = toolChain(k, Constants::CXX_LANGUAGE_ID);
+ ToolChain *tc = cxxToolChain(k);
if (tc)
tc->addToEnvironment(env);
}
@@ -534,37 +534,36 @@ void ToolChainKitAspect::addToMacroExpander(Kit *kit, Utils::MacroExpander *expa
// Compatibility with Qt Creator < 4.2:
expander->registerVariable("Compiler:Name", tr("Compiler"),
- [kit]() -> QString {
- const ToolChain *tc = toolChain(kit, Constants::CXX_LANGUAGE_ID);
+ [kit] {
+ const ToolChain *tc = cxxToolChain(kit);
return tc ? tc->displayName() : tr("None");
});
expander->registerVariable("Compiler:Executable", tr("Path to the compiler executable"),
- [kit]() -> QString {
- const ToolChain *tc = toolChain(kit, Constants::CXX_LANGUAGE_ID);
+ [kit] {
+ const ToolChain *tc = cxxToolChain(kit);
return tc ? tc->compilerCommand().toString() : QString();
});
expander->registerPrefix("Compiler:Name", tr("Compiler for different languages"),
- [kit](const QString &ls) -> QString {
+ [kit](const QString &ls) {
const ToolChain *tc = toolChain(kit, findLanguage(ls));
return tc ? tc->displayName() : tr("None");
});
expander->registerPrefix("Compiler:Executable", tr("Compiler executable for different languages"),
- [kit](const QString &ls) -> QString {
+ [kit](const QString &ls) {
const ToolChain *tc = toolChain(kit, findLanguage(ls));
return tc ? tc->compilerCommand().toString() : QString();
});
}
-
-IOutputParser *ToolChainKitAspect::createOutputParser(const Kit *k) const
+QList<Utils::OutputLineParser *> ToolChainKitAspect::createOutputParsers(const Kit *k) const
{
for (const Core::Id langId : {Constants::CXX_LANGUAGE_ID, Constants::C_LANGUAGE_ID}) {
if (const ToolChain * const tc = toolChain(k, langId))
- return tc->outputParser();
+ return tc->createOutputParsers();
}
- return nullptr;
+ return {};
}
QSet<Core::Id> ToolChainKitAspect::availableFeatures(const Kit *k) const
@@ -594,6 +593,17 @@ ToolChain *ToolChainKitAspect::toolChain(const Kit *k, Core::Id language)
return ToolChainManager::findToolChain(toolChainId(k, language));
}
+ToolChain *ToolChainKitAspect::cToolChain(const Kit *k)
+{
+ return ToolChainManager::findToolChain(toolChainId(k, ProjectExplorer::Constants::C_LANGUAGE_ID));
+}
+
+ToolChain *ToolChainKitAspect::cxxToolChain(const Kit *k)
+{
+ return ToolChainManager::findToolChain(toolChainId(k, ProjectExplorer::Constants::CXX_LANGUAGE_ID));
+}
+
+
QList<ToolChain *> ToolChainKitAspect::toolChains(const Kit *k)
{
QTC_ASSERT(k, return QList<ToolChain *>());
@@ -929,7 +939,6 @@ private:
DeviceKitAspect::setDeviceId(m_kit, m_model->deviceId(m_comboBox->currentIndex()));
}
- bool m_isReadOnly = false;
bool m_ignoreChange = false;
QComboBox *m_comboBox;
QPushButton *m_manageButton;
diff --git a/src/plugins/projectexplorer/kitinformation.h b/src/plugins/projectexplorer/kitinformation.h
index 1df90adb53..d8558b8861 100644
--- a/src/plugins/projectexplorer/kitinformation.h
+++ b/src/plugins/projectexplorer/kitinformation.h
@@ -35,6 +35,7 @@
#include <QVariant>
namespace ProjectExplorer {
+class OutputTaskParser;
class ToolChain;
class KitAspectWidget;
@@ -84,12 +85,14 @@ public:
void addToEnvironment(const Kit *k, Utils::Environment &env) const override;
void addToMacroExpander(Kit *kit, Utils::MacroExpander *expander) const override;
- IOutputParser *createOutputParser(const Kit *k) const override;
+ QList<Utils::OutputLineParser *> createOutputParsers(const Kit *k) const override;
QSet<Core::Id> availableFeatures(const Kit *k) const override;
static Core::Id id();
static QByteArray toolChainId(const Kit *k, Core::Id language);
static ToolChain *toolChain(const Kit *k, Core::Id language);
+ static ToolChain *cToolChain(const Kit *k);
+ static ToolChain *cxxToolChain(const Kit *k);
static QList<ToolChain *> toolChains(const Kit *k);
static void setToolChain(Kit *k, ToolChain *tc);
static void setAllToolChainsToMatch(Kit *k, ToolChain *tc);
diff --git a/src/plugins/projectexplorer/kitmanager.cpp b/src/plugins/projectexplorer/kitmanager.cpp
index f989b955cc..1eab4633f5 100644
--- a/src/plugins/projectexplorer/kitmanager.cpp
+++ b/src/plugins/projectexplorer/kitmanager.cpp
@@ -677,10 +677,10 @@ void KitAspect::addToEnvironment(const Kit *k, Environment &env) const
Q_UNUSED(env)
}
-IOutputParser *KitAspect::createOutputParser(const Kit *k) const
+QList<OutputLineParser *> KitAspect::createOutputParsers(const Kit *k) const
{
Q_UNUSED(k)
- return nullptr;
+ return {};
}
QString KitAspect::displayNamePostfix(const Kit *k) const
diff --git a/src/plugins/projectexplorer/kitmanager.h b/src/plugins/projectexplorer/kitmanager.h
index 21228f44c2..f55380c573 100644
--- a/src/plugins/projectexplorer/kitmanager.h
+++ b/src/plugins/projectexplorer/kitmanager.h
@@ -42,11 +42,11 @@ namespace Utils {
class Environment;
class FilePath;
class MacroExpander;
+class OutputLineParser;
} // namespace Utils
namespace ProjectExplorer {
class Task;
-class IOutputParser;
class KitAspectWidget;
class KitManager;
@@ -91,7 +91,7 @@ public:
virtual KitAspectWidget *createConfigWidget(Kit *) const = 0;
virtual void addToEnvironment(const Kit *k, Utils::Environment &env) const;
- virtual IOutputParser *createOutputParser(const Kit *k) const;
+ virtual QList<Utils::OutputLineParser *> createOutputParsers(const Kit *k) const;
virtual QString displayNamePostfix(const Kit *k) const;
diff --git a/src/plugins/projectexplorer/ldparser.cpp b/src/plugins/projectexplorer/ldparser.cpp
index 9d8aee037f..325e123b51 100644
--- a/src/plugins/projectexplorer/ldparser.cpp
+++ b/src/plugins/projectexplorer/ldparser.cpp
@@ -54,43 +54,51 @@ LdParser::LdParser()
QTC_CHECK(m_regExpGccNames.isValid());
}
-void LdParser::stdError(const QString &line)
+Utils::OutputLineParser::Result LdParser::handleLine(const QString &line, Utils::OutputFormat type)
{
+ if (type != Utils::StdErrFormat)
+ return Status::NotHandled;
+
QString lne = rightTrimmed(line);
- if (!lne.isEmpty() && !lne.at(0).isSpace() && !m_incompleteTask.isNull())
+ if (!lne.isEmpty() && !lne.at(0).isSpace() && !m_incompleteTask.isNull()) {
flush();
+ return Status::NotHandled;
+ }
if (lne.startsWith(QLatin1String("TeamBuilder "))
|| lne.startsWith(QLatin1String("distcc["))
|| lne.contains(QLatin1String("ar: creating "))) {
- IOutputParser::stdError(line);
- return;
+ return Status::NotHandled;
}
// ld on macOS
if (lne.startsWith("Undefined symbols for architecture") && lne.endsWith(":")) {
m_incompleteTask = CompileTask(Task::Error, lne);
- return;
+ return Status::InProgress;
}
if (!m_incompleteTask.isNull() && lne.startsWith(" ")) {
- m_incompleteTask.description.append('\n').append(lne);
+ m_incompleteTask.details.append(lne);
static const QRegularExpression locRegExp(" (?<symbol>\\S+) in (?<file>\\S+)");
const QRegularExpressionMatch match = locRegExp.match(lne);
- if (match.hasMatch())
- m_incompleteTask.setFile(Utils::FilePath::fromString(match.captured("file")));
- return;
+ LinkSpecs linkSpecs;
+ if (match.hasMatch()) {
+ m_incompleteTask.setFile(absoluteFilePath(Utils::FilePath::fromString(
+ match.captured("file"))));
+ addLinkSpecForAbsoluteFilePath(linkSpecs, m_incompleteTask.file, 0, match, "file");
+ }
+ return {Status::InProgress, linkSpecs};
}
if (lne.startsWith("collect2:") || lne.startsWith("collect2.exe:")) {
- emit addTask(CompileTask(Task::Error, lne /* description */), 1);
- return;
+ scheduleTask(CompileTask(Task::Error, lne /* description */), 1);
+ return Status::Done;
}
QRegularExpressionMatch match = m_ranlib.match(lne);
if (match.hasMatch()) {
QString description = match.captured(2);
- emit addTask(CompileTask(Task::Warning, description), 1);
- return;
+ scheduleTask(CompileTask(Task::Warning, description), 1);
+ return Status::Done;
}
match = m_regExpGccNames.match(lne);
@@ -103,8 +111,8 @@ void LdParser::stdError(const QString &line)
} else if (description.startsWith(QLatin1String("fatal: "))) {
description = description.mid(7);
}
- emit addTask(CompileTask(type, description), 1);
- return;
+ scheduleTask(CompileTask(type, description), 1);
+ return Status::Done;
}
match = m_regExpLinker.match(lne);
@@ -113,12 +121,15 @@ void LdParser::stdError(const QString &line)
int lineno = match.captured(7).toInt(&ok);
if (!ok)
lineno = -1;
- Utils::FilePath filename = Utils::FilePath::fromUserInput(match.captured(1));
+ Utils::FilePath filename
+ = absoluteFilePath(Utils::FilePath::fromUserInput(match.captured(1)));
+ int capIndex = 1;
const QString sourceFileName = match.captured(4);
if (!sourceFileName.isEmpty()
&& !sourceFileName.startsWith(QLatin1String("(.text"))
&& !sourceFileName.startsWith(QLatin1String("(.data"))) {
- filename = Utils::FilePath::fromUserInput(sourceFileName);
+ filename = absoluteFilePath(Utils::FilePath::fromUserInput(sourceFileName));
+ capIndex = 4;
}
QString description = match.captured(8).trimmed();
Task::TaskType type = Task::Error;
@@ -133,18 +144,20 @@ void LdParser::stdError(const QString &line)
type = Task::Warning;
description = description.mid(9);
}
- emit addTask(CompileTask(type, description, filename, lineno), 1);
- return;
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, filename, lineno, match, capIndex);
+ scheduleTask(CompileTask(type, description, filename, lineno), 1);
+ return {Status::Done, linkSpecs};
}
- IOutputParser::stdError(line);
+ return Status::NotHandled;
}
-void LdParser::doFlush()
+void LdParser::flush()
{
if (m_incompleteTask.isNull())
return;
const Task t = m_incompleteTask;
m_incompleteTask.clear();
- emit addTask(t);
+ scheduleTask(t, 1);
}
diff --git a/src/plugins/projectexplorer/ldparser.h b/src/plugins/projectexplorer/ldparser.h
index bf6a441cbe..56f94f52c7 100644
--- a/src/plugins/projectexplorer/ldparser.h
+++ b/src/plugins/projectexplorer/ldparser.h
@@ -32,15 +32,15 @@
namespace ProjectExplorer {
-class LdParser : public ProjectExplorer::IOutputParser
+class LdParser : public ProjectExplorer::OutputTaskParser
{
Q_OBJECT
public:
LdParser();
private:
- void stdError(const QString &line) override;
- void doFlush() override;
+ Result handleLine(const QString &line, Utils::OutputFormat type) override;
+ void flush() override;
QRegularExpression m_ranlib;
QRegularExpression m_regExpLinker;
diff --git a/src/plugins/projectexplorer/linuxiccparser.cpp b/src/plugins/projectexplorer/linuxiccparser.cpp
index 95ccb4dfce..0f2877dfda 100644
--- a/src/plugins/projectexplorer/linuxiccparser.cpp
+++ b/src/plugins/projectexplorer/linuxiccparser.cpp
@@ -63,17 +63,15 @@ LinuxIccParser::LinuxIccParser() :
m_pchInfoLine.setPattern(QLatin1String("^\".*\": (creating|using) precompiled header file \".*\"\n$"));
m_pchInfoLine.setMinimal(true);
QTC_CHECK(m_pchInfoLine.isValid());
-
- appendOutputParser(new Internal::LldParser);
- appendOutputParser(new LdParser);
}
-void LinuxIccParser::stdError(const QString &line)
+OutputLineParser::Result LinuxIccParser::handleLine(const QString &line, OutputFormat type)
{
- if (m_pchInfoLine.indexIn(line) != -1) {
- // totally ignore this line
- return;
- }
+ if (type != Utils::StdErrFormat)
+ return Status::NotHandled;
+
+ if (m_pchInfoLine.indexIn(line) != -1)
+ return Status::Done; // totally ignore this line
if (m_expectFirstLine && m_firstLine.indexIn(line) != -1) {
// Clear out old task
@@ -83,40 +81,33 @@ void LinuxIccParser::stdError(const QString &line)
type = Task::Error;
else if (category == QLatin1String("warning"))
type = Task::Warning;
- m_temporary = CompileTask(type,
- m_firstLine.cap(6).trimmed(),
- Utils::FilePath::fromUserInput(m_firstLine.cap(1)),
- m_firstLine.cap(2).toInt());
+ const FilePath filePath = absoluteFilePath(FilePath::fromUserInput(m_firstLine.cap(1)));
+ const int lineNo = m_firstLine.cap(2).toInt();
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, lineNo, m_firstLine, 1);
+ m_temporary = CompileTask(type, m_firstLine.cap(6).trimmed(), filePath, lineNo);
m_lines = 1;
m_expectFirstLine = false;
- } else if (!m_expectFirstLine && m_caretLine.indexIn(line) != -1) {
- // Format the last line as code
- QTextLayout::FormatRange fr;
- fr.start = m_temporary.description.lastIndexOf(QLatin1Char('\n')) + 1;
- fr.length = m_temporary.description.length() - fr.start;
- fr.format.setFontItalic(true);
- m_temporary.formats.append(fr);
-
- QTextLayout::FormatRange fr2;
- fr2.start = fr.start + line.indexOf(QLatin1Char('^')) - m_indent;
- fr2.length = 1;
- fr2.format.setFontWeight(QFont::Bold);
- m_temporary.formats.append(fr2);
- } else if (!m_expectFirstLine && line.trimmed().isEmpty()) { // last Line
+ return Status::InProgress;
+ }
+ if (!m_expectFirstLine && m_caretLine.indexIn(line) != -1) {
+ // FIXME: m_temporary.details.append(line);
+ return Status::InProgress;
+ }
+ if (!m_expectFirstLine && line.trimmed().isEmpty()) { // last Line
m_expectFirstLine = true;
- emit addTask(m_temporary, m_lines);
+ scheduleTask(m_temporary, m_lines);
m_temporary = Task();
- } else if (!m_expectFirstLine && m_continuationLines.indexIn(line) != -1) {
- m_temporary.description.append(QLatin1Char('\n'));
- m_indent = 0;
- while (m_indent < line.length() && line.at(m_indent).isSpace())
- m_indent++;
- m_temporary.description.append(m_continuationLines.cap(1).trimmed());
+ return Status::Done;
+ }
+ if (!m_expectFirstLine && m_continuationLines.indexIn(line) != -1) {
+ m_temporary.details.append(m_continuationLines.cap(1).trimmed());
++m_lines;
- } else {
- IOutputParser::stdError(line);
+ return Status::InProgress;
}
+ QTC_CHECK(m_temporary.isNull());
+ return Status::NotHandled;
}
Core::Id LinuxIccParser::id()
@@ -124,13 +115,20 @@ Core::Id LinuxIccParser::id()
return Core::Id("ProjectExplorer.OutputParser.Icc");
}
-void LinuxIccParser::doFlush()
+QList<OutputLineParser *> LinuxIccParser::iccParserSuite()
+{
+ return {new LinuxIccParser, new Internal::LldParser, new LdParser};
+}
+
+void LinuxIccParser::flush()
{
if (m_temporary.isNull())
return;
+
+ setDetailsFormat(m_temporary);
Task t = m_temporary;
m_temporary.clear();
- emit addTask(t, m_lines, 1);
+ scheduleTask(t, m_lines, 1);
}
#ifdef WITH_TESTS
@@ -227,14 +225,14 @@ void ProjectExplorerPlugin::testLinuxIccOutputParsers_data()
<< (Tasks()
<< CompileTask(Task::Unknown,
"Note: No relevant classes found. No output generated.",
- FilePath::fromUserInput("/home/qtwebkithelpviewer.h"), 0))
+ FilePath::fromUserInput("/home/qtwebkithelpviewer.h"), -1))
<< QString();
}
void ProjectExplorerPlugin::testLinuxIccOutputParsers()
{
OutputParserTester testbench;
- testbench.appendOutputParser(new LinuxIccParser);
+ testbench.setLineParsers(LinuxIccParser::iccParserSuite());
QFETCH(QString, input);
QFETCH(OutputParserTester::Channel, inputChannel);
QFETCH(Tasks, tasks);
diff --git a/src/plugins/projectexplorer/linuxiccparser.h b/src/plugins/projectexplorer/linuxiccparser.h
index 8697869cd7..4d6a00264d 100644
--- a/src/plugins/projectexplorer/linuxiccparser.h
+++ b/src/plugins/projectexplorer/linuxiccparser.h
@@ -32,19 +32,20 @@
namespace ProjectExplorer {
-class LinuxIccParser : public ProjectExplorer::IOutputParser
+class LinuxIccParser : public ProjectExplorer::OutputTaskParser
{
Q_OBJECT
public:
LinuxIccParser();
- void stdError(const QString &line) override;
-
static Core::Id id();
+ static QList<Utils::OutputLineParser *> iccParserSuite();
+
private:
- void doFlush() override;
+ Result handleLine(const QString &line, Utils::OutputFormat type) override;
+ void flush() override;
QRegExp m_firstLine;
QRegExp m_continuationLines;
@@ -52,7 +53,6 @@ private:
QRegExp m_pchInfoLine;
bool m_expectFirstLine = true;
- int m_indent = 0;
Task m_temporary;
int m_lines = 0;
};
diff --git a/src/plugins/projectexplorer/lldparser.cpp b/src/plugins/projectexplorer/lldparser.cpp
index 179bd742d3..aee20ea795 100644
--- a/src/plugins/projectexplorer/lldparser.cpp
+++ b/src/plugins/projectexplorer/lldparser.cpp
@@ -35,12 +35,15 @@
namespace ProjectExplorer {
namespace Internal {
-void LldParser::stdError(const QString &line)
+Utils::OutputLineParser::Result LldParser::handleLine(const QString &line, Utils::OutputFormat type)
{
+ if (type != Utils::StdErrFormat)
+ return Status::NotHandled;
+
const QString trimmedLine = rightTrimmed(line);
if (trimmedLine.contains("error:") && trimmedLine.contains("lld")) {
- emit addTask(CompileTask(Task::Error, trimmedLine));
- return;
+ scheduleTask(CompileTask(Task::Error, trimmedLine), 1);
+ return Status::Done;
}
static const QStringList prefixes{">>> referenced by ", ">>> defined at ", ">>> "};
for (const QString &prefix : prefixes) {
@@ -62,12 +65,15 @@ void LldParser::stdError(const QString &line)
else
filePathOffset = prefix.length();
const int filePathLen = locOffset == -1 ? -1 : locOffset - filePathOffset;
- const auto file = Utils::FilePath::fromUserInput(
- trimmedLine.mid(filePathOffset, filePathLen).trimmed());
- emit addTask(CompileTask(Task::Unknown, trimmedLine.mid(4).trimmed(), file, lineNo));
- return;
+ const auto file = absoluteFilePath(Utils::FilePath::fromUserInput(
+ trimmedLine.mid(filePathOffset, filePathLen).trimmed()));
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, file, lineNo, filePathOffset, filePathLen);
+ scheduleTask(CompileTask(Task::Unknown, trimmedLine.mid(4).trimmed(),
+ file, lineNo), 1);
+ return {Status::Done, linkSpecs};
}
- IOutputParser::stdError(line);
+ return Status::NotHandled;
}
} // namespace Internal
diff --git a/src/plugins/projectexplorer/lldparser.h b/src/plugins/projectexplorer/lldparser.h
index c459880f8e..f9bb4388aa 100644
--- a/src/plugins/projectexplorer/lldparser.h
+++ b/src/plugins/projectexplorer/lldparser.h
@@ -30,9 +30,9 @@
namespace ProjectExplorer {
namespace Internal {
-class LldParser : public IOutputParser
+class LldParser : public OutputTaskParser
{
- void stdError(const QString &line) override;
+ Result handleLine(const QString &line, Utils::OutputFormat type) override;
};
} // namespace Internal
diff --git a/src/plugins/projectexplorer/makestep.cpp b/src/plugins/projectexplorer/makestep.cpp
index ed8a048e68..ec5cafe662 100644
--- a/src/plugins/projectexplorer/makestep.cpp
+++ b/src/plugins/projectexplorer/makestep.cpp
@@ -81,23 +81,19 @@ void MakeStep::setAvailableBuildTargets(const QStringList &buildTargets)
bool MakeStep::init()
{
- BuildConfiguration *bc = buildConfiguration();
- if (!bc)
- emit addTask(Task::buildConfigurationMissingTask());
-
const CommandLine make = effectiveMakeCommand(Execution);
if (make.executable().isEmpty())
emit addTask(makeCommandMissingTask());
- if (!bc || make.executable().isEmpty()) {
+ if (make.executable().isEmpty()) {
emitFaultyConfigurationMessage();
return false;
}
ProcessParameters *pp = processParameters();
- pp->setMacroExpander(bc->macroExpander());
- pp->setWorkingDirectory(bc->buildDirectory());
- pp->setEnvironment(environment(bc));
+ pp->setMacroExpander(macroExpander());
+ pp->setWorkingDirectory(buildDirectory());
+ pp->setEnvironment(buildEnvironment());
pp->setCommandLine(make);
pp->resolveAll();
@@ -106,15 +102,17 @@ bool MakeStep::init()
// That is mostly so that rebuild works on an already clean project
setIgnoreReturnValue(isClean());
- setOutputParser(new GnuMakeParser());
- IOutputParser *parser = target()->kit()->createOutputParser();
- if (parser)
- appendOutputParser(parser);
- outputParser()->setWorkingDirectory(pp->effectiveWorkingDirectory().toString());
-
return AbstractProcessStep::init();
}
+void MakeStep::setupOutputFormatter(OutputFormatter *formatter)
+{
+ formatter->addLineParser(new GnuMakeParser());
+ formatter->addLineParsers(target()->kit()->createOutputParsers());
+ formatter->addSearchDir(processParameters()->effectiveWorkingDirectory());
+ AbstractProcessStep::setupOutputFormatter(formatter);
+}
+
void MakeStep::setClean(bool clean)
{
m_clean = clean;
@@ -153,7 +151,7 @@ FilePath MakeStep::defaultMakeCommand() const
BuildConfiguration *bc = buildConfiguration();
if (!bc)
return {};
- const Utils::Environment env = environment(bc);
+ const Utils::Environment env = makeEnvironment();
for (const ToolChain *tc : preferredToolChains(target()->kit())) {
FilePath make = tc->makeCommand(env);
if (!make.isEmpty())
@@ -225,7 +223,7 @@ static Utils::optional<int> argsJobCount(const QString &str)
bool MakeStep::makeflagsJobCountMismatch() const
{
- const Utils::Environment env = environment(buildConfiguration());
+ const Environment env = makeEnvironment();
if (!env.hasKey(MAKEFLAGS))
return false;
Utils::optional<int> makeFlagsJobCount = argsJobCount(env.expandedValueForKey(MAKEFLAGS));
@@ -234,7 +232,7 @@ bool MakeStep::makeflagsJobCountMismatch() const
bool MakeStep::makeflagsContainsJobCount() const
{
- const Utils::Environment env = environment(buildConfiguration());
+ const Environment env = makeEnvironment();
if (!env.hasKey(MAKEFLAGS))
return false;
return argsJobCount(env.expandedValueForKey(MAKEFLAGS)).has_value();
@@ -245,9 +243,9 @@ bool MakeStep::userArgsContainsJobCount() const
return argsJobCount(m_userArguments).has_value();
}
-Utils::Environment MakeStep::environment(BuildConfiguration *bc) const
+Environment MakeStep::makeEnvironment() const
{
- Utils::Environment env = bc ? bc->environment() : Utils::Environment::systemEnvironment();
+ Environment env = buildEnvironment();
Utils::Environment::setupEnglishOutput(&env);
if (makeCommand().isEmpty()) {
// We also prepend "L" to the MAKEFLAGS, so that nmake / jom are less verbose
@@ -494,10 +492,10 @@ void MakeStepConfigWidget::updateDetails()
m_ui->disableInSubDirsCheckBox->setChecked(!m_makeStep->enabledForSubDirs());
ProcessParameters param;
- param.setMacroExpander(bc->macroExpander());
- param.setWorkingDirectory(bc->buildDirectory());
+ param.setMacroExpander(m_makeStep->macroExpander());
+ param.setWorkingDirectory(m_makeStep->buildDirectory());
param.setCommandLine(make);
- param.setEnvironment(m_makeStep->environment(bc));
+ param.setEnvironment(m_makeStep->buildEnvironment());
if (param.commandMissing())
setSummaryText(tr("<b>Make:</b> %1 not found in the environment.")
diff --git a/src/plugins/projectexplorer/makestep.h b/src/plugins/projectexplorer/makestep.h
index 721e99b440..decc0b0fcc 100644
--- a/src/plugins/projectexplorer/makestep.h
+++ b/src/plugins/projectexplorer/makestep.h
@@ -54,6 +54,7 @@ public:
void setAvailableBuildTargets(const QStringList &buildTargets);
bool init() override;
+ void setupOutputFormatter(Utils::OutputFormatter *formatter) override;
ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override;
bool buildsTarget(const QString &target) const;
void setBuildTarget(const QString &target, bool on);
@@ -87,7 +88,7 @@ public:
bool enabledForSubDirs() const { return m_enabledForSubDirs; }
void setEnabledForSubDirs(bool enabled) { m_enabledForSubDirs = enabled; }
- Utils::Environment environment(BuildConfiguration *bc) const;
+ Utils::Environment makeEnvironment() const;
protected:
bool fromMap(const QVariantMap &map) override;
diff --git a/src/plugins/projectexplorer/miniprojecttargetselector.cpp b/src/plugins/projectexplorer/miniprojecttargetselector.cpp
index 342c877526..0057366a17 100644
--- a/src/plugins/projectexplorer/miniprojecttargetselector.cpp
+++ b/src/plugins/projectexplorer/miniprojecttargetselector.cpp
@@ -92,76 +92,43 @@ static QIcon createCenteredIcon(const QIcon &icon, const QIcon &overlay)
return QIcon(targetPixmap);
}
-class SelectorView : public TreeView
-{
- Q_OBJECT
-
-public:
- SelectorView(QWidget *parent);
-
- void setMaxCount(int maxCount);
- int maxCount();
-
- int optimalWidth() const;
- void setOptimalWidth(int width);
-
- int padding();
-
-private:
- void keyPressEvent(QKeyEvent *event) override;
- void keyReleaseEvent(QKeyEvent *event) override;
-
- int m_maxCount = 0;
- int m_optimalWidth = 0;
-};
-
-// The project-specific classes look annoyingly similar to the generic ones.
-// Can we merge them?
-class SelectorProjectItem : public TreeItem
-{
-public:
- SelectorProjectItem() = default;
- SelectorProjectItem(Project *project) : m_project(project) {}
- Project *project() const { return m_project; }
- QString displayName() const
- {
- const auto hasSameProjectName = [this](TreeItem *ti) {
- return ti != this && static_cast<SelectorProjectItem *>(ti)->project()->displayName()
- == project()->displayName();
- };
- QString displayName = m_project->displayName();
- if (parent()->findAnyChild(hasSameProjectName)) {
- displayName.append(" (").append(project()->projectFilePath().toUserOutput())
- .append(')');
- }
- return displayName;
- }
-
-private:
- QVariant data(int column, int role) const override
- {
- return column == 0 && role == Qt::DisplayRole ? displayName() : QString();
- }
-
- Project *m_project = nullptr;
-};
-
class GenericItem : public TreeItem
{
public:
GenericItem() = default;
GenericItem(QObject *object) : m_object(object) {}
QObject *object() const { return m_object; }
- QString displayName() const
+ QString rawDisplayName() const
{
+ if (const auto p = qobject_cast<Project *>(object()))
+ return p->displayName();
if (const auto t = qobject_cast<Target *>(object()))
return t->displayName();
return static_cast<ProjectConfiguration *>(object())->displayName();
+
+ }
+ QString displayName() const
+ {
+ if (const auto p = qobject_cast<Project *>(object())) {
+ const auto hasSameProjectName = [this](TreeItem *ti) {
+ return ti != this
+ && static_cast<GenericItem *>(ti)->rawDisplayName() == rawDisplayName();
+ };
+ QString displayName = p->displayName();
+ if (parent()->findAnyChild(hasSameProjectName)) {
+ displayName.append(" (").append(p->projectFilePath().toUserOutput())
+ .append(')');
+ }
+ return displayName;
+ }
+ return rawDisplayName();
}
private:
- QString toolTip() const
+ QVariant toolTip() const
{
+ if (qobject_cast<Project *>(object()))
+ return {};
if (const auto t = qobject_cast<Target *>(object()))
return t->toolTip();
return static_cast<ProjectConfiguration *>(object())->toolTip();
@@ -178,7 +145,8 @@ private:
return displayName();
case Qt::ToolTipRole:
return toolTip();
- default:break;
+ default:
+ break;
}
return {};
}
@@ -186,72 +154,101 @@ private:
QObject *m_object = nullptr;
};
-static QString rawDisplayName(const SelectorProjectItem *item)
+static bool compareItems(const TreeItem *ti1, const TreeItem *ti2)
{
- return item->project()->displayName();
-}
-static QString rawDisplayName(const GenericItem *item) { return item->displayName(); }
-
-template<typename T> bool compareItems(const TreeItem *ti1, const TreeItem *ti2)
-{
- const int result = caseFriendlyCompare(rawDisplayName(static_cast<const T*>(ti1)),
- rawDisplayName(static_cast<const T*>(ti2)));
+ const int result = caseFriendlyCompare(static_cast<const GenericItem *>(ti1)->rawDisplayName(),
+ static_cast<const GenericItem *>(ti2)->rawDisplayName());
if (result != 0)
return result < 0;
return ti1 < ti2;
}
-class ProjectsModel : public TreeModel<SelectorProjectItem, SelectorProjectItem>
+class GenericModel : public TreeModel<GenericItem, GenericItem>
{
Q_OBJECT
public:
- ProjectsModel(QObject *parent) : TreeModel(parent)
+ GenericModel(QObject *parent) : TreeModel(parent) { }
+
+ void rebuild(const QList<QObject *> &objects)
{
- connect(SessionManager::instance(), &SessionManager::projectAdded,
- this, [this](Project *project) {
- emit projectAdded(addItemForProject(project));
- });
- connect(SessionManager::instance(), &SessionManager::aboutToRemoveProject,
- this, [this](const Project *project) {
- SelectorProjectItem * const item = itemForProject(project);
- if (!item)
- return;
- destroyItem(item);
- emit optimalWidthChanged();
- });
- buildTree();
+ clear();
+ for (QObject * const e : objects)
+ addItemForObject(e);
+ }
+
+ const GenericItem *addItemForObject(QObject *object)
+ {
+ const auto item = new GenericItem(object);
+ rootItem()->insertOrderedChild(item, &compareItems);
+ if (const auto project = qobject_cast<Project *>(object)) {
+ connect(project, &Project::displayNameChanged,
+ this, &GenericModel::displayNameChanged);
+ } else if (const auto target = qobject_cast<Target *>(object)) {
+ connect(target, &Target::kitChanged, this, &GenericModel::displayNameChanged);
+ } else {
+ const auto pc = qobject_cast<ProjectConfiguration *>(object);
+ QTC_CHECK(pc);
+ connect(pc, &ProjectConfiguration::displayNameChanged,
+ this, &GenericModel::displayNameChanged);
+ connect(pc, &ProjectConfiguration::toolTipChanged,
+ this, &GenericModel::updateToolTips);
+ }
+ return item;
}
- SelectorProjectItem *itemForProject(const Project *project) const
+ GenericItem *itemForObject(const QObject *object) const
{
- return findItemAtLevel<1>([project](const SelectorProjectItem *item) {
- return item->project() == project;
+ return findItemAtLevel<1>([object](const GenericItem *item) {
+ return item->object() == object;
});
}
+ void setColumnCount(int columns) { m_columnCount = columns; }
+
signals:
- void projectAdded(const SelectorProjectItem *projectItem);
- void requestRestoreCurrentIndex();
- void optimalWidthChanged();
+ void displayNameChanged();
private:
- const SelectorProjectItem *addItemForProject(Project *project)
+ void updateToolTips()
{
- const auto projectItem = new SelectorProjectItem(project);
- rootItem()->insertOrderedChild(projectItem, &compareItems<SelectorProjectItem>);
- connect(project, &Project::displayNameChanged, this, [this] {
- rootItem()->sortChildren(&compareItems<SelectorProjectItem>);
- emit optimalWidthChanged();
- emit requestRestoreCurrentIndex();
- });
- return projectItem;
+ emit dataChanged(index(0, 0), index(rowCount() - 1, 0), {Qt::ToolTipRole});
}
+};
+
+class SelectorView : public TreeView
+{
+ Q_OBJECT
+
+public:
+ SelectorView(QWidget *parent);
+
+ void setMaxCount(int maxCount);
+ int maxCount();
+
+ int optimalWidth() const;
+ void setOptimalWidth(int width);
- void buildTree()
+ int padding();
+
+ GenericModel *theModel() const { return static_cast<GenericModel *>(model()); }
+
+protected:
+ void resetOptimalWidth()
{
- for (Project * const project : SessionManager::projects())
- addItemForProject(project);
+ int width = 0;
+ QFontMetrics fn(font());
+ theModel()->forItemsAtLevel<1>([this, &width, &fn](const GenericItem *item) {
+ width = qMax(fn.horizontalAdvance(item->displayName()) + padding(), width);
+ });
+ setOptimalWidth(width);
}
+
+private:
+ void keyPressEvent(QKeyEvent *event) override;
+ void keyReleaseEvent(QKeyEvent *event) override;
+
+ int m_maxCount = 0;
+ int m_optimalWidth = 0;
};
class ProjectListView : public SelectorView
@@ -261,96 +258,54 @@ class ProjectListView : public SelectorView
public:
explicit ProjectListView(QWidget *parent = nullptr) : SelectorView(parent)
{
- ProjectsModel * const model = new ProjectsModel(this);
- connect(model, &ProjectsModel::projectAdded, this,
- [this](const SelectorProjectItem *projectItem) {
+ const auto model = new GenericModel(this);
+ model->rebuild(transform<QList<QObject *>>(SessionManager::projects(),
+ [](Project *p) { return p; }));
+ connect(SessionManager::instance(), &SessionManager::projectAdded,
+ this, [this, model](Project *project) {
+ const GenericItem *projectItem = model->addItemForObject(project);
QFontMetrics fn(font());
const int width = fn.horizontalAdvance(projectItem->displayName()) + padding();
if (width > optimalWidth())
setOptimalWidth(width);
restoreCurrentIndex();
});
- connect(model, &ProjectsModel::optimalWidthChanged,
- this, &ProjectListView::resetOptimalWidth);
- connect(model, &ProjectsModel::requestRestoreCurrentIndex,
- this, &ProjectListView::restoreCurrentIndex);
+ connect(SessionManager::instance(), &SessionManager::aboutToRemoveProject,
+ this, [this, model](const Project *project) {
+ GenericItem * const item = model->itemForObject(project);
+ if (!item)
+ return;
+ model->destroyItem(item);
+ resetOptimalWidth();
+ });
connect(SessionManager::instance(), &SessionManager::startupProjectChanged,
this, [this, model](const Project *project) {
- const SelectorProjectItem * const item = model->itemForProject(project);
+ const GenericItem * const item = model->itemForObject(project);
if (item)
setCurrentIndex(item->index());
});
+ connect(model, &GenericModel::displayNameChanged, this, [this, model] {
+ model->rootItem()->sortChildren(&compareItems);
+ resetOptimalWidth();
+ restoreCurrentIndex();
+ });
setModel(model);
connect(selectionModel(), &QItemSelectionModel::currentChanged,
this, [model](const QModelIndex &index) {
- const SelectorProjectItem * const item = model->itemForIndex(index);
- if (item && item->project())
- SessionManager::setStartupProject(item->project());
+ const GenericItem * const item = model->itemForIndex(index);
+ if (item && item->object())
+ SessionManager::setStartupProject(qobject_cast<Project *>(item->object()));
});
}
private:
- ProjectsModel *theModel() const { return static_cast<ProjectsModel *>(model()); }
-
void restoreCurrentIndex()
{
- const SelectorProjectItem * const itemForStartupProject
- = theModel()->itemForProject(SessionManager::startupProject());
+ const GenericItem * const itemForStartupProject
+ = theModel()->itemForObject(SessionManager::startupProject());
if (itemForStartupProject)
setCurrentIndex(theModel()->indexForItem(itemForStartupProject));
}
-
- void resetOptimalWidth()
- {
- int width = 0;
- QFontMetrics fn(font());
- theModel()->forItemsAtLevel<1>([this, &width, &fn](const SelectorProjectItem *item) {
- width = qMax(fn.horizontalAdvance(item->displayName()) + padding(), width);
- });
- setOptimalWidth(width);
- }
-};
-
-class GenericModel : public TreeModel<GenericItem, GenericItem>
-{
- Q_OBJECT
-public:
- GenericModel(QObject *parent) : TreeModel(parent) { }
-
- void rebuild(const QList<QObject *> &objects)
- {
- clear();
- for (QObject * const e : objects)
- addItemForObject(e);
- }
-
- const GenericItem *addItemForObject(QObject *object)
- {
- const auto item = new GenericItem(object);
- rootItem()->insertOrderedChild(item, &compareItems<GenericItem>);
- if (const auto target = qobject_cast<Target *>(object)) {
- connect(target, &Target::kitChanged, this, &GenericModel::displayNameChanged);
- } else {
- const auto pc = qobject_cast<ProjectConfiguration *>(object);
- QTC_CHECK(pc);
- connect(pc, &ProjectConfiguration::displayNameChanged,
- this, &GenericModel::displayNameChanged);
- connect(pc, &ProjectConfiguration::toolTipChanged,
- this, &GenericModel::updateToolTips);
- }
- return item;
- }
-
- void setColumnCount(int columns) { m_columnCount = columns; }
-
-signals:
- void displayNameChanged();
-
-private:
- void updateToolTips()
- {
- emit dataChanged(index(0, 0), index(rowCount() - 1, 0), {Qt::ToolTipRole});
- }
};
class GenericListWidget : public SelectorView
@@ -363,7 +318,7 @@ public:
const auto model = new GenericModel(this);
connect(model, &GenericModel::displayNameChanged, this, [this, model] {
const GenericItem * const activeItem = model->itemForIndex(currentIndex());
- model->rootItem()->sortChildren(&compareItems<GenericItem>);
+ model->rootItem()->sortChildren(&compareItems);
resetOptimalWidth();
if (activeItem)
setCurrentIndex(activeItem->index());
@@ -386,7 +341,7 @@ public:
void setActiveProjectConfiguration(QObject *active)
{
- if (const GenericItem * const item = itemForObject(active))
+ if (const GenericItem * const item = theModel()->itemForObject(active))
setCurrentIndex(item->index());
}
@@ -405,7 +360,7 @@ public:
void removeProjectConfiguration(QObject *pc)
{
const auto activeItem = theModel()->itemForIndex(currentIndex());
- if (GenericItem * const item = itemForObject(pc)) {
+ if (GenericItem * const item = theModel()->itemForObject(pc)) {
theModel()->destroyItem(item);
resetOptimalWidth();
if (activeItem && activeItem != item)
@@ -413,8 +368,6 @@ public:
}
}
- GenericModel *theModel() const { return static_cast<GenericModel *>(model()); }
-
private:
void mousePressEvent(QMouseEvent *event) override
{
@@ -442,23 +395,6 @@ private:
TreeView::mouseReleaseEvent(event);
}
- GenericItem *itemForObject(const QObject *object)
- {
- return theModel()->findItemAtLevel<1>([object](const GenericItem *item) {
- return item->object() == object;
- });
- }
-
- void resetOptimalWidth()
- {
- int width = 0;
- QFontMetrics fn(font());
- theModel()->forItemsAtLevel<1>([this, &width, &fn](const GenericItem *item) {
- width = qMax(fn.horizontalAdvance(item->displayName()) + padding(), width);
- });
- setOptimalWidth(width);
- }
-
QObject *objectAt(const QModelIndex &index) const
{
return theModel()->itemForIndex(index)->object();
@@ -1054,13 +990,8 @@ void MiniProjectTargetSelector::doLayout(bool keepSize)
void MiniProjectTargetSelector::projectAdded(Project *project)
{
- connect(project, &Project::addedProjectConfiguration,
- this, &MiniProjectTargetSelector::handleNewProjectConfiguration);
connect(project, &Project::addedTarget,
this, &MiniProjectTargetSelector::handleNewTarget);
-
- connect(project, &Project::removedProjectConfiguration,
- this, &MiniProjectTargetSelector::handleRemovalOfProjectConfiguration);
connect(project, &Project::removedTarget,
this, &MiniProjectTargetSelector::handleRemovalOfTarget);
@@ -1076,13 +1007,8 @@ void MiniProjectTargetSelector::projectAdded(Project *project)
void MiniProjectTargetSelector::projectRemoved(Project *project)
{
- disconnect(project, &Project::addedProjectConfiguration,
- this, &MiniProjectTargetSelector::handleNewProjectConfiguration);
disconnect(project, &Project::addedTarget,
this, &MiniProjectTargetSelector::handleNewTarget);
-
- disconnect(project, &Project::removedProjectConfiguration,
- this, &MiniProjectTargetSelector::handleRemovalOfProjectConfiguration);
disconnect(project, &Project::removedTarget,
this, &MiniProjectTargetSelector::handleRemovalOfTarget);
@@ -1105,25 +1031,6 @@ void MiniProjectTargetSelector::handleNewTarget(Target *target)
updateRunListVisible();
}
-void MiniProjectTargetSelector::handleNewProjectConfiguration(ProjectConfiguration *pc)
-{
- if (auto bc = qobject_cast<BuildConfiguration *>(pc)) {
- if (addedBuildConfiguration(bc))
- updateBuildListVisible();
- return;
- }
- if (auto dc = qobject_cast<DeployConfiguration *>(pc)) {
- if (addedDeployConfiguration(dc))
- updateDeployListVisible();
- return;
- }
- if (auto rc = qobject_cast<RunConfiguration *>(pc)) {
- if (addedRunConfiguration(rc))
- updateRunListVisible();
- return;
- }
-}
-
void MiniProjectTargetSelector::handleRemovalOfTarget(Target *target)
{
removedTarget(target);
@@ -1134,25 +1041,6 @@ void MiniProjectTargetSelector::handleRemovalOfTarget(Target *target)
updateRunListVisible();
}
-void MiniProjectTargetSelector::handleRemovalOfProjectConfiguration(ProjectConfiguration *pc)
-{
- if (auto bc = qobject_cast<BuildConfiguration *>(pc)) {
- if (removedBuildConfiguration(bc))
- updateBuildListVisible();
- return;
- }
- if (auto dc = qobject_cast<DeployConfiguration *>(pc)) {
- if (removedDeployConfiguration(dc))
- updateDeployListVisible();
- return;
- }
- if (auto rc = qobject_cast<RunConfiguration *>(pc)) {
- if (removedRunConfiguration(rc))
- updateRunListVisible();
- return;
- }
-}
-
void MiniProjectTargetSelector::addedTarget(Target *target)
{
if (target->project() != m_project)
@@ -1161,11 +1049,11 @@ void MiniProjectTargetSelector::addedTarget(Target *target)
m_listWidgets[TARGET]->addProjectConfiguration(target);
for (BuildConfiguration *bc : target->buildConfigurations())
- addedBuildConfiguration(bc);
+ addedBuildConfiguration(bc, false);
for (DeployConfiguration *dc : target->deployConfigurations())
- addedDeployConfiguration(dc);
+ addedDeployConfiguration(dc, false);
for (RunConfiguration *rc : target->runConfigurations())
- addedRunConfiguration(rc);
+ addedRunConfiguration(rc, false);
}
void MiniProjectTargetSelector::removedTarget(Target *target)
@@ -1176,64 +1064,71 @@ void MiniProjectTargetSelector::removedTarget(Target *target)
m_listWidgets[TARGET]->removeProjectConfiguration(target);
for (BuildConfiguration *bc : target->buildConfigurations())
- removedBuildConfiguration(bc);
+ removedBuildConfiguration(bc, false);
for (DeployConfiguration *dc : target->deployConfigurations())
- removedDeployConfiguration(dc);
+ removedDeployConfiguration(dc, false);
for (RunConfiguration *rc : target->runConfigurations())
- removedRunConfiguration(rc);
+ removedRunConfiguration(rc, false);
}
-bool MiniProjectTargetSelector::addedBuildConfiguration(BuildConfiguration *bc)
+void MiniProjectTargetSelector::addedBuildConfiguration(BuildConfiguration *bc, bool update)
{
- if (bc->target() != m_project->activeTarget())
- return false;
+ if (!m_project || bc->target() != m_project->activeTarget())
+ return;
m_listWidgets[BUILD]->addProjectConfiguration(bc);
- return true;
+ if (update)
+ updateBuildListVisible();
}
-bool MiniProjectTargetSelector::removedBuildConfiguration(BuildConfiguration *bc)
+void MiniProjectTargetSelector::removedBuildConfiguration(BuildConfiguration *bc, bool update)
{
- if (bc->target() != m_project->activeTarget())
- return false;
+ if (!m_project || bc->target() != m_project->activeTarget())
+ return;
m_listWidgets[BUILD]->removeProjectConfiguration(bc);
- return true;
+ if (update)
+ updateBuildListVisible();
}
-bool MiniProjectTargetSelector::addedDeployConfiguration(DeployConfiguration *dc)
+void MiniProjectTargetSelector::addedDeployConfiguration(DeployConfiguration *dc, bool update)
{
if (!m_project || dc->target() != m_project->activeTarget())
- return false;
+ return;
m_listWidgets[DEPLOY]->addProjectConfiguration(dc);
- return true;
+ if (update)
+ updateDeployListVisible();
}
-bool MiniProjectTargetSelector::removedDeployConfiguration(DeployConfiguration *dc)
+void MiniProjectTargetSelector::removedDeployConfiguration(DeployConfiguration *dc, bool update)
{
if (!m_project || dc->target() != m_project->activeTarget())
- return false;
+ return;
m_listWidgets[DEPLOY]->removeProjectConfiguration(dc);
- return true;
+ if (update)
+ updateDeployListVisible();
}
-bool MiniProjectTargetSelector::addedRunConfiguration(RunConfiguration *rc)
+
+void MiniProjectTargetSelector::addedRunConfiguration(RunConfiguration *rc, bool update)
{
if (!m_project || rc->target() != m_project->activeTarget())
- return false;
+ return;
m_listWidgets[RUN]->addProjectConfiguration(rc);
- return true;
+ if (update)
+ updateRunListVisible();
}
-bool MiniProjectTargetSelector::removedRunConfiguration(RunConfiguration *rc)
+void MiniProjectTargetSelector::removedRunConfiguration(RunConfiguration *rc, bool update)
{
if (!m_project || rc->target() != m_project->activeTarget())
- return false;
+ return;
m_listWidgets[RUN]->removeProjectConfiguration(rc);
- return true;
+ if (update)
+ updateRunListVisible();
}
void MiniProjectTargetSelector::updateProjectListVisible()
diff --git a/src/plugins/projectexplorer/miniprojecttargetselector.h b/src/plugins/projectexplorer/miniprojecttargetselector.h
index e78d416089..b86845f59a 100644
--- a/src/plugins/projectexplorer/miniprojecttargetselector.h
+++ b/src/plugins/projectexplorer/miniprojecttargetselector.h
@@ -38,7 +38,6 @@ class Project;
class Target;
class BuildConfiguration;
class DeployConfiguration;
-class ProjectConfiguration;
class RunConfiguration;
namespace Internal {
@@ -51,7 +50,8 @@ class MiniProjectTargetSelector : public QWidget
Q_OBJECT
public:
- explicit MiniProjectTargetSelector(QAction *projectAction, QWidget *parent = nullptr);
+ explicit MiniProjectTargetSelector(QAction *projectAction, QWidget *parent);
+
void setVisible(bool visible) override;
void keyPressEvent(QKeyEvent *ke) override;
@@ -62,11 +62,10 @@ public:
void nextOrShow();
private:
+ friend class ProjectExplorer::Target;
void projectAdded(ProjectExplorer::Project *project);
void projectRemoved(ProjectExplorer::Project *project);
- void handleNewProjectConfiguration(ProjectExplorer::ProjectConfiguration *pc);
void handleNewTarget(Target *target);
- void handleRemovalOfProjectConfiguration(ProjectExplorer::ProjectConfiguration *pc);
void handleRemovalOfTarget(Target *pc);
void changeStartupProject(ProjectExplorer::Project *project);
@@ -81,12 +80,12 @@ private:
void switchToProjectsMode();
void addedTarget(Target *target);
void removedTarget(Target *target);
- bool addedBuildConfiguration(BuildConfiguration* bc);
- bool removedBuildConfiguration(BuildConfiguration* bc);
- bool addedDeployConfiguration(DeployConfiguration *dc);
- bool removedDeployConfiguration(DeployConfiguration *dc);
- bool addedRunConfiguration(RunConfiguration *rc);
- bool removedRunConfiguration(RunConfiguration *rc);
+ void addedBuildConfiguration(BuildConfiguration *bc, bool update = true);
+ void removedBuildConfiguration(BuildConfiguration *bc, bool update = true);
+ void addedDeployConfiguration(DeployConfiguration *dc, bool update = true);
+ void removedDeployConfiguration(DeployConfiguration *dc, bool update = true);
+ void addedRunConfiguration(RunConfiguration *rc, bool update = true);
+ void removedRunConfiguration(RunConfiguration *rc, bool update = true);
void updateProjectListVisible();
void updateTargetListVisible();
diff --git a/src/plugins/projectexplorer/msvcparser.cpp b/src/plugins/projectexplorer/msvcparser.cpp
index 9512ed94a3..8cd6c447bd 100644
--- a/src/plugins/projectexplorer/msvcparser.cpp
+++ b/src/plugins/projectexplorer/msvcparser.cpp
@@ -100,97 +100,86 @@ MsvcParser::MsvcParser()
QTC_CHECK(m_additionalInfoRegExp.isValid());
}
-void MsvcParser::stdOutput(const QString &line)
+Core::Id MsvcParser::id()
{
- QRegularExpressionMatch match = m_additionalInfoRegExp.match(line);
- if (line.startsWith(" ") && !match.hasMatch()) {
- if (m_lastTask.isNull())
- return;
-
- m_lastTask.description.append('\n');
- m_lastTask.description.append(line.mid(8));
- // trim trailing spaces:
- int i = 0;
- for (i = m_lastTask.description.length() - 1; i >= 0; --i) {
- if (!m_lastTask.description.at(i).isSpace())
- break;
- }
- m_lastTask.description.truncate(i + 1);
-
- if (m_lastTask.formats.isEmpty()) {
- QTextLayout::FormatRange fr;
- fr.start = m_lastTask.description.indexOf('\n') + 1;
- fr.length = m_lastTask.description.length() - fr.start;
- fr.format.setFontItalic(true);
- m_lastTask.formats.append(fr);
- } else {
- m_lastTask.formats[0].length = m_lastTask.description.length() - m_lastTask.formats[0].start;
+ return Core::Id("ProjectExplorer.OutputParser.Msvc");
+}
+
+OutputLineParser::Result MsvcParser::handleLine(const QString &line, OutputFormat type)
+{
+ if (type == OutputFormat::StdOutFormat) {
+ QRegularExpressionMatch match = m_additionalInfoRegExp.match(line);
+ if (line.startsWith(" ") && !match.hasMatch()) {
+ if (m_lastTask.isNull())
+ return Status::NotHandled;
+
+ m_lastTask.details.append(rightTrimmed(line.mid(8)));
+ ++m_lines;
+ return Status::InProgress;
}
- ++m_lines;
- return;
- }
- if (processCompileLine(line))
- return;
- if (handleNmakeJomMessage(line, &m_lastTask)) {
- m_lines = 1;
- return;
- }
- if (match.hasMatch()) {
- QString description = match.captured(1)
- + match.captured(4).trimmed();
- if (!match.captured(1).isEmpty())
- description.chop(1); // Remove trailing quote
- m_lastTask = CompileTask(Task::Unknown, description,
- FilePath::fromUserInput(match.captured(2)), /* fileName */
- match.captured(3).toInt() /* linenumber */);
- m_lines = 1;
- return;
+ const Result res = processCompileLine(line);
+ if (res.status != Status::NotHandled)
+ return res;
+ if (handleNmakeJomMessage(line, &m_lastTask)) {
+ m_lines = 1;
+ return Status::InProgress;
+ }
+ if (match.hasMatch()) {
+ QString description = match.captured(1)
+ + match.captured(4).trimmed();
+ if (!match.captured(1).isEmpty())
+ description.chop(1); // Remove trailing quote
+ const FilePath filePath = absoluteFilePath(FilePath::fromUserInput(match.captured(2)));
+ const int lineNo = match.captured(3).toInt();
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, lineNo, match, 2);
+ m_lastTask = CompileTask(Task::Unknown, description, filePath, lineNo);
+ m_lines = 1;
+ return {Status::InProgress, linkSpecs};
+ }
+ return Status::NotHandled;
}
- IOutputParser::stdOutput(line);
-}
-void MsvcParser::stdError(const QString &line)
-{
- if (processCompileLine(line))
- return;
+ const Result res = processCompileLine(line);
+ if (res.status != Status::NotHandled)
+ return res;
// Jom outputs errors to stderr
if (handleNmakeJomMessage(line, &m_lastTask)) {
m_lines = 1;
- return;
+ return Status::InProgress;
}
- IOutputParser::stdError(line);
+ return Status::NotHandled;
}
-Core::Id MsvcParser::id()
-{
- return Core::Id("ProjectExplorer.OutputParser.Msvc");
-}
-
-bool MsvcParser::processCompileLine(const QString &line)
+MsvcParser::Result MsvcParser::processCompileLine(const QString &line)
{
- doFlush();
+ flush();
QRegularExpressionMatch match = m_compileRegExp.match(line);
if (match.hasMatch()) {
QPair<FilePath, int> position = parseFileName(match.captured(1));
+ const FilePath filePath = absoluteFilePath(position.first);
m_lastTask = CompileTask(taskType(match.captured(2)),
match.captured(3) + match.captured(4).trimmed(), // description
- position.first, position.second);
+ filePath, position.second);
m_lines = 1;
- return true;
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, m_lastTask.file, m_lastTask.line, match, 1);
+ return {Status::InProgress, linkSpecs};
}
- return false;
+ return Status::NotHandled;
}
-void MsvcParser::doFlush()
+void MsvcParser::flush()
{
if (m_lastTask.isNull())
return;
+ setDetailsFormat(m_lastTask);
Task t = m_lastTask;
m_lastTask.clear();
- emit addTask(t, m_lines, 1);
+ scheduleTask(t, m_lines, 1);
}
// --------------------------------------------------------------------------
@@ -212,16 +201,6 @@ ClangClParser::ClangClParser()
QTC_CHECK(m_compileRegExp.isValid());
}
-void ClangClParser::stdOutput(const QString &line)
-{
- if (handleNmakeJomMessage(line, &m_lastTask)) {
- m_linkedLines = 1;
- doFlush();
- return;
- }
- IOutputParser::stdOutput(line);
-}
-
// Check for a code marker '~~~~ ^ ~~~~~~~~~~~~' underlining above code.
static inline bool isClangCodeMarker(const QString &trimmedLine)
{
@@ -230,57 +209,66 @@ static inline bool isClangCodeMarker(const QString &trimmedLine)
[] (QChar c) { return c != ' ' && c != '^' && c != '~'; });
}
-void ClangClParser::stdError(const QString &lineIn)
+OutputLineParser::Result ClangClParser::handleLine(const QString &line, OutputFormat type)
{
- const QString line = IOutputParser::rightTrimmed(lineIn); // Strip \r\n.
+ if (type == StdOutFormat) {
+ if (handleNmakeJomMessage(line, &m_lastTask)) {
+ m_linkedLines = 1;
+ flush();
+ return Status::Done;
+ }
+ return Status::NotHandled;
+ }
+ const QString lne = rightTrimmed(line); // Strip \n.
- if (handleNmakeJomMessage(line, &m_lastTask)) {
+ if (handleNmakeJomMessage(lne, &m_lastTask)) {
m_linkedLines = 1;
- doFlush();
- return;
+ flush();
+ return Status::Done;
}
// Finish a sequence of warnings/errors: "2 warnings generated."
- if (!line.isEmpty() && line.at(0).isDigit() && line.endsWith("generated.")) {
- doFlush();
- return;
+ if (!lne.isEmpty() && lne.at(0).isDigit() && lne.endsWith("generated.")) {
+ flush();
+ return Status::Done;
}
// Start a new error message by a sequence of "In file included from " which is to be skipped.
- if (line.startsWith("In file included from ")) {
- doFlush();
- return;
+ if (lne.startsWith("In file included from ")) {
+ flush();
+ return Status::Done;
}
- QRegularExpressionMatch match = m_compileRegExp.match(line);
+ QRegularExpressionMatch match = m_compileRegExp.match(lne);
if (match.hasMatch()) {
- doFlush();
+ flush();
const QPair<FilePath, int> position = parseFileName(match.captured(1));
m_lastTask = CompileTask(taskType(match.captured(2)), match.captured(3).trimmed(),
- position.first, position.second);
+ absoluteFilePath(position.first), position.second);
m_linkedLines = 1;
- return;
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, m_lastTask.file, m_lastTask.line, match, 1);
+ return {Status::InProgress, linkSpecs};
}
if (!m_lastTask.isNull()) {
- const QString trimmed = line.trimmed();
+ const QString trimmed = lne.trimmed();
if (isClangCodeMarker(trimmed)) {
- doFlush();
- return;
+ flush();
+ return Status::Done;
}
- m_lastTask.description.append('\n');
- m_lastTask.description.append(trimmed);
+ m_lastTask.details.append(trimmed);
++m_linkedLines;
- return;
+ return Status::InProgress;
}
- IOutputParser::stdError(lineIn);
+ return Status::NotHandled;
}
-void ClangClParser::doFlush()
+void ClangClParser::flush()
{
if (!m_lastTask.isNull()) {
- emit addTask(m_lastTask, m_linkedLines, 1);
+ scheduleTask(m_lastTask, m_linkedLines, 1);
m_lastTask.clear();
}
}
@@ -550,7 +538,7 @@ void ProjectExplorerPlugin::testMsvcOutputParsers_data()
void ProjectExplorerPlugin::testMsvcOutputParsers()
{
OutputParserTester testbench;
- testbench.appendOutputParser(new MsvcParser);
+ testbench.addLineParser(new MsvcParser);
QFETCH(QString, input);
QFETCH(OutputParserTester::Channel, inputChannel);
QFETCH(Tasks, tasks);
@@ -639,7 +627,7 @@ void ProjectExplorerPlugin::testClangClOutputParsers_data()
<< "C:\\Program Files\\LLVM\\bin\\clang-cl.exe /nologo /c /EHsc /Od -m64 /Zi /MDd "
"/DUNICODE /D_UNICODE /DWIN32 /FdTestForError.cl.pdb "
"/FoC:\\MyData\\Project_home\\cpp\build-TestForError-msvc_2017_clang-Debug\\Debug_msvc_201_47eca974c876c8b3\\TestForError.b6dd39ae\\3a52ce780950d4d9\\main.cpp.obj "
- "C:\\MyData\\Project_home\\cpp\\TestForError\\main.cpp /TP\r\n"
+ "C:\\MyData\\Project_home\\cpp\\TestForError\\main.cpp /TP\n"
" ;\n"
<< Tasks{CompileTask(Task::Error, "expected ';' after return statement\nreturn 0",
FilePath::fromUserInput("C:\\MyData\\Project_home\\cpp\\TestForError\\main.cpp"),
@@ -650,7 +638,7 @@ void ProjectExplorerPlugin::testClangClOutputParsers_data()
void ProjectExplorerPlugin::testClangClOutputParsers()
{
OutputParserTester testbench;
- testbench.appendOutputParser(new ClangClParser);
+ testbench.addLineParser(new ClangClParser);
QFETCH(QString, input);
QFETCH(OutputParserTester::Channel, inputChannel);
QFETCH(QString, childStdOutLines);
diff --git a/src/plugins/projectexplorer/msvcparser.h b/src/plugins/projectexplorer/msvcparser.h
index d06e176c58..f2b8d47d97 100644
--- a/src/plugins/projectexplorer/msvcparser.h
+++ b/src/plugins/projectexplorer/msvcparser.h
@@ -33,21 +33,20 @@
namespace ProjectExplorer {
-class PROJECTEXPLORER_EXPORT MsvcParser : public ProjectExplorer::IOutputParser
+class PROJECTEXPLORER_EXPORT MsvcParser : public ProjectExplorer::OutputTaskParser
{
Q_OBJECT
public:
MsvcParser();
- void stdOutput(const QString &line) override;
- void stdError(const QString &line) override;
-
static Core::Id id();
private:
- void doFlush() override;
- bool processCompileLine(const QString &line);
+ Result handleLine(const QString &line, Utils::OutputFormat type) override;
+ void flush() override;
+
+ Result processCompileLine(const QString &line);
QRegularExpression m_compileRegExp;
QRegularExpression m_additionalInfoRegExp;
@@ -56,18 +55,16 @@ private:
int m_lines = 0;
};
-class PROJECTEXPLORER_EXPORT ClangClParser : public ProjectExplorer::IOutputParser
+class PROJECTEXPLORER_EXPORT ClangClParser : public ProjectExplorer::OutputTaskParser
{
Q_OBJECT
public:
ClangClParser();
- void stdOutput(const QString &line) override;
- void stdError(const QString &line) override;
-
private:
- void doFlush() override;
+ Result handleLine(const QString &line, Utils::OutputFormat type) override;
+ void flush() override;
const QRegularExpression m_compileRegExp;
Task m_lastTask;
diff --git a/src/plugins/projectexplorer/msvctoolchain.cpp b/src/plugins/projectexplorer/msvctoolchain.cpp
index 9748b52f7f..a2332739bc 100644
--- a/src/plugins/projectexplorer/msvctoolchain.cpp
+++ b/src/plugins/projectexplorer/msvctoolchain.cpp
@@ -67,7 +67,6 @@ using namespace Utils;
static const char varsBatKeyC[] = KEY_ROOT "VarsBat";
static const char varsBatArgKeyC[] = KEY_ROOT "VarsBatArg";
static const char supportedAbiKeyC[] = KEY_ROOT "SupportedAbi";
-static const char supportedAbisKeyC[] = KEY_ROOT "SupportedAbis";
static const char environModsKeyC[] = KEY_ROOT "environmentModifications";
enum { debug = 0 };
@@ -775,55 +774,6 @@ void MsvcToolChain::updateEnvironmentModifications(Utils::EnvironmentItems modif
}
}
-void MsvcToolChain::detectInstalledAbis()
-{
- static QMap<QString, Abis> abiCache;
- const QString vcVarsBase
- = QDir::fromNativeSeparators(m_vcvarsBat).left(m_vcvarsBat.lastIndexOf('/'));
- if (abiCache.contains(vcVarsBase)) {
- m_supportedAbis = abiCache.value(vcVarsBase);
- } else {
- // Clear previously detected m_supportedAbis to repopulate it.
- m_supportedAbis.clear();
- const Abi baseAbi = targetAbi();
- for (MsvcPlatform platform : platforms) {
- bool toolchainInstalled = false;
- QString perhapsVcVarsPath = vcVarsBase + QLatin1Char('/') + QLatin1String(platform.bat);
- const Platform p = platform.platform;
- if (QFileInfo(perhapsVcVarsPath).isFile()) {
- toolchainInstalled = true;
- } else {
- // MSVC 2015 and below had various versions of vcvars scripts in subfolders. Try these
- // as fallbacks.
- perhapsVcVarsPath = vcVarsBase + platform.prefix + QLatin1Char('/')
- + QLatin1String(platform.bat);
- toolchainInstalled = QFileInfo(perhapsVcVarsPath).isFile();
- }
- if (hostSupportsPlatform(platform.platform) && toolchainInstalled) {
- Abi newAbi(archForPlatform(p),
- baseAbi.os(),
- baseAbi.osFlavor(),
- baseAbi.binaryFormat(),
- wordWidthForPlatform(p));
- if (!m_supportedAbis.contains(newAbi))
- m_supportedAbis.append(newAbi);
- }
- }
-
- abiCache.insert(vcVarsBase, m_supportedAbis);
- }
-
- // Always add targetAbi in supportedAbis if it is empty.
- // targetAbi is the abi with which the toolchain was detected.
- // This is necessary for toolchains that don't have vcvars32.bat and the like in their
- // vcVarsBase path, like msvc2010.
- // Also, don't include that one in abiCache to avoid polluting it with values specific
- // to one toolchain as the cache is global for a vcVarsBase path. For this reason, the
- // targetAbi needs to be added manually.
- if (m_supportedAbis.empty())
- m_supportedAbis.append(targetAbi());
-}
-
Utils::Environment MsvcToolChain::readEnvironmentSetting(const Utils::Environment &env) const
{
Utils::Environment resultEnv = env;
@@ -862,7 +812,7 @@ MsvcToolChain::MsvcToolChain(Core::Id typeId)
: ToolChain(typeId)
{
setDisplayName("Microsoft Visual C++ Compiler");
- setTypeDisplayName(MsvcToolChainFactory::tr("MSVC"));
+ setTypeDisplayName(tr("MSVC"));
}
void MsvcToolChain::inferWarningsForLevel(int warningLevel, WarningFlags &flags)
@@ -894,11 +844,6 @@ Abi MsvcToolChain::targetAbi() const
return m_abi;
}
-Abis MsvcToolChain::supportedAbis() const
-{
- return m_supportedAbis;
-}
-
void MsvcToolChain::setTargetAbi(const Abi &abi)
{
m_abi = abi;
@@ -978,7 +923,6 @@ QVariantMap MsvcToolChain::toMap() const
if (!m_varsBatArg.isEmpty())
data.insert(QLatin1String(varsBatArgKeyC), m_varsBatArg);
data.insert(QLatin1String(supportedAbiKeyC), m_abi.toString());
- data.insert(supportedAbisKeyC, Utils::transform<QStringList>(m_supportedAbis, &Abi::toString));
Utils::EnvironmentItem::sort(&m_environmentModifications);
data.insert(QLatin1String(environModsKeyC),
Utils::EnvironmentItem::toVariantList(m_environmentModifications));
@@ -994,14 +938,6 @@ bool MsvcToolChain::fromMap(const QVariantMap &data)
const QString abiString = data.value(QLatin1String(supportedAbiKeyC)).toString();
m_abi = Abi::fromString(abiString);
- const QStringList abiList = data.value(supportedAbisKeyC).toStringList();
- m_supportedAbis.clear();
- for (const QString &a : abiList) {
- Abi abi = Abi::fromString(a);
- if (!abi.isValid())
- continue;
- m_supportedAbis.append(abi);
- }
m_environmentModifications = Utils::EnvironmentItem::itemsFromVariantList(
data.value(QLatin1String(environModsKeyC)).toList());
rescanForCompiler();
@@ -1011,11 +947,7 @@ bool MsvcToolChain::fromMap(const QVariantMap &data)
m_vcvarsBat,
m_varsBatArg));
- // supported Abis were not stored in the map in previous versions of the settings. Re-detect
- if (m_supportedAbis.isEmpty())
- detectInstalledAbis();
-
- const bool valid = !m_vcvarsBat.isEmpty() && m_abi.isValid() && !m_supportedAbis.isEmpty();
+ const bool valid = !m_vcvarsBat.isEmpty() && m_abi.isValid();
if (valid)
addToAvailableMsvcToolchains(this);
@@ -1237,9 +1169,9 @@ void MsvcToolChain::rescanForCompiler()
});
}
-IOutputParser *MsvcToolChain::outputParser() const
+QList<OutputLineParser *> MsvcToolChain::createOutputParsers() const
{
- return new MsvcParser;
+ return {new MsvcParser};
}
void MsvcToolChain::setupVarsBat(const Abi &abi, const QString &varsBat, const QString &varsBatArg)
@@ -1250,7 +1182,6 @@ void MsvcToolChain::setupVarsBat(const Abi &abi, const QString &varsBat, const Q
m_varsBatArg = varsBatArg;
if (!varsBat.isEmpty()) {
- detectInstalledAbis();
initEnvModWatcher(Utils::runAsync(envModThreadPool(),
&MsvcToolChain::environmentModifications,
varsBat,
@@ -1410,34 +1341,66 @@ void MsvcToolChainConfigWidget::setFromMsvcToolChain()
m_abiWidget->setAbis(tc->supportedAbis(), tc->targetAbi());
}
-void MsvcToolChainConfigWidget::handleVcVarsChange(const QString &vcVars)
+void MsvcToolChainConfigWidget::updateAbis()
{
- const QString normalizedVcVars = QDir::fromNativeSeparators(vcVars);
+ const QString normalizedVcVars = QDir::fromNativeSeparators(m_varsBatPathCombo->currentText());
const auto *currentTc = static_cast<const MsvcToolChain *>(toolChain());
QTC_ASSERT(currentTc, return );
const MsvcToolChain::Platform platform = m_varsBatArchCombo->currentData().value<MsvcToolChain::Platform>();
const Abi::Architecture arch = archForPlatform(platform);
const unsigned char wordWidth = wordWidthForPlatform(platform);
+ // Search the selected vcVars bat file in already detected MSVC compilers.
+ // For each variant of MSVC found, add its supported ABIs to the ABI widget so the user can
+ // choose one appropriately.
+ Abis supportedAbis;
+ Abi targetAbi;
for (const MsvcToolChain *tc : g_availableMsvcToolchains) {
if (tc->varsBat() == normalizedVcVars && tc->targetAbi().wordWidth() == wordWidth
- && tc->targetAbi().architecture() == arch) {
- m_abiWidget->setAbis(tc->supportedAbis(), tc->targetAbi());
- break;
+ && tc->targetAbi().architecture() == arch && tc->language() == currentTc->language()) {
+ // We need to filter out duplicates as there might be multiple toolchains with
+ // same abi (like x86, amd64_x86 for example).
+ for (const Abi &abi : tc->supportedAbis()) {
+ if (!supportedAbis.contains(abi))
+ supportedAbis.append(abi);
+ }
+ targetAbi = tc->targetAbi();
+ }
+ }
+
+ // If we didn't find an exact match, try to find a fallback according to varsBat only.
+ // This can happen when the toolchain does not support user-selected arch/wordWidth.
+ if (!targetAbi.isValid()) {
+ const MsvcToolChain *tc = Utils::findOrDefault(g_availableMsvcToolchains,
+ [normalizedVcVars](const MsvcToolChain *tc) {
+ return tc->varsBat() == normalizedVcVars;
+ });
+ if (tc) {
+ targetAbi = Abi(arch,
+ tc->targetAbi().os(),
+ tc->targetAbi().osFlavor(),
+ tc->targetAbi().binaryFormat(),
+ wordWidth);
}
}
+
+ // Always set ABIs, even if none was found, to prevent stale data in the ABI widget.
+ // In that case, a custom ABI will be selected according to targetAbi.
+ m_abiWidget->setAbis(supportedAbis, targetAbi);
+
emit dirty();
}
+void MsvcToolChainConfigWidget::handleVcVarsChange(const QString &)
+{
+ updateAbis();
+}
+
void MsvcToolChainConfigWidget::handleVcVarsArchChange(const QString &)
{
- Abi currentAbi = m_abiWidget->currentAbi();
- const MsvcToolChain::Platform platform = m_varsBatArchCombo->currentData().value<MsvcToolChain::Platform>();
- Abi newAbi(archForPlatform(platform), currentAbi.os(), currentAbi.osFlavor(),
- currentAbi.binaryFormat(), wordWidthForPlatform(platform));
- if (currentAbi != newAbi)
- m_abiWidget->setAbis(m_abiWidget->supportedAbis(), newAbi);
- emit dirty();
+ // supportedAbi list in the widget only contains matching ABIs to whatever arch was selected.
+ // We need to reupdate it from scratch with new arch parameters
+ updateAbis();
}
QString MsvcToolChainConfigWidget::vcVarsArguments() const
@@ -1503,7 +1466,7 @@ void ClangClToolChainConfigWidget::setFromClangClToolChain()
if (clangClToolChain->isAutoDetected())
m_llvmDirLabel->setText(QDir::toNativeSeparators(clangClToolChain->clangPath()));
else
- m_compilerCommand->setFileName(Utils::FilePath::fromString(clangClToolChain->clangPath()));
+ m_compilerCommand->setFilePath(Utils::FilePath::fromString(clangClToolChain->clangPath()));
}
static const MsvcToolChain *findMsvcToolChain(unsigned char wordWidth, Abi::OSFlavor flavor)
@@ -1616,7 +1579,7 @@ static QString compilerFromPath(const QString &path)
void ClangClToolChainConfigWidget::applyImpl()
{
- Utils::FilePath clangClPath = m_compilerCommand->fileName();
+ Utils::FilePath clangClPath = m_compilerCommand->filePath();
auto clangClToolChain = static_cast<ClangClToolChain *>(toolChain());
clangClToolChain->setClangPath(clangClPath.toString());
@@ -1693,9 +1656,9 @@ QStringList ClangClToolChain::suggestedMkspecList() const
return {mkspec, "win32-clang-msvc"};
}
-IOutputParser *ClangClToolChain::outputParser() const
+QList<OutputLineParser *> ClangClToolChain::createOutputParsers() const
{
- return new ClangClParser;
+ return {new ClangClParser};
}
static inline QString llvmDirKey()
@@ -1784,7 +1747,7 @@ ClangClToolChain::BuiltInHeaderPathsRunner ClangClToolChain::createBuiltInHeader
MsvcToolChainFactory::MsvcToolChainFactory()
{
- setDisplayName(tr("MSVC"));
+ setDisplayName(MsvcToolChain::tr("MSVC"));
setSupportedToolChainType(Constants::MSVC_TOOLCHAIN_TYPEID);
setSupportedLanguages({Constants::C_LANGUAGE_ID, Constants::CXX_LANGUAGE_ID});
setToolchainConstructor([] { return new MsvcToolChain(Constants::MSVC_TOOLCHAIN_TYPEID); });
@@ -1966,7 +1929,7 @@ QList<ToolChain *> MsvcToolChainFactory::autoDetect(const QList<ToolChain *> &al
ClangClToolChainFactory::ClangClToolChainFactory()
{
- setDisplayName(tr("clang-cl"));
+ setDisplayName(ClangClToolChain::tr("clang-cl"));
setSupportedLanguages({Constants::C_LANGUAGE_ID, Constants::CXX_LANGUAGE_ID});
setSupportedToolChainType(Constants::CLANG_CL_TOOLCHAIN_TYPEID);
setToolchainConstructor([] { return new ClangClToolChain; });
diff --git a/src/plugins/projectexplorer/msvctoolchain.h b/src/plugins/projectexplorer/msvctoolchain.h
index b224b4b68b..7731598cb1 100644
--- a/src/plugins/projectexplorer/msvctoolchain.h
+++ b/src/plugins/projectexplorer/msvctoolchain.h
@@ -53,6 +53,8 @@ namespace Internal {
class MsvcToolChain : public ToolChain
{
+ Q_DECLARE_TR_FUNCTIONS(ProjectExplorer::Internal::MsvcToolChain)
+
public:
enum Type { WindowsSDK, VS };
enum Platform { x86, amd64, x86_amd64, ia64, x86_ia64, arm, x86_arm, amd64_arm, amd64_x86 };
@@ -61,7 +63,6 @@ public:
~MsvcToolChain() override;
Abi targetAbi() const override;
- Abis supportedAbis() const override;
void setTargetAbi(const Abi &abi);
bool isValid() const override;
@@ -88,7 +89,7 @@ public:
Utils::FilePath makeCommand(const Utils::Environment &environment) const override;
Utils::FilePath compilerCommand() const override;
- IOutputParser *outputParser() const override;
+ QList<Utils::OutputLineParser *> createOutputParsers() const override;
QString varsBatArg() const { return m_varsBatArg; }
QString varsBat() const { return m_vcvarsBat; }
@@ -146,7 +147,6 @@ protected:
private:
void updateEnvironmentModifications(Utils::EnvironmentItems modifications);
void rescanForCompiler();
- void detectInstalledAbis();
mutable Utils::EnvironmentItems m_environmentModifications;
mutable QFutureWatcher<GenerateEnvResult> m_envModWatcher;
@@ -158,7 +158,6 @@ private:
protected:
Abi m_abi;
- Abis m_supportedAbis;
QString m_vcvarsBat;
QString m_varsBatArg; // Argument
@@ -166,6 +165,8 @@ protected:
class PROJECTEXPLORER_EXPORT ClangClToolChain : public MsvcToolChain
{
+ Q_DECLARE_TR_FUNCTIONS(ProjectExplorer::Internal::ClangClToolChain)
+
public:
ClangClToolChain();
@@ -173,7 +174,7 @@ public:
QStringList suggestedMkspecList() const override;
void addToEnvironment(Utils::Environment &env) const override;
Utils::FilePath compilerCommand() const override;
- IOutputParser *outputParser() const override;
+ QList<Utils::OutputLineParser *> createOutputParsers() const override;
QVariantMap toMap() const override;
bool fromMap(const QVariantMap &data) override;
std::unique_ptr<ToolChainConfigWidget> createConfigurationWidget() override;
@@ -202,8 +203,6 @@ private:
class MsvcToolChainFactory : public ToolChainFactory
{
- Q_OBJECT
-
public:
MsvcToolChainFactory();
@@ -218,8 +217,6 @@ public:
class ClangClToolChainFactory : public ToolChainFactory
{
- Q_OBJECT
-
public:
ClangClToolChainFactory();
@@ -271,6 +268,7 @@ private:
void setFromMsvcToolChain();
+ void updateAbis();
void handleVcVarsChange(const QString &vcVars);
void handleVcVarsArchChange(const QString &arch);
diff --git a/src/plugins/projectexplorer/osparser.cpp b/src/plugins/projectexplorer/osparser.cpp
index 6fffa257a5..9a1f11a0ba 100644
--- a/src/plugins/projectexplorer/osparser.cpp
+++ b/src/plugins/projectexplorer/osparser.cpp
@@ -36,31 +36,30 @@ OsParser::OsParser()
setObjectName(QLatin1String("OsParser"));
}
-void OsParser::stdError(const QString &line)
+Utils::OutputLineParser::Result OsParser::handleLine(const QString &line, Utils::OutputFormat type)
{
- if (Utils::HostOsInfo::isLinuxHost()) {
- const QString trimmed = line.trimmed();
- if (trimmed.contains(QLatin1String(": error while loading shared libraries:")))
- emit addTask(CompileTask(Task::Error, trimmed));
+ if (type == Utils::StdOutFormat) {
+ if (Utils::HostOsInfo::isWindowsHost()) {
+ const QString trimmed = line.trimmed();
+ if (trimmed == QLatin1String("The process cannot access the file because it is "
+ "being used by another process.")) {
+ scheduleTask(CompileTask(Task::Error, tr(
+ "The process cannot access the file because it is being used "
+ "by another process.\n"
+ "Please close all running instances of your application before "
+ "starting a build.")), 1);
+ m_hasFatalError = true;
+ return Status::Done;
+ }
+ }
+ return Status::NotHandled;
}
- IOutputParser::stdError(line);
-}
-
-void OsParser::stdOutput(const QString &line)
-{
- if (Utils::HostOsInfo::isWindowsHost()) {
+ if (Utils::HostOsInfo::isLinuxHost()) {
const QString trimmed = line.trimmed();
- if (trimmed == QLatin1String("The process cannot access the file because it is being used by another process.")) {
- emit addTask(CompileTask(Task::Error, tr(
- "The process cannot access the file because it is being used by another process.\n"
- "Please close all running instances of your application before starting a build.")));
- m_hasFatalError = true;
+ if (trimmed.contains(QLatin1String(": error while loading shared libraries:"))) {
+ scheduleTask(CompileTask(Task::Error, trimmed), 1);
+ return Status::Done;
}
}
- IOutputParser::stdOutput(line);
-}
-
-bool OsParser::hasFatalErrors() const
-{
- return m_hasFatalError || IOutputParser::hasFatalErrors();
+ return Status::NotHandled;
}
diff --git a/src/plugins/projectexplorer/osparser.h b/src/plugins/projectexplorer/osparser.h
index a053a65a73..d3e97eee6e 100644
--- a/src/plugins/projectexplorer/osparser.h
+++ b/src/plugins/projectexplorer/osparser.h
@@ -33,19 +33,17 @@
namespace ProjectExplorer {
-class PROJECTEXPLORER_EXPORT OsParser : public ProjectExplorer::IOutputParser
+class PROJECTEXPLORER_EXPORT OsParser : public ProjectExplorer::OutputTaskParser
{
Q_OBJECT
public:
OsParser();
- void stdError(const QString &line) override;
- void stdOutput(const QString &line) override;
-
- bool hasFatalErrors() const override;
-
private:
+ Result handleLine(const QString &line, Utils::OutputFormat type) override;
+ bool hasFatalErrors() const override { return m_hasFatalError; }
+
bool m_hasFatalError = false;
};
diff --git a/src/plugins/projectexplorer/outputparser_test.cpp b/src/plugins/projectexplorer/outputparser_test.cpp
index 17834ff5c8..99d241bf13 100644
--- a/src/plugins/projectexplorer/outputparser_test.cpp
+++ b/src/plugins/projectexplorer/outputparser_test.cpp
@@ -24,7 +24,9 @@
****************************************************************************/
#include "outputparser_test.h"
+#include "projectexplorer.h"
#include "task.h"
+#include "taskhub.h"
#if defined(WITH_TESTS)
@@ -38,9 +40,19 @@ static inline QByteArray msgFileComparisonFail(const Utils::FilePath &f1, const
return result.toLocal8Bit();
}
-OutputParserTester::OutputParserTester() = default;
-
// test functions:
+OutputParserTester::OutputParserTester()
+{
+ connect(TaskHub::instance(), &TaskHub::taskAdded, this, [this](const Task &t) {
+ m_receivedTasks.append(t);
+ });
+}
+
+OutputParserTester::~OutputParserTester()
+{
+ TaskHub::instance()->disconnect(this);
+}
+
void OutputParserTester::testParsing(const QString &lines,
Channel inputChannel,
Tasks tasks,
@@ -48,31 +60,21 @@ void OutputParserTester::testParsing(const QString &lines,
const QString &childStdErrLines,
const QString &outputLines)
{
+ const auto terminator = new TestTerminator(this);
+ if (!lineParsers().isEmpty())
+ terminator->setRedirectionDetector(lineParsers().last());
+ addLineParser(terminator);
reset();
- Q_ASSERT(childParser());
-
- const QStringList inputLines = lines.split('\n');
- for (const QString &input : inputLines) {
- if (inputChannel == STDOUT)
- childParser()->stdOutput(input + '\n');
- else
- childParser()->stdError(input + '\n');
- }
- childParser()->flush();
-
- // first disconnect ourselves from the end of the parser chain again
- IOutputParser *parser = this;
- while ( (parser = parser->childParser()) ) {
- if (parser->childParser() == this) {
- childParser()->takeOutputParserChain();
- break;
- }
- }
- parser = nullptr;
- emit aboutToDeleteParser();
- // then delete the parser(s) to test
- setChildParser(nullptr);
+ if (inputChannel == STDOUT)
+ appendMessage(lines + '\n', Utils::StdOutFormat);
+ else
+ appendMessage(lines + '\n', Utils::StdErrFormat);
+ flush();
+
+ // delete the parser(s) to test
+ emit aboutToDeleteParser();
+ setLineParsers({});
QCOMPARE(m_receivedOutput, outputLines);
QCOMPARE(m_receivedStdErrChildLine, childStdErrLines);
@@ -81,7 +83,7 @@ void OutputParserTester::testParsing(const QString &lines,
if (m_receivedTasks.size() == tasks.size()) {
for (int i = 0; i < tasks.size(); ++i) {
QCOMPARE(m_receivedTasks.at(i).category, tasks.at(i).category);
- QCOMPARE(m_receivedTasks.at(i).description, tasks.at(i).description);
+ QCOMPARE(m_receivedTasks.at(i).description(), tasks.at(i).description());
QVERIFY2(m_receivedTasks.at(i).file == tasks.at(i).file,
msgFileComparisonFail(m_receivedTasks.at(i).file, tasks.at(i).file));
QCOMPARE(m_receivedTasks.at(i).line, tasks.at(i).line);
@@ -90,66 +92,11 @@ void OutputParserTester::testParsing(const QString &lines,
}
}
-void OutputParserTester::testTaskMangling(const Task &input,
- const Task &output)
-{
- reset();
- childParser()->taskAdded(input);
-
- QVERIFY(m_receivedOutput.isNull());
- QVERIFY(m_receivedStdErrChildLine.isNull());
- QVERIFY(m_receivedStdOutChildLine.isNull());
- QVERIFY(m_receivedTasks.size() == 1);
- if (m_receivedTasks.size() == 1) {
- QCOMPARE(m_receivedTasks.at(0).category, output.category);
- QCOMPARE(m_receivedTasks.at(0).description, output.description);
- QVERIFY2(m_receivedTasks.at(0).file == output.file,
- msgFileComparisonFail(m_receivedTasks.at(0).file, output.file));
- QCOMPARE(m_receivedTasks.at(0).line, output.line);
- QCOMPARE(m_receivedTasks.at(0).type, output.type);
- }
-}
-
-void OutputParserTester::testOutputMangling(const QString &input,
- const QString &output)
-{
- reset();
-
- childParser()->outputAdded(input, BuildStep::OutputFormat::Stdout);
-
- QCOMPARE(m_receivedOutput, output);
- QVERIFY(m_receivedStdErrChildLine.isNull());
- QVERIFY(m_receivedStdOutChildLine.isNull());
- QVERIFY(m_receivedTasks.isEmpty());
-}
-
void OutputParserTester::setDebugEnabled(bool debug)
{
m_debug = debug;
}
-void OutputParserTester::appendOutputParser(IOutputParser *parser)
-{
- Q_ASSERT(!childParser());
- parser->appendOutputParser(new TestTerminator(this));
- IOutputParser::appendOutputParser(parser);
-}
-
-void OutputParserTester::outputAdded(const QString &line, BuildStep::OutputFormat format)
-{
- Q_UNUSED(format)
- if (!m_receivedOutput.isEmpty())
- m_receivedOutput.append('\n');
- m_receivedOutput.append(line);
-}
-
-void OutputParserTester::taskAdded(const Task &task, int linkedLines, int skipLines)
-{
- Q_UNUSED(linkedLines)
- Q_UNUSED(skipLines)
- m_receivedTasks.append(task);
-}
-
void OutputParserTester::reset()
{
m_receivedStdErrChildLine.clear();
@@ -162,16 +109,72 @@ TestTerminator::TestTerminator(OutputParserTester *t) :
m_tester(t)
{ }
-void TestTerminator::stdOutput(const QString &line)
+Utils::OutputLineParser::Result TestTerminator::handleLine(const QString &line, Utils::OutputFormat type)
+{
+ QTC_CHECK(line.endsWith('\n'));
+ if (type == Utils::StdOutFormat)
+ m_tester->m_receivedStdOutChildLine.append(line);
+ else
+ m_tester->m_receivedStdErrChildLine.append(line);
+ return Status::Done;
+}
+
+void ProjectExplorerPlugin::testAnsiFilterOutputParser_data()
{
- QVERIFY(line.endsWith('\n'));
- m_tester->m_receivedStdOutChildLine.append(line);
+ QTest::addColumn<QString>("input");
+ QTest::addColumn<OutputParserTester::Channel>("inputChannel");
+ QTest::addColumn<QString>("childStdOutLines");
+ QTest::addColumn<QString>("childStdErrLines");
+ QTest::addColumn<QString>("outputLines");
+
+ QTest::newRow("pass-through stdout")
+ << QString::fromLatin1("Sometext") << OutputParserTester::STDOUT
+ << QString::fromLatin1("Sometext\n") << QString();
+ QTest::newRow("pass-through stderr")
+ << QString::fromLatin1("Sometext") << OutputParserTester::STDERR
+ << QString() << QString::fromLatin1("Sometext\n");
+
+ QString input = QString::fromLatin1("te") + QChar(27) + QString::fromLatin1("Nst");
+ QTest::newRow("ANSI: ESC-N")
+ << input << OutputParserTester::STDOUT
+ << QString::fromLatin1("test\n") << QString();
+ input = QString::fromLatin1("te") + QChar(27) + QLatin1String("^ignored") + QChar(27) + QLatin1String("\\st");
+ QTest::newRow("ANSI: ESC-^ignoredESC-\\")
+ << input << OutputParserTester::STDOUT
+ << QString::fromLatin1("test\n") << QString();
+ input = QString::fromLatin1("te") + QChar(27) + QLatin1String("]0;ignored") + QChar(7) + QLatin1String("st");
+ QTest::newRow("ANSI: window title change")
+ << input << OutputParserTester::STDOUT
+ << QString::fromLatin1("test\n") << QString();
+ input = QString::fromLatin1("te") + QChar(27) + QLatin1String("[Ast");
+ QTest::newRow("ANSI: cursor up")
+ << input << OutputParserTester::STDOUT
+ << QString::fromLatin1("test\n") << QString();
+ input = QString::fromLatin1("te") + QChar(27) + QLatin1String("[2Ast");
+ QTest::newRow("ANSI: cursor up (with int parameter)")
+ << input << OutputParserTester::STDOUT
+ << QString::fromLatin1("test\n") << QString();
+ input = QString::fromLatin1("te") + QChar(27) + QLatin1String("[2;3Hst");
+ QTest::newRow("ANSI: position cursor")
+ << input << OutputParserTester::STDOUT
+ << QString::fromLatin1("test\n") << QString();
+ input = QString::fromLatin1("te") + QChar(27) + QLatin1String("[31;1mst");
+ QTest::newRow("ANSI: bold red")
+ << input << OutputParserTester::STDOUT
+ << QString::fromLatin1("test\n") << QString();
}
-void TestTerminator::stdError(const QString &line)
+void ProjectExplorerPlugin::testAnsiFilterOutputParser()
{
- QVERIFY(line.endsWith('\n'));
- m_tester->m_receivedStdErrChildLine.append(line);
+ OutputParserTester testbench;
+ QFETCH(QString, input);
+ QFETCH(OutputParserTester::Channel, inputChannel);
+ QFETCH(QString, childStdOutLines);
+ QFETCH(QString, childStdErrLines);
+
+ testbench.testParsing(input, inputChannel,
+ Tasks(), childStdOutLines, childStdErrLines,
+ QString());
}
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/outputparser_test.h b/src/plugins/projectexplorer/outputparser_test.h
index 43920d0ebf..b41b9a1f87 100644
--- a/src/plugins/projectexplorer/outputparser_test.h
+++ b/src/plugins/projectexplorer/outputparser_test.h
@@ -36,7 +36,7 @@ namespace ProjectExplorer {
class TestTerminator;
-class PROJECTEXPLORER_EXPORT OutputParserTester : public IOutputParser
+class PROJECTEXPLORER_EXPORT OutputParserTester : public Utils::OutputFormatter
{
Q_OBJECT
@@ -47,6 +47,7 @@ public:
};
OutputParserTester();
+ ~OutputParserTester();
// test functions:
void testParsing(const QString &lines, Channel inputChannel,
@@ -54,22 +55,13 @@ public:
const QString &childStdOutLines,
const QString &childStdErrLines,
const QString &outputLines);
- void testTaskMangling(const Task &input,
- const Task &output);
- void testOutputMangling(const QString &input,
- const QString &output);
void setDebugEnabled(bool);
- void appendOutputParser(IOutputParser *parser) override;
-
signals:
void aboutToDeleteParser();
private:
- void outputAdded(const QString &string, ProjectExplorer::BuildStep::OutputFormat format) override;
- void taskAdded(const ProjectExplorer::Task &task, int linkedLines, int skipLines) override;
-
void reset();
bool m_debug = false;
@@ -82,17 +74,16 @@ private:
friend class TestTerminator;
};
-class TestTerminator : public IOutputParser
+class TestTerminator : public OutputTaskParser
{
Q_OBJECT
public:
TestTerminator(OutputParserTester *t);
- void stdOutput(const QString &line) override;
- void stdError(const QString &line) override;
-
private:
+ Result handleLine(const QString &line, Utils::OutputFormat type) override;
+
OutputParserTester *m_tester = nullptr;
};
diff --git a/src/plugins/projectexplorer/panelswidget.cpp b/src/plugins/projectexplorer/panelswidget.cpp
index 7e7b22eacb..488390e822 100644
--- a/src/plugins/projectexplorer/panelswidget.cpp
+++ b/src/plugins/projectexplorer/panelswidget.cpp
@@ -25,15 +25,18 @@
#include "panelswidget.h"
-#include <QPainter>
-#include <QVBoxLayout>
-#include <QLabel>
+#include <coreplugin/minisplitter.h>
#include <utils/stylehelper.h>
#include <utils/theme/theme.h>
#include <utils/qtcassert.h>
#include <utils/styledbar.h>
+#include <QLabel>
+#include <QPainter>
+#include <QScrollArea>
+#include <QVBoxLayout>
+
using namespace Utils;
namespace ProjectExplorer {
@@ -46,53 +49,27 @@ const int ABOVE_CONTENTS_MARGIN = 4;
const int BELOW_CONTENTS_MARGIN = 16;
const int PANEL_LEFT_MARGIN = 70;
-class RootWidget : public QWidget
-{
-public:
- RootWidget(QWidget *parent) : QWidget(parent) {
- setFocusPolicy(Qt::NoFocus);
- }
- void paintEvent(QPaintEvent *) override;
-};
-
-void RootWidget::paintEvent(QPaintEvent *e)
-{
- QWidget::paintEvent(e);
-
- if (!creatorTheme()->flag(Theme::FlatToolBars)) {
- // draw separator line to the right of the settings panel
- QPainter painter(this);
- QColor light = StyleHelper::mergedColors(
- palette().button().color(), Qt::white, 30);
- QColor dark = StyleHelper::mergedColors(
- palette().button().color(), Qt::black, 85);
-
- painter.setPen(light);
- painter.drawLine(rect().topRight(), rect().bottomRight());
- painter.setPen(dark);
- painter.drawLine(rect().topRight() - QPoint(1,0), rect().bottomRight() - QPoint(1,0));
- }
-}
}
///
// PanelsWidget
///
-PanelsWidget::PanelsWidget(QWidget *parent) :
- QWidget(parent),
- m_root(new RootWidget(this))
+PanelsWidget::PanelsWidget(QWidget *parent) : QWidget(parent)
{
- // We want a 900px wide widget with and the scrollbar at the
- // side of the screen.
- m_root->setMaximumWidth(900);
+ const auto splitter = new Core::MiniSplitter(this);
+ m_root = new QWidget(nullptr);
+ m_root->setFocusPolicy(Qt::NoFocus);
m_root->setContentsMargins(0, 0, 40, 0);
+ splitter->addWidget(m_root);
+ splitter->addWidget(new QWidget);
+ splitter->setStretchFactor(1, 100); // Force root widget to its minimum size initially
- m_scroller = new QScrollArea(this);
- m_scroller->setWidget(m_root);
- m_scroller->setFrameStyle(QFrame::NoFrame);
- m_scroller->setWidgetResizable(true);
- m_scroller->setFocusPolicy(Qt::NoFocus);
+ const auto scroller = new QScrollArea(this);
+ scroller->setWidget(splitter);
+ scroller->setFrameStyle(QFrame::NoFrame);
+ scroller->setWidgetResizable(true);
+ scroller->setFocusPolicy(Qt::NoFocus);
// The layout holding the individual panels:
auto topLayout = new QVBoxLayout(m_root);
@@ -110,7 +87,7 @@ PanelsWidget::PanelsWidget(QWidget *parent) :
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(0);
layout->addWidget(new Utils::StyledBar(this));
- layout->addWidget(m_scroller);
+ layout->addWidget(scroller);
//layout->addWidget(new FindToolBarPlaceHolder(this));
}
diff --git a/src/plugins/projectexplorer/panelswidget.h b/src/plugins/projectexplorer/panelswidget.h
index 52cd593508..1be7723aaa 100644
--- a/src/plugins/projectexplorer/panelswidget.h
+++ b/src/plugins/projectexplorer/panelswidget.h
@@ -27,7 +27,7 @@
#include "projectexplorer_export.h"
-#include <QScrollArea>
+#include <QWidget>
QT_BEGIN_NAMESPACE
class QGridLayout;
@@ -51,7 +51,6 @@ public:
private:
QGridLayout *m_layout;
- QScrollArea *m_scroller;
QWidget *m_root;
};
diff --git a/src/plugins/projectexplorer/parseissuesdialog.cpp b/src/plugins/projectexplorer/parseissuesdialog.cpp
index 7b0d3758e6..5a53574d93 100644
--- a/src/plugins/projectexplorer/parseissuesdialog.cpp
+++ b/src/plugins/projectexplorer/parseissuesdialog.cpp
@@ -136,13 +136,13 @@ ParseIssuesDialog::~ParseIssuesDialog()
}
static void parse(QFutureInterface<void> &future, const QString &output,
- const std::unique_ptr<IOutputParser> &parser, bool isStderr)
+ const std::unique_ptr<Utils::OutputFormatter> &parser, bool isStderr)
{
const QStringList lines = output.split('\n');
future.setProgressRange(0, lines.count());
- const auto parserFunc = isStderr ? &IOutputParser::stdError : &IOutputParser::stdOutput;
+ const Utils::OutputFormat format = isStderr ? Utils::StdErrFormat : Utils::StdOutFormat;
for (const QString &line : lines) {
- (parser.get()->*parserFunc)(line);
+ parser->appendMessage(line + '\n', format);
future.setProgressValue(future.progressValue() + 1);
if (future.isCanceled())
return;
@@ -151,15 +151,17 @@ static void parse(QFutureInterface<void> &future, const QString &output,
void ParseIssuesDialog::accept()
{
- std::unique_ptr<IOutputParser> parser(d->kitChooser.currentKit()->createOutputParser());
- if (!parser) {
+ const QList<Utils::OutputLineParser *> lineParsers =
+ d->kitChooser.currentKit()->createOutputParsers();
+ if (lineParsers.isEmpty()) {
QMessageBox::critical(this, tr("Cannot Parse"), tr("Cannot parse: The chosen kit does "
"not provide an output parser."));
return;
}
+ std::unique_ptr<Utils::OutputFormatter> parser(new Utils::OutputFormatter);
+ parser->setLineParsers(lineParsers);
if (d->clearTasksCheckBox.isChecked())
TaskHub::clearTasks();
- connect(parser.get(), &IOutputParser::addTask, [](const Task &t) { TaskHub::addTask(t); });
const QFuture<void> f = Utils::runAsync(&parse, d->compileOutputEdit.toPlainText(),
std::move(parser), d->stderrCheckBox.isChecked());
Core::ProgressManager::addTask(f, tr("Parsing build output"),
diff --git a/src/plugins/projectexplorer/processstep.cpp b/src/plugins/projectexplorer/processstep.cpp
index c061eee1c1..035b816ff0 100644
--- a/src/plugins/projectexplorer/processstep.cpp
+++ b/src/plugins/projectexplorer/processstep.cpp
@@ -24,28 +24,44 @@
****************************************************************************/
#include "processstep.h"
+
+#include "abstractprocessstep.h"
#include "buildconfiguration.h"
-#include "buildstep.h"
#include "kit.h"
#include "processparameters.h"
+#include "projectconfigurationaspects.h"
#include "projectexplorerconstants.h"
+#include "projectexplorer_export.h"
#include "target.h"
-#include <coreplugin/variablechooser.h>
-
#include <utils/fileutils.h>
-#include <utils/macroexpander.h>
-
-#include <QFormLayout>
+#include <utils/outputformatter.h>
using namespace Utils;
namespace ProjectExplorer {
+namespace Internal {
const char PROCESS_COMMAND_KEY[] = "ProjectExplorer.ProcessStep.Command";
const char PROCESS_WORKINGDIRECTORY_KEY[] = "ProjectExplorer.ProcessStep.WorkingDirectory";
const char PROCESS_ARGUMENTS_KEY[] = "ProjectExplorer.ProcessStep.Arguments";
+class ProcessStep final : public AbstractProcessStep
+{
+ Q_DECLARE_TR_FUNCTIONS(ProjectExplorer::ProcessStep)
+
+public:
+ ProcessStep(BuildStepList *bsl, Core::Id id);
+
+ bool init() final;
+ void setupOutputFormatter(Utils::OutputFormatter *formatter);
+ void setupProcessParameters(ProcessParameters *pp);
+
+ BaseStringAspect *m_command;
+ BaseStringAspect *m_arguments;
+ BaseStringAspect *m_workingDirectory;
+};
+
ProcessStep::ProcessStep(BuildStepList *bsl, Core::Id id)
: AbstractProcessStep(bsl, id)
{
@@ -86,32 +102,29 @@ ProcessStep::ProcessStep(BuildStepList *bsl, Core::Id id)
bool ProcessStep::init()
{
setupProcessParameters(processParameters());
- setOutputParser(target()->kit()->createOutputParser());
return AbstractProcessStep::init();
}
-void ProcessStep::setupProcessParameters(ProcessParameters *pp)
+void ProcessStep::setupOutputFormatter(OutputFormatter *formatter)
{
- BuildConfiguration *bc = buildConfiguration();
+ formatter->addLineParsers(target()->kit()->createOutputParsers());
+ AbstractProcessStep::setupOutputFormatter(formatter);
+}
+void ProcessStep::setupProcessParameters(ProcessParameters *pp)
+{
QString workingDirectory = m_workingDirectory->value();
- if (workingDirectory.isEmpty()) {
- if (bc)
- workingDirectory = Constants::DEFAULT_WORKING_DIR;
- else
- workingDirectory = Constants::DEFAULT_WORKING_DIR_ALTERNATE;
- }
-
- pp->setMacroExpander(bc ? bc->macroExpander() : Utils::globalMacroExpander());
- pp->setEnvironment(bc ? bc->environment() : Utils::Environment::systemEnvironment());
- pp->setWorkingDirectory(Utils::FilePath::fromString(workingDirectory));
+ if (workingDirectory.isEmpty())
+ workingDirectory = fallbackWorkingDirectory();
+
+ pp->setMacroExpander(macroExpander());
+ pp->setEnvironment(buildEnvironment());
+ pp->setWorkingDirectory(FilePath::fromString(workingDirectory));
pp->setCommandLine({m_command->filePath(), m_arguments->value(), CommandLine::Raw});
pp->resolveAll();
}
-//*******
// ProcessStepFactory
-//*******
ProcessStepFactory::ProcessStepFactory()
{
@@ -119,4 +132,5 @@ ProcessStepFactory::ProcessStepFactory()
setDisplayName(ProcessStep::tr("Custom Process Step", "item in combobox"));
}
+} // Internal
} // ProjectExplorer
diff --git a/src/plugins/projectexplorer/processstep.h b/src/plugins/projectexplorer/processstep.h
index 95f0f49a22..964f0685db 100644
--- a/src/plugins/projectexplorer/processstep.h
+++ b/src/plugins/projectexplorer/processstep.h
@@ -25,33 +25,16 @@
#pragma once
-#include "abstractprocessstep.h"
-#include "projectconfigurationaspects.h"
-#include "projectexplorer_export.h"
+#include "buildstep.h"
namespace ProjectExplorer {
+namespace Internal {
-class ProcessStepFactory : public BuildStepFactory
+class ProcessStepFactory final : public BuildStepFactory
{
public:
ProcessStepFactory();
};
-class PROJECTEXPLORER_EXPORT ProcessStep : public AbstractProcessStep
-{
- Q_OBJECT
- friend class ProcessStepFactory;
-
-public:
- ProcessStep(BuildStepList *bsl, Core::Id id);
-
-private:
- bool init() override;
- void setupProcessParameters(ProcessParameters *pp);
-
- ProjectExplorer::BaseStringAspect *m_command;
- ProjectExplorer::BaseStringAspect *m_arguments;
- ProjectExplorer::BaseStringAspect *m_workingDirectory;
-};
-
+} // namespace Internal
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/project.cpp b/src/plugins/projectexplorer/project.cpp
index e7e6599ed9..7376ecd6ea 100644
--- a/src/plugins/projectexplorer/project.cpp
+++ b/src/plugins/projectexplorer/project.cpp
@@ -31,6 +31,7 @@
#include "deployconfiguration.h"
#include "editorconfiguration.h"
#include "kit.h"
+#include "kitinformation.h"
#include "makestep.h"
#include "projectexplorer.h"
#include "projectmacroexpander.h"
@@ -39,6 +40,7 @@
#include "runcontrol.h"
#include "session.h"
#include "target.h"
+#include "taskhub.h"
#include "userfileaccessor.h"
#include <coreplugin/idocument.h>
@@ -57,6 +59,7 @@
#include <utils/macroexpander.h>
#include <utils/pointeralgorithm.h>
#include <utils/qtcassert.h>
+#include <utils/stringutils.h>
#include <QFileDialog>
@@ -757,8 +760,22 @@ void Project::createTargetFromMap(const QVariantMap &map, int index)
Kit *k = KitManager::kit(id);
if (!k) {
- qWarning("Warning: No kit '%s' found. Continuing.", qPrintable(id.toString()));
- return;
+ Core::Id deviceTypeId = Core::Id::fromSetting(targetMap.value(Target::deviceTypeKey()));
+ if (!deviceTypeId.isValid())
+ deviceTypeId = Constants::DESKTOP_DEVICE_TYPE;
+ const QString formerKitName = targetMap.value(Target::displayNameKey()).toString();
+ k = KitManager::registerKit([deviceTypeId, &formerKitName](Kit *kit) {
+ const QString tempKitName = Utils::makeUniquelyNumbered(
+ tr("Replacement for \"%1\"").arg(formerKitName),
+ Utils::transform(KitManager::kits(), &Kit::unexpandedDisplayName));
+ kit->setUnexpandedDisplayName(tempKitName);
+ DeviceTypeKitAspect::setDeviceTypeId(kit, deviceTypeId);
+ kit->setup();
+ }, id);
+ TaskHub::addTask(BuildSystemTask(Task::Warning, tr("Project \"%1\" was configured for "
+ "kit \"%2\" with id %3, which does not exist anymore. The new kit \"%4\" was "
+ "created in its place, in an attempt not to lose custom project settings.")
+ .arg(displayName(), formerKitName, id.toString(), k->displayName())));
}
auto t = std::make_unique<Target>(this, k, Target::_constructor_tag{});
diff --git a/src/plugins/projectexplorer/project.h b/src/plugins/projectexplorer/project.h
index b6b65e6889..4974e64297 100644
--- a/src/plugins/projectexplorer/project.h
+++ b/src/plugins/projectexplorer/project.h
@@ -51,12 +51,10 @@ namespace ProjectExplorer {
class BuildInfo;
class BuildSystem;
-class BuildConfiguration;
class ContainerNode;
class EditorConfiguration;
class FolderNode;
class Node;
-class ProjectConfiguration;
class ProjectImporter;
class ProjectNode;
class ProjectPrivate;
@@ -183,9 +181,6 @@ signals:
// Note: activeTarget can be 0 (if no targets are defined).
void activeTargetChanged(ProjectExplorer::Target *target);
- void removedProjectConfiguration(ProjectExplorer::ProjectConfiguration *pc);
- void addedProjectConfiguration(ProjectExplorer::ProjectConfiguration *pc);
-
void aboutToRemoveTarget(ProjectExplorer::Target *target);
void removedTarget(ProjectExplorer::Target *target);
void addedTarget(ProjectExplorer::Target *target);
diff --git a/src/plugins/projectexplorer/projectconfiguration.h b/src/plugins/projectexplorer/projectconfiguration.h
index 3702655e16..0aa0e9f85e 100644
--- a/src/plugins/projectexplorer/projectconfiguration.h
+++ b/src/plugins/projectexplorer/projectconfiguration.h
@@ -29,7 +29,6 @@
#include <coreplugin/id.h>
#include <utils/displayname.h>
-#include <utils/macroexpander.h>
#include <QObject>
#include <QPointer>
@@ -188,9 +187,6 @@ public:
// Note: Make sure subclasses call the superclasses' toMap() function!
virtual QVariantMap toMap() const;
- Utils::MacroExpander *macroExpander() { return &m_macroExpander; }
- const Utils::MacroExpander *macroExpander() const { return &m_macroExpander; }
-
Target *target() const;
Project *project() const;
@@ -221,7 +217,6 @@ private:
const Core::Id m_id;
Utils::DisplayName m_displayName;
QString m_toolTip;
- Utils::MacroExpander m_macroExpander;
};
// helper function:
diff --git a/src/plugins/projectexplorer/projectconfigurationaspects.cpp b/src/plugins/projectexplorer/projectconfigurationaspects.cpp
index 588318de59..2a39634ad9 100644
--- a/src/plugins/projectexplorer/projectconfigurationaspects.cpp
+++ b/src/plugins/projectexplorer/projectconfigurationaspects.cpp
@@ -107,8 +107,10 @@ public:
Utils::MacroExpanderProvider m_expanderProvider;
QPixmap m_labelPixmap;
Utils::FilePath m_baseFileName;
+ BaseStringAspect::ValueAcceptor m_valueAcceptor;
bool m_readOnly = false;
bool m_showToolTipOnLabel = false;
+ bool m_fileDialogOnly = false;
template<class Widget> void updateWidgetFromCheckStatus(Widget *w)
{
@@ -146,6 +148,11 @@ BaseStringAspect::BaseStringAspect()
BaseStringAspect::~BaseStringAspect() = default;
+void BaseStringAspect::setValueAcceptor(BaseStringAspect::ValueAcceptor &&acceptor)
+{
+ d->m_valueAcceptor = std::move(acceptor);
+}
+
QString BaseStringAspect::value() const
{
return d->m_value;
@@ -154,10 +161,22 @@ QString BaseStringAspect::value() const
void BaseStringAspect::setValue(const QString &value)
{
const bool isSame = value == d->m_value;
- d->m_value = value;
+ if (isSame)
+ return;
+
+ QString processedValue = value;
+ if (d->m_valueAcceptor) {
+ const Utils::optional<QString> tmp = d->m_valueAcceptor(d->m_value, value);
+ if (!tmp) {
+ update(); // Make sure the original value is retained in the UI
+ return;
+ }
+ processedValue = tmp.value();
+ }
+
+ d->m_value = processedValue;
update();
- if (!isSame)
- emit changed();
+ emit changed();
}
void BaseStringAspect::fromMap(const QVariantMap &map)
@@ -257,6 +276,13 @@ void BaseStringAspect::setExpectedKind(const PathChooser::Kind expectedKind)
d->m_pathChooserDisplay->setExpectedKind(expectedKind);
}
+void BaseStringAspect::setFileDialogOnly(bool requireFileDialog)
+{
+ d->m_fileDialogOnly = requireFileDialog;
+ if (d->m_pathChooserDisplay)
+ d->m_pathChooserDisplay->setFileDialogOnly(requireFileDialog);
+}
+
void BaseStringAspect::setEnvironment(const Environment &env)
{
d->m_environment = env;
@@ -287,6 +313,14 @@ void BaseStringAspect::setMacroExpanderProvider(const MacroExpanderProvider &exp
d->m_expanderProvider = expanderProvider;
}
+void BaseStringAspect::validateInput()
+{
+ if (d->m_pathChooserDisplay)
+ d->m_pathChooserDisplay->triggerChanged();
+ if (d->m_lineEditDisplay)
+ d->m_lineEditDisplay->validate();
+}
+
void BaseStringAspect::setUncheckedSemantics(BaseStringAspect::UncheckedSemantics semantics)
{
d->m_uncheckedSemantics = semantics;
@@ -329,6 +363,7 @@ void BaseStringAspect::addToLayout(LayoutBuilder &builder)
connect(d->m_pathChooserDisplay, &PathChooser::pathChanged,
this, &BaseStringAspect::setValue);
builder.addItem(d->m_pathChooserDisplay.data());
+ d->m_pathChooserDisplay->setFileDialogOnly(d->m_fileDialogOnly);
break;
case LineEditDisplay:
d->m_lineEditDisplay = new FancyLineEdit;
@@ -362,6 +397,8 @@ void BaseStringAspect::addToLayout(LayoutBuilder &builder)
break;
}
+ validateInput();
+
if (d->m_checker && d->m_checkBoxPlacement == CheckBoxPlacement::Right)
d->m_checker->addToLayout(builder);
@@ -374,7 +411,7 @@ void BaseStringAspect::update()
: d->m_value;
if (d->m_pathChooserDisplay) {
- d->m_pathChooserDisplay->setFileName(FilePath::fromString(displayedString));
+ d->m_pathChooserDisplay->setFilePath(FilePath::fromString(displayedString));
d->updateWidgetFromCheckStatus(d->m_pathChooserDisplay.data());
}
@@ -398,6 +435,8 @@ void BaseStringAspect::update()
if (!d->m_labelPixmap.isNull())
d->m_label->setPixmap(d->m_labelPixmap);
}
+
+ validateInput();
}
void BaseStringAspect::makeCheckable(CheckBoxPlacement checkBoxPlacement,
diff --git a/src/plugins/projectexplorer/projectconfigurationaspects.h b/src/plugins/projectexplorer/projectconfigurationaspects.h
index 5d6977fa02..f57b69869a 100644
--- a/src/plugins/projectexplorer/projectconfigurationaspects.h
+++ b/src/plugins/projectexplorer/projectconfigurationaspects.h
@@ -115,6 +115,9 @@ public:
void addToLayout(LayoutBuilder &builder) override;
+ // Hook between UI and BaseStringAspect:
+ using ValueAcceptor = std::function<Utils::optional<QString>(const QString &, const QString &)>;
+ void setValueAcceptor(ValueAcceptor &&acceptor);
QString value() const;
void setValue(const QString &val);
@@ -127,11 +130,14 @@ public:
void setPlaceHolderText(const QString &placeHolderText);
void setHistoryCompleter(const QString &historyCompleterKey);
void setExpectedKind(const Utils::PathChooser::Kind expectedKind);
+ void setFileDialogOnly(bool requireFileDialog);
void setEnvironment(const Utils::Environment &env);
void setBaseFileName(const Utils::FilePath &baseFileName);
void setReadOnly(bool readOnly);
void setMacroExpanderProvider(const Utils::MacroExpanderProvider &expanderProvider);
+ void validateInput();
+
enum class UncheckedSemantics { Disabled, ReadOnly };
enum class CheckBoxPlacement { Top, Right };
void setUncheckedSemantics(UncheckedSemantics semantics);
diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp
index c4a15ec526..5ece973a05 100644
--- a/src/plugins/projectexplorer/projectexplorer.cpp
+++ b/src/plugins/projectexplorer/projectexplorer.cpp
@@ -33,6 +33,7 @@
#include "compileoutputwindow.h"
#include "configtaskhandler.h"
#include "customexecutablerunconfiguration.h"
+#include "customparserssettingspage.h"
#include "customwizard/customwizard.h"
#include "deployablefile.h"
#include "deployconfiguration.h"
@@ -156,6 +157,7 @@
#include <QInputDialog>
#include <QMenu>
#include <QMessageBox>
+#include <QPair>
#include <QThreadPool>
#include <QTimer>
@@ -282,6 +284,9 @@ const char SEPARATE_DEBUG_INFO_SETTINGS_KEY[] = "ProjectExplorer/Settings/Separa
const char QML_DEBUGGING_SETTINGS_KEY[] = "ProjectExplorer/Settings/QmlDebugging";
const char QT_QUICK_COMPILER_SETTINGS_KEY[] = "ProjectExplorer/Settings/QtQuickCompiler";
+const char CUSTOM_PARSER_COUNT_KEY[] = "ProjectExplorer/Settings/CustomParserCount";
+const char CUSTOM_PARSER_PREFIX_KEY[] = "ProjectExplorer/Settings/CustomParser";
+
} // namespace Constants
@@ -519,6 +524,7 @@ public:
QAction *m_openFileAction;
QAction *m_projectTreeCollapseAllAction;
QAction *m_projectTreeExpandAllAction;
+ QAction *m_projectTreeExpandNodeAction = nullptr;
Utils::ParameterAction *m_closeProjectFilesActionFileMenu;
Utils::ParameterAction *m_closeProjectFilesActionContextMenu;
QAction *m_searchOnFileSystem;
@@ -549,6 +555,7 @@ public:
MiniProjectTargetSelector * m_targetSelector;
ProjectExplorerSettings m_projectExplorerSettings;
BuildPropertiesSettings m_buildPropertiesSettings;
+ QList<Internal::CustomParserSettings> m_customParsers;
bool m_shouldHaveRunConfiguration = false;
bool m_shuttingDown = false;
Core::Id m_runMode = Constants::NO_RUN_MODE;
@@ -629,6 +636,7 @@ public:
CompileOutputSettingsPage m_compileOutputSettingsPage;
DeviceSettingsPage m_deviceSettingsPage;
SshSettingsPage m_sshSettingsPage;
+ CustomParsersSettingsPage m_customParsersSettingsPage;
ProjectTreeWidgetFactory m_projectTreeFactory;
FolderNavigationWidgetFactory m_folderNavigationWidgetFactory;
@@ -752,6 +760,8 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
ProjectTree *tree = &dd->m_projectTree;
connect(tree, &ProjectTree::currentProjectChanged,
dd, &ProjectExplorerPluginPrivate::updateContextMenuActions);
+ connect(tree, &ProjectTree::nodeActionsChanged,
+ dd, &ProjectExplorerPluginPrivate::updateContextMenuActions);
connect(tree, &ProjectTree::currentNodeChanged,
dd, &ProjectExplorerPluginPrivate::updateContextMenuActions);
connect(tree, &ProjectTree::currentProjectChanged,
@@ -813,6 +823,8 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
});
ProjectPanelFactory::registerFactory(panelFactory);
+ RunConfiguration::registerAspect<CustomParsersAspect>();
+
// context menus
ActionContainer *msessionContextMenu =
ActionManager::createMenu(Constants::M_SESSIONCONTEXT);
@@ -1361,7 +1373,7 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
dd->m_removeFileAction = new QAction(this);
cmd = ActionManager::registerAction(dd->m_removeFileAction, Constants::REMOVEFILE,
projectTreeContext);
- cmd->setDefaultKeySequence(QKeySequence::Delete);
+ cmd->setDefaultKeySequences({QKeySequence::Delete, QKeySequence::Backspace});
mfileContextMenu->addAction(cmd, Constants::G_FILE_OTHER);
// duplicate file action
@@ -1380,7 +1392,7 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
dd->m_deleteFileAction = new QAction(tr("Delete File..."), this);
cmd = ActionManager::registerAction(dd->m_deleteFileAction, Constants::DELETEFILE,
projectTreeContext);
- cmd->setDefaultKeySequence(QKeySequence::Delete);
+ cmd->setDefaultKeySequences({QKeySequence::Delete, QKeySequence::Backspace});
mfileContextMenu->addAction(cmd, Constants::G_FILE_OTHER);
// renamefile action
@@ -1412,6 +1424,13 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
// Collapse & Expand.
const Id treeGroup = Constants::G_PROJECT_TREE;
+
+ dd->m_projectTreeExpandNodeAction = new QAction(tr("Expand"), this);
+ connect(dd->m_projectTreeExpandNodeAction, &QAction::triggered,
+ ProjectTree::instance(), &ProjectTree::expandCurrentNodeRecursively);
+ Command * const expandNodeCmd = ActionManager::registerAction(
+ dd->m_projectTreeExpandNodeAction, "ProjectExplorer.ExpandNode",
+ projectTreeContext);
dd->m_projectTreeCollapseAllAction = new QAction(tr("Collapse All"), this);
Command * const collapseCmd = ActionManager::registerAction(
dd->m_projectTreeCollapseAllAction, Constants::PROJECTTREE_COLLAPSE_ALL,
@@ -1423,6 +1442,7 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
for (Core::ActionContainer * const ac : {mfileContextMenu, msubProjectContextMenu,
mfolderContextMenu, mprojectContextMenu, msessionContextMenu}) {
ac->addSeparator(treeGroup);
+ ac->addAction(expandNodeCmd, treeGroup);
ac->addAction(collapseCmd, treeGroup);
ac->addAction(expandCmd, treeGroup);
}
@@ -1511,7 +1531,7 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
tmp = Utils::HostOsInfo::isWindowsHost() ? 1 : 0;
dd->m_projectExplorerSettings.stopBeforeBuild = StopBeforeBuild(tmp);
dd->m_projectExplorerSettings.terminalMode = static_cast<TerminalMode>(s->value(
- Constants::TERMINAL_MODE_SETTINGS_KEY, int(TerminalMode::Smart)).toInt());
+ Constants::TERMINAL_MODE_SETTINGS_KEY, int(TerminalMode::Off)).toInt());
dd->m_projectExplorerSettings.closeSourceFilesWithProject
= s->value(Constants::CLOSE_FILES_WITH_PROJECT_SETTINGS_KEY, true).toBool();
dd->m_projectExplorerSettings.clearIssuesOnRebuild
@@ -1535,6 +1555,14 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
dd->m_buildPropertiesSettings.qtQuickCompiler
= loadTriStateValue(Constants::QT_QUICK_COMPILER_SETTINGS_KEY);
+ const int customParserCount = s->value(Constants::CUSTOM_PARSER_COUNT_KEY).toInt();
+ for (int i = 0; i < customParserCount; ++i) {
+ CustomParserSettings settings;
+ settings.fromMap(s->value(Constants::CUSTOM_PARSER_PREFIX_KEY
+ + QString::number(i)).toMap());
+ dd->m_customParsers << settings;
+ }
+
auto buildManager = new BuildManager(this, dd->m_cancelBuildAction);
connect(buildManager, &BuildManager::buildStateChanged,
dd, &ProjectExplorerPluginPrivate::updateActions);
@@ -2169,6 +2197,12 @@ void ProjectExplorerPluginPrivate::savePersistentSettings()
dd->m_buildPropertiesSettings.qmlDebugging.toVariant());
s->setValue(Constants::QT_QUICK_COMPILER_SETTINGS_KEY,
dd->m_buildPropertiesSettings.qtQuickCompiler.toVariant());
+
+ s->setValue(Constants::CUSTOM_PARSER_COUNT_KEY, dd->m_customParsers.count());
+ for (int i = 0; i < dd->m_customParsers.count(); ++i) {
+ s->setValue(Constants::CUSTOM_PARSER_PREFIX_KEY + QString::number(i),
+ dd->m_customParsers.at(i).toMap());
+ }
}
void ProjectExplorerPlugin::openProjectWelcomePage(const QString &fileName)
@@ -2351,6 +2385,11 @@ QThreadPool *ProjectExplorerPlugin::sharedThreadPool()
return &(dd->m_threadPool);
}
+MiniProjectTargetSelector *ProjectExplorerPlugin::targetSelector()
+{
+ return dd->m_targetSelector;
+}
+
/*!
This function is connected to the ICore::coreOpened signal. If
there was no session explicitly loaded, it creates an empty new
@@ -2696,17 +2735,6 @@ ProjectExplorerPluginPrivate::ProjectExplorerPluginPrivate()
m_allProjectDirectoriesFilter.setIsCustomFilter(false);
}
-QString ProjectExplorerPlugin::displayNameForStepId(Id stepId)
-{
- if (stepId == Constants::BUILDSTEPS_CLEAN)
- return tr("Clean");
- if (stepId == Constants::BUILDSTEPS_BUILD)
- return tr("Build", "Build step");
- if (stepId == Constants::BUILDSTEPS_DEPLOY)
- return tr("Deploy");
- return tr("Build", "Build step");
-}
-
void ProjectExplorerPluginPrivate::runProjectContextMenu()
{
const Node *node = ProjectTree::currentNode();
@@ -3236,20 +3264,28 @@ void ProjectExplorerPluginPrivate::updateContextMenuActions()
return currentNode->supportsAction(action, currentNode);
};
+ bool canEditProject = true;
+ if (project && project->activeTarget()) {
+ const BuildSystem * const bs = project->activeTarget()->buildSystem();
+ if (bs->isParsing() || bs->isWaitingForParse())
+ canEditProject = false;
+ }
if (currentNode->asFolderNode()) {
// Also handles ProjectNode
- m_addNewFileAction->setEnabled(supports(AddNewFile)
+ m_addNewFileAction->setEnabled(canEditProject && supports(AddNewFile)
&& !ICore::isNewItemDialogRunning());
- m_addNewSubprojectAction->setEnabled(currentNode->isProjectNodeType()
+ m_addNewSubprojectAction->setEnabled(canEditProject && currentNode->isProjectNodeType()
&& supports(AddSubProject)
&& !ICore::isNewItemDialogRunning());
- m_addExistingProjectsAction->setEnabled(currentNode->isProjectNodeType()
+ m_addExistingProjectsAction->setEnabled(canEditProject
+ && currentNode->isProjectNodeType()
&& supports(AddExistingProject));
- m_removeProjectAction->setEnabled(currentNode->isProjectNodeType()
+ m_removeProjectAction->setEnabled(canEditProject && currentNode->isProjectNodeType()
&& supports(RemoveSubProject));
- m_addExistingFilesAction->setEnabled(supports(AddExistingFile));
- m_addExistingDirectoryAction->setEnabled(supports(AddExistingDirectory));
- m_renameFileAction->setEnabled(supports(Rename));
+ m_addExistingFilesAction->setEnabled(canEditProject && supports(AddExistingFile));
+ m_addExistingDirectoryAction->setEnabled(canEditProject
+ && supports(AddExistingDirectory));
+ m_renameFileAction->setEnabled(canEditProject && supports(Rename));
} else if (auto fileNode = currentNode->asFileNode()) {
// Enable and show remove / delete in magic ways:
// If both are disabled show Remove
@@ -3257,20 +3293,20 @@ void ProjectExplorerPluginPrivate::updateContextMenuActions()
// If only removeFile is enabled only show it
// If only deleteFile is enable only show it
bool isTypeProject = fileNode->fileType() == FileType::Project;
- bool enableRemove = !isTypeProject && supports(RemoveFile);
+ bool enableRemove = canEditProject && !isTypeProject && supports(RemoveFile);
m_removeFileAction->setEnabled(enableRemove);
- bool enableDelete = !isTypeProject && supports(EraseFile);
+ bool enableDelete = canEditProject && !isTypeProject && supports(EraseFile);
m_deleteFileAction->setEnabled(enableDelete);
m_deleteFileAction->setVisible(enableDelete);
m_removeFileAction->setVisible(!enableDelete || enableRemove);
- m_renameFileAction->setEnabled(!isTypeProject && supports(Rename));
+ m_renameFileAction->setEnabled(canEditProject && !isTypeProject && supports(Rename));
const bool currentNodeIsTextFile = isTextFile(
currentNode->filePath().toString());
m_diffFileAction->setEnabled(DiffService::instance()
&& currentNodeIsTextFile && TextEditor::TextDocument::currentTextDocument());
- const bool canDuplicate = supports(AddNewFile)
+ const bool canDuplicate = canEditProject && supports(AddNewFile)
&& currentNode->asFileNode()->fileType() != FileType::Project;
m_duplicateFileAction->setVisible(canDuplicate);
m_duplicateFileAction->setEnabled(canDuplicate);
@@ -3580,38 +3616,54 @@ void ProjectExplorerPluginPrivate::removeFile()
QTC_ASSERT(currentNode && currentNode->asFileNode(), return);
const Utils::FilePath filePath = currentNode->filePath();
+ using NodeAndPath = QPair<const Node *, Utils::FilePath>;
+ QList<NodeAndPath> filesToRemove{qMakePair(currentNode, currentNode->filePath())};
+ QList<NodeAndPath> siblings;
+ for (const Node * const n : ProjectTree::siblingsWithSameBaseName(currentNode))
+ siblings << qMakePair(n, n->filePath());
+
Utils::RemoveFileDialog removeFileDialog(filePath.toString(), ICore::mainWindow());
+ if (removeFileDialog.exec() != QDialog::Accepted)
+ return;
+
+ const bool deleteFile = removeFileDialog.isDeleteFileChecked();
- if (removeFileDialog.exec() == QDialog::Accepted) {
- const bool deleteFile = removeFileDialog.isDeleteFileChecked();
+ const QMessageBox::StandardButton reply = QMessageBox::question(
+ Core::ICore::mainWindow(), tr("Remove More Files?"),
+ tr("Would you like to remove these files as well?\n %1")
+ .arg(Utils::transform<QStringList>(siblings, [](const NodeAndPath &np) {
+ return np.second.toFileInfo().fileName();
+ }).join("\n ")));
+ if (reply == QMessageBox::Yes)
+ filesToRemove << siblings;
- // Re-read the current node, in case the project is re-parsed while the dialog is open
- if (!ProjectTree::hasNode(currentNode)) {
+ for (const NodeAndPath &file : filesToRemove) {
+ // Nodes can become invalid if the project was re-parsed while the dialog was open
+ if (!ProjectTree::hasNode(file.first)) {
QMessageBox::warning(ICore::mainWindow(), tr("Removing File Failed"),
- tr("File %1 was not removed, because the project has changed "
+ tr("File \"%1\" was not removed, because the project has changed "
"in the meantime.\nPlease try again.")
- .arg(filePath.toUserOutput()));
+ .arg(file.second.toUserOutput()));
return;
}
// remove from project
- FolderNode *folderNode = currentNode->asFileNode()->parentFolderNode();
+ FolderNode *folderNode = file.first->asFileNode()->parentFolderNode();
QTC_ASSERT(folderNode, return);
const RemovedFilesFromProject status
- = folderNode->removeFiles(QStringList(filePath.toString()));
+ = folderNode->removeFiles(QStringList(file.second.toString()));
const bool success = status == RemovedFilesFromProject::Ok
|| (status == RemovedFilesFromProject::Wildcard
&& removeFileDialog.isDeleteFileChecked());
if (!success) {
- QMessageBox::warning(ICore::mainWindow(), tr("Removing File Failed"),
- tr("Could not remove file %1 from project %2.")
- .arg(filePath.toUserOutput())
- .arg(folderNode->managingProject()->displayName()));
+ TaskHub::addTask(BuildSystemTask(Task::Error,
+ tr("Could not remove file \"%1\" from project \"%2\".")
+ .arg(filePath.toUserOutput(), folderNode->managingProject()->displayName()),
+ folderNode->managingProject()->filePath()));
if (!deleteFile)
- return;
+ continue;
}
-
FileChangeBlocker changeGuard(filePath.toString());
FileUtils::removeFile(filePath.toString(), deleteFile);
}
@@ -3839,6 +3891,19 @@ void ProjectExplorerPlugin::showQtSettings()
dd->m_buildPropertiesSettings.showQtSettings = true;
}
+void ProjectExplorerPlugin::setCustomParsers(const QList<CustomParserSettings> &settings)
+{
+ if (dd->m_customParsers != settings) {
+ dd->m_customParsers = settings;
+ emit m_instance->customParsersChanged();
+ }
+}
+
+const QList<CustomParserSettings> ProjectExplorerPlugin::customParsers()
+{
+ return dd->m_customParsers;
+}
+
QStringList ProjectExplorerPlugin::projectFilePatterns()
{
QStringList patterns;
diff --git a/src/plugins/projectexplorer/projectexplorer.h b/src/plugins/projectexplorer/projectexplorer.h
index 55870aefa1..5f95965eb3 100644
--- a/src/plugins/projectexplorer/projectexplorer.h
+++ b/src/plugins/projectexplorer/projectexplorer.h
@@ -59,6 +59,8 @@ class FileNode;
namespace Internal {
class AppOutputSettings;
+class CustomParserSettings;
+class MiniProjectTargetSelector;
class ProjectExplorerSettings;
}
@@ -140,6 +142,9 @@ public:
static const BuildPropertiesSettings &buildPropertiesSettings();
static void showQtSettings();
+ static void setCustomParsers(const QList<Internal::CustomParserSettings> &settings);
+ static const QList<Internal::CustomParserSettings> customParsers();
+
static void startRunControl(RunControl *runControl);
static void showOutputPaneForRunControl(RunControl *runControl);
@@ -161,11 +166,10 @@ public:
static void initiateInlineRenaming();
- static QString displayNameForStepId(Core::Id stepId);
-
static QStringList projectFileGlobs();
static QThreadPool *sharedThreadPool();
+ static Internal::MiniProjectTargetSelector *targetSelector();
static void showSessionManager();
static void openNewProjectDialog();
@@ -192,6 +196,7 @@ signals:
void recentProjectsChanged();
void settingsChanged();
+ void customParsersChanged();
void runActionsUpdated();
@@ -227,7 +232,6 @@ private slots:
void testGnuMakeParserParsing_data();
void testGnuMakeParserParsing();
- void testGnuMakeParserTaskMangling_data();
void testGnuMakeParserTaskMangling();
void testXcodebuildParserParsing_data();
diff --git a/src/plugins/projectexplorer/projectexplorer.pro b/src/plugins/projectexplorer/projectexplorer.pro
index e9357a8e65..d9f7cbf55b 100644
--- a/src/plugins/projectexplorer/projectexplorer.pro
+++ b/src/plugins/projectexplorer/projectexplorer.pro
@@ -11,7 +11,6 @@ HEADERS += projectexplorer.h \
abi.h \
abiwidget.h \
addrunconfigdialog.h \
- ansifilterparser.h \
buildaspects.h \
buildinfo.h \
buildpropertiessettings.h \
@@ -20,6 +19,7 @@ HEADERS += projectexplorer.h \
buildtargettype.h \
clangparser.h \
configtaskhandler.h \
+ customparserssettingspage.h \
desktoprunconfiguration.h \
environmentaspect.h \
environmentaspectwidget.h \
@@ -105,7 +105,6 @@ HEADERS += projectexplorer.h \
projectexplorersettingspage.h \
baseprojectwizarddialog.h \
miniprojecttargetselector.h \
- buildenvironmentwidget.h \
ldparser.h \
lldparser.h \
linuxiccparser.h \
@@ -173,12 +172,12 @@ SOURCES += projectexplorer.cpp \
abi.cpp \
abiwidget.cpp \
addrunconfigdialog.cpp \
- ansifilterparser.cpp \
buildaspects.cpp \
buildinfo.cpp \
buildpropertiessettingspage.cpp \
buildsystem.cpp \
clangparser.cpp \
+ customparserssettingspage.cpp \
configtaskhandler.cpp \
desktoprunconfiguration.cpp \
environmentaspect.cpp \
@@ -259,7 +258,6 @@ SOURCES += projectexplorer.cpp \
projectexplorersettingspage.cpp \
baseprojectwizarddialog.cpp \
miniprojecttargetselector.cpp \
- buildenvironmentwidget.cpp \
ldparser.cpp \
lldparser.cpp \
linuxiccparser.cpp \
diff --git a/src/plugins/projectexplorer/projectexplorer.qbs b/src/plugins/projectexplorer/projectexplorer.qbs
index a3d53a2262..d6429ca9d8 100644
--- a/src/plugins/projectexplorer/projectexplorer.qbs
+++ b/src/plugins/projectexplorer/projectexplorer.qbs
@@ -27,13 +27,11 @@ Project {
"addrunconfigdialog.cpp", "addrunconfigdialog.h",
"allprojectsfilter.cpp", "allprojectsfilter.h",
"allprojectsfind.cpp", "allprojectsfind.h",
- "ansifilterparser.cpp", "ansifilterparser.h",
"applicationlauncher.cpp", "applicationlauncher.h",
"appoutputpane.cpp", "appoutputpane.h",
"baseprojectwizarddialog.cpp", "baseprojectwizarddialog.h",
"buildaspects.cpp", "buildaspects.h",
"buildconfiguration.cpp", "buildconfiguration.h",
- "buildenvironmentwidget.cpp", "buildenvironmentwidget.h",
"buildinfo.cpp", "buildinfo.h",
"buildmanager.cpp", "buildmanager.h",
"buildprogress.cpp", "buildprogress.h",
@@ -56,6 +54,7 @@ Project {
"customexecutablerunconfiguration.cpp", "customexecutablerunconfiguration.h",
"customparser.cpp", "customparser.h",
"customparserconfigdialog.cpp", "customparserconfigdialog.h", "customparserconfigdialog.ui",
+ "customparserssettingspage.cpp", "customparserssettingspage.h",
"customtoolchain.cpp", "customtoolchain.h",
"dependenciespanel.cpp", "dependenciespanel.h",
"deployablefile.cpp", "deployablefile.h",
diff --git a/src/plugins/projectexplorer/projectexplorer.qrc b/src/plugins/projectexplorer/projectexplorer.qrc
index 0f5e0dc306..32fb160cf6 100644
--- a/src/plugins/projectexplorer/projectexplorer.qrc
+++ b/src/plugins/projectexplorer/projectexplorer.qrc
@@ -64,6 +64,10 @@
<file>images/fileoverlay_qrc@2x.png</file>
<file>images/fileoverlay_qt.png</file>
<file>images/fileoverlay_qt@2x.png</file>
+ <file>images/fileoverlay_product.png</file>
+ <file>images/fileoverlay_product@2x.png</file>
+ <file>images/fileoverlay_group.png</file>
+ <file>images/fileoverlay_group@2x.png</file>
<file>images/fileoverlay_ui.png</file>
<file>images/fileoverlay_ui@2x.png</file>
<file>images/fileoverlay_scxml.png</file>
diff --git a/src/plugins/projectexplorer/projectexplorerconstants.h b/src/plugins/projectexplorer/projectexplorerconstants.h
index 4855035908..08e8210610 100644
--- a/src/plugins/projectexplorer/projectexplorerconstants.h
+++ b/src/plugins/projectexplorer/projectexplorerconstants.h
@@ -110,6 +110,7 @@ const char KITS_SETTINGS_PAGE_ID[] = "D.ProjectExplorer.KitsOptions";
const char SSH_SETTINGS_PAGE_ID[] = "F.ProjectExplorer.SshOptions";
const char TOOLCHAIN_SETTINGS_PAGE_ID[] = "M.ProjectExplorer.ToolChainOptions";
const char DEBUGGER_SETTINGS_PAGE_ID[] = "N.ProjectExplorer.DebuggerOptions";
+const char CUSTOM_PARSERS_SETTINGS_PAGE_ID[] = "X.ProjectExplorer.CustomParsersSettingsPage";
// Build and Run settings category
const char BUILD_AND_RUN_SETTINGS_CATEGORY[] = "K.BuildAndRun";
@@ -210,6 +211,8 @@ const char PROJECTTREE_ID[] = "Projects";
// File icon overlays
const char FILEOVERLAY_QT[]=":/projectexplorer/images/fileoverlay_qt.png";
+const char FILEOVERLAY_GROUP[] = ":/projectexplorer/images/fileoverlay_group.png";
+const char FILEOVERLAY_PRODUCT[] = ":/projectexplorer/images/fileoverlay_product.png";
const char FILEOVERLAY_QML[]=":/projectexplorer/images/fileoverlay_qml.png";
const char FILEOVERLAY_UI[]=":/projectexplorer/images/fileoverlay_ui.png";
const char FILEOVERLAY_QRC[]=":/projectexplorer/images/fileoverlay_qrc.png";
diff --git a/src/plugins/projectexplorer/projectexplorersettings.h b/src/plugins/projectexplorer/projectexplorersettings.h
index b1509f2c3e..496bc3e26a 100644
--- a/src/plugins/projectexplorer/projectexplorersettings.h
+++ b/src/plugins/projectexplorer/projectexplorersettings.h
@@ -54,7 +54,7 @@ public:
bool abortBuildAllOnError = true;
bool lowBuildPriority = false;
StopBeforeBuild stopBeforeBuild = StopBeforeBuild::None;
- TerminalMode terminalMode = TerminalMode::Smart;
+ TerminalMode terminalMode = TerminalMode::Off;
// Add a UUid which is used to identify the development environment.
// This is used to warn the user when he is trying to open a .user file that was created
diff --git a/src/plugins/projectexplorer/projectexplorersettingspage.cpp b/src/plugins/projectexplorer/projectexplorersettingspage.cpp
index 4172424160..14d5a33e6f 100644
--- a/src/plugins/projectexplorer/projectexplorersettingspage.cpp
+++ b/src/plugins/projectexplorer/projectexplorersettingspage.cpp
@@ -137,7 +137,7 @@ void ProjectExplorerSettingsWidget::setSettings(const ProjectExplorerSettings &
QString ProjectExplorerSettingsWidget::projectsDirectory() const
{
- return m_ui.projectsDirectoryPathChooser->path();
+ return m_ui.projectsDirectoryPathChooser->filePath().toString();
}
void ProjectExplorerSettingsWidget::setProjectsDirectory(const QString &pd)
diff --git a/src/plugins/projectexplorer/projectmodels.cpp b/src/plugins/projectexplorer/projectmodels.cpp
index 8a47245d1b..1939674d4e 100644
--- a/src/plugins/projectexplorer/projectmodels.cpp
+++ b/src/plugins/projectexplorer/projectmodels.cpp
@@ -214,35 +214,23 @@ bool FlatModel::setData(const QModelIndex &index, const QVariant &value, int rol
// The base name of the file was changed. Go look for other files with the same base name
// and offer to rename them as well.
if (orgFilePath != newFilePath && orgFileInfo.suffix() == newFilePath.toFileInfo().suffix()) {
- ProjectNode *productNode = node->parentProjectNode();
- while (productNode && !productNode->isProduct())
- productNode = productNode->parentProjectNode();
- if (productNode) {
- const auto filter = [&orgFilePath, &orgFileInfo](const Node *n) {
- return n->asFileNode()
- && n->filePath().toFileInfo().dir() == orgFileInfo.dir()
- && n->filePath().toFileInfo().completeBaseName()
- == orgFileInfo.completeBaseName()
- && n->filePath() != orgFilePath;
- };
- const QList<Node *> candidateNodes = productNode->findNodes(filter);
- if (!candidateNodes.isEmpty()) {
- const QMessageBox::StandardButton reply = QMessageBox::question(
- Core::ICore::mainWindow(), tr("Rename More Files?"),
- tr("Would you like to rename these files as well?\n %1")
- .arg(transform<QStringList>(candidateNodes, [](const Node *n) {
- return n->filePath().toFileInfo().fileName();
- }).join("\n ")));
- if (reply == QMessageBox::Yes) {
- for (Node * const n : candidateNodes) {
- QString targetFilePath = orgFileInfo.absolutePath() + '/'
- + newFilePath.toFileInfo().completeBaseName();
- const QString suffix = n->filePath().toFileInfo().suffix();
- if (!suffix.isEmpty())
- targetFilePath.append('.').append(suffix);
- toRename.emplace_back(std::make_tuple(n, n->filePath(),
- FilePath::fromString(targetFilePath)));
- }
+ const QList<Node *> candidateNodes = ProjectTree::siblingsWithSameBaseName(node);
+ if (!candidateNodes.isEmpty()) {
+ const QMessageBox::StandardButton reply = QMessageBox::question(
+ Core::ICore::mainWindow(), tr("Rename More Files?"),
+ tr("Would you like to rename these files as well?\n %1")
+ .arg(transform<QStringList>(candidateNodes, [](const Node *n) {
+ return n->filePath().toFileInfo().fileName();
+ }).join("\n ")));
+ if (reply == QMessageBox::Yes) {
+ for (Node * const n : candidateNodes) {
+ QString targetFilePath = orgFileInfo.absolutePath() + '/'
+ + newFilePath.toFileInfo().completeBaseName();
+ const QString suffix = n->filePath().toFileInfo().suffix();
+ if (!suffix.isEmpty())
+ targetFilePath.append('.').append(suffix);
+ toRename.emplace_back(std::make_tuple(n, n->filePath(),
+ FilePath::fromString(targetFilePath)));
}
}
}
@@ -370,6 +358,7 @@ void FlatModel::handleProjectAdded(Project *project)
this, [this, project]() {
if (nodeForProject(project))
parsingStateChanged(project);
+ emit ProjectTree::instance()->nodeActionsChanged();
});
addOrRebuildProjectModel(project);
}
@@ -515,7 +504,7 @@ public:
targetDirLayout->addWidget(new QLabel(tr("Target directory:"), this));
m_targetDirChooser = new PathChooser(this);
m_targetDirChooser->setExpectedKind(PathChooser::ExistingDirectory);
- m_targetDirChooser->setFileName(defaultTargetDir);
+ m_targetDirChooser->setFilePath(defaultTargetDir);
connect(m_targetDirChooser, &PathChooser::validChanged, this, [this](bool valid) {
m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(valid);
});
@@ -548,7 +537,7 @@ public:
DropAction dropAction() const { return static_cast<DropAction>(m_buttonGroup->checkedId()); }
FilePath targetDir() const
{
- return m_targetDirChooser ? m_targetDirChooser->fileName() : FilePath();
+ return m_targetDirChooser ? m_targetDirChooser->filePath() : FilePath();
}
private:
diff --git a/src/plugins/projectexplorer/projecttree.cpp b/src/plugins/projectexplorer/projecttree.cpp
index 1ff829a061..204c53e6ca 100644
--- a/src/plugins/projectexplorer/projecttree.cpp
+++ b/src/plugins/projectexplorer/projecttree.cpp
@@ -48,6 +48,7 @@
#include <utils/qtcassert.h>
#include <QApplication>
+#include <QFileInfo>
#include <QMenu>
#include <QTimer>
@@ -154,7 +155,7 @@ void ProjectTree::update()
ProjectTreeWidget *focus = m_focusForContextMenu;
static QPointer<ProjectTreeWidget> lastFocusedProjectTreeWidget;
if (!focus) {
- focus = Utils::findOrDefault(m_projectTreeWidgets, &ProjectTree::hasFocus);
+ focus = currentWidget();
lastFocusedProjectTreeWidget = focus;
}
if (!focus)
@@ -284,15 +285,21 @@ void ProjectTree::sessionAndTreeChanged()
emit treeChanged();
}
+void ProjectTree::expandCurrentNodeRecursively()
+{
+ if (const auto w = currentWidget())
+ w->expandCurrentNodeRecursively();
+}
+
void ProjectTree::collapseAll()
{
- if (auto w = Utils::findOrDefault(s_instance->m_projectTreeWidgets, &ProjectTree::hasFocus))
+ if (const auto w = currentWidget())
w->collapseAll();
}
void ProjectTree::expandAll()
{
- if (auto w = Utils::findOrDefault(s_instance->m_projectTreeWidgets, &ProjectTree::hasFocus))
+ if (const auto w = currentWidget())
w->expandAll();
}
@@ -344,6 +351,11 @@ bool ProjectTree::hasFocus(ProjectTreeWidget *widget)
|| s_instance->m_focusForContextMenu == widget);
}
+ProjectTreeWidget *ProjectTree::currentWidget() const
+{
+ return findOrDefault(m_projectTreeWidgets, &ProjectTree::hasFocus);
+}
+
void ProjectTree::showContextMenu(ProjectTreeWidget *focus, const QPoint &globalPos, Node *node)
{
QMenu *contextMenu = nullptr;
@@ -459,6 +471,23 @@ Node *ProjectTree::nodeForFile(const FilePath &fileName)
return node;
}
+const QList<Node *> ProjectTree::siblingsWithSameBaseName(const Node *fileNode)
+{
+ ProjectNode *productNode = fileNode->parentProjectNode();
+ while (productNode && !productNode->isProduct())
+ productNode = productNode->parentProjectNode();
+ if (!productNode)
+ return {};
+ const QFileInfo fi = fileNode->filePath().toFileInfo();
+ const auto filter = [&fi](const Node *n) {
+ return n->asFileNode()
+ && n->filePath().toFileInfo().dir() == fi.dir()
+ && n->filePath().toFileInfo().completeBaseName() == fi.completeBaseName()
+ && n->filePath().toString() != fi.filePath();
+ };
+ return productNode->findNodes(filter);
+}
+
void ProjectTree::hideContextMenu()
{
m_focusForContextMenu = nullptr;
diff --git a/src/plugins/projectexplorer/projecttree.h b/src/plugins/projectexplorer/projecttree.h
index bf1335e5be..aeefa6bea0 100644
--- a/src/plugins/projectexplorer/projecttree.h
+++ b/src/plugins/projectexplorer/projecttree.h
@@ -82,6 +82,10 @@ public:
static Project *projectForNode(const Node *node);
static Node *nodeForFile(const Utils::FilePath &fileName);
+ static const QList<Node *> siblingsWithSameBaseName(const Node *fileNode);
+
+ void expandCurrentNodeRecursively();
+
void collapseAll();
void expandAll();
@@ -93,6 +97,7 @@ public:
signals:
void currentProjectChanged(ProjectExplorer::Project *project);
void currentNodeChanged();
+ void nodeActionsChanged();
// Emitted whenever the model needs to send a update signal.
void subtreeChanged(ProjectExplorer::FolderNode *node);
@@ -117,6 +122,7 @@ private:
void updateExternalFileWarning();
static bool hasFocus(Internal::ProjectTreeWidget *widget);
+ Internal::ProjectTreeWidget *currentWidget() const;
void hideContextMenu();
private:
diff --git a/src/plugins/projectexplorer/projecttreewidget.cpp b/src/plugins/projectexplorer/projecttreewidget.cpp
index ddf1bdf496..cdd24622cd 100644
--- a/src/plugins/projectexplorer/projecttreewidget.cpp
+++ b/src/plugins/projectexplorer/projecttreewidget.cpp
@@ -432,6 +432,20 @@ void ProjectTreeWidget::setAutoSynchronization(bool sync)
syncFromDocumentManager();
}
+void ProjectTreeWidget::expandNodeRecursively(const QModelIndex &index)
+{
+ const int rc = index.model()->rowCount(index);
+ for (int i = 0; i < rc; ++i)
+ expandNodeRecursively(index.model()->index(i, index.column(), index));
+ if (rc > 0)
+ m_view->expand(index);
+}
+
+void ProjectTreeWidget::expandCurrentNodeRecursively()
+{
+ expandNodeRecursively(m_view->currentIndex());
+}
+
void ProjectTreeWidget::collapseAll()
{
m_view->collapseAll();
diff --git a/src/plugins/projectexplorer/projecttreewidget.h b/src/plugins/projectexplorer/projecttreewidget.h
index e53396c4b9..aa612fdf7e 100644
--- a/src/plugins/projectexplorer/projecttreewidget.h
+++ b/src/plugins/projectexplorer/projecttreewidget.h
@@ -67,6 +67,7 @@ public:
void toggleAutoSynchronization();
void editCurrentItem();
+ void expandCurrentNodeRecursively();
void collapseAll();
void expandAll();
@@ -87,6 +88,8 @@ private:
void syncFromDocumentManager();
+ void expandNodeRecursively(const QModelIndex &index);
+
QTreeView *m_view = nullptr;
FlatModel *m_model = nullptr;
QAction *m_filterProjectsAction = nullptr;
diff --git a/src/plugins/projectexplorer/rawprojectpart.cpp b/src/plugins/projectexplorer/rawprojectpart.cpp
index 7e029c1ced..19eb7ab30f 100644
--- a/src/plugins/projectexplorer/rawprojectpart.cpp
+++ b/src/plugins/projectexplorer/rawprojectpart.cpp
@@ -155,8 +155,8 @@ KitInfo::KitInfo(Kit *kit)
{
// Toolchains
if (kit) {
- cToolChain = ToolChainKitAspect::toolChain(kit, Constants::C_LANGUAGE_ID);
- cxxToolChain = ToolChainKitAspect::toolChain(kit, Constants::CXX_LANGUAGE_ID);
+ cToolChain = ToolChainKitAspect::cToolChain(kit);
+ cxxToolChain = ToolChainKitAspect::cxxToolChain(kit);
}
// Sysroot
diff --git a/src/plugins/projectexplorer/removetaskhandler.cpp b/src/plugins/projectexplorer/removetaskhandler.cpp
index b71b9b0556..b8abc22e11 100644
--- a/src/plugins/projectexplorer/removetaskhandler.cpp
+++ b/src/plugins/projectexplorer/removetaskhandler.cpp
@@ -42,7 +42,7 @@ QAction *RemoveTaskHandler::createAction(QObject *parent) const
{
QAction *removeAction = new QAction(tr("Remove", "Name of the action triggering the removetaskhandler"), parent);
removeAction->setToolTip(tr("Remove task from the task list."));
- removeAction->setShortcut(QKeySequence(QKeySequence::Delete));
+ removeAction->setShortcuts({QKeySequence::Delete, QKeySequence::Backspace});
removeAction->setShortcutContext(Qt::WidgetWithChildrenShortcut);
return removeAction;
}
diff --git a/src/plugins/projectexplorer/runconfiguration.cpp b/src/plugins/projectexplorer/runconfiguration.cpp
index 36c988434d..69f6dc8606 100644
--- a/src/plugins/projectexplorer/runconfiguration.cpp
+++ b/src/plugins/projectexplorer/runconfiguration.cpp
@@ -167,27 +167,26 @@ RunConfiguration::RunConfiguration(Target *target, Core::Id id)
QTC_CHECK(target && target == this->target());
connect(target, &Target::parsingFinished, this, &RunConfiguration::update);
- Utils::MacroExpander *expander = macroExpander();
- expander->setDisplayName(tr("Run Settings"));
- expander->setAccumulating(true);
- expander->registerSubProvider([target] {
+ m_expander.setDisplayName(tr("Run Settings"));
+ m_expander.setAccumulating(true);
+ m_expander.registerSubProvider([target] {
BuildConfiguration *bc = target->activeBuildConfiguration();
return bc ? bc->macroExpander() : target->macroExpander();
});
- expander->registerPrefix("CurrentRun:Env", tr("Variables in the current run environment"),
+ m_expander.registerPrefix("CurrentRun:Env", tr("Variables in the current run environment"),
[this](const QString &var) {
const auto envAspect = aspect<EnvironmentAspect>();
return envAspect ? envAspect->environment().expandedValueForKey(var) : QString();
});
- expander->registerVariable(Constants::VAR_CURRENTRUN_WORKINGDIR,
+ m_expander.registerVariable(Constants::VAR_CURRENTRUN_WORKINGDIR,
tr("The currently active run configuration's working directory"),
- [this, expander] {
+ [this] {
const auto wdAspect = aspect<WorkingDirectoryAspect>();
- return wdAspect ? wdAspect->workingDirectory(expander).toString() : QString();
+ return wdAspect ? wdAspect->workingDirectory(&m_expander).toString() : QString();
});
- expander->registerVariable(Constants::VAR_CURRENTRUN_NAME,
+ m_expander.registerVariable(Constants::VAR_CURRENTRUN_NAME,
QCoreApplication::translate("ProjectExplorer", "The currently active run configuration's name."),
[this] { return displayName(); }, false);
@@ -227,7 +226,7 @@ QWidget *RunConfiguration::createConfigurationWidget()
}
}
- Core::VariableChooser::addSupportForChildWidgets(widget, macroExpander());
+ Core::VariableChooser::addSupportForChildWidgets(widget, &m_expander);
auto detailsWidget = new Utils::DetailsWidget;
detailsWidget->setState(DetailsWidget::NoSummary);
@@ -446,17 +445,17 @@ QString RunConfigurationFactory::decoratedTargetName(const QString &targetName,
}
QList<RunConfigurationCreationInfo>
-RunConfigurationFactory::availableCreators(Target *parent) const
+RunConfigurationFactory::availableCreators(Target *target) const
{
- const QList<BuildTargetInfo> buildTargets = parent->applicationTargets();
+ const QList<BuildTargetInfo> buildTargets = target->buildSystem()->applicationTargets();
const bool hasAnyQtcRunnable = Utils::anyOf(buildTargets,
Utils::equal(&BuildTargetInfo::isQtcRunnable, true));
return Utils::transform(buildTargets, [&](const BuildTargetInfo &ti) {
QString displayName = ti.displayName;
if (displayName.isEmpty())
- displayName = decoratedTargetName(ti.buildKey, parent);
+ displayName = decoratedTargetName(ti.buildKey, target);
else if (m_decorateDisplayNames)
- displayName = decoratedTargetName(displayName, parent);
+ displayName = decoratedTargetName(displayName, target);
RunConfigurationCreationInfo rci;
rci.factory = this;
rci.id = m_runConfigBaseId;
diff --git a/src/plugins/projectexplorer/runconfiguration.h b/src/plugins/projectexplorer/runconfiguration.h
index 017384a833..e896968c10 100644
--- a/src/plugins/projectexplorer/runconfiguration.h
+++ b/src/plugins/projectexplorer/runconfiguration.h
@@ -33,6 +33,7 @@
#include "task.h"
#include <utils/environment.h>
+#include <utils/macroexpander.h>
#include <utils/port.h>
#include <QWidget>
@@ -135,8 +136,6 @@ public:
bool isConfigured() const { return checkForIssues().isEmpty(); }
virtual Tasks checkForIssues() const { return {}; }
- Utils::OutputFormatter *createOutputFormatter() const;
-
using CommandLineGetter = std::function<Utils::CommandLine()>;
void setCommandLineGetter(const CommandLineGetter &cmdGetter);
Utils::CommandLine commandLine() const;
@@ -168,6 +167,8 @@ public:
void update();
+ const Utils::MacroExpander *macroExpander() const { return &m_expander; }
+
signals:
void enabledChanged();
@@ -196,6 +197,7 @@ private:
QString m_buildKey;
CommandLineGetter m_commandLineGetter;
Updater m_updater;
+ Utils::MacroExpander m_expander;
};
class RunConfigurationCreationInfo
@@ -232,7 +234,7 @@ public:
static QString decoratedTargetName(const QString &targetName, Target *kit);
protected:
- virtual QList<RunConfigurationCreationInfo> availableCreators(Target *parent) const;
+ virtual QList<RunConfigurationCreationInfo> availableCreators(Target *target) const;
using RunConfigurationCreator = std::function<RunConfiguration *(Target *)>;
diff --git a/src/plugins/projectexplorer/runconfigurationaspects.cpp b/src/plugins/projectexplorer/runconfigurationaspects.cpp
index 343ca369ea..0324b673d5 100644
--- a/src/plugins/projectexplorer/runconfigurationaspects.cpp
+++ b/src/plugins/projectexplorer/runconfigurationaspects.cpp
@@ -148,10 +148,10 @@ void WorkingDirectoryAspect::addToLayout(LayoutBuilder &builder)
m_chooser->setExpectedKind(Utils::PathChooser::Directory);
m_chooser->setPromptDialogTitle(tr("Select Working Directory"));
m_chooser->setBaseDirectory(m_defaultWorkingDirectory);
- m_chooser->setFileName(m_workingDirectory.isEmpty() ? m_defaultWorkingDirectory : m_workingDirectory);
+ m_chooser->setFilePath(m_workingDirectory.isEmpty() ? m_defaultWorkingDirectory : m_workingDirectory);
connect(m_chooser.data(), &PathChooser::pathChanged, this,
[this]() {
- m_workingDirectory = m_chooser->rawFileName();
+ m_workingDirectory = m_chooser->rawFilePath();
m_resetButton->setEnabled(m_workingDirectory != m_defaultWorkingDirectory);
});
@@ -183,7 +183,7 @@ QString WorkingDirectoryAspect::keyForDefaultWd() const
void WorkingDirectoryAspect::resetPath()
{
- m_chooser->setFileName(m_defaultWorkingDirectory);
+ m_chooser->setFilePath(m_defaultWorkingDirectory);
}
void WorkingDirectoryAspect::fromMap(const QVariantMap &map)
@@ -195,7 +195,7 @@ void WorkingDirectoryAspect::fromMap(const QVariantMap &map)
m_workingDirectory = m_defaultWorkingDirectory;
if (m_chooser)
- m_chooser->setFileName(m_workingDirectory.isEmpty() ? m_defaultWorkingDirectory : m_workingDirectory);
+ m_chooser->setFilePath(m_workingDirectory.isEmpty() ? m_defaultWorkingDirectory : m_workingDirectory);
}
void WorkingDirectoryAspect::toMap(QVariantMap &data) const
@@ -238,7 +238,7 @@ void WorkingDirectoryAspect::setDefaultWorkingDirectory(const FilePath &defaultW
if (m_workingDirectory.isEmpty() || m_workingDirectory == oldDefaultDir) {
if (m_chooser)
- m_chooser->setFileName(m_defaultWorkingDirectory);
+ m_chooser->setFilePath(m_defaultWorkingDirectory);
m_workingDirectory = defaultWorkingDir;
}
}
diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp
index 1bd5d90f9a..a545b972de 100644
--- a/src/plugins/projectexplorer/runcontrol.cpp
+++ b/src/plugins/projectexplorer/runcontrol.cpp
@@ -26,16 +26,17 @@
#include "runcontrol.h"
#include "devicesupport/desktopdevice.h"
-#include "project.h"
-#include "target.h"
-#include "toolchain.h"
#include "abi.h"
#include "buildconfiguration.h"
+#include "customparser.h"
#include "environmentaspect.h"
#include "kitinformation.h"
+#include "project.h"
+#include "projectexplorer.h"
#include "runconfigurationaspects.h"
#include "session.h"
-#include "kitinformation.h"
+#include "target.h"
+#include "toolchain.h"
#include <utils/algorithm.h>
#include <utils/checkablemessagebox.h>
@@ -279,7 +280,6 @@ public:
: q(parent), runMode(mode)
{
icon = Icons::RUN_SMALL_TOOLBAR;
- outputFormatter = new OutputFormatter();
}
~RunControlPrivate() override
@@ -289,7 +289,6 @@ public:
q = nullptr;
qDeleteAll(m_workers);
m_workers.clear();
- delete outputFormatter;
}
Q_ENUM(RunControlState)
@@ -322,7 +321,7 @@ public:
IDevice::ConstPtr device;
Core::Id runMode;
Utils::Icon icon;
- MacroExpander *macroExpander;
+ const MacroExpander *macroExpander;
QPointer<RunConfiguration> runConfiguration; // Not owned. Avoid use.
QString buildKey;
QMap<Core::Id, QVariantMap> settingsData;
@@ -334,7 +333,6 @@ public:
Kit *kit = nullptr; // Not owned.
QPointer<Target> target; // Not owned.
QPointer<Project> project; // Not owned.
- QPointer<Utils::OutputFormatter> outputFormatter = nullptr;
std::function<bool(bool*)> promptToStop;
std::vector<RunWorkerFactory> m_factories;
@@ -385,11 +383,6 @@ void RunControl::setTarget(Target *target)
d->buildEnvironment = bc->environment();
}
- delete d->outputFormatter;
- d->outputFormatter = OutputFormatterFactory::createFormatter(target);
- if (!d->outputFormatter)
- d->outputFormatter = new OutputFormatter();
-
setKit(target->kit());
d->project = target->project();
}
@@ -831,9 +824,17 @@ void RunControlPrivate::showError(const QString &msg)
q->appendMessage(msg + '\n', ErrorMessageFormat);
}
-Utils::OutputFormatter *RunControl::outputFormatter() const
+QList<Utils::OutputLineParser *> RunControl::createOutputParsers() const
{
- return d->outputFormatter;
+ QList<Utils::OutputLineParser *> parsers = OutputFormatterFactory::createFormatters(target());
+ if (const auto customParsersAspect
+ = (runConfiguration() ? runConfiguration()->aspect<CustomParsersAspect>() : nullptr)) {
+ for (const Core::Id id : customParsersAspect->parsers()) {
+ if (CustomParser * const parser = CustomParser::createFromId(id))
+ parsers << parser;
+ }
+ }
+ return parsers;
}
Core::Id RunControl::runMode() const
@@ -896,7 +897,7 @@ Kit *RunControl::kit() const
return d->kit;
}
-MacroExpander *RunControl::macroExpander() const
+const MacroExpander *RunControl::macroExpander() const
{
return d->macroExpander;
}
@@ -1214,12 +1215,12 @@ void SimpleTargetRunner::doStart(const Runnable &runnable, const IDevice::ConstP
connect(&m_launcher, &ApplicationLauncher::remoteStderr,
this, [this](const QString &output) {
- appendMessage(output, Utils::StdErrFormatSameLine, false);
+ appendMessage(output, Utils::StdErrFormat, false);
});
connect(&m_launcher, &ApplicationLauncher::remoteStdout,
this, [this](const QString &output) {
- appendMessage(output, Utils::StdOutFormatSameLine, false);
+ appendMessage(output, Utils::StdOutFormat, false);
});
connect(&m_launcher, &ApplicationLauncher::finished,
@@ -1601,11 +1602,7 @@ static QList<OutputFormatterFactory *> g_outputFormatterFactories;
OutputFormatterFactory::OutputFormatterFactory()
{
- // This is a bit cheating: We know that only two formatters exist right now,
- // and this here gives the second (python) implicit more priority.
- // For a final solution, probably all matching formatters should be used
- // in parallel, so there's no need to invent a fancy priority system here.
- g_outputFormatterFactories.prepend(this);
+ g_outputFormatterFactories.append(this);
}
OutputFormatterFactory::~OutputFormatterFactory()
@@ -1613,17 +1610,15 @@ OutputFormatterFactory::~OutputFormatterFactory()
g_outputFormatterFactories.removeOne(this);
}
-OutputFormatter *OutputFormatterFactory::createFormatter(Target *target)
+QList<OutputLineParser *> OutputFormatterFactory::createFormatters(Target *target)
{
- for (auto factory : qAsConst(g_outputFormatterFactories)) {
- if (auto formatter = factory->m_creator(target))
- return formatter;
- }
- return nullptr;
+ QList<OutputLineParser *> formatters;
+ for (auto factory : qAsConst(g_outputFormatterFactories))
+ formatters << factory->m_creator(target);
+ return formatters;
}
-void OutputFormatterFactory::setFormatterCreator
- (const std::function<OutputFormatter *(Target *)> &creator)
+void OutputFormatterFactory::setFormatterCreator(const FormatterCreator &creator)
{
m_creator = creator;
}
diff --git a/src/plugins/projectexplorer/runcontrol.h b/src/plugins/projectexplorer/runcontrol.h
index 1ad3e26b27..242f3b3b15 100644
--- a/src/plugins/projectexplorer/runcontrol.h
+++ b/src/plugins/projectexplorer/runcontrol.h
@@ -45,7 +45,7 @@
namespace Utils {
class MacroExpander;
-class OutputFormatter;
+class OutputLineParser;
} // Utils
namespace ProjectExplorer {
@@ -222,7 +222,7 @@ public:
Target *target() const;
Project *project() const;
Kit *kit() const;
- Utils::MacroExpander *macroExpander() const;
+ const Utils::MacroExpander *macroExpander() const;
ProjectConfigurationAspect *aspect(Core::Id id) const;
template <typename T> T *aspect() const {
return runConfiguration() ? runConfiguration()->aspect<T>() : nullptr;
@@ -238,7 +238,7 @@ public:
Utils::FilePath targetFilePath() const;
Utils::FilePath projectFilePath() const;
- Utils::OutputFormatter *outputFormatter() const;
+ QList<Utils::OutputLineParser *> createOutputParsers() const;
Core::Id runMode() const;
const Runnable &runnable() const;
@@ -309,13 +309,14 @@ protected:
public:
virtual ~OutputFormatterFactory();
- static Utils::OutputFormatter *createFormatter(Target *target);
+ static QList<Utils::OutputLineParser *> createFormatters(Target *target);
protected:
- void setFormatterCreator(const std::function<Utils::OutputFormatter *(Target *)> &creator);
+ using FormatterCreator = std::function<QList<Utils::OutputLineParser *>(Target *)>;
+ void setFormatterCreator(const FormatterCreator &creator);
private:
- std::function<Utils::OutputFormatter *(Target *)> m_creator;
+ FormatterCreator m_creator;
};
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/selectablefilesmodel.cpp b/src/plugins/projectexplorer/selectablefilesmodel.cpp
index 9351aa9898..4e524f2cad 100644
--- a/src/plugins/projectexplorer/selectablefilesmodel.cpp
+++ b/src/plugins/projectexplorer/selectablefilesmodel.cpp
@@ -563,7 +563,7 @@ SelectableFilesWidget::SelectableFilesWidget(QWidget *parent) :
connect(m_baseDirChooser, &Utils::PathChooser::validChanged,
this, &SelectableFilesWidget::baseDirectoryChanged);
connect(m_startParsingButton, &QAbstractButton::clicked,
- this, [this]() { startParsing(m_baseDirChooser->fileName()); });
+ this, [this]() { startParsing(m_baseDirChooser->filePath()); });
m_selectFilesFilterLabel->setText(tr("Select files matching:"));
m_selectFilesFilterEdit->setText(selectFilter);
@@ -645,7 +645,7 @@ void SelectableFilesWidget::resetModel(const Utils::FilePath &path, const Utils:
connect(m_model, &SelectableFilesModel::checkedFilesChanged,
this, &SelectableFilesWidget::selectedFilesChanged);
- m_baseDirChooser->setFileName(path);
+ m_baseDirChooser->setFilePath(path);
m_view->setModel(m_model);
startParsing(path);
diff --git a/src/plugins/projectexplorer/sessionview.cpp b/src/plugins/projectexplorer/sessionview.cpp
index ab92ce16b8..49cd8b1486 100644
--- a/src/plugins/projectexplorer/sessionview.cpp
+++ b/src/plugins/projectexplorer/sessionview.cpp
@@ -152,7 +152,7 @@ void SessionView::showEvent(QShowEvent *event)
void SessionView::keyPressEvent(QKeyEvent *event)
{
- if (event->key() != Qt::Key_Delete) {
+ if (event->key() != Qt::Key_Delete && event->key() != Qt::Key_Backspace) {
TreeView::keyPressEvent(event);
return;
}
diff --git a/src/plugins/projectexplorer/simpleprojectwizard.cpp b/src/plugins/projectexplorer/simpleprojectwizard.cpp
index d9d88aa315..51dea77c11 100644
--- a/src/plugins/projectexplorer/simpleprojectwizard.cpp
+++ b/src/plugins/projectexplorer/simpleprojectwizard.cpp
@@ -168,7 +168,7 @@ void FilesSelectionWizardPage::initializePage()
SimpleProjectWizard::SimpleProjectWizard()
{
setSupportedProjectTypes({QmakeProjectManager::Constants::QMAKEPROJECT_ID,
- CMakeProjectManager::Constants::CMAKEPROJECT_ID});
+ CMakeProjectManager::Constants::CMAKE_PROJECT_ID});
setIcon(QIcon(QLatin1String(":/projectexplorer/images/importasproject.png")));
setDisplayName(tr("Import as qmake or cmake Project (Limited Functionality)"));
setId("Z.DummyProFile");
diff --git a/src/plugins/projectexplorer/target.cpp b/src/plugins/projectexplorer/target.cpp
index b3f04c646f..e46f259f8a 100644
--- a/src/plugins/projectexplorer/target.cpp
+++ b/src/plugins/projectexplorer/target.cpp
@@ -37,6 +37,7 @@
#include "kit.h"
#include "kitinformation.h"
#include "kitmanager.h"
+#include "miniprojecttargetselector.h"
#include "project.h"
#include "projectexplorer.h"
#include "projectexplorericons.h"
@@ -46,8 +47,6 @@
#include <coreplugin/coreconstants.h>
-#include <extensionsystem/pluginmanager.h>
-
#include <utils/algorithm.h>
#include <utils/macroexpander.h>
#include <utils/qtcassert.h>
@@ -150,17 +149,16 @@ Target::Target(Project *project, Kit *k, _constructor_tag) :
connect(km, &KitManager::kitUpdated, this, &Target::handleKitUpdates);
connect(km, &KitManager::kitRemoved, this, &Target::handleKitRemoval);
- Utils::MacroExpander *expander = macroExpander();
- expander->setDisplayName(tr("Target Settings"));
- expander->setAccumulating(true);
+ d->m_macroExpander.setDisplayName(tr("Target Settings"));
+ d->m_macroExpander.setAccumulating(true);
- expander->registerSubProvider([this] { return kit()->macroExpander(); });
+ d->m_macroExpander.registerSubProvider([this] { return kit()->macroExpander(); });
- expander->registerVariable("sourceDir", tr("Source directory"),
+ d->m_macroExpander.registerVariable("sourceDir", tr("Source directory"),
[project] { return project->projectDirectory().toUserOutput(); });
// Legacy support.
- expander->registerVariable(Constants::VAR_CURRENTPROJECT_NAME,
+ d->m_macroExpander.registerVariable(Constants::VAR_CURRENTPROJECT_NAME,
QCoreApplication::translate("ProjectExplorer", "Name of current project"),
[project] { return project->displayName(); },
false);
@@ -234,16 +232,19 @@ DeploymentData Target::buildSystemDeploymentData() const
return buildSystem()->deploymentData();
}
-const QList<BuildTargetInfo> Target::applicationTargets() const
+BuildTargetInfo Target::buildTarget(const QString &buildKey) const
{
QTC_ASSERT(buildSystem(), return {});
- return buildSystem()->applicationTargets();
+ return buildSystem()->buildTarget(buildKey);
}
-BuildTargetInfo Target::buildTarget(const QString &buildKey) const
+QString Target::activeBuildKey() const
{
- QTC_ASSERT(buildSystem(), return {});
- return buildSystem()->buildTarget(buildKey);
+ // Should not happen. If it does, return a buildKey that wont be found in
+ // the project tree, so that the project()->findNodeForBuildKey(buildKey)
+ // returns null.
+ QTC_ASSERT(d->m_activeRunConfiguration, return QString(QChar(0)));
+ return d->m_activeRunConfiguration->buildKey();
}
Core::Id Target::id() const
@@ -261,6 +262,16 @@ QString Target::toolTip() const
return d->m_kit->toHtml();
}
+QString Target::displayNameKey()
+{
+ return QString("ProjectExplorer.ProjectConfiguration.DisplayName");
+}
+
+QString Target::deviceTypeKey()
+{
+ return QString("DeviceType");
+}
+
void Target::addBuildConfiguration(BuildConfiguration *bc)
{
QTC_ASSERT(bc && !d->m_buildConfigurations.contains(bc), return);
@@ -280,7 +291,7 @@ void Target::addBuildConfiguration(BuildConfiguration *bc)
// add it
d->m_buildConfigurations.push_back(bc);
- project()->addedProjectConfiguration(bc);
+ ProjectExplorerPlugin::targetSelector()->addedBuildConfiguration(bc);
emit addedBuildConfiguration(bc);
d->m_buildConfigurationModel.addProjectConfiguration(bc);
@@ -307,7 +318,7 @@ bool Target::removeBuildConfiguration(BuildConfiguration *bc)
}
emit removedBuildConfiguration(bc);
- project()->removedProjectConfiguration(bc);
+ ProjectExplorerPlugin::targetSelector()->removedBuildConfiguration(bc);
d->m_buildConfigurationModel.removeProjectConfiguration(bc);
delete bc;
@@ -349,7 +360,7 @@ void Target::addDeployConfiguration(DeployConfiguration *dc)
// add it
d->m_deployConfigurations.push_back(dc);
- project()->addedProjectConfiguration(dc);
+ ProjectExplorerPlugin::targetSelector()->addedDeployConfiguration(dc);
d->m_deployConfigurationModel.addProjectConfiguration(dc);
emit addedDeployConfiguration(dc);
@@ -377,7 +388,7 @@ bool Target::removeDeployConfiguration(DeployConfiguration *dc)
SetActive::Cascade);
}
- project()->removedProjectConfiguration(dc);
+ ProjectExplorerPlugin::targetSelector()->removedDeployConfiguration(dc);
d->m_deployConfigurationModel.removeProjectConfiguration(dc);
emit removedDeployConfiguration(dc);
@@ -428,7 +439,7 @@ void Target::addRunConfiguration(RunConfiguration *rc)
d->m_runConfigurations.push_back(rc);
- project()->addedProjectConfiguration(rc);
+ ProjectExplorerPlugin::targetSelector()->addedRunConfiguration(rc);
d->m_runConfigurationModel.addProjectConfiguration(rc);
emit addedRunConfiguration(rc);
@@ -450,7 +461,7 @@ void Target::removeRunConfiguration(RunConfiguration *rc)
}
emit removedRunConfiguration(rc);
- project()->removedProjectConfiguration(rc);
+ ProjectExplorerPlugin::targetSelector()->removedRunConfiguration(rc);
d->m_runConfigurationModel.removeProjectConfiguration(rc);
delete rc;
@@ -501,15 +512,15 @@ QVariantMap Target::toMap() const
return QVariantMap();
QVariantMap map;
+ map.insert(displayNameKey(), displayName());
+ map.insert(deviceTypeKey(), DeviceTypeKitAspect::deviceTypeId(kit()).toSetting());
{
// FIXME: For compatibility within the 4.11 cycle, remove this block later.
// This is only read by older versions of Creator, but even there not actively used.
const char CONFIGURATION_ID_KEY[] = "ProjectExplorer.ProjectConfiguration.Id";
- const char DISPLAY_NAME_KEY[] = "ProjectExplorer.ProjectConfiguration.DisplayName";
const char DEFAULT_DISPLAY_NAME_KEY[] = "ProjectExplorer.ProjectConfiguration.DefaultDisplayName";
map.insert(QLatin1String(CONFIGURATION_ID_KEY), id().toSetting());
- map.insert(QLatin1String(DISPLAY_NAME_KEY), displayName());
map.insert(QLatin1String(DEFAULT_DISPLAY_NAME_KEY), displayName());
}
diff --git a/src/plugins/projectexplorer/target.h b/src/plugins/projectexplorer/target.h
index 1e31c47bda..26be1fb988 100644
--- a/src/plugins/projectexplorer/target.h
+++ b/src/plugins/projectexplorer/target.h
@@ -32,6 +32,8 @@
QT_FORWARD_DECLARE_CLASS(QIcon)
+namespace Utils { class MacroExpander; }
+
namespace ProjectExplorer {
class BuildConfiguration;
class BuildTargetInfo;
@@ -67,6 +69,9 @@ public:
QString displayName() const;
QString toolTip() const;
+ static QString displayNameKey();
+ static QString deviceTypeKey();
+
// Build configuration
void addBuildConfiguration(BuildConfiguration *bc);
bool removeBuildConfiguration(BuildConfiguration *bc);
@@ -116,9 +121,10 @@ public:
DeploymentData deploymentData() const;
DeploymentData buildSystemDeploymentData() const;
- const QList<BuildTargetInfo> applicationTargets() const;
BuildTargetInfo buildTarget(const QString &buildKey) const;
+ QString activeBuildKey() const; // Build key of active run configuaration
+
signals:
void targetEnabled(bool);
void iconChanged();
diff --git a/src/plugins/projectexplorer/targetsetuppage.cpp b/src/plugins/projectexplorer/targetsetuppage.cpp
index e750f06adf..20297313ac 100644
--- a/src/plugins/projectexplorer/targetsetuppage.cpp
+++ b/src/plugins/projectexplorer/targetsetuppage.cpp
@@ -101,9 +101,11 @@ public:
noValidKitLabel = new QLabel(setupTargetPage);
noValidKitLabel->setWordWrap(true);
- noValidKitLabel->setText(TargetSetupPage::tr("<span style=\" font-weight:600;\">No suitable kits found.</span><br/>"
- "Add a kit in the <a href=\"buildandrun\">options</a> "
- "or via the maintenance tool of the SDK."));
+ noValidKitLabel->setText("<span style=\" font-weight:600;\">"
+ + TargetSetupPage::tr("No suitable kits found.") + "</span><br/>"
+ + TargetSetupPage::tr("Add a kit in the <a href=\"buildandrun\">"
+ "options</a> or via the maintenance tool of"
+ " the SDK."));
noValidKitLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
noValidKitLabel->setVisible(false);
diff --git a/src/plugins/projectexplorer/targetsetupwidget.cpp b/src/plugins/projectexplorer/targetsetupwidget.cpp
index 281723dedd..2982ed9ad6 100644
--- a/src/plugins/projectexplorer/targetsetupwidget.cpp
+++ b/src/plugins/projectexplorer/targetsetupwidget.cpp
@@ -160,7 +160,7 @@ void TargetSetupWidget::addBuildInfo(const BuildInfo &info, bool isImport)
store.pathChooser = new Utils::PathChooser();
store.pathChooser->setExpectedKind(Utils::PathChooser::Directory);
- store.pathChooser->setFileName(info.buildDirectory);
+ store.pathChooser->setFilePath(info.buildDirectory);
store.pathChooser->setHistoryCompleter(QLatin1String("TargetSetup.BuildDir.History"));
store.pathChooser->setReadOnly(isImport);
m_newBuildsLayout->addWidget(store.pathChooser, pos * 2, 1);
@@ -302,7 +302,7 @@ void TargetSetupWidget::updateDefaultBuildDirectories()
if (buildInfoStore.buildInfo.typeName == buildInfo.typeName) {
if (!buildInfoStore.customBuildDir) {
m_ignoreChange = true;
- buildInfoStore.pathChooser->setFileName(buildInfo.buildDirectory);
+ buildInfoStore.pathChooser->setFilePath(buildInfo.buildDirectory);
m_ignoreChange = false;
}
found = true;
@@ -344,7 +344,7 @@ void TargetSetupWidget::pathChanged()
return store.pathChooser == pathChooser;
});
QTC_ASSERT(it != m_infoStore.end(), return);
- it->buildInfo.buildDirectory = pathChooser->fileName();
+ it->buildInfo.buildDirectory = pathChooser->filePath();
it->customBuildDir = true;
reportIssues(static_cast<int>(std::distance(m_infoStore.begin(), it)));
}
@@ -388,7 +388,7 @@ QPair<Task::TaskType, QString> TargetSetupWidget::findIssues(const BuildInfo &in
highestType = Task::Warning;
severity = tr("<b>Warning:</b> ", "Severity is Task::Warning");
}
- text.append(severity + t.description);
+ text.append(severity + t.description());
}
if (!text.isEmpty())
text = QLatin1String("<nobr>") + text;
diff --git a/src/plugins/projectexplorer/task.cpp b/src/plugins/projectexplorer/task.cpp
index 136d4db09a..1e68e747d3 100644
--- a/src/plugins/projectexplorer/task.cpp
+++ b/src/plugins/projectexplorer/task.cpp
@@ -62,15 +62,20 @@ unsigned int Task::s_nextId = 1;
\sa ProjectExplorer::TaskHub
*/
-Task::Task(TaskType type_, const QString &description_,
+Task::Task(TaskType type_, const QString &description,
const Utils::FilePath &file_, int line_, Core::Id category_,
const QIcon &icon, Options options) :
- taskId(s_nextId), type(type_), options(options), description(description_),
+ taskId(s_nextId), type(type_), options(options), summary(description),
line(line_), movedLine(line_), category(category_),
icon(icon.isNull() ? taskTypeIcon(type_) : icon)
{
++s_nextId;
setFile(file_);
+ QStringList desc = description.split('\n');
+ if (desc.length() > 1) {
+ summary = desc.first();
+ details = desc.mid(1);
+ }
}
Task Task::compilerMissingTask()
@@ -81,14 +86,6 @@ Task Task::compilerMissingTask()
.arg(Core::Constants::IDE_DISPLAY_NAME));
}
-Task Task::buildConfigurationMissingTask()
-{
- return BuildSystemTask(Task::Error,
- tr("%1 needs a build configuration set up to build. "
- "Configure a build configuration in the project settings.")
- .arg(Core::Constants::IDE_DISPLAY_NAME));
-}
-
void Task::setMark(TextEditor::TextMark *mark)
{
QTC_ASSERT(mark, return);
@@ -105,7 +102,8 @@ void Task::clear()
{
taskId = 0;
type = Task::Unknown;
- description.clear();
+ summary.clear();
+ details.clear();
file = Utils::FilePath();
line = -1;
movedLine = -1;
@@ -127,6 +125,14 @@ void Task::setFile(const Utils::FilePath &file_)
}
}
+QString Task::description() const
+{
+ QString desc = summary;
+ if (!details.isEmpty())
+ desc.append('\n').append(details.join('\n'));
+ return desc;
+}
+
//
// functions
//
@@ -181,7 +187,7 @@ QString toHtml(const Tasks &issues)
default:
break;
}
- str << "</b>" << t.description << "<br>";
+ str << "</b>" << t.description() << "<br>";
}
return result;
}
diff --git a/src/plugins/projectexplorer/task.h b/src/plugins/projectexplorer/task.h
index 8d17f086fb..d609a13584 100644
--- a/src/plugins/projectexplorer/task.h
+++ b/src/plugins/projectexplorer/task.h
@@ -32,6 +32,7 @@
#include <QIcon>
#include <QMetaType>
+#include <QStringList>
#include <QTextLayout>
namespace TextEditor {
@@ -68,16 +69,17 @@ public:
Options options = AddTextMark | FlashWorthy);
static Task compilerMissingTask();
- static Task buildConfigurationMissingTask();
bool isNull() const;
void clear();
void setFile(const Utils::FilePath &file);
+ QString description() const;
unsigned int taskId = 0;
TaskType type = Unknown;
Options options = AddTextMark | FlashWorthy;
- QString description;
+ QString summary;
+ QStringList details;
Utils::FilePath file;
Utils::FilePaths fileCandidates;
int line = -1;
diff --git a/src/plugins/projectexplorer/taskhub.cpp b/src/plugins/projectexplorer/taskhub.cpp
index ea38fe0422..cb41d8fafe 100644
--- a/src/plugins/projectexplorer/taskhub.cpp
+++ b/src/plugins/projectexplorer/taskhub.cpp
@@ -74,9 +74,9 @@ public:
if (task.category == Constants::TASK_CATEGORY_COMPILE) {
setToolTip("<html><body><b>" + QApplication::translate("TaskHub", "Build Issue")
+ "</b><br/><code style=\"white-space:pre;font-family:monospace\">"
- + task.description.toHtmlEscaped() + "</code></body></html>");
+ + task.description().toHtmlEscaped() + "</code></body></html>");
} else {
- setToolTip(task.description);
+ setToolTip(task.description());
}
setIcon(task.icon);
setVisible(!task.icon.isNull());
@@ -152,7 +152,7 @@ void TaskHub::addTask(Task::TaskType type, const QString &description, Core::Id
void TaskHub::addTask(Task task)
{
QTC_ASSERT(m_registeredCategories.contains(task.category), return);
- QTC_ASSERT(!task.description.isEmpty(), return);
+ QTC_ASSERT(!task.description().isEmpty(), return);
QTC_ASSERT(!task.isNull(), return);
QTC_ASSERT(task.m_mark.isNull(), return);
diff --git a/src/plugins/projectexplorer/taskmodel.cpp b/src/plugins/projectexplorer/taskmodel.cpp
index f256f026cb..abcbc6732b 100644
--- a/src/plugins/projectexplorer/taskmodel.cpp
+++ b/src/plugins/projectexplorer/taskmodel.cpp
@@ -247,7 +247,7 @@ QVariant TaskModel::data(const QModelIndex &index, int role) const
else if (role == TaskModel::MovedLine)
return m_tasks.at(index.row()).movedLine;
else if (role == TaskModel::Description)
- return m_tasks.at(index.row()).description;
+ return m_tasks.at(index.row()).description();
else if (role == TaskModel::FileNotFound)
return m_fileNotFound.value(m_tasks.at(index.row()).file.toString());
else if (role == TaskModel::Type)
@@ -405,7 +405,7 @@ bool TaskFilterModel::filterAcceptsTask(const Task &task) const
return m_filterStringIsRegexp ? m_filterRegexp.isValid() && s.contains(m_filterRegexp)
: s.contains(m_filterText, m_filterCaseSensitivity);
};
- if ((accepts(task.file.toString()) || accepts(task.description)) == m_filterIsInverted)
+ if ((accepts(task.file.toString()) || accepts(task.description())) == m_filterIsInverted)
accept = false;
}
diff --git a/src/plugins/projectexplorer/taskwindow.cpp b/src/plugins/projectexplorer/taskwindow.cpp
index 9548be0552..732f29c50e 100644
--- a/src/plugins/projectexplorer/taskwindow.cpp
+++ b/src/plugins/projectexplorer/taskwindow.cpp
@@ -34,13 +34,15 @@
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/command.h>
+#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/icore.h>
#include <coreplugin/icontext.h>
#include <utils/algorithm.h>
#include <utils/fileinprojectfinder.h>
-#include <utils/qtcassert.h>
#include <utils/itemviews.h>
+#include <utils/outputformatter.h>
+#include <utils/qtcassert.h>
#include <utils/utilsicons.h>
#include <QDir>
@@ -77,7 +79,23 @@ class TaskView : public Utils::ListView
public:
TaskView(QWidget *parent = nullptr);
~TaskView() override;
+
+private:
void resizeEvent(QResizeEvent *e) override;
+ void mousePressEvent(QMouseEvent *e) override;
+ void mouseReleaseEvent(QMouseEvent *e) override;
+ void mouseMoveEvent(QMouseEvent *e) override;
+
+ class Location {
+ public:
+ Utils::FilePath file;
+ int line;
+ int column;
+ };
+ Location locationForPos(const QPoint &pos);
+
+ bool m_linksActive = true;
+ Qt::MouseButton m_mouseButtonPressed = Qt::NoButton;
};
class TaskWindowContext : public Core::IContext
@@ -103,11 +121,14 @@ public:
void currentChanged(const QModelIndex &current, const QModelIndex &previous);
+ QString hrefForPos(const QPointF &pos);
+
private:
void generateGradientPixmap(int width, int height, QColor color, bool selected) const;
mutable int m_cachedHeight = 0;
mutable QFont m_cachedFont;
+ mutable QList<QPair<QRectF, QString>> m_hrefs;
/*
Collapsed:
@@ -186,6 +207,7 @@ TaskView::TaskView(QWidget *parent)
{
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
+ setMouseTracking(true);
QFontMetrics fm(font());
int vStepSize = fm.height() + 3;
@@ -203,6 +225,54 @@ void TaskView::resizeEvent(QResizeEvent *e)
static_cast<TaskDelegate *>(itemDelegate())->emitSizeHintChanged(selectionModel()->currentIndex());
}
+void TaskView::mousePressEvent(QMouseEvent *e)
+{
+ m_mouseButtonPressed = e->button();
+ ListView::mousePressEvent(e);
+}
+
+void TaskView::mouseReleaseEvent(QMouseEvent *e)
+{
+ if (m_linksActive && m_mouseButtonPressed == Qt::LeftButton) {
+ const Location loc = locationForPos(e->pos());
+ if (!loc.file.isEmpty())
+ Core::EditorManager::openEditorAt(loc.file.toString(), loc.line, loc.column);
+ }
+
+ // Mouse was released, activate links again
+ m_linksActive = true;
+ m_mouseButtonPressed = Qt::NoButton;
+ ListView::mouseReleaseEvent(e);
+}
+
+void TaskView::mouseMoveEvent(QMouseEvent *e)
+{
+ // Cursor was dragged, deactivate links
+ if (m_mouseButtonPressed != Qt::NoButton)
+ m_linksActive = false;
+
+ viewport()->setCursor(m_linksActive && !locationForPos(e->pos()).file.isEmpty()
+ ? Qt::PointingHandCursor : Qt::ArrowCursor);
+ ListView::mouseMoveEvent(e);
+}
+
+TaskView::Location TaskView::locationForPos(const QPoint &pos)
+{
+ const auto delegate = qobject_cast<TaskDelegate *>(itemDelegate(indexAt(pos)));
+ if (!delegate)
+ return {};
+ Utils::OutputFormatter formatter;
+ Location loc;
+ connect(&formatter, &Utils::OutputFormatter::openInEditorRequested, this,
+ [&loc](const Utils::FilePath &fp, int line, int column) {
+ loc.file = fp;
+ loc.line = line;
+ loc.column = column;
+ });
+ formatter.handleLink(delegate->hrefForPos(pos));
+ return loc;
+}
+
/////
// TaskWindow
/////
@@ -764,6 +834,15 @@ void TaskDelegate::currentChanged(const QModelIndex &current, const QModelIndex
emit sizeHintChanged(previous);
}
+QString TaskDelegate::hrefForPos(const QPointF &pos)
+{
+ for (const auto &link : m_hrefs) {
+ if (link.first.contains(pos))
+ return link.second;
+ }
+ return {};
+}
+
void TaskDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QStyleOptionViewItem opt = option;
@@ -825,7 +904,10 @@ void TaskDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
int height = 0;
description.replace(QLatin1Char('\n'), QChar::LineSeparator);
QTextLayout tl(description);
- tl.setFormats(index.data(TaskModel::Task_t).value<Task>().formats);
+ QVector<QTextLayout::FormatRange> formats = index.data(TaskModel::Task_t).value<Task>().formats;
+ for (QTextLayout::FormatRange &format : formats)
+ format.format.setForeground(opt.palette.highlightedText());
+ tl.setFormats(formats);
tl.beginLayout();
while (true) {
QTextLine line = tl.createLine();
@@ -837,7 +919,33 @@ void TaskDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
height += static_cast<int>(line.height());
}
tl.endLayout();
+ const QPoint indexPos = view->visualRect(index).topLeft();
tl.draw(painter, QPoint(positions.textAreaLeft(), positions.top()));
+ m_hrefs.clear();
+ for (const auto &range : tl.formats()) {
+ if (!range.format.isAnchor())
+ continue;
+ const QTextLine &firstLinkLine = tl.lineForTextPosition(range.start);
+ const QTextLine &lastLinkLine = tl.lineForTextPosition(range.start + range.length - 1);
+ for (int i = firstLinkLine.lineNumber(); i <= lastLinkLine.lineNumber(); ++i) {
+ const QTextLine &linkLine = tl.lineAt(i);
+ if (!linkLine.isValid())
+ break;
+ const QPointF linePos = linkLine.position();
+ const int linkStartPos = i == firstLinkLine.lineNumber()
+ ? range.start : linkLine.textStart();
+ const qreal startOffset = linkLine.cursorToX(linkStartPos);
+ const int linkEndPos = i == lastLinkLine.lineNumber()
+ ? range.start + range.length
+ : linkLine.textStart() + linkLine.textLength();
+ const qreal endOffset = linkLine.cursorToX(linkEndPos);
+ const QPointF linkPos(indexPos.x() + positions.textAreaLeft() + linePos.x()
+ + startOffset, positions.top() + linePos.y());
+ const QSize linkSize(endOffset - startOffset, linkLine.height());
+ const QRectF linkRect(linkPos, linkSize);
+ m_hrefs << qMakePair(linkRect, range.format.anchorHref());
+ }
+ }
QColor mix;
mix.setRgb( static_cast<int>(0.7 * textColor.red() + 0.3 * backgroundColor.red()),
diff --git a/src/plugins/projectexplorer/toolchain.h b/src/plugins/projectexplorer/toolchain.h
index 519239c1f0..b2dbc7ca9a 100644
--- a/src/plugins/projectexplorer/toolchain.h
+++ b/src/plugins/projectexplorer/toolchain.h
@@ -47,6 +47,8 @@
#include <functional>
#include <memory>
+namespace Utils { class OutputLineParser; }
+
namespace ProjectExplorer {
namespace Internal { class ToolChainPrivate; }
@@ -64,7 +66,6 @@ QString languageId(Language l);
} // namespace Deprecated
class Abi;
-class IOutputParser;
class ToolChainConfigWidget;
class ToolChainFactory;
class Kit;
@@ -150,7 +151,7 @@ public:
Core::Id language() const;
virtual Utils::FilePath compilerCommand() const = 0;
- virtual IOutputParser *outputParser() const = 0;
+ virtual QList<Utils::OutputLineParser *> createOutputParsers() const = 0;
virtual bool operator ==(const ToolChain &) const;
@@ -193,13 +194,14 @@ private:
friend class ToolChainFactory;
};
-class PROJECTEXPLORER_EXPORT ToolChainFactory : public QObject
+class PROJECTEXPLORER_EXPORT ToolChainFactory
{
- Q_OBJECT
+ ToolChainFactory(const ToolChainFactory &) = delete;
+ ToolChainFactory &operator=(const ToolChainFactory &) = delete;
public:
ToolChainFactory();
- ~ToolChainFactory() override;
+ virtual ~ToolChainFactory();
static const QList<ToolChainFactory *> allToolChainFactories();
diff --git a/src/plugins/projectexplorer/toolchainconfigwidget.cpp b/src/plugins/projectexplorer/toolchainconfigwidget.cpp
index 96e021a867..d38c6ea3bf 100644
--- a/src/plugins/projectexplorer/toolchainconfigwidget.cpp
+++ b/src/plugins/projectexplorer/toolchainconfigwidget.cpp
@@ -28,6 +28,7 @@
#include <utils/detailswidget.h>
#include <utils/qtcassert.h>
+#include <utils/qtcprocess.h>
#include <QString>
@@ -125,4 +126,20 @@ void ToolChainConfigWidget::clearErrorMessage()
m_errorLabel->setVisible(false);
}
+QStringList ToolChainConfigWidget::splitString(const QString &s)
+{
+ Utils::QtcProcess::SplitError splitError;
+ const Utils::OsType osType = Utils::HostOsInfo::hostOs();
+ QStringList res = Utils::QtcProcess::splitArgs(s, osType, false, &splitError);
+ if (splitError != Utils::QtcProcess::SplitOk){
+ res = Utils::QtcProcess::splitArgs(s + '\\', osType, false, &splitError);
+ if (splitError != Utils::QtcProcess::SplitOk){
+ res = Utils::QtcProcess::splitArgs(s + '"', osType, false, &splitError);
+ if (splitError != Utils::QtcProcess::SplitOk)
+ res = Utils::QtcProcess::splitArgs(s + '\'', osType, false, &splitError);
+ }
+ }
+ return res;
+}
+
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/toolchainconfigwidget.h b/src/plugins/projectexplorer/toolchainconfigwidget.h
index e6b5764ca4..8e48fc1ca9 100644
--- a/src/plugins/projectexplorer/toolchainconfigwidget.h
+++ b/src/plugins/projectexplorer/toolchainconfigwidget.h
@@ -71,6 +71,7 @@ protected:
virtual void makeReadOnlyImpl() = 0;
void addErrorLabel();
+ static QStringList splitString(const QString &s);
QFormLayout *m_mainLayout;
QLineEdit *m_nameLineEdit;
diff --git a/src/plugins/projectexplorer/toolchainsettingsaccessor.cpp b/src/plugins/projectexplorer/toolchainsettingsaccessor.cpp
index 78fafb5ea7..dd6e540b1a 100644
--- a/src/plugins/projectexplorer/toolchainsettingsaccessor.cpp
+++ b/src/plugins/projectexplorer/toolchainsettingsaccessor.cpp
@@ -324,7 +324,7 @@ public:
void addToEnvironment(Environment &env) const override { Q_UNUSED(env) }
FilePath makeCommand(const Environment &) const override { return FilePath::fromString("make"); }
FilePath compilerCommand() const override { return Utils::FilePath::fromString("/tmp/test/gcc"); }
- IOutputParser *outputParser() const override { return nullptr; }
+ QList<OutputLineParser *> createOutputParsers() const override { return {}; }
std::unique_ptr<ToolChainConfigWidget> createConfigurationWidget() override { return nullptr; }
bool operator ==(const ToolChain &other) const override {
if (!ToolChain::operator==(other))
diff --git a/src/plugins/projectexplorer/xcodebuildparser.cpp b/src/plugins/projectexplorer/xcodebuildparser.cpp
index 32dc1d312a..9b6486e5d5 100644
--- a/src/plugins/projectexplorer/xcodebuildparser.cpp
+++ b/src/plugins/projectexplorer/xcodebuildparser.cpp
@@ -52,53 +52,51 @@ XcodebuildParser::XcodebuildParser()
QTC_CHECK(m_buildRe.isValid());
}
-bool XcodebuildParser::hasFatalErrors() const
-{
- return (m_fatalErrorCount > 0) || IOutputParser::hasFatalErrors();
-}
-
-void XcodebuildParser::stdOutput(const QString &line)
+OutputLineParser::Result XcodebuildParser::handleLine(const QString &line, OutputFormat type)
{
const QString lne = rightTrimmed(line);
- if (m_buildRe.indexIn(lne) > -1) {
- m_xcodeBuildParserState = InXcodebuild;
- m_lastTarget = m_buildRe.cap(2);
- m_lastProject = m_buildRe.cap(3);
- return;
- }
- if (m_xcodeBuildParserState == InXcodebuild || m_xcodeBuildParserState == UnknownXcodebuildState) {
- if (m_successRe.indexIn(lne) > -1) {
- m_xcodeBuildParserState = OutsideXcodebuild;
- return;
+ if (type == StdOutFormat) {
+ if (m_buildRe.indexIn(lne) > -1) {
+ m_xcodeBuildParserState = InXcodebuild;
+ m_lastTarget = m_buildRe.cap(2);
+ m_lastProject = m_buildRe.cap(3);
+ return Status::Done;
}
- if (lne.endsWith(QLatin1String(signatureChangeEndsWithPattern))) {
- CompileTask task(Task::Warning,
- tr("Replacing signature"),
- FilePath::fromString(
- lne.left(lne.size() - QLatin1String(signatureChangeEndsWithPattern).size())));
- taskAdded(task, 1);
- return;
+ if (m_xcodeBuildParserState == InXcodebuild
+ || m_xcodeBuildParserState == UnknownXcodebuildState) {
+ if (m_successRe.indexIn(lne) > -1) {
+ m_xcodeBuildParserState = OutsideXcodebuild;
+ return Status::Done;
+ }
+ if (lne.endsWith(QLatin1String(signatureChangeEndsWithPattern))) {
+ const int filePathEndPos = lne.size()
+ - QLatin1String(signatureChangeEndsWithPattern).size();
+ CompileTask task(Task::Warning,
+ tr("Replacing signature"),
+ absoluteFilePath(FilePath::fromString(
+ lne.left(filePathEndPos))));
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, task.file, task.line, 0, filePathEndPos);
+ scheduleTask(task, 1);
+ return {Status::Done, linkSpecs};
+ }
}
- IOutputParser::stdError(line);
- } else {
- IOutputParser::stdOutput(line);
+ return Status::NotHandled;
}
-}
-
-void XcodebuildParser::stdError(const QString &line)
-{
- const QString lne = rightTrimmed(line);
if (m_failureRe.indexIn(lne) > -1) {
++m_fatalErrorCount;
m_xcodeBuildParserState = UnknownXcodebuildState;
// unfortunately the m_lastTarget, m_lastProject might not be in sync
- taskAdded(CompileTask(Task::Error, tr("Xcodebuild failed.")));
- return;
- }
- if (m_xcodeBuildParserState == OutsideXcodebuild) { // also forward if UnknownXcodebuildState ?
- IOutputParser::stdError(line);
- return;
+ scheduleTask(CompileTask(Task::Error, tr("Xcodebuild failed.")), 1);
}
+ if (m_xcodeBuildParserState == OutsideXcodebuild)
+ return Status::NotHandled;
+ return Status::Done;
+}
+
+bool XcodebuildParser::hasDetectedRedirection() const
+{
+ return m_xcodeBuildParserState != OutsideXcodebuild;
}
} // namespace ProjectExplorer
@@ -260,7 +258,7 @@ void ProjectExplorerPlugin::testXcodebuildParserParsing()
connect(&testbench, &OutputParserTester::aboutToDeleteParser,
tester, &XcodebuildParserTester::onAboutToDeleteParser);
- testbench.appendOutputParser(childParser);
+ testbench.addLineParser(childParser);
QFETCH(ProjectExplorer::XcodebuildParser::XcodebuildStatus, initialStatus);
QFETCH(QString, input);
QFETCH(OutputParserTester::Channel, inputChannel);
diff --git a/src/plugins/projectexplorer/xcodebuildparser.h b/src/plugins/projectexplorer/xcodebuildparser.h
index 4333a8fcef..9342cd3785 100644
--- a/src/plugins/projectexplorer/xcodebuildparser.h
+++ b/src/plugins/projectexplorer/xcodebuildparser.h
@@ -34,7 +34,7 @@
namespace ProjectExplorer {
-class PROJECTEXPLORER_EXPORT XcodebuildParser : public IOutputParser
+class PROJECTEXPLORER_EXPORT XcodebuildParser : public OutputTaskParser
{
Q_OBJECT
public:
@@ -46,11 +46,11 @@ public:
XcodebuildParser();
- void stdOutput(const QString &line) override;
- void stdError(const QString &line) override;
- bool hasFatalErrors() const override;
-
private:
+ Result handleLine(const QString &line, Utils::OutputFormat type) override;
+ bool hasDetectedRedirection() const override;
+ bool hasFatalErrors() const override { return m_fatalErrorCount > 0; }
+
int m_fatalErrorCount = 0;
QRegExp m_failureRe;
QRegExp m_successRe;
diff --git a/src/plugins/python/pythonconstants.h b/src/plugins/python/pythonconstants.h
index 0fba0603e9..eb01dc5fab 100644
--- a/src/plugins/python/pythonconstants.h
+++ b/src/plugins/python/pythonconstants.h
@@ -37,6 +37,10 @@ const char C_EDITOR_DISPLAY_NAME[] =
const char C_PYTHONOPTIONS_PAGE_ID[] = "PythonEditor.OptionsPage";
const char C_PYTHON_SETTINGS_CATEGORY[] = "P.Python";
+const char PYTHON_OPEN_REPL[] = "Python.OpenRepl";
+const char PYTHON_OPEN_REPL_IMPORT[] = "Python.OpenReplImport";
+const char PYTHON_OPEN_REPL_IMPORT_TOPLEVEL[] = "Python.OpenReplImportToplevel";
+
/*******************************************************************************
* MIME type
******************************************************************************/
diff --git a/src/plugins/python/pythoneditor.cpp b/src/plugins/python/pythoneditor.cpp
index cfd8623363..9b98493c83 100644
--- a/src/plugins/python/pythoneditor.cpp
+++ b/src/plugins/python/pythoneditor.cpp
@@ -27,16 +27,81 @@
#include "pythonconstants.h"
#include "pythonhighlighter.h"
#include "pythonindenter.h"
+#include "pythonsettings.h"
#include "pythonutils.h"
+#include <coreplugin/actionmanager/actionmanager.h>
+#include <coreplugin/actionmanager/commandbutton.h>
+
#include <texteditor/textdocument.h>
#include <texteditor/texteditoractionhandler.h>
+#include <QAction>
+#include <QMenu>
+
namespace Python {
namespace Internal {
+static QAction *createAction(QObject *parent, ReplType type)
+{
+ QAction *action = new QAction(parent);
+ switch (type) {
+ case ReplType::Unmodified:
+ action->setText(QCoreApplication::translate("Python", "REPL"));
+ action->setToolTip(QCoreApplication::translate("Python", "Open interactive Python."));
+ break;
+ case ReplType::Import:
+ action->setText(QCoreApplication::translate("Python", "REPL Import File"));
+ action->setToolTip(
+ QCoreApplication::translate("Python", "Open interactive Python and import file."));
+ break;
+ case ReplType::ImportToplevel:
+ action->setText(QCoreApplication::translate("Python", "REPL Import *"));
+ action->setToolTip(
+ QCoreApplication::translate("Python",
+ "Open interactive Python and import * from file."));
+ break;
+ }
+
+ QObject::connect(action, &QAction::triggered, parent, [type] {
+ Core::IDocument *doc = Core::EditorManager::currentDocument();
+ openPythonRepl(doc ? doc->filePath() : Utils::FilePath(), type);
+ });
+ return action;
+}
+
+static void registerReplAction(QObject *parent)
+{
+ Core::ActionManager::registerAction(createAction(parent, ReplType::Unmodified),
+ Constants::PYTHON_OPEN_REPL);
+ Core::ActionManager::registerAction(createAction(parent, ReplType::Import),
+ Constants::PYTHON_OPEN_REPL_IMPORT);
+ Core::ActionManager::registerAction(createAction(parent, ReplType::ImportToplevel),
+ Constants::PYTHON_OPEN_REPL_IMPORT_TOPLEVEL);
+}
+
+static QWidget *createEditorWidget()
+{
+ auto widget = new TextEditor::TextEditorWidget;
+ auto replButton = new QToolButton(widget);
+ replButton->setProperty("noArrow", true);
+ replButton->setText(QCoreApplication::translate("Python", "REPL"));
+ replButton->setPopupMode(QToolButton::InstantPopup);
+ auto menu = new QMenu(replButton);
+ replButton->setMenu(menu);
+ menu->addAction(Core::ActionManager::command(Constants::PYTHON_OPEN_REPL)->action());
+ menu->addSeparator();
+ menu->addAction(Core::ActionManager::command(Constants::PYTHON_OPEN_REPL_IMPORT)->action());
+ menu->addAction(
+ Core::ActionManager::command(Constants::PYTHON_OPEN_REPL_IMPORT_TOPLEVEL)->action());
+ widget->insertExtraToolBarWidget(TextEditor::TextEditorWidget::Left, replButton);
+ return widget;
+}
+
PythonEditorFactory::PythonEditorFactory()
{
+ registerReplAction(this);
+
setId(Constants::C_PYTHONEDITOR_ID);
setDisplayName(
QCoreApplication::translate("OpenWith::Editors", Constants::C_EDITOR_DISPLAY_NAME));
@@ -48,6 +113,7 @@ PythonEditorFactory::PythonEditorFactory()
| TextEditor::TextEditorActionHandler::FollowSymbolUnderCursor);
setDocumentCreator([] { return new TextEditor::TextDocument(Constants::C_PYTHONEDITOR_ID); });
+ setEditorWidgetCreator(createEditorWidget);
setIndenterCreator([](QTextDocument *doc) { return new PythonIndenter(doc); });
setSyntaxHighlighterCreator([] { return new PythonHighlighter; });
setCommentDefinition(Utils::CommentDefinition::HashStyle);
diff --git a/src/plugins/python/pythonrunconfiguration.cpp b/src/plugins/python/pythonrunconfiguration.cpp
index 1783b46930..1b0db037b8 100644
--- a/src/plugins/python/pythonrunconfiguration.cpp
+++ b/src/plugins/python/pythonrunconfiguration.cpp
@@ -60,10 +60,10 @@ using namespace Utils;
namespace Python {
namespace Internal {
-class PythonOutputFormatter : public OutputFormatter
+class PythonOutputLineParser : public OutputLineParser
{
public:
- PythonOutputFormatter()
+ PythonOutputLineParser()
// Note that moc dislikes raw string literals.
: filePattern("^(\\s*)(File \"([^\"]+)\", line (\\d+), .*$)")
{
@@ -71,66 +71,64 @@ public:
}
private:
- void appendMessage(const QString &text, OutputFormat format) final
+ Result handleLine(const QString &text, OutputFormat format) final
{
- const bool isTrace = (format == StdErrFormat
- || format == StdErrFormatSameLine)
- && (text.startsWith("Traceback (most recent call last):")
- || text.startsWith("\nTraceback (most recent call last):"));
-
- if (!isTrace) {
- OutputFormatter::appendMessage(text, format);
- return;
+ if (!m_inTraceBack) {
+ m_inTraceBack = format == StdErrFormat
+ && text.startsWith("Traceback (most recent call last):");
+ if (m_inTraceBack)
+ return Status::InProgress;
+ return Status::NotHandled;
}
- const QTextCharFormat frm = charFormat(format);
- const Core::Id id(PythonErrorTaskCategory);
- QVector<Task> tasks;
- const QStringList lines = text.split('\n');
- unsigned taskId = unsigned(lines.size());
-
- for (const QString &line : lines) {
- const QRegularExpressionMatch match = filePattern.match(line);
- if (match.hasMatch()) {
- QTextCursor tc = plainTextEdit()->textCursor();
- tc.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);
- tc.insertText('\n' + match.captured(1));
- tc.insertText(match.captured(2), linkFormat(frm, match.captured(2)));
-
- const auto fileName = FilePath::fromString(match.captured(3));
- const int lineNumber = match.capturedRef(4).toInt();
- Task task(Task::Warning,
- QString(), fileName, lineNumber, id);
- task.taskId = --taskId;
- tasks.append(task);
+ const Core::Id category(PythonErrorTaskCategory);
+ const QRegularExpressionMatch match = filePattern.match(text);
+ if (match.hasMatch()) {
+ const LinkSpec link(match.capturedStart(2), match.capturedLength(2), match.captured(2));
+ const auto fileName = FilePath::fromString(match.captured(3));
+ const int lineNumber = match.capturedRef(4).toInt();
+ m_tasks.append({Task::Warning, QString(), fileName, lineNumber, category});
+ return {Status::InProgress, {link}};
+ }
+
+ Status status = Status::InProgress;
+ if (text.startsWith(' ')) {
+ // Neither traceback start, nor file, nor error message line.
+ // Not sure if that can actually happen.
+ if (m_tasks.isEmpty()) {
+ m_tasks.append({Task::Warning, text.trimmed(), {}, -1, category});
} else {
- if (!tasks.isEmpty()) {
- Task &task = tasks.back();
- if (!task.description.isEmpty())
- task.description += ' ';
- task.description += line.trimmed();
- }
- OutputFormatter::appendMessage('\n' + line, format);
+ Task &task = m_tasks.back();
+ if (!task.summary.isEmpty())
+ task.summary += ' ';
+ task.summary += text.trimmed();
}
- }
- if (!tasks.isEmpty()) {
- tasks.back().type = Task::Error;
- for (auto rit = tasks.crbegin(), rend = tasks.crend(); rit != rend; ++rit)
+ } else {
+ // The actual exception. This ends the traceback.
+ TaskHub::addTask({Task::Error, text, {}, -1, category});
+ for (auto rit = m_tasks.crbegin(), rend = m_tasks.crend(); rit != rend; ++rit)
TaskHub::addTask(*rit);
+ m_tasks.clear();
+ m_inTraceBack = false;
+ status = Status::Done;
}
+ return status;
}
- void handleLink(const QString &href) final
+ bool handleLink(const QString &href) final
{
const QRegularExpressionMatch match = filePattern.match(href);
if (!match.hasMatch())
- return;
+ return false;
const QString fileName = match.captured(3);
const int lineNumber = match.capturedRef(4).toInt();
Core::EditorManager::openEditorAt(fileName, lineNumber);
+ return true;
}
const QRegularExpression filePattern;
+ QList<Task> m_tasks;
+ bool m_inTraceBack;
};
////////////////////////////////////////////////////////////////
@@ -333,10 +331,10 @@ PythonRunConfigurationFactory::PythonRunConfigurationFactory()
PythonOutputFormatterFactory::PythonOutputFormatterFactory()
{
- setFormatterCreator([](Target *t) -> OutputFormatter * {
- if (t->project()->mimeType() == Constants::C_PY_MIMETYPE)
- return new PythonOutputFormatter;
- return nullptr;
+ setFormatterCreator([](Target *t) -> QList<OutputLineParser *> {
+ if (t && t->project()->mimeType() == Constants::C_PY_MIMETYPE)
+ return {new PythonOutputLineParser};
+ return {};
});
}
diff --git a/src/plugins/python/pythonsettings.cpp b/src/plugins/python/pythonsettings.cpp
index d2d1d74f87..e45ff9d5e5 100644
--- a/src/plugins/python/pythonsettings.cpp
+++ b/src/plugins/python/pythonsettings.cpp
@@ -79,7 +79,7 @@ public:
Interpreter toInterpreter()
{
- return {m_currentId, m_name->text(), FilePath::fromUserInput(m_executable->path())};
+ return {m_currentId, m_name->text(), FilePath::fromUserInput(m_executable->filePath().toString())};
}
QLineEdit *m_name = nullptr;
PathChooser *m_executable = nullptr;
@@ -123,9 +123,7 @@ InterpreterOptionsWidget::InterpreterOptionsWidget(const QList<Interpreter> &int
}
return {};
});
-
- for (const Interpreter &interpreter : interpreters)
- m_model.appendItem(interpreter);
+ m_model.setAllData(interpreters);
auto mainLayout = new QVBoxLayout();
auto layout = new QHBoxLayout();
@@ -308,11 +306,9 @@ void InterpreterOptionsWidget::makeDefault()
{
const QModelIndex &index = m_view.currentIndex();
if (index.isValid()) {
- QModelIndex defaultIndex;
- if (auto *defaultItem = m_model.findItemByData(
- [this](const Interpreter &interpreter) { return interpreter.id == m_defaultId; })) {
- defaultIndex = m_model.indexForItem(defaultItem);
- }
+ QModelIndex defaultIndex = m_model.findIndex([this](const Interpreter &interpreter) {
+ return interpreter.id == m_defaultId;
+ });
m_defaultId = m_model.itemAt(index.row())->itemData.id;
emit m_model.dataChanged(index, index, {Qt::FontRole});
if (defaultIndex.isValid())
diff --git a/src/plugins/python/pythonutils.cpp b/src/plugins/python/pythonutils.cpp
index e584a90e4d..bae86fb4e1 100644
--- a/src/plugins/python/pythonutils.cpp
+++ b/src/plugins/python/pythonutils.cpp
@@ -43,6 +43,8 @@
#include <texteditor/textdocument.h>
+#include <utils/consoleprocess.h>
+#include <utils/mimetypes/mimedatabase.h>
#include <utils/qtcassert.h>
#include <utils/runextensions.h>
#include <utils/synchronousprocess.h>
@@ -170,8 +172,10 @@ static FilePath detectPython(const FilePath &documentPath)
{
FilePath python;
- PythonProject *project = qobject_cast<PythonProject *>(
- ProjectExplorer::SessionManager::projectForFile(documentPath));
+ PythonProject *project = documentPath.isEmpty()
+ ? nullptr
+ : qobject_cast<PythonProject *>(
+ ProjectExplorer::SessionManager::projectForFile(documentPath));
if (!project)
project = qobject_cast<PythonProject *>(ProjectExplorer::SessionManager::startupProject());
@@ -285,7 +289,7 @@ private:
m_future.reportFinished();
if (exitStatus == QProcess::NormalExit && exitCode == 0) {
if (Client *client = registerLanguageServer(m_python))
- LanguageClientManager::reOpenDocumentWithClient(m_document, client);
+ LanguageClientManager::openDocumentWithClient(m_document, client);
} else {
Core::MessageManager::write(
tr("Installing the Python language server failed with exit code %1").arg(exitCode));
@@ -334,7 +338,7 @@ static void setupPythonLanguageServer(const FilePath &python,
{
document->infoBar()->removeInfo(startPylsInfoBarId);
if (Client *client = registerLanguageServer(python))
- LanguageClientManager::reOpenDocumentWithClient(document, client);
+ LanguageClientManager::openDocumentWithClient(document, client);
}
static void enablePythonLanguageServer(const FilePath &python,
@@ -345,7 +349,7 @@ static void enablePythonLanguageServer(const FilePath &python,
LanguageClientManager::enableClientSettings(setting->m_id);
if (const StdIOSettings *setting = PyLSConfigureAssistant::languageServerForPython(python)) {
if (Client *client = LanguageClientManager::clientForSetting(setting).value(0)) {
- LanguageClientManager::reOpenDocumentWithClient(document, client);
+ LanguageClientManager::openDocumentWithClient(document, client);
PyLSConfigureAssistant::updateEditorInfoBars(python, client);
}
}
@@ -402,7 +406,7 @@ void PyLSConfigureAssistant::handlePyLSState(const FilePath &python,
if (state.state == PythonLanguageServerState::AlreadyConfigured) {
if (const StdIOSettings *setting = languageServerForPython(python)) {
if (Client *client = LanguageClientManager::clientForSetting(setting).value(0))
- LanguageClientManager::reOpenDocumentWithClient(document, client);
+ LanguageClientManager::openDocumentWithClient(document, client);
}
return;
}
@@ -452,7 +456,7 @@ void PyLSConfigureAssistant::updateEditorInfoBars(const FilePath &python, Client
for (TextEditor::TextDocument *document : instance()->m_infoBarEntries.take(python)) {
instance()->resetEditorInfoBar(document);
if (client)
- LanguageClientManager::reOpenDocumentWithClient(document, client);
+ LanguageClientManager::openDocumentWithClient(document, client);
}
}
@@ -480,6 +484,55 @@ PyLSConfigureAssistant::PyLSConfigureAssistant(QObject *parent)
});
}
+static QStringList replImportArgs(const FilePath &pythonFile, ReplType type)
+{
+ using MimeTypes = QList<MimeType>;
+ const MimeTypes mimeTypes = pythonFile.isEmpty() || type == ReplType::Unmodified
+ ? MimeTypes()
+ : mimeTypesForFileName(pythonFile.toString());
+ const bool isPython = Utils::anyOf(mimeTypes, [](const MimeType &mt) {
+ return mt.inherits("text/x-python") || mt.inherits("text/x-python3");
+ });
+ if (type == ReplType::Unmodified || !isPython)
+ return {};
+ const auto import = type == ReplType::Import
+ ? QString("import %1").arg(pythonFile.toFileInfo().completeBaseName())
+ : QString("from %1 import *")
+ .arg(pythonFile.toFileInfo().completeBaseName());
+ return {"-c", QString("%1; print('Running \"%1\"')").arg(import)};
+}
+
+void openPythonRepl(const FilePath &file, ReplType type)
+{
+ static const auto workingDir = [](const FilePath &file) {
+ if (file.isEmpty()) {
+ if (ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject())
+ return project->projectDirectory().toFileInfo().filePath();
+ return QDir::currentPath();
+ }
+ return file.toFileInfo().path();
+ };
+
+ const auto args = QStringList{"-i"} + replImportArgs(file, type);
+ auto process = new ConsoleProcess;
+ const FilePath pythonCommand = detectPython(file);
+ process->setCommand({pythonCommand, args});
+ process->setWorkingDirectory(workingDir(file));
+ const QString commandLine = process->command().toUserOutput();
+ QObject::connect(process,
+ &ConsoleProcess::processError,
+ process,
+ [process, commandLine](const QString &errorString) {
+ Core::MessageManager::write(
+ QCoreApplication::translate("Python",
+ "Failed to run Python (%1): \"%2\".")
+ .arg(commandLine, errorString));
+ process->deleteLater();
+ });
+ QObject::connect(process, &ConsoleProcess::stubStopped, process, &QObject::deleteLater);
+ process->start();
+}
+
} // namespace Internal
} // namespace Python
diff --git a/src/plugins/python/pythonutils.h b/src/plugins/python/pythonutils.h
index 28d1faf607..9bedd9f6cf 100644
--- a/src/plugins/python/pythonutils.h
+++ b/src/plugins/python/pythonutils.h
@@ -40,6 +40,10 @@ namespace TextEditor { class TextDocument; }
namespace Python {
namespace Internal {
+enum class ReplType { Unmodified, Import, ImportToplevel };
+
+void openPythonRepl(const Utils::FilePath &file, ReplType type);
+
struct PythonLanguageServerState;
class PyLSConfigureAssistant : public QObject
diff --git a/src/plugins/qbsprojectmanager/CMakeLists.txt b/src/plugins/qbsprojectmanager/CMakeLists.txt
index a754c922d7..cbe09a5661 100644
--- a/src/plugins/qbsprojectmanager/CMakeLists.txt
+++ b/src/plugins/qbsprojectmanager/CMakeLists.txt
@@ -15,7 +15,6 @@ add_qtc_plugin(QbsProjectManager
qbskitinformation.cpp qbskitinformation.h
qbsnodes.cpp qbsnodes.h
qbsnodetreebuilder.cpp qbsnodetreebuilder.h
- qbsparser.cpp qbsparser.h
qbspmlogging.cpp qbspmlogging.h
qbsprofilemanager.cpp qbsprofilemanager.h
qbsprofilessettingspage.cpp qbsprofilessettingspage.h
diff --git a/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp b/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp
index d8f380e3b6..5e94dee80c 100644
--- a/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp
+++ b/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp
@@ -52,6 +52,8 @@
#include <QRegularExpression>
#include <QSettings>
+using namespace ProjectExplorer;
+
namespace QbsProjectManager {
using namespace Constants;
@@ -253,27 +255,24 @@ QVariantMap DefaultPropertyProvider::autoGeneratedProperties(const ProjectExplor
{
QVariantMap data = defaultData;
- const QString sysroot = ProjectExplorer::SysRootKitAspect::sysRoot(k).toUserOutput();
+ const QString sysroot = SysRootKitAspect::sysRoot(k).toUserOutput();
if (!sysroot.isEmpty())
data.insert(QLatin1String(QBS_SYSROOT), sysroot);
- ProjectExplorer::ToolChain *tcC
- = ProjectExplorer::ToolChainKitAspect::toolChain(k, ProjectExplorer::Constants::C_LANGUAGE_ID);
- ProjectExplorer::ToolChain *tcCxx
- = ProjectExplorer::ToolChainKitAspect::toolChain(k, ProjectExplorer::Constants::CXX_LANGUAGE_ID);
+ ToolChain *tcC = ToolChainKitAspect::cToolChain(k);
+ ToolChain *tcCxx = ToolChainKitAspect::cxxToolChain(k);
if (!tcC && !tcCxx)
return data;
- ProjectExplorer::ToolChain *mainTc = tcCxx ? tcCxx : tcC;
+ ToolChain *mainTc = tcCxx ? tcCxx : tcC;
- ProjectExplorer::Abi targetAbi = mainTc->targetAbi();
+ Abi targetAbi = mainTc->targetAbi();
auto archs = architectures(mainTc);
if (!archs.isEmpty())
data.insert(QLatin1String(QBS_ARCHITECTURES), archs);
- if (mainTc->targetAbi() !=
- ProjectExplorer::Abi::abiFromTargetTriplet(mainTc->originalTargetTriple())
- || targetAbi.osFlavor() == ProjectExplorer::Abi::AndroidLinuxFlavor) {
+ if (mainTc->targetAbi() != Abi::abiFromTargetTriplet(mainTc->originalTargetTriple())
+ || targetAbi.osFlavor() == Abi::AndroidLinuxFlavor) {
data.insert(QLatin1String(QBS_ARCHITECTURE), architecture(mainTc->targetAbi()));
} else if (archs.count() == 1) {
data.insert(QLatin1String(QBS_ARCHITECTURE), archs.first());
@@ -281,8 +280,8 @@ QVariantMap DefaultPropertyProvider::autoGeneratedProperties(const ProjectExplor
data.insert(QLatin1String(QBS_TARGETPLATFORM), targetPlatform(targetAbi, k));
QStringList toolchain = toolchainList(mainTc);
- if (targetAbi.osFlavor() == ProjectExplorer::Abi::AndroidLinuxFlavor) {
- const ProjectExplorer::IDevice::ConstPtr dev = ProjectExplorer::DeviceKitAspect::device(k);
+ if (targetAbi.osFlavor() == Abi::AndroidLinuxFlavor) {
+ const IDevice::ConstPtr dev = DeviceKitAspect::device(k);
if (dev) {
const QString sdkDir = k->value(Android::Constants::ANDROID_KIT_SDK).toString();
if (!sdkDir.isEmpty())
diff --git a/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp b/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp
index b2d0811d8d..33e41c31c7 100644
--- a/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp
+++ b/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp
@@ -319,11 +319,6 @@ QString QbsBuildConfiguration::equivalentCommandLine(const QbsBuildStepData &ste
return commandLine.arguments();
}
-bool QbsBuildConfiguration::isQmlDebuggingEnabled() const
-{
- return qmlDebuggingSetting() == TriState::Enabled;
-}
-
TriState QbsBuildConfiguration::qmlDebuggingSetting() const
{
return aspect<QtSupport::QmlDebuggingAspect>()->setting();
diff --git a/src/plugins/qbsprojectmanager/qbsbuildconfiguration.h b/src/plugins/qbsprojectmanager/qbsbuildconfiguration.h
index 96b66e2f47..4f9454ea1c 100644
--- a/src/plugins/qbsprojectmanager/qbsbuildconfiguration.h
+++ b/src/plugins/qbsprojectmanager/qbsbuildconfiguration.h
@@ -61,11 +61,6 @@ class QbsBuildConfiguration final : public ProjectExplorer::BuildConfiguration
{
Q_OBJECT
- // used in DebuggerRunConfigurationAspect
- Q_PROPERTY(bool linkQmlDebuggingLibrary
- READ isQmlDebuggingEnabled
- NOTIFY qbsConfigurationChanged)
-
friend class ProjectExplorer::BuildConfigurationFactory;
QbsBuildConfiguration(ProjectExplorer::Target *target, Core::Id id);
~QbsBuildConfiguration() final;
@@ -90,7 +85,6 @@ public:
QString configurationName() const;
QString equivalentCommandLine(const QbsBuildStepData &stepData) const;
- bool isQmlDebuggingEnabled() const;
ProjectExplorer::TriState qmlDebuggingSetting() const;
ProjectExplorer::TriState qtQuickCompilerSetting() const;
ProjectExplorer::TriState separateDebugInfoSetting() const;
diff --git a/src/plugins/qbsprojectmanager/qbsbuildstep.cpp b/src/plugins/qbsprojectmanager/qbsbuildstep.cpp
index 239276de77..062f48e15b 100644
--- a/src/plugins/qbsprojectmanager/qbsbuildstep.cpp
+++ b/src/plugins/qbsprojectmanager/qbsbuildstep.cpp
@@ -26,7 +26,6 @@
#include "qbsbuildstep.h"
#include "qbsbuildconfiguration.h"
-#include "qbsparser.h"
#include "qbsproject.h"
#include "qbsprojectmanagerconstants.h"
#include "qbssession.h"
@@ -40,6 +39,7 @@
#include <projectexplorer/target.h>
#include <qtsupport/qtversionmanager.h>
#include <utils/macroexpander.h>
+#include <utils/outputformatter.h>
#include <utils/pathchooser.h>
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
@@ -60,7 +60,6 @@
// --------------------------------------------------------------------
const char QBS_CONFIG[] = "Qbs.Configuration";
-const char QBS_DRY_RUN[] = "Qbs.DryRun";
const char QBS_KEEP_GOING[] = "Qbs.DryKeepGoing";
const char QBS_MAXJOBCOUNT[] = "Qbs.MaxJobs";
const char QBS_SHOWCOMMANDLINES[] = "Qbs.ShowCommandLines";
@@ -156,7 +155,6 @@ QbsBuildStep::~QbsBuildStep()
doCancel();
if (m_session)
m_session->disconnect(this);
- delete m_parser;
}
bool QbsBuildStep::init()
@@ -169,25 +167,19 @@ bool QbsBuildStep::init()
if (!bc)
return false;
- delete m_parser;
- m_parser = new Internal::QbsParser;
- ProjectExplorer::IOutputParser *parser = target()->kit()->createOutputParser();
- if (parser)
- m_parser->appendOutputParser(parser);
-
m_changedFiles = bc->changedFiles();
m_activeFileTags = bc->activeFileTags();
m_products = bc->products();
- connect(m_parser, &ProjectExplorer::IOutputParser::addOutput,
- this, [this](const QString &string, ProjectExplorer::BuildStep::OutputFormat format) {
- emit addOutput(string, format);
- });
- connect(m_parser, &ProjectExplorer::IOutputParser::addTask, this, &QbsBuildStep::addTask);
-
return true;
}
+void QbsBuildStep::setupOutputFormatter(OutputFormatter *formatter)
+{
+ formatter->addLineParsers(target()->kit()->createOutputParsers());
+ BuildStep::setupOutputFormatter(formatter);
+}
+
void QbsBuildStep::doRun()
{
// We need a pre-build parsing step in order not to lose project file changes done
@@ -234,7 +226,7 @@ QVariantMap QbsBuildStep::qbsConfiguration(VariableHandling variableHandling) co
Constants::QBS_CONFIG_QUICK_COMPILER_KEY);
if (variableHandling == ExpandVariables) {
- const MacroExpander * const expander = buildConfiguration()->macroExpander();
+ const MacroExpander * const expander = macroExpander();
for (auto it = config.begin(), end = config.end(); it != end; ++it) {
const QString rawString = it.value().toString();
const QString expandedString = expander->expand(rawString);
@@ -273,7 +265,7 @@ Utils::FilePath QbsBuildStep::installRoot(VariableHandling variableHandling) con
return Utils::FilePath::fromString(root);
QString defaultInstallDir = QbsSettings::defaultInstallDirTemplate();
if (variableHandling == VariableHandling::ExpandVariables)
- defaultInstallDir = buildConfiguration()->macroExpander()->expand(defaultInstallDir);
+ defaultInstallDir = macroExpander()->expand(defaultInstallDir);
return FilePath::fromString(defaultInstallDir);
}
@@ -379,29 +371,24 @@ void QbsBuildStep::handleProcessResult(
const QStringList &stdErr,
bool success)
{
+ Q_UNUSED(workingDir);
const bool hasOutput = !stdOut.isEmpty() || !stdErr.isEmpty();
if (success && !hasOutput)
return;
- m_parser->setWorkingDirectory(workingDir.toString());
emit addOutput(executable.toUserOutput() + ' ' + QtcProcess::joinArgs(arguments),
OutputFormat::Stdout);
- for (const QString &line : stdErr) {
- m_parser->stdError(line);
+ for (const QString &line : stdErr)
emit addOutput(line, OutputFormat::Stderr);
- }
- for (const QString &line : stdOut) {
- m_parser->stdOutput(line);
+ for (const QString &line : stdOut)
emit addOutput(line, OutputFormat::Stdout);
- }
- m_parser->flush();
}
void QbsBuildStep::createTaskAndOutput(ProjectExplorer::Task::TaskType type, const QString &message,
const QString &file, int line)
{
- emit addTask(CompileTask(type, message, FilePath::fromString(file), line), 1);
emit addOutput(message, OutputFormat::Stdout);
+ emit addTask(CompileTask(type, message, FilePath::fromString(file), line), 1);
}
QString QbsBuildStep::buildVariant() const
@@ -411,7 +398,7 @@ QString QbsBuildStep::buildVariant() const
QbsBuildSystem *QbsBuildStep::qbsBuildSystem() const
{
- return static_cast<QbsBuildSystem *>(buildConfiguration()->buildSystem());
+ return static_cast<QbsBuildSystem *>(buildSystem());
}
void QbsBuildStep::setBuildVariant(const QString &variant)
@@ -653,9 +640,7 @@ QbsBuildStepConfigWidget::QbsBuildStepConfigWidget(QbsBuildStep *step) :
auto chooser = new Core::VariableChooser(this);
chooser->addSupportedWidget(propertyEdit);
chooser->addSupportedWidget(installDirChooser->lineEdit());
- chooser->addMacroExpanderProvider([step] {
- return step->buildConfiguration()->macroExpander();
- });
+ chooser->addMacroExpanderProvider([step] { return step->macroExpander(); });
propertyEdit->setValidationFunction([this](FancyLineEdit *edit, QString *errorMessage) {
return validateProperties(edit, errorMessage);
});
@@ -693,7 +678,7 @@ void QbsBuildStepConfigWidget::updateState()
cleanInstallRootCheckBox->setChecked(qbsStep()->cleanInstallRoot());
forceProbesCheckBox->setChecked(qbsStep()->forceProbes());
updatePropertyEdit(qbsStep()->qbsConfiguration(QbsBuildStep::PreserveVariables));
- installDirChooser->setFileName(qbsStep()->installRoot(QbsBuildStep::PreserveVariables));
+ installDirChooser->setFilePath(qbsStep()->installRoot(QbsBuildStep::PreserveVariables));
defaultInstallDirCheckBox->setChecked(!qbsStep()->hasCustomInstallRoot());
}
@@ -876,7 +861,7 @@ bool QbsBuildStepConfigWidget::validateProperties(Utils::FancyLineEdit *edit, QS
}
QList<Property> properties;
- const MacroExpander * const expander = step()->buildConfiguration()->macroExpander();
+ const MacroExpander * const expander = step()->macroExpander();
foreach (const QString &rawArg, argList) {
int pos = rawArg.indexOf(':');
if (pos > 0) {
diff --git a/src/plugins/qbsprojectmanager/qbsbuildstep.h b/src/plugins/qbsprojectmanager/qbsbuildstep.h
index d6766768c4..d257662bdb 100644
--- a/src/plugins/qbsprojectmanager/qbsbuildstep.h
+++ b/src/plugins/qbsprojectmanager/qbsbuildstep.h
@@ -80,6 +80,7 @@ signals:
private:
bool init() override;
+ void setupOutputFormatter(Utils::OutputFormatter *formatter) override;
void doRun() override;
void doCancel() override;
ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override;
@@ -133,7 +134,6 @@ private:
QString m_currentTask;
int m_maxProgress;
bool m_lastWasSuccess;
- ProjectExplorer::IOutputParser *m_parser = nullptr;
bool m_parsingProject = false;
bool m_parsingAfterBuild = false;
diff --git a/src/plugins/qbsprojectmanager/qbscleanstep.cpp b/src/plugins/qbsprojectmanager/qbscleanstep.cpp
index 07adf568d2..44d3372896 100644
--- a/src/plugins/qbsprojectmanager/qbscleanstep.cpp
+++ b/src/plugins/qbsprojectmanager/qbscleanstep.cpp
@@ -160,8 +160,8 @@ void QbsCleanStep::handleProgress(int value)
void QbsCleanStep::createTaskAndOutput(ProjectExplorer::Task::TaskType type, const QString &message, const QString &file, int line)
{
- emit addTask(CompileTask(type, message, Utils::FilePath::fromString(file), line), 1);
emit addOutput(message, OutputFormat::Stdout);
+ emit addTask(CompileTask(type, message, Utils::FilePath::fromString(file), line), 1);
}
// --------------------------------------------------------------------
diff --git a/src/plugins/qbsprojectmanager/qbscleanstep.h b/src/plugins/qbsprojectmanager/qbscleanstep.h
index f757afe9e0..81a51351da 100644
--- a/src/plugins/qbsprojectmanager/qbscleanstep.h
+++ b/src/plugins/qbsprojectmanager/qbscleanstep.h
@@ -68,7 +68,6 @@ private:
QString m_description;
int m_maxProgress;
bool m_showCompilerOutput = true;
- ProjectExplorer::IOutputParser *m_parser = nullptr;
};
class QbsCleanStepFactory : public ProjectExplorer::BuildStepFactory
diff --git a/src/plugins/qbsprojectmanager/qbsinstallstep.cpp b/src/plugins/qbsprojectmanager/qbsinstallstep.cpp
index 371cf4c8d6..9ad460e48e 100644
--- a/src/plugins/qbsprojectmanager/qbsinstallstep.cpp
+++ b/src/plugins/qbsprojectmanager/qbsinstallstep.cpp
@@ -109,7 +109,7 @@ QbsInstallStep::~QbsInstallStep()
bool QbsInstallStep::init()
{
- QTC_ASSERT(!buildConfiguration()->buildSystem()->isParsing() && !m_session, return false);
+ QTC_ASSERT(!buildSystem()->isParsing() && !m_session, return false);
return true;
}
@@ -202,9 +202,8 @@ void QbsInstallStep::handleProgress(int value)
void QbsInstallStep::createTaskAndOutput(Task::TaskType type, const QString &message,
const Utils::FilePath &file, int line)
{
- const CompileTask task(type, message, file, line);
- emit addTask(task, 1);
emit addOutput(message, OutputFormat::Stdout);
+ emit addTask(CompileTask(type, message, file, line), 1);
}
void QbsInstallStep::setRemoveFirst(bool rf)
diff --git a/src/plugins/qbsprojectmanager/qbsinstallstep.h b/src/plugins/qbsprojectmanager/qbsinstallstep.h
index 9df1afaa7e..1a0a418fc3 100644
--- a/src/plugins/qbsprojectmanager/qbsinstallstep.h
+++ b/src/plugins/qbsprojectmanager/qbsinstallstep.h
@@ -80,7 +80,6 @@ private:
QbsSession *m_session = nullptr;
QString m_description;
int m_maxProgress;
- ProjectExplorer::IOutputParser *m_parser = nullptr;
friend class QbsInstallStepConfigWidget;
};
diff --git a/src/plugins/qbsprojectmanager/qbsnodes.cpp b/src/plugins/qbsprojectmanager/qbsnodes.cpp
index 01bfa6e976..2ed8d1adf3 100644
--- a/src/plugins/qbsprojectmanager/qbsnodes.cpp
+++ b/src/plugins/qbsprojectmanager/qbsnodes.cpp
@@ -73,7 +73,7 @@ const QbsProductNode *parentQbsProductNode(const ProjectExplorer::Node *node)
QbsGroupNode::QbsGroupNode(const QJsonObject &grp) : ProjectNode(FilePath()), m_groupData(grp)
{
- static QIcon groupIcon = QIcon(QString(Constants::QBS_GROUP_ICON));
+ static QIcon groupIcon = QIcon(QString(ProjectExplorer::Constants::FILEOVERLAY_GROUP));
setIcon(groupIcon);
setDisplayName(grp.value("name").toString());
setEnabled(grp.value("is-enabled").toBool());
@@ -109,7 +109,7 @@ QVariant QbsGroupNode::data(Core::Id role) const
QbsProductNode::QbsProductNode(const QJsonObject &prd) : ProjectNode(FilePath()), m_productData(prd)
{
static QIcon productIcon = Core::FileIconProvider::directoryIcon(
- Constants::QBS_PRODUCT_OVERLAY_ICON);
+ ProjectExplorer::Constants::FILEOVERLAY_PRODUCT);
setIcon(productIcon);
if (prd.value("is-runnable").toBool()) {
setProductType(ProductType::App);
diff --git a/src/plugins/qbsprojectmanager/qbsproject.cpp b/src/plugins/qbsprojectmanager/qbsproject.cpp
index 96efcd1d6b..26d3e7eef0 100644
--- a/src/plugins/qbsprojectmanager/qbsproject.cpp
+++ b/src/plugins/qbsprojectmanager/qbsproject.cpp
@@ -49,8 +49,6 @@
#include <cpptools/cppprojectupdater.h>
#include <cpptools/cpptoolsconstants.h>
#include <cpptools/generatedcodemodelsupport.h>
-#include <extensionsystem/pluginmanager.h>
-#include <projectexplorer/buildenvironmentwidget.h>
#include <projectexplorer/buildinfo.h>
#include <projectexplorer/buildmanager.h>
#include <projectexplorer/buildtargetinfo.h>
@@ -79,6 +77,7 @@
#include <QJsonArray>
#include <QMessageBox>
#include <QSet>
+#include <QTimer>
#include <QVariantMap>
#include <algorithm>
@@ -203,7 +202,6 @@ QbsBuildSystem::QbsBuildSystem(QbsBuildConfiguration *bc)
});
connect(m_session, &QbsSession::fileListUpdated, this, &QbsBuildSystem::delayParsing);
- m_parsingDelay.setInterval(1000); // delay parsing by 1s.
delayParsing();
connect(bc->project(), &Project::activeTargetChanged,
@@ -212,8 +210,6 @@ QbsBuildSystem::QbsBuildSystem(QbsBuildConfiguration *bc)
connect(bc->target(), &Target::activeBuildConfigurationChanged,
this, &QbsBuildSystem::delayParsing);
- connect(&m_parsingDelay, &QTimer::timeout, this, &QbsBuildSystem::triggerParsing);
-
connect(bc->project(), &Project::projectFileIsDirty, this, &QbsBuildSystem::delayParsing);
updateProjectNodes({});
}
@@ -597,7 +593,7 @@ void QbsBuildSystem::triggerParsing()
void QbsBuildSystem::delayParsing()
{
if (m_buildConfiguration->isActive())
- m_parsingDelay.start();
+ requestDelayedParse();
}
void QbsBuildSystem::parseCurrentBuildConfiguration()
@@ -635,7 +631,7 @@ void QbsBuildSystem::parseCurrentBuildConfiguration()
prepareForParsing();
- m_parsingDelay.stop();
+ cancelDelayedParseRequest();
QTC_ASSERT(!m_qbsProjectParser, return);
m_qbsProjectParser = new QbsProjectParser(this, m_qbsUpdateFutureInterface);
diff --git a/src/plugins/qbsprojectmanager/qbsproject.h b/src/plugins/qbsprojectmanager/qbsproject.h
index 250d544e3b..7d4a027adf 100644
--- a/src/plugins/qbsprojectmanager/qbsproject.h
+++ b/src/plugins/qbsprojectmanager/qbsproject.h
@@ -39,7 +39,6 @@
#include <QFutureWatcher>
#include <QHash>
#include <QJsonObject>
-#include <QTimer>
#include <functional>
@@ -149,7 +148,6 @@ private:
QSet<Core::IDocument *> m_qbsDocuments;
QJsonObject m_projectData; // TODO: Perhaps store this in the root project node instead?
- QTimer m_parsingDelay;
QbsProjectParser *m_qbsProjectParser = nullptr;
QFutureInterface<bool> *m_qbsUpdateFutureInterface = nullptr;
using TreeCreationWatcher = QFutureWatcher<QbsProjectNode *>;
diff --git a/src/plugins/qbsprojectmanager/qbsprojectimporter.cpp b/src/plugins/qbsprojectmanager/qbsprojectimporter.cpp
index 8ff3371eef..06f9812169 100644
--- a/src/plugins/qbsprojectmanager/qbsprojectimporter.cpp
+++ b/src/plugins/qbsprojectmanager/qbsprojectimporter.cpp
@@ -165,10 +165,8 @@ bool QbsProjectImporter::matchKit(void *directoryData, const Kit *k) const
&& bgData->cxxCompilerPath.isEmpty()) {
return true;
}
- const ToolChain * const cToolchain
- = ToolChainKitAspect::toolChain(k, Constants::C_LANGUAGE_ID);
- const ToolChain * const cxxToolchain
- = ToolChainKitAspect::toolChain(k, Constants::CXX_LANGUAGE_ID);
+ const ToolChain * const cToolchain = ToolChainKitAspect::cToolChain(k);
+ const ToolChain * const cxxToolchain = ToolChainKitAspect::cxxToolChain(k);
if (!bgData->cCompilerPath.isEmpty()) {
if (!cToolchain)
return false;
diff --git a/src/plugins/qbsprojectmanager/qbsprojectmanager.pro b/src/plugins/qbsprojectmanager/qbsprojectmanager.pro
index a03f4d4bb0..1d541089c9 100644
--- a/src/plugins/qbsprojectmanager/qbsprojectmanager.pro
+++ b/src/plugins/qbsprojectmanager/qbsprojectmanager.pro
@@ -16,7 +16,6 @@ HEADERS = \
qbsinstallstep.h \
qbsnodes.h \
qbsnodetreebuilder.h \
- qbsparser.h \
qbspmlogging.h \
qbsprofilemanager.h \
qbsprofilessettingspage.h \
@@ -39,7 +38,6 @@ SOURCES = \
qbskitinformation.cpp \
qbsnodes.cpp \
qbsnodetreebuilder.cpp \
- qbsparser.cpp \
qbspmlogging.cpp \
qbsprofilemanager.cpp \
qbsprofilessettingspage.cpp \
diff --git a/src/plugins/qbsprojectmanager/qbsprojectmanager.qbs b/src/plugins/qbsprojectmanager/qbsprojectmanager.qbs
index 9830c06efc..197fcdc299 100644
--- a/src/plugins/qbsprojectmanager/qbsprojectmanager.qbs
+++ b/src/plugins/qbsprojectmanager/qbsprojectmanager.qbs
@@ -40,8 +40,6 @@ QtcPlugin {
"qbsnodes.h",
"qbsnodetreebuilder.cpp",
"qbsnodetreebuilder.h",
- "qbsparser.cpp",
- "qbsparser.h",
"qbspmlogging.cpp",
"qbspmlogging.h",
"qbsprofilemanager.cpp",
diff --git a/src/plugins/qbsprojectmanager/qbsprojectmanager.qrc b/src/plugins/qbsprojectmanager/qbsprojectmanager.qrc
index d2848ec977..d943220240 100644
--- a/src/plugins/qbsprojectmanager/qbsprojectmanager.qrc
+++ b/src/plugins/qbsprojectmanager/qbsprojectmanager.qrc
@@ -1,9 +1,5 @@
<RCC>
<qresource prefix="/qbsprojectmanager">
- <file>images/groups.png</file>
- <file>images/groups@2x.png</file>
- <file>images/productgear.png</file>
- <file>images/productgear@2x.png</file>
<file>images/settingscategory_qbsprojectmanager.png</file>
<file>images/settingscategory_qbsprojectmanager@2x.png</file>
</qresource>
diff --git a/src/plugins/qbsprojectmanager/qbsprojectmanagerconstants.h b/src/plugins/qbsprojectmanager/qbsprojectmanagerconstants.h
index 12e3147cb1..30a415fa57 100644
--- a/src/plugins/qbsprojectmanager/qbsprojectmanagerconstants.h
+++ b/src/plugins/qbsprojectmanager/qbsprojectmanagerconstants.h
@@ -73,10 +73,6 @@ const char QBS_CONFIG_QUICK_COMPILER_KEY[] = "modules.Qt.quick.useCompiler";
const char QBS_CONFIG_SEPARATE_DEBUG_INFO_KEY[] = "modules.cpp.separateDebugInformation";
const char QBS_FORCE_PROBES_KEY[] = "qbspm.forceProbes";
-// Icons:
-const char QBS_GROUP_ICON[] = ":/qbsprojectmanager/images/groups.png";
-const char QBS_PRODUCT_OVERLAY_ICON[] = ":/qbsprojectmanager/images/productgear.png";
-
// Toolchain related settings:
const char QBS_TARGETPLATFORM[] = "qbs.targetPlatform";
const char QBS_SYSROOT[] = "qbs.sysroot";
diff --git a/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp b/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp
index e9f8e64ea3..d0da8a47e0 100644
--- a/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp
+++ b/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp
@@ -542,17 +542,13 @@ void QbsProjectManagerPlugin::runStepsForProducts(QbsProject *project,
bc->setChangedFiles(QStringList());
bc->setProducts(products);
QList<ProjectExplorer::BuildStepList *> stepLists;
- QStringList stepListNames;
for (const Core::Id &stepType : stepTypes) {
- if (stepType == ProjectExplorer::Constants::BUILDSTEPS_BUILD) {
+ if (stepType == ProjectExplorer::Constants::BUILDSTEPS_BUILD)
stepLists << bc->buildSteps();
- stepListNames << ProjectExplorerPlugin::displayNameForStepId(stepType);
- } else if (stepType == ProjectExplorer::Constants::BUILDSTEPS_CLEAN) {
+ else if (stepType == ProjectExplorer::Constants::BUILDSTEPS_CLEAN)
stepLists << bc->cleanSteps();
- stepListNames << ProjectExplorerPlugin::displayNameForStepId(stepType);
- }
}
- BuildManager::buildLists(stepLists, stepListNames);
+ BuildManager::buildLists(stepLists);
bc->setProducts(QStringList());
}
diff --git a/src/plugins/qbsprojectmanager/qbssettings.cpp b/src/plugins/qbsprojectmanager/qbssettings.cpp
index 3a7b97a98e..e3200a0ae0 100644
--- a/src/plugins/qbsprojectmanager/qbssettings.cpp
+++ b/src/plugins/qbsprojectmanager/qbssettings.cpp
@@ -138,7 +138,7 @@ public:
SettingsWidget()
{
m_qbsExePathChooser.setExpectedKind(PathChooser::ExistingCommand);
- m_qbsExePathChooser.setFileName(QbsSettings::qbsExecutableFilePath());
+ m_qbsExePathChooser.setFilePath(QbsSettings::qbsExecutableFilePath());
m_defaultInstallDirLineEdit.setText(QbsSettings::defaultInstallDirTemplate());
m_versionLabel.setText(getQbsVersion());
m_settingsDirCheckBox.setText(tr("Use %1 settings directory for Qbs")
@@ -155,8 +155,8 @@ public:
void apply()
{
QbsSettingsData settings = QbsSettings::rawSettingsData();
- if (m_qbsExePathChooser.fileName() != QbsSettings::qbsExecutableFilePath())
- settings.qbsExecutableFilePath = m_qbsExePathChooser.fileName();
+ if (m_qbsExePathChooser.filePath() != QbsSettings::qbsExecutableFilePath())
+ settings.qbsExecutableFilePath = m_qbsExePathChooser.filePath();
settings.defaultInstallDirTemplate = m_defaultInstallDirLineEdit.text();
settings.useCreatorSettings = m_settingsDirCheckBox.isChecked();
QbsSettings::setSettingsData(settings);
diff --git a/src/plugins/qmakeprojectmanager/CMakeLists.txt b/src/plugins/qmakeprojectmanager/CMakeLists.txt
index 90d48c0347..f61d50d0c3 100644
--- a/src/plugins/qmakeprojectmanager/CMakeLists.txt
+++ b/src/plugins/qmakeprojectmanager/CMakeLists.txt
@@ -32,7 +32,6 @@ add_qtc_plugin(QmakeProjectManager
qmakeparsernodes.cpp qmakeparsernodes.h
qmakeproject.cpp qmakeproject.h
qmakeprojectimporter.cpp qmakeprojectimporter.h
- qmakeprojectmanager.cpp qmakeprojectmanager.h
qmakeprojectmanager.qrc
qmakeprojectmanager_global.h
qmakeprojectmanagerconstants.h
diff --git a/src/plugins/qmakeprojectmanager/addlibrarywizard.cpp b/src/plugins/qmakeprojectmanager/addlibrarywizard.cpp
index 34553567b9..0b758e01bc 100644
--- a/src/plugins/qmakeprojectmanager/addlibrarywizard.cpp
+++ b/src/plugins/qmakeprojectmanager/addlibrarywizard.cpp
@@ -195,7 +195,7 @@ DetailsPage::DetailsPage(AddLibraryWizard *parent)
const auto pathValidator = [libPathChooser](Utils::FancyLineEdit *edit, QString *errorMessage) {
return libPathChooser->defaultValidationFunction()(edit, errorMessage)
- && validateLibraryPath(libPathChooser->fileName(),
+ && validateLibraryPath(libPathChooser->filePath(),
libPathChooser, errorMessage);
};
libPathChooser->setValidationFunction(pathValidator);
diff --git a/src/plugins/qmakeprojectmanager/customwidgetwizard/classdefinition.cpp b/src/plugins/qmakeprojectmanager/customwidgetwizard/classdefinition.cpp
index 0d0ab31179..0407387dc2 100644
--- a/src/plugins/qmakeprojectmanager/customwidgetwizard/classdefinition.cpp
+++ b/src/plugins/qmakeprojectmanager/customwidgetwizard/classdefinition.cpp
@@ -140,7 +140,7 @@ PluginOptions::WidgetOptions ClassDefinition::widgetOptions(const QString &class
wo.pluginClassName = m_ui.pluginClassEdit->text();
wo.pluginHeaderFile = m_ui.pluginHeaderEdit->text();
wo.pluginSourceFile = m_ui.pluginSourceEdit->text();
- wo.iconFile = m_ui.iconPathChooser->path();
+ wo.iconFile = m_ui.iconPathChooser->filePath().toString();
wo.group = m_ui.groupEdit->text();
wo.toolTip = m_ui.tooltipEdit->text();
wo.whatsThis = m_ui.whatsthisEdit->toPlainText();
diff --git a/src/plugins/qmakeprojectmanager/customwidgetwizard/classlist.cpp b/src/plugins/qmakeprojectmanager/customwidgetwizard/classlist.cpp
index 6c6a3ad7c6..1dcca7754c 100644
--- a/src/plugins/qmakeprojectmanager/customwidgetwizard/classlist.cpp
+++ b/src/plugins/qmakeprojectmanager/customwidgetwizard/classlist.cpp
@@ -147,6 +147,7 @@ void ClassList::removeCurrentClass()
void ClassList::keyPressEvent(QKeyEvent *event)
{
switch (event->key()) {
+ case Qt::Key_Backspace:
case Qt::Key_Delete:
removeCurrentClass();
break;
diff --git a/src/plugins/qmakeprojectmanager/librarydetailscontroller.cpp b/src/plugins/qmakeprojectmanager/librarydetailscontroller.cpp
index 4569ad9dfa..8a79dcf314 100644
--- a/src/plugins/qmakeprojectmanager/librarydetailscontroller.cpp
+++ b/src/plugins/qmakeprojectmanager/librarydetailscontroller.cpp
@@ -622,7 +622,7 @@ AddLibraryWizard::LinkageType NonInternalLibraryDetailsController::suggestedLink
AddLibraryWizard::LinkageType type = AddLibraryWizard::NoLinkage;
if (libraryPlatformType() != Utils::OsTypeWindows) {
if (libraryDetailsWidget()->libraryPathChooser->isValid()) {
- QFileInfo fi(libraryDetailsWidget()->libraryPathChooser->path());
+ QFileInfo fi(libraryDetailsWidget()->libraryPathChooser->filePath().toString());
if (fi.suffix() == QLatin1String("a"))
type = AddLibraryWizard::StaticLinkage;
else
@@ -637,7 +637,7 @@ AddLibraryWizard::MacLibraryType NonInternalLibraryDetailsController::suggestedM
AddLibraryWizard::MacLibraryType type = AddLibraryWizard::NoLibraryType;
if (libraryPlatformType() == Utils::OsTypeMac) {
if (libraryDetailsWidget()->libraryPathChooser->isValid()) {
- QFileInfo fi(libraryDetailsWidget()->libraryPathChooser->path());
+ QFileInfo fi(libraryDetailsWidget()->libraryPathChooser->filePath().toString());
if (fi.suffix() == QLatin1String("framework"))
type = AddLibraryWizard::FrameworkType;
else
@@ -651,7 +651,7 @@ QString NonInternalLibraryDetailsController::suggestedIncludePath() const
{
QString includePath;
if (libraryDetailsWidget()->libraryPathChooser->isValid()) {
- QFileInfo fi(libraryDetailsWidget()->libraryPathChooser->path());
+ QFileInfo fi(libraryDetailsWidget()->libraryPathChooser->filePath().toString());
includePath = fi.absolutePath();
QFileInfo dfi(includePath);
// TODO: Win: remove debug or release folder first if appropriate
@@ -722,7 +722,7 @@ void NonInternalLibraryDetailsController::slotLibraryPathChanged()
bool subfoldersEnabled = true;
bool removeSuffixEnabled = true;
if (libraryDetailsWidget()->libraryPathChooser->isValid()) {
- QFileInfo fi(libraryDetailsWidget()->libraryPathChooser->path());
+ QFileInfo fi(libraryDetailsWidget()->libraryPathChooser->filePath().toString());
QFileInfo dfi(fi.absolutePath());
const QString parentFolderName = dfi.fileName().toLower();
if (parentFolderName != QLatin1String("debug") &&
@@ -755,7 +755,7 @@ bool NonInternalLibraryDetailsController::isComplete() const
QString NonInternalLibraryDetailsController::snippet() const
{
- QString libPath = libraryDetailsWidget()->libraryPathChooser->path();
+ QString libPath = libraryDetailsWidget()->libraryPathChooser->filePath().toString();
QFileInfo fi(libPath);
QString libName;
const bool removeSuffix = isWindowsGroupVisible()
@@ -801,7 +801,7 @@ QString NonInternalLibraryDetailsController::snippet() const
}
targetRelativePath = appendSeparator(pdir.relativeFilePath(absoluteLibraryPath));
- const QString includePath = libraryDetailsWidget()->includePathChooser->path();
+ const QString includePath = libraryDetailsWidget()->includePathChooser->filePath().toString();
if (!includePath.isEmpty())
includeRelativePath = pdir.relativeFilePath(includePath);
}
@@ -914,7 +914,7 @@ void ExternalLibraryDetailsController::updateWindowsOptionsEnablement()
bool removeSuffixEnabled = true;
if (libraryPlatformType() == Utils::OsTypeWindows
&& libraryDetailsWidget()->libraryPathChooser->isValid()) {
- QFileInfo fi(libraryDetailsWidget()->libraryPathChooser->path());
+ QFileInfo fi(libraryDetailsWidget()->libraryPathChooser->filePath().toString());
QFileInfo dfi(fi.absolutePath());
const QString parentFolderName = dfi.fileName().toLower();
if (parentFolderName != QLatin1String("debug") &&
@@ -1117,7 +1117,7 @@ QString InternalLibraryDetailsController::snippet() const
TargetInformation targetInfo = m_proFiles.at(currentIndex)->targetInformation();
const QString targetRelativePath = appendSeparator(projectBuildDir.relativeFilePath(targetInfo.buildDir.toString()));
- const QString includeRelativePath = projectSrcDir.relativeFilePath(libraryDetailsWidget()->includePathChooser->path());
+ const QString includeRelativePath = projectSrcDir.relativeFilePath(libraryDetailsWidget()->includePathChooser->filePath().toString());
const bool useSubfolders = libraryDetailsWidget()->useSubfoldersCheckBox->isChecked();
const bool addSuffix = libraryDetailsWidget()->addSuffixCheckBox->isChecked();
diff --git a/src/plugins/qmakeprojectmanager/profileeditor.cpp b/src/plugins/qmakeprojectmanager/profileeditor.cpp
index a00e26d39e..6443af2635 100644
--- a/src/plugins/qmakeprojectmanager/profileeditor.cpp
+++ b/src/plugins/qmakeprojectmanager/profileeditor.cpp
@@ -30,8 +30,6 @@
#include "profilehoverhandler.h"
#include "qmakenodes.h"
#include "qmakeproject.h"
-#include "qmakeprojectmanager.h"
-#include "qmakeprojectmanagerconstants.h"
#include "qmakeprojectmanagerconstants.h"
#include <coreplugin/fileiconprovider.h>
diff --git a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp
index b44ae9fba3..6cf2179015 100644
--- a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp
+++ b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp
@@ -313,7 +313,7 @@ void QmakeBuildConfiguration::updateProblemLabel()
}
if (!text.endsWith(QLatin1String("br>")))
text.append(QLatin1String("<br>"));
- text.append(type + task.description);
+ text.append(type + task.description());
}
buildDirectoryAspect()->setProblem(text);
return;
@@ -424,11 +424,6 @@ TriState QmakeBuildConfiguration::qmlDebugging() const
return aspect<QmlDebuggingAspect>()->setting();
}
-bool QmakeBuildConfiguration::linkQmlDebuggingLibrary() const
-{
- return qmlDebugging() == TriState::Enabled;
-}
-
void QmakeBuildConfiguration::forceQmlDebugging(bool enable)
{
aspect<QmlDebuggingAspect>()->setSetting(enable ? TriState::Enabled : TriState::Disabled);
@@ -829,7 +824,7 @@ QmakeBuildConfiguration::LastKitState::LastKitState(Kit *k)
m_sysroot(SysRootKitAspect::sysRoot(k).toString()),
m_mkspec(QmakeKitAspect::mkspec(k))
{
- ToolChain *tc = ToolChainKitAspect::toolChain(k, ProjectExplorer::Constants::CXX_LANGUAGE_ID);
+ ToolChain *tc = ToolChainKitAspect::cxxToolChain(k);
m_toolchain = tc ? tc->id() : QByteArray();
}
@@ -855,7 +850,7 @@ bool QmakeBuildConfiguration::regenerateBuildFiles(Node *node)
qs->setForced(true);
BuildManager::buildList(cleanSteps());
- BuildManager::appendStep(qs, ProjectExplorerPlugin::displayNameForStepId(ProjectExplorer::Constants::BUILDSTEPS_CLEAN));
+ BuildManager::appendStep(qs, BuildManager::displayNameForStepId(ProjectExplorer::Constants::BUILDSTEPS_CLEAN));
QmakeProFileNode *proFile = nullptr;
if (node && node != target()->project()->rootProjectNode())
diff --git a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.h b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.h
index 53d92c3c59..058af3e796 100644
--- a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.h
+++ b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.h
@@ -44,9 +44,6 @@ class QMAKEPROJECTMANAGER_EXPORT QmakeBuildConfiguration : public ProjectExplore
{
Q_OBJECT
- // used in DebuggerRunConfigurationAspect
- Q_PROPERTY(bool linkQmlDebuggingLibrary READ linkQmlDebuggingLibrary NOTIFY qmlDebuggingChanged)
-
public:
QmakeBuildConfiguration(ProjectExplorer::Target *target, Core::Id id);
~QmakeBuildConfiguration() override;
@@ -103,7 +100,6 @@ public:
void forceSeparateDebugInfo(bool sepDebugInfo);
ProjectExplorer::TriState qmlDebugging() const;
- bool linkQmlDebuggingLibrary() const;
void forceQmlDebugging(bool enable);
ProjectExplorer::TriState useQtQuickCompiler() const;
diff --git a/src/plugins/qmakeprojectmanager/qmakekitinformation.cpp b/src/plugins/qmakeprojectmanager/qmakekitinformation.cpp
index be619435b4..9333f75330 100644
--- a/src/plugins/qmakeprojectmanager/qmakekitinformation.cpp
+++ b/src/plugins/qmakeprojectmanager/qmakekitinformation.cpp
@@ -159,8 +159,7 @@ QString QmakeKitAspect::defaultMkspec(const Kit *k)
if (!version) // No version, so no qmake
return {};
- return version->mkspecFor(ToolChainKitAspect::toolChain(k,
- ProjectExplorer::Constants::CXX_LANGUAGE_ID));
+ return version->mkspecFor(ToolChainKitAspect::cxxToolChain(k));
}
} // namespace Internal
diff --git a/src/plugins/qmakeprojectmanager/qmakemakestep.cpp b/src/plugins/qmakeprojectmanager/qmakemakestep.cpp
index 83809bc77a..8a105d6666 100644
--- a/src/plugins/qmakeprojectmanager/qmakemakestep.cpp
+++ b/src/plugins/qmakeprojectmanager/qmakemakestep.cpp
@@ -65,8 +65,6 @@ QmakeMakeStep::QmakeMakeStep(BuildStepList *bsl, Core::Id id)
bool QmakeMakeStep::init()
{
const auto bc = static_cast<QmakeBuildConfiguration *>(buildConfiguration());
- if (!bc)
- emit addTask(Task::buildConfigurationMissingTask());
const Utils::CommandLine unmodifiedMake = effectiveMakeCommand(Execution);
const Utils::FilePath makeExecutable = unmodifiedMake.executable();
@@ -86,7 +84,7 @@ bool QmakeMakeStep::init()
Utils::FilePath workingDirectory;
if (bc->subNodeBuild())
- workingDirectory = bc->subNodeBuild()->buildDir(bc);
+ workingDirectory = bc->qmakeBuildSystem()->buildDir(bc->subNodeBuild()->filePath());
else
workingDirectory = bc->buildDirectory();
pp->setWorkingDirectory(workingDirectory);
@@ -107,7 +105,7 @@ bool QmakeMakeStep::init()
// for file builds, since the rules for that are
// only in those files.
if (subProFile->isDebugAndRelease() && bc->fileNodeBuild()) {
- if (bc->buildType() == QmakeBuildConfiguration::Debug)
+ if (buildType() == QmakeBuildConfiguration::Debug)
makefile += ".Debug";
else
makefile += ".Release";
@@ -132,7 +130,7 @@ bool QmakeMakeStep::init()
if (bc->fileNodeBuild() && subProFile) {
QString objectsDir = subProFile->objectsDirectory();
if (objectsDir.isEmpty()) {
- objectsDir = subProFile->buildDir(bc).toString();
+ objectsDir = bc->qmakeBuildSystem()->buildDir(subProFile->filePath()).toString();
if (subProFile->isDebugAndRelease()) {
if (bc->buildType() == QmakeBuildConfiguration::Debug)
objectsDir += "/debug";
@@ -162,23 +160,11 @@ bool QmakeMakeStep::init()
makeCmd.addArg(objectFile);
}
- pp->setEnvironment(environment(bc));
+ pp->setEnvironment(makeEnvironment());
pp->setCommandLine(makeCmd);
pp->resolveAll();
- setOutputParser(new ProjectExplorer::GnuMakeParser());
- ToolChain *tc = ToolChainKitAspect::toolChain(target()->kit(),
- ProjectExplorer::Constants::CXX_LANGUAGE_ID);
- if (tc && tc->targetAbi().os() == Abi::DarwinOS)
- appendOutputParser(new XcodebuildParser);
- IOutputParser *parser = target()->kit()->createOutputParser();
- if (parser)
- appendOutputParser(parser);
- outputParser()->setWorkingDirectory(pp->effectiveWorkingDirectory());
- appendOutputParser(new QMakeParser); // make may cause qmake to be run, add last to make sure
- // it has a low priority.
-
- auto rootNode = dynamic_cast<QmakeProFileNode *>(bc->project()->rootProjectNode());
+ auto rootNode = dynamic_cast<QmakeProFileNode *>(project()->rootProjectNode());
QTC_ASSERT(rootNode, return false);
m_scriptTarget = rootNode->projectType() == ProjectType::ScriptTemplate;
m_unalignedBuildDir = !bc->isBuildDirAtSafeLocation();
@@ -194,6 +180,30 @@ bool QmakeMakeStep::init()
return AbstractProcessStep::init();
}
+void QmakeMakeStep::setupOutputFormatter(Utils::OutputFormatter *formatter)
+{
+ formatter->addLineParser(new ProjectExplorer::GnuMakeParser());
+ ToolChain *tc = ToolChainKitAspect::cxxToolChain(target()->kit());
+ OutputTaskParser *xcodeBuildParser = nullptr;
+ if (tc && tc->targetAbi().os() == Abi::DarwinOS) {
+ xcodeBuildParser = new XcodebuildParser;
+ formatter->addLineParser(xcodeBuildParser);
+ }
+ QList<Utils::OutputLineParser *> additionalParsers = target()->kit()->createOutputParsers();
+
+ // make may cause qmake to be run, add last to make sure it has a low priority.
+ additionalParsers << new QMakeParser;
+
+ if (xcodeBuildParser) {
+ for (Utils::OutputLineParser * const p : qAsConst(additionalParsers))
+ p->setRedirectionDetector(xcodeBuildParser);
+ }
+ formatter->addLineParsers(additionalParsers);
+ formatter->addSearchDir(processParameters()->effectiveWorkingDirectory());
+
+ AbstractProcessStep::setupOutputFormatter(formatter);
+}
+
void QmakeMakeStep::doRun()
{
if (m_scriptTarget || m_ignoredNonTopLevelBuild) {
diff --git a/src/plugins/qmakeprojectmanager/qmakemakestep.h b/src/plugins/qmakeprojectmanager/qmakemakestep.h
index 29e5898e01..ea4fc72b66 100644
--- a/src/plugins/qmakeprojectmanager/qmakemakestep.h
+++ b/src/plugins/qmakeprojectmanager/qmakemakestep.h
@@ -52,6 +52,7 @@ public:
private:
void finish(bool success) override;
bool init() override;
+ void setupOutputFormatter(Utils::OutputFormatter *formatter) override;
void doRun() override;
QStringList displayArguments() const override;
diff --git a/src/plugins/qmakeprojectmanager/qmakenodes.cpp b/src/plugins/qmakeprojectmanager/qmakenodes.cpp
index d17ccfd5a1..557ded347a 100644
--- a/src/plugins/qmakeprojectmanager/qmakenodes.cpp
+++ b/src/plugins/qmakeprojectmanager/qmakenodes.cpp
@@ -26,7 +26,6 @@
#include "qmakenodes.h"
#include "qmakeproject.h"
-#include "qmakeprojectmanager.h"
#include <projectexplorer/buildconfiguration.h>
#include <projectexplorer/runconfiguration.h>
@@ -343,7 +342,7 @@ bool QmakeProFileNode::validParse() const
void QmakeProFileNode::build()
{
- QmakeManager::buildProduct(getProject(), this);
+ m_buildSystem->buildHelper(QmakeBuildSystem::BUILD, false, this, nullptr);
}
QStringList QmakeProFileNode::targetApplications() const
@@ -506,12 +505,6 @@ QString QmakeProFileNode::singleVariableValue(const Variable var) const
return values.isEmpty() ? QString() : values.first();
}
-FilePath QmakeProFileNode::buildDir(BuildConfiguration *bc) const
-{
- const QmakeProFile *pro = proFile();
- return pro ? pro->buildDir(bc) : FilePath();
-}
-
QString QmakeProFileNode::objectExtension() const
{
QStringList exts = variableValue(Variable::ObjectExt);
diff --git a/src/plugins/qmakeprojectmanager/qmakenodes.h b/src/plugins/qmakeprojectmanager/qmakenodes.h
index cf92bd950c..c6793dea0d 100644
--- a/src/plugins/qmakeprojectmanager/qmakenodes.h
+++ b/src/plugins/qmakeprojectmanager/qmakenodes.h
@@ -98,7 +98,6 @@ public:
bool setData(Core::Id role, const QVariant &value) const override;
QmakeProjectManager::ProjectType projectType() const;
- Utils::FilePath buildDir(ProjectExplorer::BuildConfiguration *bc) const;
QStringList variableValue(const Variable var) const;
QString singleVariableValue(const Variable var) const;
diff --git a/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp b/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp
index b4dfa4325d..f5563678c7 100644
--- a/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp
+++ b/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp
@@ -95,6 +95,8 @@ public:
QVector<FileTypeData> fileTypeData;
QIcon projectIcon;
+ QIcon productIcon;
+ QIcon groupIcon;
};
void clearQmakeStaticData();
@@ -114,6 +116,8 @@ QmakeStaticData::QmakeStaticData()
}
// Project icon
projectIcon = Core::FileIconProvider::directoryIcon(ProjectExplorer::Constants::FILEOVERLAY_QT);
+ productIcon = Core::FileIconProvider::directoryIcon(ProjectExplorer::Constants::FILEOVERLAY_PRODUCT);
+ groupIcon = Core::FileIconProvider::directoryIcon(ProjectExplorer::Constants::FILEOVERLAY_GROUP);
qAddPostRoutine(clearQmakeStaticData);
}
@@ -124,12 +128,20 @@ void clearQmakeStaticData()
{
qmakeStaticData()->fileTypeData.clear();
qmakeStaticData()->projectIcon = QIcon();
+ qmakeStaticData()->productIcon = QIcon();
+ qmakeStaticData()->groupIcon = QIcon();
}
} // namespace
namespace QmakeProjectManager {
+static QIcon iconForProfile(const QmakeProFile *proFile)
+{
+ return proFile->projectType() == ProjectType::SubDirsTemplate ? qmakeStaticData()->projectIcon
+ : qmakeStaticData()->productIcon;
+}
+
static void createTree(QmakeBuildSystem *buildSystem,
const QmakePriFile *pri,
QmakePriFileNode *node,
@@ -139,7 +151,6 @@ static void createTree(QmakeBuildSystem *buildSystem,
QTC_ASSERT(node, return);
node->setDisplayName(pri->displayName());
- node->setIcon(qmakeStaticData()->projectIcon);
// .pro/.pri-file itself:
node->addNode(std::make_unique<FileNode>(pri->filePath(), FileType::Project));
@@ -211,7 +222,7 @@ static void createTree(QmakeBuildSystem *buildSystem,
if (!generatedFiles.empty()) {
QTC_CHECK(proFile);
const FilePath baseDir = generatedFiles.size() == 1 ? generatedFiles.first().parentDir()
- : proFile->buildDir();
+ : buildSystem->buildDir(proFile->filePath());
auto genFolder = std::make_unique<VirtualFolderNode>(baseDir);
genFolder->setDisplayName(QCoreApplication::translate("QmakeProjectManager::QmakePriFile",
"Generated Files"));
@@ -227,10 +238,14 @@ static void createTree(QmakeBuildSystem *buildSystem,
// Virtual folders:
for (QmakePriFile *c : pri->children()) {
std::unique_ptr<QmakePriFileNode> newNode;
- if (auto pf = dynamic_cast<QmakeProFile *>(c))
+ if (auto pf = dynamic_cast<QmakeProFile *>(c)) {
newNode = std::make_unique<QmakeProFileNode>(c->buildSystem(), c->filePath(), pf);
- else
- newNode = std::make_unique<QmakePriFileNode>(c->buildSystem(), node->proFileNode(), c->filePath(), c);
+ newNode->setIcon(iconForProfile(pf));
+ } else {
+ newNode = std::make_unique<QmakePriFileNode>(c->buildSystem(), node->proFileNode(),
+ c->filePath(), c);
+ newNode->setIcon(qmakeStaticData->groupIcon);
+ }
createTree(buildSystem, c, newNode.get(), toExclude);
node->addNode(std::move(newNode));
}
@@ -239,14 +254,14 @@ static void createTree(QmakeBuildSystem *buildSystem,
std::unique_ptr<QmakeProFileNode> QmakeNodeTreeBuilder::buildTree(QmakeBuildSystem *buildSystem)
{
// Remove qmake implementation details that litter up the project data:
- Target *t = buildSystem->target();
- BaseQtVersion *qt = QtKitAspect::qtVersion(t->kit());
+ BaseQtVersion *qt = QtKitAspect::qtVersion(buildSystem->kit());
const FilePaths toExclude = qt ? qt->directoriesToIgnoreInProjectTree() : FilePaths();
auto root = std::make_unique<QmakeProFileNode>(buildSystem,
buildSystem->projectFilePath(),
buildSystem->rootProFile());
+ root->setIcon(iconForProfile(buildSystem->rootProFile()));
createTree(buildSystem, buildSystem->rootProFile(), root.get(), toExclude);
return root;
diff --git a/src/plugins/qmakeprojectmanager/qmakeparser.cpp b/src/plugins/qmakeprojectmanager/qmakeparser.cpp
index 46ad10a0a0..64e08bf675 100644
--- a/src/plugins/qmakeprojectmanager/qmakeparser.cpp
+++ b/src/plugins/qmakeprojectmanager/qmakeparser.cpp
@@ -40,18 +40,23 @@ QMakeParser::QMakeParser() : m_error(QLatin1String("^(.+):(\\d+):\\s(.+)$"))
m_error.setMinimal(true);
}
-void QMakeParser::stdError(const QString &line)
+OutputLineParser::Result QMakeParser::handleLine(const QString &line, OutputFormat type)
{
+ if (type != Utils::StdErrFormat)
+ return Status::NotHandled;
QString lne = rightTrimmed(line);
if (m_error.indexIn(lne) > -1) {
QString fileName = m_error.cap(1);
Task::TaskType type = Task::Error;
const QString description = m_error.cap(3);
+ int fileNameOffset = m_error.pos(1);
if (fileName.startsWith(QLatin1String("WARNING: "))) {
type = Task::Warning;
fileName = fileName.mid(9);
+ fileNameOffset += 9;
} else if (fileName.startsWith(QLatin1String("ERROR: "))) {
fileName = fileName.mid(7);
+ fileNameOffset += 7;
}
if (description.startsWith(QLatin1String("note:"), Qt::CaseInsensitive))
type = Task::Unknown;
@@ -59,26 +64,28 @@ void QMakeParser::stdError(const QString &line)
type = Task::Warning;
else if (description.startsWith(QLatin1String("error:"), Qt::CaseInsensitive))
type = Task::Error;
- emit addTask(BuildSystemTask(type,
- description,
- FilePath::fromUserInput(fileName),
- m_error.cap(2).toInt() /* line */),
- 1);
- return;
+
+ BuildSystemTask t(type, description, absoluteFilePath(FilePath::fromUserInput(fileName)),
+ m_error.cap(2).toInt() /* line */);
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, t.file, t.line, fileNameOffset,
+ fileName.length());
+ scheduleTask(t, 1);
+ return {Status::Done, linkSpecs};
}
if (lne.startsWith(QLatin1String("Project ERROR: "))
|| lne.startsWith(QLatin1String("ERROR: "))) {
const QString description = lne.mid(lne.indexOf(QLatin1Char(':')) + 2);
- emit addTask(BuildSystemTask(Task::Error, description), 1);
- return;
+ scheduleTask(BuildSystemTask(Task::Error, description), 1);
+ return Status::Done;
}
if (lne.startsWith(QLatin1String("Project WARNING: "))
|| lne.startsWith(QLatin1String("WARNING: "))) {
const QString description = lne.mid(lne.indexOf(QLatin1Char(':')) + 2);
- emit addTask(BuildSystemTask(Task::Warning, description), 1);
- return;
+ scheduleTask(BuildSystemTask(Task::Warning, description), 1);
+ return Status::Done;
}
- IOutputParser::stdError(line);
+ return Status::NotHandled;
}
} // QmakeProjectManager
@@ -172,14 +179,14 @@ void QmakeProjectManagerPlugin::testQmakeOutputParsers_data()
<< (Tasks()
<< BuildSystemTask(Task::Unknown,
"Note: No relevant classes found. No output generated.",
- FilePath::fromUserInput("/home/qtwebkithelpviewer.h"), 0))
+ FilePath::fromUserInput("/home/qtwebkithelpviewer.h"), -1))
<< QString();
}
void QmakeProjectManagerPlugin::testQmakeOutputParsers()
{
OutputParserTester testbench;
- testbench.appendOutputParser(new QMakeParser);
+ testbench.addLineParser(new QMakeParser);
QFETCH(QString, input);
QFETCH(OutputParserTester::Channel, inputChannel);
QFETCH(Tasks, tasks);
diff --git a/src/plugins/qmakeprojectmanager/qmakeparser.h b/src/plugins/qmakeprojectmanager/qmakeparser.h
index 51680e45c5..210e5e576c 100644
--- a/src/plugins/qmakeprojectmanager/qmakeparser.h
+++ b/src/plugins/qmakeprojectmanager/qmakeparser.h
@@ -33,15 +33,16 @@
namespace QmakeProjectManager {
-class QMAKEPROJECTMANAGER_EXPORT QMakeParser : public ProjectExplorer::IOutputParser
+class QMAKEPROJECTMANAGER_EXPORT QMakeParser : public ProjectExplorer::OutputTaskParser
{
Q_OBJECT
public:
QMakeParser();
- void stdError(const QString &line) override;
private:
+ Result handleLine(const QString &line, Utils::OutputFormat type) override;
+
QRegExp m_error;
};
diff --git a/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp b/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp
index 068fb5d703..7c3f8ee915 100644
--- a/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp
+++ b/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp
@@ -1336,7 +1336,7 @@ QmakeEvalInput QmakeProFile::evalInput() const
QmakeEvalInput input;
input.projectDir = directoryPath().toString();
input.projectFilePath = filePath();
- input.buildDirectory = buildDir();
+ input.buildDirectory = m_buildSystem->buildDir(m_filePath);
input.sysroot = FilePath::fromString(m_buildSystem->qmakeSysroot());
input.readerExact = m_readerExact;
input.readerCumulative = m_readerCumulative;
@@ -1726,13 +1726,13 @@ void QmakeProFile::applyEvaluate(QmakeEvalResult *evalResult)
//
// Add/Remove pri files, sub projects
//
- FilePath buildDirectory = buildDir();
+ FilePath buildDirectory = m_buildSystem->buildDir(m_filePath);
makeEmpty();
for (QmakePriFile * const toAdd : qAsConst(result->directChildren))
addChild(toAdd);
result->directChildren.clear();
- for (const auto priFiles : qAsConst(result->priFiles)) {
+ for (const auto &priFiles : qAsConst(result->priFiles)) {
priFiles.first->finishInitialization(m_buildSystem, this);
priFiles.first->update(priFiles.second);
}
@@ -2069,20 +2069,6 @@ FilePath QmakeProFile::sourceDir() const
return directoryPath();
}
-FilePath QmakeProFile::buildDir(BuildConfiguration *bc) const
-{
- if (!bc)
- bc = m_buildSystem->target()->activeBuildConfiguration();
-
- const QDir srcDirRoot = QDir(m_buildSystem->projectDirectory().toString());
- const QString relativeDir = srcDirRoot.relativeFilePath(directoryPath().toString());
- const QString buildConfigBuildDir = bc ? bc->buildDirectory().toString() : QString();
- const QString buildDir = buildConfigBuildDir.isEmpty()
- ? m_buildSystem->projectDirectory().toString()
- : buildConfigBuildDir;
- return FilePath::fromString(QDir::cleanPath(QDir(buildDir).absoluteFilePath(relativeDir)));
-}
-
FilePaths QmakeProFile::generatedFiles(const FilePath &buildDir,
const FilePath &sourceFile,
const FileType &sourceFileType) const
diff --git a/src/plugins/qmakeprojectmanager/qmakeparsernodes.h b/src/plugins/qmakeprojectmanager/qmakeparsernodes.h
index c1029bde85..54331a82d7 100644
--- a/src/plugins/qmakeprojectmanager/qmakeparsernodes.h
+++ b/src/plugins/qmakeprojectmanager/qmakeparsernodes.h
@@ -42,6 +42,8 @@
#include <memory>
+namespace ProjectExplorer { class BuildConfiguration; }
+
namespace Utils {
class FilePath;
class FileSystemWatcher;
@@ -50,7 +52,6 @@ class FileSystemWatcher;
namespace QtSupport { class ProFileReader; }
namespace QmakeProjectManager {
-class QmakeBuildConfiguration;
class QmakeBuildSystem;
class QmakeProFile;
class QmakeProject;
@@ -320,7 +321,6 @@ public:
}
Utils::FilePath sourceDir() const;
- Utils::FilePath buildDir(ProjectExplorer::BuildConfiguration *bc = nullptr) const;
Utils::FilePaths generatedFiles(const Utils::FilePath &buildDirectory,
const Utils::FilePath &sourceFile,
diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp
index 00d23d3f75..90eeeb8f9b 100644
--- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp
+++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp
@@ -25,14 +25,13 @@
#include "qmakeproject.h"
-#include "qmakeprojectmanager.h"
-#include "qmakeprojectimporter.h"
+#include "qmakebuildconfiguration.h"
#include "qmakebuildinfo.h"
-#include "qmakestep.h"
#include "qmakenodes.h"
#include "qmakenodetreebuilder.h"
+#include "qmakeprojectimporter.h"
#include "qmakeprojectmanagerconstants.h"
-#include "qmakebuildconfiguration.h"
+#include "qmakestep.h"
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/icontext.h>
@@ -74,6 +73,7 @@
#include <QDir>
#include <QFileSystemWatcher>
#include <QLoggingCategory>
+#include <QTimer>
using namespace QmakeProjectManager::Internal;
using namespace ProjectExplorer;
@@ -87,6 +87,17 @@ const int UPDATE_INTERVAL = 3000;
static Q_LOGGING_CATEGORY(qmakeBuildSystemLog, "qtc.qmake.buildsystem", QtWarningMsg);
+#define TRACE(msg) \
+ if (qmakeBuildSystemLog().isDebugEnabled()) { \
+ qCDebug(qmakeBuildSystemLog) \
+ << qPrintable(buildConfiguration()->displayName()) \
+ << ", guards project: " << int(m_guard.guardsProject()) \
+ << ", isParsing: " << int(isParsing()) \
+ << ", hasParsingData: " << int(hasParsingData()) \
+ << ", " << __FUNCTION__ \
+ << msg; \
+ }
+
/// Watches folders for QmakePriFile nodes
/// use one file system watcher to watch all folders
/// such minimizing system ressouce usage
@@ -171,33 +182,32 @@ DeploymentKnowledge QmakeProject::deploymentKnowledge() const
//
QmakeBuildSystem::QmakeBuildSystem(QmakeBuildConfiguration *bc)
- : BuildSystem(bc),
- m_qmakeVfs(new QMakeVfs),
- m_cppCodeModelUpdater(new CppTools::CppProjectUpdater),
- m_buildConfiguration(bc)
+ : BuildSystem(bc)
+ , m_qmakeVfs(new QMakeVfs)
+ , m_cppCodeModelUpdater(new CppTools::CppProjectUpdater)
{
const QTextCodec *codec = Core::EditorManager::defaultTextCodec();
m_qmakeVfs->setTextCodec(codec);
- m_asyncUpdateTimer.setSingleShot(true);
- m_asyncUpdateTimer.setInterval(0);
- connect(&m_asyncUpdateTimer, &QTimer::timeout, this, &QmakeBuildSystem::asyncUpdate);
+ setParseDelay(0);
m_rootProFile = std::make_unique<QmakeProFile>(this, projectFilePath());
connect(BuildManager::instance(), &BuildManager::buildQueueFinished,
this, &QmakeBuildSystem::buildFinished);
- connect(bc->target(), &Target::activeBuildConfigurationChanged,
- this, [this](BuildConfiguration *bc) {
- if (bc == m_buildConfiguration)
- scheduleUpdateAllNowOrLater();
-// FIXME: This is too eager in the presence of not handling updates
-// when the build configuration is not active, see startAsyncTimer
-// below.
-// else
-// m_cancelEvaluate = true;
- });
+ connect(bc->target(),
+ &Target::activeBuildConfigurationChanged,
+ this,
+ [this](BuildConfiguration *bc) {
+ if (bc == buildConfiguration())
+ scheduleUpdateAllNowOrLater();
+ // FIXME: This is too eager in the presence of not handling updates
+ // when the build configuration is not active, see startAsyncTimer
+ // below.
+ // else
+ // m_cancelEvaluate = true;
+ });
connect(bc->project(), &Project::activeTargetChanged,
this, &QmakeBuildSystem::activeTargetWasChanged);
@@ -212,7 +222,7 @@ QmakeBuildSystem::QmakeBuildSystem(QmakeBuildConfiguration *bc)
connect(ToolChainManager::instance(), &ToolChainManager::toolChainUpdated,
this, [this](ToolChain *tc) {
- if (ToolChainKitAspect::toolChain(kit(), ProjectExplorer::Constants::CXX_LANGUAGE_ID) == tc)
+ if (ToolChainKitAspect::cxxToolChain(kit()) == tc)
scheduleUpdateAllNowOrLater();
});
@@ -248,7 +258,7 @@ QmakeBuildSystem::~QmakeBuildSystem()
void QmakeBuildSystem::updateCodeModels()
{
- if (!m_buildConfiguration->isActive())
+ if (!buildConfiguration()->isActive())
return;
updateCppCodeModel();
@@ -449,23 +459,38 @@ void QmakeBuildSystem::scheduleAsyncUpdateFile(QmakeProFile *file, QmakeProFile:
void QmakeBuildSystem::scheduleUpdateAllNowOrLater()
{
- qCDebug(qmakeBuildSystemLog) << __FUNCTION__ << m_firstParseNeeded;
if (m_firstParseNeeded)
scheduleUpdateAll(QmakeProFile::ParseNow);
else
scheduleUpdateAll(QmakeProFile::ParseLater);
}
+QmakeBuildConfiguration *QmakeBuildSystem::qmakeBuildConfiguration() const
+{
+ return static_cast<QmakeBuildConfiguration *>(BuildSystem::buildConfiguration());
+}
+
void QmakeBuildSystem::scheduleUpdateAll(QmakeProFile::AsyncUpdateDelay delay)
{
- if (m_asyncUpdateState == ShuttingDown)
+ if (m_asyncUpdateState == ShuttingDown) {
+ TRACE("suppressed: we are shutting down");
return;
+ }
if (m_cancelEvaluate) { // we are in progress of canceling
// and will start the evaluation after that
+ TRACE("suppressed: was previously canceled");
return;
}
+ if (!buildConfiguration()->isActive()) {
+ TRACE("firstParseNeeded: " << int(m_firstParseNeeded)
+ << ", suppressed: buildconfig not active");
+ return;
+ }
+
+ TRACE("firstParseNeeded: " << int(m_firstParseNeeded) << ", delay: " << delay);
+
rootProFile()->setParseInProgressRecursive(true);
if (m_asyncUpdateState == AsyncUpdateInProgress) {
@@ -484,18 +509,15 @@ void QmakeBuildSystem::scheduleUpdateAll(QmakeProFile::AsyncUpdateDelay delay)
void QmakeBuildSystem::startAsyncTimer(QmakeProFile::AsyncUpdateDelay delay)
{
- if (!m_buildConfiguration->isActive()) {
- qCDebug(qmakeBuildSystemLog) << __FUNCTION__ << "skipped, not active";
+ if (!buildConfiguration()->isActive()) {
+ TRACE("skipped, not active")
return;
- }
+ }
- const int interval = qMin(m_asyncUpdateTimer.interval(),
+ const int interval = qMin(parseDelay(),
delay == QmakeProFile::ParseLater ? UPDATE_INTERVAL : 0);
- qCDebug(qmakeBuildSystemLog) << __FUNCTION__ << interval;
-
- m_asyncUpdateTimer.stop();
- m_asyncUpdateTimer.setInterval(interval);
- m_asyncUpdateTimer.start();
+ TRACE("interval: " << interval);
+ requestParseWithCustomDelay(interval);
}
void QmakeBuildSystem::incrementPendingEvaluateFutures()
@@ -508,6 +530,7 @@ void QmakeBuildSystem::incrementPendingEvaluateFutures()
m_guard = guardParsingRun();
}
++m_pendingEvaluateFuturesCount;
+ TRACE("pending inc to: " << m_pendingEvaluateFuturesCount);
m_asyncUpdateFutureInterface.setProgressRange(m_asyncUpdateFutureInterface.progressMinimum(),
m_asyncUpdateFutureInterface.progressMaximum() + 1);
}
@@ -515,9 +538,12 @@ void QmakeBuildSystem::incrementPendingEvaluateFutures()
void QmakeBuildSystem::decrementPendingEvaluateFutures()
{
--m_pendingEvaluateFuturesCount;
+ TRACE("pending dec to: " << m_pendingEvaluateFuturesCount);
- if (!rootProFile())
+ if (!rootProFile()) {
+ TRACE("closing project");
return; // We are closing the project!
+ }
m_asyncUpdateFutureInterface.setProgressValue(m_asyncUpdateFutureInterface.progressValue() + 1);
if (m_pendingEvaluateFuturesCount == 0) {
@@ -544,10 +570,11 @@ void QmakeBuildSystem::decrementPendingEvaluateFutures()
updateDocuments();
target()->updateDefaultDeployConfigurations();
m_guard.markAsSuccess(); // Qmake always returns (some) data, even when it failed:-)
+ TRACE("success" << int(m_guard.isSuccess()));
m_guard = {}; // This triggers emitParsingFinished by destroying the previous guard.
- qCDebug(qmakeBuildSystemLog) << __FUNCTION__ << "first parse succeeded";
m_firstParseNeeded = false;
+ TRACE("first parse succeeded");
emitBuildSystemUpdated();
}
@@ -561,8 +588,8 @@ bool QmakeBuildSystem::wasEvaluateCanceled()
void QmakeBuildSystem::asyncUpdate()
{
- m_asyncUpdateTimer.setInterval(UPDATE_INTERVAL);
- qCDebug(qmakeBuildSystemLog) << __FUNCTION__;
+ setParseDelay(UPDATE_INTERVAL);
+ TRACE("");
if (m_invalidateQmakeVfsContents) {
m_invalidateQmakeVfsContents = false;
@@ -578,12 +605,13 @@ void QmakeBuildSystem::asyncUpdate()
m_asyncUpdateFutureInterface.reportStarted();
- const Kit * const kit = target()->kit();
- QtSupport::BaseQtVersion * const qtVersion = QtSupport::QtKitAspect::qtVersion(kit);
+ const Kit *const k = kit();
+ QtSupport::BaseQtVersion *const qtVersion = QtSupport::QtKitAspect::qtVersion(k);
if (!qtVersion || !qtVersion->isValid()) {
- const QString errorMessage = kit
- ? tr("Cannot parse project \"%1\": The currently selected kit \"%2\" does not "
- "have a valid Qt.").arg(project()->displayName(), kit->displayName())
+ const QString errorMessage
+ = k ? tr("Cannot parse project \"%1\": The currently selected kit \"%2\" does not "
+ "have a valid Qt.")
+ .arg(project()->displayName(), k->displayName())
: tr("Cannot parse project \"%1\": No kit selected.").arg(project()->displayName());
proFileParseError(errorMessage);
m_asyncUpdateFutureInterface.reportCanceled();
@@ -616,7 +644,7 @@ Tasks QmakeProject::projectIssues(const Kit *k) const
result.append(createProjectTask(Task::TaskType::Error, tr("No Qt version set in kit.")));
else if (!qtFromKit->isValid())
result.append(createProjectTask(Task::TaskType::Error, tr("Qt version is invalid.")));
- if (!ToolChainKitAspect::toolChain(k, ProjectExplorer::Constants::CXX_LANGUAGE_ID))
+ if (!ToolChainKitAspect::cxxToolChain(k))
result.append(createProjectTask(Task::TaskType::Error, tr("No C++ compiler set in kit.")));
// A project can be considered part of more than one Qt version, for instance if it is an
@@ -664,6 +692,17 @@ static FileNode *fileNodeOf(FolderNode *in, const FilePath &fileName)
return nullptr;
}
+FilePath QmakeBuildSystem::buildDir(const FilePath &proFilePath) const
+{
+ const QDir srcDirRoot = QDir(projectDirectory().toString());
+ const QString relativeDir = srcDirRoot.relativeFilePath(proFilePath.parentDir().toString());
+ const QString buildConfigBuildDir = buildConfiguration()->buildDirectory().toString();
+ const QString buildDir = buildConfigBuildDir.isEmpty()
+ ? projectDirectory().toString()
+ : buildConfigBuildDir;
+ return FilePath::fromString(QDir::cleanPath(QDir(buildDir).absoluteFilePath(relativeDir)));
+}
+
void QmakeBuildSystem::proFileParseError(const QString &errorMessage)
{
Core::MessageManager::write(errorMessage);
@@ -677,13 +716,14 @@ QtSupport::ProFileReader *QmakeBuildSystem::createProFileReader(const QmakeProFi
QStringList qmakeArgs;
- Target *t = target();
- Kit *k = t->kit();
- Environment env = m_buildConfiguration->environment();
- if (QMakeStep *qs = m_buildConfiguration->qmakeStep())
+ Kit *k = kit();
+ QmakeBuildConfiguration *bc = qmakeBuildConfiguration();
+
+ Environment env = bc->environment();
+ if (QMakeStep *qs = bc->qmakeStep())
qmakeArgs = qs->parserArguments();
else
- qmakeArgs = m_buildConfiguration->configCommandLineArguments();
+ qmakeArgs = bc->configCommandLineArguments();
QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitAspect::qtVersion(k);
m_qmakeSysroot = SysRootKitAspect::sysRoot(k).toString();
@@ -693,13 +733,13 @@ QtSupport::ProFileReader *QmakeBuildSystem::createProFileReader(const QmakeProFi
qtVersion->applyProperties(m_qmakeGlobals.get());
}
m_qmakeGlobals->setDirectories(rootProFile()->sourceDir().toString(),
- rootProFile()->buildDir().toString());
+ buildDir(rootProFile()->filePath()).toString());
Environment::const_iterator eit = env.constBegin(), eend = env.constEnd();
for (; eit != eend; ++eit)
m_qmakeGlobals->environment.insert(env.key(eit), env.expandedValueForKey(env.key(eit)));
- m_qmakeGlobals->setCommandLineArguments(rootProFile()->buildDir().toString(), qmakeArgs);
+ m_qmakeGlobals->setCommandLineArguments(buildDir(rootProFile()->filePath()).toString(), qmakeArgs);
QtSupport::ProFileCacheManager::instance()->incRefCount();
@@ -721,7 +761,7 @@ QtSupport::ProFileReader *QmakeBuildSystem::createProFileReader(const QmakeProFi
auto reader = new QtSupport::ProFileReader(m_qmakeGlobals.get(), m_qmakeVfs);
- reader->setOutputDir(qmakeProFile->buildDir().toString());
+ reader->setOutputDir(buildDir(qmakeProFile->filePath()).toString());
return reader;
}
@@ -766,7 +806,7 @@ void QmakeBuildSystem::deregisterFromCacheManager()
void QmakeBuildSystem::activeTargetWasChanged(Target *t)
{
// We are only interested in our own target.
- if (t != m_buildConfiguration->target())
+ if (t != target())
return;
m_invalidateQmakeVfsContents = true;
@@ -1052,7 +1092,7 @@ void QmakeBuildSystem::updateBuildSystemData()
if (!libDirectories.isEmpty()) {
QmakeProFile *proFile = node->proFile();
QTC_ASSERT(proFile, return);
- const QString proDirectory = proFile->buildDir().toString();
+ const QString proDirectory = buildDir(proFile->filePath()).toString();
foreach (QString dir, libDirectories) {
// Fix up relative entries like "LIBS+=-L.."
const QFileInfo fi(dir);
@@ -1061,7 +1101,7 @@ void QmakeBuildSystem::updateBuildSystemData()
libraryPaths.append(dir);
}
}
- QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitAspect::qtVersion(target()->kit());
+ QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitAspect::qtVersion(kit());
if (qtVersion)
libraryPaths.append(qtVersion->librarySearchPath().toString());
@@ -1135,8 +1175,7 @@ void QmakeBuildSystem::collectLibraryData(const QmakeProFile *file, DeploymentDa
const QString targetPath = file->installsList().targetPath;
if (targetPath.isEmpty())
return;
- const Kit * const kit = target()->kit();
- const ToolChain * const toolchain = ToolChainKitAspect::toolChain(kit, ProjectExplorer::Constants::CXX_LANGUAGE_ID);
+ const ToolChain *const toolchain = ToolChainKitAspect::cxxToolChain(kit());
if (!toolchain)
return;
@@ -1245,12 +1284,7 @@ void QmakeBuildSystem::testToolChain(ToolChain *tc, const FilePath &path) const
return;
const Utils::FilePath expected = tc->compilerCommand();
-
- Target *t = target();
- QTC_ASSERT(t, return);
-
- QTC_ASSERT(m_buildConfiguration, return);
- Environment env = m_buildConfiguration->environment();
+ Environment env = buildConfiguration()->environment();
if (env.isSameExecutable(path.toString(), expected.toString()))
return;
@@ -1265,35 +1299,29 @@ void QmakeBuildSystem::testToolChain(ToolChain *tc, const FilePath &path) const
return;
}
TaskHub::addTask(
- BuildSystemTask(Task::Warning,
- QCoreApplication::translate(
- "QmakeProjectManager",
- "\"%1\" is used by qmake, but \"%2\" is configured in the kit.\n"
- "Please update your kit (%3) or choose a mkspec for qmake that matches "
- "your target environment better.")
- .arg(path.toUserOutput())
- .arg(expected.toUserOutput())
- .arg(t->kit()->displayName())));
+ BuildSystemTask(Task::Warning,
+ QCoreApplication::translate(
+ "QmakeProjectManager",
+ "\"%1\" is used by qmake, but \"%2\" is configured in the kit.\n"
+ "Please update your kit (%3) or choose a mkspec for qmake that matches "
+ "your target environment better.")
+ .arg(path.toUserOutput())
+ .arg(expected.toUserOutput())
+ .arg(kit()->displayName())));
m_toolChainWarnings.insert(pair);
}
void QmakeBuildSystem::warnOnToolChainMismatch(const QmakeProFile *pro) const
{
- const Target *t = target();
- const BuildConfiguration *bc = t ? t->activeBuildConfiguration() : nullptr;
- if (!bc)
- return;
-
- testToolChain(ToolChainKitAspect::toolChain(t->kit(), ProjectExplorer::Constants::C_LANGUAGE_ID),
- getFullPathOf(pro, Variable::QmakeCc, bc));
- testToolChain(ToolChainKitAspect::toolChain(t->kit(), ProjectExplorer::Constants::CXX_LANGUAGE_ID),
+ const BuildConfiguration *bc = buildConfiguration();
+ testToolChain(ToolChainKitAspect::cToolChain(kit()), getFullPathOf(pro, Variable::QmakeCc, bc));
+ testToolChain(ToolChainKitAspect::cxxToolChain(kit()),
getFullPathOf(pro, Variable::QmakeCxx, bc));
}
QString QmakeBuildSystem::executableFor(const QmakeProFile *file)
{
- const Kit *const kit = target()->kit();
- const ToolChain *const tc = ToolChainKitAspect::toolChain(kit, ProjectExplorer::Constants::CXX_LANGUAGE_ID);
+ const ToolChain *const tc = ToolChainKitAspect::cxxToolChain(kit());
if (!tc)
return QString();
@@ -1346,7 +1374,7 @@ QStringList QmakeBuildSystem::filesGeneratedFrom(const QString &input) const
const QmakeProFileNode *pro = dynamic_cast<QmakeProFileNode *>(file->parentFolderNode());
QTC_ASSERT(pro, return {});
if (const QmakeProFile *proFile = pro->proFile())
- return Utils::transform(proFile->generatedFiles(pro->buildDir(nullptr),
+ return Utils::transform(proFile->generatedFiles(buildDir(pro->filePath()),
file->filePath(), file->fileType()),
&FilePath::toString);
}
@@ -1360,6 +1388,34 @@ QVariant QmakeBuildSystem::additionalData(Core::Id id) const
return BuildSystem::additionalData(id);
}
+void QmakeBuildSystem::buildHelper(Action action, bool isFileBuild, QmakeProFileNode *profile,
+ FileNode *buildableFile)
+{
+ auto bc = qmakeBuildConfiguration();
+
+ if (!profile || !buildableFile)
+ isFileBuild = false;
+
+ if (profile) {
+ if (profile != project()->rootProjectNode() || isFileBuild)
+ bc->setSubNodeBuild(profile->proFileNode());
+ }
+
+ if (isFileBuild)
+ bc->setFileNodeBuild(buildableFile);
+ if (ProjectExplorerPlugin::saveModifiedFiles()) {
+ if (action == BUILD)
+ BuildManager::buildList(bc->buildSteps());
+ else if (action == CLEAN)
+ BuildManager::buildList(bc->cleanSteps());
+ else if (action == REBUILD)
+ BuildManager::buildLists({bc->cleanSteps(), bc->buildSteps()});
+ }
+
+ bc->setSubNodeBuild(nullptr);
+ bc->setFileNodeBuild(nullptr);
+}
+
} // QmakeProjectManager
#include "qmakeproject.moc"
diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.h b/src/plugins/qmakeprojectmanager/qmakeproject.h
index 9cd8902dbb..bf2f9ae45d 100644
--- a/src/plugins/qmakeprojectmanager/qmakeproject.h
+++ b/src/plugins/qmakeprojectmanager/qmakeproject.h
@@ -26,16 +26,16 @@
#pragma once
#include "qmakeprojectmanager_global.h"
-#include "qmakeprojectmanager.h"
+
#include "qmakenodes.h"
#include "qmakeparsernodes.h"
#include <projectexplorer/deploymentdata.h>
#include <projectexplorer/project.h>
+#include <projectexplorer/toolchain.h>
#include <QStringList>
#include <QFutureInterface>
-#include <QTimer>
#include <QFuture>
QT_BEGIN_NAMESPACE
@@ -49,6 +49,8 @@ namespace QtSupport { class ProFileReader; }
namespace QmakeProjectManager {
+class QmakeBuildConfiguration;
+
namespace Internal { class CentralizedFolderWatcher; }
class QMAKEPROJECTMANAGER_EXPORT QmakeProject final : public ProjectExplorer::Project
@@ -166,10 +168,19 @@ public:
void notifyChanged(const Utils::FilePath &name);
-public:
+ enum Action { BUILD, REBUILD, CLEAN };
+ void buildHelper(Action action, bool isFileBuild,
+ QmakeProFileNode *profile,
+ ProjectExplorer::FileNode *buildableFile);
+
+ Utils::FilePath buildDir(const Utils::FilePath &proFilePath) const;
+ QmakeBuildConfiguration *qmakeBuildConfiguration() const;
+
+ void scheduleUpdateAllNowOrLater();
+
+private:
void scheduleUpdateAll(QmakeProFile::AsyncUpdateDelay delay);
void scheduleUpdateAllLater() { scheduleUpdateAll(QmakeProFile::ParseLater); }
- void scheduleUpdateAllNowOrLater();
mutable QSet<const QPair<Utils::FilePath, Utils::FilePath>> m_toolChainWarnings;
@@ -188,7 +199,6 @@ public:
QString m_qmakeSysroot;
- QTimer m_asyncUpdateTimer;
QFutureInterface<void> m_asyncUpdateFutureInterface;
int m_pendingEvaluateFuturesCount = 0;
AsyncUpdateState m_asyncUpdateState = Base;
@@ -200,7 +210,6 @@ public:
Internal::CentralizedFolderWatcher *m_centralizedFolderWatcher = nullptr;
ProjectExplorer::BuildSystem::ParseGuard m_guard;
- QmakeBuildConfiguration *m_buildConfiguration = nullptr;
bool m_firstParseNeeded = true;
};
diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectimporter.cpp b/src/plugins/qmakeprojectmanager/qmakeprojectimporter.cpp
index 71fd912e10..c4ef9ce815 100644
--- a/src/plugins/qmakeprojectmanager/qmakeprojectimporter.cpp
+++ b/src/plugins/qmakeprojectmanager/qmakeprojectimporter.cpp
@@ -206,7 +206,7 @@ bool QmakeProjectImporter::matchKit(void *directoryData, const Kit *k) const
BaseQtVersion *kitVersion = QtKitAspect::qtVersion(k);
QString kitSpec = QmakeKitAspect::mkspec(k);
- ToolChain *tc = ToolChainKitAspect::toolChain(k, ProjectExplorer::Constants::CXX_LANGUAGE_ID);
+ ToolChain *tc = ToolChainKitAspect::cxxToolChain(k);
if (kitSpec.isEmpty() && kitVersion)
kitSpec = kitVersion->mkspecFor(tc);
QMakeStepConfig::TargetArchConfig kitTargetArch = QMakeStepConfig::NoArch;
diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectmanager.cpp b/src/plugins/qmakeprojectmanager/qmakeprojectmanager.cpp
deleted file mode 100644
index ba7b44b7d6..0000000000
--- a/src/plugins/qmakeprojectmanager/qmakeprojectmanager.cpp
+++ /dev/null
@@ -1,256 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qmakeprojectmanager.h"
-
-#include "qmakeprojectmanagerconstants.h"
-#include "qmakeprojectmanagerplugin.h"
-#include "qmakenodes.h"
-#include "qmakeproject.h"
-#include "profileeditor.h"
-#include "qmakestep.h"
-#include "qmakebuildconfiguration.h"
-#include "addlibrarywizard.h"
-
-#include <coreplugin/icore.h>
-#include <coreplugin/editormanager/editormanager.h>
-#include <projectexplorer/projectexplorer.h>
-#include <projectexplorer/projecttree.h>
-#include <projectexplorer/buildmanager.h>
-#include <projectexplorer/session.h>
-#include <projectexplorer/target.h>
-#include <utils/qtcassert.h>
-#include <texteditor/texteditor.h>
-
-#include <QDir>
-#include <QFileInfo>
-#include <QVariant>
-
-using namespace ProjectExplorer;
-using namespace TextEditor;
-
-namespace QmakeProjectManager {
-
-static QmakeProFileNode *buildableFileProFile(Node *node)
-{
- if (node) {
- auto subPriFileNode = dynamic_cast<QmakePriFileNode *>(node);
- if (!subPriFileNode)
- subPriFileNode = dynamic_cast<QmakePriFileNode *>(node->parentProjectNode());
- if (subPriFileNode)
- return subPriFileNode->proFileNode();
- }
- return nullptr;
-}
-
-FileNode *QmakeManager::contextBuildableFileNode()
-{
- Node *node = ProjectTree::currentNode();
-
- QmakeProFileNode *subProjectNode = buildableFileProFile(node);
- FileNode *fileNode = node ? node->asFileNode() : nullptr;
- bool buildFilePossible = subProjectNode && fileNode
- && (fileNode->fileType() == ProjectExplorer::FileType::Source);
-
- return buildFilePossible ? fileNode : nullptr;
-}
-
-void QmakeManager::addLibrary()
-{
- if (auto editor = qobject_cast<BaseTextEditor *>(Core::EditorManager::currentEditor()))
- addLibraryImpl(editor->document()->filePath().toString(), editor);
-}
-
-void QmakeManager::addLibraryContextMenu()
-{
- QString projectPath;
-
- Node *node = ProjectTree::currentNode();
- if (ContainerNode *cn = node->asContainerNode())
- projectPath = cn->project()->projectFilePath().toString();
- else if (dynamic_cast<QmakeProFileNode *>(node))
- projectPath = node->filePath().toString();
-
- addLibraryImpl(projectPath, nullptr);
-}
-
-void QmakeManager::addLibraryImpl(const QString &fileName, BaseTextEditor *editor)
-{
- if (fileName.isEmpty())
- return;
-
- Internal::AddLibraryWizard wizard(fileName, Core::ICore::dialogParent());
- if (wizard.exec() != QDialog::Accepted)
- return;
-
- if (!editor)
- editor = qobject_cast<BaseTextEditor *>(Core::EditorManager::openEditor(fileName,
- Constants::PROFILE_EDITOR_ID, Core::EditorManager::DoNotMakeVisible));
- if (!editor)
- return;
-
- const int endOfDoc = editor->position(EndOfDocPosition);
- editor->setCursorPosition(endOfDoc);
- QString snippet = wizard.snippet();
-
- // add extra \n in case the last line is not empty
- int line, column;
- editor->convertPosition(endOfDoc, &line, &column);
- const int positionInBlock = column - 1;
- if (!editor->textAt(endOfDoc - positionInBlock, positionInBlock).simplified().isEmpty())
- snippet = QLatin1Char('\n') + snippet;
-
- editor->insert(snippet);
-}
-
-void QmakeManager::runQMake()
-{
- runQMakeImpl(SessionManager::startupProject(), nullptr);
-}
-
-void QmakeManager::runQMakeContextMenu()
-{
- runQMakeImpl(ProjectTree::currentProject(), ProjectTree::currentNode());
-}
-
-void QmakeManager::runQMakeImpl(ProjectExplorer::Project *p, ProjectExplorer::Node *node)
-{
- if (!ProjectExplorerPlugin::saveModifiedFiles())
- return;
- auto *qmakeProject = qobject_cast<QmakeProject *>(p);
- QTC_ASSERT(qmakeProject, return);
-
- if (!qmakeProject->activeTarget() || !qmakeProject->activeTarget()->activeBuildConfiguration())
- return;
-
- auto *bc = static_cast<QmakeBuildConfiguration *>(qmakeProject->activeTarget()->activeBuildConfiguration());
- QMakeStep *qs = bc->qmakeStep();
- if (!qs)
- return;
-
- //found qmakeStep, now use it
- qs->setForced(true);
-
- if (node && node != qmakeProject->rootProjectNode())
- if (auto *profile = dynamic_cast<QmakeProFileNode *>(node))
- bc->setSubNodeBuild(profile);
-
- BuildManager::appendStep(qs, tr("QMake"));
- bc->setSubNodeBuild(nullptr);
-}
-
-void QmakeManager::buildSubDirContextMenu()
-{
- handleSubDirContextMenu(BUILD, false);
-}
-
-void QmakeManager::cleanSubDirContextMenu()
-{
- handleSubDirContextMenu(CLEAN, false);
-}
-
-void QmakeManager::rebuildSubDirContextMenu()
-{
- handleSubDirContextMenu(REBUILD, false);
-}
-
-void QmakeManager::buildFileContextMenu()
-{
- handleSubDirContextMenu(BUILD, true);
-}
-
-void QmakeManager::buildFile()
-{
- if (Core::IDocument *currentDocument= Core::EditorManager::currentDocument()) {
- const Utils::FilePath file = currentDocument->filePath();
- Node *n = ProjectTree::nodeForFile(file);
- FileNode *node = n ? n->asFileNode() : nullptr;
- Project *project = SessionManager::projectForFile(file);
-
- if (project && node)
- handleSubDirContextMenu(BUILD, true, project, node->parentProjectNode(), node);
- }
-}
-
-void QmakeManager::buildProduct(Project *project, Node *proFileNode)
-{
- handleSubDirContextMenu(BUILD, false, project, proFileNode, nullptr);
-}
-
-void QmakeManager::handleSubDirContextMenu(QmakeManager::Action action, bool isFileBuild)
-{
- handleSubDirContextMenu(action,
- isFileBuild,
- ProjectTree::currentProject(),
- buildableFileProFile(ProjectTree::currentNode()),
- contextBuildableFileNode());
-}
-
-void QmakeManager::handleSubDirContextMenu(QmakeManager::Action action, bool isFileBuild,
- Project *contextProject, Node *contextNode,
- FileNode *buildableFile)
-{
- QTC_ASSERT(contextProject, return);
- Target *target = contextProject->activeTarget();
- if (!target)
- return;
-
- auto *bc = qobject_cast<QmakeBuildConfiguration *>(target->activeBuildConfiguration());
- if (!bc)
- return;
-
- if (!contextNode || !buildableFile)
- isFileBuild = false;
-
- if (auto *prifile = dynamic_cast<QmakePriFileNode *>(contextNode)) {
- if (QmakeProFileNode *profile = prifile->proFileNode()) {
- if (profile != contextProject->rootProjectNode() || isFileBuild)
- bc->setSubNodeBuild(profile->proFileNode());
- }
- }
-
- if (isFileBuild)
- bc->setFileNodeBuild(buildableFile);
- if (ProjectExplorerPlugin::saveModifiedFiles()) {
- const Core::Id buildStep = ProjectExplorer::Constants::BUILDSTEPS_BUILD;
- const Core::Id cleanStep = ProjectExplorer::Constants::BUILDSTEPS_CLEAN;
- if (action == BUILD) {
- BuildManager::buildList(bc->buildSteps());
- } else if (action == CLEAN) {
- BuildManager::buildList(bc->cleanSteps());
- } else if (action == REBUILD) {
- QStringList names;
- names << ProjectExplorerPlugin::displayNameForStepId(cleanStep)
- << ProjectExplorerPlugin::displayNameForStepId(buildStep);
-
- BuildManager::buildLists({bc->cleanSteps(), bc->buildSteps()}, names);
- }
- }
-
- bc->setSubNodeBuild(nullptr);
- bc->setFileNodeBuild(nullptr);
-}
-
-} // namespace QmakeProjectManager
diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectmanager.h b/src/plugins/qmakeprojectmanager/qmakeprojectmanager.h
deleted file mode 100644
index 722ab07577..0000000000
--- a/src/plugins/qmakeprojectmanager/qmakeprojectmanager.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qmakeprojectmanager_global.h"
-
-#include <projectexplorer/projectnodes.h>
-
-namespace Core { class IEditor; }
-namespace TextEditor { class BaseTextEditor; }
-
-namespace ProjectExplorer {
-class Project;
-class Node;
-class ToolChain;
-}
-
-namespace QmakeProjectManager {
-
-class QMAKEPROJECTMANAGER_EXPORT QmakeManager : public QObject
-{
- Q_OBJECT
-
-public:
- void notifyChanged(const Utils::FilePath &name);
-
- // Context information used in the slot implementations
- static ProjectExplorer::FileNode *contextBuildableFileNode();
-
- enum Action { BUILD, REBUILD, CLEAN };
-
- void addLibrary();
- void addLibraryContextMenu();
- void runQMake();
- void runQMakeContextMenu();
- void buildSubDirContextMenu();
- void rebuildSubDirContextMenu();
- void cleanSubDirContextMenu();
- void buildFileContextMenu();
- void buildFile();
-
- static void buildProduct(ProjectExplorer::Project *project, ProjectExplorer::Node *proFileNode);
-
-private:
- void handleSubDirContextMenu(Action action, bool isFileBuild);
- static void handleSubDirContextMenu(QmakeManager::Action action, bool isFileBuild,
- ProjectExplorer::Project *contextProject,
- ProjectExplorer::Node *contextProFileNode,
- ProjectExplorer::FileNode *buildableFile);
- void addLibraryImpl(const QString &fileName, TextEditor::BaseTextEditor *editor);
- void runQMakeImpl(ProjectExplorer::Project *p, ProjectExplorer::Node *node);
-};
-
-} // namespace QmakeProjectManager
diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectmanager.pro b/src/plugins/qmakeprojectmanager/qmakeprojectmanager.pro
index aa56251ada..90a6a78a8f 100644
--- a/src/plugins/qmakeprojectmanager/qmakeprojectmanager.pro
+++ b/src/plugins/qmakeprojectmanager/qmakeprojectmanager.pro
@@ -10,7 +10,6 @@ HEADERS += \
qmakeparsernodes.h \
qmakeprojectimporter.h \
qmakeprojectmanagerplugin.h \
- qmakeprojectmanager.h \
qmakeproject.h \
qmakesettings.h \
qmakenodes.h \
@@ -39,7 +38,6 @@ SOURCES += \
qmakeparsernodes.cpp \
qmakeprojectimporter.cpp \
qmakeprojectmanagerplugin.cpp \
- qmakeprojectmanager.cpp \
qmakeproject.cpp \
qmakenodes.cpp \
qmakesettings.cpp \
diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectmanager.qbs b/src/plugins/qmakeprojectmanager/qmakeprojectmanager.qbs
index 24a4fce431..e46f7c90b4 100644
--- a/src/plugins/qmakeprojectmanager/qmakeprojectmanager.qbs
+++ b/src/plugins/qmakeprojectmanager/qmakeprojectmanager.qbs
@@ -46,7 +46,6 @@ Project {
"qmakenodes.cpp", "qmakenodes.h",
"qmakenodetreebuilder.cpp", "qmakenodetreebuilder.h",
"qmakeproject.cpp", "qmakeproject.h",
- "qmakeprojectmanager.cpp", "qmakeprojectmanager.h",
"qmakeprojectmanager.qrc",
"qmakeprojectmanager_global.h",
"qmakeprojectmanagerconstants.h",
diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp b/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp
index 6ca690f6f0..7a896d4999 100644
--- a/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp
+++ b/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp
@@ -25,8 +25,8 @@
#include "qmakeprojectmanagerplugin.h"
+#include "addlibrarywizard.h"
#include "profileeditor.h"
-#include "qmakeprojectmanager.h"
#include "qmakenodes.h"
#include "qmakesettings.h"
#include "qmakestep.h"
@@ -49,12 +49,15 @@
#include <coreplugin/editormanager/ieditor.h>
#include <projectexplorer/buildmanager.h>
+#include <projectexplorer/projectnodes.h>
#include <projectexplorer/projectmanager.h>
#include <projectexplorer/projecttree.h>
#include <projectexplorer/runcontrol.h>
#include <projectexplorer/session.h>
#include <projectexplorer/target.h>
+#include <projectexplorer/projectexplorer.h>
+#include <texteditor/texteditor.h>
#include <texteditor/texteditoractionhandler.h>
#include <texteditor/texteditorconstants.h>
@@ -67,6 +70,7 @@
using namespace Core;
using namespace ProjectExplorer;
+using namespace TextEditor;
namespace QmakeProjectManager {
namespace Internal {
@@ -86,7 +90,6 @@ public:
void disableBuildFileMenus();
void enableBuildFileMenus(const Utils::FilePath &file);
- QmakeManager qmakeProjectManager;
Core::Context projectContext;
CustomWizardMetaFactory<CustomQmakeProjectWizard>
@@ -105,7 +108,7 @@ public:
ExternalQtEditor *m_linguistEditor{ExternalQtEditor::createLinguistEditor()};
QmakeProject *m_previousStartupProject = nullptr;
- ProjectExplorer::Target *m_previousTarget = nullptr;
+ Target *m_previousTarget = nullptr;
QAction *m_runQMakeAction = nullptr;
QAction *m_runQMakeActionContextMenu = nullptr;
@@ -122,6 +125,21 @@ public:
QAction *m_addLibraryActionContextMenu = nullptr;
QmakeKitAspect qmakeKitAspect;
+
+ void addLibrary();
+ void addLibraryContextMenu();
+ void runQMake();
+ void runQMakeContextMenu();
+
+ void buildSubDirContextMenu() { handleSubDirContextMenu(QmakeBuildSystem::BUILD, false); }
+ void rebuildSubDirContextMenu() { handleSubDirContextMenu(QmakeBuildSystem::REBUILD, false); }
+ void cleanSubDirContextMenu() { handleSubDirContextMenu(QmakeBuildSystem::CLEAN, false); }
+ void buildFileContextMenu() { handleSubDirContextMenu(QmakeBuildSystem::BUILD, true); }
+ void buildFile();
+
+ void handleSubDirContextMenu(QmakeBuildSystem::Action action, bool isFileBuild);
+ void addLibraryImpl(const QString &fileName, TextEditor::BaseTextEditor *editor);
+ void runQMakeImpl(Project *p, ProjectExplorer::Node *node);
};
QmakeProjectManagerPlugin::~QmakeProjectManagerPlugin()
@@ -170,7 +188,7 @@ bool QmakeProjectManagerPlugin::initialize(const QStringList &arguments, QString
command->setDescription(d->m_buildSubProjectContextMenu->text());
msubproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_BUILD);
connect(d->m_buildSubProjectContextMenu, &QAction::triggered,
- &d->qmakeProjectManager, &QmakeManager::buildSubDirContextMenu);
+ d, &QmakeProjectManagerPluginPrivate::buildSubDirContextMenu);
d->m_runQMakeActionContextMenu = new QAction(tr("Run qmake"), this);
command = ActionManager::registerAction(d->m_runQMakeActionContextMenu, Constants::RUNQMAKECONTEXTMENU, projectContext);
@@ -178,7 +196,7 @@ bool QmakeProjectManagerPlugin::initialize(const QStringList &arguments, QString
mproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_BUILD);
msubproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_BUILD);
connect(d->m_runQMakeActionContextMenu, &QAction::triggered,
- &d->qmakeProjectManager, &QmakeManager::runQMakeContextMenu);
+ d, &QmakeProjectManagerPluginPrivate::runQMakeContextMenu);
command = msubproject->addSeparator(projectContext, ProjectExplorer::Constants::G_PROJECT_BUILD,
&d->m_subProjectRebuildSeparator);
@@ -190,7 +208,7 @@ bool QmakeProjectManagerPlugin::initialize(const QStringList &arguments, QString
command->setAttribute(Command::CA_Hide);
msubproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_BUILD);
connect(d->m_rebuildSubProjectContextMenu, &QAction::triggered,
- &d->qmakeProjectManager, &QmakeManager::rebuildSubDirContextMenu);
+ d, &QmakeProjectManagerPluginPrivate::rebuildSubDirContextMenu);
d->m_cleanSubProjectContextMenu = new QAction(tr("Clean"), this);
command = ActionManager::registerAction(
@@ -198,14 +216,14 @@ bool QmakeProjectManagerPlugin::initialize(const QStringList &arguments, QString
command->setAttribute(Command::CA_Hide);
msubproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_BUILD);
connect(d->m_cleanSubProjectContextMenu, &QAction::triggered,
- &d->qmakeProjectManager, &QmakeManager::cleanSubDirContextMenu);
+ d, &QmakeProjectManagerPluginPrivate::cleanSubDirContextMenu);
d->m_buildFileContextMenu = new QAction(tr("Build"), this);
command = ActionManager::registerAction(d->m_buildFileContextMenu, Constants::BUILDFILECONTEXTMENU, projectContext);
command->setAttribute(Command::CA_Hide);
mfile->addAction(command, ProjectExplorer::Constants::G_FILE_OTHER);
connect(d->m_buildFileContextMenu, &QAction::triggered,
- &d->qmakeProjectManager, &QmakeManager::buildFileContextMenu);
+ d, &QmakeProjectManagerPluginPrivate::buildFileContextMenu);
d->m_buildSubProjectAction = new Utils::ParameterAction(tr("Build &Subproject"), tr("Build &Subproject \"%1\""),
Utils::ParameterAction::AlwaysEnabled, this);
@@ -215,13 +233,14 @@ bool QmakeProjectManagerPlugin::initialize(const QStringList &arguments, QString
command->setDescription(d->m_buildSubProjectAction->text());
mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_BUILD);
connect(d->m_buildSubProjectAction, &QAction::triggered,
- &d->qmakeProjectManager, &QmakeManager::buildSubDirContextMenu);
+ d, &QmakeProjectManagerPluginPrivate::buildSubDirContextMenu);
d->m_runQMakeAction = new QAction(tr("Run qmake"), this);
const Context globalcontext(Core::Constants::C_GLOBAL);
command = ActionManager::registerAction(d->m_runQMakeAction, Constants::RUNQMAKE, globalcontext);
mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_BUILD);
- connect(d->m_runQMakeAction, &QAction::triggered, &d->qmakeProjectManager, &QmakeManager::runQMake);
+ connect(d->m_runQMakeAction, &QAction::triggered,
+ d, &QmakeProjectManagerPluginPrivate::runQMake);
d->m_rebuildSubProjectAction = new Utils::ParameterAction(tr("Rebuild Subproject"), tr("Rebuild Subproject \"%1\""),
Utils::ParameterAction::AlwaysEnabled, this);
@@ -231,7 +250,7 @@ bool QmakeProjectManagerPlugin::initialize(const QStringList &arguments, QString
command->setDescription(d->m_rebuildSubProjectAction->text());
mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_REBUILD);
connect(d->m_rebuildSubProjectAction, &QAction::triggered,
- &d->qmakeProjectManager, &QmakeManager::rebuildSubDirContextMenu);
+ d, &QmakeProjectManagerPluginPrivate::rebuildSubDirContextMenu);
d->m_cleanSubProjectAction = new Utils::ParameterAction(tr("Clean Subproject"), tr("Clean Subproject \"%1\""),
Utils::ParameterAction::AlwaysEnabled, this);
@@ -241,7 +260,7 @@ bool QmakeProjectManagerPlugin::initialize(const QStringList &arguments, QString
command->setDescription(d->m_cleanSubProjectAction->text());
mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_CLEAN);
connect(d->m_cleanSubProjectAction, &QAction::triggered,
- &d->qmakeProjectManager, &QmakeManager::cleanSubDirContextMenu);
+ d, &QmakeProjectManagerPluginPrivate::cleanSubDirContextMenu);
d->m_buildFileAction = new Utils::ParameterAction(tr("Build File"), tr("Build File \"%1\""),
Utils::ParameterAction::AlwaysEnabled, this);
@@ -251,7 +270,8 @@ bool QmakeProjectManagerPlugin::initialize(const QStringList &arguments, QString
command->setDescription(d->m_buildFileAction->text());
command->setDefaultKeySequence(QKeySequence(tr("Ctrl+Alt+B")));
mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_BUILD);
- connect(d->m_buildFileAction, &QAction::triggered, &d->qmakeProjectManager, &QmakeManager::buildFile);
+ connect(d->m_buildFileAction, &QAction::triggered,
+ d, &QmakeProjectManagerPluginPrivate::buildFile);
connect(BuildManager::instance(), &BuildManager::buildStateChanged,
d, &QmakeProjectManagerPluginPrivate::buildStateChanged);
@@ -273,14 +293,15 @@ bool QmakeProjectManagerPlugin::initialize(const QStringList &arguments, QString
d->m_addLibraryAction = new QAction(tr("Add Library..."), this);
command = ActionManager::registerAction(d->m_addLibraryAction,
Constants::ADDLIBRARY, proFileEditorContext);
- connect(d->m_addLibraryAction, &QAction::triggered, &d->qmakeProjectManager, &QmakeManager::addLibrary);
+ connect(d->m_addLibraryAction, &QAction::triggered,
+ d, &QmakeProjectManagerPluginPrivate::addLibrary);
contextMenu->addAction(command);
d->m_addLibraryActionContextMenu = new QAction(tr("Add Library..."), this);
command = ActionManager::registerAction(d->m_addLibraryActionContextMenu,
Constants::ADDLIBRARY, projectTreeContext);
connect(d->m_addLibraryActionContextMenu, &QAction::triggered,
- &d->qmakeProjectManager, &QmakeManager::addLibraryContextMenu);
+ d, &QmakeProjectManagerPluginPrivate::addLibraryContextMenu);
mproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_FILES);
msubproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_FILES);
@@ -322,6 +343,137 @@ void QmakeProjectManagerPluginPrivate::projectChanged()
activeTargetChanged();
}
+static QmakeProFileNode *buildableFileProFile(Node *node)
+{
+ if (node) {
+ auto subPriFileNode = dynamic_cast<QmakePriFileNode *>(node);
+ if (!subPriFileNode)
+ subPriFileNode = dynamic_cast<QmakePriFileNode *>(node->parentProjectNode());
+ if (subPriFileNode)
+ return subPriFileNode->proFileNode();
+ }
+ return nullptr;
+}
+
+void QmakeProjectManagerPluginPrivate::addLibrary()
+{
+ if (auto editor = qobject_cast<BaseTextEditor *>(Core::EditorManager::currentEditor()))
+ addLibraryImpl(editor->document()->filePath().toString(), editor);
+}
+
+void QmakeProjectManagerPluginPrivate::addLibraryContextMenu()
+{
+ QString projectPath;
+
+ Node *node = ProjectTree::currentNode();
+ if (ContainerNode *cn = node->asContainerNode())
+ projectPath = cn->project()->projectFilePath().toString();
+ else if (dynamic_cast<QmakeProFileNode *>(node))
+ projectPath = node->filePath().toString();
+
+ addLibraryImpl(projectPath, nullptr);
+}
+
+void QmakeProjectManagerPluginPrivate::addLibraryImpl(const QString &fileName, BaseTextEditor *editor)
+{
+ if (fileName.isEmpty())
+ return;
+
+ Internal::AddLibraryWizard wizard(fileName, Core::ICore::dialogParent());
+ if (wizard.exec() != QDialog::Accepted)
+ return;
+
+ if (!editor)
+ editor = qobject_cast<BaseTextEditor *>(Core::EditorManager::openEditor(fileName,
+ Constants::PROFILE_EDITOR_ID, Core::EditorManager::DoNotMakeVisible));
+ if (!editor)
+ return;
+
+ const int endOfDoc = editor->position(EndOfDocPosition);
+ editor->setCursorPosition(endOfDoc);
+ QString snippet = wizard.snippet();
+
+ // add extra \n in case the last line is not empty
+ int line, column;
+ editor->convertPosition(endOfDoc, &line, &column);
+ const int positionInBlock = column - 1;
+ if (!editor->textAt(endOfDoc - positionInBlock, positionInBlock).simplified().isEmpty())
+ snippet = QLatin1Char('\n') + snippet;
+
+ editor->insert(snippet);
+}
+
+void QmakeProjectManagerPluginPrivate::runQMake()
+{
+ runQMakeImpl(SessionManager::startupProject(), nullptr);
+}
+
+void QmakeProjectManagerPluginPrivate::runQMakeContextMenu()
+{
+ runQMakeImpl(ProjectTree::currentProject(), ProjectTree::currentNode());
+}
+
+void QmakeProjectManagerPluginPrivate::runQMakeImpl(Project *p, Node *node)
+{
+ if (!ProjectExplorerPlugin::saveModifiedFiles())
+ return;
+ auto *qmakeProject = qobject_cast<QmakeProject *>(p);
+ QTC_ASSERT(qmakeProject, return);
+
+ if (!qmakeProject->activeTarget() || !qmakeProject->activeTarget()->activeBuildConfiguration())
+ return;
+
+ auto *bc = static_cast<QmakeBuildConfiguration *>(qmakeProject->activeTarget()->activeBuildConfiguration());
+ QMakeStep *qs = bc->qmakeStep();
+ if (!qs)
+ return;
+
+ //found qmakeStep, now use it
+ qs->setForced(true);
+
+ if (node && node != qmakeProject->rootProjectNode())
+ if (auto *profile = dynamic_cast<QmakeProFileNode *>(node))
+ bc->setSubNodeBuild(profile);
+
+ BuildManager::appendStep(qs, tr("QMake"));
+ bc->setSubNodeBuild(nullptr);
+}
+
+void QmakeProjectManagerPluginPrivate::buildFile()
+{
+ Core::IDocument *currentDocument = Core::EditorManager::currentDocument();
+ if (!currentDocument)
+ return;
+
+ const Utils::FilePath file = currentDocument->filePath();
+ Node *n = ProjectTree::nodeForFile(file);
+ FileNode *node = n ? n->asFileNode() : nullptr;
+ if (!node)
+ return;
+ Project *project = SessionManager::projectForFile(file);
+ if (!project)
+ return;
+ Target *target = project->activeTarget();
+ if (!target)
+ return;
+
+ if (auto bs = qobject_cast<QmakeBuildSystem *>(target->buildSystem()))
+ bs->buildHelper(QmakeBuildSystem::BUILD, true, buildableFileProFile(node), node);
+}
+
+void QmakeProjectManagerPluginPrivate::handleSubDirContextMenu(QmakeBuildSystem::Action action, bool isFileBuild)
+{
+ Node *node = ProjectTree::currentNode();
+
+ QmakeProFileNode *subProjectNode = buildableFileProFile(node);
+ FileNode *fileNode = node ? node->asFileNode() : nullptr;
+ bool buildFilePossible = subProjectNode && fileNode && fileNode->fileType() == FileType::Source;
+ FileNode *buildableFileNode = buildFilePossible ? fileNode : nullptr;
+
+ if (auto bs = qobject_cast<QmakeBuildSystem *>(ProjectTree::currentBuildSystem()))
+ bs->buildHelper(action, isFileBuild, subProjectNode, buildableFileNode);
+}
+
void QmakeProjectManagerPluginPrivate::activeTargetChanged()
{
if (m_previousTarget)
diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.h b/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.h
index 5b3176b9b7..68255197dd 100644
--- a/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.h
+++ b/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.h
@@ -27,7 +27,12 @@
#include <extensionsystem/iplugin.h>
+namespace ProjectExplorer { class Project; }
+
namespace QmakeProjectManager {
+
+class QmakeProFileNode;
+
namespace Internal {
class QmakeProjectManagerPlugin final : public ExtensionSystem::IPlugin
diff --git a/src/plugins/qmakeprojectmanager/qmakestep.cpp b/src/plugins/qmakeprojectmanager/qmakestep.cpp
index 4a55e66383..424e12f543 100644
--- a/src/plugins/qmakeprojectmanager/qmakestep.cpp
+++ b/src/plugins/qmakeprojectmanager/qmakestep.cpp
@@ -142,16 +142,14 @@ QString QMakeStep::allArguments(const BaseQtVersion *v, ArgumentFlags flags) con
QMakeStepConfig QMakeStep::deducedArguments() const
{
- ProjectExplorer::Kit *kit = target()->kit();
+ Kit *kit = target()->kit();
QMakeStepConfig config;
- ProjectExplorer::ToolChain *tc
- = ProjectExplorer::ToolChainKitAspect::toolChain(kit, ProjectExplorer::Constants::CXX_LANGUAGE_ID);
- ProjectExplorer::Abi targetAbi;
- if (tc) {
+ Abi targetAbi;
+ if (ToolChain *tc = ToolChainKitAspect::cxxToolChain(kit)) {
targetAbi = tc->targetAbi();
if (HostOsInfo::isWindowsHost()
&& tc->typeId() == ProjectExplorer::Constants::CLANG_TOOLCHAIN_TYPEID) {
- config.sysRoot = ProjectExplorer::SysRootKitAspect::sysRoot(kit).toString();
+ config.sysRoot = SysRootKitAspect::sysRoot(kit).toString();
config.targetTriple = tc->originalTargetTriple();
}
}
@@ -181,7 +179,7 @@ bool QMakeStep::init()
FilePath workingDirectory;
if (qmakeBc->subNodeBuild())
- workingDirectory = qmakeBc->subNodeBuild()->buildDir(qmakeBc);
+ workingDirectory = qmakeBc->qmakeBuildSystem()->buildDir(qmakeBc->subNodeBuild()->filePath());
else
workingDirectory = qmakeBc->buildDirectory();
@@ -227,8 +225,6 @@ bool QMakeStep::init()
pp->setWorkingDirectory(workingDirectory);
pp->setEnvironment(qmakeBc->environment());
- setOutputParser(new QMakeParser);
-
QmakeProFileNode *node = static_cast<QmakeProFileNode *>(qmakeBc->project()->rootProjectNode());
if (qmakeBc->subNodeBuild())
node = qmakeBc->subNodeBuild();
@@ -256,6 +252,13 @@ bool QMakeStep::init()
return AbstractProcessStep::init();
}
+void QMakeStep::setupOutputFormatter(OutputFormatter *formatter)
+{
+ formatter->addLineParser(new QMakeParser);
+ m_outputFormatter = formatter;
+ AbstractProcessStep::setupOutputFormatter(formatter);
+}
+
void QMakeStep::doRun()
{
if (m_scriptTemplate) {
@@ -334,15 +337,15 @@ void QMakeStep::runNextCommand()
case State::IDLE:
return;
case State::RUN_QMAKE:
- setOutputParser(new QMakeParser);
+ m_outputFormatter->setLineParsers({new QMakeParser});
m_nextState = (m_runMakeQmake ? State::RUN_MAKE_QMAKE_ALL : State::POST_PROCESS);
startOneCommand(m_qmakeCommand);
return;
case State::RUN_MAKE_QMAKE_ALL:
{
auto *parser = new GnuMakeParser;
- parser->setWorkingDirectory(processParameters()->workingDirectory().toString());
- setOutputParser(parser);
+ parser->addSearchDir(processParameters()->workingDirectory());
+ m_outputFormatter->setLineParsers({parser});
m_nextState = State::POST_PROCESS;
startOneCommand(m_makeCommand);
}
@@ -584,14 +587,8 @@ QMakeStepConfigWidget::QMakeStepConfigWidget(QMakeStep *step)
connect(step->target(), &Target::kitChanged, this, &QMakeStepConfigWidget::qtVersionChanged);
connect(abisListWidget, &QListWidget::itemChanged, this, [this]{
abisChanged();
- QmakeBuildConfiguration *bc = m_step->qmakeBuildConfiguration();
- if (!bc)
- return;
-
- QList<ProjectExplorer::BuildStepList *> stepLists;
- const Core::Id clean = ProjectExplorer::Constants::BUILDSTEPS_CLEAN;
- stepLists << bc->cleanSteps();
- BuildManager::buildLists(stepLists, {ProjectExplorerPlugin::displayNameForStepId(clean)});
+ if (QmakeBuildConfiguration *bc = m_step->qmakeBuildConfiguration())
+ BuildManager::buildLists({bc->cleanSteps()});
});
auto chooser = new Core::VariableChooser(qmakeAdditonalArgumentsLineEdit);
chooser->addMacroExpanderProvider([step] { return step->macroExpander(); });
@@ -779,15 +776,8 @@ void QMakeStepConfigWidget::updateEffectiveQMakeCall()
void QMakeStepConfigWidget::recompileMessageBoxFinished(int button)
{
if (button == QMessageBox::Yes) {
- BuildConfiguration *bc = m_step->buildConfiguration();
- if (!bc)
- return;
-
- const Core::Id clean = ProjectExplorer::Constants::BUILDSTEPS_CLEAN;
- const Core::Id build = ProjectExplorer::Constants::BUILDSTEPS_BUILD;
- BuildManager::buildLists({bc->cleanSteps(), bc->buildSteps()},
- QStringList() << ProjectExplorerPlugin::displayNameForStepId(clean)
- << ProjectExplorerPlugin::displayNameForStepId(build));
+ if (BuildConfiguration *bc = m_step->buildConfiguration())
+ BuildManager::buildLists({bc->cleanSteps(), bc->buildSteps()});
}
}
diff --git a/src/plugins/qmakeprojectmanager/qmakestep.h b/src/plugins/qmakeprojectmanager/qmakestep.h
index 6475757e16..05710e1083 100644
--- a/src/plugins/qmakeprojectmanager/qmakestep.h
+++ b/src/plugins/qmakeprojectmanager/qmakestep.h
@@ -121,6 +121,7 @@ public:
QmakeBuildConfiguration *qmakeBuildConfiguration() const;
QmakeBuildSystem *qmakeBuildSystem() const;
bool init() override;
+ void setupOutputFormatter(Utils::OutputFormatter *formatter) override;
void doRun() override;
ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override;
void setForced(bool b);
@@ -192,6 +193,7 @@ private:
bool m_runMakeQmake = false;
bool m_scriptTemplate = false;
QStringList m_selectedAbis;
+ Utils::OutputFormatter *m_outputFormatter = nullptr;
};
diff --git a/src/plugins/qmakeprojectmanager/wizards/qtwizard.cpp b/src/plugins/qmakeprojectmanager/wizards/qtwizard.cpp
index 38074cb0c6..f9d66de3ed 100644
--- a/src/plugins/qmakeprojectmanager/wizards/qtwizard.cpp
+++ b/src/plugins/qmakeprojectmanager/wizards/qtwizard.cpp
@@ -26,7 +26,6 @@
#include "qtwizard.h"
#include <qmakeprojectmanager/qmakeproject.h>
-#include <qmakeprojectmanager/qmakeprojectmanager.h>
#include <qmakeprojectmanager/qmakeprojectmanagerconstants.h>
#include <coreplugin/icore.h>
diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt
index 9c32da72c4..d68085cdfc 100644
--- a/src/plugins/qmldesigner/CMakeLists.txt
+++ b/src/plugins/qmldesigner/CMakeLists.txt
@@ -247,6 +247,7 @@ extend_qtc_plugin(QmlDesigner
snapper.cpp snapper.h
snappinglinecreator.cpp snappinglinecreator.h
toolbox.cpp toolbox.h
+ transitiontool.cpp transitiontool.h
)
extend_qtc_plugin(QmlDesigner
@@ -558,6 +559,7 @@ extend_qtc_plugin(QmlDesigner
annotationeditordialog.cpp annotationeditordialog.h annotationeditordialog.ui
annotationeditor.cpp annotationeditor.h
annotationtool.cpp annotationtool.h
+ globalannotationeditor.cpp globalannotationeditor.h
)
extend_qtc_plugin(QmlDesigner
@@ -592,6 +594,13 @@ extend_qtc_plugin(QmlDesigner
)
extend_qtc_plugin(QmlDesigner
+ SOURCES_PREFIX components/richtexteditor
+ SOURCES
+ hyperlinkdialog.cpp hyperlinkdialog.h hyperlinkdialog.ui
+ richtexteditor.cpp richtexteditor.h hyperlinkdialog.ui
+)
+
+extend_qtc_plugin(QmlDesigner
SOURCES_PREFIX components/timelineeditor
SOURCES
animationcurvedialog.cpp animationcurvedialog.h
diff --git a/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.cpp b/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.cpp
index bd7aed67d0..bfe18e952b 100644
--- a/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.cpp
+++ b/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.cpp
@@ -26,6 +26,8 @@
#include "annotationcommenttab.h"
#include "ui_annotationcommenttab.h"
+#include "richtexteditor/richtexteditor.h"
+
namespace QmlDesigner {
AnnotationCommentTab::AnnotationCommentTab(QWidget *parent) :
@@ -34,6 +36,9 @@ AnnotationCommentTab::AnnotationCommentTab(QWidget *parent) :
{
ui->setupUi(this);
+ m_editor = new RichTextEditor;
+ ui->formLayout->setWidget(3, QFormLayout::FieldRole, m_editor);
+
connect(ui->titleEdit, &QLineEdit::textEdited,
this, &AnnotationCommentTab::commentTitleChanged);
}
@@ -49,7 +54,7 @@ Comment AnnotationCommentTab::currentComment() const
result.setTitle(ui->titleEdit->text().trimmed());
result.setAuthor(ui->authorEdit->text().trimmed());
- result.setText(ui->textEdit->toPlainText().trimmed());
+ result.setText(m_editor->richText().trimmed());
if (m_comment.sameContent(result))
result.setTimestamp(m_comment.timestamp());
@@ -74,7 +79,7 @@ void AnnotationCommentTab::resetUI()
{
ui->titleEdit->setText(m_comment.title());
ui->authorEdit->setText(m_comment.author());
- ui->textEdit->setText(m_comment.text());
+ m_editor->setRichText(m_comment.text());
if (m_comment.timestamp() > 0)
ui->timeLabel->setText(m_comment.timestampStr());
diff --git a/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.h b/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.h
index cc8d4c3d76..55fcf6ff1e 100644
--- a/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.h
+++ b/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.h
@@ -35,6 +35,8 @@ namespace Ui {
class AnnotationCommentTab;
}
+class RichTextEditor;
+
class AnnotationCommentTab : public QWidget
{
Q_OBJECT
@@ -59,6 +61,7 @@ private slots:
private:
Ui::AnnotationCommentTab *ui;
+ RichTextEditor *m_editor;
Comment m_comment;
};
diff --git a/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.ui b/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.ui
index f6bf277eb7..4a69703d57 100644
--- a/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.ui
+++ b/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.ui
@@ -33,13 +33,6 @@
</property>
</widget>
</item>
- <item row="3" column="1">
- <widget class="QTextEdit" name="textEdit">
- <property name="tabChangesFocus">
- <bool>true</bool>
- </property>
- </widget>
- </item>
<item row="2" column="0">
<widget class="QLabel" name="authorLabel">
<property name="text">
@@ -64,7 +57,6 @@
<tabstops>
<tabstop>titleEdit</tabstop>
<tabstop>authorEdit</tabstop>
- <tabstop>textEdit</tabstop>
</tabstops>
<resources/>
<connections/>
diff --git a/src/plugins/qmldesigner/components/annotationeditor/annotationeditor.cpp b/src/plugins/qmldesigner/components/annotationeditor/annotationeditor.cpp
index 10b6876949..c119dfdca1 100644
--- a/src/plugins/qmldesigner/components/annotationeditor/annotationeditor.cpp
+++ b/src/plugins/qmldesigner/components/annotationeditor/annotationeditor.cpp
@@ -138,14 +138,16 @@ void AnnotationEditor::removeFullAnnotation()
if (!m_modelNode.customId().isNull()) {
dialogTitle = m_modelNode.customId();
}
- QMessageBox *deleteDialog = new QMessageBox(Core::ICore::dialogParent());
+ QPointer<QMessageBox> deleteDialog = new QMessageBox(Core::ICore::dialogParent());
deleteDialog->setWindowTitle(dialogTitle);
deleteDialog->setText(tr("Delete this annotation?"));
deleteDialog->setStandardButtons(QMessageBox::Yes | QMessageBox::No);
deleteDialog->setDefaultButton(QMessageBox::Yes);
int result = deleteDialog->exec();
- if (deleteDialog) deleteDialog->deleteLater();
+
+ if (deleteDialog)
+ deleteDialog->deleteLater();
if (result == QMessageBox::Yes) {
m_modelNode.removeCustomId();
diff --git a/src/plugins/qmldesigner/components/annotationeditor/annotationeditor.pri b/src/plugins/qmldesigner/components/annotationeditor/annotationeditor.pri
index e221b3bb61..9a3a00e2da 100644
--- a/src/plugins/qmldesigner/components/annotationeditor/annotationeditor.pri
+++ b/src/plugins/qmldesigner/components/annotationeditor/annotationeditor.pri
@@ -2,11 +2,13 @@ HEADERS += $$PWD/annotationtool.h
HEADERS += $$PWD/annotationcommenttab.h
HEADERS += $$PWD/annotationeditordialog.h
HEADERS += $$PWD/annotationeditor.h
+HEADERS += $$PWD/globalannotationeditor.h
SOURCES += $$PWD/annotationtool.cpp
SOURCES += $$PWD/annotationcommenttab.cpp
SOURCES += $$PWD/annotationeditordialog.cpp
SOURCES += $$PWD/annotationeditor.cpp
+SOURCES += $$PWD/globalannotationeditor.cpp
FORMS += $$PWD/annotationcommenttab.ui
FORMS += $$PWD/annotationeditordialog.ui
diff --git a/src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.cpp b/src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.cpp
index dd234a074c..a25d93b666 100644
--- a/src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.cpp
+++ b/src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.cpp
@@ -40,16 +40,16 @@
namespace QmlDesigner {
-AnnotationEditorDialog::AnnotationEditorDialog(QWidget *parent, const QString &targetId, const QString &customId, const Annotation &annotation)
+AnnotationEditorDialog::AnnotationEditorDialog(QWidget *parent, const QString &targetId, const QString &customId, const Annotation &annotation, EditorMode mode)
: QDialog(parent)
, ui(new Ui::AnnotationEditorDialog)
, m_customId(customId)
, m_annotation(annotation)
+ , m_editorMode(mode)
{
ui->setupUi(this);
setWindowFlag(Qt::Tool, true);
- setWindowTitle(titleString);
setModal(true);
connect(this, &QDialog::accepted, this, &AnnotationEditorDialog::acceptedClicked);
@@ -98,6 +98,7 @@ AnnotationEditorDialog::AnnotationEditorDialog(QWidget *parent, const QString &t
ui->tabWidget->setCornerWidget(commentCornerWidget, Qt::TopRightCorner);
ui->targetIdEdit->setText(targetId);
+ changeEditorMode(m_editorMode);
fillFields();
}
@@ -128,6 +129,39 @@ QString AnnotationEditorDialog::customId() const
return m_customId;
}
+void AnnotationEditorDialog::changeEditorMode(AnnotationEditorDialog::EditorMode mode)
+{
+ switch (mode) {
+ case ItemAnnotation: {
+ ui->customIdEdit->setVisible(true);
+ ui->customIdLabel->setVisible(true);
+ ui->targetIdEdit->setVisible(true);
+ ui->targetIdLabel->setVisible(true);
+ setWindowTitle(annotationEditorTitle);
+
+ break;
+ }
+ case GlobalAnnotation: {
+ ui->customIdEdit->clear();
+ ui->targetIdEdit->clear();
+ ui->customIdEdit->setVisible(false);
+ ui->customIdLabel->setVisible(false);
+ ui->targetIdEdit->setVisible(false);
+ ui->targetIdLabel->setVisible(false);
+ setWindowTitle(globalEditorTitle);
+
+ break;
+ }
+ }
+
+ m_editorMode = mode;
+}
+
+AnnotationEditorDialog::EditorMode AnnotationEditorDialog::editorMode() const
+{
+ return m_editorMode;
+}
+
void AnnotationEditorDialog::acceptedClicked()
{
m_customId = ui->customIdEdit->text();
diff --git a/src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.h b/src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.h
index 1324115a72..0c3cb50c80 100644
--- a/src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.h
+++ b/src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.h
@@ -40,7 +40,10 @@ class AnnotationEditorDialog : public QDialog
Q_OBJECT
public:
- explicit AnnotationEditorDialog(QWidget *parent, const QString &targetId, const QString &customId, const Annotation &annotation);
+ enum EditorMode { ItemAnnotation, GlobalAnnotation };
+
+ explicit AnnotationEditorDialog(QWidget *parent, const QString &targetId, const QString &customId, const Annotation &annotation,
+ EditorMode mode = EditorMode::ItemAnnotation);
~AnnotationEditorDialog();
void setAnnotation(const Annotation &annotation);
@@ -49,6 +52,9 @@ public:
void setCustomId(const QString &customId);
QString customId() const;
+ void changeEditorMode(EditorMode mode);
+ EditorMode editorMode() const;
+
signals:
void accepted();
@@ -68,12 +74,15 @@ private:
void deleteAllTabs();
private:
- const QString titleString = {tr("Annotation Editor")};
+ const QString annotationEditorTitle = {tr("Annotation Editor")};
+ const QString globalEditorTitle = {tr("Global Annotation Editor")};
const QString defaultTabName = {tr("Annotation")};
Ui::AnnotationEditorDialog *ui;
QString m_customId;
Annotation m_annotation;
+
+ EditorMode m_editorMode;
};
} //namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.ui b/src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.ui
index 8ca9b75136..93ce92b045 100644
--- a/src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.ui
+++ b/src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.ui
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
- <width>700</width>
- <height>487</height>
+ <width>1100</width>
+ <height>600</height>
</rect>
</property>
<property name="windowTitle">
diff --git a/src/plugins/qmldesigner/components/annotationeditor/globalannotationeditor.cpp b/src/plugins/qmldesigner/components/annotationeditor/globalannotationeditor.cpp
new file mode 100644
index 0000000000..1beeacaf74
--- /dev/null
+++ b/src/plugins/qmldesigner/components/annotationeditor/globalannotationeditor.cpp
@@ -0,0 +1,148 @@
+/****************************************************************************
+**
+** 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 "globalannotationeditor.h"
+
+#include "annotationeditordialog.h"
+#include "annotation.h"
+
+#include "qmlmodelnodeproxy.h"
+#include <coreplugin/icore.h>
+
+#include <QObject>
+#include <QToolBar>
+#include <QAction>
+#include <QMessageBox>
+
+namespace QmlDesigner {
+
+GlobalAnnotationEditor::GlobalAnnotationEditor(QObject *)
+{
+}
+
+GlobalAnnotationEditor::~GlobalAnnotationEditor()
+{
+ hideWidget();
+}
+
+void GlobalAnnotationEditor::showWidget()
+{
+ m_dialog = new AnnotationEditorDialog(Core::ICore::dialogParent(),
+ modelNode().validId(),
+ "",
+ modelNode().globalAnnotation(),
+ AnnotationEditorDialog::EditorMode::GlobalAnnotation);
+
+ QObject::connect(m_dialog, &AnnotationEditorDialog::accepted,
+ this, &GlobalAnnotationEditor::acceptedClicked);
+ QObject::connect(m_dialog, &AnnotationEditorDialog::rejected,
+ this, &GlobalAnnotationEditor::cancelClicked);
+
+ m_dialog->setAttribute(Qt::WA_DeleteOnClose);
+
+ m_dialog->show();
+ m_dialog->raise();
+}
+
+void GlobalAnnotationEditor::showWidget(int x, int y)
+{
+ showWidget();
+ m_dialog->move(x, y);
+}
+
+void GlobalAnnotationEditor::hideWidget()
+{
+ if (m_dialog)
+ m_dialog->close();
+ m_dialog = nullptr;
+}
+
+void GlobalAnnotationEditor::setModelNode(const ModelNode &modelNode)
+{
+ m_modelNode = modelNode;
+}
+
+ModelNode GlobalAnnotationEditor::modelNode() const
+{
+ return m_modelNode;
+}
+
+bool GlobalAnnotationEditor::hasAnnotation() const
+{
+ if (m_modelNode.isValid())
+ return m_modelNode.hasGlobalAnnotation();
+ return false;
+}
+
+void GlobalAnnotationEditor::removeFullAnnotation()
+{
+ if (!m_modelNode.isValid())
+ return;
+
+ QString dialogTitle = tr("Global Annotation");
+ QMessageBox *deleteDialog = new QMessageBox(Core::ICore::dialogParent());
+ deleteDialog->setWindowTitle(dialogTitle);
+ deleteDialog->setText(tr("Delete this annotation?"));
+ deleteDialog->setStandardButtons(QMessageBox::Yes | QMessageBox::No);
+ deleteDialog->setDefaultButton(QMessageBox::Yes);
+
+ int result = deleteDialog->exec();
+ if (deleteDialog) deleteDialog->deleteLater();
+
+ if (result == QMessageBox::Yes) {
+ m_modelNode.removeGlobalAnnotation();
+ }
+
+ emit annotationChanged();
+}
+
+void GlobalAnnotationEditor::acceptedClicked()
+{
+ if (m_dialog) {
+ Annotation annotation = m_dialog->annotation();
+
+ if (annotation.comments().isEmpty())
+ m_modelNode.removeGlobalAnnotation();
+ else
+ m_modelNode.setGlobalAnnotation(annotation);
+ }
+
+ hideWidget();
+
+ emit accepted();
+
+ emit annotationChanged();
+}
+
+void GlobalAnnotationEditor::cancelClicked()
+{
+ hideWidget();
+
+ emit canceled();
+
+ emit annotationChanged();
+}
+
+} //namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/annotationeditor/globalannotationeditor.h b/src/plugins/qmldesigner/components/annotationeditor/globalannotationeditor.h
new file mode 100644
index 0000000000..e0aa66a119
--- /dev/null
+++ b/src/plugins/qmldesigner/components/annotationeditor/globalannotationeditor.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** 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 <QObject>
+#include <QtQml>
+#include <QPointer>
+
+#include "annotationeditordialog.h"
+#include "annotation.h"
+
+#include "modelnode.h"
+
+namespace QmlDesigner {
+
+class GlobalAnnotationEditor : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit GlobalAnnotationEditor(QObject *parent = nullptr);
+ ~GlobalAnnotationEditor();
+
+ Q_INVOKABLE void showWidget();
+ Q_INVOKABLE void showWidget(int x, int y);
+ Q_INVOKABLE void hideWidget();
+
+ void setModelNode(const ModelNode &modelNode);
+ ModelNode modelNode() const;
+
+ Q_INVOKABLE bool hasAnnotation() const;
+
+ Q_INVOKABLE void removeFullAnnotation();
+
+signals:
+ void accepted();
+ void canceled();
+ void modelNodeBackendChanged();
+
+ void annotationChanged();
+
+private slots:
+ void acceptedClicked();
+ void cancelClicked();
+
+private:
+ QPointer<AnnotationEditorDialog> m_dialog;
+
+ ModelNode m_modelNode;
+};
+
+} //namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/componentcore/componentcore_constants.h b/src/plugins/qmldesigner/components/componentcore/componentcore_constants.h
index 2965bcd90b..c0f7af85c2 100644
--- a/src/plugins/qmldesigner/components/componentcore/componentcore_constants.h
+++ b/src/plugins/qmldesigner/components/componentcore/componentcore_constants.h
@@ -41,6 +41,7 @@ const char anchorsCategory[] = "Anchors";
const char positionCategory[] = "Position";
const char layoutCategory[] = "Layout";
const char flowCategory[] = "Flow";
+const char flowEffectCategory[] = "FlowEffect";
const char flowConnectionCategory[] = "FlowConnection";
const char stackedContainerCategory[] = "StackedContainer";
const char genericToolBarCategory[] = "GenericToolBar";
@@ -57,6 +58,7 @@ const char anchorsFillCommandId[] = "AnchorsFill";
const char anchorsResetCommandId[] = "AnchorsReset";
const char removePositionerCommandId[] = "RemovePositioner";
const char createFlowActionAreaCommandId[] = "CreateFlowActionArea";
+const char setFlowStartCommandId[] = "SetFlowStart";
const char layoutRowPositionerCommandId[] = "LayoutRowPositioner";
const char layoutColumnPositionerCommandId[] = "LayoutColumnPositioner";
const char layoutGridPositionerCommandId[] = "LayoutGridPositioner";
@@ -85,6 +87,7 @@ const char anchorsCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextM
const char positionCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Position");
const char layoutCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Layout");
const char flowCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Flow");
+const char flowEffectCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Flow Effects");
const char stackedContainerCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Stacked Container");
const char cutSelectionDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Cut");
@@ -124,6 +127,7 @@ const char layoutGridPositionerDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerCon
const char layoutFlowPositionerDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Position in Flow");
const char removePositionerDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Remove Positioner");
const char createFlowActionAreaDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Create Flow Action");
+const char setFlowStartDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Set Flow Start");
const char removeLayoutDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Remove Layout");
const char addItemToStackedContainerDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Add Item");
diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp
index 42f95952db..cf3fb5e152 100644
--- a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp
@@ -346,6 +346,12 @@ bool isFlowItem(const SelectionContext &context)
&& QmlFlowItemNode::isValidQmlFlowItemNode(context.currentSingleSelectedNode());
}
+bool isFlowTarget(const SelectionContext &context)
+{
+ return context.singleNodeIsSelected()
+ && QmlFlowTargetNode::isFlowEditorTarget(context.currentSingleSelectedNode());
+}
+
bool isFlowTransitionItem(const SelectionContext &context)
{
return context.singleNodeIsSelected()
@@ -362,9 +368,9 @@ bool isFlowActionItemItem(const SelectionContext &context)
|| QmlVisualNode::isFlowWildcard(selectedNode));
}
-bool isFlowItemOrTransition(const SelectionContext &context)
+bool isFlowTargetOrTransition(const SelectionContext &context)
{
- return isFlowItem(context) || isFlowTransitionItem(context);
+ return isFlowTarget(context) || isFlowTransitionItem(context);
}
class FlowActionConnectAction : public ActionGroup
@@ -853,15 +859,24 @@ void DesignerActionManager::createDefaultDesignerActions()
priorityLayoutCategory,
&layoutOptionVisible));
- //isFlowTransitionItem
-
addDesignerAction(new ActionGroup(
flowCategoryDisplayName,
flowCategory,
priorityFlowCategory,
- &isFlowItemOrTransition,
+ &isFlowTargetOrTransition,
&flowOptionVisible));
+
+ auto effectMenu = new ActionGroup(
+ flowEffectCategoryDisplayName,
+ flowEffectCategory,
+ priorityFlowCategory,
+ &isFlowTransitionItem,
+ &flowOptionVisible);
+
+ effectMenu->setCategory(flowCategory);
+ addDesignerAction(effectMenu);
+
addDesignerAction(new ModelNodeFormEditorAction(
createFlowActionAreaCommandId,
createFlowActionAreaDisplayName,
@@ -874,6 +889,17 @@ void DesignerActionManager::createDefaultDesignerActions()
&isFlowItem,
&flowOptionVisible));
+ addDesignerAction(new ModelNodeContextMenuAction(
+ setFlowStartCommandId,
+ setFlowStartDisplayName,
+ {},
+ flowCategory,
+ priorityFirst,
+ {},
+ &setFlowStartItem,
+ &isFlowItem,
+ &flowOptionVisible));
+
addDesignerAction(new FlowActionConnectAction(
flowConnectionCategoryDisplayName,
flowConnectionCategory,
@@ -1175,7 +1201,7 @@ void DesignerActionManager::addTransitionEffectAction(const TypeName &typeName)
QByteArray(ComponentCoreConstants::flowAssignEffectCommandId) + typeName,
QLatin1String(ComponentCoreConstants::flowAssignEffectDisplayName) + typeName,
{},
- ComponentCoreConstants::flowCategory,
+ ComponentCoreConstants::flowEffectCategory,
{},
typeName == "None" ? 100 : 140,
[typeName](const SelectionContext &context)
diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.h b/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.h
index 67a53ef997..59029400e5 100644
--- a/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.h
+++ b/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.h
@@ -132,16 +132,22 @@ public:
bool isVisible(const SelectionContext &m_selectionState) const override { return m_visibility(m_selectionState); }
bool isEnabled(const SelectionContext &m_selectionState) const override { return m_enabled(m_selectionState); }
- QByteArray category() const override { return QByteArray(); }
+ QByteArray category() const override { return m_category; }
QByteArray menuId() const override { return m_menuId; }
int priority() const override { return m_priority; }
Type type() const override { return ContextMenu; }
+ void setCategory(const QByteArray &catageoryId)
+ {
+ m_category = catageoryId;
+ }
+
private:
const QByteArray m_menuId;
const int m_priority;
SelectionContextPredicate m_enabled;
SelectionContextPredicate m_visibility;
+ QByteArray m_category;
};
class SeperatorDesignerAction : public AbstractAction
diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp
index 2c239a8aa9..cf148776de 100644
--- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp
@@ -77,22 +77,6 @@ namespace QmlDesigner {
const PropertyName auxDataString("anchors_");
-static inline QList<QmlItemNode> siblingsForNode(const QmlItemNode &itemNode)
-{
- QList<QmlItemNode> siblingList;
-
- if (itemNode.isValid() && itemNode.modelNode().hasParentProperty()) {
- QList<ModelNode> modelNodes = itemNode.modelNode().parentProperty().parentModelNode().directSubModelNodes();
- foreach (const ModelNode &node, modelNodes) {
- QmlItemNode childItemNode = node;
- if (childItemNode.isValid())
- siblingList.append(childItemNode);
- }
- }
-
- return siblingList;
-}
-
static inline void reparentTo(const ModelNode &node, const QmlItemNode &parent)
{
@@ -311,8 +295,10 @@ void resetSize(const SelectionContext &selectionState)
selectionState.view()->executeInTransaction("DesignerActionManager|resetSize",[selectionState](){
foreach (ModelNode node, selectionState.selectedModelNodes()) {
QmlItemNode itemNode(node);
- itemNode.removeProperty("width");
- itemNode.removeProperty("height");
+ if (itemNode.isValid()) {
+ itemNode.removeProperty("width");
+ itemNode.removeProperty("height");
+ }
}
});
}
@@ -325,8 +311,10 @@ void resetPosition(const SelectionContext &selectionState)
selectionState.view()->executeInTransaction("DesignerActionManager|resetPosition",[selectionState](){
foreach (ModelNode node, selectionState.selectedModelNodes()) {
QmlItemNode itemNode(node);
- itemNode.removeProperty("x");
- itemNode.removeProperty("y");
+ if (itemNode.isValid()) {
+ itemNode.removeProperty("x");
+ itemNode.removeProperty("y");
+ }
}
});
}
@@ -348,7 +336,8 @@ void resetZ(const SelectionContext &selectionState)
selectionState.view()->executeInTransaction("DesignerActionManager|resetZ",[selectionState](){
foreach (ModelNode node, selectionState.selectedModelNodes()) {
QmlItemNode itemNode(node);
- itemNode.removeProperty("z");
+ if (itemNode.isValid())
+ itemNode.removeProperty("z");
}
});
}
@@ -1061,7 +1050,7 @@ void addTransition(const SelectionContext &selectionContext)
view->executeInTransaction("DesignerActionManager:addTransition",
- [view, targetNode, &sourceNode](){
+ [targetNode, &sourceNode](){
sourceNode.assignTargetItem(targetNode);
});
}
@@ -1095,7 +1084,24 @@ void addFlowEffect(const SelectionContext &selectionContext, const TypeName &typ
container.nodeProperty("effect").reparentHere(effectNode);
view->setSelectedModelNode(effectNode);
}
- });
+ });
+}
+
+void setFlowStartItem(const SelectionContext &selectionContext)
+{
+ AbstractView *view = selectionContext.view();
+
+ QTC_ASSERT(view && selectionContext.hasSingleSelectedModelNode(), return);
+ ModelNode node = selectionContext.currentSingleSelectedNode();
+ QTC_ASSERT(node.isValid(), return);
+ QTC_ASSERT(node.metaInfo().isValid(), return);
+ QmlFlowItemNode flowItem(node);
+ QTC_ASSERT(flowItem.isValid(), return);
+ QTC_ASSERT(flowItem.flowView().isValid(), return);
+ view->executeInTransaction("DesignerActionManager:setFlowStartItem",
+ [&flowItem](){
+ flowItem.flowView().setStartFlowItem(flowItem);
+ });
}
} // namespace Mode
diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h
index 994110297e..57fd0ea12a 100644
--- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h
+++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h
@@ -77,6 +77,7 @@ bool addFontToProject(const QStringList &fileNames, const QString &directory);
void createFlowActionArea(const SelectionContext &selectionContext);
void addTransition(const SelectionContext &selectionState);
void addFlowEffect(const SelectionContext &selectionState, const TypeName &typeName);
+void setFlowStartItem(const SelectionContext &selectionContext);
} // namespace ModelNodeOperationso
} //QmlDesigner
diff --git a/src/plugins/qmldesigner/components/componentcore/theme.cpp b/src/plugins/qmldesigner/components/componentcore/theme.cpp
index ec4128479f..29b937a502 100644
--- a/src/plugins/qmldesigner/components/componentcore/theme.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/theme.cpp
@@ -28,19 +28,46 @@
#include <qmldesignerplugin.h>
+#include <coreplugin/icore.h>
+
#include <utils/stylehelper.h>
#include <QApplication>
#include <QRegExp>
#include <QScreen>
#include <QPointer>
+#include <QQmlEngine>
+#include <QQmlComponent>
+#include <QQmlProperty>
#include <qqml.h>
+static Q_LOGGING_CATEGORY(themeLog, "qtc.qmldesigner.theme", QtWarningMsg)
+
namespace QmlDesigner {
Theme::Theme(Utils::Theme *originTheme, QObject *parent)
: Utils::Theme(originTheme, parent)
+ , m_constants(nullptr)
{
+ QString constantsPath = Core::ICore::resourcePath() +
+ QStringLiteral("/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml");
+
+ QQmlEngine* engine = new QQmlEngine(this);
+ QQmlComponent component(engine, QUrl::fromLocalFile(constantsPath));
+
+ if (component.status() == QQmlComponent::Ready) {
+ m_constants = component.create();
+ }
+ else if (component.status() == QQmlComponent::Error ) {
+ qCWarning(themeLog) << "Couldn't load" << constantsPath
+ << "due to the following error(s):";
+ for (QQmlError error : component.errors())
+ qCWarning(themeLog) << error.toString();
+ }
+ else {
+ qCWarning(themeLog) << "Couldn't load" << constantsPath
+ << "the status of the QQmlComponent is" << component.status();
+ }
}
QColor Theme::evaluateColorAtThemeInstance(const QString &themeColorName)
@@ -129,6 +156,25 @@ QPixmap Theme::getPixmap(const QString &id)
return QmlDesignerIconProvider::getPixmap(id);
}
+QString Theme::getIconUnicode(Theme::Icon i)
+{
+ if (!instance()->m_constants)
+ return QString();
+
+ const QMetaObject *m = instance()->metaObject();
+ const char *enumName = "Icon";
+ int enumIndex = m->indexOfEnumerator(enumName);
+
+ if (enumIndex == -1) {
+ qCWarning(themeLog) << "Couldn't find enum" << enumName;
+ return QString();
+ }
+
+ QMetaEnum e = m->enumerator(enumIndex);
+
+ return instance()->m_constants->property(e.valueToKey(i)).toString();
+}
+
QColor Theme::qmlDesignerBackgroundColorDarker() const
{
return getColor(QmlDesigner_BackgroundColorDarker);
diff --git a/src/plugins/qmldesigner/components/componentcore/theme.h b/src/plugins/qmldesigner/components/componentcore/theme.h
index 6940c0c1cf..07ee4caca8 100644
--- a/src/plugins/qmldesigner/components/componentcore/theme.h
+++ b/src/plugins/qmldesigner/components/componentcore/theme.h
@@ -41,12 +41,91 @@ namespace QmlDesigner {
class QMLDESIGNERCORE_EXPORT Theme : public Utils::Theme
{
Q_OBJECT
+
+ Q_ENUMS(Icon)
+
public:
+ enum Icon {
+ actionIcon,
+ actionIconBinding,
+ addColumnAfter,
+ addColumnBefore,
+ addFile,
+ addRowAfter,
+ addRowBefore,
+ addTable,
+ adsClose,
+ adsDetach,
+ adsDropDown,
+ alignBottom,
+ alignCenterHorizontal,
+ alignCenterVertical,
+ alignLeft,
+ alignRight,
+ alignTo,
+ alignTop,
+ anchorBaseline,
+ anchorBottom,
+ anchorFill,
+ anchorLeft,
+ anchorRight,
+ anchorTop,
+ annotationBubble,
+ annotationDecal,
+ centerHorizontal,
+ centerVertical,
+ closeCross,
+ decisionNode,
+ deleteColumn,
+ deleteRow,
+ deleteTable,
+ detach,
+ distributeBottom,
+ distributeCenterHorizontal,
+ distributeCenterVertical,
+ distributeLeft,
+ distributeOriginBottomRight,
+ distributeOriginCenter,
+ distributeOriginNone,
+ distributeOriginTopLeft,
+ distributeRight,
+ distributeSpacingHorizontal,
+ distributeSpacingVertical,
+ distributeTop,
+ edit,
+ fontStyleBold,
+ fontStyleItalic,
+ fontStyleStrikethrough,
+ fontStyleUnderline,
+ mergeCells,
+ redo,
+ splitColumns,
+ splitRows,
+ startNode,
+ testIcon,
+ textAlignBottom,
+ textAlignCenter,
+ textAlignLeft,
+ textAlignMiddle,
+ textAlignRight,
+ textAlignTop,
+ textBulletList,
+ textFullJustification,
+ textNumberedList,
+ tickIcon,
+ triState,
+ undo,
+ upDownIcon,
+ upDownSquare2,
+ wildcard
+ };
+
static Theme *instance();
static QString replaceCssColors(const QString &input);
static void setupTheme(QQmlEngine *engine);
static QColor getColor(Color role);
static QPixmap getPixmap(const QString &id);
+ static QString getIconUnicode(Theme::Icon i);
Q_INVOKABLE QColor qmlDesignerBackgroundColorDarker() const;
Q_INVOKABLE QColor qmlDesignerBackgroundColorDarkAlternate() const;
@@ -58,9 +137,12 @@ public:
Q_INVOKABLE int smallFontPixelSize() const;
Q_INVOKABLE int captionFontPixelSize() const;
Q_INVOKABLE bool highPixelDensity() const;
+
private:
Theme(Utils::Theme *originTheme, QObject *parent);
QColor evaluateColorAtThemeInstance(const QString &themeColorName);
+
+ QObject *m_constants;
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.cpp b/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.cpp
index ae4532f1f1..1163af6c58 100644
--- a/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.cpp
+++ b/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.cpp
@@ -58,7 +58,6 @@ ConnectionViewWidget::ConnectionViewWidget(QWidget *parent) :
ui(new Ui::ConnectionViewWidget)
{
m_actionEditor = new QmlDesigner::ActionEditor(this);
- m_deleteShortcut = new QShortcut(this);
QObject::connect(m_actionEditor, &QmlDesigner::ActionEditor::accepted,
[&]() {
if (m_actionEditor->hasModelIndex()) {
@@ -125,7 +124,6 @@ ConnectionViewWidget::~ConnectionViewWidget()
{
delete m_actionEditor;
delete ui;
- delete m_deleteShortcut;
}
void ConnectionViewWidget::setBindingModel(BindingModel *model)
@@ -215,9 +213,11 @@ QList<QToolButton *> ConnectionViewWidget::createToolBarWidgets()
connect(buttons.constLast(), &QAbstractButton::clicked, this, &ConnectionViewWidget::removeButtonClicked);
connect(this, &ConnectionViewWidget::setEnabledRemoveButton, buttons.constLast(), &QWidget::setEnabled);
- m_deleteShortcut->setKey(Qt::Key_Delete);
- m_deleteShortcut->setContext(Qt::WidgetWithChildrenShortcut);
- connect(m_deleteShortcut, &QShortcut::activated, this, &ConnectionViewWidget::removeButtonClicked);
+ QAction *deleteShortcut = new QAction(this);
+ this->addAction(deleteShortcut);
+ deleteShortcut->setShortcuts({QKeySequence::Delete, QKeySequence::Backspace});
+ deleteShortcut->setShortcutContext(Qt::WidgetWithChildrenShortcut);
+ connect(deleteShortcut, &QAction::triggered, this, &ConnectionViewWidget::removeButtonClicked);
return buttons;
}
diff --git a/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.h b/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.h
index c1f1271fca..d69d0de280 100644
--- a/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.h
+++ b/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.h
@@ -102,7 +102,6 @@ private:
private:
Ui::ConnectionViewWidget *ui;
QmlDesigner::ActionEditor *m_actionEditor;
- QShortcut *m_deleteShortcut;
};
} // namespace Internal
diff --git a/src/plugins/qmldesigner/components/curveeditor/curveeditormodel.cpp b/src/plugins/qmldesigner/components/curveeditor/curveeditormodel.cpp
index 2d87bd76d9..5c2796016d 100644
--- a/src/plugins/qmldesigner/components/curveeditor/curveeditormodel.cpp
+++ b/src/plugins/qmldesigner/components/curveeditor/curveeditormodel.cpp
@@ -111,7 +111,7 @@ void CurveEditorModel::reset(const std::vector<TreeItem *> &items)
graphicsView()->reset(pinned);
if (SelectionModel *sm = selectionModel())
- sm->select(sel);
+ sm->selectPaths(sel);
}
} // End namespace DesignTools.
diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.cpp b/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.cpp
index ef844badcd..e06b140e1a 100644
--- a/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.cpp
+++ b/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.cpp
@@ -338,7 +338,7 @@ void GraphicsView::contextMenuEvent(QContextMenuEvent *event)
QAction *insertKeyframeAction = menu.addAction(tr("Insert Keyframe"));
connect(insertKeyframeAction, &QAction::triggered, insertKeyframes);
- auto deleteKeyframes = [this, event] { m_scene->deleteSelectedKeyframes(); };
+ auto deleteKeyframes = [this] { m_scene->deleteSelectedKeyframes(); };
QAction *deleteKeyframeAction = menu.addAction(tr("Delete Selected Keyframes"));
connect(deleteKeyframeAction, &QAction::triggered, deleteKeyframes);
@@ -566,6 +566,8 @@ void GraphicsView::drawTimeScale(QPainter *painter, const QRectF &rect)
for (double i = minimumTime(); i <= maximumTime(); i += timeIncrement)
paintLabeledTick(i);
+ drawRangeBar(painter, rect);
+
painter->restore();
}
diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/selectionmodel.cpp b/src/plugins/qmldesigner/components/curveeditor/detail/selectionmodel.cpp
index 74b765843f..d35b0c3142 100644
--- a/src/plugins/qmldesigner/components/curveeditor/detail/selectionmodel.cpp
+++ b/src/plugins/qmldesigner/components/curveeditor/detail/selectionmodel.cpp
@@ -98,7 +98,7 @@ std::vector<PropertyTreeItem *> SelectionModel::selectedPropertyItems() const
return items;
}
-void SelectionModel::select(const std::vector<TreeItem::Path> &selection)
+void SelectionModel::selectPaths(const std::vector<TreeItem::Path> &selection)
{
for (auto &&path : selection) {
if (auto *treeModel = qobject_cast<TreeModel *>(model())) {
diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/selectionmodel.h b/src/plugins/qmldesigner/components/curveeditor/detail/selectionmodel.h
index 80b32db995..5a9a52ba07 100644
--- a/src/plugins/qmldesigner/components/curveeditor/detail/selectionmodel.h
+++ b/src/plugins/qmldesigner/components/curveeditor/detail/selectionmodel.h
@@ -59,7 +59,7 @@ public:
std::vector<PropertyTreeItem *> selectedPropertyItems() const;
- void select(const std::vector<TreeItem::Path> &selection);
+ void selectPaths(const std::vector<TreeItem::Path> &selection);
private:
void changeSelection(const QItemSelection &selected, const QItemSelection &deselected);
diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/selector.cpp b/src/plugins/qmldesigner/components/curveeditor/detail/selector.cpp
index 82f2125413..2ed74611e7 100644
--- a/src/plugins/qmldesigner/components/curveeditor/detail/selector.cpp
+++ b/src/plugins/qmldesigner/components/curveeditor/detail/selector.cpp
@@ -67,7 +67,7 @@ void Selector::mousePress(QMouseEvent *event, GraphicsView *view, GraphicsScene
if (HandleItem *hitem = qobject_cast<HandleItem *>(sitem))
kitem = hitem->keyframe();
- if (!kitem->selected()) {
+ if (kitem && !kitem->selected()) {
if (select(SelectionTool::Undefined, click, scene))
applyPreSelection(scene);
}
diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp
index c8e1e222e5..9e882be2fd 100644
--- a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp
+++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp
@@ -179,6 +179,17 @@ void Edit3DView::importsChanged(const QList<Import> &addedImports,
checkImports();
}
+void Edit3DView::customNotification(const AbstractView *view, const QString &identifier,
+ const QList<ModelNode> &nodeList, const QList<QVariant> &data)
+{
+ Q_UNUSED(view)
+ Q_UNUSED(nodeList)
+ Q_UNUSED(data)
+
+ if (identifier == "asset_import_update")
+ resetPuppet();
+}
+
void Edit3DView::sendInputEvent(QInputEvent *e) const
{
if (nodeInstanceView())
@@ -301,14 +312,16 @@ QVector<Edit3DAction *> Edit3DView::rightActions() const
void Edit3DView::addQuick3DImport()
{
- const QList<Import> imports = model()->possibleImports();
- for (const auto &import : imports) {
- if (import.url() == "QtQuick3D") {
- model()->changeImports({import}, {});
-
- // Subcomponent manager update needed to make item library entries appear
- QmlDesignerPlugin::instance()->currentDesignDocument()->updateSubcomponentManager();
- return;
+ if (model()) {
+ const QList<Import> imports = model()->possibleImports();
+ for (const auto &import : imports) {
+ if (import.url() == "QtQuick3D") {
+ model()->changeImports({import}, {});
+
+ // Subcomponent manager update needed to make item library entries appear
+ QmlDesignerPlugin::instance()->currentDesignDocument()->updateSubcomponentManager();
+ return;
+ }
}
}
Core::AsynchronousMessageBox::warning(tr("Failed to Add Import"),
diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.h b/src/plugins/qmldesigner/components/edit3d/edit3dview.h
index d1646470b7..6c3ae892a9 100644
--- a/src/plugins/qmldesigner/components/edit3d/edit3dview.h
+++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.h
@@ -58,6 +58,7 @@ public:
void modelAttached(Model *model) override;
void modelAboutToBeDetached(Model *model) override;
void importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports) override;
+ void customNotification(const AbstractView *view, const QString &identifier, const QList<ModelNode> &nodeList, const QList<QVariant> &data) override;
void sendInputEvent(QInputEvent *e) const;
void edit3DViewResized(const QSize &size) const;
diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp
index c948227233..3d0d3f2f64 100644
--- a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp
+++ b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp
@@ -106,12 +106,11 @@ Edit3DWidget::Edit3DWidget(Edit3DView *view) :
// Onboarding label contains instructions for new users how to get 3D content into the project
m_onboardingLabel = new QLabel(this);
QString labelText =
- "No 3D import here yet!<br><br>"
- "To create a 3D View you need to add the QtQuick3D import to your file.<br>"
- "You can add the import via the QML Imports tab of the Library view, or alternatively click"
- " <a href=\"#add_import\"><span style=\"text-decoration:none;color:%1\">here</span></a> "
- "to add it straight away.<br><br>"
- "If you want to import 3D assets from another tool, click on the \"Add New Assets...\" button in the Assets tab of the Library view.";
+ tr("Your file does not import Qt Quick 3D.<br><br>"
+ "To create a 3D view, add the QtQuick3D import to your file in the QML Imports tab of the Library view. Or click"
+ " <a href=\"#add_import\"><span style=\"text-decoration:none;color:%1\">here</span></a> "
+ "here to add it immediately.<br><br>"
+ "To import 3D assets from another tool, click on the \"Add New Assets...\" button in the Assets tab of the Library view.");
m_onboardingLabel->setText(labelText.arg(Utils::creatorTheme()->color(Utils::Theme::TextColorLink).name()));
m_onboardingLabel->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
connect(m_onboardingLabel, &QLabel::linkActivated, this, &Edit3DWidget::linkActivated);
diff --git a/src/plugins/qmldesigner/components/formeditor/formeditor.pri b/src/plugins/qmldesigner/components/formeditor/formeditor.pri
index 3464ba3afe..4609b277f9 100644
--- a/src/plugins/qmldesigner/components/formeditor/formeditor.pri
+++ b/src/plugins/qmldesigner/components/formeditor/formeditor.pri
@@ -36,7 +36,8 @@ SOURCES += formeditoritem.cpp \
contentnoteditableindicator.cpp \
backgroundaction.cpp \
formeditortoolbutton.cpp \
- formeditorannotationicon.cpp
+ formeditorannotationicon.cpp \
+ transitiontool.cpp
HEADERS += formeditorscene.h \
formeditorwidget.h \
@@ -75,6 +76,7 @@ HEADERS += formeditorscene.h \
contentnoteditableindicator.h \
backgroundaction.h \
formeditortoolbutton.h \
- formeditorannotationicon.h
+ formeditorannotationicon.h \
+ transitiontool.h
RESOURCES += formeditor.qrc
diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorannotationicon.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorannotationicon.cpp
index 5fa24f1a5c..220c763471 100644
--- a/src/plugins/qmldesigner/components/formeditor/formeditorannotationicon.cpp
+++ b/src/plugins/qmldesigner/components/formeditor/formeditorannotationicon.cpp
@@ -339,7 +339,7 @@ QGraphicsItem *FormEditorAnnotationIcon::createCommentBubble(QRectF rect, const
authorItem->update();
QGraphicsTextItem *textItem = new QGraphicsTextItem(frameItem);
- textItem->setPlainText(text);
+ textItem->setHtml(text);
textItem->setDefaultTextColor(textColor);
textItem->setTextWidth(rect.width());
textItem->setPos(authorItem->x(), authorItem->boundingRect().height() + authorItem->y() + 5);
@@ -444,14 +444,15 @@ void FormEditorAnnotationIcon::removeAnnotationDialog()
if (!m_customId.isNull()) {
dialogTitle = m_customId;
}
- QMessageBox *deleteDialog = new QMessageBox(Core::ICore::dialogParent());
+ QPointer<QMessageBox> deleteDialog = new QMessageBox(Core::ICore::dialogParent());
deleteDialog->setWindowTitle(dialogTitle);
deleteDialog->setText(tr("Delete this annotation?"));
deleteDialog->setStandardButtons(QMessageBox::Yes | QMessageBox::No);
deleteDialog->setDefaultButton(QMessageBox::Yes);
int result = deleteDialog->exec();
- if (deleteDialog) deleteDialog->deleteLater();
+ if (deleteDialog)
+ deleteDialog->deleteLater();
if (result == QMessageBox::Yes) {
m_modelNode.removeCustomId();
diff --git a/src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp b/src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp
index 96a4cc5adf..8371031093 100644
--- a/src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp
+++ b/src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp
@@ -32,10 +32,13 @@
#include <nodehints.h>
#include <nodemetainfo.h>
+#include <theme.h>
+
#include <utils/theme/theme.h>
#include <utils/qtcassert.h>
#include <QDebug>
+#include <QFontDatabase>
#include <QPainter>
#include <QPainterPath>
#include <QStyleOptionGraphicsItem>
@@ -47,6 +50,36 @@
namespace QmlDesigner {
const int flowBlockSize = 200;
+const int blockRadius = 18;
+const int blockAdjust = 40;
+
+const char startNodeIcon[] = "\u0055";
+
+void drawIcon(QPainter *painter,
+ int x,
+ int y,
+ const QString &iconSymbol,
+ int fontSize, int iconSize,
+ const QColor &penColor)
+{
+ static QFontDatabase a;
+
+ const QString fontName = "qtds_propertyIconFont.ttf";
+
+ Q_ASSERT(a.hasFamily(fontName));
+
+ if (a.hasFamily(fontName)) {
+ QFont font(fontName);
+ font.setPixelSize(fontSize);
+
+ painter->save();
+ painter->setPen(penColor);
+ painter->setFont(font);
+ painter->drawText(QRectF(x, y, iconSize, iconSize), iconSymbol);
+
+ painter->restore();
+ }
+}
FormEditorScene *FormEditorItem::scene() const {
return qobject_cast<FormEditorScene*>(QGraphicsItem::scene());
@@ -578,6 +611,7 @@ void FormEditorFlowActionItem::paint(QPainter *painter, const QStyleOptionGraphi
return;
painter->save();
+ painter->setRenderHint(QPainter::Antialiasing);
QPen pen;
pen.setJoinStyle(Qt::MiterJoin);
@@ -591,7 +625,6 @@ void FormEditorFlowActionItem::paint(QPainter *painter, const QStyleOptionGraphi
if (qmlItemNode().modelNode().hasAuxiliaryData("color"))
flowColor = qmlItemNode().modelNode().auxiliaryData("color").value<QColor>();
- const qreal scaleFactor = viewportTransform().m11();
qreal width = 2;
if (qmlItemNode().modelNode().hasAuxiliaryData("width"))
@@ -622,10 +655,9 @@ void FormEditorFlowActionItem::paint(QPainter *painter, const QStyleOptionGraphi
fillColor = qmlItemNode().modelNode().auxiliaryData("fillColor").value<QColor>();
if (fillColor.alpha() > 0)
- painter->fillRect(boundingRect(), fillColor);
-
- painter->drawRect(boundingRect());
+ painter->setBrush(fillColor);
+ painter->drawRoundedRect(boundingRect(), blockRadius, blockRadius);
painter->restore();
}
@@ -686,7 +718,7 @@ public:
if (from == node.rootModelNode()) {
isStartLine = true;
} else {
- for (const ModelNode wildcard : QmlFlowViewNode(node.rootModelNode()).wildcards()) {
+ for (const ModelNode &wildcard : QmlFlowViewNode(node.rootModelNode()).wildcards()) {
if (wildcard.bindingProperty("target").resolveToModelNode() == node.modelNode()) {
from = wildcard;
isWildcardLine = true;
@@ -990,6 +1022,7 @@ void FormEditorTransitionItem::paint(QPainter *painter, const QStyleOptionGraphi
return;
painter->save();
+ painter->setRenderHint(QPainter::Antialiasing);
ResolveConnection resolved(qmlItemNode());
@@ -1022,8 +1055,8 @@ void FormEditorTransitionItem::paint(QPainter *painter, const QStyleOptionGraphi
toRect.translate(QmlItemNode(resolved.to).flowPosition());
if (resolved.isStartLine) {
- fromRect = QRectF(0,0,50,50);
- fromRect.translate(QmlItemNode(resolved.to).flowPosition() + QPoint(-120, toRect.height() / 2 - 25));
+ fromRect = QRectF(0, 0, 96, 96);
+ fromRect.translate(QmlItemNode(resolved.to).flowPosition() + QPoint(-180, toRect.height() / 2 - 96 / 2));
}
toRect.translate(-pos());
@@ -1076,23 +1109,28 @@ void FormEditorTransitionItem::paint(QPainter *painter, const QStyleOptionGraphi
if (qmlItemNode().modelNode().hasAuxiliaryData("breakPoint"))
breakOffset = qmlItemNode().modelNode().auxiliaryData("breakPoint").toInt();
+ if (resolved.isStartLine)
+ fromRect.translate(0, inOffset);
+
paintConnection(painter, fromRect, toRect, width, adjustedWidth ,color, dash, outOffset, inOffset, breakOffset);
if (resolved.isStartLine) {
+
+ const QString icon = Theme::getIconUnicode(Theme::startNode);
+
QPen pen;
pen.setCosmetic(true);
-
pen.setColor(color);
painter->setPen(pen);
- painter->drawRect(fromRect);
-
- if (scaleFactor > 0.4) {
- painter->drawLine(fromRect.topRight() + QPoint(20,10), fromRect.bottomRight() + QPoint(20,-10));
- painter->drawLine(fromRect.topRight() + QPoint(25,12), fromRect.bottomRight() + QPoint(25,-12));
- painter->drawLine(fromRect.topRight() + QPoint(30,15), fromRect.bottomRight() + QPoint(30,-15));
- painter->drawLine(fromRect.topRight() + QPoint(35,17), fromRect.bottomRight() + QPoint(35,-17));
- painter->drawLine(fromRect.topRight() + QPoint(40,20), fromRect.bottomRight() + QPoint(40,-20));
- }
+
+ const int iconAdjust = 48;
+ const int offset = 96;
+ const int size = fromRect.width();
+ const int iconSize = size - iconAdjust;
+ const int x = fromRect.topRight().x() - offset;
+ const int y = fromRect.topRight().y();
+ painter->drawRoundedRect(x, y , size - 10, size, size / 2, iconSize / 2);
+ drawIcon(painter, x + iconAdjust / 2, y + iconAdjust / 2, icon, iconSize, iconSize, color);
}
painter->restore();
@@ -1141,6 +1179,9 @@ void FormEditorFlowDecisionItem::paint(QPainter *painter, const QStyleOptionGrap
painter->save();
+ painter->setRenderHint(QPainter::Antialiasing);
+ painter->setRenderHint(QPainter::SmoothPixmapTransform);
+
QPen pen;
pen.setJoinStyle(Qt::MiterJoin);
pen.setCosmetic(true);
@@ -1153,7 +1194,6 @@ void FormEditorFlowDecisionItem::paint(QPainter *painter, const QStyleOptionGrap
if (qmlItemNode().modelNode().hasAuxiliaryData("color"))
flowColor = qmlItemNode().modelNode().auxiliaryData("color").value<QColor>();
- const qreal scaleFactor = viewportTransform().m11();
qreal width = 2;
if (qmlItemNode().modelNode().hasAuxiliaryData("width"))
@@ -1179,20 +1219,37 @@ void FormEditorFlowDecisionItem::paint(QPainter *painter, const QStyleOptionGrap
if (qmlItemNode().modelNode().hasAuxiliaryData("fillColor"))
fillColor = qmlItemNode().modelNode().auxiliaryData("fillColor").value<QColor>();
+ painter->save();
+
+ if (m_iconType == DecisionIcon) {
+ painter->translate(boundingRect().center());
+ painter->rotate(45);
+ painter->translate(-boundingRect().center());
+ }
+
if (fillColor.alpha() > 0)
- painter->fillRect(boundingRect(), fillColor);
+ painter->setBrush(fillColor);
- painter->drawLine(boundingRect().left(), boundingRect().center().y(),
- boundingRect().center().x(), boundingRect().top());
+ int radius = blockRadius;
- painter->drawLine(boundingRect().center().x(), boundingRect().top(),
- boundingRect().right(), boundingRect().center().y());
+ const QRectF adjustedRect = boundingRect().adjusted(blockAdjust,
+ blockAdjust,
+ -blockAdjust,
+ -blockAdjust);
+
+ painter->drawRoundedRect(adjustedRect, radius, radius);
+
+ const int iconDecrement = 32;
+ const int iconSize = adjustedRect.width() - iconDecrement;
+ const int offset = iconDecrement / 2 + blockAdjust;
+
+ painter->restore();
- painter->drawLine(boundingRect().right(), boundingRect().center().y(),
- boundingRect().center().x(), boundingRect().bottom());
+ const QString icon = (m_iconType ==
+ WildcardIcon) ? Theme::getIconUnicode(Theme::wildcard)
+ : Theme::getIconUnicode(Theme::decisionNode);
- painter->drawLine(boundingRect().center().x(), boundingRect().bottom(),
- boundingRect().left(), boundingRect().center().y());
+ drawIcon(painter, offset, offset, icon, iconSize, iconSize, flowColor);
painter->restore();
}
diff --git a/src/plugins/qmldesigner/components/formeditor/formeditoritem.h b/src/plugins/qmldesigner/components/formeditor/formeditoritem.h
index d725afd0b0..91dcad44a4 100644
--- a/src/plugins/qmldesigner/components/formeditor/formeditoritem.h
+++ b/src/plugins/qmldesigner/components/formeditor/formeditoritem.h
@@ -207,9 +207,17 @@ public:
bool flowHitTest(const QPointF &point) const override;
protected:
- FormEditorFlowDecisionItem(const QmlItemNode &qmlItemNode, FormEditorScene* scene)
- : FormEditorFlowItem(qmlItemNode, scene)
+ enum IconType {
+ DecisionIcon,
+ WildcardIcon
+ };
+
+ FormEditorFlowDecisionItem(const QmlItemNode &qmlItemNode,
+ FormEditorScene* scene,
+ IconType iconType = DecisionIcon)
+ : FormEditorFlowItem(qmlItemNode, scene), m_iconType(iconType)
{}
+ IconType m_iconType;
};
class FormEditorFlowWildcardItem : FormEditorFlowDecisionItem
@@ -221,8 +229,9 @@ public:
protected:
FormEditorFlowWildcardItem(const QmlItemNode &qmlItemNode, FormEditorScene* scene)
- : FormEditorFlowDecisionItem(qmlItemNode, scene)
- {}
+ : FormEditorFlowDecisionItem(qmlItemNode, scene, WildcardIcon)
+ {
+ }
};
inline int FormEditorItem::type() const
diff --git a/src/plugins/qmldesigner/components/formeditor/selectionindicator.cpp b/src/plugins/qmldesigner/components/formeditor/selectionindicator.cpp
index 883fe841d9..02f3ce9ee6 100644
--- a/src/plugins/qmldesigner/components/formeditor/selectionindicator.cpp
+++ b/src/plugins/qmldesigner/components/formeditor/selectionindicator.cpp
@@ -44,7 +44,6 @@ namespace QmlDesigner {
SelectionIndicator::SelectionIndicator(LayerItem *layerItem)
: m_layerItem(layerItem)
- , m_annotationItem(nullptr)
{
}
diff --git a/src/plugins/qmldesigner/components/formeditor/selectionindicator.h b/src/plugins/qmldesigner/components/formeditor/selectionindicator.h
index 252020e990..b70d30ed51 100644
--- a/src/plugins/qmldesigner/components/formeditor/selectionindicator.h
+++ b/src/plugins/qmldesigner/components/formeditor/selectionindicator.h
@@ -57,11 +57,10 @@ private:
private:
QHash<FormEditorItem*, QGraphicsPolygonItem *> m_indicatorShapeHash;
- FormEditorItem *m_selectedItem;
QPointer<LayerItem> m_layerItem;
QCursor m_cursor;
std::unique_ptr<QGraphicsPolygonItem> m_labelItem;
- FormEditorAnnotationIcon *m_annotationItem; //handled by m_labelItem
+ FormEditorAnnotationIcon *m_annotationItem = nullptr; //handled by m_labelItem
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/formeditor/transitiontool.cpp b/src/plugins/qmldesigner/components/formeditor/transitiontool.cpp
new file mode 100644
index 0000000000..e8222e8ac8
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/transitiontool.cpp
@@ -0,0 +1,438 @@
+/****************************************************************************
+**
+** 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 "transitiontool.h"
+
+#include <formeditorscene.h>
+#include <formeditorview.h>
+#include <formeditorwidget.h>
+#include <itemutilfunctions.h>
+#include <formeditoritem.h>
+#include <layeritem.h>
+
+#include <resizehandleitem.h>
+
+#include <bindingproperty.h>
+#include <nodeabstractproperty.h>
+#include <nodelistproperty.h>
+#include <nodemetainfo.h>
+#include <qmlitemnode.h>
+#include <qmldesignerplugin.h>
+#include <abstractaction.h>
+#include <designeractionmanager.h>
+#include <variantproperty.h>
+#include <rewritingexception.h>
+#include <rewritertransaction.h>
+
+#include <coreplugin/icore.h>
+#include <utils/qtcassert.h>
+
+#include <QApplication>
+#include <QGraphicsSceneMouseEvent>
+#include <QAction>
+#include <QMessageBox>
+#include <QPair>
+#include <QGraphicsSceneMouseEvent>
+
+namespace QmlDesigner {
+
+static bool isTransitionSource(const ModelNode &node)
+{
+ return QmlFlowTargetNode::isFlowEditorTarget(node);
+}
+
+static bool isTransitionTarget(const QmlItemNode &node)
+{
+ return QmlFlowTargetNode::isFlowEditorTarget(node)
+ && !node.isFlowActionArea()
+ && !node.isFlowWildcard();
+}
+
+class TransitionToolAction : public AbstractAction
+{
+public:
+ TransitionToolAction(const QString &name) : AbstractAction(name) {}
+
+ QByteArray category() const override
+ {
+ return QByteArray();
+ }
+
+ QByteArray menuId() const override
+ {
+ return "TransitionTool";
+ }
+
+ int priority() const override
+ {
+ return CustomActionsPriority;
+ }
+
+ Type type() const override
+ {
+ return ContextMenuAction;
+ }
+
+protected:
+ bool isVisible(const SelectionContext &selectionContext) const override
+ {
+ if (selectionContext.scenePosition().isNull())
+ return false;
+
+ if (selectionContext.singleNodeIsSelected())
+ return isTransitionSource(selectionContext.currentSingleSelectedNode());
+
+ return false;
+ }
+
+ bool isEnabled(const SelectionContext &selectionContext) const override
+ {
+ return isVisible(selectionContext);
+ }
+};
+
+class TransitionCustomAction : public TransitionToolAction
+{
+public:
+ TransitionCustomAction(const QString &name) : TransitionToolAction(name) {}
+
+ QByteArray category() const override
+ {
+ return ComponentCoreConstants::flowCategory;
+ }
+
+ SelectionContext selectionContext() const
+ {
+ return AbstractAction::selectionContext();
+ }
+
+};
+
+static QRectF paintedBoundingRect(FormEditorItem *item)
+{
+ QRectF boundingRect = item->qmlItemNode().instanceBoundingRect();
+ if (boundingRect.width() < 4)
+ boundingRect = item->boundingRect();
+ return boundingRect;
+}
+
+static QPointF centerPoint(FormEditorItem *item)
+{
+ QRectF boundingRect = paintedBoundingRect(item);
+ return QPointF(item->scenePos().x() + boundingRect.width() / 2,
+ item->scenePos().y() + boundingRect.height() / 2);
+}
+
+void static setToBoundingRect(QGraphicsRectItem *rect, FormEditorItem *item)
+{
+ QPolygonF boundingRectInSceneSpace(item->mapToScene(paintedBoundingRect(item)));
+ rect->setRect(boundingRectInSceneSpace.boundingRect());
+}
+
+TransitionTool::TransitionTool()
+ : QObject(), AbstractCustomTool()
+{
+
+ TransitionToolAction *transitionToolAction = new TransitionToolAction(tr("Add Transition"));
+ QmlDesignerPlugin::instance()->designerActionManager().addDesignerAction(transitionToolAction);
+
+ connect(transitionToolAction->action(), &QAction::triggered,
+ this, &TransitionTool::activateTool);
+
+ TransitionCustomAction *removeAction = new TransitionCustomAction(tr("Remove Transitions"));
+ QmlDesignerPlugin::instance()->designerActionManager().addDesignerAction(removeAction);
+
+ connect(removeAction->action(), &QAction::triggered,
+ this, [removeAction](){
+
+ SelectionContext context = removeAction->selectionContext();
+ QmlFlowTargetNode node = QmlFlowTargetNode(context.currentSingleSelectedNode());
+
+ context.view()->executeInTransaction("Remove Transitions", [&node](){
+ if (node.isValid())
+ node.removeTransitions();
+ });
+ });
+
+ TransitionCustomAction *removeAllTransitionsAction = new TransitionCustomAction(tr("Remove All Transitions"));
+ QmlDesignerPlugin::instance()->designerActionManager().addDesignerAction(removeAllTransitionsAction);
+
+ connect(removeAllTransitionsAction->action(), &QAction::triggered,
+ this, [removeAllTransitionsAction](){
+
+ if (QMessageBox::question(Core::ICore::dialogParent(),
+ tr("Remove All Transitions"),
+ tr("Do you really want to remove all transitions?"),
+ QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes)
+ return;
+
+ SelectionContext context = removeAllTransitionsAction->selectionContext();
+ QmlFlowTargetNode node = QmlFlowTargetNode(context.currentSingleSelectedNode());
+
+ context.view()->executeInTransaction("Remove All Transitions", [&node](){
+ if (node.isValid() && node.flowView().isValid())
+ node.flowView().removeAllTransitions();
+ });
+ });
+
+ TransitionCustomAction *removeDanglingTransitionAction = new TransitionCustomAction(tr("Remove Dangling Transitions"));
+ QmlDesignerPlugin::instance()->designerActionManager().addDesignerAction(removeDanglingTransitionAction);
+
+ connect(removeDanglingTransitionAction->action(), &QAction::triggered,
+ this, [removeDanglingTransitionAction](){
+
+ SelectionContext context = removeDanglingTransitionAction->selectionContext();
+ QmlFlowTargetNode node = QmlFlowTargetNode(context.currentSingleSelectedNode());
+
+ context.view()->executeInTransaction("Remove Dangling Transitions", [&node](){
+ if (node.isValid() && node.flowView().isValid())
+ node.flowView().removeDanglingTransitions();
+ });
+ });
+}
+
+TransitionTool::~TransitionTool()
+{
+}
+
+void TransitionTool::clear()
+{
+ m_lineItem.reset(nullptr);
+ m_rectangleItem1.reset(nullptr);
+ m_rectangleItem2.reset(nullptr);
+
+ AbstractFormEditorTool::clear();
+}
+
+void TransitionTool::mousePressEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event)
+{
+ if (m_blockEvents)
+ return;
+
+ if (event->button() != Qt::LeftButton)
+ return;
+
+ AbstractFormEditorTool::mousePressEvent(itemList, event);
+ TransitionTool::mouseMoveEvent(itemList, event);
+}
+
+void TransitionTool::mouseMoveEvent(const QList<QGraphicsItem*> & itemList,
+ QGraphicsSceneMouseEvent * event)
+{
+ if (!m_lineItem)
+ return;
+
+ QTC_ASSERT(currentFormEditorItem(), return);
+
+ const QPointF pos = centerPoint(m_formEditorItem);
+ lineItem()->setLine(pos.x(),
+ pos.y(),
+ event->scenePos().x(),
+ event->scenePos().y());
+
+ FormEditorItem *formEditorItem = nearestFormEditorItem(event->scenePos(), itemList);
+
+ if (formEditorItem
+ && formEditorItem->qmlItemNode().isValid()
+ && isTransitionTarget(formEditorItem->qmlItemNode().modelNode())) {
+ rectangleItem2()->setVisible(true);
+ setToBoundingRect(rectangleItem2(), formEditorItem);
+ } else {
+ rectangleItem2()->setVisible(false);
+ }
+}
+
+void TransitionTool::hoverMoveEvent(const QList<QGraphicsItem*> & itemList,
+ QGraphicsSceneMouseEvent *event)
+{
+ mouseMoveEvent(itemList, event);
+}
+
+void TransitionTool::keyPressEvent(QKeyEvent * /*keyEvent*/)
+{
+}
+
+void TransitionTool::keyReleaseEvent(QKeyEvent * /*keyEvent*/)
+{
+ view()->changeToSelectionTool();
+}
+
+void TransitionTool::dragLeaveEvent(const QList<QGraphicsItem*> &/*itemList*/, QGraphicsSceneDragDropEvent * /*event*/)
+{
+}
+
+void TransitionTool::dragMoveEvent(const QList<QGraphicsItem*> &/*itemList*/, QGraphicsSceneDragDropEvent * /*event*/)
+{
+}
+
+void TransitionTool::mouseReleaseEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event)
+{
+ if (m_blockEvents)
+ return;
+
+ if (event->button() == Qt::LeftButton) {
+ FormEditorItem *formEditorItem = nearestFormEditorItem(event->scenePos(), itemList);
+
+ if (formEditorItem
+ && QmlFlowTargetNode(formEditorItem->qmlItemNode().modelNode()).isValid())
+ createTransition(m_formEditorItem, formEditorItem);
+ }
+
+ view()->changeToSelectionTool();
+}
+
+
+void TransitionTool::mouseDoubleClickEvent(const QList<QGraphicsItem*> &itemList, QGraphicsSceneMouseEvent *event)
+{
+ AbstractFormEditorTool::mouseDoubleClickEvent(itemList, event);
+}
+
+void TransitionTool::itemsAboutToRemoved(const QList<FormEditorItem*> &)
+{
+ view()->changeCurrentToolTo(this);
+}
+
+void TransitionTool::selectedItemsChanged(const QList<FormEditorItem*> &itemList)
+{
+ if (!itemList.isEmpty()) {
+ createItems();
+
+ m_formEditorItem = itemList.first();
+ setToBoundingRect(rectangleItem1(), m_formEditorItem);
+ }
+}
+
+void TransitionTool::instancesCompleted(const QList<FormEditorItem*> & /*itemList*/)
+{
+}
+
+void TransitionTool::instancesParentChanged(const QList<FormEditorItem *> & /*itemList*/)
+{
+}
+
+void TransitionTool::instancePropertyChange(const QList<QPair<ModelNode, PropertyName> > & /*propertyList*/)
+{
+}
+
+void TransitionTool::formEditorItemsChanged(const QList<FormEditorItem*> & /*itemList*/)
+{
+}
+
+int TransitionTool::wantHandleItem(const ModelNode &modelNode) const
+{
+ if (isTransitionSource(modelNode))
+ return 10;
+
+ return 0;
+}
+
+QString TransitionTool::name() const
+{
+ return tr("Transition Tool");
+}
+
+void TransitionTool::activateTool()
+{
+ view()->changeToCustomTool();
+}
+
+void TransitionTool::unblock()
+{
+ m_blockEvents = false;
+}
+
+QGraphicsLineItem *TransitionTool::lineItem()
+{
+ return m_lineItem.get();
+}
+
+QGraphicsRectItem *TransitionTool::rectangleItem1()
+{
+ return m_rectangleItem1.get();
+}
+
+QGraphicsRectItem *TransitionTool::rectangleItem2()
+{
+ return m_rectangleItem2.get();
+}
+
+FormEditorItem *TransitionTool::currentFormEditorItem() const
+{
+ if (scene()->items().contains(m_formEditorItem))
+ return m_formEditorItem;
+
+ return nullptr;
+}
+
+void TransitionTool::createItems() {
+ m_blockEvents = true;
+ QTimer::singleShot(200, this, [this](){ unblock(); });
+
+ if (!lineItem())
+ m_lineItem.reset(new QGraphicsLineItem(scene()->manipulatorLayerItem()));
+
+ if (!rectangleItem1())
+ m_rectangleItem1.reset(new QGraphicsRectItem(scene()->manipulatorLayerItem()));
+
+ if (!rectangleItem2())
+ m_rectangleItem2.reset(new QGraphicsRectItem(scene()->manipulatorLayerItem()));
+
+ m_rectangleItem2->setVisible(false);
+
+ QPen pen;
+ pen.setColor(QColor(Qt::lightGray));
+ pen.setStyle(Qt::DashLine);
+ pen.setWidth(0);
+ m_lineItem->setPen(pen);
+
+ pen.setColor(QColor(108, 141, 221));
+ pen.setStyle(Qt::SolidLine);
+ pen.setWidth(4);
+ pen.setCosmetic(true);
+ m_rectangleItem1->setPen(pen);
+
+ m_rectangleItem2->setPen(pen);
+}
+
+void TransitionTool::createTransition(FormEditorItem *source, FormEditorItem *target)
+{
+ QmlFlowTargetNode sourceNode(source->qmlItemNode().modelNode());
+ QmlFlowTargetNode targetNode(target->qmlItemNode().modelNode());
+
+ if (sourceNode.isValid() && targetNode.isValid()
+ && sourceNode != targetNode
+ && !targetNode.isFlowActionArea()
+ && !targetNode.isFlowWildcard()) {
+ view()->executeInTransaction("create transition", [&sourceNode, targetNode](){
+ sourceNode.assignTargetItem(targetNode);
+ });
+ } else {
+ qWarning() << Q_FUNC_INFO << "nodes invalid";
+ }
+}
+
+}
diff --git a/src/plugins/qmldesigner/components/formeditor/transitiontool.h b/src/plugins/qmldesigner/components/formeditor/transitiontool.h
new file mode 100644
index 0000000000..43c3894933
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/transitiontool.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** 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 "abstractcustomtool.h"
+#include "selectionindicator.h"
+
+#include <QGraphicsLineItem>
+#include <QHash>
+#include <QPointer>
+
+#include <memory>
+
+namespace QmlDesigner {
+
+class TransitionTool : public QObject, public AbstractCustomTool
+{
+ Q_OBJECT
+public:
+ TransitionTool();
+ ~TransitionTool();
+
+ void mousePressEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event) override;
+ void mouseMoveEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event) override;
+ void mouseReleaseEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event) override;
+ void mouseDoubleClickEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event) override;
+ void hoverMoveEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event) override;
+ void keyPressEvent(QKeyEvent *event) override;
+ void keyReleaseEvent(QKeyEvent *keyEvent) override;
+
+ void dragLeaveEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneDragDropEvent * event) override;
+ void dragMoveEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneDragDropEvent * event) override;
+
+ void itemsAboutToRemoved(const QList<FormEditorItem*> &itemList) override;
+
+ void selectedItemsChanged(const QList<FormEditorItem*> &itemList) override;
+
+ void instancesCompleted(const QList<FormEditorItem*> &itemList) override;
+ void instancesParentChanged(const QList<FormEditorItem *> &itemList) override;
+ void instancePropertyChange(const QList<QPair<ModelNode, PropertyName> > &propertyList) override;
+
+ void clear() override;
+
+ void formEditorItemsChanged(const QList<FormEditorItem*> &itemList) override;
+
+ int wantHandleItem(const ModelNode &modelNode) const override;
+
+ QString name() const override;
+
+ void activateTool();
+ void unblock();
+
+ QGraphicsLineItem *lineItem();
+ QGraphicsRectItem *rectangleItem1();
+ QGraphicsRectItem *rectangleItem2();
+
+private:
+ FormEditorItem *currentFormEditorItem() const;
+ void createItems();
+ void createTransition(FormEditorItem *item1, FormEditorItem *item2);
+
+ FormEditorItem* m_formEditorItem;
+ std::unique_ptr<QGraphicsLineItem> m_lineItem;
+ std::unique_ptr<QGraphicsRectItem> m_rectangleItem1;
+ std::unique_ptr<QGraphicsRectItem> m_rectangleItem2;
+ bool m_blockEvents = true;
+};
+
+} //QmlDesigner
diff --git a/src/plugins/qmldesigner/components/importmanager/importmanagerview.cpp b/src/plugins/qmldesigner/components/importmanager/importmanagerview.cpp
index df9590af64..c2bce0b0ce 100644
--- a/src/plugins/qmldesigner/components/importmanager/importmanagerview.cpp
+++ b/src/plugins/qmldesigner/components/importmanager/importmanagerview.cpp
@@ -81,14 +81,16 @@ void ImportManagerView::modelAboutToBeDetached(Model *model)
void ImportManagerView::importsChanged(const QList<Import> &/*addedImports*/, const QList<Import> &/*removedImports*/)
{
- if (m_importsWidget)
+ if (m_importsWidget) {
m_importsWidget->setImports(model()->imports());
+ // setImports recreates labels, so we need to update used imports, as it is not guaranteed
+ // usedImportsChanged notification will come after this.
+ m_importsWidget->setUsedImports(model()->usedImports());
+ }
}
void ImportManagerView::possibleImportsChanged(const QList<Import> &/*possibleImports*/)
{
- QmlDesignerPlugin::instance()->currentDesignDocument()->updateSubcomponentManager();
-
if (m_importsWidget)
m_importsWidget->setPossibleImports(model()->possibleImports());
}
diff --git a/src/plugins/qmldesigner/components/integration/designdocument.cpp b/src/plugins/qmldesigner/components/integration/designdocument.cpp
index e5d7e8978d..9acede8f79 100644
--- a/src/plugins/qmldesigner/components/integration/designdocument.cpp
+++ b/src/plugins/qmldesigner/components/integration/designdocument.cpp
@@ -488,7 +488,7 @@ void DesignDocument::paste()
}
}
- rewriterView()->executeInTransaction("DesignDocument::paste1", [this, &view, selectedNodes, targetNode](){
+ rewriterView()->executeInTransaction("DesignDocument::paste1", [&view, selectedNodes, targetNode](){
QList<ModelNode> pastedNodeList;
int offset = double(qrand()) / RAND_MAX * 20 - 10;
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp
index 3f403d0313..0beb5bce72 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp
@@ -32,6 +32,9 @@
#include "utils/outputformatter.h"
#include "theme.h"
+#include <projectexplorer/project.h>
+#include <projectexplorer/session.h>
+
#include <QtCore/qfileinfo.h>
#include <QtCore/qdir.h>
#include <QtCore/qloggingcategory.h>
@@ -97,6 +100,20 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(const QStringList &im
ui->buttonBox->button(QDialogButtonBox::Close)->setDefault(true);
+ QStringList importPaths;
+ auto doc = QmlDesignerPlugin::instance()->currentDesignDocument();
+ if (doc) {
+ Model *model = doc->currentModel();
+ if (model)
+ importPaths = model->importPaths();
+ }
+
+ QString targetDir = defaulTargetDirectory;
+
+ ProjectExplorer::Project *currentProject = ProjectExplorer::SessionManager::projectForFile(doc->fileName());
+ if (currentProject)
+ targetDir = currentProject->projectDirectory().toString();
+
// Import is always done under known folder. The order of preference for folder is:
// 1) An existing QUICK_3D_ASSETS_FOLDER under DEFAULT_ASSET_IMPORT_FOLDER project import path
// 2) An existing QUICK_3D_ASSETS_FOLDER under any project import path
@@ -105,19 +122,11 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(const QStringList &im
// 5) New QUICK_3D_ASSETS_FOLDER under new DEFAULT_ASSET_IMPORT_FOLDER under project
const QString defaultAssetFolder = QLatin1String(Constants::DEFAULT_ASSET_IMPORT_FOLDER);
const QString quick3DFolder = QLatin1String(Constants::QUICK_3D_ASSETS_FOLDER);
- QString candidatePath = defaulTargetDirectory + defaultAssetFolder + quick3DFolder;
+ QString candidatePath = targetDir + defaultAssetFolder + quick3DFolder;
int candidatePriority = 5;
- QStringList importPaths;
-
- auto doc = QmlDesignerPlugin::instance()->currentDesignDocument();
- if (doc) {
- Model *model = doc->currentModel();
- if (model)
- importPaths = model->importPaths();
- }
for (auto importPath : qAsConst(importPaths)) {
- if (importPath.startsWith(defaulTargetDirectory)) {
+ if (importPath.startsWith(targetDir)) {
const bool isDefaultFolder = importPath.endsWith(defaultAssetFolder);
const QString assetFolder = importPath + quick3DFolder;
const bool exists = QFileInfo(assetFolder).exists();
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp
index 34fa71222d..6a5edb18a3 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp
@@ -280,7 +280,16 @@ void ItemLibraryAssetImporter::parseQuick3DAsset(const QString &file, const QVar
return;
}
+ QString originalAssetName = assetName;
if (targetDir.exists(assetName)) {
+ // If we have a file system with case insensitive filenames, assetName may be
+ // different from the existing name. Modify assetName to ensure exact match to
+ // the overwritten old asset capitalization
+ const QStringList assetDirs = targetDir.entryList({assetName}, QDir::Dirs);
+ if (assetDirs.size() == 1) {
+ assetName = assetDirs[0];
+ targetDirPath = targetDir.filePath(assetName);
+ }
if (!confirmAssetOverwrite(assetName)) {
addWarning(tr("Skipped import of existing asset: \"%1\"").arg(assetName));
return;
@@ -306,6 +315,16 @@ void ItemLibraryAssetImporter::parseQuick3DAsset(const QString &file, const QVar
return;
}
+ // The importer is reset after every import to avoid issues with it caching various things
+ m_quick3DAssetImporter.reset(new QSSGAssetImportManager);
+
+ if (originalAssetName != assetName) {
+ // Fix the generated qml file name
+ const QString assetQml = originalAssetName + ".qml";
+ if (outDir.exists(assetQml))
+ outDir.rename(assetQml, assetName + ".qml");
+ }
+
QHash<QString, QString> assetFiles;
const int outDirPathSize = outDir.path().size();
auto insertAsset = [&](const QString &filePath) {
@@ -512,18 +531,24 @@ void ItemLibraryAssetImporter::finalizeQuick3DImport()
addInfo(progressTitle);
notifyProgress(0, progressTitle);
- // There is an inbuilt delay before rewriter change actually updates the data model,
- // so we need to wait for a moment to allow the change to take effect.
+ // 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
+ // model, so we need to wait for another moment to allow the change to take effect.
// Otherwise subsequent subcomponent manager update won't detect new imports properly.
QTimer *timer = new QTimer(parent());
static int counter;
counter = 0;
- timer->callOnTimeout([this, timer, progressTitle, model]() {
+ timer->callOnTimeout([this, timer, progressTitle, model, doc]() {
if (!isCancelled()) {
- notifyProgress(++counter * 10, progressTitle);
- if (counter >= 10) {
- // Trigger underlying qmljs snapshot update by making a non-change to the doc
+ notifyProgress(++counter * 5, progressTitle);
+ if (counter == 10) {
model->rewriterView()->textModifier()->replace(0, 0, {});
+ } else if (counter == 19) {
+ doc->updateSubcomponentManager();
+ } else if (counter >= 20) {
+ if (!m_overwrittenImports.isEmpty())
+ model->rewriterView()->emitCustomNotification("asset_import_update");
timer->stop();
notifyFinished();
}
diff --git a/src/plugins/qmldesigner/components/navigator/navigatormodelinterface.h b/src/plugins/qmldesigner/components/navigator/navigatormodelinterface.h
index bedcc2f561..d560eb2824 100644
--- a/src/plugins/qmldesigner/components/navigator/navigatormodelinterface.h
+++ b/src/plugins/qmldesigner/components/navigator/navigatormodelinterface.h
@@ -43,6 +43,7 @@ public:
virtual void notifyModelNodesRemoved(const QList<ModelNode> &modelNodes) = 0;
virtual void notifyModelNodesInserted(const QList<ModelNode> &modelNodes) = 0;
virtual void notifyModelNodesMoved(const QList<ModelNode> &modelNodes) = 0;
+ virtual void notifyIconsChanged() = 0;
virtual void setFilter(bool showObjects) = 0;
virtual void resetModel() = 0;
};
diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp
index c91ff78626..6370d2bfd4 100644
--- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp
+++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp
@@ -602,7 +602,7 @@ void NavigatorTreeModel::moveNodesInteractive(NodeAbstractProperty &parentProper
{
QTC_ASSERT(m_view, return);
- m_view->executeInTransaction("NavigatorTreeModel::moveNodesInteractive",[this, &parentProperty, modelNodes, targetIndex](){
+ m_view->executeInTransaction("NavigatorTreeModel::moveNodesInteractive",[&parentProperty, modelNodes, targetIndex](){
const TypeName propertyQmlType = parentProperty.parentModelNode().metaInfo().propertyTypeName(parentProperty.name());
foreach (const ModelNode &modelNode, modelNodes) {
if (modelNode.isValid()
@@ -695,6 +695,11 @@ void NavigatorTreeModel::notifyModelNodesMoved(const QList<ModelNode> &modelNode
emit layoutChanged(indexes);
}
+void NavigatorTreeModel::notifyIconsChanged()
+{
+ emit dataChanged(index(0, 0), index(rowCount(), 0), {Qt::DecorationRole});
+}
+
void NavigatorTreeModel::setFilter(bool showOnlyVisibleItems)
{
m_showOnlyVisibleItems = showOnlyVisibleItems;
diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h
index f10198adcc..15e89d3636 100644
--- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h
+++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h
@@ -87,6 +87,7 @@ public:
void notifyModelNodesRemoved(const QList<ModelNode> &modelNodes) override;
void notifyModelNodesInserted(const QList<ModelNode> &modelNodes) override;
void notifyModelNodesMoved(const QList<ModelNode> &modelNodes) override;
+ void notifyIconsChanged() override;
void setFilter(bool showOnlyVisibleItems) override;
void resetModel() override;
diff --git a/src/plugins/qmldesigner/components/navigator/navigatorview.cpp b/src/plugins/qmldesigner/components/navigator/navigatorview.cpp
index ea64f0715a..832e57d069 100644
--- a/src/plugins/qmldesigner/components/navigator/navigatorview.cpp
+++ b/src/plugins/qmldesigner/components/navigator/navigatorview.cpp
@@ -147,6 +147,17 @@ void NavigatorView::bindingPropertiesChanged(const QList<BindingProperty> & prop
}
}
+void NavigatorView::customNotification(const AbstractView *view, const QString &identifier,
+ const QList<ModelNode> &nodeList, const QList<QVariant> &data)
+{
+ Q_UNUSED(view)
+ Q_UNUSED(nodeList)
+ Q_UNUSED(data)
+
+ if (identifier == "asset_import_update")
+ m_currentModelInterface->notifyIconsChanged();
+}
+
void NavigatorView::handleChangedExport(const ModelNode &modelNode, bool exported)
{
const ModelNode rootNode = rootModelNode();
@@ -155,7 +166,7 @@ void NavigatorView::handleChangedExport(const ModelNode &modelNode, bool exporte
if (rootNode.hasProperty(modelNodeId))
rootNode.removeProperty(modelNodeId);
if (exported) {
- executeInTransaction("NavigatorTreeModel:exportItem", [this, modelNode](){
+ executeInTransaction("NavigatorTreeModel:exportItem", [modelNode](){
QmlObjectNode qmlObjectNode(modelNode);
qmlObjectNode.ensureAliasExport();
});
@@ -434,7 +445,7 @@ void NavigatorView::updateItemSelection()
// make sure selected nodes a visible
foreach (const QModelIndex &selectedIndex, itemSelection.indexes()) {
if (selectedIndex.column() == 0)
- expandRecursively(selectedIndex);
+ expandAncestors(selectedIndex);
}
}
@@ -458,9 +469,9 @@ bool NavigatorView::blockSelectionChangedSignal(bool block)
return oldValue;
}
-void NavigatorView::expandRecursively(const QModelIndex &index)
+void NavigatorView::expandAncestors(const QModelIndex &index)
{
- QModelIndex currentIndex = index;
+ QModelIndex currentIndex = index.parent();
while (currentIndex.isValid()) {
if (!treeWidget()->isExpanded(currentIndex))
treeWidget()->expand(currentIndex);
diff --git a/src/plugins/qmldesigner/components/navigator/navigatorview.h b/src/plugins/qmldesigner/components/navigator/navigatorview.h
index 852dddc70f..3bafe0fa80 100644
--- a/src/plugins/qmldesigner/components/navigator/navigatorview.h
+++ b/src/plugins/qmldesigner/components/navigator/navigatorview.h
@@ -84,6 +84,8 @@ public:
void bindingPropertiesChanged(const QList<BindingProperty> &propertyList, PropertyChangeFlags) override;
+ void customNotification(const AbstractView *view, const QString &identifier, const QList<ModelNode> &nodeList, const QList<QVariant> &data) override;
+
void handleChangedExport(const ModelNode &modelNode, bool exported);
bool isNodeInvisible(const ModelNode &modelNode) const;
@@ -108,7 +110,7 @@ protected: //functions
QTreeView *treeWidget() const;
NavigatorTreeModel *treeModel();
bool blockSelectionChangedSignal(bool block);
- void expandRecursively(const QModelIndex &index);
+ void expandAncestors(const QModelIndex &index);
void reparentAndCatch(NodeAbstractProperty property, const ModelNode &modelNode);
void setupWidget();
diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp
index 5307bf522b..f097f266e5 100644
--- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp
+++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp
@@ -212,7 +212,6 @@ void PropertyEditorView::changeValue(const QString &name)
}
}
- bool forceReset = false;
if (name == "state" && castedValue.toString() == "base state")
castedValue = "";
diff --git a/src/plugins/qbsprojectmanager/qbsparser.cpp b/src/plugins/qmldesigner/components/richtexteditor/hyperlinkdialog.cpp
index d6b2339dbb..82d24f6839 100644
--- a/src/plugins/qbsprojectmanager/qbsparser.cpp
+++ b/src/plugins/qmldesigner/components/richtexteditor/hyperlinkdialog.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -23,40 +23,47 @@
**
****************************************************************************/
-#include "qbsparser.h"
+#include "hyperlinkdialog.h"
+#include "ui_hyperlinkdialog.h"
-#include <projectexplorer/task.h>
+#include <QPushButton>
-#include <utils/fileutils.h>
+namespace QmlDesigner {
-#include <QFileInfo>
-namespace QbsProjectManager {
-namespace Internal {
-
-QbsParser::QbsParser()
+HyperlinkDialog::HyperlinkDialog(QWidget *parent) :
+ QDialog(parent),
+ ui(new Ui::HyperlinkDialog)
{
- setObjectName(QLatin1String("QbsParser"));
+ ui->setupUi(this);
+ connect (ui->linkEdit, &QLineEdit::textChanged, [this] () {
+ ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!(ui->linkEdit->text().isEmpty()));
+ });
}
-void QbsParser::setWorkingDirectory(const QString &workingDirectory)
+HyperlinkDialog::~HyperlinkDialog()
{
- m_workingDirectory = QDir(workingDirectory);
- IOutputParser::setWorkingDirectory(workingDirectory);
+ delete ui;
}
-void QbsParser::taskAdded(const ProjectExplorer::Task &task, int linkedLines, int skipLines)
+QString HyperlinkDialog::getLink() const
{
- ProjectExplorer::Task editable(task);
-
- QString filePath = task.file.toString();
+ return ui->linkEdit->text().trimmed();
+}
- if (!filePath.isEmpty())
- editable.file = Utils::FilePath::fromUserInput(m_workingDirectory.absoluteFilePath(filePath));
+void HyperlinkDialog::setLink(const QString &link)
+{
+ ui->linkEdit->setText(link);
+}
- IOutputParser::taskAdded(editable, linkedLines, skipLines);
+QString HyperlinkDialog::getAnchor() const
+{
+ return ui->anchorEdit->text().trimmed();
}
-} // namespace Internal
-} // namespace QbsProjectManager
+void HyperlinkDialog::setAnchor(const QString &anchor)
+{
+ ui->anchorEdit->setText(anchor);
+}
+}
diff --git a/src/plugins/qbsprojectmanager/qbsparser.h b/src/plugins/qmldesigner/components/richtexteditor/hyperlinkdialog.h
index 44bfb133ba..dcf8759e49 100644
--- a/src/plugins/qbsprojectmanager/qbsparser.h
+++ b/src/plugins/qmldesigner/components/richtexteditor/hyperlinkdialog.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -25,28 +25,30 @@
#pragma once
-#include "qbsprojectmanager_global.h"
+#include <QDialog>
-#include <projectexplorer/ioutputparser.h>
+namespace QmlDesigner {
-#include <QDir>
+namespace Ui {
+class HyperlinkDialog;
+}
-namespace QbsProjectManager {
-namespace Internal {
-
-class QbsParser : public ProjectExplorer::IOutputParser
+class HyperlinkDialog : public QDialog
{
Q_OBJECT
public:
- explicit QbsParser();
+ explicit HyperlinkDialog(QWidget *parent = nullptr);
+ ~HyperlinkDialog();
-private:
- void setWorkingDirectory(const QString &workingDirectory) override;
- void taskAdded(const ProjectExplorer::Task &task, int linkedLines, int skipLines) override;
+ QString getLink() const;
+ void setLink(const QString &link);
- QDir m_workingDirectory;
+ QString getAnchor() const;
+ void setAnchor(const QString &anchor);
+
+private:
+ Ui::HyperlinkDialog *ui;
};
-} // namespace Internal
-} // namespace QbsProjectManager
+}
diff --git a/src/plugins/qmldesigner/components/richtexteditor/hyperlinkdialog.ui b/src/plugins/qmldesigner/components/richtexteditor/hyperlinkdialog.ui
new file mode 100644
index 0000000000..7906a1fccb
--- /dev/null
+++ b/src/plugins/qmldesigner/components/richtexteditor/hyperlinkdialog.ui
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>QmlDesigner::HyperlinkDialog</class>
+ <widget class="QDialog" name="QmlDesigner::HyperlinkDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>403</width>
+ <height>156</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string notr="true">Dialog</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QFormLayout" name="formLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Link</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="linkEdit"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Anchor</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="anchorEdit"/>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>QmlDesigner::HyperlinkDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>QmlDesigner::HyperlinkDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.cpp b/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.cpp
new file mode 100644
index 0000000000..af04bb676a
--- /dev/null
+++ b/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.cpp
@@ -0,0 +1,684 @@
+/****************************************************************************
+**
+** 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 "richtexteditor.h"
+#include "ui_richtexteditor.h"
+#include "hyperlinkdialog.h"
+
+#include <functional>
+
+#include <QToolButton>
+#include <QAction>
+#include <QStyle>
+#include <QStyleFactory>
+#include <QColorDialog>
+#include <QWidgetAction>
+#include <QTextTable>
+#include <QScopeGuard>
+#include <QPointer>
+
+#include <utils/stylehelper.h>
+
+namespace QmlDesigner {
+
+template <class T>
+class FontWidgetActions : public QWidgetAction {
+public:
+ FontWidgetActions(QObject *parent = nullptr)
+ : QWidgetAction(parent) {}
+
+ ~FontWidgetActions () override {}
+
+ void setInitializer(std::function<void(T*)> func)
+ {
+ m_initializer = func;
+ }
+
+ QList<QWidget *> createdWidgets()
+ {
+ return QWidgetAction::createdWidgets();
+ }
+
+protected:
+ QWidget *createWidget(QWidget *parent) override
+ {
+ T *w = new T(parent);
+ if (m_initializer)
+ m_initializer(w);
+ return w;
+ }
+
+ void deleteWidget(QWidget *widget) override
+ {
+ widget->deleteLater();
+ }
+
+private:
+ std::function<void(T*)> m_initializer;
+};
+
+static void cursorEditBlock(QTextCursor& cursor, std::function<void()> f) {
+ cursor.beginEditBlock();
+ f();
+ cursor.endEditBlock();
+}
+
+RichTextEditor::RichTextEditor(QWidget *parent)
+ : QWidget(parent)
+ , ui(new Ui::RichTextEditor)
+ , m_linkDialog(new HyperlinkDialog(this))
+{
+ ui->setupUi(this);
+ ui->textEdit->setTextInteractionFlags(Qt::TextEditorInteraction | Qt::LinksAccessibleByMouse);
+ ui->tableBar->setVisible(false);
+
+ setupEditActions();
+ setupTextActions();
+ setupHyperlinkActions();
+ setupAlignActions();
+ setupListActions();
+ setupFontActions();
+ setupTableActions();
+
+ connect(ui->textEdit, &QTextEdit::currentCharFormatChanged,
+ this, &RichTextEditor::currentCharFormatChanged);
+ connect(ui->textEdit, &QTextEdit::cursorPositionChanged,
+ this, &RichTextEditor::cursorPositionChanged);
+ connect(m_linkDialog, &QDialog::accepted, [this]() {
+ QTextCharFormat oldFormat = ui->textEdit->textCursor().charFormat();
+
+ QTextCursor tcursor = ui->textEdit->textCursor();
+ QTextCharFormat charFormat = tcursor.charFormat();
+
+ charFormat.setForeground(QApplication::palette().color(QPalette::Link));
+ charFormat.setFontUnderline(true);
+
+ QString link = m_linkDialog->getLink();
+ QString anchor = m_linkDialog->getAnchor();
+
+ if (anchor.isEmpty())
+ anchor = link;
+
+ charFormat.setAnchor(true);
+ charFormat.setAnchorHref(link);
+ charFormat.setAnchorNames(QStringList(anchor));
+
+ tcursor.insertText(anchor, charFormat);
+
+ tcursor.insertText(" ", oldFormat);
+
+ m_linkDialog->hide();
+ });
+
+ ui->textEdit->setFocus();
+ m_linkDialog->hide();
+}
+
+RichTextEditor::~RichTextEditor()
+{
+}
+
+void RichTextEditor::setPlainText(const QString &text)
+{
+ ui->textEdit->setPlainText(text);
+}
+
+QString RichTextEditor::plainText() const
+{
+ return ui->textEdit->toPlainText();
+}
+
+void RichTextEditor::setRichText(const QString &text)
+{
+ ui->textEdit->setHtml(text);
+}
+
+void RichTextEditor::setTabChangesFocus(bool change)
+{
+ ui->textEdit->setTabChangesFocus(change);
+}
+
+QIcon RichTextEditor::getIcon(Theme::Icon icon)
+{
+ const QString fontName = "qtds_propertyIconFont.ttf";
+
+ return Utils::StyleHelper::getIconFromIconFont(fontName, Theme::getIconUnicode(icon), 20, 20);
+}
+
+QString RichTextEditor::richText() const
+{
+ return ui->textEdit->toHtml();
+}
+
+void RichTextEditor::currentCharFormatChanged(const QTextCharFormat &format)
+{
+ fontChanged(format.font());
+ colorChanged(format.foreground().color());
+}
+
+void RichTextEditor::cursorPositionChanged()
+{
+ alignmentChanged(ui->textEdit->alignment());
+ styleChanged(ui->textEdit->textCursor());
+ tableChanged(ui->textEdit->textCursor());
+}
+
+void RichTextEditor::mergeFormatOnWordOrSelection(const QTextCharFormat &format)
+{
+ QTextCursor cursor = ui->textEdit->textCursor();
+ if (!cursor.hasSelection())
+ cursor.select(QTextCursor::WordUnderCursor);
+ cursor.mergeCharFormat(format);
+ ui->textEdit->mergeCurrentCharFormat(format);
+}
+
+void RichTextEditor::fontChanged(const QFont &f)
+{
+ for (QWidget* w: m_fontNameAction->createdWidgets() ) {
+ QFontComboBox* box = qobject_cast<QFontComboBox*>(w);
+ if (box)
+ box->setCurrentFont(f);
+ }
+ for (QWidget* w: m_fontSizeAction->createdWidgets() ) {
+ QComboBox* box = qobject_cast<QComboBox*>(w);
+ if (box)
+ box->setCurrentText(QString::number(f.pointSize()));
+ }
+
+ m_actionTextBold->setChecked(f.bold());
+ m_actionTextItalic->setChecked(f.italic());
+ m_actionTextUnderline->setChecked(f.underline());
+}
+
+void RichTextEditor::colorChanged(const QColor &c)
+{
+ QPixmap colorBox(ui->tableBar->iconSize());
+ colorBox.fill(c);
+ m_actionTextColor->setIcon(colorBox);
+}
+
+void RichTextEditor::alignmentChanged(Qt::Alignment a)
+{
+ if (a & Qt::AlignLeft)
+ m_actionAlignLeft->setChecked(true);
+ else if (a & Qt::AlignHCenter)
+ m_actionAlignCenter->setChecked(true);
+ else if (a & Qt::AlignRight)
+ m_actionAlignRight->setChecked(true);
+ else if (a & Qt::AlignJustify)
+ m_actionAlignJustify->setChecked(true);
+}
+
+void RichTextEditor::styleChanged(const QTextCursor &cursor)
+{
+ if (!m_actionBulletList || !m_actionNumberedList) return;
+
+ QTextList *currentList = cursor.currentList();
+
+ if (currentList) {
+ if (currentList->format().style() == QTextListFormat::ListDisc) {
+ m_actionBulletList->setChecked(true);
+ m_actionNumberedList->setChecked(false);
+ }
+ else if (currentList->format().style() == QTextListFormat::ListDecimal) {
+ m_actionBulletList->setChecked(false);
+ m_actionNumberedList->setChecked(true);
+ }
+ else {
+ m_actionBulletList->setChecked(false);
+ m_actionNumberedList->setChecked(false);
+ }
+ }
+ else {
+ m_actionBulletList->setChecked(false);
+ m_actionNumberedList->setChecked(false);
+ }
+}
+
+void RichTextEditor::tableChanged(const QTextCursor &cursor)
+{
+ if (!m_actionTableSettings) return;
+
+ QTextTable *currentTable = cursor.currentTable();
+
+ if (currentTable) {
+ m_actionTableSettings->setChecked(true);
+ ui->tableBar->setVisible(true);
+
+ setTableActionsActive(true);
+ }
+ else {
+ setTableActionsActive(false);
+ }
+}
+
+void RichTextEditor::setupEditActions()
+{
+ const QIcon undoIcon(getIcon(Theme::Icon::undo));
+ QAction *actionUndo = ui->toolBar->addAction(undoIcon, tr("&Undo"), ui->textEdit, &QTextEdit::undo);
+ actionUndo->setShortcut(QKeySequence::Undo);
+ connect(ui->textEdit->document(), &QTextDocument::undoAvailable,
+ actionUndo, &QAction::setEnabled);
+
+ const QIcon redoIcon(getIcon(Theme::Icon::redo));
+ QAction *actionRedo = ui->toolBar->addAction(redoIcon, tr("&Redo"), ui->textEdit, &QTextEdit::redo);
+ actionRedo->setShortcut(QKeySequence::Redo);
+ connect(ui->textEdit->document(), &QTextDocument::redoAvailable,
+ actionRedo, &QAction::setEnabled);
+
+ actionUndo->setEnabled(ui->textEdit->document()->isUndoAvailable());
+ actionRedo->setEnabled(ui->textEdit->document()->isRedoAvailable());
+
+ ui->toolBar->addSeparator();
+}
+
+void RichTextEditor::setupTextActions()
+{
+ const QIcon boldIcon(getIcon(Theme::Icon::fontStyleBold));
+ m_actionTextBold = ui->toolBar->addAction(boldIcon, tr("&Bold"),
+ [this](bool checked) {
+ QTextCharFormat fmt;
+ fmt.setFontWeight(checked ? QFont::Bold : QFont::Normal);
+ mergeFormatOnWordOrSelection(fmt);
+ });
+ m_actionTextBold->setShortcut(Qt::CTRL + Qt::Key_B);
+ QFont bold;
+ bold.setBold(true);
+ m_actionTextBold->setFont(bold);
+ m_actionTextBold->setCheckable(true);
+
+ const QIcon italicIcon(getIcon(Theme::Icon::fontStyleItalic));
+ m_actionTextItalic = ui->toolBar->addAction(italicIcon, tr("&Italic"),
+ [this](bool checked) {
+ QTextCharFormat fmt;
+ fmt.setFontItalic(checked);
+ mergeFormatOnWordOrSelection(fmt);
+ });
+ m_actionTextItalic->setShortcut(Qt::CTRL + Qt::Key_I);
+ QFont italic;
+ italic.setItalic(true);
+ m_actionTextItalic->setFont(italic);
+ m_actionTextItalic->setCheckable(true);
+
+ const QIcon underlineIcon(getIcon(Theme::Icon::fontStyleUnderline));
+ m_actionTextUnderline = ui->toolBar->addAction(underlineIcon, tr("&Underline"),
+ [this](bool checked) {
+ QTextCharFormat fmt;
+ fmt.setFontUnderline(checked);
+ mergeFormatOnWordOrSelection(fmt);
+ });
+ m_actionTextUnderline->setShortcut(Qt::CTRL + Qt::Key_U);
+ QFont underline;
+ underline.setUnderline(true);
+ m_actionTextUnderline->setFont(underline);
+ m_actionTextUnderline->setCheckable(true);
+
+ ui->toolBar->addSeparator();
+}
+
+void RichTextEditor::setupHyperlinkActions()
+{
+ const QIcon bulletIcon(getIcon(Theme::Icon::actionIconBinding));
+ m_actionHyperlink = ui->toolBar->addAction(bulletIcon, tr("Hyperlink Settings"), [this]() {
+ QTextCursor cursor = ui->textEdit->textCursor();
+ QTextCharFormat linkFormat = cursor.charFormat();
+ if (linkFormat.isAnchor()) {
+ m_linkDialog->setLink(linkFormat.anchorHref());
+ m_linkDialog->setAnchor(linkFormat.anchorName());
+ }
+ else {
+ m_linkDialog->setLink("http://");
+ m_linkDialog->setAnchor("");
+ }
+
+ m_linkDialog->show();
+ });
+ m_actionHyperlink->setCheckable(false);
+
+ ui->toolBar->addSeparator();
+}
+
+void RichTextEditor::setupAlignActions()
+{
+ const QIcon leftIcon(getIcon(Theme::Icon::textAlignLeft));
+ m_actionAlignLeft = ui->toolBar->addAction(leftIcon, tr("&Left"), [this]() { ui->textEdit->setAlignment(Qt::AlignLeft | Qt::AlignAbsolute); });
+ m_actionAlignLeft->setShortcut(Qt::CTRL + Qt::Key_L);
+ m_actionAlignLeft->setCheckable(true);
+ m_actionAlignLeft->setPriority(QAction::LowPriority);
+
+ const QIcon centerIcon(getIcon(Theme::Icon::textAlignCenter));
+ m_actionAlignCenter = ui->toolBar->addAction(centerIcon, tr("C&enter"), [this]() { ui->textEdit->setAlignment(Qt::AlignHCenter); });
+ m_actionAlignCenter->setShortcut(Qt::CTRL + Qt::Key_E);
+ m_actionAlignCenter->setCheckable(true);
+ m_actionAlignCenter->setPriority(QAction::LowPriority);
+
+ const QIcon rightIcon(getIcon(Theme::Icon::textAlignRight));
+ m_actionAlignRight = ui->toolBar->addAction(rightIcon, tr("&Right"), [this]() { ui->textEdit->setAlignment(Qt::AlignRight | Qt::AlignAbsolute); });
+ m_actionAlignRight->setShortcut(Qt::CTRL + Qt::Key_R);
+ m_actionAlignRight->setCheckable(true);
+ m_actionAlignRight->setPriority(QAction::LowPriority);
+
+ const QIcon fillIcon(getIcon(Theme::Icon::textFullJustification));
+ m_actionAlignJustify = ui->toolBar->addAction(fillIcon, tr("&Justify"), [this]() { ui->textEdit->setAlignment(Qt::AlignJustify); });
+ m_actionAlignJustify->setShortcut(Qt::CTRL + Qt::Key_J);
+ m_actionAlignJustify->setCheckable(true);
+ m_actionAlignJustify->setPriority(QAction::LowPriority);
+
+ // Make sure the alignLeft is always left of the alignRight
+ QActionGroup *alignGroup = new QActionGroup(ui->toolBar);
+
+ if (QApplication::isLeftToRight()) {
+ alignGroup->addAction(m_actionAlignLeft);
+ alignGroup->addAction(m_actionAlignCenter);
+ alignGroup->addAction(m_actionAlignRight);
+ } else {
+ alignGroup->addAction(m_actionAlignRight);
+ alignGroup->addAction(m_actionAlignCenter);
+ alignGroup->addAction(m_actionAlignLeft);
+ }
+ alignGroup->addAction(m_actionAlignJustify);
+
+ ui->toolBar->addActions(alignGroup->actions());
+
+ ui->toolBar->addSeparator();
+}
+
+void RichTextEditor::setupListActions()
+{
+ const QIcon bulletIcon(getIcon(Theme::Icon::textBulletList));
+ m_actionBulletList = ui->toolBar->addAction(bulletIcon, tr("Bullet List"), [this](bool checked) {
+ if (checked) {
+ m_actionNumberedList->setChecked(false);
+ textStyle(QTextListFormat::ListDisc);
+ }
+ else if (!m_actionNumberedList->isChecked()) {
+ textStyle(QTextListFormat::ListStyleUndefined);
+ }
+ });
+ m_actionBulletList->setCheckable(true);
+
+ const QIcon numberedIcon(getIcon(Theme::Icon::textNumberedList));
+ m_actionNumberedList = ui->toolBar->addAction(numberedIcon, tr("Numbered List"), [this](bool checked) {
+ if (checked) {
+ m_actionBulletList->setChecked(false);
+ textStyle(QTextListFormat::ListDecimal);
+ }
+ else if (!m_actionBulletList->isChecked()) {
+ textStyle(QTextListFormat::ListStyleUndefined);
+ }
+ });
+ m_actionNumberedList->setCheckable(true);
+
+ ui->toolBar->addSeparator();
+}
+
+void RichTextEditor::setupFontActions()
+{
+ QPixmap colorBox(ui->tableBar->iconSize());
+ colorBox.fill(ui->textEdit->textColor());
+
+ m_actionTextColor = ui->toolBar->addAction(colorBox, tr("&Color..."), [this]() {
+ QColor col = QColorDialog::getColor(ui->textEdit->textColor(), this);
+ if (!col.isValid())
+ return;
+ QTextCharFormat fmt;
+ fmt.setForeground(col);
+ mergeFormatOnWordOrSelection(fmt);
+ colorChanged(col);
+ });
+
+ m_fontNameAction = new FontWidgetActions<QFontComboBox>(this);
+ m_fontNameAction->setInitializer([this](QFontComboBox *w) {
+ if (!w) return;
+
+ w->setCurrentIndex(w->findText(ui->textEdit->currentCharFormat().font().family()));
+ connect(w, QOverload<const QString &>::of(&QComboBox::activated), [this](const QString &f) {
+ QTextCharFormat fmt;
+ fmt.setFontFamily(f);
+ mergeFormatOnWordOrSelection(fmt);
+ });
+ });
+
+ m_fontNameAction->setDefaultWidget(new QFontComboBox);
+ ui->toolBar->addAction(m_fontNameAction);
+
+ m_fontSizeAction = new FontWidgetActions<QComboBox>(this);
+ m_fontSizeAction->setInitializer([this](QComboBox *w) {
+ if (!w) return;
+
+ w->setEditable(true);
+
+ const QList<int> standardSizes = QFontDatabase::standardSizes();
+ foreach (int size, standardSizes)
+ w->addItem(QString::number(size));
+ w->setCurrentText(QString::number(ui->textEdit->currentCharFormat().font().pointSize()));
+ connect(w, QOverload<const QString &>::of(&QComboBox::activated), [this](const QString &p) {
+ qreal pointSize = p.toDouble();
+ if (pointSize > 0.0) {
+ QTextCharFormat fmt;
+ fmt.setFontPointSize(pointSize);
+ mergeFormatOnWordOrSelection(fmt);
+ }
+ });
+ });
+
+ m_fontSizeAction->setDefaultWidget(new QComboBox);
+ ui->toolBar->addAction(m_fontSizeAction);
+
+
+ ui->toolBar->addSeparator();
+}
+
+void RichTextEditor::setupTableActions()
+{
+ const QIcon tableIcon(getIcon(Theme::Icon::addTable));
+ m_actionTableSettings = ui->toolBar->addAction(tableIcon, tr("&Table Settings"), [this](bool checked) {
+ ui->tableBar->setVisible(checked);
+ });
+ m_actionTableSettings->setShortcut(Qt::CTRL + Qt::Key_T);
+ m_actionTableSettings->setCheckable(true);
+ m_actionTableSettings->setPriority(QAction::LowPriority);
+
+//table bar:
+
+ const QIcon createTableIcon(getIcon(Theme::Icon::addTable));
+ m_actionCreateTable = ui->tableBar->addAction(createTableIcon, tr("Create Table"), [this]() {
+ QTextCursor cursor = ui->textEdit->textCursor();
+ cursorEditBlock(cursor, [&] () {
+ cursor.insertTable(1,1);
+ });
+ });
+ m_actionCreateTable->setCheckable(false);
+
+ const QIcon removeTableIcon(getIcon(Theme::Icon::deleteTable));
+ m_actionRemoveTable = ui->tableBar->addAction(removeTableIcon, tr("Remove Table"), [this]() {
+ QTextCursor cursor = ui->textEdit->textCursor();
+ if (QTextTable *currentTable = ui->textEdit->textCursor().currentTable()) {
+ cursorEditBlock(cursor, [&] () {
+ currentTable->removeRows(0, currentTable->rows());
+ });
+ }
+ });
+ m_actionRemoveTable->setCheckable(false);
+
+ ui->tableBar->addSeparator();
+
+ const QIcon addRowIcon(getIcon(Theme::Icon::addRowAfter)); //addRowAfter
+ m_actionAddRow = ui->tableBar->addAction(addRowIcon, tr("Add Row"), [this]() {
+ QTextCursor cursor = ui->textEdit->textCursor();
+ if (QTextTable *currentTable = ui->textEdit->textCursor().currentTable()) {
+ cursorEditBlock(cursor, [&] () {
+ currentTable->insertRows(currentTable->cellAt(cursor).row()+1, 1);
+ });
+ }
+ });
+ m_actionAddRow->setCheckable(false);
+
+ const QIcon addColumnIcon(getIcon(Theme::Icon::addColumnAfter)); //addColumnAfter
+ m_actionAddColumn = ui->tableBar->addAction(addColumnIcon, tr("Add Column"), [this]() {
+ QTextCursor cursor = ui->textEdit->textCursor();
+ if (QTextTable *currentTable = ui->textEdit->textCursor().currentTable()) {
+ cursorEditBlock(cursor, [&] () {
+ currentTable->insertColumns(currentTable->cellAt(cursor).column()+1, 1);
+ });
+ }
+ });
+ m_actionAddColumn->setCheckable(false);
+
+ const QIcon removeRowIcon(getIcon(Theme::Icon::deleteRow));
+ m_actionRemoveRow = ui->tableBar->addAction(removeRowIcon, tr("Remove Row"), [this]() {
+ QTextCursor cursor = ui->textEdit->textCursor();
+ if (QTextTable *currentTable = cursor.currentTable()) {
+ cursorEditBlock(cursor, [&] () {
+ currentTable->insertColumns(currentTable->cellAt(cursor).column()+1, 1);
+
+ int firstRow = 0;
+ int numRows = 0;
+ int firstColumn = 0;
+ int numColumns = 0;
+
+ if (cursor.hasSelection())
+ cursor.selectedTableCells(&firstRow, &numRows, &firstColumn, &numColumns);
+
+ if (numRows < 1)
+ currentTable->removeRows(currentTable->cellAt(cursor).row(), 1);
+ else
+ currentTable->removeRows(firstRow, numRows);
+ });
+ }
+ });
+ m_actionRemoveRow->setCheckable(false);
+
+ const QIcon removeColumnIcon(getIcon(Theme::Icon::deleteColumn));
+ m_actionRemoveColumn = ui->tableBar->addAction(removeColumnIcon, tr("Remove Column"), [this]() {
+ QTextCursor cursor = ui->textEdit->textCursor();
+ if (QTextTable *currentTable = cursor.currentTable()) {
+ cursorEditBlock(cursor, [&] () {
+ int firstRow = 0;
+ int numRows = 0;
+ int firstColumn = 0;
+ int numColumns = 0;
+
+ if (cursor.hasSelection())
+ cursor.selectedTableCells(&firstRow, &numRows, &firstColumn, &numColumns);
+
+ if (numColumns < 1)
+ currentTable->removeColumns(currentTable->cellAt(cursor).column(), 1);
+ else
+ currentTable->removeColumns(firstColumn, numColumns);
+ });
+ }
+ });
+ m_actionRemoveColumn->setCheckable(false);
+
+ ui->tableBar->addSeparator();
+
+ const QIcon mergeCellsIcon(getIcon(Theme::Icon::mergeCells));
+ m_actionMergeCells = ui->tableBar->addAction(mergeCellsIcon, tr("Merge Cells"), [this]() {
+ QTextCursor cursor = ui->textEdit->textCursor();
+ if (QTextTable *currentTable = cursor.currentTable()) {
+ if (cursor.hasSelection()) {
+ cursorEditBlock(cursor, [&] () {
+ currentTable->mergeCells(cursor);
+ });
+ }
+ }
+ });
+ m_actionMergeCells->setCheckable(false);
+
+ const QIcon splitRowIcon(getIcon(Theme::Icon::splitRows));
+ m_actionSplitRow = ui->tableBar->addAction(splitRowIcon, tr("Split Row"), [this]() {
+ QTextCursor cursor = ui->textEdit->textCursor();
+ if (QTextTable *currentTable = cursor.currentTable()) {
+ cursorEditBlock(cursor, [&] () {
+ currentTable->splitCell(currentTable->cellAt(cursor).row(),
+ currentTable->cellAt(cursor).column(),
+ 2, 1);
+ });
+ }
+ });
+ m_actionSplitRow->setCheckable(false);
+
+ const QIcon splitColumnIcon(getIcon(Theme::Icon::splitColumns));
+ m_actionSplitColumn = ui->tableBar->addAction(splitRowIcon, tr("Split Column"), [this]() {
+ QTextCursor cursor = ui->textEdit->textCursor();
+ if (QTextTable *currentTable = cursor.currentTable()) {
+ cursorEditBlock(cursor, [&] () {
+ currentTable->splitCell(currentTable->cellAt(cursor).row(),
+ currentTable->cellAt(cursor).column(),
+ 1, 2);
+ });
+ }
+ });
+ m_actionSplitColumn->setCheckable(false);
+}
+
+void RichTextEditor::textStyle(QTextListFormat::Style style)
+{
+ QTextCursor cursor = ui->textEdit->textCursor();
+ cursorEditBlock(cursor, [&] () {
+ if (style != QTextListFormat::ListStyleUndefined) {
+ QTextBlockFormat blockFmt = cursor.blockFormat();
+ QTextListFormat listFmt;
+
+ if (cursor.currentList()) {
+ listFmt = cursor.currentList()->format();
+ } else {
+ listFmt.setIndent(blockFmt.indent() + 1);
+ blockFmt.setIndent(0);
+ cursor.setBlockFormat(blockFmt);
+ }
+
+ listFmt.setStyle(style);
+
+ cursor.createList(listFmt);
+ } else {
+ QTextList* currentList = cursor.currentList();
+ QTextBlock currentBlock = cursor.block();
+ currentList->remove(currentBlock);
+
+ QTextBlockFormat blockFormat = cursor.blockFormat();
+ blockFormat.setIndent(0);
+ cursor.setBlockFormat(blockFormat);
+ }
+ });
+}
+
+void RichTextEditor::setTableActionsActive(bool active)
+{
+ m_actionCreateTable->setEnabled(!active);
+ m_actionRemoveTable->setEnabled(active);
+
+ m_actionAddRow->setEnabled(active);
+ m_actionAddColumn->setEnabled(active);
+ m_actionRemoveRow->setEnabled(active);
+ m_actionRemoveColumn->setEnabled(active);
+
+ m_actionMergeCells->setEnabled(active);
+ m_actionSplitRow->setEnabled(active);
+ m_actionSplitColumn->setEnabled(active);
+}
+
+}
diff --git a/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.h b/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.h
new file mode 100644
index 0000000000..50053c1ab3
--- /dev/null
+++ b/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.h
@@ -0,0 +1,130 @@
+/****************************************************************************
+**
+** 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 <theme.h>
+
+#include <QWidget>
+#include <QToolBar>
+#include <QList>
+#include <QTextCharFormat>
+#include <QTextList>
+#include <QFontComboBox>
+#include <QWidgetAction>
+#include <QPointer>
+
+namespace QmlDesigner {
+
+namespace Ui {
+class RichTextEditor;
+}
+
+template <class>
+class FontWidgetActions;
+
+class HyperlinkDialog;
+
+class RichTextEditor : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit RichTextEditor(QWidget *parent = nullptr);
+ ~RichTextEditor();
+
+ void setPlainText(const QString &text);
+ QString plainText() const;
+
+ void setRichText(const QString &text);
+ QString richText() const;
+
+ void setTabChangesFocus(bool change);
+
+private slots:
+ void currentCharFormatChanged(const QTextCharFormat &format);
+ void cursorPositionChanged();
+
+private:
+ QIcon getIcon(Theme::Icon icon);
+ void mergeFormatOnWordOrSelection(const QTextCharFormat &format);
+
+ void fontChanged(const QFont &f);
+ void colorChanged(const QColor &c);
+ void alignmentChanged(Qt::Alignment a);
+ void styleChanged(const QTextCursor &cursor);
+ void tableChanged(const QTextCursor &cursor);
+
+ void setupEditActions();
+ void setupTextActions();
+ void setupHyperlinkActions();
+ void setupAlignActions();
+ void setupListActions();
+ void setupFontActions();
+ void setupTableActions();
+
+ void textStyle(QTextListFormat::Style style);
+
+ void setTableActionsActive(bool active); //switches between "has table/has no table" ui setup
+
+private:
+ QScopedPointer<Ui::RichTextEditor> ui;
+ QPointer<HyperlinkDialog> m_linkDialog;
+
+ QAction *m_actionTextBold;
+ QAction *m_actionTextItalic;
+ QAction *m_actionTextUnderline;
+
+ QAction *m_actionHyperlink;
+
+ QAction *m_actionAlignLeft;
+ QAction *m_actionAlignCenter;
+ QAction *m_actionAlignRight;
+ QAction *m_actionAlignJustify;
+
+ QAction *m_actionTextColor;
+
+ QAction *m_actionBulletList;
+ QAction *m_actionNumberedList;
+
+ QAction *m_actionTableSettings;
+
+ QAction *m_actionCreateTable;
+ QAction *m_actionRemoveTable;
+
+ QAction *m_actionAddRow;
+ QAction *m_actionAddColumn;
+ QAction *m_actionRemoveRow;
+ QAction *m_actionRemoveColumn;
+
+ QAction *m_actionMergeCells;
+ QAction *m_actionSplitRow;
+ QAction *m_actionSplitColumn;
+
+ QPointer<FontWidgetActions<QFontComboBox>> m_fontNameAction;
+ QPointer<FontWidgetActions<QComboBox>> m_fontSizeAction;
+};
+
+} //namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.pri b/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.pri
new file mode 100644
index 0000000000..68b6dbe026
--- /dev/null
+++ b/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.pri
@@ -0,0 +1,8 @@
+HEADERS += $$PWD/richtexteditor.h
+HEADERS += $$PWD/hyperlinkdialog.h
+
+SOURCES += $$PWD/richtexteditor.cpp
+SOURCES += $$PWD/hyperlinkdialog.cpp
+
+FORMS += $$PWD/richtexteditor.ui
+FORMS += $$PWD/hyperlinkdialog.ui
diff --git a/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.ui b/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.ui
new file mode 100644
index 0000000000..3c21f9147f
--- /dev/null
+++ b/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.ui
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>QmlDesigner::RichTextEditor</class>
+ <widget class="QWidget" name="QmlDesigner::RichTextEditor">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>428</width>
+ <height>283</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>5</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="windowTitle">
+ <string notr="true">Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QToolBar" name="toolBar">
+ <property name="iconSize">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolBar" name="tableBar">
+ <property name="iconSize">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTextEdit" name="textEdit"/>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/qmldesigner/components/timelineeditor/easingcurvedialog.cpp b/src/plugins/qmldesigner/components/timelineeditor/easingcurvedialog.cpp
index 91ab233900..be33e7c1cb 100644
--- a/src/plugins/qmldesigner/components/timelineeditor/easingcurvedialog.cpp
+++ b/src/plugins/qmldesigner/components/timelineeditor/easingcurvedialog.cpp
@@ -204,7 +204,7 @@ bool EasingCurveDialog::apply()
}
AbstractView *view = m_frames.first().view();
- return view->executeInTransaction("EasingCurveDialog::apply", [this, view](){
+ return view->executeInTransaction("EasingCurveDialog::apply", [this](){
auto expression = m_splineEditor->easingCurve().toString();
for (const auto &frame : m_frames)
frame.bindingProperty("easing.bezierCurve").setExpression(expression);
diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.cpp
index 098fe766a0..d399eb1952 100644
--- a/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.cpp
+++ b/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.cpp
@@ -58,6 +58,7 @@
#include <QSlider>
#include <QVBoxLayout>
#include <QtGlobal>
+#include <QSpacerItem>
namespace QmlDesigner {
@@ -118,6 +119,7 @@ TimelineWidget::TimelineWidget(TimelineView *view)
, m_timelineView(view)
, m_graphicsScene(new TimelineGraphicsScene(this))
, m_addButton(new QPushButton(this))
+ , m_onboardingContainer(new QWidget(this))
{
setWindowTitle(tr("Timeline", "Title of timeline view"));
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
@@ -185,6 +187,50 @@ TimelineWidget::TimelineWidget(TimelineView *view)
m_addButton->setFlat(true);
m_addButton->setFixedSize(32, 32);
+
+ widgetLayout->addWidget(m_onboardingContainer);
+
+ auto *onboardingTopLabel = new QLabel(m_onboardingContainer);
+ auto *onboardingBottomLabel = new QLabel(m_onboardingContainer);
+ auto *onboardingBottomIcon = new QLabel(m_onboardingContainer);
+
+ auto *onboardingLayout = new QVBoxLayout;
+ auto *onboardingSublayout = new QHBoxLayout;
+ auto *leftSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
+ auto *rightSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
+ auto *topSpacer = new QSpacerItem(40, 20, QSizePolicy::Minimum, QSizePolicy::Expanding);
+ auto *bottomSpacer = new QSpacerItem(40, 20, QSizePolicy::Minimum, QSizePolicy::Expanding);
+
+ QString labelText =
+ tr("This file does not contain a timeline. <br><br> \
+ To create an animation, add a timeline by clicking the + button.");
+ onboardingTopLabel->setText(labelText);
+ onboardingTopLabel->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
+
+ m_onboardingContainer->setLayout(onboardingLayout);
+ onboardingLayout->setContentsMargins(0, 0, 0, 0);
+ onboardingLayout->setSpacing(0);
+ onboardingLayout->addSpacerItem(topSpacer);
+ onboardingLayout->addWidget(onboardingTopLabel);
+ onboardingLayout->addLayout(onboardingSublayout);
+
+ onboardingSublayout->setContentsMargins(0, 0, 0, 0);
+ onboardingSublayout->setSpacing(0);
+ onboardingSublayout->addSpacerItem(leftSpacer);
+
+ onboardingBottomLabel->setAlignment(Qt::AlignRight | Qt::AlignTop);
+ onboardingBottomLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+ onboardingSublayout->addWidget(onboardingBottomLabel);
+ onboardingBottomLabel->setText(tr("To edit the timeline settings, click "));
+
+ onboardingBottomIcon->setAlignment(Qt::AlignLeft | Qt::AlignTop);
+ onboardingBottomIcon->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+ onboardingSublayout->addWidget(onboardingBottomIcon);
+ onboardingBottomIcon->setPixmap(TimelineIcons::ANIMATION.pixmap());
+
+ onboardingSublayout->addSpacerItem(rightSpacer);
+ onboardingLayout->addSpacerItem(bottomSpacer);
+
widgetLayout->addLayout(contentLayout);
this->setLayout(widgetLayout);
@@ -532,6 +578,7 @@ void TimelineWidget::setTimelineActive(bool b)
m_rulerView->setVisible(true);
m_scrollbar->setVisible(true);
m_addButton->setVisible(false);
+ m_onboardingContainer->setVisible(false);
m_graphicsView->update();
m_rulerView->update();
} else {
@@ -540,6 +587,7 @@ void TimelineWidget::setTimelineActive(bool b)
m_rulerView->setVisible(false);
m_scrollbar->setVisible(false);
m_addButton->setVisible(true);
+ m_onboardingContainer->setVisible(true);
}
}
diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.h b/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.h
index 681181dbe9..4d0e4711cb 100644
--- a/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.h
+++ b/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.h
@@ -104,6 +104,8 @@ private:
TimelineGraphicsScene *m_graphicsScene;
QPushButton *m_addButton = nullptr;
+
+ QWidget *m_onboardingContainer = nullptr;
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/filemanager/changeimportsvisitor.cpp b/src/plugins/qmldesigner/designercore/filemanager/changeimportsvisitor.cpp
index a35ff98ef4..cc82a5607e 100644
--- a/src/plugins/qmldesigner/designercore/filemanager/changeimportsvisitor.cpp
+++ b/src/plugins/qmldesigner/designercore/filemanager/changeimportsvisitor.cpp
@@ -85,10 +85,25 @@ bool ChangeImportsVisitor::remove(QmlJS::AST::UiProgram *ast, const Import &impo
bool ChangeImportsVisitor::equals(QmlJS::AST::UiImport *ast, const Import &import)
{
+ bool equal = false;
if (import.isLibraryImport())
- return toString(ast->importUri) == import.url();
+ equal = toString(ast->importUri) == import.url();
else if (import.isFileImport())
- return ast->fileName == import.file();
- else
- return false;
+ equal = ast->fileName == import.file();
+
+ if (equal) {
+ equal = (!ast->version || (ast->version->minorVersion == 0 && ast->version->majorVersion == 0))
+ && import.version().isEmpty();
+ if (!equal && ast->version) {
+ const QStringList versions = import.version().split('.');
+ if (versions.size() >= 1 && versions[0].toInt() == ast->version->majorVersion) {
+ if (versions.size() >= 2)
+ equal = versions[1].toInt() == ast->version->minorVersion;
+ else
+ equal = ast->version->minorVersion == 0;
+ }
+ }
+ }
+
+ return equal;
}
diff --git a/src/plugins/qmldesigner/designercore/include/annotation.h b/src/plugins/qmldesigner/designercore/include/annotation.h
index 95fcf81fa2..2b7c64bb4a 100644
--- a/src/plugins/qmldesigner/designercore/include/annotation.h
+++ b/src/plugins/qmldesigner/designercore/include/annotation.h
@@ -35,6 +35,7 @@ namespace QmlDesigner {
static const PropertyName customIdProperty = {("customId")};
static const PropertyName annotationProperty = {("annotation")};
+static const PropertyName globalAnnotationProperty = {("globalAnnotation")};
class Comment
{
diff --git a/src/plugins/qmldesigner/designercore/include/modelnode.h b/src/plugins/qmldesigner/designercore/include/modelnode.h
index ac65de0240..85302ad2c4 100644
--- a/src/plugins/qmldesigner/designercore/include/modelnode.h
+++ b/src/plugins/qmldesigner/designercore/include/modelnode.h
@@ -202,6 +202,11 @@ public:
void setAnnotation(const Annotation &annotation);
void removeAnnotation();
+ Annotation globalAnnotation() const;
+ bool hasGlobalAnnotation() const;
+ void setGlobalAnnotation(const Annotation &annotation);
+ void removeGlobalAnnotation();
+
qint32 internalId() const;
void setNodeSource(const QString&);
diff --git a/src/plugins/qmldesigner/designercore/include/qmlitemnode.h b/src/plugins/qmldesigner/designercore/include/qmlitemnode.h
index ef8f1b28ba..d779cc15bf 100644
--- a/src/plugins/qmldesigner/designercore/include/qmlitemnode.h
+++ b/src/plugins/qmldesigner/designercore/include/qmlitemnode.h
@@ -182,8 +182,13 @@ public:
const QList<ModelNode> wildcards() const;
const QList<ModelNode> decicions() const;
QList<ModelNode> transitionsForTarget(const ModelNode &modelNode);
+ QList<ModelNode> transitionsForSource(const ModelNode &modelNode);
void removeDanglingTransitions();
void removeAllTransitions();
+ void setStartFlowItem(const QmlFlowItemNode &flowItem);
+ ModelNode createTransition();
+protected:
+ QList<ModelNode> transitionsForProperty(const PropertyName &propertyName, const ModelNode &modelNode);
};
diff --git a/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp b/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp
index f480e9bb97..0688ebde6e 100644
--- a/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp
+++ b/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp
@@ -68,6 +68,8 @@
static Q_LOGGING_CATEGORY(puppetStart, "qtc.puppet.start", QtWarningMsg)
static Q_LOGGING_CATEGORY(puppetBuild, "qtc.puppet.build", QtWarningMsg)
+using namespace ProjectExplorer;
+
namespace QmlDesigner {
class EventFilter : public QObject {
@@ -532,11 +534,7 @@ QString PuppetCreator::buildCommand() const
Utils::Environment environment = Utils::Environment::systemEnvironment();
m_target->kit()->addToEnvironment(environment);
- ProjectExplorer::ToolChain *toolChain
- = ProjectExplorer::ToolChainKitAspect::toolChain(m_target->kit(),
- ProjectExplorer::Constants::CXX_LANGUAGE_ID);
-
- if (toolChain)
+ if (ToolChain *toolChain = ToolChainKitAspect::cxxToolChain(m_target->kit()))
return toolChain->makeCommand(environment).toString();
return QString();
diff --git a/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp b/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp
index ff65187f46..b4b043847e 100644
--- a/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp
+++ b/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp
@@ -420,8 +420,7 @@ void SubComponentManager::parseQuick3DAssetDir(const QString &assetPath)
itemLibraryEntry.addHints(hints);
}
- if (!model()->metaInfo().itemLibraryInfo()->containsEntry(itemLibraryEntry))
- model()->metaInfo().itemLibraryInfo()->addEntries({itemLibraryEntry});
+ model()->metaInfo().itemLibraryInfo()->addEntries({itemLibraryEntry}, true);
}
}
}
diff --git a/src/plugins/qmldesigner/designercore/model/modelnode.cpp b/src/plugins/qmldesigner/designercore/model/modelnode.cpp
index 61d0f93cf5..1d1a5386f2 100644
--- a/src/plugins/qmldesigner/designercore/model/modelnode.cpp
+++ b/src/plugins/qmldesigner/designercore/model/modelnode.cpp
@@ -1150,6 +1150,35 @@ void ModelNode::removeAnnotation()
}
}
+Annotation ModelNode::globalAnnotation() const
+{
+ Annotation result;
+ ModelNode root = view()->rootModelNode();
+
+ if (hasGlobalAnnotation())
+ result.fromQString(root.auxiliaryData(globalAnnotationProperty).value<QString>());
+
+ return result;
+}
+
+bool ModelNode::hasGlobalAnnotation() const
+{
+ return view()->rootModelNode().hasAuxiliaryData(globalAnnotationProperty);
+}
+
+void ModelNode::setGlobalAnnotation(const Annotation &annotation)
+{
+ view()->rootModelNode().setAuxiliaryData(globalAnnotationProperty,
+ QVariant::fromValue<QString>(annotation.toQString()));
+}
+
+void ModelNode::removeGlobalAnnotation()
+{
+ if (hasGlobalAnnotation()) {
+ view()->rootModelNode().removeAuxiliaryData(globalAnnotationProperty);
+ }
+}
+
void ModelNode::setScriptFunctions(const QStringList &scriptFunctionList)
{
model()->d->setScriptFunctions(internalNode(), scriptFunctionList);
diff --git a/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp b/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp
index 098f8317a5..023a09ec03 100644
--- a/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp
+++ b/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp
@@ -628,7 +628,7 @@ ModelNode QmlFlowActionAreaNode::decisionNodeForTransition(const ModelNode &tran
}
QmlFlowViewNode flowView(view()->rootModelNode());
if (flowView.isValid()) {
- for (const ModelNode target : flowView.decicions()) {
+ for (const ModelNode &target : flowView.decicions()) {
if (target.hasBindingProperty("targets")
&& target.bindingProperty("targets").resolveToModelNodeList().contains(transition))
return target;
@@ -664,9 +664,7 @@ QList<QmlFlowItemNode> QmlFlowViewNode::flowItems() const
ModelNode QmlFlowViewNode::addTransition(const QmlFlowTargetNode &from, const QmlFlowTargetNode &to)
{
- ModelNode transition = view()->createModelNode("FlowView.FlowTransition", 1, 0);
-
- nodeListProperty("flowTransitions").reparentHere(transition);
+ ModelNode transition = createTransition();
QmlFlowTargetNode f = from;
QmlFlowTargetNode t = to;
@@ -684,8 +682,6 @@ const QList<ModelNode> QmlFlowViewNode::transitions() const
return modelNode().nodeListProperty("flowTransitions").toModelNodeList();
return {};
-
-
}
const QList<ModelNode> QmlFlowViewNode::wildcards() const
@@ -706,13 +702,12 @@ const QList<ModelNode> QmlFlowViewNode::decicions() const
QList<ModelNode> QmlFlowViewNode::transitionsForTarget(const ModelNode &modelNode)
{
- QList<ModelNode> list;
- for (const ModelNode &transition : transitions()) {
- if (transition.hasBindingProperty("to")
- && transition.bindingProperty("to").resolveToModelNode() == modelNode)
- list.append(transition);
- }
- return list;
+ return transitionsForProperty("to", modelNode);
+}
+
+QList<ModelNode> QmlFlowViewNode::transitionsForSource(const ModelNode &modelNode)
+{
+ return transitionsForProperty("from", modelNode);
}
void QmlFlowViewNode::removeDanglingTransitions()
@@ -787,7 +782,7 @@ ModelNode QmlFlowTargetNode::findSourceForDecisionNode() const
if (!isFlowDecision())
return {};
- for (const ModelNode transition : flowView().transitionsForTarget(modelNode())) {
+ for (const ModelNode &transition : flowView().transitionsForTarget(modelNode())) {
if (transition.hasBindingProperty("from")) {
const ModelNode source = transition.bindingProperty("from").resolveToModelNode();
if (source.isValid()) {
@@ -830,4 +825,41 @@ void QmlFlowViewNode::removeAllTransitions()
removeProperty("flowTransitions");
}
+void QmlFlowViewNode::setStartFlowItem(const QmlFlowItemNode &flowItem)
+{
+ QTC_ASSERT(flowItem.isValid(), return);
+ QmlFlowItemNode item = flowItem;
+
+ ModelNode transition;
+
+ for (const ModelNode &node : transitionsForSource(modelNode()))
+ transition = node;
+ if (!transition.isValid())
+ transition = createTransition();
+
+ transition.bindingProperty("from").setExpression(modelNode().validId());
+ transition.bindingProperty("to").setExpression(item.validId());
+}
+
+ModelNode QmlFlowViewNode::createTransition()
+{
+ ModelNode transition = view()->createModelNode("FlowView.FlowTransition", 1, 0);
+ nodeListProperty("flowTransitions").reparentHere(transition);
+
+ return transition;
+}
+
+QList<ModelNode> QmlFlowViewNode::transitionsForProperty(const PropertyName &propertyName,
+ const ModelNode &modelNode)
+{
+ QList<ModelNode> list;
+ for (const ModelNode &transition : transitions()) {
+ if (transition.hasBindingProperty(propertyName)
+ && transition.bindingProperty(propertyName).resolveToModelNode() == modelNode)
+ list.append(transition);
+ }
+ return list;
+
+}
+
} //QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp
index 41bc1944ca..fd0d9a51ff 100644
--- a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp
+++ b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp
@@ -91,7 +91,12 @@ QStringList globalQtEnums()
"Horizontal", "Vertical", "AlignVCenter", "AlignLeft", "LeftToRight", "RightToLeft",
"AlignHCenter", "AlignRight", "AlignBottom", "AlignBaseline", "AlignTop", "BottomLeft",
"LeftEdge", "RightEdge", "BottomEdge", "TopEdge", "TabFocus", "ClickFocus", "StrongFocus",
- "WheelFocus", "NoFocus"
+ "WheelFocus", "NoFocus", "ArrowCursor", "UpArrowCursor", "CrossCursor", "WaitCursor",
+ "IBeamCursor", "SizeVerCursor", "SizeHorCursor", "SizeBDiagCursor", "SizeFDiagCursor",
+ "SizeAllCursor", "BlankCursor", "SplitVCursor", "SplitHCursor", "PointingHandCursor",
+ "ForbiddenCursor", "WhatsThisCursor", "BusyCursor", "OpenHandCursor", "ClosedHandCursor",
+ "DragCopyCursor", "DragMoveCursor", "DragLinkCursor", "TopToBottom",
+ "LeftButton", "RightButton", "MiddleButton", "BackButton", "ForwardButton", "AllButtons"
};
return list;
@@ -101,7 +106,7 @@ QStringList knownEnumScopes()
{
static const QStringList list = {
"TextInput", "TextEdit", "Material", "Universal", "Font", "Shape", "ShapePath",
- "AbstractButton", "Text", "ShaderEffectSource"
+ "AbstractButton", "Text", "ShaderEffectSource", "Grid"
};
return list;
}
diff --git a/src/plugins/qmldesigner/designmodewidget.cpp b/src/plugins/qmldesigner/designmodewidget.cpp
index d9db2ea006..379e225b60 100644
--- a/src/plugins/qmldesigner/designmodewidget.cpp
+++ b/src/plugins/qmldesigner/designmodewidget.cpp
@@ -60,6 +60,7 @@
#include <utils/algorithm.h>
#include <utils/fileutils.h>
#include <utils/qtcassert.h>
+#include <utils/stylehelper.h>
#include <QSettings>
#include <QToolBar>
@@ -70,6 +71,7 @@
#include <advanceddockingsystem/dockareawidget.h>
#include <advanceddockingsystem/docksplitter.h>
+#include <advanceddockingsystem/iconprovider.h>
using Core::MiniSplitter;
using Core::IEditor;
@@ -227,14 +229,34 @@ void DesignModeWidget::setup()
QString sheet = QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/dockwidgets.css"));
m_dockManager->setStyleSheet(Theme::replaceCssColors(sheet));
+ // Setup icons
+ QColor buttonColor(Theme::getColor(Theme::QmlDesigner_TabLight)); // TODO Use correct color roles
+ QColor tabColor(Theme::getColor(Theme::QmlDesigner_TabDark));
+
+ const QString closeUnicode = Theme::getIconUnicode(Theme::Icon::adsClose);
+ const QString menuUnicode = Theme::getIconUnicode(Theme::Icon::adsDropDown);
+ const QString undockUnicode = Theme::getIconUnicode(Theme::Icon::adsDetach);
+
+ const QString fontName = "qtds_propertyIconFont.ttf";
+ const QIcon tabsCloseIcon = Utils::StyleHelper::getIconFromIconFont(fontName, closeUnicode, 28, 28, tabColor);
+ const QIcon menuIcon = Utils::StyleHelper::getIconFromIconFont(fontName, menuUnicode, 28, 28, buttonColor);
+ const QIcon undockIcon = Utils::StyleHelper::getIconFromIconFont(fontName, undockUnicode, 28, 28, buttonColor);
+ const QIcon closeIcon = Utils::StyleHelper::getIconFromIconFont(fontName, closeUnicode, 28, 28, buttonColor);
+
+ m_dockManager->iconProvider().registerCustomIcon(ADS::TabCloseIcon, tabsCloseIcon);
+ m_dockManager->iconProvider().registerCustomIcon(ADS::DockAreaMenuIcon, menuIcon);
+ m_dockManager->iconProvider().registerCustomIcon(ADS::DockAreaUndockIcon, undockIcon);
+ m_dockManager->iconProvider().registerCustomIcon(ADS::DockAreaCloseIcon, closeIcon);
+ m_dockManager->iconProvider().registerCustomIcon(ADS::FloatingWidgetCloseIcon, closeIcon);
+
// Setup Actions and Menus
- Core::ActionContainer *mwindow = Core::ActionManager::actionContainer(Core::Constants::M_WINDOW);
+ Core::ActionContainer *mview = Core::ActionManager::actionContainer(Core::Constants::M_VIEW);
// Window > Views
- Core::ActionContainer *mviews = Core::ActionManager::actionContainer(Core::Constants::M_WINDOW_VIEWS);
+ Core::ActionContainer *mviews = Core::ActionManager::createMenu(Core::Constants::M_VIEW_VIEWS);
mviews->menu()->addSeparator();
// Window > Workspaces
Core::ActionContainer *mworkspaces = Core::ActionManager::createMenu(QmlDesigner::Constants::M_WINDOW_WORKSPACES);
- mwindow->addMenu(mworkspaces, Core::Constants::G_WINDOW_VIEWS);
+ mview->addMenu(mworkspaces, Core::Constants::G_VIEW_VIEWS);
mworkspaces->menu()->setTitle(tr("&Workspaces"));
mworkspaces->setOnAllDisabledBehavior(Core::ActionContainer::Show);
// Connect opening of the 'workspaces' menu with creation of the workspaces menu
@@ -409,6 +431,19 @@ void DesignModeWidget::setup()
m_dockManager->openWorkspace(workspaceComboBox->currentText());
});
+ const QIcon gaIcon = Utils::StyleHelper::getIconFromIconFont(fontName,
+ Theme::getIconUnicode(Theme::Icon::annotationBubble), 36, 36);
+ toolBar->addAction(gaIcon, tr("Edit global annotation for current file."), [&](){
+ ModelNode node = currentDesignDocument()->rewriterView()->rootModelNode();
+
+ if (node.isValid()) {
+ m_globalAnnotationEditor.setModelNode(node);
+ m_globalAnnotationEditor.showWidget();
+ }
+ });
+
+
+
viewManager().enableWidgets();
readSettings();
show();
diff --git a/src/plugins/qmldesigner/designmodewidget.h b/src/plugins/qmldesigner/designmodewidget.h
index 8e44ce8c49..67f8f3d554 100644
--- a/src/plugins/qmldesigner/designmodewidget.h
+++ b/src/plugins/qmldesigner/designmodewidget.h
@@ -36,6 +36,7 @@
#include <QScopedPointer>
#include <advanceddockingsystem/dockmanager.h>
+#include <annotationeditor/globalannotationeditor.h>
namespace Core {
class SideBar;
@@ -120,6 +121,7 @@ private: // variables
ADS::DockManager *m_dockManager = nullptr;
ADS::DockWidget *m_outputPaneDockWidget = nullptr;
+ GlobalAnnotationEditor m_globalAnnotationEditor;
};
} // namespace Internal
diff --git a/src/plugins/qmldesigner/qmldesigner.qbs b/src/plugins/qmldesigner/qmldesigner.qbs
index e46eec6f91..d9ff0b56c5 100644
--- a/src/plugins/qmldesigner/qmldesigner.qbs
+++ b/src/plugins/qmldesigner/qmldesigner.qbs
@@ -6,5 +6,6 @@ Project {
"qmldesignerplugin.qbs",
"qtquickplugin/qtquickplugin.qbs",
"componentsplugin/componentsplugin.qbs",
+ "qmlpreviewplugin/qmlpreviewplugin.qbs",
]
}
diff --git a/src/plugins/qmldesigner/qmldesignerplugin.cpp b/src/plugins/qmldesigner/qmldesignerplugin.cpp
index a65ff3600b..21d1ffadf2 100644
--- a/src/plugins/qmldesigner/qmldesignerplugin.cpp
+++ b/src/plugins/qmldesigner/qmldesignerplugin.cpp
@@ -38,6 +38,7 @@
#include <sourcetool/sourcetool.h>
#include <colortool/colortool.h>
#include <annotationeditor/annotationtool.h>
+#include <formeditor/transitiontool.h>
#include <texttool/texttool.h>
#include <timelineeditor/timelineview.h>
#include <pathtool/pathtool.h>
@@ -216,6 +217,11 @@ bool QmlDesignerPlugin::initialize(const QStringList & /*arguments*/, QString *e
if (DesignerSettings::getValue(DesignerSettingsKey::STANDALONE_MODE).toBool())
GenerateResource::generateMenuEntry();
+ QString fontPath = Core::ICore::resourcePath() +
+ QStringLiteral("/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf");
+ if (QFontDatabase::addApplicationFont(fontPath) < 0)
+ qCWarning(qmldesignerLog) << "Could not add font " << fontPath << "to font database";
+
return true;
}
@@ -242,6 +248,7 @@ bool QmlDesignerPlugin::delayedInitialize()
d->viewManager.registerFormEditorToolTakingOwnership(new QmlDesigner::AnnotationTool);
d->viewManager.registerFormEditorToolTakingOwnership(new QmlDesigner::TextTool);
d->viewManager.registerFormEditorToolTakingOwnership(new QmlDesigner::PathTool);
+ d->viewManager.registerFormEditorToolTakingOwnership(new QmlDesigner::TransitionTool);
return true;
}
diff --git a/src/plugins/qmldesigner/qmldesignerplugin.pro b/src/plugins/qmldesigner/qmldesignerplugin.pro
index ea017e3cef..0095aa8f10 100644
--- a/src/plugins/qmldesigner/qmldesignerplugin.pro
+++ b/src/plugins/qmldesigner/qmldesignerplugin.pro
@@ -31,6 +31,7 @@ include(components/connectioneditor/connectioneditor.pri)
include(components/curveeditor/curveeditor.pri)
include(components/bindingeditor/bindingeditor.pri)
include(components/annotationeditor/annotationeditor.pri)
+include(components/richtexteditor/richtexteditor.pri)
BUILD_PUPPET_IN_CREATOR_BINPATH = $$(BUILD_PUPPET_IN_CREATOR_BINPATH)
diff --git a/src/plugins/qmldesigner/qmldesignerplugin.qbs b/src/plugins/qmldesigner/qmldesignerplugin.qbs
index 3c434788cd..dbbdb1079a 100644
--- a/src/plugins/qmldesigner/qmldesignerplugin.qbs
+++ b/src/plugins/qmldesigner/qmldesignerplugin.qbs
@@ -530,6 +530,8 @@ Project {
"formeditor/toolbox.h",
"formeditor/formeditortoolbutton.cpp",
"formeditor/formeditortoolbutton.h",
+ "formeditor/transitiontool.cpp",
+ "formeditor/transitiontool.h",
"importmanager/importlabel.cpp",
"importmanager/importlabel.h",
"importmanager/importmanagercombobox.cpp",
@@ -654,6 +656,8 @@ Project {
"annotationeditor/annotationcommenttab.ui",
"annotationeditor/annotationeditor.cpp",
"annotationeditor/annotationeditor.h",
+ "annotationeditor/globalannotationeditor.cpp",
+ "annotationeditor/globalannotationeditor.h",
"annotationeditor/annotationeditordialog.cpp",
"annotationeditor/annotationeditordialog.h",
"annotationeditor/annotationeditordialog.ui",
@@ -746,6 +750,12 @@ Project {
"pathtool/pathtool.h",
"pathtool/pathtoolview.cpp",
"pathtool/pathtoolview.h",
+ "richtexteditor/hyperlinkdialog.cpp",
+ "richtexteditor/hyperlinkdialog.h",
+ "richtexteditor/hyperlinkdialog.ui",
+ "richtexteditor/richtexteditor.cpp",
+ "richtexteditor/richtexteditor.h",
+ "richtexteditor/richtexteditor.ui",
"sourcetool/sourcetool.cpp",
"sourcetool/sourcetool.h",
"texttool/textedititem.cpp",
diff --git a/src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewplugin.qbs b/src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewplugin.qbs
new file mode 100644
index 0000000000..8e48e6aa85
--- /dev/null
+++ b/src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewplugin.qbs
@@ -0,0 +1,40 @@
+import qbs
+
+QtcProduct {
+ name: "qmlpreviewplugin"
+ type: ["dynamiclibrary"]
+ installDir: qtc.ide_plugin_path + '/' + installDirName
+ property string installDirName: qbs.targetOS.contains("macos") ? "QmlDesigner" : "qmldesigner"
+
+ cpp.defines: base.concat("QMLPREVIEW_LIBRARY")
+ cpp.includePaths: base.concat("../designercore/include")
+ Properties {
+ condition: qbs.targetOS.contains("unix")
+ cpp.internalVersion: ""
+ }
+
+ Depends { name: "Core" }
+ Depends { name: "ProjectExplorer" }
+ Depends { name: "QmlDesigner" }
+ Depends { name: "Qt.qml" }
+ Depends { name: "Utils" }
+
+ Group {
+ name: "images"
+ files: ["images/*.png"]
+ }
+
+ Group {
+ name: "plugin metadata"
+ files: ["qmlpreviewplugin.json"]
+ fileTags: ["qt_plugin_metadata"]
+ }
+
+ files: [
+ "qmlpreviewactions.cpp",
+ "qmlpreviewactions.h",
+ "qmlpreviewplugin.cpp",
+ "qmlpreviewplugin.h",
+ "qmlpreviewplugin.qrc",
+ ]
+}
diff --git a/src/plugins/qmldesigner/shortcutmanager.cpp b/src/plugins/qmldesigner/shortcutmanager.cpp
index 72f79a8810..617c1775ab 100644
--- a/src/plugins/qmldesigner/shortcutmanager.cpp
+++ b/src/plugins/qmldesigner/shortcutmanager.cpp
@@ -154,12 +154,7 @@ void ShortCutManager::registerActions(const Core::Context &qmlDesignerMainContex
m_deleteAction.setIcon(QIcon::fromTheme(QLatin1String("edit-cut"), Utils::Icons::EDIT_CLEAR_TOOLBAR.icon()));
command = Core::ActionManager::registerAction(&m_deleteAction, QmlDesigner::Constants::C_DELETE, qmlDesignerMainContext);
- if (Utils::HostOsInfo::isMacHost())
- command->setDefaultKeySequence(QKeySequence::Backspace);
- else
- command->setDefaultKeySequence(QKeySequence::Delete);
-
- Utils::HostOsInfo::isMacHost() ;
+ command->setDefaultKeySequences({QKeySequence::Delete, QKeySequence::Backspace});
command->setAttribute(Core::Command::CA_Hide); // don't show delete in other modes
if (!Utils::HostOsInfo::isMacHost())
@@ -193,7 +188,7 @@ void ShortCutManager::registerActions(const Core::Context &qmlDesignerMainContex
command->setDefaultKeySequence(QKeySequence::SelectAll);
editMenu->addAction(command, Core::Constants::G_EDIT_SELECTALL);
- Core::ActionContainer *viewsMenu = Core::ActionManager::actionContainer(Core::Constants::M_WINDOW_VIEWS);
+ Core::ActionContainer *viewsMenu = Core::ActionManager::actionContainer(Core::Constants::M_VIEW_VIEWS);
command = Core::ActionManager::registerAction(&m_collapseExpandStatesAction, Constants::TOGGLE_STATES_EDITOR, qmlDesignerMainContext);
command->setAttribute(Core::Command::CA_Hide);
diff --git a/src/plugins/qmljseditor/qmljscomponentnamedialog.cpp b/src/plugins/qmljseditor/qmljscomponentnamedialog.cpp
index 1f486a8265..0be9d8ee24 100644
--- a/src/plugins/qmljseditor/qmljscomponentnamedialog.cpp
+++ b/src/plugins/qmljseditor/qmljscomponentnamedialog.cpp
@@ -87,7 +87,7 @@ bool ComponentNameDialog::go(QString *proposedName,
if (QDialog::Accepted == d.exec()) {
*proposedName = d.ui->componentNameEdit->text();
- *proposedPath = d.ui->pathEdit->path();
+ *proposedPath = d.ui->pathEdit->filePath().toString();
if (d.ui->checkBox->isChecked())
*proposedSuffix = "ui.qml";
diff --git a/src/plugins/qmljseditor/qmljseditor.cpp b/src/plugins/qmljseditor/qmljseditor.cpp
index 16aaa6ec47..f2de0347b8 100644
--- a/src/plugins/qmljseditor/qmljseditor.cpp
+++ b/src/plugins/qmljseditor/qmljseditor.cpp
@@ -844,7 +844,7 @@ void QmlJSEditorWidget::findUsages()
m_findReferences->findUsages(textDocument()->filePath().toString(), textCursor().position());
}
-void QmlJSEditorWidget::renameUsages()
+void QmlJSEditorWidget::renameSymbolUnderCursor()
{
m_findReferences->renameUsages(textDocument()->filePath().toString(), textCursor().position());
}
@@ -1098,9 +1098,10 @@ QmlJSEditorFactory::QmlJSEditorFactory(Core::Id _id)
setCompletionAssistProvider(new QmlJSCompletionAssistProvider);
setEditorActionHandlers(TextEditorActionHandler::Format
- | TextEditorActionHandler::UnCommentSelection
- | TextEditorActionHandler::UnCollapseAll
- | TextEditorActionHandler::FollowSymbolUnderCursor);
+ | TextEditorActionHandler::UnCommentSelection
+ | TextEditorActionHandler::UnCollapseAll
+ | TextEditorActionHandler::FollowSymbolUnderCursor
+ | TextEditorActionHandler::RenameSymbol);
}
void QmlJSEditorFactory::decorateEditor(TextEditorWidget *editor)
diff --git a/src/plugins/qmljseditor/qmljseditor.h b/src/plugins/qmljseditor/qmljseditor.h
index cb5265e66e..f13415f7f4 100644
--- a/src/plugins/qmljseditor/qmljseditor.h
+++ b/src/plugins/qmljseditor/qmljseditor.h
@@ -74,7 +74,7 @@ public:
void inspectElementUnderCursor() const;
void findUsages() override;
- void renameUsages();
+ void renameSymbolUnderCursor() override;
void showContextPane();
signals:
diff --git a/src/plugins/qmljseditor/qmljseditorplugin.cpp b/src/plugins/qmljseditor/qmljseditorplugin.cpp
index 4853c6840d..83e7e2ef48 100644
--- a/src/plugins/qmljseditor/qmljseditorplugin.cpp
+++ b/src/plugins/qmljseditor/qmljseditorplugin.cpp
@@ -162,10 +162,7 @@ QmlJSEditorPluginPrivate::QmlJSEditorPluginPrivate()
contextMenu->addAction(cmd);
qmlToolsMenu->addAction(cmd);
- QAction *renameUsagesAction = new QAction(QmlJSEditorPlugin::tr("Rename Symbol Under Cursor"), this);
- cmd = ActionManager::registerAction(renameUsagesAction, "QmlJSEditor.RenameUsages", context);
- cmd->setDefaultKeySequence(QKeySequence(QmlJSEditorPlugin::tr("Ctrl+Shift+R")));
- connect(renameUsagesAction, &QAction::triggered, this, &QmlJSEditorPluginPrivate::renameUsages);
+ cmd = ActionManager::command(TextEditor::Constants::RENAME_SYMBOL);
contextMenu->addAction(cmd);
qmlToolsMenu->addAction(cmd);
@@ -247,7 +244,7 @@ QuickToolBar *QmlJSEditorPlugin::quickToolBar()
void QmlJSEditorPluginPrivate::renameUsages()
{
if (auto editor = qobject_cast<QmlJSEditorWidget*>(EditorManager::currentEditor()->widget()))
- editor->renameUsages();
+ editor->renameSymbolUnderCursor();
}
void QmlJSEditorPluginPrivate::reformatFile()
diff --git a/src/plugins/qmljstools/qmljsmodelmanager.cpp b/src/plugins/qmljstools/qmljsmodelmanager.cpp
index e5b9014543..9b4038a632 100644
--- a/src/plugins/qmljstools/qmljsmodelmanager.cpp
+++ b/src/plugins/qmljstools/qmljsmodelmanager.cpp
@@ -37,6 +37,7 @@
#include <cpptools/cppmodelmanager.h>
#include <projectexplorer/buildconfiguration.h>
+#include <projectexplorer/buildsystem.h>
#include <projectexplorer/project.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/projectnodes.h>
@@ -44,6 +45,7 @@
#include <projectexplorer/runconfiguration.h>
#include <projectexplorer/session.h>
#include <projectexplorer/target.h>
+
#include <qmljs/qmljsbind.h>
#include <qmljs/qmljsfindexportedcpptypes.h>
#include <qmljs/qmljsplugindumper.h>
@@ -141,7 +143,7 @@ ModelManagerInterface::ProjectInfo ModelManager::defaultProjectInfoForProject(
projectInfo.qmlDumpEnvironment.appendOrSet("QML2_IMPORT_PATH", bc->environment().expandedValueForKey("QML2_IMPORT_PATH"), ":");
}
- const auto appTargets = activeTarget->applicationTargets();
+ const auto appTargets = activeTarget->buildSystem()->applicationTargets();
for (const auto &target : appTargets) {
if (target.targetFilePath.isEmpty())
continue;
diff --git a/src/plugins/qmljstools/qmljstools_test.cpp b/src/plugins/qmljstools/qmljstools_test.cpp
index 9db7c7ef7a..ab8a09abae 100644
--- a/src/plugins/qmljstools/qmljstools_test.cpp
+++ b/src/plugins/qmljstools/qmljstools_test.cpp
@@ -45,7 +45,7 @@ void QmlJSToolsPlugin::test_basic()
const QString qmlFilePath = Core::ICore::resourcePath() + QLatin1String("/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml");
modelManager->updateSourceFiles(QStringList(qmlFilePath), false);
- modelManager->joinAllThreads();
+ modelManager->test_joinAllThreads();
Snapshot snapshot = modelManager->snapshot();
Document::Ptr doc = snapshot.document(qmlFilePath);
diff --git a/src/plugins/qmlprofiler/qmlprofileractions.cpp b/src/plugins/qmlprofiler/qmlprofileractions.cpp
index 3fd754a4eb..0a8c68e0c2 100644
--- a/src/plugins/qmlprofiler/qmlprofileractions.cpp
+++ b/src/plugins/qmlprofiler/qmlprofileractions.cpp
@@ -75,7 +75,7 @@ void QmlProfilerActions::attachToTool(QmlProfilerTool *tool)
QmlProfilerStateManager *stateManager = tool->stateManager();
connect(stateManager, &QmlProfilerStateManager::serverRecordingChanged,
- this, [this, stateManager](bool recording) {
+ this, [this](bool recording) {
m_loadQmlTrace->setEnabled(!recording);
});
m_loadQmlTrace->setEnabled(!stateManager->serverRecording());
diff --git a/src/plugins/qmlprofiler/qmlprofilerstatisticsview.cpp b/src/plugins/qmlprofiler/qmlprofilerstatisticsview.cpp
index d11c97e085..81d5735875 100644
--- a/src/plugins/qmlprofiler/qmlprofilerstatisticsview.cpp
+++ b/src/plugins/qmlprofiler/qmlprofilerstatisticsview.cpp
@@ -360,7 +360,8 @@ void QmlProfilerStatisticsMainView::copyTableToClipboard() const
str += textForItem(itemModel->index(i, 0));
QClipboard *clipboard = QApplication::clipboard();
- clipboard->setText(str, QClipboard::Selection);
+ if (clipboard->supportsSelection())
+ clipboard->setText(str, QClipboard::Selection);
clipboard->setText(str, QClipboard::Clipboard);
}
@@ -368,7 +369,8 @@ void QmlProfilerStatisticsMainView::copyRowToClipboard() const
{
QString str = textForItem(selectedModelIndex());
QClipboard *clipboard = QApplication::clipboard();
- clipboard->setText(str, QClipboard::Selection);
+ if (clipboard->supportsSelection())
+ clipboard->setText(str, QClipboard::Selection);
clipboard->setText(str, QClipboard::Clipboard);
}
diff --git a/src/plugins/qnx/qnxconfiguration.cpp b/src/plugins/qnx/qnxconfiguration.cpp
index 11a846e612..bdfef8b380 100644
--- a/src/plugins/qnx/qnxconfiguration.cpp
+++ b/src/plugins/qnx/qnxconfiguration.cpp
@@ -178,7 +178,7 @@ void QnxConfiguration::deactivate()
foreach (Kit *kit, KitManager::kits()) {
if (kit->isAutoDetected()
&& DeviceTypeKitAspect::deviceTypeId(kit) == Constants::QNX_QNX_OS_TYPE
- && toolChainsToRemove.contains(ToolChainKitAspect::toolChain(kit, ProjectExplorer::Constants::CXX_LANGUAGE_ID)))
+ && toolChainsToRemove.contains(ToolChainKitAspect::cxxToolChain(kit)))
KitManager::deregisterKit(kit);
}
diff --git a/src/plugins/qnx/qnxdebugsupport.cpp b/src/plugins/qnx/qnxdebugsupport.cpp
index 4e0a8646ea..4451e23c1f 100644
--- a/src/plugins/qnx/qnxdebugsupport.cpp
+++ b/src/plugins/qnx/qnxdebugsupport.cpp
@@ -177,8 +177,8 @@ public:
mainLayout->insertLayout(mainLayout->count() - 2, formLayout);
}
- QString projectSource() const { return m_projectSource->path(); }
- FilePath localExecutable() const { return m_localExecutable->fileName(); }
+ QString projectSource() const { return m_projectSource->filePath().toString(); }
+ FilePath localExecutable() const { return m_localExecutable->filePath(); }
private:
PathChooser *m_projectSource;
diff --git a/src/plugins/qnx/qnxtoolchain.cpp b/src/plugins/qnx/qnxtoolchain.cpp
index f1bdb8ceae..88ac04bde3 100644
--- a/src/plugins/qnx/qnxtoolchain.cpp
+++ b/src/plugins/qnx/qnxtoolchain.cpp
@@ -106,7 +106,7 @@ QnxToolChain::QnxToolChain()
: GccToolChain(Constants::QNX_TOOLCHAIN_ID)
{
setOptionsReinterpreter(&reinterpretOptions);
- setTypeDisplayName(QnxToolChainFactory::tr("QCC"));
+ setTypeDisplayName(tr("QCC"));
}
std::unique_ptr<ToolChainConfigWidget> QnxToolChain::createConfigurationWidget()
@@ -204,7 +204,7 @@ bool QnxToolChain::operator ==(const ToolChain &other) const
QnxToolChainFactory::QnxToolChainFactory()
{
- setDisplayName(tr("QCC"));
+ setDisplayName(QnxToolChain::tr("QCC"));
setSupportedToolChainType(Constants::QNX_TOOLCHAIN_ID);
setSupportedLanguages({ProjectExplorer::Constants::C_LANGUAGE_ID,
ProjectExplorer::Constants::CXX_LANGUAGE_ID});
@@ -235,7 +235,7 @@ QnxToolChainConfigWidget::QnxToolChainConfigWidget(QnxToolChain *tc)
{
m_compilerCommand->setExpectedKind(PathChooser::ExistingCommand);
m_compilerCommand->setHistoryCompleter(QLatin1String("Qnx.ToolChain.History"));
- m_compilerCommand->setFileName(tc->compilerCommand());
+ m_compilerCommand->setFilePath(tc->compilerCommand());
m_compilerCommand->setEnabled(!tc->isAutoDetected());
m_sdpPath->setExpectedKind(PathChooser::ExistingDirectory);
@@ -243,7 +243,7 @@ QnxToolChainConfigWidget::QnxToolChainConfigWidget(QnxToolChain *tc)
m_sdpPath->setPath(tc->sdpPath());
m_sdpPath->setEnabled(!tc->isAutoDetected());
- const Abis abiList = detectTargetAbis(m_sdpPath->fileName());
+ const Abis abiList = detectTargetAbis(m_sdpPath->filePath());
m_abiWidget->setAbis(abiList, tc->targetAbi());
m_abiWidget->setEnabled(!tc->isAutoDetected() && !abiList.isEmpty());
@@ -267,9 +267,9 @@ void QnxToolChainConfigWidget::applyImpl()
Q_ASSERT(tc);
QString displayName = tc->displayName();
tc->setDisplayName(displayName); // reset display name
- tc->setSdpPath(m_sdpPath->fileName().toString());
+ tc->setSdpPath(m_sdpPath->filePath().toString());
tc->setTargetAbi(m_abiWidget->currentAbi());
- tc->resetToolChain(m_compilerCommand->fileName());
+ tc->resetToolChain(m_compilerCommand->filePath());
}
void QnxToolChainConfigWidget::discardImpl()
@@ -277,10 +277,10 @@ void QnxToolChainConfigWidget::discardImpl()
// subwidgets are not yet connected!
QSignalBlocker blocker(this);
auto tc = static_cast<const QnxToolChain *>(toolChain());
- m_compilerCommand->setFileName(tc->compilerCommand());
+ m_compilerCommand->setFilePath(tc->compilerCommand());
m_sdpPath->setPath(tc->sdpPath());
m_abiWidget->setAbis(tc->supportedAbis(), tc->targetAbi());
- if (!m_compilerCommand->path().isEmpty())
+ if (!m_compilerCommand->filePath().toString().isEmpty())
m_abiWidget->setEnabled(true);
}
@@ -288,8 +288,8 @@ bool QnxToolChainConfigWidget::isDirtyImpl() const
{
auto tc = static_cast<const QnxToolChain *>(toolChain());
Q_ASSERT(tc);
- return m_compilerCommand->fileName() != tc->compilerCommand()
- || m_sdpPath->path() != tc->sdpPath()
+ return m_compilerCommand->filePath() != tc->compilerCommand()
+ || m_sdpPath->filePath().toString() != tc->sdpPath()
|| m_abiWidget->currentAbi() != tc->targetAbi();
}
@@ -297,7 +297,7 @@ void QnxToolChainConfigWidget::handleSdpPathChange()
{
const Abi currentAbi = m_abiWidget->currentAbi();
const bool customAbi = m_abiWidget->isCustomAbi();
- const Abis abiList = detectTargetAbis(m_sdpPath->fileName());
+ const Abis abiList = detectTargetAbis(m_sdpPath->filePath());
m_abiWidget->setEnabled(!abiList.isEmpty());
diff --git a/src/plugins/qnx/qnxtoolchain.h b/src/plugins/qnx/qnxtoolchain.h
index 71e10a2879..3f38f2c555 100644
--- a/src/plugins/qnx/qnxtoolchain.h
+++ b/src/plugins/qnx/qnxtoolchain.h
@@ -33,6 +33,8 @@ namespace Internal {
class QnxToolChain : public ProjectExplorer::GccToolChain
{
+ Q_DECLARE_TR_FUNCTIONS(Qnx::Internal::QnxToolChain)
+
public:
QnxToolChain();
@@ -65,8 +67,6 @@ private:
class QnxToolChainFactory : public ProjectExplorer::ToolChainFactory
{
- Q_OBJECT
-
public:
QnxToolChainFactory();
diff --git a/src/plugins/qtsupport/baseqtversion.cpp b/src/plugins/qtsupport/baseqtversion.cpp
index 67cc6b8699..e6abb0ad88 100644
--- a/src/plugins/qtsupport/baseqtversion.cpp
+++ b/src/plugins/qtsupport/baseqtversion.cpp
@@ -510,8 +510,7 @@ Tasks BaseQtVersion::validateKit(const Kit *k)
if (!tdt.isEmpty() && !tdt.contains(dt))
result << BuildSystemTask(Task::Warning, tr("Device type is not supported by Qt version."));
- ToolChain *tc = ToolChainKitAspect::toolChain(k, ProjectExplorer::Constants::CXX_LANGUAGE_ID);
- if (tc) {
+ if (ToolChain *tc = ToolChainKitAspect::cxxToolChain(k)) {
Abi targetAbi = tc->targetAbi();
bool fuzzyMatch = false;
bool fullMatch = false;
@@ -538,7 +537,7 @@ Tasks BaseQtVersion::validateKit(const Kit *k)
version->displayName(), qtAbiString);
result << BuildSystemTask(fuzzyMatch ? Task::Warning : Task::Error, message);
}
- } else if (ToolChainKitAspect::toolChain(k, ProjectExplorer::Constants::C_LANGUAGE_ID)) {
+ } else if (ToolChainKitAspect::cToolChain(k)) {
const QString message = tr("The kit has a Qt version, but no C++ compiler.");
result << BuildSystemTask(Task::Warning, message);
}
diff --git a/src/plugins/qtsupport/baseqtversion.h b/src/plugins/qtsupport/baseqtversion.h
index 464b292127..8d61c21492 100644
--- a/src/plugins/qtsupport/baseqtversion.h
+++ b/src/plugins/qtsupport/baseqtversion.h
@@ -119,7 +119,6 @@ public:
virtual QString toHtml(bool verbose) const;
ProjectExplorer::Abis qtAbis() const;
- virtual ProjectExplorer::Abis detectQtAbis() const;
void applyProperties(QMakeGlobals *qmakeGlobals) const;
virtual void addToEnvironment(const ProjectExplorer::Kit *k, Utils::Environment &env) const;
@@ -243,6 +242,8 @@ protected:
virtual QSet<Core::Id> availableFeatures() const;
virtual ProjectExplorer::Tasks reportIssuesImpl(const QString &proFile, const QString &buildDir) const;
+ virtual ProjectExplorer::Abis detectQtAbis() const;
+
// helper function for desktop and simulator to figure out the supported abis based on the libraries
static ProjectExplorer::Abis qtAbisFromLibrary(const Utils::FilePaths &coreLibraries);
diff --git a/src/plugins/qtsupport/gettingstartedwelcomepage.cpp b/src/plugins/qtsupport/gettingstartedwelcomepage.cpp
index db737fb5ac..cfd675158d 100644
--- a/src/plugins/qtsupport/gettingstartedwelcomepage.cpp
+++ b/src/plugins/qtsupport/gettingstartedwelcomepage.cpp
@@ -125,7 +125,7 @@ QString ExamplesWelcomePage::copyToAlternativeLocation(const QFileInfo& proFileI
int code = d.exec();
if (code == Copy) {
QString exampleDirName = proFileInfo.dir().dirName();
- QString destBaseDir = chooser->path();
+ QString destBaseDir = chooser->filePath().toString();
settings->setValue(QString::fromLatin1(C_FALLBACK_ROOT), destBaseDir);
QDir toDirWithExamplesDir(destBaseDir);
if (toDirWithExamplesDir.cd(exampleDirName)) {
diff --git a/src/plugins/qtsupport/qtkitinformation.cpp b/src/plugins/qtsupport/qtkitinformation.cpp
index 6c5a8b90cb..070f8c4860 100644
--- a/src/plugins/qtsupport/qtkitinformation.cpp
+++ b/src/plugins/qtsupport/qtkitinformation.cpp
@@ -219,8 +219,9 @@ void QtKitAspect::fix(ProjectExplorer::Kit *k)
}
// Set a matching toolchain if we don't have one.
- if (ToolChainKitAspect::toolChain(k, ProjectExplorer::Constants::CXX_LANGUAGE_ID))
+ if (ToolChainKitAspect::cxxToolChain(k))
return;
+
const QString spec = version->mkspec();
QList<ToolChain *> possibleTcs = ToolChainManager::toolChains(
[version](const ToolChain *t) {
@@ -287,14 +288,11 @@ void QtKitAspect::addToEnvironment(const ProjectExplorer::Kit *k, Utils::Environ
version->addToEnvironment(k, env);
}
-ProjectExplorer::IOutputParser *QtKitAspect::createOutputParser(const ProjectExplorer::Kit *k) const
+QList<Utils::OutputLineParser *> QtKitAspect::createOutputParsers(const Kit *k) const
{
- if (qtVersion(k)) {
- const auto parser = new Internal::QtTestParser;
- parser->appendOutputParser(new QtParser);
- return parser;
- }
- return nullptr;
+ if (qtVersion(k))
+ return {new Internal::QtTestParser, new QtParser};
+ return {};
}
class QtMacroSubProvider
diff --git a/src/plugins/qtsupport/qtkitinformation.h b/src/plugins/qtsupport/qtkitinformation.h
index d155b8ea5f..b494ec09a4 100644
--- a/src/plugins/qtsupport/qtkitinformation.h
+++ b/src/plugins/qtsupport/qtkitinformation.h
@@ -54,7 +54,7 @@ public:
ItemList toUserOutput(const ProjectExplorer::Kit *k) const override;
void addToEnvironment(const ProjectExplorer::Kit *k, Utils::Environment &env) const override;
- ProjectExplorer::IOutputParser *createOutputParser(const ProjectExplorer::Kit *k) const override;
+ QList<Utils::OutputLineParser *> createOutputParsers(const ProjectExplorer::Kit *k) const override;
void addToMacroExpander(ProjectExplorer::Kit *kit, Utils::MacroExpander *expander) const override;
static Core::Id id();
diff --git a/src/plugins/qtsupport/qtoptionspage.cpp b/src/plugins/qtsupport/qtoptionspage.cpp
index 3f851979fe..f2e275269b 100644
--- a/src/plugins/qtsupport/qtoptionspage.cpp
+++ b/src/plugins/qtsupport/qtoptionspage.cpp
@@ -934,10 +934,10 @@ static bool validateQtInstallDir(FancyLineEdit *input, QString *errorString)
if (!settingsDirForQtDir(qtDir)) {
if (errorString) {
const QStringList filesToCheck = settingsFilesToCheck() + qtversionFilesToCheck();
- *errorString = QtOptionsPageWidget::tr(
- "<html><body>Qt installation information was not found in \"%1\". "
- "Choose a directory that contains one of the files <pre>%2</pre>")
- .arg(qtDir, filesToCheck.join('\n'));
+ *errorString = "<html><body>" + QtOptionsPageWidget::tr(
+ "Qt installation information was not found in \"%1\". "
+ "Choose a directory that contains one of the files %2")
+ .arg(qtDir, "<pre>" + filesToCheck.join('\n') + "</pre>");
}
return false;
}
diff --git a/src/plugins/qtsupport/qtoutputformatter.cpp b/src/plugins/qtsupport/qtoutputformatter.cpp
index 52517c5847..62cee36796 100644
--- a/src/plugins/qtsupport/qtoutputformatter.cpp
+++ b/src/plugins/qtsupport/qtoutputformatter.cpp
@@ -27,6 +27,7 @@
#include "qtkitinformation.h"
#include "qtsupportconstants.h"
+#include "qttestparser.h"
#include <coreplugin/editormanager/editormanager.h>
#include <projectexplorer/project.h>
@@ -45,19 +46,14 @@
#include <QTextCursor>
#include <QUrl>
+#include <tuple>
+
using namespace ProjectExplorer;
using namespace Utils;
namespace QtSupport {
namespace Internal {
-struct LinkResult
-{
- int start = -1;
- int end = -1;
- QString href;
-};
-
class QtOutputFormatterPrivate
{
public:
@@ -81,38 +77,30 @@ public:
const QRegularExpression qtTestFailUnix;
const QRegularExpression qtTestFailWin;
QPointer<Project> project;
- QList<FormattedText> lastLine;
FileInProjectFinder projectFinder;
- QTextCursor cursor;
};
-class QtOutputFormatter : public OutputFormatter
+class QtOutputLineParser : public OutputLineParser
{
public:
- explicit QtOutputFormatter(Target *target);
- ~QtOutputFormatter() override;
-
- void appendMessage(const QString &text, Utils::OutputFormat format) override;
- void handleLink(const QString &href) override;
- void setPlainTextEdit(QPlainTextEdit *plainText) override;
+ explicit QtOutputLineParser(Target *target);
+ ~QtOutputLineParser() override;
protected:
- void clearLastLine() override;
virtual void openEditor(const QString &fileName, int line, int column = -1);
private:
+ Result handleLine(const QString &text, Utils::OutputFormat format) override;
+ bool handleLink(const QString &href) override;
+
void updateProjectFileList();
- LinkResult matchLine(const QString &line) const;
- void appendMessagePart(const QString &txt, const QTextCharFormat &fmt);
- void appendLine(const LinkResult &lr, const QString &line, Utils::OutputFormat format);
- void appendLine(const LinkResult &lr, const QString &line, const QTextCharFormat &format);
- void appendMessage(const QString &text, const QTextCharFormat &format) override;
+ LinkSpec matchLine(const QString &line) const;
QtOutputFormatterPrivate *d;
friend class QtSupportPlugin; // for testing
};
-QtOutputFormatter::QtOutputFormatter(Target *target)
+QtOutputLineParser::QtOutputLineParser(Target *target)
: d(new QtOutputFormatterPrivate)
{
d->project = target ? target->project() : nullptr;
@@ -123,28 +111,28 @@ QtOutputFormatter::QtOutputFormatter(Target *target)
connect(d->project,
&Project::fileListChanged,
this,
- &QtOutputFormatter::updateProjectFileList,
+ &QtOutputLineParser::updateProjectFileList,
Qt::QueuedConnection);
}
}
-QtOutputFormatter::~QtOutputFormatter()
+QtOutputLineParser::~QtOutputLineParser()
{
delete d;
}
-LinkResult QtOutputFormatter::matchLine(const QString &line) const
+OutputLineParser::LinkSpec QtOutputLineParser::matchLine(const QString &line) const
{
- LinkResult lr;
+ LinkSpec lr;
auto hasMatch = [&lr, line](const QRegularExpression &regex) {
const QRegularExpressionMatch match = regex.match(line);
if (!match.hasMatch())
return false;
- lr.href = match.captured(1);
- lr.start = match.capturedStart(1);
- lr.end = lr.start + lr.href.length();
+ lr.target = match.captured(1);
+ lr.startPos = match.capturedStart(1);
+ lr.length = lr.target.length();
return true;
};
@@ -164,81 +152,16 @@ LinkResult QtOutputFormatter::matchLine(const QString &line) const
return lr;
}
-void QtOutputFormatter::appendMessage(const QString &txt, OutputFormat format)
-{
- appendMessage(txt, charFormat(format));
-}
-
-void QtOutputFormatter::appendMessagePart(const QString &txt, const QTextCharFormat &fmt)
-{
- QString deferredText;
-
- const int length = txt.length();
- for (int start = 0, pos = -1; start < length; start = pos + 1) {
- bool linkHandled = false;
- pos = txt.indexOf('\n', start);
- const QString newPart = txt.mid(start, (pos == -1) ? -1 : pos - start + 1);
- QString line = newPart;
- QTextCharFormat format = fmt;
- if (!d->lastLine.isEmpty()) {
- line = d->lastLine.last().text + newPart;
- format = d->lastLine.last().format;
- }
-
- LinkResult lr = matchLine(line);
- if (!lr.href.isEmpty()) {
- // Found something && line continuation
- d->cursor.insertText(deferredText, fmt);
- deferredText.clear();
- if (!d->lastLine.isEmpty())
- clearLastLine();
- appendLine(lr, line, format);
- linkHandled = true;
- } else {
- // Found nothing, just emit the new part
- deferredText += newPart;
- }
-
- if (pos == -1) {
- d->lastLine.clear();
- if (!linkHandled)
- d->lastLine.append(FormattedText(line, format));
- break;
- }
- d->lastLine.clear(); // Handled line continuation
- }
- d->cursor.insertText(deferredText, fmt);
-}
-
-void QtOutputFormatter::appendMessage(const QString &txt, const QTextCharFormat &format)
-{
- if (!d->cursor.atEnd())
- d->cursor.movePosition(QTextCursor::End);
- d->cursor.beginEditBlock();
-
- const QList<FormattedText> ansiTextList = parseAnsi(txt, format);
- for (const FormattedText &output : ansiTextList)
- appendMessagePart(output.text, output.format);
-
- d->cursor.endEditBlock();
-
- emit contentChanged();
-}
-
-void QtOutputFormatter::appendLine(const LinkResult &lr, const QString &line, OutputFormat format)
+OutputLineParser::Result QtOutputLineParser::handleLine(const QString &txt, OutputFormat format)
{
- appendLine(lr, line, charFormat(format));
+ Q_UNUSED(format);
+ const LinkSpec lr = matchLine(txt);
+ if (!lr.target.isEmpty())
+ return Result(Status::Done, {lr});
+ return Status::NotHandled;
}
-void QtOutputFormatter::appendLine(const LinkResult &lr, const QString &line,
- const QTextCharFormat &format)
-{
- d->cursor.insertText(line.left(lr.start), format);
- d->cursor.insertText(line.mid(lr.start, lr.end - lr.start), linkFormat(format, lr.href));
- d->cursor.insertText(line.mid(lr.end), format);
-}
-
-void QtOutputFormatter::handleLink(const QString &href)
+bool QtOutputLineParser::handleLink(const QString &href)
{
if (!href.isEmpty()) {
static const QRegularExpression qmlLineColumnLink("^(" QT_QML_URL_REGEXP ")" // url
@@ -254,7 +177,7 @@ void QtOutputFormatter::handleLink(const QString &href)
const int line = qmlLineColumnMatch.captured(2).toInt();
const int column = qmlLineColumnMatch.captured(3).toInt();
openEditor(getFileToOpen(fileUrl), line, column - 1);
- return;
+ return true;
}
static const QRegularExpression qmlLineLink("^(" QT_QML_URL_REGEXP ")" // url
@@ -269,7 +192,7 @@ void QtOutputFormatter::handleLink(const QString &href)
fileUrl = QUrl::fromLocalFile(filePath.mid(int(strlen(scheme))));
const int line = qmlLineMatch.captured(2).toInt();
openEditor(getFileToOpen(fileUrl), line);
- return;
+ return true;
}
QString fileName;
@@ -299,30 +222,18 @@ void QtOutputFormatter::handleLink(const QString &href)
if (!fileName.isEmpty()) {
fileName = getFileToOpen(QUrl::fromLocalFile(fileName));
openEditor(fileName, line);
- return;
+ return true;
}
}
+ return false;
}
-void QtOutputFormatter::setPlainTextEdit(QPlainTextEdit *plainText)
-{
- OutputFormatter::setPlainTextEdit(plainText);
- d->cursor = plainText ? plainText->textCursor() : QTextCursor();
-}
-
-void QtOutputFormatter::clearLastLine()
-{
- OutputFormatter::clearLastLine();
- if (!d->lastLine.isEmpty())
- d->lastLine.removeLast();
-}
-
-void QtOutputFormatter::openEditor(const QString &fileName, int line, int column)
+void QtOutputLineParser::openEditor(const QString &fileName, int line, int column)
{
Core::EditorManager::openEditorAt(fileName, line, column);
}
-void QtOutputFormatter::updateProjectFileList()
+void QtOutputLineParser::updateProjectFileList()
{
if (d->project)
d->projectFinder.setProjectFiles(d->project->files(Project::SourceFiles));
@@ -332,9 +243,10 @@ void QtOutputFormatter::updateProjectFileList()
QtOutputFormatterFactory::QtOutputFormatterFactory()
{
- setFormatterCreator([](Target *t) -> OutputFormatter * {
- BaseQtVersion *qt = QtKitAspect::qtVersion(t->kit());
- return qt ? new QtOutputFormatter(t) : nullptr;
+ setFormatterCreator([](Target *t) -> QList<OutputLineParser *> {
+ if (QtKitAspect::qtVersion(t ? t->kit() : nullptr))
+ return {new QtTestParser, new QtOutputLineParser(t)};
+ return {};
});
}
@@ -355,11 +267,11 @@ namespace QtSupport {
using namespace QtSupport::Internal;
-class TestQtOutputFormatter : public QtOutputFormatter
+class TestQtOutputLineParser : public QtOutputLineParser
{
public:
- TestQtOutputFormatter() :
- QtOutputFormatter(nullptr)
+ TestQtOutputLineParser() :
+ QtOutputLineParser(nullptr)
{
}
@@ -376,6 +288,11 @@ public:
int column = -1;
};
+class TestQtOutputFormatter : public OutputFormatter
+{
+public:
+ TestQtOutputFormatter() { setLineParsers({new TestQtOutputLineParser}); }
+};
void QtSupportPlugin::testQtOutputFormatter_data()
{
@@ -393,7 +310,7 @@ void QtSupportPlugin::testQtOutputFormatter_data()
QTest::newRow("pass through")
<< "Pass through plain text."
- << -1 << -1 << QString()
+ << -1 << -2 << QString()
<< QString() << -1 << -1;
QTest::newRow("qrc:/main.qml:20")
@@ -499,14 +416,14 @@ void QtSupportPlugin::testQtOutputFormatter()
QFETCH(int, line);
QFETCH(int, column);
- TestQtOutputFormatter formatter;
+ TestQtOutputLineParser formatter;
- LinkResult result = formatter.matchLine(input);
- formatter.handleLink(result.href);
+ QtOutputLineParser::LinkSpec result = formatter.matchLine(input);
+ formatter.handleLink(result.target);
- QCOMPARE(result.start, linkStart);
- QCOMPARE(result.end, linkEnd);
- QCOMPARE(result.href, href);
+ QCOMPARE(result.startPos, linkStart);
+ QCOMPARE(result.startPos + result.length, linkEnd);
+ QCOMPARE(result.target, href);
QCOMPARE(formatter.fileName, file);
QCOMPARE(formatter.line, line);
@@ -566,8 +483,13 @@ void QtSupportPlugin::testQtOutputFormatter_appendMessage()
QFETCH(QString, outputText);
QFETCH(QTextCharFormat, inputFormat);
QFETCH(QTextCharFormat, outputFormat);
+ if (outputFormat == QTextCharFormat())
+ outputFormat = formatter.charFormat(StdOutFormat);
+ if (inputFormat != QTextCharFormat())
+ formatter.overrideTextCharFormat(inputFormat);
- formatter.appendMessage(inputText, inputFormat);
+ formatter.appendMessage(inputText, StdOutFormat);
+ formatter.flush();
QCOMPARE(edit.toPlainText(), outputText);
QCOMPARE(edit.currentCharFormat(), outputFormat);
@@ -576,6 +498,7 @@ void QtSupportPlugin::testQtOutputFormatter_appendMessage()
void QtSupportPlugin::testQtOutputFormatter_appendMixedAssertAndAnsi()
{
QPlainTextEdit edit;
+
TestQtOutputFormatter formatter;
formatter.setPlainTextEdit(&edit);
@@ -588,7 +511,7 @@ void QtSupportPlugin::testQtOutputFormatter_appendMixedAssertAndAnsi()
"file://test.cpp:123 "
"Blue\n";
- formatter.appendMessage(inputText, QTextCharFormat());
+ formatter.appendMessage(inputText, StdOutFormat);
QCOMPARE(edit.toPlainText(), outputText);
@@ -597,7 +520,8 @@ void QtSupportPlugin::testQtOutputFormatter_appendMixedAssertAndAnsi()
edit.moveCursor(QTextCursor::WordRight);
edit.moveCursor(QTextCursor::Right);
- QCOMPARE(edit.currentCharFormat(), OutputFormatter::linkFormat(QTextCharFormat(), "file://test.cpp:123"));
+ QCOMPARE(edit.currentCharFormat(),
+ OutputFormatter::linkFormat(QTextCharFormat(), "file://test.cpp:123"));
edit.moveCursor(QTextCursor::End);
QCOMPARE(edit.currentCharFormat(), blueFormat());
diff --git a/src/plugins/qtsupport/qtparser.cpp b/src/plugins/qtsupport/qtparser.cpp
index 7b01fb874d..b376e9911c 100644
--- a/src/plugins/qtsupport/qtparser.cpp
+++ b/src/plugins/qtsupport/qtparser.cpp
@@ -28,9 +28,18 @@
#include <projectexplorer/task.h>
#include <projectexplorer/projectexplorerconstants.h>
-using namespace QtSupport;
+#include <QFileInfo>
+
+#ifdef WITH_TESTS
+#include "qtsupportplugin.h"
+#include <projectexplorer/outputparser_test.h>
+#include <QTest>
+#endif
+
using namespace ProjectExplorer;
+namespace QtSupport {
+
// opt. drive letter + filename: (2 brackets)
#define FILE_PATTERN "^(([A-Za-z]:)?[^:]+\\.[^:]+)"
@@ -43,8 +52,11 @@ QtParser::QtParser() :
m_translationRegExp.setMinimal(true);
}
-void QtParser::stdError(const QString &line)
+Utils::OutputLineParser::Result QtParser::handleLine(const QString &line, Utils::OutputFormat type)
{
+ if (type != Utils::StdErrFormat)
+ return Status::NotHandled;
+
QString lne = rightTrimmed(line);
if (m_mocRegExp.indexIn(lne) > -1) {
bool ok;
@@ -57,35 +69,33 @@ void QtParser::stdError(const QString &line)
type = Task::Warning;
if (level.compare(QLatin1String("Note"), Qt::CaseInsensitive) == 0)
type = Task::Unknown;
- CompileTask task(type, m_mocRegExp.cap(5).trimmed() /* description */,
- Utils::FilePath::fromUserInput(m_mocRegExp.cap(1)) /* filename */,
- lineno);
- emit addTask(task, 1);
- return;
+ LinkSpecs linkSpecs;
+ const Utils::FilePath file
+ = absoluteFilePath(Utils::FilePath::fromUserInput(m_mocRegExp.cap(1)));
+ addLinkSpecForAbsoluteFilePath(linkSpecs, file, lineno, m_mocRegExp, 1);
+ CompileTask task(type, m_mocRegExp.cap(5).trimmed() /* description */, file, lineno);
+ scheduleTask(task, 1);
+ return {Status::Done, linkSpecs};
}
if (m_translationRegExp.indexIn(lne) > -1) {
Task::TaskType type = Task::Warning;
if (m_translationRegExp.cap(1) == QLatin1String("Error"))
type = Task::Error;
- CompileTask task(type, m_translationRegExp.cap(2),
- Utils::FilePath::fromUserInput(m_translationRegExp.cap(3)));
- emit addTask(task, 1);
- return;
+ LinkSpecs linkSpecs;
+ const Utils::FilePath file
+ = absoluteFilePath(Utils::FilePath::fromUserInput(m_translationRegExp.cap(3)));
+ addLinkSpecForAbsoluteFilePath(linkSpecs, file, 0, m_translationRegExp, 3);
+ CompileTask task(type, m_translationRegExp.cap(2), file);
+ scheduleTask(task, 1);
+ return {Status::Done, linkSpecs};
}
- IOutputParser::stdError(line);
+ return Status::NotHandled;
}
// Unit tests:
#ifdef WITH_TESTS
-# include <QTest>
-
-# include "qtsupportplugin.h"
-# include <projectexplorer/projectexplorerconstants.h>
-# include <projectexplorer/outputparser_test.h>
-
-using namespace ProjectExplorer;
-using namespace QtSupport::Internal;
+namespace Internal {
void QtSupportPlugin::testQtOutputParser_data()
{
@@ -136,7 +146,7 @@ void QtSupportPlugin::testQtOutputParser_data()
<< QString() << QString()
<< (Tasks() << CompileTask(Task::Warning,
QLatin1String("No relevant classes found. No output generated."),
- Utils::FilePath::fromUserInput(QLatin1String("..\\untitled\\errorfile.h")), 0))
+ Utils::FilePath::fromUserInput(QLatin1String("..\\untitled\\errorfile.h")), -1))
<< QString();
QTest::newRow("moc warning 2")
<< QString::fromLatin1("c:\\code\\test.h(96): Warning: Property declaration ) has no READ accessor function. The property will be invalid.")
@@ -152,7 +162,7 @@ void QtSupportPlugin::testQtOutputParser_data()
<< QString() << QString()
<< (Tasks() << CompileTask(Task::Unknown,
QLatin1String("No relevant classes found. No output generated."),
- Utils::FilePath::fromUserInput(QLatin1String("/home/qtwebkithelpviewer.h")), 0))
+ Utils::FilePath::fromUserInput(QLatin1String("/home/qtwebkithelpviewer.h")), -1))
<< QString();
QTest::newRow("ninja with moc")
<< QString::fromLatin1("E:/sandbox/creator/loaden/src/libs/utils/iwelcomepage.h(54): Error: Undefined interface")
@@ -175,7 +185,7 @@ void QtSupportPlugin::testQtOutputParser_data()
void QtSupportPlugin::testQtOutputParser()
{
OutputParserTester testbench;
- testbench.appendOutputParser(new QtParser);
+ testbench.addLineParser(new QtParser);
QFETCH(QString, input);
QFETCH(OutputParserTester::Channel, inputChannel);
QFETCH(Tasks, tasks);
@@ -185,4 +195,8 @@ void QtSupportPlugin::testQtOutputParser()
testbench.testParsing(input, inputChannel, tasks, childStdOutLines, childStdErrLines, outputLines);
}
+
+} // namespace Internal
#endif
+
+} // namespace QtSupport
diff --git a/src/plugins/qtsupport/qtparser.h b/src/plugins/qtsupport/qtparser.h
index 608838e9c7..e70661f648 100644
--- a/src/plugins/qtsupport/qtparser.h
+++ b/src/plugins/qtsupport/qtparser.h
@@ -34,17 +34,18 @@ namespace QtSupport {
// Parser for Qt-specific utilities like moc, uic, etc.
-class QTSUPPORT_EXPORT QtParser : public ProjectExplorer::IOutputParser
+class QTSUPPORT_EXPORT QtParser : public ProjectExplorer::OutputTaskParser
{
Q_OBJECT
public:
QtParser();
- void stdError(const QString &line) override;
private:
+ Result handleLine(const QString &line, Utils::OutputFormat type) override;
+
QRegExp m_mocRegExp;
QRegExp m_translationRegExp;
};
-} // namespace ProjectExplorer
+} // namespace QtSupport
diff --git a/src/plugins/qtsupport/qttestparser.cpp b/src/plugins/qtsupport/qttestparser.cpp
index 901613437e..ec9bde4dd1 100644
--- a/src/plugins/qtsupport/qttestparser.cpp
+++ b/src/plugins/qtsupport/qttestparser.cpp
@@ -47,8 +47,11 @@ using namespace Utils;
namespace QtSupport {
namespace Internal {
-void QtTestParser::stdOutput(const QString &line)
+OutputLineParser::Result QtTestParser::handleLine(const QString &line, OutputFormat type)
{
+ if (type != StdOutFormat)
+ return Status::NotHandled;
+
const QString theLine = rightTrimmed(line);
static const QRegularExpression triggerPattern("^(?:XPASS|FAIL!) : .+$");
QTC_CHECK(triggerPattern.isValid());
@@ -56,31 +59,33 @@ void QtTestParser::stdOutput(const QString &line)
emitCurrentTask();
m_currentTask = Task(Task::Error, theLine, FilePath(), -1,
Constants::TASK_CATEGORY_AUTOTEST);
- return;
- }
- if (m_currentTask.isNull()) {
- IOutputParser::stdOutput(line);
- return;
+ return Status::InProgress;
}
+ if (m_currentTask.isNull())
+ return Status::NotHandled;
static const QRegularExpression locationPattern(HostOsInfo::isWindowsHost()
? QString(QT_TEST_FAIL_WIN_REGEXP)
: QString(QT_TEST_FAIL_UNIX_REGEXP));
QTC_CHECK(locationPattern.isValid());
const QRegularExpressionMatch match = locationPattern.match(theLine);
if (match.hasMatch()) {
- m_currentTask.file = FilePath::fromString(
- QDir::fromNativeSeparators(match.captured("file")));
+ LinkSpecs linkSpecs;
+ m_currentTask.file = absoluteFilePath(FilePath::fromString(
+ QDir::fromNativeSeparators(match.captured("file"))));
m_currentTask.line = match.captured("line").toInt();
+ addLinkSpecForAbsoluteFilePath(linkSpecs, m_currentTask.file, m_currentTask.line, match,
+ "file");
emitCurrentTask();
- return;
+ return {Status::Done, linkSpecs};
}
- m_currentTask.description.append('\n').append(theLine);
+ m_currentTask.details.append(theLine);
+ return Status::InProgress;
}
void QtTestParser::emitCurrentTask()
{
if (!m_currentTask.isNull()) {
- emit taskAdded(m_currentTask);
+ scheduleTask(m_currentTask, 1);
m_currentTask.clear();
}
}
@@ -89,7 +94,7 @@ void QtTestParser::emitCurrentTask()
void QtSupportPlugin::testQtTestOutputParser()
{
OutputParserTester testbench;
- testbench.appendOutputParser(new QtTestParser);
+ testbench.addLineParser(new QtTestParser);
const QString input = "random output\n"
"PASS : MyTest::someTest()\n"
"XPASS : MyTest::someTest()\n"
diff --git a/src/plugins/qtsupport/qttestparser.h b/src/plugins/qtsupport/qttestparser.h
index 28ca1f3b04..8e76eaba40 100644
--- a/src/plugins/qtsupport/qttestparser.h
+++ b/src/plugins/qtsupport/qttestparser.h
@@ -31,12 +31,12 @@
namespace QtSupport {
namespace Internal {
-class QtTestParser : public ProjectExplorer::IOutputParser
+class QtTestParser : public ProjectExplorer::OutputTaskParser
{
Q_OBJECT
private:
- void stdOutput(const QString &line) override;
- void doFlush() override { emitCurrentTask(); }
+ Result handleLine(const QString &line, Utils::OutputFormat type) override;
+ void flush() override { emitCurrentTask(); }
void emitCurrentTask();
diff --git a/src/plugins/remotelinux/abstractpackagingstep.cpp b/src/plugins/remotelinux/abstractpackagingstep.cpp
index ceb2d4c50b..b9221460c4 100644
--- a/src/plugins/remotelinux/abstractpackagingstep.cpp
+++ b/src/plugins/remotelinux/abstractpackagingstep.cpp
@@ -86,7 +86,7 @@ QString AbstractPackagingStep::cachedPackageDirectory() const
QString AbstractPackagingStep::packageDirectory() const
{
- return buildConfiguration()->buildDirectory().toString();
+ return buildDirectory().toString();
}
bool AbstractPackagingStep::isPackagingNeeded() const
diff --git a/src/plugins/remotelinux/abstractremotelinuxdeploystep.cpp b/src/plugins/remotelinux/abstractremotelinuxdeploystep.cpp
index 6a552296d1..7d24e38fb6 100644
--- a/src/plugins/remotelinux/abstractremotelinuxdeploystep.cpp
+++ b/src/plugins/remotelinux/abstractremotelinuxdeploystep.cpp
@@ -139,15 +139,15 @@ void AbstractRemoteLinuxDeployStep::handleProgressMessage(const QString &message
void AbstractRemoteLinuxDeployStep::handleErrorMessage(const QString &message)
{
- emit addTask(DeploymentTask(Task::Error, message), 1); // TODO correct?
emit addOutput(message, OutputFormat::ErrorMessage);
+ emit addTask(DeploymentTask(Task::Error, message), 1); // TODO correct?
d->hasError = true;
}
void AbstractRemoteLinuxDeployStep::handleWarningMessage(const QString &message)
{
- emit addTask(DeploymentTask(Task::Warning, message), 1); // TODO correct?
emit addOutput(message, OutputFormat::ErrorMessage);
+ emit addTask(DeploymentTask(Task::Warning, message), 1); // TODO correct?
}
void AbstractRemoteLinuxDeployStep::handleFinished()
diff --git a/src/plugins/remotelinux/genericdirectuploadstep.cpp b/src/plugins/remotelinux/genericdirectuploadstep.cpp
index a355e94175..cd3ab65546 100644
--- a/src/plugins/remotelinux/genericdirectuploadstep.cpp
+++ b/src/plugins/remotelinux/genericdirectuploadstep.cpp
@@ -26,6 +26,7 @@
#include "genericdirectuploadstep.h"
#include "genericdirectuploadservice.h"
+#include "remotelinux_constants.h"
#include <projectexplorer/deploymentdata.h>
#include <projectexplorer/target.h>
@@ -79,7 +80,7 @@ GenericDirectUploadStep::~GenericDirectUploadStep() = default;
Core::Id GenericDirectUploadStep::stepId()
{
- return "RemoteLinux.DirectUploadStep";
+ return Constants::DirectUploadStepId;
}
QString GenericDirectUploadStep::displayName()
diff --git a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp
index a184bb2fd3..74dbe099a0 100644
--- a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp
+++ b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp
@@ -123,7 +123,7 @@ void GenericLinuxDeviceConfigurationWidget::userNameEditingFinished()
void GenericLinuxDeviceConfigurationWidget::keyFileEditingFinished()
{
SshConnectionParameters sshParams = device()->sshParameters();
- sshParams.privateKeyFile = m_ui->keyFileLineEdit->path();
+ sshParams.privateKeyFile = m_ui->keyFileLineEdit->filePath().toString();
device()->setSshParameters(sshParams);
}
@@ -187,8 +187,8 @@ void GenericLinuxDeviceConfigurationWidget::initGui()
m_ui->keyFileLineEdit->setExpectedKind(PathChooser::File);
m_ui->keyFileLineEdit->setHistoryCompleter(QLatin1String("Ssh.KeyFile.History"));
m_ui->keyFileLineEdit->lineEdit()->setMinimumWidth(0);
- QRegExpValidator * const portsValidator
- = new QRegExpValidator(QRegExp(PortList::regularExpression()), this);
+ QRegularExpressionValidator * const portsValidator
+ = new QRegularExpressionValidator(QRegularExpression(PortList::regularExpression()), this);
m_ui->portsLineEdit->setValidator(portsValidator);
const SshConnectionParameters &sshParams = device()->sshParameters();
diff --git a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizardpages.cpp b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizardpages.cpp
index e3ffd91e98..9165ee56c8 100644
--- a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizardpages.cpp
+++ b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizardpages.cpp
@@ -196,7 +196,7 @@ GenericLinuxDeviceConfigurationWizardKeyDeploymentPage::GenericLinuxDeviceConfig
deployLayout->addStretch();
mainLayout->addLayout(deployLayout);
connect(&d->keyFileChooser, &PathChooser::pathChanged, this, [this, deployButton] {
- deployButton->setEnabled(d->keyFileChooser.fileName().exists());
+ deployButton->setEnabled(d->keyFileChooser.filePath().exists());
d->iconLabel.clear();
emit completeChanged();
});
@@ -227,15 +227,15 @@ void GenericLinuxDeviceConfigurationWizardKeyDeploymentPage::initializePage()
bool GenericLinuxDeviceConfigurationWizardKeyDeploymentPage::isComplete() const
{
- return d->keyFileChooser.path().isEmpty() || d->keyFileChooser.fileName().exists();
+ return d->keyFileChooser.filePath().toString().isEmpty() || d->keyFileChooser.filePath().exists();
}
bool GenericLinuxDeviceConfigurationWizardKeyDeploymentPage::validatePage()
{
- if (!d->defaultKeys().contains(d->keyFileChooser.path())) {
+ if (!d->defaultKeys().contains(d->keyFileChooser.filePath().toString())) {
SshConnectionParameters sshParams = d->device->sshParameters();
sshParams.authenticationType = SshConnectionParameters::AuthenticationTypeSpecificKey;
- sshParams.privateKeyFile = d->keyFileChooser.path();
+ sshParams.privateKeyFile = d->keyFileChooser.filePath().toString();
d->device->setSshParameters(sshParams);
}
return true;
@@ -243,7 +243,7 @@ bool GenericLinuxDeviceConfigurationWizardKeyDeploymentPage::validatePage()
QString GenericLinuxDeviceConfigurationWizardKeyDeploymentPage::privateKeyFilePath() const
{
- return d->keyFileChooser.path();
+ return d->keyFileChooser.filePath().toString();
}
void GenericLinuxDeviceConfigurationWizardKeyDeploymentPage::createKey()
diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp
index 96d74870b6..7fcfe9f22c 100644
--- a/src/plugins/remotelinux/linuxdevice.cpp
+++ b/src/plugins/remotelinux/linuxdevice.cpp
@@ -280,16 +280,6 @@ DeviceEnvironmentFetcher::Ptr LinuxDevice::environmentFetcher() const
return DeviceEnvironmentFetcher::Ptr(new LinuxDeviceEnvironmentFetcher(sharedFromThis()));
}
-void LinuxDevice::setSupportsRsync(bool supportsRsync)
-{
- setExtraData("RemoteLinux.SupportsRSync", supportsRsync);
-}
-
-bool LinuxDevice::supportsRSync() const
-{
- return extraData("RemoteLinux.SupportsRSync").toBool();
-}
-
namespace Internal {
// Factory
diff --git a/src/plugins/remotelinux/linuxdevice.h b/src/plugins/remotelinux/linuxdevice.h
index 8cf11c7524..29ca02e39d 100644
--- a/src/plugins/remotelinux/linuxdevice.h
+++ b/src/plugins/remotelinux/linuxdevice.h
@@ -55,9 +55,6 @@ public:
ProjectExplorer::DeviceProcessSignalOperation::Ptr signalOperation() const override;
ProjectExplorer::DeviceEnvironmentFetcher::Ptr environmentFetcher() const override;
- void setSupportsRsync(bool supportsRsync);
- bool supportsRSync() const;
-
protected:
LinuxDevice();
};
diff --git a/src/plugins/remotelinux/linuxdevicetester.cpp b/src/plugins/remotelinux/linuxdevicetester.cpp
index a5327f8c5e..8e3a8dab23 100644
--- a/src/plugins/remotelinux/linuxdevicetester.cpp
+++ b/src/plugins/remotelinux/linuxdevicetester.cpp
@@ -25,7 +25,7 @@
#include "linuxdevicetester.h"
-#include "linuxdevice.h"
+#include "remotelinux_constants.h"
#include "rsyncdeploystep.h"
#include <projectexplorer/devicesupport/deviceusedportsgatherer.h>
@@ -261,7 +261,7 @@ void GenericLinuxDeviceTester::handleRsyncFinished()
emit progressMessage(tr("rsync is functional.\n"));
}
- d->deviceConfiguration.staticCast<LinuxDevice>()->setSupportsRsync(error.isEmpty());
+ d->deviceConfiguration->setExtraData(Constants::SupportsRSync, error.isEmpty());
setFinished(result);
}
diff --git a/src/plugins/remotelinux/makeinstallstep.cpp b/src/plugins/remotelinux/makeinstallstep.cpp
index 8aa811a944..b4ce1b5632 100644
--- a/src/plugins/remotelinux/makeinstallstep.cpp
+++ b/src/plugins/remotelinux/makeinstallstep.cpp
@@ -25,6 +25,8 @@
#include "makeinstallstep.h"
+#include "remotelinux_constants.h"
+
#include <projectexplorer/buildconfiguration.h>
#include <projectexplorer/buildsteplist.h>
#include <projectexplorer/buildsystem.h>
@@ -112,7 +114,7 @@ MakeInstallStep::MakeInstallStep(BuildStepList *parent, Core::Id id) : MakeStep(
Core::Id MakeInstallStep::stepId()
{
- return "RemoteLinux.MakeInstall";
+ return Constants::MakeInstallStepId;
}
QString MakeInstallStep::displayName()
diff --git a/src/plugins/remotelinux/publickeydeploymentdialog.cpp b/src/plugins/remotelinux/publickeydeploymentdialog.cpp
index 9d31ea580d..6cf31ed16a 100644
--- a/src/plugins/remotelinux/publickeydeploymentdialog.cpp
+++ b/src/plugins/remotelinux/publickeydeploymentdialog.cpp
@@ -29,6 +29,7 @@
#include <coreplugin/icore.h>
#include <ssh/sshconnection.h>
+#include <utils/theme/theme.h>
#include <QFileDialog>
@@ -100,16 +101,15 @@ void PublicKeyDeploymentDialog::handleDeploymentError(const QString &errorMsg)
void PublicKeyDeploymentDialog::handleDeploymentFinished(const QString &errorMsg)
{
QString buttonText;
- const char *textColor;
+ QString textColor;
if (errorMsg.isEmpty()) {
buttonText = tr("Deployment finished successfully.");
- textColor = "blue";
+ textColor = Utils::creatorTheme()->color(Utils::Theme::TextColorNormal).name();
} else {
buttonText = errorMsg;
- textColor = "red";
+ textColor = Utils::creatorTheme()->color(Utils::Theme::TextColorError).name();
}
- setLabelText(QString::fromLatin1("<font color=\"%1\">%2</font>").arg(QLatin1String(textColor),
- buttonText));
+ setLabelText(QString::fromLatin1("<font color=\"%1\">%2</font>").arg(textColor, buttonText));
setCancelButtonText(tr("Close"));
}
diff --git a/src/plugins/remotelinux/remotelinux_constants.h b/src/plugins/remotelinux/remotelinux_constants.h
index 479dfda167..7ad2fc7d08 100644
--- a/src/plugins/remotelinux/remotelinux_constants.h
+++ b/src/plugins/remotelinux/remotelinux_constants.h
@@ -30,5 +30,10 @@ namespace Constants {
const char GenericLinuxOsType[] = "GenericLinuxOsType";
+const char CheckForFreeDiskSpaceId[] = "RemoteLinux.CheckForFreeDiskSpaceStep";
+const char DirectUploadStepId[] = "RemoteLinux.DirectUploadStep";
+const char MakeInstallStepId[] = "RemoteLinux.MakeInstall";
+const char SupportsRSync[] = "RemoteLinux.SupportsRSync";
+
} // Constants
} // RemoteLinux
diff --git a/src/plugins/remotelinux/remotelinuxdeployconfiguration.cpp b/src/plugins/remotelinux/remotelinuxdeployconfiguration.cpp
index 6a81085bf0..294328a4d8 100644
--- a/src/plugins/remotelinux/remotelinuxdeployconfiguration.cpp
+++ b/src/plugins/remotelinux/remotelinuxdeployconfiguration.cpp
@@ -26,7 +26,6 @@
#include "remotelinuxdeployconfiguration.h"
#include "genericdirectuploadstep.h"
-#include "linuxdevice.h"
#include "makeinstallstep.h"
#include "remotelinuxcheckforfreediskspacestep.h"
#include "remotelinuxkillappstep.h"
@@ -79,12 +78,12 @@ RemoteLinuxDeployConfigurationFactory::RemoteLinuxDeployConfigurationFactory()
addInitialStep(RemoteLinuxCheckForFreeDiskSpaceStep::stepId());
addInitialStep(RemoteLinuxKillAppStep::stepId());
addInitialStep(RsyncDeployStep::stepId(), [](Target *target) {
- auto device = DeviceKitAspect::device(target->kit()).staticCast<const LinuxDevice>();
- return device && device->supportsRSync();
+ auto device = DeviceKitAspect::device(target->kit());
+ return device && device->extraData(Constants::SupportsRSync).toBool();
});
addInitialStep(GenericDirectUploadStep::stepId(), [](Target *target) {
- auto device = DeviceKitAspect::device(target->kit()).staticCast<const LinuxDevice>();
- return device && !device->supportsRSync();
+ auto device = DeviceKitAspect::device(target->kit());
+ return device && !device->extraData(Constants::SupportsRSync).toBool();
});
}
diff --git a/src/plugins/resourceeditor/qrceditor/resourcefile.cpp b/src/plugins/resourceeditor/qrceditor/resourcefile.cpp
index 81c211cb0a..71f5fb05c4 100644
--- a/src/plugins/resourceeditor/qrceditor/resourcefile.cpp
+++ b/src/plugins/resourceeditor/qrceditor/resourcefile.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -448,6 +448,18 @@ QString ResourceFile::absolutePath(const QString &rel_path) const
return QDir::cleanPath(rc);
}
+void ResourceFile::orderList()
+{
+ for (Prefix *p : m_prefix_list) {
+ std::sort(p->file_list.begin(), p->file_list.end(), [&](File *f1, File *f2) {
+ return *f1 < *f2;
+ });
+ }
+
+ if (!save())
+ m_error_message = tr("Cannot save file.");
+}
+
bool ResourceFile::contains(const QString &prefix, const QString &lang, const QString &file) const
{
int pref_idx = indexOfPrefix(prefix, lang);
@@ -688,6 +700,11 @@ QList<QModelIndex> ResourceModel::nonExistingFiles() const
return files;
}
+void ResourceModel::orderList()
+{
+ m_resource_file.orderList();
+}
+
Qt::ItemFlags ResourceModel::flags(const QModelIndex &index) const
{
Qt::ItemFlags f = QAbstractItemModel::flags(index);
diff --git a/src/plugins/resourceeditor/qrceditor/resourcefile_p.h b/src/plugins/resourceeditor/qrceditor/resourcefile_p.h
index 8957a56f0e..0afb55290c 100644
--- a/src/plugins/resourceeditor/qrceditor/resourcefile_p.h
+++ b/src/plugins/resourceeditor/qrceditor/resourcefile_p.h
@@ -170,6 +170,8 @@ public:
QString relativePath(const QString &abs_path) const;
QString absolutePath(const QString &rel_path) const;
+ void orderList();
+
static QString fixPrefix(const QString &prefix);
private:
@@ -260,6 +262,8 @@ public:
bool dirty() const { return m_dirty; }
void setDirty(bool b);
+ void orderList();
+
private:
QMimeData *mimeData (const QModelIndexList & indexes) const override;
diff --git a/src/plugins/resourceeditor/qrceditor/resourceview.cpp b/src/plugins/resourceeditor/qrceditor/resourceview.cpp
index 8e2c70ad79..1fc524bf28 100644
--- a/src/plugins/resourceeditor/qrceditor/resourceview.cpp
+++ b/src/plugins/resourceeditor/qrceditor/resourceview.cpp
@@ -175,7 +175,7 @@ void ResourceView::removeFiles(int prefixIndex, int firstFileIndex, int lastFile
void ResourceView::keyPressEvent(QKeyEvent *e)
{
- if (e->key() == Qt::Key_Delete)
+ if (e->key() == Qt::Key_Delete || e->key() == Qt::Key_Backspace)
emit removeItem();
else
Utils::TreeView::keyPressEvent(e);
diff --git a/src/plugins/resourceeditor/resourceeditorw.cpp b/src/plugins/resourceeditor/resourceeditorw.cpp
index 2255810bb9..8467b8bf13 100644
--- a/src/plugins/resourceeditor/resourceeditorw.cpp
+++ b/src/plugins/resourceeditor/resourceeditorw.cpp
@@ -95,6 +95,7 @@ ResourceEditorW::ResourceEditorW(const Core::Context &context,
&ResourceEditorW::renameCurrentFile);
m_copyFileNameAction = m_contextMenu->addAction(tr("Copy Resource Path to Clipboard"),
this, &ResourceEditorW::copyCurrentResourcePath);
+ m_orderList = m_contextMenu->addAction(tr("Sort Alphabetically"), this, &ResourceEditorW::orderList);
connect(m_resourceDocument, &ResourceEditorDocument::loaded,
m_resourceEditor, &QrcEditor::loaded);
@@ -331,6 +332,11 @@ void ResourceEditorW::copyCurrentResourcePath()
QApplication::clipboard()->setText(m_resourceEditor->currentResourcePath());
}
+void ResourceEditorW::orderList()
+{
+ m_resourceDocument->model()->orderList();
+}
+
void ResourceEditorW::onUndo()
{
m_resourceEditor->onUndo();
diff --git a/src/plugins/resourceeditor/resourceeditorw.h b/src/plugins/resourceeditor/resourceeditorw.h
index 8ac4e8d9b2..90fbc93bb3 100644
--- a/src/plugins/resourceeditor/resourceeditorw.h
+++ b/src/plugins/resourceeditor/resourceeditorw.h
@@ -101,6 +101,7 @@ private:
void openFile(const QString &fileName);
void renameCurrentFile();
void copyCurrentResourcePath();
+ void orderList();
const QString m_extension;
const QString m_fileFilter;
@@ -114,6 +115,7 @@ private:
QToolBar *m_toolBar;
QAction *m_renameAction;
QAction *m_copyFileNameAction;
+ QAction *m_orderList;
public:
void onRefresh();
diff --git a/src/plugins/scxmleditor/common/structure.cpp b/src/plugins/scxmleditor/common/structure.cpp
index be49e9711d..96f8e29fd4 100644
--- a/src/plugins/scxmleditor/common/structure.cpp
+++ b/src/plugins/scxmleditor/common/structure.cpp
@@ -42,7 +42,7 @@
#include <QLabel>
#include <QLineEdit>
#include <QRegExp>
-#include <QRegExpValidator>
+#include <QRegularExpressionValidator>
#include <QToolBar>
#include <QToolButton>
#include <QUndoStack>
@@ -63,9 +63,9 @@ QWidget *TreeItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewI
if (index.isValid()) {
auto edit = new QLineEdit(parent);
edit->setFocusPolicy(Qt::StrongFocus);
- QRegExp rx("^(?!xml)[_a-z][a-z0-9-._]*$");
- rx.setCaseSensitivity(Qt::CaseInsensitive);
- edit->setValidator(new QRegExpValidator(rx, parent));
+ QRegularExpression rx("^(?!xml)[_a-z][a-z0-9-._]*$");
+ rx.setPatternOptions(QRegularExpression::CaseInsensitiveOption);
+ edit->setValidator(new QRegularExpressionValidator(rx, parent));
return edit;
}
return QStyledItemDelegate::createEditor(parent, option, index);
@@ -239,7 +239,7 @@ void Structure::childAdded(const QModelIndex &childIndex)
void Structure::keyPressEvent(QKeyEvent *e)
{
- if (e->key() == Qt::Key_Delete) {
+ if (e->key() == Qt::Key_Delete || e->key() == Qt::Key_Backspace) {
QModelIndex ind = m_proxyModel->mapToSource(m_structureView->currentIndex());
auto tag = static_cast<ScxmlTag*>(ind.internalPointer());
if (tag && m_currentDocument) {
diff --git a/src/plugins/scxmleditor/plugin_interface/graphicsscene.cpp b/src/plugins/scxmleditor/plugin_interface/graphicsscene.cpp
index 5513ed1ee7..863b40ae0c 100644
--- a/src/plugins/scxmleditor/plugin_interface/graphicsscene.cpp
+++ b/src/plugins/scxmleditor/plugin_interface/graphicsscene.cpp
@@ -679,7 +679,7 @@ void GraphicsScene::keyPressEvent(QKeyEvent *event)
{
QGraphicsItem *focusItem = this->focusItem();
if (!focusItem || focusItem->type() != TextType) {
- if (event->key() == Qt::Key_Delete)
+ if (event->key() == Qt::Key_Delete || event->key() == Qt::Key_Backspace)
removeSelectedItems();
}
QGraphicsScene::keyPressEvent(event);
diff --git a/src/plugins/scxmleditor/plugin_interface/scattributeitemdelegate.cpp b/src/plugins/scxmleditor/plugin_interface/scattributeitemdelegate.cpp
index 78735dcf5a..61f86671d0 100644
--- a/src/plugins/scxmleditor/plugin_interface/scattributeitemdelegate.cpp
+++ b/src/plugins/scxmleditor/plugin_interface/scattributeitemdelegate.cpp
@@ -28,7 +28,7 @@
#include <QComboBox>
#include <QLineEdit>
#include <QRegExp>
-#include <QRegExpValidator>
+#include <QRegularExpressionValidator>
using namespace ScxmlEditor::PluginInterface;
@@ -51,9 +51,10 @@ QWidget *SCAttributeItemDelegate::createEditor(QWidget *parent, const QStyleOpti
if (index.column() == 0) {
auto edit = new QLineEdit(parent);
edit->setFocusPolicy(Qt::StrongFocus);
- QRegExp rx("^(?!xml)[_a-z][a-z0-9-._]*$");
- rx.setCaseSensitivity(Qt::CaseInsensitive);
- edit->setValidator(new QRegExpValidator(rx, parent));
+ QRegularExpression rx("^(?!xml)[_a-z][a-z0-9-._]*$");
+ rx.setPatternOptions(QRegularExpression::CaseInsensitiveOption);
+
+ edit->setValidator(new QRegularExpressionValidator(rx, parent));
return edit;
}
}
diff --git a/src/plugins/scxmleditor/plugin_interface/transitionitem.cpp b/src/plugins/scxmleditor/plugin_interface/transitionitem.cpp
index e388a43cc8..fb0c5743ab 100644
--- a/src/plugins/scxmleditor/plugin_interface/transitionitem.cpp
+++ b/src/plugins/scxmleditor/plugin_interface/transitionitem.cpp
@@ -457,7 +457,7 @@ void TransitionItem::selectedMenuAction(const QAction *action)
void TransitionItem::keyPressEvent(QKeyEvent *event)
{
- if (event->key() == Qt::Key_Delete) {
+ if (event->key() == Qt::Key_Delete || event->key() == Qt::Key_Backspace) {
bool bFound = false;
if (m_cornerGrabbers.count() > 2) {
for (int i = m_cornerGrabbers.count() - 1; i >= 1; i--) {
diff --git a/src/plugins/serialterminal/serialcontrol.cpp b/src/plugins/serialterminal/serialcontrol.cpp
index 10b2dd74c1..499179482a 100644
--- a/src/plugins/serialterminal/serialcontrol.cpp
+++ b/src/plugins/serialterminal/serialcontrol.cpp
@@ -135,11 +135,6 @@ bool SerialControl::canReUseOutputPane(const SerialControl *other) const
return other->portName() == portName();
}
-Utils::OutputFormatter *SerialControl::outputFormatter()
-{
- return new Utils::OutputFormatter(); // TODO: custom formatter?
-}
-
void SerialControl::appendMessage(const QString &msg, Utils::OutputFormat format)
{
emit appendMessageRequested(this, msg, format);
diff --git a/src/plugins/serialterminal/serialcontrol.h b/src/plugins/serialterminal/serialcontrol.h
index 229bf169c6..db59db2d07 100644
--- a/src/plugins/serialterminal/serialcontrol.h
+++ b/src/plugins/serialterminal/serialcontrol.h
@@ -59,8 +59,6 @@ public:
bool canReUseOutputPane(const SerialControl *other) const;
- Utils::OutputFormatter *outputFormatter();
-
void appendMessage(const QString &msg, Utils::OutputFormat format);
QString portName() const;
diff --git a/src/plugins/serialterminal/serialoutputpane.cpp b/src/plugins/serialterminal/serialoutputpane.cpp
index e9dfb50ce7..5941cf38f1 100644
--- a/src/plugins/serialterminal/serialoutputpane.cpp
+++ b/src/plugins/serialterminal/serialoutputpane.cpp
@@ -291,7 +291,9 @@ void SerialOutputPane::createNewOutputWindow(SerialControl *rc)
connect(rc, &SerialControl::finished,
[this, rc]() {
- rc->outputFormatter()->flush();
+ const int tabIndex = indexOf(rc);
+ if (tabIndex != -1)
+ m_serialControlTabs[tabIndex].window->flush();
if (isCurrent(rc))
enableButtons(rc, false);
});
@@ -299,8 +301,6 @@ void SerialOutputPane::createNewOutputWindow(SerialControl *rc)
connect(rc, &SerialControl::appendMessageRequested,
this, &SerialOutputPane::appendMessage);
- Utils::OutputFormatter *formatter = rc->outputFormatter();
-
// Create new
static int counter = 0;
Core::Id contextId = Core::Id(Constants::C_SERIAL_OUTPUT).withSuffix(counter++);
@@ -315,7 +315,6 @@ void SerialOutputPane::createNewOutputWindow(SerialControl *rc)
this, fontSettingsChanged);
fontSettingsChanged();
ow->setWindowTitle(tr("Serial Terminal Window"));
- ow->setFormatter(formatter);
// TODO: wordwrap, maxLineCount, zoom/wheelZoom (add to settings)
auto controlTab = SerialControlTab(rc, ow);
diff --git a/src/plugins/studiowelcome/studiowelcome.qbs b/src/plugins/studiowelcome/studiowelcome.qbs
new file mode 100644
index 0000000000..b875a35c77
--- /dev/null
+++ b/src/plugins/studiowelcome/studiowelcome.qbs
@@ -0,0 +1,36 @@
+import qbs.FileInfo
+
+QtcPlugin {
+ name: "StudioWelcome"
+
+ Depends { name: "Qt"; submodules: ["qml", "quick", "quickwidgets"] }
+ Depends { name: "Utils" }
+
+ Depends { name: "Core" }
+ Depends { name: "ProjectExplorer" }
+ Depends { name: "QtSupport" }
+ Depends { name: "app_version_header" }
+
+ cpp.defines: 'STUDIO_QML_PATH="' + FileInfo.joinPaths(sourceDirectory, "qml") + '"'
+
+ files: [
+ "studiowelcome_global.h",
+ "studiowelcomeplugin.h",
+ "studiowelcomeplugin.cpp",
+ "studiowelcome.qrc",
+ ]
+
+ Group {
+ name: "studiofonts"
+ prefix: "../../share/3rdparty/studiofonts/"
+ files: "studiofonts.qrc"
+ }
+
+ Qt.core.resourceFileBaseName: "StudioWelcome_qml"
+ Qt.core.resourceSourceBase: "."
+ Group {
+ name: "Qml Files"
+ fileTags: "qt.core.resource_data"
+ files: "qml/**"
+ }
+}
diff --git a/src/plugins/texteditor/CMakeLists.txt b/src/plugins/texteditor/CMakeLists.txt
index 368afb4742..ab8d806f08 100644
--- a/src/plugins/texteditor/CMakeLists.txt
+++ b/src/plugins/texteditor/CMakeLists.txt
@@ -34,7 +34,6 @@ add_qtc_plugin(TextEditor
codeassist/runner.cpp codeassist/runner.h
codeassist/textdocumentmanipulator.cpp codeassist/textdocumentmanipulator.h
codeassist/textdocumentmanipulatorinterface.h
- codecselector.cpp codecselector.h
codestyleeditor.cpp codestyleeditor.h
codestylepool.cpp codestylepool.h
codestyleselectorwidget.cpp codestyleselectorwidget.h codestyleselectorwidget.ui
diff --git a/src/plugins/texteditor/behaviorsettingswidget.cpp b/src/plugins/texteditor/behaviorsettingswidget.cpp
index f5dc751eb6..fe7e983fad 100644
--- a/src/plugins/texteditor/behaviorsettingswidget.cpp
+++ b/src/plugins/texteditor/behaviorsettingswidget.cpp
@@ -101,6 +101,8 @@ BehaviorSettingsWidget::BehaviorSettingsWidget(QWidget *parent)
this, &BehaviorSettingsWidget::slotStorageSettingsChanged);
connect(d->m_ui.cleanIndentation, &QAbstractButton::clicked,
this, &BehaviorSettingsWidget::slotStorageSettingsChanged);
+ connect(d->m_ui.skipTrailingWhitespace, &QAbstractButton::clicked,
+ this, &BehaviorSettingsWidget::slotStorageSettingsChanged);
connect(d->m_ui.mouseHiding, &QAbstractButton::clicked,
this, &BehaviorSettingsWidget::slotBehaviorSettingsChanged);
connect(d->m_ui.mouseNavigation, &QAbstractButton::clicked,
@@ -190,6 +192,9 @@ void BehaviorSettingsWidget::setAssignedStorageSettings(const StorageSettings &s
d->m_ui.inEntireDocument->setChecked(storageSettings.m_inEntireDocument);
d->m_ui.cleanIndentation->setChecked(storageSettings.m_cleanIndentation);
d->m_ui.addFinalNewLine->setChecked(storageSettings.m_addFinalNewLine);
+ d->m_ui.skipTrailingWhitespace->setChecked(storageSettings.m_skipTrailingWhitespace);
+ d->m_ui.ignoreFileTypes->setText(storageSettings.m_ignoreFileTypes);
+ d->m_ui.ignoreFileTypes->setEnabled(d->m_ui.skipTrailingWhitespace->isChecked());
}
void BehaviorSettingsWidget::assignedStorageSettings(StorageSettings *storageSettings) const
@@ -198,6 +203,8 @@ void BehaviorSettingsWidget::assignedStorageSettings(StorageSettings *storageSet
storageSettings->m_inEntireDocument = d->m_ui.inEntireDocument->isChecked();
storageSettings->m_cleanIndentation = d->m_ui.cleanIndentation->isChecked();
storageSettings->m_addFinalNewLine = d->m_ui.addFinalNewLine->isChecked();
+ storageSettings->m_skipTrailingWhitespace = d->m_ui.skipTrailingWhitespace->isChecked();
+ storageSettings->m_ignoreFileTypes = d->m_ui.ignoreFileTypes->text();
}
void BehaviorSettingsWidget::updateConstrainTooltipsBoxTooltip() const
@@ -273,6 +280,10 @@ void BehaviorSettingsWidget::slotStorageSettingsChanged()
{
StorageSettings settings;
assignedStorageSettings(&settings);
+
+ bool ignoreFileTypesEnabled = d->m_ui.cleanWhitespace->isChecked() && d->m_ui.skipTrailingWhitespace->isChecked();
+ d->m_ui.ignoreFileTypes->setEnabled(ignoreFileTypesEnabled);
+
emit storageSettingsChanged(settings);
}
diff --git a/src/plugins/texteditor/behaviorsettingswidget.ui b/src/plugins/texteditor/behaviorsettingswidget.ui
index c36bb9ae47..d6d9fed5c6 100644
--- a/src/plugins/texteditor/behaviorsettingswidget.ui
+++ b/src/plugins/texteditor/behaviorsettingswidget.ui
@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>801</width>
- <height>547</height>
+ <height>693</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
@@ -169,13 +169,72 @@ Specifies how backspace interacts with indentation.
<string>Cleanups Upon Saving</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
- <item row="0" column="0" colspan="2">
- <widget class="QCheckBox" name="cleanWhitespace">
+ <item row="5" column="1">
+ <widget class="QWidget" name="widget" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QCheckBox" name="skipTrailingWhitespace">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="toolTip">
+ <string>For the file patterns listed, do not trim trailing whitespace.</string>
+ </property>
+ <property name="text">
+ <string>Skip clean whitespace for file types:</string>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ <property name="tristate">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="ignoreFileTypes">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="acceptDrops">
+ <bool>false</bool>
+ </property>
+ <property name="toolTip">
+ <string>List of wildcard-aware file patterns, separated by commas or semicolons.</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="9" column="0" colspan="2">
+ <widget class="QCheckBox" name="addFinalNewLine">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
<property name="toolTip">
- <string>Removes trailing whitespace upon saving.</string>
+ <string>Always writes a newline character at the end of the file.</string>
</property>
<property name="text">
- <string>&amp;Clean whitespace</string>
+ <string>&amp;Ensure newline at end of file</string>
</property>
</widget>
</item>
@@ -195,26 +254,17 @@ Specifies how backspace interacts with indentation.
</property>
</spacer>
</item>
- <item row="1" column="1">
- <widget class="QCheckBox" name="inEntireDocument">
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="sizePolicy">
- <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
+ <item row="0" column="0" colspan="2">
+ <widget class="QCheckBox" name="cleanWhitespace">
<property name="toolTip">
- <string>Cleans whitespace in entire document instead of only for changed parts.</string>
+ <string>Removes trailing whitespace upon saving.</string>
</property>
<property name="text">
- <string>In entire &amp;document</string>
+ <string>&amp;Clean whitespace</string>
</property>
</widget>
</item>
- <item row="2" column="1">
+ <item row="3" column="1">
<widget class="QCheckBox" name="cleanIndentation">
<property name="enabled">
<bool>false</bool>
@@ -227,13 +277,22 @@ Specifies how backspace interacts with indentation.
</property>
</widget>
</item>
- <item row="3" column="0" colspan="2">
- <widget class="QCheckBox" name="addFinalNewLine">
+ <item row="1" column="1">
+ <widget class="QCheckBox" name="inEntireDocument">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
<property name="toolTip">
- <string>Always writes a newline character at the end of the file.</string>
+ <string>Cleans whitespace in entire document instead of only for changed parts.</string>
</property>
<property name="text">
- <string>&amp;Ensure newline at end of file</string>
+ <string>In entire &amp;document</string>
</property>
</widget>
</item>
@@ -521,5 +580,37 @@ Specifies how backspace interacts with indentation.
</hint>
</hints>
</connection>
+ <connection>
+ <sender>cleanWhitespace</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>skipTrailingWhitespace</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>530</x>
+ <y>48</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>548</x>
+ <y>144</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>cleanWhitespace</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>ignoreFileTypes</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>530</x>
+ <y>48</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>556</x>
+ <y>177</y>
+ </hint>
+ </hints>
+ </connection>
</connections>
</ui>
diff --git a/src/plugins/texteditor/codeassist/codeassistant.cpp b/src/plugins/texteditor/codeassist/codeassistant.cpp
index b115489674..ce90f64b48 100644
--- a/src/plugins/texteditor/codeassist/codeassistant.cpp
+++ b/src/plugins/texteditor/codeassist/codeassistant.cpp
@@ -252,19 +252,20 @@ void CodeAssistantPrivate::requestProposal(AssistReason reason,
break;
}
case IAssistProvider::Asynchronous: {
- processor->setAsyncCompletionAvailableHandler(
- [this, reason](IAssistProposal *newProposal){
- if (m_asyncProcessor && m_asyncProcessor->needsRestart() && m_receivedContentWhileWaiting) {
- delete newProposal;
- m_receivedContentWhileWaiting = false;
- invalidateCurrentRequestData();
- requestProposal(reason, m_assistKind, m_requestProvider);
- } else {
- invalidateCurrentRequestData();
- displayProposal(newProposal, reason);
-
- emit q->finished();
- }
+ processor->setAsyncCompletionAvailableHandler([this, reason, processor](IAssistProposal *newProposal) {
+ // do not delete this processor directly since this function is called from within the processor
+ QTimer::singleShot(0, [processor]() { delete processor; });
+ if (processor != m_asyncProcessor)
+ return;
+ invalidateCurrentRequestData();
+ if (processor && processor->needsRestart() && m_receivedContentWhileWaiting) {
+ delete newProposal;
+ m_receivedContentWhileWaiting = false;
+ requestProposal(reason, m_assistKind, m_requestProvider);
+ } else {
+ displayProposal(newProposal, reason);
+ emit q->finished();
+ }
});
// If there is a proposal, nothing asynchronous happened...
@@ -274,6 +275,7 @@ void CodeAssistantPrivate::requestProposal(AssistReason reason,
} else if (!processor->running()) {
delete processor;
} else { // ...async request was triggered
+ QTC_CHECK(!m_asyncProcessor);
m_asyncProcessor = processor;
}
@@ -288,8 +290,10 @@ void CodeAssistantPrivate::cancelCurrentRequest()
m_requestRunner->setDiscardProposal(true);
disconnect(m_runnerConnection);
}
- if (m_asyncProcessor)
+ if (m_asyncProcessor) {
m_asyncProcessor->cancel();
+ delete m_asyncProcessor;
+ }
invalidateCurrentRequestData();
}
diff --git a/src/plugins/texteditor/findinfiles.cpp b/src/plugins/texteditor/findinfiles.cpp
index 3acd20f51b..85073877ac 100644
--- a/src/plugins/texteditor/findinfiles.cpp
+++ b/src/plugins/texteditor/findinfiles.cpp
@@ -205,7 +205,7 @@ QWidget *FindInFiles::createConfigWidget()
FilePath FindInFiles::path() const
{
- return m_directory->fileName();
+ return m_directory->filePath();
}
void FindInFiles::writeSettings(QSettings *settings)
@@ -224,7 +224,7 @@ void FindInFiles::readSettings(QSettings *settings)
void FindInFiles::setDirectory(const FilePath &directory)
{
- m_directory->setFileName(directory);
+ m_directory->setFilePath(directory);
}
void FindInFiles::setBaseDirectory(const FilePath &directory)
@@ -234,7 +234,7 @@ void FindInFiles::setBaseDirectory(const FilePath &directory)
FilePath FindInFiles::directory() const
{
- return m_directory->fileName();
+ return m_directory->filePath();
}
void FindInFiles::findOnFileSystem(const QString &path)
diff --git a/src/plugins/texteditor/highlighter.cpp b/src/plugins/texteditor/highlighter.cpp
index 29b5a8eab5..a81d66a3af 100644
--- a/src/plugins/texteditor/highlighter.cpp
+++ b/src/plugins/texteditor/highlighter.cpp
@@ -110,35 +110,6 @@ Highlighter::Highlighter()
&categoryForTextStyle);
}
-Highlighter::Definition Highlighter::definitionForDocument(const TextDocument *document)
-{
- const Utils::MimeType mimeType = Utils::mimeTypeForName(document->mimeType());
- Definition definition;
- if (mimeType.isValid())
- definition = Highlighter::definitionForMimeType(mimeType.name());
- if (!definition.isValid())
- definition = Highlighter::definitionForFilePath(document->filePath());
- return definition;
-}
-
-Highlighter::Definition Highlighter::definitionForMimeType(const QString &mimeType)
-{
- if (mimeType.isEmpty())
- return {};
- const Definitions definitions = definitionsForMimeType(mimeType);
- if (definitions.size() == 1)
- return definitions.first();
- return highlightRepository()->definitionForMimeType(mimeType);
-}
-
-Highlighter::Definition Highlighter::definitionForFilePath(const Utils::FilePath &fileName)
-{
- const Definitions definitions = definitionsForFileName(fileName);
- if (definitions.size() == 1)
- return definitions.first();
- return highlightRepository()->definitionForFileName(fileName.fileName());
-}
-
Highlighter::Definition Highlighter::definitionForName(const QString &name)
{
return highlightRepository()->definitionForName(name);
@@ -147,22 +118,20 @@ Highlighter::Definition Highlighter::definitionForName(const QString &name)
Highlighter::Definitions Highlighter::definitionsForDocument(const TextDocument *document)
{
QTC_ASSERT(document, return {});
+ // First try to find definitions for the file path, only afterwards try the MIME type.
+ // An example where that is important is if there was a definition for "*.rb.xml", which
+ // cannot be referred to with a MIME type (since there is none), but there is the definition
+ // for XML files, which specifies a MIME type in addition to a glob pattern.
+ // If we check the MIME type first and then skip the pattern, the definition for "*.rb.xml" is
+ // never considered.
+ // The KSyntaxHighlighting CLI also completely ignores MIME types.
+ const Definitions &fileNameDefinitions = definitionsForFileName(document->filePath());
+ if (!fileNameDefinitions.isEmpty())
+ return fileNameDefinitions;
const Utils::MimeType &mimeType = Utils::mimeTypeForName(document->mimeType());
- if (mimeType.isValid()) {
- if (mimeType.name() == "text/plain") {
- // text/plain is the base mime type for all text types so ignore it and try matching the
- // file name against the pattern and only if no definition can be found for the
- // file name try matching the mime type
- const Definitions &fileNameDefinitions = definitionsForFileName(document->filePath());
- if (!fileNameDefinitions.isEmpty())
- return fileNameDefinitions;
- return definitionsForMimeType(mimeType.name());
- }
- const Definitions &mimeTypeDefinitions = definitionsForMimeType(mimeType.name());
- if (!mimeTypeDefinitions.isEmpty())
- return mimeTypeDefinitions;
- }
- return definitionsForFileName(document->filePath());
+ if (!mimeType.isValid())
+ return fileNameDefinitions;
+ return definitionsForMimeType(mimeType.name());
}
static Highlighter::Definition definitionForSetting(const QString &settingsKey,
@@ -206,8 +175,8 @@ Highlighter::Definitions Highlighter::definitionsForFileName(const Utils::FilePa
return definitions;
}
-void Highlighter::rememberDefintionForDocument(const Highlighter::Definition &definition,
- const TextDocument *document)
+void Highlighter::rememberDefinitionForDocument(const Highlighter::Definition &definition,
+ const TextDocument *document)
{
QTC_ASSERT(document, return );
if (!definition.isValid())
@@ -236,7 +205,7 @@ void Highlighter::rememberDefintionForDocument(const Highlighter::Definition &de
settings->endGroup();
}
-void Highlighter::clearDefintionForDocumentCache()
+void Highlighter::clearDefinitionForDocumentCache()
{
QSettings *settings = Core::ICore::settings();
settings->beginGroup(Constants::HIGHLIGHTER_SETTINGS_CATEGORY);
diff --git a/src/plugins/texteditor/highlighter.h b/src/plugins/texteditor/highlighter.h
index 0a23009c23..e18a67e8f8 100644
--- a/src/plugins/texteditor/highlighter.h
+++ b/src/plugins/texteditor/highlighter.h
@@ -44,18 +44,15 @@ public:
using Definitions = QList<Definition>;
Highlighter();
- static Definition definitionForDocument(const TextDocument *document);
- static Definition definitionForMimeType(const QString &mimeType);
- static Definition definitionForFilePath(const Utils::FilePath &fileName);
static Definition definitionForName(const QString &name);
static Definitions definitionsForDocument(const TextDocument *document);
static Definitions definitionsForMimeType(const QString &mimeType);
static Definitions definitionsForFileName(const Utils::FilePath &fileName);
- static void rememberDefintionForDocument(const Definition &definition,
- const TextDocument *document);
- static void clearDefintionForDocumentCache();
+ static void rememberDefinitionForDocument(const Definition &definition,
+ const TextDocument *document);
+ static void clearDefinitionForDocumentCache();
static void addCustomHighlighterPath(const Utils::FilePath &path);
static void downloadDefinitions(std::function<void()> callback = nullptr);
diff --git a/src/plugins/texteditor/highlightersettingspage.cpp b/src/plugins/texteditor/highlightersettingspage.cpp
index e0a7f12c49..7180e1dc14 100644
--- a/src/plugins/texteditor/highlightersettingspage.cpp
+++ b/src/plugins/texteditor/highlightersettingspage.cpp
@@ -116,7 +116,7 @@ QWidget *HighlighterSettingsPage::widget()
Highlighter::reload();
});
connect(m_d->m_page->resetCache, &QPushButton::clicked, []() {
- Highlighter::clearDefintionForDocumentCache();
+ Highlighter::clearDefinitionForDocumentCache();
});
settingsToUI();
@@ -150,7 +150,7 @@ const HighlighterSettings &HighlighterSettingsPage::highlighterSettings() const
void HighlighterSettingsPage::settingsFromUI()
{
m_d->ensureInitialized();
- m_d->m_settings.setDefinitionFilesPath(m_d->m_page->definitionFilesPath->path());
+ m_d->m_settings.setDefinitionFilesPath(m_d->m_page->definitionFilesPath->filePath().toString());
m_d->m_settings.setIgnoredFilesPatterns(m_d->m_page->ignoreEdit->text());
m_d->m_settings.toSettings(m_d->m_settingsPrefix, Core::ICore::settings());
}
@@ -165,6 +165,6 @@ void HighlighterSettingsPage::settingsToUI()
bool HighlighterSettingsPage::settingsChanged() const
{
m_d->ensureInitialized();
- return (m_d->m_settings.definitionFilesPath() != m_d->m_page->definitionFilesPath->path())
+ return (m_d->m_settings.definitionFilesPath() != m_d->m_page->definitionFilesPath->filePath().toString())
|| (m_d->m_settings.ignoredFilesPatterns() != m_d->m_page->ignoreEdit->text());
}
diff --git a/src/plugins/texteditor/indenter.h b/src/plugins/texteditor/indenter.h
index 7248d1721c..5dbf7ac2db 100644
--- a/src/plugins/texteditor/indenter.h
+++ b/src/plugins/texteditor/indenter.h
@@ -85,7 +85,6 @@ public:
indent(cursor, QChar::Null, tabSettings, cursorPositionInEditor);
}
- // By default just calls indent with default settings.
virtual Utils::Text::Replacements format(const RangesInLines & /*rangesInLines*/)
{
return Utils::Text::Replacements();
diff --git a/src/plugins/texteditor/storagesettings.cpp b/src/plugins/texteditor/storagesettings.cpp
index a1c4645b0c..a4b805f92f 100644
--- a/src/plugins/texteditor/storagesettings.cpp
+++ b/src/plugins/texteditor/storagesettings.cpp
@@ -25,8 +25,10 @@
#include "storagesettings.h"
+#include <utils/hostosinfo.h>
#include <utils/settingsutils.h>
+#include <QRegularExpression>
#include <QSettings>
#include <QString>
@@ -36,13 +38,18 @@ static const char cleanWhitespaceKey[] = "cleanWhitespace";
static const char inEntireDocumentKey[] = "inEntireDocument";
static const char addFinalNewLineKey[] = "addFinalNewLine";
static const char cleanIndentationKey[] = "cleanIndentation";
+static const char skipTrailingWhitespaceKey[] = "skipTrailingWhitespace";
+static const char ignoreFileTypesKey[] = "ignoreFileTypes";
static const char groupPostfix[] = "StorageSettings";
+static const char defaultTrailingWhitespaceBlacklist[] = "*.md, *.MD, Makefile";
StorageSettings::StorageSettings()
- : m_cleanWhitespace(true),
+ : m_ignoreFileTypes(defaultTrailingWhitespaceBlacklist),
+ m_cleanWhitespace(true),
m_inEntireDocument(false),
m_addFinalNewLine(true),
- m_cleanIndentation(true)
+ m_cleanIndentation(true),
+ m_skipTrailingWhitespace(true)
{
}
@@ -63,6 +70,8 @@ void StorageSettings::toMap(const QString &prefix, QVariantMap *map) const
map->insert(prefix + QLatin1String(inEntireDocumentKey), m_inEntireDocument);
map->insert(prefix + QLatin1String(addFinalNewLineKey), m_addFinalNewLine);
map->insert(prefix + QLatin1String(cleanIndentationKey), m_cleanIndentation);
+ map->insert(prefix + QLatin1String(skipTrailingWhitespaceKey), m_skipTrailingWhitespace);
+ map->insert(prefix + QLatin1String(ignoreFileTypesKey), m_ignoreFileTypes.toLatin1().data());
}
void StorageSettings::fromMap(const QString &prefix, const QVariantMap &map)
@@ -75,6 +84,56 @@ void StorageSettings::fromMap(const QString &prefix, const QVariantMap &map)
map.value(prefix + QLatin1String(addFinalNewLineKey), m_addFinalNewLine).toBool();
m_cleanIndentation =
map.value(prefix + QLatin1String(cleanIndentationKey), m_cleanIndentation).toBool();
+ m_skipTrailingWhitespace =
+ map.value(prefix + QLatin1String(skipTrailingWhitespaceKey), m_skipTrailingWhitespace).toBool();
+ m_ignoreFileTypes =
+ map.value(prefix + QLatin1String(ignoreFileTypesKey), m_ignoreFileTypes).toString();
+}
+
+bool StorageSettings::removeTrailingWhitespace(const QString &fileName) const
+{
+ // if the user has elected not to trim trailing whitespace altogether, then
+ // early out here
+ if (!m_skipTrailingWhitespace) {
+ return true;
+ }
+
+ const QString ignoreFileTypesRegExp(R"(\s*((?>\*\.)?[\w\d\.\*]+)[,;]?\s*)");
+
+ // use the ignore-files regex to extract the specified file patterns
+ QRegularExpression re(ignoreFileTypesRegExp);
+ QRegularExpressionMatchIterator iter = re.globalMatch(m_ignoreFileTypes);
+
+ while (iter.hasNext()) {
+ QRegularExpressionMatch match = iter.next();
+ QString pattern = match.captured(1);
+
+ QString wildcardRegExp
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
+ = QRegularExpression::wildcardToRegularExpression(pattern);
+#else
+ = pattern;
+ // handle at least the most likely appearing
+ wildcardRegExp.replace('.', "\\.");
+ wildcardRegExp.replace('$', "\\$");
+ wildcardRegExp.replace('(', "\\(").replace(')', "\\)");
+ wildcardRegExp.replace('[', "\\[").replace(']', "\\]");
+ wildcardRegExp.replace('{', "\\{").replace('}', "\\}");
+ wildcardRegExp.replace('+', "\\+");
+ wildcardRegExp.replace('*', ".*");
+ wildcardRegExp.replace('?', '.');
+#endif
+ QRegularExpression patternRegExp(wildcardRegExp);
+ QRegularExpressionMatch patternMatch = patternRegExp.match(fileName);
+ if (patternMatch.hasMatch()) {
+ // if the filename has a pattern we want to ignore, then we need to return
+ // false ("don't remove trailing whitespace")
+ return false;
+ }
+ }
+
+ // the supplied pattern does not match, so we want to remove trailing whitespace
+ return true;
}
bool StorageSettings::equals(const StorageSettings &ts) const
@@ -82,7 +141,9 @@ bool StorageSettings::equals(const StorageSettings &ts) const
return m_addFinalNewLine == ts.m_addFinalNewLine
&& m_cleanWhitespace == ts.m_cleanWhitespace
&& m_inEntireDocument == ts.m_inEntireDocument
- && m_cleanIndentation == ts.m_cleanIndentation;
+ && m_cleanIndentation == ts.m_cleanIndentation
+ && m_skipTrailingWhitespace == ts.m_skipTrailingWhitespace
+ && m_ignoreFileTypes == ts.m_ignoreFileTypes;
}
} // namespace TextEditor
diff --git a/src/plugins/texteditor/storagesettings.h b/src/plugins/texteditor/storagesettings.h
index ffe7823f0f..cd9c176b59 100644
--- a/src/plugins/texteditor/storagesettings.h
+++ b/src/plugins/texteditor/storagesettings.h
@@ -46,12 +46,17 @@ public:
void toMap(const QString &prefix, QVariantMap *map) const;
void fromMap(const QString &prefix, const QVariantMap &map);
+ // calculated based on boolean setting plus file type blacklist examination
+ bool removeTrailingWhitespace(const QString &filePattern) const;
+
bool equals(const StorageSettings &ts) const;
+ QString m_ignoreFileTypes;
bool m_cleanWhitespace;
bool m_inEntireDocument;
bool m_addFinalNewLine;
bool m_cleanIndentation;
+ bool m_skipTrailingWhitespace;
};
inline bool operator==(const StorageSettings &t1, const StorageSettings &t2) { return t1.equals(t2); }
diff --git a/src/plugins/texteditor/textdocument.cpp b/src/plugins/texteditor/textdocument.cpp
index 319f77a397..0f3ef7a05f 100644
--- a/src/plugins/texteditor/textdocument.cpp
+++ b/src/plugins/texteditor/textdocument.cpp
@@ -622,7 +622,7 @@ bool TextDocument::save(QString *errorString, const QString &saveFileName, bool
cursor.movePosition(QTextCursor::Start);
if (d->m_storageSettings.m_cleanWhitespace)
- cleanWhitespace(cursor, d->m_storageSettings.m_cleanIndentation, d->m_storageSettings.m_inEntireDocument);
+ cleanWhitespace(cursor, d->m_storageSettings);
if (d->m_storageSettings.m_addFinalNewLine)
ensureFinalNewLine(cursor);
cursor.endEditBlock();
@@ -883,14 +883,22 @@ void TextDocument::cleanWhitespace(const QTextCursor &cursor)
QTextCursor copyCursor = cursor;
copyCursor.setVisualNavigation(false);
copyCursor.beginEditBlock();
- cleanWhitespace(copyCursor, true, true);
+
+ cleanWhitespace(copyCursor, d->m_storageSettings);
+
if (!hasSelection)
ensureFinalNewLine(copyCursor);
+
copyCursor.endEditBlock();
}
-void TextDocument::cleanWhitespace(QTextCursor &cursor, bool cleanIndentation, bool inEntireDocument)
+void TextDocument::cleanWhitespace(QTextCursor &cursor, const StorageSettings &storageSettings)
{
+ if (!d->m_storageSettings.m_cleanWhitespace)
+ return;
+
+ const QString fileName(filePath().fileName());
+
auto documentLayout = qobject_cast<TextDocumentLayout*>(d->m_document.documentLayout());
Q_ASSERT(cursor.visualNavigation() == false);
@@ -901,7 +909,7 @@ void TextDocument::cleanWhitespace(QTextCursor &cursor, bool cleanIndentation, b
QVector<QTextBlock> blocks;
while (block.isValid() && block != end) {
- if (inEntireDocument || block.revision() != documentLayout->lastSaveRevision)
+ if (storageSettings.m_inEntireDocument || block.revision() != documentLayout->lastSaveRevision)
blocks.append(block);
block = block.next();
}
@@ -914,9 +922,12 @@ void TextDocument::cleanWhitespace(QTextCursor &cursor, bool cleanIndentation, b
foreach (block, blocks) {
QString blockText = block.text();
- currentTabSettings.removeTrailingWhitespace(cursor, block);
+
+ if (storageSettings.removeTrailingWhitespace(fileName))
+ currentTabSettings.removeTrailingWhitespace(cursor, block);
+
const int indent = indentations[block.blockNumber()];
- if (cleanIndentation && !currentTabSettings.isIndentationClean(block, indent)) {
+ if (storageSettings.m_cleanIndentation && !currentTabSettings.isIndentationClean(block, indent)) {
cursor.setPosition(block.position());
int firstNonSpace = currentTabSettings.firstNonSpace(blockText);
if (firstNonSpace == blockText.length()) {
@@ -934,6 +945,9 @@ void TextDocument::cleanWhitespace(QTextCursor &cursor, bool cleanIndentation, b
void TextDocument::ensureFinalNewLine(QTextCursor& cursor)
{
+ if (!d->m_storageSettings.m_addFinalNewLine)
+ return;
+
cursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);
bool emptyFile = !cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
diff --git a/src/plugins/texteditor/textdocument.h b/src/plugins/texteditor/textdocument.h
index 447edd0e50..35e6b334ef 100644
--- a/src/plugins/texteditor/textdocument.h
+++ b/src/plugins/texteditor/textdocument.h
@@ -169,7 +169,7 @@ protected:
private:
OpenResult openImpl(QString *errorString, const QString &fileName, const QString &realFileName,
bool reload);
- void cleanWhitespace(QTextCursor &cursor, bool cleanIndentation, bool inEntireDocument);
+ void cleanWhitespace(QTextCursor &cursor, const StorageSettings &storageSettings);
void ensureFinalNewLine(QTextCursor &cursor);
void modificationChanged(bool modified);
void updateLayout() const;
diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp
index a44eb794a2..2c32af5b28 100644
--- a/src/plugins/texteditor/texteditor.cpp
+++ b/src/plugins/texteditor/texteditor.cpp
@@ -35,7 +35,6 @@
#include "behaviorsettings.h"
#include "circularclipboard.h"
#include "circularclipboardassist.h"
-#include "codecselector.h"
#include "completionsettings.h"
#include "extraencodingsettings.h"
#include "highlighter.h"
@@ -59,6 +58,7 @@
#include <texteditor/codeassist/completionassistprovider.h>
#include <texteditor/codeassist/documentcontentcompletion.h>
+#include <coreplugin/dialogs/codecselector.h>
#include <coreplugin/icore.h>
#include <aggregation/aggregate.h>
#include <coreplugin/actionmanager/actionmanager.h>
@@ -194,6 +194,8 @@ private:
TextEditorWidget::tr("Line: %1, Col: %2")
.arg(line)
.arg(m_editor->textDocument()->tabSettings().columnAt(block.text(), column) + 1));
+ setToolTip(TextEditorWidget::tr("Cursor position: %1")
+ .arg(QString::number(cursor.position())));
}
TextEditorWidget *m_editor;
@@ -1963,6 +1965,11 @@ void TextEditorWidget::findUsages()
emit requestUsages(textCursor());
}
+void TextEditorWidget::renameSymbolUnderCursor()
+{
+ emit requestRename(textCursor());
+}
+
void TextEditorWidget::abortAssist()
{
d->m_codeAssistant.destroyContext();
@@ -2501,6 +2508,10 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e)
case Qt::Key_Down:
case Qt::Key_Right:
case Qt::Key_Left:
+ case Qt::Key_PageUp:
+ case Qt::Key_PageDown:
+ case Qt::Key_Home:
+ case Qt::Key_End:
if (HostOsInfo::isMacHost())
break;
if ((e->modifiers()
@@ -2523,6 +2534,22 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e)
case Qt::Key_Right:
++d->m_blockSelection.positionColumn;
break;
+ case Qt::Key_PageUp:
+ d->m_blockSelection.positionBlock -= verticalScrollBar()->pageStep();
+ if (d->m_blockSelection.positionBlock < 0)
+ d->m_blockSelection.positionBlock = 0;
+ break;
+ case Qt::Key_PageDown:
+ d->m_blockSelection.positionBlock += verticalScrollBar()->pageStep();
+ if (d->m_blockSelection.positionBlock > document()->blockCount() - 1)
+ d->m_blockSelection.positionBlock = document()->blockCount() - 1;
+ break;
+ case Qt::Key_Home:
+ d->m_blockSelection.positionBlock = 0;
+ break;
+ case Qt::Key_End:
+ d->m_blockSelection.positionBlock = document()->blockCount() - 1;
+ break;
default:
break;
}
@@ -3187,7 +3214,7 @@ void TextEditorWidgetPrivate::rememberCurrentSyntaxDefinition()
return;
const Highlighter::Definition &definition = highlighter->definition();
if (definition.isValid())
- Highlighter::rememberDefintionForDocument(definition, m_document.data());
+ Highlighter::rememberDefinitionForDocument(definition, m_document.data());
}
bool TextEditorWidget::codeFoldingVisible() const
diff --git a/src/plugins/texteditor/texteditor.h b/src/plugins/texteditor/texteditor.h
index f7b69b4822..ad95abe3cd 100644
--- a/src/plugins/texteditor/texteditor.h
+++ b/src/plugins/texteditor/texteditor.h
@@ -453,6 +453,7 @@ public:
void openLinkUnderCursorInNextSplit();
virtual void findUsages();
+ virtual void renameSymbolUnderCursor();
/// Abort code assistant if it is running.
void abortAssist();
@@ -490,6 +491,7 @@ signals:
void requestLinkAt(const QTextCursor &cursor, Utils::ProcessLinkCallback &callback,
bool resolveTarget, bool inNextSplit);
void requestUsages(const QTextCursor &cursor);
+ void requestRename(const QTextCursor &cursor);
protected:
QTextBlock blockForVisibleRow(int row) const;
diff --git a/src/plugins/texteditor/texteditor.pro b/src/plugins/texteditor/texteditor.pro
index 6892ddd79c..bbf536459e 100644
--- a/src/plugins/texteditor/texteditor.pro
+++ b/src/plugins/texteditor/texteditor.pro
@@ -33,7 +33,6 @@ SOURCES += texteditorplugin.cpp \
findinfiles.cpp \
basefilefind.cpp \
texteditorsettings.cpp \
- codecselector.cpp \
findincurrentfile.cpp \
findinopenfiles.cpp \
colorscheme.cpp \
@@ -120,7 +119,6 @@ HEADERS += texteditorplugin.h \
findinfiles.h \
basefilefind.h \
texteditorsettings.h \
- codecselector.h \
findincurrentfile.h \
findinopenfiles.h \
colorscheme.h \
diff --git a/src/plugins/texteditor/texteditor.qbs b/src/plugins/texteditor/texteditor.qbs
index 6564c97b0c..fb43695ef9 100644
--- a/src/plugins/texteditor/texteditor.qbs
+++ b/src/plugins/texteditor/texteditor.qbs
@@ -41,8 +41,6 @@ Project {
"circularclipboard.h",
"circularclipboardassist.cpp",
"circularclipboardassist.h",
- "codecselector.cpp",
- "codecselector.h",
"codestyleeditor.cpp",
"codestyleeditor.h",
"codestylepool.cpp",
diff --git a/src/plugins/texteditor/texteditoractionhandler.cpp b/src/plugins/texteditor/texteditoractionhandler.cpp
index 67d5898509..1077417859 100644
--- a/src/plugins/texteditor/texteditoractionhandler.cpp
+++ b/src/plugins/texteditor/texteditoractionhandler.cpp
@@ -182,6 +182,7 @@ public:
QAction *m_followSymbolAction = nullptr;
QAction *m_followSymbolInNextSplitAction = nullptr;
QAction *m_findUsageAction = nullptr;
+ QAction *m_renameSymbolAction = nullptr;
QAction *m_jumpToFileAction = nullptr;
QAction *m_jumpToFileInNextSplitAction = nullptr;
QList<QAction *> m_modifyingActions;
@@ -285,6 +286,9 @@ void TextEditorActionHandlerPrivate::createActions()
m_findUsageAction = registerAction(FIND_USAGES,
[] (TextEditorWidget *w) { w->findUsages(); }, true, tr("Find References to Symbol Under Cursor"),
QKeySequence(tr("Ctrl+Shift+U")));
+ m_renameSymbolAction = registerAction(RENAME_SYMBOL,
+ [] (TextEditorWidget *w) { w->renameSymbolUnderCursor(); }, true, tr("Rename Symbol Under Cursor"),
+ QKeySequence(tr("Ctrl+Shift+R")));
m_jumpToFileAction = registerAction(JUMP_TO_FILE_UNDER_CURSOR,
[] (TextEditorWidget *w) { w->openLinkUnderCursor(); }, true, tr("Jump to File Under Cursor"),
QKeySequence(Qt::Key_F2));
@@ -519,6 +523,7 @@ void TextEditorActionHandlerPrivate::createActions()
m_jumpToFileAction->setEnabled(m_optionalActions & TextEditorActionHandler::JumpToFileUnderCursor);
m_jumpToFileInNextSplitAction->setEnabled(m_optionalActions & TextEditorActionHandler::JumpToFileUnderCursor);
m_unfoldAllAction->setEnabled(m_optionalActions & TextEditorActionHandler::UnCollapseAll);
+ m_renameSymbolAction->setEnabled(m_optionalActions & TextEditorActionHandler::RenameSymbol);
}
void TextEditorActionHandlerPrivate::updateActions()
diff --git a/src/plugins/texteditor/texteditoractionhandler.h b/src/plugins/texteditor/texteditoractionhandler.h
index f91ad7a806..cfa684a13d 100644
--- a/src/plugins/texteditor/texteditoractionhandler.h
+++ b/src/plugins/texteditor/texteditoractionhandler.h
@@ -55,7 +55,8 @@ public:
UnCommentSelection = 2,
UnCollapseAll = 4,
FollowSymbolUnderCursor = 8,
- JumpToFileUnderCursor = 16
+ JumpToFileUnderCursor = 16,
+ RenameSymbol = 32,
};
using TextEditorWidgetResolver = std::function<TextEditorWidget *(Core::IEditor *)>;
diff --git a/src/plugins/texteditor/texteditorconstants.h b/src/plugins/texteditor/texteditorconstants.h
index 3435a713af..c74bbfcde8 100644
--- a/src/plugins/texteditor/texteditorconstants.h
+++ b/src/plugins/texteditor/texteditorconstants.h
@@ -201,6 +201,8 @@ const char UNINDENT[] = "TextEditor.Unindent";
const char FOLLOW_SYMBOL_UNDER_CURSOR[] = "TextEditor.FollowSymbolUnderCursor";
const char FOLLOW_SYMBOL_UNDER_CURSOR_IN_NEXT_SPLIT[] = "TextEditor.FollowSymbolUnderCursorInNextSplit";
const char FIND_USAGES[] = "TextEditor.FindUsages";
+// moved from CppEditor to TextEditor avoid breaking the setting by using the old key
+const char RENAME_SYMBOL[] = "CppEditor.RenameSymbolUnderCursor";
const char JUMP_TO_FILE_UNDER_CURSOR[] = "TextEditor.JumpToFileUnderCursor";
const char JUMP_TO_FILE_UNDER_CURSOR_IN_NEXT_SPLIT[] = "TextEditor.JumpToFileUnderCursorInNextSplit";
diff --git a/src/plugins/todo/todooutputpane.cpp b/src/plugins/todo/todooutputpane.cpp
index 940f6e97f2..a4a3fa1cce 100644
--- a/src/plugins/todo/todooutputpane.cpp
+++ b/src/plugins/todo/todooutputpane.cpp
@@ -202,7 +202,7 @@ void TodoOutputPane::updateKeywordFilter()
int sortColumn = m_todoTreeView->header()->sortIndicatorSection();
Qt::SortOrder sortOrder = m_todoTreeView->header()->sortIndicatorOrder();
- m_filteredTodoItemsModel->setFilterRegExp(pattern);
+ m_filteredTodoItemsModel->setFilterRegularExpression(pattern);
m_filteredTodoItemsModel->sort(sortColumn, sortOrder);
updateTodoCount();
diff --git a/src/plugins/valgrind/callgrind/callgrindproxymodel.cpp b/src/plugins/valgrind/callgrind/callgrindproxymodel.cpp
index 13809a83d4..66a362f495 100644
--- a/src/plugins/valgrind/callgrind/callgrindproxymodel.cpp
+++ b/src/plugins/valgrind/callgrind/callgrindproxymodel.cpp
@@ -109,7 +109,7 @@ bool DataProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_
return false;
// if the filter regexp is a non-empty string, ignore our filters
- if (!filterRegExp().isEmpty())
+ if (!filterRegularExpression().pattern().isEmpty())
return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
// check max rows
diff --git a/src/plugins/valgrind/callgrindtool.cpp b/src/plugins/valgrind/callgrindtool.cpp
index 92ed908ac9..867b77f49e 100644
--- a/src/plugins/valgrind/callgrindtool.cpp
+++ b/src/plugins/valgrind/callgrindtool.cpp
@@ -554,7 +554,7 @@ void CallgrindToolPrivate::doClear(bool clearParseData)
m_proxyModel.setFilterBaseDir(QString());
if (m_searchFilter)
m_searchFilter->clear();
- m_proxyModel.setFilterFixedString(QString());
+ m_proxyModel.setFilterRegularExpression(QRegularExpression());
}
void CallgrindToolPrivate::setBusyCursor(bool busy)
@@ -609,7 +609,7 @@ void CallgrindToolPrivate::stackBrowserChanged()
void CallgrindToolPrivate::updateFilterString()
{
- m_proxyModel.setFilterFixedString(m_searchFilter->text());
+ m_proxyModel.setFilterRegularExpression(QRegularExpression::escape(m_searchFilter->text()));
}
void CallgrindToolPrivate::setCostFormat(CostDelegate::CostFormat format)
diff --git a/src/plugins/valgrind/memcheckerrorview.cpp b/src/plugins/valgrind/memcheckerrorview.cpp
index 3dfa939ddd..0e45b76d43 100644
--- a/src/plugins/valgrind/memcheckerrorview.cpp
+++ b/src/plugins/valgrind/memcheckerrorview.cpp
@@ -61,7 +61,7 @@ MemcheckErrorView::MemcheckErrorView(QWidget *parent)
{":/valgrind/images/suppressoverlay.png", Utils::Theme::IconsErrorColor}},
Utils::Icon::Tint | Utils::Icon::PunchEdges).icon();
m_suppressAction->setIcon(icon);
- m_suppressAction->setShortcut(QKeySequence(Qt::Key_Delete));
+ m_suppressAction->setShortcuts({QKeySequence::Delete, QKeySequence::Backspace});
m_suppressAction->setShortcutContext(Qt::WidgetWithChildrenShortcut);
connect(m_suppressAction, &QAction::triggered, this, &MemcheckErrorView::suppressError);
addAction(m_suppressAction);
diff --git a/src/plugins/valgrind/memchecktool.cpp b/src/plugins/valgrind/memchecktool.cpp
index c5073bd40f..ec58ea86ed 100644
--- a/src/plugins/valgrind/memchecktool.cpp
+++ b/src/plugins/valgrind/memchecktool.cpp
@@ -1390,7 +1390,7 @@ bool HeobDialog::attach() const
QString HeobDialog::path() const
{
- return m_pathChooser->path();
+ return m_pathChooser->filePath().toString();
}
void HeobDialog::keyPressEvent(QKeyEvent *e)
@@ -1475,7 +1475,7 @@ void HeobDialog::saveOptions()
settings->setValue(heobLeakRecordingC, m_leakRecordingCombo->currentIndex());
settings->setValue(heobAttachC, m_attachCheck->isChecked());
settings->setValue(heobExtraArgsC, m_extraArgsEdit->text());
- settings->setValue(heobPathC, m_pathChooser->path());
+ settings->setValue(heobPathC, m_pathChooser->filePath().toString());
settings->endGroup();
}
diff --git a/src/plugins/valgrind/suppressiondialog.cpp b/src/plugins/valgrind/suppressiondialog.cpp
index e853791f8c..695aa42b02 100644
--- a/src/plugins/valgrind/suppressiondialog.cpp
+++ b/src/plugins/valgrind/suppressiondialog.cpp
@@ -194,7 +194,7 @@ void SuppressionDialog::maybeShow(MemcheckErrorView *view)
void SuppressionDialog::accept()
{
- const QString path = m_fileChooser->path();
+ const QString path = m_fileChooser->filePath().toString();
QTC_ASSERT(!path.isEmpty(), return);
QTC_ASSERT(!m_suppressionEdit->toPlainText().trimmed().isEmpty(), return);
diff --git a/src/plugins/vcsbase/basevcseditorfactory.cpp b/src/plugins/vcsbase/basevcseditorfactory.cpp
index 12f467afa0..8f25813885 100644
--- a/src/plugins/vcsbase/basevcseditorfactory.cpp
+++ b/src/plugins/vcsbase/basevcseditorfactory.cpp
@@ -54,7 +54,6 @@ VcsEditorFactory::VcsEditorFactory(const VcsBaseEditorParameters *parameters,
const EditorWidgetCreator editorWidgetCreator,
std::function<void(const QString &, const QString &)> describeFunc)
{
- setProperty("VcsEditorFactoryName", QByteArray(parameters->id));
setId(parameters->id);
setDisplayName(QCoreApplication::translate("VCS", parameters->displayName));
if (QLatin1String(parameters->mimeType) != QLatin1String(DiffEditor::Constants::DIFF_EDITOR_MIMETYPE))
diff --git a/src/plugins/vcsbase/basevcseditorfactory.h b/src/plugins/vcsbase/basevcseditorfactory.h
index b1b828716e..0afddcd5ce 100644
--- a/src/plugins/vcsbase/basevcseditorfactory.h
+++ b/src/plugins/vcsbase/basevcseditorfactory.h
@@ -37,8 +37,6 @@ class VcsBaseEditorParameters;
class VCSBASE_EXPORT VcsEditorFactory : public TextEditor::TextEditorFactory
{
- Q_OBJECT
-
public:
VcsEditorFactory(const VcsBaseEditorParameters *parameters,
const EditorWidgetCreator editorWidgetCreator,
diff --git a/src/plugins/vcsbase/commonsettingspage.cpp b/src/plugins/vcsbase/commonsettingspage.cpp
index 9c3920dfe8..f1f2a73f7e 100644
--- a/src/plugins/vcsbase/commonsettingspage.cpp
+++ b/src/plugins/vcsbase/commonsettingspage.cpp
@@ -74,12 +74,12 @@ CommonSettingsWidget::~CommonSettingsWidget()
CommonVcsSettings CommonSettingsWidget::settings() const
{
CommonVcsSettings rc;
- rc.nickNameMailMap = m_ui->nickNameMailMapChooser->path();
- rc.nickNameFieldListFile = m_ui->nickNameFieldsFileChooser->path();
- rc.submitMessageCheckScript = m_ui->submitMessageCheckScriptChooser->path();
+ rc.nickNameMailMap = m_ui->nickNameMailMapChooser->filePath().toString();
+ rc.nickNameFieldListFile = m_ui->nickNameFieldsFileChooser->filePath().toString();
+ rc.submitMessageCheckScript = m_ui->submitMessageCheckScriptChooser->filePath().toString();
rc.lineWrap= m_ui->lineWrapCheckBox->isChecked();
rc.lineWrapWidth = m_ui->lineWrapSpinBox->value();
- rc.sshPasswordPrompt = m_ui->sshPromptChooser->path();
+ rc.sshPasswordPrompt = m_ui->sshPromptChooser->filePath().toString();
return rc;
}
diff --git a/src/plugins/vcsbase/diffandloghighlighter.cpp b/src/plugins/vcsbase/diffandloghighlighter.cpp
index a2f0836f35..220b3b1ae9 100644
--- a/src/plugins/vcsbase/diffandloghighlighter.cpp
+++ b/src/plugins/vcsbase/diffandloghighlighter.cpp
@@ -115,6 +115,7 @@ public:
QTextCharFormat m_addedTrailingWhiteSpaceFormat;
Internal::FoldingState m_foldingState;
+ bool m_enabled = true;
};
TextEditor::TextStyle DiffAndLogHighlighterPrivate::analyzeLine(const QString &text) const
@@ -179,16 +180,18 @@ void DiffAndLogHighlighter::highlightBlock(const QString &text)
const int length = text.length();
const TextEditor::TextStyle format = d->analyzeLine(text);
- if (format == TextEditor::C_ADDED_LINE) {
+ if (d->m_enabled) {
+ if (format == TextEditor::C_ADDED_LINE) {
// Mark trailing whitespace.
const int trimmedLen = trimmedLength(text);
setFormatWithSpaces(text, 0, trimmedLen, formatForCategory(format));
if (trimmedLen != length)
setFormat(trimmedLen, length - trimmedLen, d->m_addedTrailingWhiteSpaceFormat);
- } else if (format != TextEditor::C_TEXT) {
- setFormatWithSpaces(text, 0, length, formatForCategory(format));
- } else {
- formatSpaces(text);
+ } else if (format != TextEditor::C_TEXT) {
+ setFormatWithSpaces(text, 0, length, formatForCategory(format));
+ } else {
+ formatSpaces(text);
+ }
}
// codefolding:
@@ -241,4 +244,9 @@ void DiffAndLogHighlighter::setFontSettings(const TextEditor::FontSettings &font
d->updateOtherFormats();
}
+void DiffAndLogHighlighter::setEnabled(bool e)
+{
+ d->m_enabled = e;
+}
+
} // namespace VcsBase
diff --git a/src/plugins/vcsbase/diffandloghighlighter.h b/src/plugins/vcsbase/diffandloghighlighter.h
index c43f4a510d..050374c343 100644
--- a/src/plugins/vcsbase/diffandloghighlighter.h
+++ b/src/plugins/vcsbase/diffandloghighlighter.h
@@ -53,6 +53,8 @@ public:
void setFontSettings(const TextEditor::FontSettings &fontSettings) override;
+ void setEnabled(bool e);
+
private:
friend class DiffAndLogHighlighterPrivate;
DiffAndLogHighlighterPrivate *const d;
diff --git a/src/plugins/vcsbase/vcsbaseeditor.cpp b/src/plugins/vcsbase/vcsbaseeditor.cpp
index 0f334b7f13..37fc44bacd 100644
--- a/src/plugins/vcsbase/vcsbaseeditor.cpp
+++ b/src/plugins/vcsbase/vcsbaseeditor.cpp
@@ -424,11 +424,10 @@ bool UrlTextCursorHandler::findContentsUnderCursor(const QTextCursor &cursor)
if (cursorForUrl.hasSelection()) {
const QString line = cursorForUrl.selectedText();
const int cursorCol = cursor.columnNumber();
- int urlMatchIndex = -1;
QRegularExpressionMatchIterator i = m_pattern.globalMatch(line);
while (i.hasNext()) {
const QRegularExpressionMatch match = i.next();
- urlMatchIndex = match.capturedStart();
+ const int urlMatchIndex = match.capturedStart();
const QString url = match.captured(0);
if (urlMatchIndex <= cursorCol && cursorCol <= urlMatchIndex + url.length()) {
m_urlData.startColumn = urlMatchIndex;
@@ -443,14 +442,15 @@ bool UrlTextCursorHandler::findContentsUnderCursor(const QTextCursor &cursor)
void UrlTextCursorHandler::highlightCurrentContents()
{
+ const QColor linkColor = creatorTheme()->color(Theme::TextColorLink);
QTextEdit::ExtraSelection sel;
sel.cursor = currentCursor();
sel.cursor.setPosition(currentCursor().position()
- (currentCursor().columnNumber() - m_urlData.startColumn));
sel.cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, m_urlData.url.length());
sel.format.setFontUnderline(true);
- sel.format.setForeground(Qt::blue);
- sel.format.setUnderlineColor(Qt::blue);
+ sel.format.setForeground(linkColor);
+ sel.format.setUnderlineColor(linkColor);
sel.format.setProperty(QTextFormat::UserProperty, m_urlData.url);
editorWidget()->setExtraSelections(VcsBaseEditorWidget::OtherSelection,
QList<QTextEdit::ExtraSelection>() << sel);
@@ -828,6 +828,12 @@ void VcsBaseEditorWidget::setFileLogAnnotateEnabled(bool e)
d->m_fileLogAnnotateEnabled = e;
}
+void VcsBaseEditorWidget::setHighlightingEnabled(bool e)
+{
+ auto dh = static_cast<DiffAndLogHighlighter *>(textDocument()->syntaxHighlighter());
+ dh->setEnabled(e);
+}
+
QString VcsBaseEditorWidget::workingDirectory() const
{
return d->m_workingDirectory;
diff --git a/src/plugins/vcsbase/vcsbaseeditor.h b/src/plugins/vcsbase/vcsbaseeditor.h
index 5340a3d4b2..72df0289ae 100644
--- a/src/plugins/vcsbase/vcsbaseeditor.h
+++ b/src/plugins/vcsbase/vcsbaseeditor.h
@@ -192,6 +192,8 @@ public:
bool isFileLogAnnotateEnabled() const;
void setFileLogAnnotateEnabled(bool e);
+ void setHighlightingEnabled(bool e);
+
QTextCodec *codec() const;
void setCodec(QTextCodec *);
diff --git a/src/plugins/vcsbase/vcsoutputformatter.cpp b/src/plugins/vcsbase/vcsoutputformatter.cpp
index 07d7c19375..9fd116dda0 100644
--- a/src/plugins/vcsbase/vcsoutputformatter.cpp
+++ b/src/plugins/vcsbase/vcsoutputformatter.cpp
@@ -34,7 +34,7 @@
namespace VcsBase {
-VcsOutputFormatter::VcsOutputFormatter() :
+VcsOutputLineParser::VcsOutputLineParser() :
m_regexp(
"(https?://\\S*)" // https://codereview.org/c/1234
"|(v[0-9]+\\.[0-9]+\\.[0-9]+[\\-A-Za-z0-9]*)" // v0.1.2-beta3
@@ -43,37 +43,35 @@ VcsOutputFormatter::VcsOutputFormatter() :
{
}
-void VcsOutputFormatter::appendMessage(const QString &text, Utils::OutputFormat format)
+Utils::OutputLineParser::Result VcsOutputLineParser::handleLine(const QString &text,
+ Utils::OutputFormat format)
{
+ Q_UNUSED(format);
QRegularExpressionMatchIterator it = m_regexp.globalMatch(text);
- int begin = 0;
+ if (!it.hasNext())
+ return Status::NotHandled;
+ LinkSpecs linkSpecs;
while (it.hasNext()) {
const QRegularExpressionMatch match = it.next();
- const QTextCharFormat normalFormat = charFormat(format);
- OutputFormatter::appendMessage(text.mid(begin, match.capturedStart() - begin), format);
- QTextCursor tc = plainTextEdit()->textCursor();
+ const int startPos = match.capturedStart();
QStringView url = match.capturedView();
- begin = match.capturedEnd();
- while (url.rbegin()->isPunct()) {
+ while (url.rbegin()->isPunct())
url.chop(1);
- --begin;
- }
- tc.movePosition(QTextCursor::End);
- tc.insertText(url.toString(), linkFormat(normalFormat, url.toString()));
- tc.movePosition(QTextCursor::End);
+ linkSpecs << LinkSpec(startPos, url.length(), url.toString());
}
- OutputFormatter::appendMessage(text.mid(begin), format);
+ return {Status::Done, linkSpecs};
}
-void VcsOutputFormatter::handleLink(const QString &href)
+bool VcsOutputLineParser::handleLink(const QString &href)
{
if (href.startsWith("http://") || href.startsWith("https://"))
QDesktopServices::openUrl(QUrl(href));
else if (!href.isEmpty())
emit referenceClicked(href);
+ return true;
}
-void VcsOutputFormatter::fillLinkContextMenu(
+void VcsOutputLineParser::fillLinkContextMenu(
QMenu *menu, const QString &workingDirectory, const QString &href)
{
if (href.isEmpty() || href.startsWith("http://") || href.startsWith("https://")) {
diff --git a/src/plugins/vcsbase/vcsoutputformatter.h b/src/plugins/vcsbase/vcsoutputformatter.h
index b9fd8c6c7e..0b9486e2a9 100644
--- a/src/plugins/vcsbase/vcsoutputformatter.h
+++ b/src/plugins/vcsbase/vcsoutputformatter.h
@@ -31,20 +31,20 @@ QT_FORWARD_DECLARE_CLASS(QMenu)
namespace VcsBase {
-class VcsOutputFormatter : public Utils::OutputFormatter
+class VcsOutputLineParser : public Utils::OutputLineParser
{
Q_OBJECT
public:
- VcsOutputFormatter();
- ~VcsOutputFormatter() override = default;
- void appendMessage(const QString &text, Utils::OutputFormat format) override;
- void handleLink(const QString &href) override;
+ VcsOutputLineParser();
void fillLinkContextMenu(QMenu *menu, const QString &workingDirectory, const QString &href);
signals:
void referenceClicked(const QString &reference);
private:
+ Result handleLine(const QString &text, Utils::OutputFormat format) override;
+ bool handleLink(const QString &href) override;
+
const QRegularExpression m_regexp;
};
diff --git a/src/plugins/vcsbase/vcsoutputwindow.cpp b/src/plugins/vcsbase/vcsoutputwindow.cpp
index 1cff2dc4b7..2aac7b1bda 100644
--- a/src/plugins/vcsbase/vcsoutputwindow.cpp
+++ b/src/plugins/vcsbase/vcsoutputwindow.cpp
@@ -31,7 +31,6 @@
#include <coreplugin/find/basetextfind.h>
#include <coreplugin/outputwindow.h>
#include <utils/fileutils.h>
-#include <utils/outputformatter.h>
#include <utils/qtcprocess.h>
#include <texteditor/behaviorsettings.h>
#include <texteditor/fontsettings.h>
@@ -47,7 +46,7 @@
#include <QPlainTextEdit>
#include <QPoint>
#include <QPointer>
-#include <QRegExp>
+#include <QRegularExpression>
#include <QTextBlock>
#include <QTextBlockUserData>
#include <QTextCharFormat>
@@ -97,12 +96,11 @@ class OutputWindowPlainTextEdit : public Core::OutputWindow
{
public:
explicit OutputWindowPlainTextEdit(QWidget *parent = nullptr);
- ~OutputWindowPlainTextEdit() override;
void appendLines(const QString &s, const QString &repository = QString());
void appendLinesWithStyle(const QString &s, VcsOutputWindow::MessageStyle style,
const QString &repository = QString());
- VcsOutputFormatter *formatter();
+ VcsOutputLineParser *parser();
protected:
void contextMenuEvent(QContextMenuEvent *event) override;
@@ -112,7 +110,7 @@ private:
QString identifierUnderCursor(const QPoint &pos, QString *repository = nullptr) const;
Utils::OutputFormat m_format;
- VcsOutputFormatter *m_formatter = nullptr;
+ VcsOutputLineParser *m_parser = nullptr;
};
OutputWindowPlainTextEdit::OutputWindowPlainTextEdit(QWidget *parent) :
@@ -121,19 +119,14 @@ OutputWindowPlainTextEdit::OutputWindowPlainTextEdit(QWidget *parent) :
setReadOnly(true);
setUndoRedoEnabled(false);
setFrameStyle(QFrame::NoFrame);
- m_formatter = new VcsOutputFormatter;
- m_formatter->setBoldFontEnabled(false);
- setFormatter(m_formatter);
+ outputFormatter()->setBoldFontEnabled(false);
+ m_parser = new VcsOutputLineParser;
+ setLineParsers({m_parser});
auto agg = new Aggregation::Aggregate;
agg->add(this);
agg->add(new Core::BaseTextFind(this));
}
-OutputWindowPlainTextEdit::~OutputWindowPlainTextEdit()
-{
- delete m_formatter;
-}
-
// Search back for beginning of word
static inline int firstWordCharacter(const QString &s, int startPos)
{
@@ -181,9 +174,9 @@ void OutputWindowPlainTextEdit::contextMenuEvent(QContextMenuEvent *event)
QString repository;
const QString token = identifierUnderCursor(event->pos(), &repository);
if (!repository.isEmpty()) {
- if (VcsOutputFormatter *f = formatter()) {
+ if (VcsOutputLineParser * const p = parser()) {
if (!href.isEmpty())
- f->fillLinkContextMenu(menu, repository, href);
+ p->fillLinkContextMenu(menu, repository, href);
}
}
QAction *openAction = nullptr;
@@ -228,10 +221,7 @@ void OutputWindowPlainTextEdit::appendLines(const QString &s, const QString &rep
const int previousLineCount = document()->lineCount();
- const QChar newLine('\n');
- const QChar lastChar = s.at(s.size() - 1);
- const bool appendNewline = (lastChar != '\r' && lastChar != newLine);
- m_formatter->appendMessage(appendNewline ? s + newLine : s, m_format);
+ outputFormatter()->appendMessage(s, m_format);
// Scroll down
moveCursor(QTextCursor::End);
@@ -258,24 +248,24 @@ void OutputWindowPlainTextEdit::appendLinesWithStyle(const QString &s,
}
}
-VcsOutputFormatter *OutputWindowPlainTextEdit::formatter()
+VcsOutputLineParser *OutputWindowPlainTextEdit::parser()
{
- return m_formatter;
+ return m_parser;
}
void OutputWindowPlainTextEdit::setFormat(VcsOutputWindow::MessageStyle style)
{
- m_formatter->setBoldFontEnabled(style == VcsOutputWindow::Command);
+ outputFormatter()->setBoldFontEnabled(style == VcsOutputWindow::Command);
switch (style) {
case VcsOutputWindow::Warning:
m_format = LogMessageFormat;
break;
case VcsOutputWindow::Error:
- m_format = ErrorMessageFormat;
+ m_format = StdErrFormat;
break;
case VcsOutputWindow::Message:
- m_format = NormalMessageFormat;
+ m_format = StdOutFormat;
break;
case VcsOutputWindow::Command:
m_format = NormalMessageFormat;
@@ -295,7 +285,7 @@ class VcsOutputWindowPrivate
public:
Internal::OutputWindowPlainTextEdit widget;
QString repository;
- QRegExp passwordRegExp;
+ const QRegularExpression passwordRegExp = QRegularExpression("://([^@:]+):([^@]+)@");
};
static VcsOutputWindow *m_instance = nullptr;
@@ -304,7 +294,6 @@ static VcsOutputWindowPrivate *d = nullptr;
VcsOutputWindow::VcsOutputWindow()
{
d = new VcsOutputWindowPrivate;
- d->passwordRegExp = QRegExp("://([^@:]+):([^@]+)@");
Q_ASSERT(d->passwordRegExp.isValid());
m_instance = this;
@@ -321,22 +310,13 @@ VcsOutputWindow::VcsOutputWindow()
connect(this, &IOutputPane::resetZoom, &d->widget, &Core::OutputWindow::resetZoom);
connect(TextEditor::TextEditorSettings::instance(), &TextEditor::TextEditorSettings::behaviorSettingsChanged,
this, updateBehaviorSettings);
- connect(d->widget.formatter(), &VcsOutputFormatter::referenceClicked,
+ connect(d->widget.parser(), &VcsOutputLineParser::referenceClicked,
VcsOutputWindow::instance(), &VcsOutputWindow::referenceClicked);
}
-static QString filterPasswordFromUrls(const QString &input)
+static QString filterPasswordFromUrls(QString input)
{
- int pos = 0;
- QString result = input;
- while ((pos = d->passwordRegExp.indexIn(result, pos)) >= 0) {
- QString tmp = result.left(pos + 3) + d->passwordRegExp.cap(1) + ":***@";
- int newStart = tmp.count();
- tmp += result.midRef(pos + d->passwordRegExp.matchedLength());
- result = tmp;
- pos = newStart;
- }
- return result;
+ return input.replace(d->passwordRegExp, "://\\1:***@");
}
VcsOutputWindow::~VcsOutputWindow()
diff --git a/src/plugins/webassembly/webassemblytoolchain.cpp b/src/plugins/webassembly/webassemblytoolchain.cpp
index 73c407c361..30c67eb0c5 100644
--- a/src/plugins/webassembly/webassemblytoolchain.cpp
+++ b/src/plugins/webassembly/webassemblytoolchain.cpp
@@ -142,14 +142,14 @@ WebAssemblyToolChain::WebAssemblyToolChain() :
setCompilerCommand(Utils::FilePath::fromString(command));
setSupportedAbis({toolChainAbi()});
setTargetAbi(toolChainAbi());
- const QString typeAndDisplayName = WebAssemblyToolChainFactory::tr("Emscripten Compiler");
+ const QString typeAndDisplayName = tr("Emscripten Compiler");
setDisplayName(typeAndDisplayName);
setTypeDisplayName(typeAndDisplayName);
}
WebAssemblyToolChainFactory::WebAssemblyToolChainFactory()
{
- setDisplayName(tr("WebAssembly"));
+ setDisplayName(WebAssemblyToolChain::tr("WebAssembly"));
setSupportedToolChainType(Constants::WEBASSEMBLY_TOOLCHAIN_TYPEID);
setSupportedLanguages({ProjectExplorer::Constants::C_LANGUAGE_ID,
ProjectExplorer::Constants::CXX_LANGUAGE_ID});
diff --git a/src/plugins/webassembly/webassemblytoolchain.h b/src/plugins/webassembly/webassemblytoolchain.h
index 4693bc7a10..9e01de8827 100644
--- a/src/plugins/webassembly/webassemblytoolchain.h
+++ b/src/plugins/webassembly/webassemblytoolchain.h
@@ -32,6 +32,8 @@ namespace Internal {
class WebAssemblyToolChain final : public ProjectExplorer::ClangToolChain
{
+ Q_DECLARE_TR_FUNCTIONS(WebAssembly::Internal::WebAssemblyToolChain)
+
public:
void addToEnvironment(Utils::Environment &env) const override;
@@ -43,8 +45,6 @@ private:
class WebAssemblyToolChainFactory : public ProjectExplorer::ToolChainFactory
{
- Q_OBJECT
-
public:
WebAssemblyToolChainFactory();
diff --git a/src/plugins/winrt/winrtdeployconfiguration.cpp b/src/plugins/winrt/winrtdeployconfiguration.cpp
index e6eb9fd0da..f42d48c924 100644
--- a/src/plugins/winrt/winrtdeployconfiguration.cpp
+++ b/src/plugins/winrt/winrtdeployconfiguration.cpp
@@ -66,17 +66,5 @@ WinRtEmulatorDeployConfigurationFactory::WinRtEmulatorDeployConfigurationFactory
addInitialStep(Constants::WINRT_BUILD_STEP_DEPLOY);
}
-WinRtDeployStepFactory::WinRtDeployStepFactory()
-{
- registerStep<WinRtPackageDeploymentStep>(Constants::WINRT_BUILD_STEP_DEPLOY);
- setDisplayName(QCoreApplication::translate("WinRt::Internal::WinRtDeployStepFactory", "Run windeployqt"));
- setFlags(BuildStepInfo::Unclonable);
- setSupportedStepList(ProjectExplorer::Constants::BUILDSTEPS_DEPLOY);
- setSupportedDeviceTypes({Constants::WINRT_DEVICE_TYPE_LOCAL,
- Constants::WINRT_DEVICE_TYPE_EMULATOR,
- Constants::WINRT_DEVICE_TYPE_PHONE});
- setRepeatable(false);
-}
-
} // namespace Internal
} // namespace WinRt
diff --git a/src/plugins/winrt/winrtdeployconfiguration.h b/src/plugins/winrt/winrtdeployconfiguration.h
index 906679ea6d..1ea45eb8e9 100644
--- a/src/plugins/winrt/winrtdeployconfiguration.h
+++ b/src/plugins/winrt/winrtdeployconfiguration.h
@@ -49,11 +49,5 @@ public:
WinRtEmulatorDeployConfigurationFactory();
};
-class WinRtDeployStepFactory : public ProjectExplorer::BuildStepFactory
-{
-public:
- WinRtDeployStepFactory();
-};
-
} // namespace Internal
} // namespace WinRt
diff --git a/src/plugins/winrt/winrtpackagedeploymentstep.cpp b/src/plugins/winrt/winrtpackagedeploymentstep.cpp
index 61cb14ff0a..5c2759672a 100644
--- a/src/plugins/winrt/winrtpackagedeploymentstep.cpp
+++ b/src/plugins/winrt/winrtpackagedeploymentstep.cpp
@@ -27,15 +27,17 @@
#include "winrtconstants.h"
-#include <projectexplorer/project.h>
-#include <projectexplorer/target.h>
+#include <projectexplorer/abstractprocessstep.h>
#include <projectexplorer/buildconfiguration.h>
#include <projectexplorer/buildtargetinfo.h>
#include <projectexplorer/deployablefile.h>
#include <projectexplorer/deploymentdata.h>
#include <projectexplorer/processparameters.h>
+#include <projectexplorer/projectconfigurationaspects.h>
#include <projectexplorer/projectexplorerconstants.h>
+#include <projectexplorer/project.h>
#include <projectexplorer/runconfiguration.h>
+#include <projectexplorer/target.h>
#include <qtsupport/qtkitinformation.h>
@@ -57,11 +59,62 @@ namespace Internal {
const char ARGUMENTS_KEY[] = "WinRt.BuildStep.Deploy.Arguments";
const char DEFAULTARGUMENTS_KEY[] = "WinRt.BuildStep.Deploy.DefaultArguments";
-WinRtArgumentsAspect::WinRtArgumentsAspect() = default;
+class WinRtArgumentsAspect final : public ProjectConfigurationAspect
+{
+ Q_DECLARE_TR_FUNCTIONS(WinRt::Internal::WinRtArgumentsAspect)
+
+public:
+ WinRtArgumentsAspect() = default;
+
+ void addToLayout(LayoutBuilder &builder) final;
+
+ void fromMap(const QVariantMap &map) final;
+ void toMap(QVariantMap &map) const final;
+
+ void setValue(const QString &value);
+ QString value() const { return m_value; }
+
+ void setDefaultValue(const QString &value) { m_defaultValue = value; }
+ QString defaultValue() const { return m_defaultValue; }
+
+ void restoreDefaultValue();
+
+private:
+ FancyLineEdit *m_lineEdit = nullptr;
+ QString m_value;
+ QString m_defaultValue;
+};
+
+class WinRtPackageDeploymentStep final : public AbstractProcessStep
+{
+ Q_DECLARE_TR_FUNCTIONS(WinRt::Internal::WinRtPackageDeploymentStep)
+
+public:
+ WinRtPackageDeploymentStep(BuildStepList *bsl, Core::Id id);
+
+ QString defaultWinDeployQtArguments() const;
+
+ void raiseError(const QString &errorMessage);
+ void raiseWarning(const QString &warningMessage);
+
+private:
+ bool init() override;
+ void doRun() override;
+ bool processSucceeded(int exitCode, QProcess::ExitStatus status) override;
+ void stdOutput(const QString &line) override;
-WinRtArgumentsAspect::~WinRtArgumentsAspect() = default;
+ bool parseIconsAndExecutableFromManifest(QString manifestFileName, QStringList *items, QString *executable);
-void WinRtArgumentsAspect::addToLayout(ProjectExplorer::LayoutBuilder &builder)
+ WinRtArgumentsAspect *m_argsAspect = nullptr;
+ QString m_targetFilePath;
+ QString m_targetDirPath;
+ QString m_executablePathInManifest;
+ QString m_mappingFileContent;
+ QString m_manifestFileName;
+ bool m_createMappingFile = false;
+};
+
+void WinRtArgumentsAspect::addToLayout(LayoutBuilder &builder)
{
QTC_CHECK(!m_lineEdit);
auto label = new QLabel(tr("Arguments:"));
@@ -109,21 +162,6 @@ void WinRtArgumentsAspect::setValue(const QString &value)
emit changed();
}
-QString WinRtArgumentsAspect::value() const
-{
- return m_value;
-}
-
-void WinRtArgumentsAspect::setDefaultValue(const QString &value)
-{
- m_defaultValue = value;
-}
-
-QString WinRtArgumentsAspect::defaultValue() const
-{
- return m_defaultValue;
-}
-
void WinRtArgumentsAspect::restoreDefaultValue()
{
if (m_defaultValue == m_value)
@@ -187,7 +225,7 @@ bool WinRtPackageDeploymentStep::init()
return false;
}
params->setCommandLine(windeployqt);
- params->setEnvironment(buildConfiguration()->environment());
+ params->setEnvironment(buildEnvironment());
return AbstractProcessStep::init();
}
@@ -309,14 +347,14 @@ QString WinRtPackageDeploymentStep::defaultWinDeployQtArguments() const
void WinRtPackageDeploymentStep::raiseError(const QString &errorMessage)
{
- emit addTask(DeploymentTask(Task::Error, errorMessage), 1);
emit addOutput(errorMessage, BuildStep::OutputFormat::ErrorMessage);
+ emit addTask(DeploymentTask(Task::Error, errorMessage), 1);
}
void WinRtPackageDeploymentStep::raiseWarning(const QString &warningMessage)
{
- emit addTask(DeploymentTask(Task::Warning, warningMessage), 1);
emit addOutput(warningMessage, BuildStep::OutputFormat::NormalMessage);
+ emit addTask(DeploymentTask(Task::Warning, warningMessage), 1);
}
bool WinRtPackageDeploymentStep::parseIconsAndExecutableFromManifest(QString manifestFileName, QStringList *icons, QString *executable)
@@ -346,5 +384,19 @@ bool WinRtPackageDeploymentStep::parseIconsAndExecutableFromManifest(QString man
return true;
}
+// WinRtDeployStepFactory
+
+WinRtDeployStepFactory::WinRtDeployStepFactory()
+{
+ registerStep<WinRtPackageDeploymentStep>(Constants::WINRT_BUILD_STEP_DEPLOY);
+ setDisplayName(QCoreApplication::translate("WinRt::Internal::WinRtDeployStepFactory", "Run windeployqt"));
+ setFlags(BuildStepInfo::Unclonable);
+ setSupportedStepList(ProjectExplorer::Constants::BUILDSTEPS_DEPLOY);
+ setSupportedDeviceTypes({Constants::WINRT_DEVICE_TYPE_LOCAL,
+ Constants::WINRT_DEVICE_TYPE_EMULATOR,
+ Constants::WINRT_DEVICE_TYPE_PHONE});
+ setRepeatable(false);
+}
+
} // namespace Internal
} // namespace WinRt
diff --git a/src/plugins/winrt/winrtpackagedeploymentstep.h b/src/plugins/winrt/winrtpackagedeploymentstep.h
index 2b1329db79..c20898ade9 100644
--- a/src/plugins/winrt/winrtpackagedeploymentstep.h
+++ b/src/plugins/winrt/winrtpackagedeploymentstep.h
@@ -25,66 +25,15 @@
#pragma once
-#include <projectexplorer/abstractprocessstep.h>
-#include <projectexplorer/projectconfigurationaspects.h>
+#include <projectexplorer/buildstep.h>
namespace WinRt {
namespace Internal {
-class WinRtArgumentsAspect : public ProjectExplorer::ProjectConfigurationAspect
+class WinRtDeployStepFactory final : public ProjectExplorer::BuildStepFactory
{
- Q_OBJECT
-
public:
- WinRtArgumentsAspect();
- ~WinRtArgumentsAspect() override;
-
- void addToLayout(ProjectExplorer::LayoutBuilder &builder) override;
-
- void fromMap(const QVariantMap &map) override;
- void toMap(QVariantMap &map) const override;
-
- void setValue(const QString &value);
- QString value() const;
-
- void setDefaultValue(const QString &value);
- QString defaultValue() const;
-
- void restoreDefaultValue();
-
-private:
- Utils::FancyLineEdit *m_lineEdit = nullptr;
- QString m_value;
- QString m_defaultValue;
-};
-
-class WinRtPackageDeploymentStep : public ProjectExplorer::AbstractProcessStep
-{
- Q_OBJECT
-
-public:
- WinRtPackageDeploymentStep(ProjectExplorer::BuildStepList *bsl, Core::Id id);
-
- QString defaultWinDeployQtArguments() const;
-
- void raiseError(const QString &errorMessage);
- void raiseWarning(const QString &warningMessage);
-
-private:
- bool init() override;
- void doRun() override;
- bool processSucceeded(int exitCode, QProcess::ExitStatus status) override;
- void stdOutput(const QString &line) override;
-
- bool parseIconsAndExecutableFromManifest(QString manifestFileName, QStringList *items, QString *executable);
-
- WinRtArgumentsAspect *m_argsAspect = nullptr;
- QString m_targetFilePath;
- QString m_targetDirPath;
- QString m_executablePathInManifest;
- QString m_mappingFileContent;
- QString m_manifestFileName;
- bool m_createMappingFile = false;
+ WinRtDeployStepFactory();
};
} // namespace Internal
diff --git a/src/plugins/winrt/winrtplugin.cpp b/src/plugins/winrt/winrtplugin.cpp
index c42cde7c17..314443e134 100644
--- a/src/plugins/winrt/winrtplugin.cpp
+++ b/src/plugins/winrt/winrtplugin.cpp
@@ -24,14 +24,16 @@
****************************************************************************/
#include "winrtplugin.h"
+
#include "winrtconstants.h"
-#include "winrtdevice.h"
+#include "winrtdebugsupport.h"
#include "winrtdeployconfiguration.h"
-#include "winrtqtversion.h"
+#include "winrtdevice.h"
+#include "winrtpackagedeploymentstep.h"
#include "winrtphoneqtversion.h"
+#include "winrtqtversion.h"
#include "winrtrunconfiguration.h"
#include "winrtruncontrol.h"
-#include "winrtdebugsupport.h"
#include <projectexplorer/devicesupport/devicemanager.h>
#include <projectexplorer/devicesupport/idevice.h>
diff --git a/src/share/3rdparty/CMakeLists.txt b/src/share/3rdparty/CMakeLists.txt
index ede2157426..2168701e06 100644
--- a/src/share/3rdparty/CMakeLists.txt
+++ b/src/share/3rdparty/CMakeLists.txt
@@ -3,11 +3,7 @@ install(
DESTINATION "${IDE_DATA_PATH}"
)
-add_custom_target(copy_fonts_to_builddir ALL VERBATIM)
-add_custom_command(TARGET copy_fonts_to_builddir POST_BUILD
- COMMAND "${CMAKE_COMMAND}" -E copy_directory fonts
- "${PROJECT_BINARY_DIR}/${IDE_DATA_PATH}/fonts"
- WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
- COMMENT Copy files into build directory
- VERBATIM
+qtc_copy_to_builddir(copy_fonts_to_builddir
+ DIRECTORIES fonts
+ DESTINATION "${IDE_DATA_PATH}/fonts"
)
diff --git a/src/shared/help/bookmarkmanager.cpp b/src/shared/help/bookmarkmanager.cpp
index c067334d4c..788bf6a714 100644
--- a/src/shared/help/bookmarkmanager.cpp
+++ b/src/shared/help/bookmarkmanager.cpp
@@ -49,6 +49,7 @@
#include <QApplication>
#include <QDialogButtonBox>
#include <QSortFilterProxyModel>
+#include <QRegularExpression>
#include <QHelpEngine>
@@ -76,8 +77,7 @@ BookmarkDialog::BookmarkDialog(BookmarkManager *manager, const QString &title,
proxyModel->setDynamicSortFilter(true);
proxyModel->setFilterRole(Qt::UserRole + 10);
proxyModel->setSourceModel(bookmarkManager->treeBookmarkModel());
- proxyModel->setFilterRegExp(QRegExp(QLatin1String("Folder"),
- Qt::CaseSensitive, QRegExp::FixedString));
+ proxyModel->setFilterRegularExpression(QRegularExpression(QLatin1String("Folder")));
ui.treeView->setModel(proxyModel);
ui.treeView->expandAll();
@@ -273,6 +273,7 @@ bool BookmarkDialog::eventFilter(QObject *object, QEvent *e)
}
} break;
+ case Qt::Key_Backspace:
case Qt::Key_Delete: {
bookmarkManager->removeBookmarkItem(ui.treeView,
proxyModel->mapToSource(index));
@@ -319,14 +320,14 @@ void BookmarkWidget::filterChanged()
{
bool searchBookmarks = searchField->text().isEmpty();
if (!searchBookmarks) {
- regExp.setPattern(searchField->text());
+ regExp.setPattern(QRegularExpression::escape(searchField->text()));
filterBookmarkModel->setSourceModel(bookmarkManager->listBookmarkModel());
} else {
regExp.setPattern(QString());
filterBookmarkModel->setSourceModel(bookmarkManager->treeBookmarkModel());
}
- filterBookmarkModel->setFilterRegExp(regExp);
+ filterBookmarkModel->setFilterRegularExpression(regExp);
const QModelIndex &index = treeView->indexAt(QPoint(1, 1));
if (index.isValid())
@@ -407,8 +408,7 @@ void BookmarkWidget::customContextMenuRequested(const QPoint &point)
void BookmarkWidget::setup()
{
- regExp.setPatternSyntax(QRegExp::FixedString);
- regExp.setCaseSensitivity(Qt::CaseInsensitive);
+ regExp.setPatternOptions(QRegularExpression::CaseInsensitiveOption);
QLayout *vlayout = new QVBoxLayout(this);
vlayout->setContentsMargins(0, 0, 0, 0);
@@ -489,7 +489,7 @@ bool BookmarkWidget::eventFilter(QObject *object, QEvent *e)
treeView->edit(index);
item->setEditable(false);
}
- } else if (ke->key() == Qt::Key_Delete) {
+ } else if (ke->key() == Qt::Key_Delete || ke->key() == Qt::Key_Backspace) {
bookmarkManager->removeBookmarkItem(treeView, src);
}
}
diff --git a/src/shared/help/bookmarkmanager.h b/src/shared/help/bookmarkmanager.h
index c11cc5e9bb..0339bbf315 100644
--- a/src/shared/help/bookmarkmanager.h
+++ b/src/shared/help/bookmarkmanager.h
@@ -122,7 +122,7 @@ private:
void expandItems();
bool eventFilter(QObject *object, QEvent *event);
- QRegExp regExp;
+ QRegularExpression regExp;
TreeView *treeView;
Utils::FancyLineEdit *searchField;
BookmarkManager *bookmarkManager;
diff --git a/src/shared/help/indexwindow.cpp b/src/shared/help/indexwindow.cpp
index f55ce3091b..af58ff8739 100644
--- a/src/shared/help/indexwindow.cpp
+++ b/src/shared/help/indexwindow.cpp
@@ -47,6 +47,11 @@
#include <QHelpEngine>
#include <QHelpIndexModel>
+#ifdef HELP_NEW_FILTER_ENGINE
+#include <QHelpLink>
+#endif
+
+
using namespace Help::Internal;
IndexWindow::IndexWindow()
@@ -195,8 +200,16 @@ void IndexWindow::disableSearchLineEdit()
void IndexWindow::open(const QModelIndex &index, bool newPage)
{
- QString keyword = m_filteredIndexModel->data(index, Qt::DisplayRole).toString();
- QMap<QString, QUrl> links = LocalHelpManager::helpEngine().indexModel()->linksForKeyword(keyword);
+ const QString keyword = m_filteredIndexModel->data(index, Qt::DisplayRole).toString();
+#ifndef HELP_NEW_FILTER_ENGINE
+ QMultiMap<QString, QUrl> links = LocalHelpManager::helpEngine().linksForKeyword(keyword);
+#else
+ QMultiMap<QString, QUrl> links;
+ const QList<QHelpLink> docs = LocalHelpManager::helpEngine().documentsForKeyword(keyword);
+ for (const auto doc : docs)
+ links.insert(doc.title, doc.url);
+
+#endif
emit linksActivated(links, keyword, newPage);
}
diff --git a/src/shared/help/indexwindow.h b/src/shared/help/indexwindow.h
index 1b44c1f576..8b1dec0872 100644
--- a/src/shared/help/indexwindow.h
+++ b/src/shared/help/indexwindow.h
@@ -88,7 +88,7 @@ public:
void setOpenInNewPageActionVisible(bool visible);
signals:
- void linksActivated(const QMap<QString, QUrl> &links,
+ void linksActivated(const QMultiMap<QString, QUrl> &links,
const QString &keyword, bool newPage);
private:
diff --git a/src/shared/help/topicchooser.cpp b/src/shared/help/topicchooser.cpp
index b7e5db7f3f..44852da95b 100644
--- a/src/shared/help/topicchooser.cpp
+++ b/src/shared/help/topicchooser.cpp
@@ -33,7 +33,7 @@
#include <QSortFilterProxyModel>
TopicChooser::TopicChooser(QWidget *parent, const QString &keyword,
- const QMap<QString, QUrl> &links)
+ const QMultiMap<QString, QUrl> &links)
: QDialog(parent)
, m_filterModel(new QSortFilterProxyModel(this))
{
@@ -49,7 +49,7 @@ TopicChooser::TopicChooser(QWidget *parent, const QString &keyword,
m_filterModel->setSourceModel(model);
m_filterModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
- QMap<QString, QUrl>::const_iterator it = links.constBegin();
+ QMultiMap<QString, QUrl>::const_iterator it = links.constBegin();
for (; it != links.constEnd(); ++it) {
m_links.append(it.value());
QStandardItem *item = new QStandardItem(it.key());
diff --git a/src/shared/help/topicchooser.h b/src/shared/help/topicchooser.h
index 88c6fa90b6..8f278428c7 100644
--- a/src/shared/help/topicchooser.h
+++ b/src/shared/help/topicchooser.h
@@ -42,7 +42,7 @@ class TopicChooser : public QDialog
public:
TopicChooser(QWidget *parent, const QString &keyword,
- const QMap<QString, QUrl> &links);
+ const QMultiMap<QString, QUrl> &links);
QUrl link() const;
diff --git a/src/shared/proparser/CMakeLists.txt b/src/shared/proparser/CMakeLists.txt
index d47141178a..3a8404af7a 100644
--- a/src/shared/proparser/CMakeLists.txt
+++ b/src/shared/proparser/CMakeLists.txt
@@ -23,7 +23,7 @@ add_qtc_library(ProParser SHARED
WINDOWS_EXPORT_ALL_SYMBOLS ON
)
-extend_qtc_target(ProParser
+extend_qtc_library(ProParser
CONDITION WIN32
DEFINES _UNICODE UNICODE
)
diff --git a/src/shared/proparser/qmakebuiltins.cpp b/src/shared/proparser/qmakebuiltins.cpp
index f7d2a43038..e55e212644 100644
--- a/src/shared/proparser/qmakebuiltins.cpp
+++ b/src/shared/proparser/qmakebuiltins.cpp
@@ -1742,7 +1742,6 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
evalError(fL1S("system(exec) requires one argument."));
return ReturnFalse;
}
-#ifdef PROEVALUATOR_FULL
if (m_cumulative) // Anything else would be insanity
return ReturnFalse;
#ifndef QT_BOOTSTRAPPED
@@ -1760,9 +1759,6 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
# endif
return returnBool(ec == 0);
#endif
-#else
- return ReturnTrue;
-#endif
}
case T_ISEMPTY: {
if (args.count() != 1) {
diff --git a/src/shared/qbs b/src/shared/qbs
-Subproject 846fc574f38395af24a9e60726372cb56075cff
+Subproject 62215625dde98f6a6457159b4e3ef975d701425
diff --git a/src/shared/shared.pro b/src/shared/shared.pro
index ea76484dec..b4c64a02fb 100644
--- a/src/shared/shared.pro
+++ b/src/shared/shared.pro
@@ -4,6 +4,7 @@ QBS_DIRS = \
qbscorelib \
qbsapps \
qbslibexec \
+ qbsmsbuildlib \
qbsplugins \
qbsstatic
@@ -12,8 +13,10 @@ qbsapps.subdir = qbs/src/app
qbsapps.depends = qbscorelib
qbslibexec.subdir = qbs/src/libexec
qbslibexec.depends = qbscorelib
+qbsmsbuildlib.subdir = qbs/src/lib/msbuild
+qbsmsbuildlib.depends = qbscorelib
qbsplugins.subdir = qbs/src/plugins
-qbsplugins.depends = qbscorelib
+qbsplugins.depends = qbscorelib qbsmsbuildlib
qbsstatic.file = qbs/static.pro
exists(qbs/qbs.pro) {
diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt
index 280e46de64..19e2769bf0 100644
--- a/src/tools/CMakeLists.txt
+++ b/src/tools/CMakeLists.txt
@@ -27,8 +27,8 @@ endfunction()
if (BUILD_CPLUSPLUS_TOOLS)
add_qtc_cpp_tool(cplusplus-ast2png "")
add_qtc_cpp_tool(cplusplus-frontend "")
- add_qtc_cpp_tool(cplusplus-mkvisitor PATH_AST_H=\"${CMAKE_CURRENT_SOURCE_DIR}/../../libs/3rdparty/cplusplus/AST.h\")
- add_qtc_cpp_tool(cplusplus-update-frontend PATH_CPP_FRONTEND=\"${CMAKE_CURRENT_SOURCE_DIR}/../../libs/3rdparty/cplusplus\" PATH_DUMPERS_FILE=\"${CMAKE_CURRENT_SOURCE_DIR}/../cplusplus-ast2png/dumpers.inc\")
+ add_qtc_cpp_tool(cplusplus-mkvisitor PATH_AST_H=\"${CMAKE_CURRENT_SOURCE_DIR}/../libs/3rdparty/cplusplus/AST.h\")
+ add_qtc_cpp_tool(cplusplus-update-frontend PATH_CPP_FRONTEND=\"${CMAKE_CURRENT_SOURCE_DIR}/../libs/3rdparty/cplusplus\" PATH_DUMPERS_FILE=\"${CMAKE_CURRENT_SOURCE_DIR}/cplusplus-ast2png/dumpers.inc\")
endif()
if (APPLE)
diff --git a/src/tools/buildoutputparser/outputprocessor.cpp b/src/tools/buildoutputparser/outputprocessor.cpp
index 083f4de89e..11bcdfe77c 100644
--- a/src/tools/buildoutputparser/outputprocessor.cpp
+++ b/src/tools/buildoutputparser/outputprocessor.cpp
@@ -30,10 +30,11 @@
#include <projectexplorer/gnumakeparser.h>
#include <projectexplorer/msvcparser.h>
#include <projectexplorer/osparser.h>
+#include <projectexplorer/taskhub.h>
#include <qmakeprojectmanager/qmakeparser.h>
#include <qtsupport/qtparser.h>
#include <utils/fileutils.h>
-
+#include <utils/outputformatter.h>
#include <QIODevice>
#include <QTextStream>
@@ -54,26 +55,29 @@ CompilerOutputProcessor::~CompilerOutputProcessor()
void CompilerOutputProcessor::start()
{
- ProjectExplorer::OsParser parser;
- parser.appendOutputParser(new QmakeProjectManager::QMakeParser);
- parser.appendOutputParser(new ProjectExplorer::GnuMakeParser);
- parser.appendOutputParser(new QtSupport::QtParser);
+ Utils::OutputFormatter parser;
+ parser.addLineParser(new ProjectExplorer::OsParser);
+ parser.addLineParser(new QmakeProjectManager::QMakeParser);
+ parser.addLineParser(new ProjectExplorer::GnuMakeParser);
+ parser.addLineParser(new QtSupport::QtParser);
switch (m_compilerType) {
case CompilerTypeGcc:
- parser.appendOutputParser(new ProjectExplorer::GccParser);
+ parser.addLineParsers(ProjectExplorer::GccParser::gccParserSuite());
break;
case CompilerTypeClang:
- parser.appendOutputParser(new ProjectExplorer::ClangParser);
+ parser.addLineParsers(ProjectExplorer::ClangParser::clangParserSuite());
break;
case CompilerTypeMsvc:
- parser.appendOutputParser(new ProjectExplorer::MsvcParser);
+ parser.addLineParser(new ProjectExplorer::MsvcParser);
break;
}
- connect(&parser, &ProjectExplorer::IOutputParser::addTask,
+ connect(ProjectExplorer::TaskHub::instance(), &ProjectExplorer::TaskHub::taskAdded,
this, &CompilerOutputProcessor::handleTask);
- while (!m_source.atEnd())
- parser.stdError(QString::fromLocal8Bit(m_source.readLine().trimmed()));
+ while (!m_source.atEnd()) {
+ parser.appendMessage(QString::fromLocal8Bit(m_source.readLine().trimmed()),
+ Utils::StdErrFormat);
+ }
QCoreApplication::quit();
}
@@ -86,5 +90,5 @@ void CompilerOutputProcessor::handleTask(const ProjectExplorer::Task &task)
*m_ostream << ':' << task.line;
*m_ostream << ": ";
}
- *m_ostream << task.description << '\n';
+ *m_ostream << task.description() << '\n';
}
diff --git a/src/tools/clangbackend/source/clangtooltipinfocollector.cpp b/src/tools/clangbackend/source/clangtooltipinfocollector.cpp
index 36281674f7..a4ab626a8a 100644
--- a/src/tools/clangbackend/source/clangtooltipinfocollector.cpp
+++ b/src/tools/clangbackend/source/clangtooltipinfocollector.cpp
@@ -149,6 +149,28 @@ Utf8String sizeInBytes(const Cursor &cursor)
return Utf8String();
}
+QVariant value(const Cursor &cursor)
+{
+ if (!clang_isDeclaration(cursor.cx().kind) && !clang_isExpression(cursor.cx().kind))
+ return {};
+ const CXEvalResult evalResult = clang_Cursor_Evaluate(cursor.cx());
+ QVariant v;
+ switch (clang_EvalResult_getKind(evalResult)) {
+ case CXEval_Int:
+ v = clang_EvalResult_isUnsignedInt(evalResult)
+ ? QVariant::fromValue(clang_EvalResult_getAsUnsigned(evalResult))
+ : QVariant::fromValue(clang_EvalResult_getAsLongLong(evalResult));
+ break;
+ case CXEval_Float:
+ v = QVariant::fromValue(clang_EvalResult_getAsDouble(evalResult));
+ break;
+ default:
+ break;
+ }
+ clang_EvalResult_dispose(evalResult);
+ return v;
+}
+
Cursor referencedCursor(const Cursor &cursor)
{
// Query the referenced cursor directly instead of first testing with cursor.isReference().
@@ -503,6 +525,7 @@ ToolTipInfo ToolTipInfoCollector::collect(uint line, uint column) const
ToolTipInfo info;
info.text = text(cursor, referenced);
info.briefComment = referenced.briefComment();
+ info.value = value(cursor);
{
ToolTipInfo qDocToolTipInfo = qDocInfo(referenced);
diff --git a/src/tools/clangbackend/source/codecompleter.cpp b/src/tools/clangbackend/source/codecompleter.cpp
index 91a9ad69ba..ae49b650dd 100644
--- a/src/tools/clangbackend/source/codecompleter.cpp
+++ b/src/tools/clangbackend/source/codecompleter.cpp
@@ -61,6 +61,8 @@ CodeCompletions toCodeCompletions(const UnsavedFile &unsavedFile,
return codeCompletions;
}
+// CLANG-UPGRADE-CHECK: Remove this workaround once we require LLVM/Clang 11 as that version makes
+// the workaround pointless.
void filterUnknownContextResults(ClangCodeCompleteResults &results,
const UnsavedFile &theUnsavedFile,
uint line,
diff --git a/src/tools/clangbackend/source/skippedsourceranges.cpp b/src/tools/clangbackend/source/skippedsourceranges.cpp
index 2ce2f15acb..c2005996d1 100644
--- a/src/tools/clangbackend/source/skippedsourceranges.cpp
+++ b/src/tools/clangbackend/source/skippedsourceranges.cpp
@@ -48,6 +48,7 @@ SkippedSourceRanges::~SkippedSourceRanges()
SkippedSourceRanges &SkippedSourceRanges::operator=(SkippedSourceRanges &&other)
{
if (this != &other) {
+ this->~SkippedSourceRanges();
cxTranslationUnit = other.cxTranslationUnit;
cxSkippedSourceRanges = other.cxSkippedSourceRanges;
other.cxTranslationUnit = nullptr;
diff --git a/src/tools/clangpchmanagerbackend/source/pchtaskqueue.h b/src/tools/clangpchmanagerbackend/source/pchtaskqueue.h
index 80d96b8e85..f7be8ae012 100644
--- a/src/tools/clangpchmanagerbackend/source/pchtaskqueue.h
+++ b/src/tools/clangpchmanagerbackend/source/pchtaskqueue.h
@@ -55,7 +55,9 @@ public:
, m_transactionsInterface(transactionsInterface)
, m_progressCounter(progressCounter)
, m_environment(environment)
- {}
+ {
+ Q_UNUSED(m_transactionsInterface)
+ }
void addSystemPchTasks(PchTasks &&pchTasks) override;
void addProjectPchTasks(PchTasks &&pchTasks) override;
diff --git a/src/tools/clangpchmanagerbackend/source/projectpartsmanager.h b/src/tools/clangpchmanagerbackend/source/projectpartsmanager.h
index 426aa0229f..8e7de47429 100644
--- a/src/tools/clangpchmanagerbackend/source/projectpartsmanager.h
+++ b/src/tools/clangpchmanagerbackend/source/projectpartsmanager.h
@@ -57,7 +57,9 @@ public:
, m_filePathCache(filePathCache)
, m_clangPathwatcher(clangPathwatcher)
, m_generatedFiles(generatedFiles)
- {}
+ {
+ Q_UNUSED(m_filePathCache)
+ }
UpToDataProjectParts update(ProjectPartContainers &&projectsParts) override;
void remove(const ProjectPartIds &projectPartIds) override;
diff --git a/src/tools/cplusplus-shared/utils.cpp b/src/tools/cplusplus-shared/utils.cpp
index a4111b6dd9..4568513156 100644
--- a/src/tools/cplusplus-shared/utils.cpp
+++ b/src/tools/cplusplus-shared/utils.cpp
@@ -82,14 +82,12 @@ SystemPreprocessor::SystemPreprocessor(bool verbose)
m_knownCompilers[Utils::HostOsInfo::withExecutableSuffix("cl")]
= QLatin1String("/DCPLUSPLUS_WITHOUT_QT /U__BLOCKS__ /TP /E /I . /FI");
- QMapIterator<QString, QString> i(m_knownCompilers);
- while (i.hasNext()) {
- i.next();
+ for (const QString &key:m_knownCompilers.keys()) {
const Utils::FilePath executablePath
- = Utils::Environment::systemEnvironment().searchInPath(i.key());
+ = Utils::Environment::systemEnvironment().searchInPath(key);
if (!executablePath.isEmpty()) {
- m_compiler = i.key();
- m_compilerArguments = i.value().split(QLatin1Char(' '), QString::SkipEmptyParts);
+ m_compiler = key;
+ m_compilerArguments = m_knownCompilers[key].split(QLatin1Char(' '), QString::SkipEmptyParts);
m_compilerArguments
<< QDir::toNativeSeparators(QLatin1String(PATH_PREPROCESSOR_CONFIG));
break;
diff --git a/src/tools/cplusplus-update-frontend/cplusplus-update-frontend.cpp b/src/tools/cplusplus-update-frontend/cplusplus-update-frontend.cpp
index 47a8ead13f..d32494c7bf 100644
--- a/src/tools/cplusplus-update-frontend/cplusplus-update-frontend.cpp
+++ b/src/tools/cplusplus-update-frontend/cplusplus-update-frontend.cpp
@@ -667,7 +667,7 @@ protected:
if (typeName.endsWith("ListAST")) {
*out << " for (" << typeName << " *iter = " << memberName << ", **ast_iter = &ast->" << memberName << ";" << endl
<< " iter; iter = iter->next, ast_iter = &(*ast_iter)->next)" << endl
- << " *ast_iter = new (pool) " << typeName << "((iter->value) ? iter->value->clone(pool) : 0);" << endl;
+ << " *ast_iter = new (pool) " << typeName << "((iter->value) ? iter->value->clone(pool) : nullptr);" << endl;
} else if (typeName.endsWith("AST")) {
*out << " if (" << memberName << ")" << endl
<< " ast->" << memberName << " = " << memberName << "->clone(pool);" << endl;
@@ -1585,7 +1585,7 @@ void generateASTPatternBuilder_h(const QDir &cplusplusDir)
const QString elementName = className.left(className.length() - 7) + QLatin1String("AST");
out
<< " " << className << " *" << methodName << "("
- << elementName << " *value, " << className << " *next = 0)" << endl
+ << elementName << " *value, " << className << " *next = nullptr)" << endl
<< " {" << endl
<< " " << className << " *list = new (&pool) " << className << ";" << endl
<< " list->next = next;" << endl
diff --git a/src/tools/qml2puppet/CMakeLists.txt b/src/tools/qml2puppet/CMakeLists.txt
index f3548e19ed..27583e5ed9 100644
--- a/src/tools/qml2puppet/CMakeLists.txt
+++ b/src/tools/qml2puppet/CMakeLists.txt
@@ -97,18 +97,7 @@ extend_qtc_executable(qml2puppet
FEATURE_INFO "Qt Quick 3D"
DEPENDS Qt5::Quick3D Qt5::Quick3DPrivate
DEFINES QUICK3D_MODULE
-)
-
-extend_qtc_executable(qml2puppet
- SOURCES_PREFIX "${SRCDIR}/interfaces"
- SOURCES
- commondefines.h
- nodeinstanceclientinterface.h
- nodeinstanceglobal.h
- nodeinstanceserverinterface.cpp nodeinstanceserverinterface.h
-)
-extend_qtc_executable(qml2puppet
SOURCES_PREFIX "${SRCDIR}/qml2puppet/editor3d"
SOURCES
generalhelper.cpp generalhelper.h
@@ -122,6 +111,15 @@ extend_qtc_executable(qml2puppet
)
extend_qtc_executable(qml2puppet
+ SOURCES_PREFIX "${SRCDIR}/interfaces"
+ SOURCES
+ commondefines.h
+ nodeinstanceclientinterface.h
+ nodeinstanceglobal.h
+ nodeinstanceserverinterface.cpp nodeinstanceserverinterface.h
+)
+
+extend_qtc_executable(qml2puppet
SOURCES_PREFIX "${SRCDIR}/qml2puppet/iconrenderer"
SOURCES
iconrenderer.cpp iconrenderer.h
diff --git a/src/tools/qml2puppet/qml2puppet.qbs b/src/tools/qml2puppet/qml2puppet.qbs
index 8a26457901..ccc85fcc7c 100644
--- a/src/tools/qml2puppet/qml2puppet.qbs
+++ b/src/tools/qml2puppet/qml2puppet.qbs
@@ -1,4 +1,4 @@
-import qbs
+import qbs.Utilities
import QtcFunctions
QtcTool {
@@ -15,7 +15,16 @@ QtcTool {
"widgets"
]
}
- cpp.defines: base.filter(function(d) { return d != "QT_CREATOR"; })
+ Depends { name: "Qt.quick3d-private"; required: false }
+ property bool useQuick3d: Utilities.versionCompare(Qt.core.version, "5.15") >= 0
+ && Qt["quick3d-private"].present
+
+ cpp.defines: {
+ var defines = base.filter(function(d) { return d != "QT_CREATOR"; });
+ if (useQuick3d)
+ defines.push("QUICK3D_MODULE");
+ return defines;
+ }
Properties {
condition: qbs.targetOS.contains("unix") && !qbs.targetOS.contains("bsd")
cpp.dynamicLibraries: base.concat("rt")
@@ -204,25 +213,33 @@ QtcTool {
"instances/servernodeinstance.cpp",
"instances/servernodeinstance.h",
"editor3d/generalhelper.cpp",
- "editor3d/generalhelper.h",
"editor3d/mousearea3d.cpp",
- "editor3d/mousearea3d.h",
"editor3d/camerageometry.cpp",
- "editor3d/camerageometry.h",
"editor3d/lightgeometry.cpp",
- "editor3d/lightgeometry.h",
"editor3d/gridgeometry.cpp",
- "editor3d/gridgeometry.h",
"editor3d/selectionboxgeometry.cpp",
- "editor3d/selectionboxgeometry.h",
"editor3d/linegeometry.cpp",
- "editor3d/linegeometry.h",
"editor3d/icongizmoimageprovider.cpp",
"editor3d/icongizmoimageprovider.h",
"iconrenderer/iconrenderer.cpp",
"iconrenderer/iconrenderer.h",
"qml2puppetmain.cpp",
]
+
+ Group {
+ name: "3d-only puppet2 headers"
+ files: [
+ "editor3d/camerageometry.h",
+ "editor3d/generalhelper.h",
+ "editor3d/gridgeometry.h",
+ "editor3d/lightgeometry.h",
+ "editor3d/linegeometry.h",
+ "editor3d/selectionboxgeometry.h",
+ "editor3d/mousearea3d.h",
+ ]
+ fileTags: product.useQuick3d ? [] : ["unmocable"]
+ overrideTags: false
+ }
}
Group {
diff --git a/src/tools/sdktool/CMakeLists.txt b/src/tools/sdktool/CMakeLists.txt
index e25ae3f31a..e477788f6a 100644
--- a/src/tools/sdktool/CMakeLists.txt
+++ b/src/tools/sdktool/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.9)
+cmake_minimum_required(VERSION 3.10)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake")
diff --git a/tests/auto/cplusplus/codeformatter/tst_codeformatter.cpp b/tests/auto/cplusplus/codeformatter/tst_codeformatter.cpp
index f54816f9fe..225ef18470 100644
--- a/tests/auto/cplusplus/codeformatter/tst_codeformatter.cpp
+++ b/tests/auto/cplusplus/codeformatter/tst_codeformatter.cpp
@@ -125,6 +125,8 @@ private Q_SLOTS:
void braceReturn();
void staticVarDeclWithTypeDecl();
void strings();
+ void initializerWithinFunctionArg();
+ void shiftWithinInitializer();
};
struct Line {
@@ -2170,6 +2172,29 @@ void tst_CodeFormatter::strings()
checkIndent(data);
}
+void tst_CodeFormatter::initializerWithinFunctionArg()
+{
+ QList<Line> data;
+ data << Line("void f() {")
+ << Line(" g(foo,")
+ << Line(" { 1, 2});", 4, 2)
+ << Line("}")
+ ;
+
+ checkIndent(data);
+}
+
+void tst_CodeFormatter::shiftWithinInitializer()
+{
+ QList<Line> data;
+ data << Line("void f() {")
+ << Line(" list << A{1 << 1};")
+ << Line(" list;") // OK, same indentation/padding as above.
+ << Line("}")
+ ;
+ checkIndent(data);
+}
+
QTEST_MAIN(tst_CodeFormatter)
#include "tst_codeformatter.moc"
diff --git a/tests/auto/debugger/tst_dumpers.cpp b/tests/auto/debugger/tst_dumpers.cpp
index 9bbd10b266..68b5f1f499 100644
--- a/tests/auto/debugger/tst_dumpers.cpp
+++ b/tests/auto/debugger/tst_dumpers.cpp
@@ -28,11 +28,11 @@
#include "watchdata.h"
#include "watchutils.h"
+#include <utils/fileutils.h>
#ifdef Q_OS_WIN
#include <utils/environment.h>
#ifdef Q_CC_MSVC
#include <utils/qtcprocess.h>
-#include <utils/fileutils.h>
#include <utils/synchronousprocess.h>
#endif // Q_CC_MSVC
#endif // Q_OS_WIN
@@ -220,6 +220,12 @@ struct BoostVersion : VersionBase
{}
};
+struct ConfigTest
+{
+ QString executable;
+ QStringList arguments;
+};
+
static QString noValue = "\001";
enum DebuggerEngine
@@ -962,7 +968,7 @@ public:
mutable BoostVersion neededBoostVersion; // DEC. 105400 for 1.54.0
mutable DwarfVersion neededDwarfVersion; // DEC. 105400 for 1.54.0
- mutable QString configTest;
+ mutable ConfigTest configTest;
mutable QString allProfile; // Overrides anything below if not empty.
mutable QString allCode; // Overrides anything below if not empty.
@@ -1288,15 +1294,18 @@ void tst_Dumpers::dumper()
+ QByteArray::number(data.neededMsvcVersion.max));
}
- if (!data.configTest.isEmpty()) {
+ if (!data.configTest.executable.isEmpty()) {
QProcess configTest;
- configTest.start(data.configTest);
+ configTest.start(data.configTest.executable, data.configTest.arguments);
QVERIFY(configTest.waitForFinished());
output = configTest.readAllStandardOutput();
error = configTest.readAllStandardError();
if (configTest.exitCode()) {
- MSKIP_SINGLE("Configure test failed: '"
- + data.configTest.toUtf8() + "' " + output + ' ' + error);
+ QString msg = "Configure test failed: '"
+ + data.configTest.executable + ' '
+ + data.configTest.arguments.join(' ')
+ + "' " + output + ' ' + error;
+ MSKIP_SINGLE(msg.toUtf8());
}
}
@@ -1487,7 +1496,7 @@ void tst_Dumpers::dumper()
}
};
collectExpandedINames(data.checks);
- for (const auto checkset : qAsConst(data.checksets))
+ for (const auto &checkset : qAsConst(data.checksets))
collectExpandedINames(checkset.checks);
QString expanded;
@@ -1523,7 +1532,6 @@ void tst_Dumpers::dumper()
#else
"file doit\n"
#endif
- "set print object on\n"
"set auto-load python-scripts off\n";
cmds += "python sys.path.insert(1, '" + dumperDir + "')\n"
@@ -5857,7 +5865,7 @@ void tst_Dumpers::dumper_data()
// + Check("c.r", "1", "int");
// // Manual: Toogle "Sort Member Alphabetically" in context menu
-// // Manual: of "Locals and Expressions" view");
+// // Manual: of "Locals" and "Expressions" views");
// // Manual: Check that order of displayed members changes");
QTest::newRow("Typedef")
@@ -5972,7 +5980,7 @@ void tst_Dumpers::dumper_data()
// QTest::newRow("TypeFormats")
// << Data(
// "// These tests should result in properly displayed umlauts in the\n"
-// "// Locals and Expressions view. It is only support on gdb with Python");\n"
+// "// Locals and Expressions views. It is only support on gdb with Python");\n"
// "const char *s = "aöa";\n"
// "const wchar_t *w = L"aöa";\n"
// "QString u;\n"
@@ -7652,7 +7660,7 @@ void tst_Dumpers::dumper_data()
#ifdef Q_OS_LINUX
Data f90data;
- f90data.configTest = "which f95";
+ f90data.configTest = {"which", {"f95"}};
f90data.allProfile =
"CONFIG -= qt\n"
"SOURCES += main.f90\n"
@@ -7690,7 +7698,7 @@ void tst_Dumpers::dumper_data()
// touch qt_tst_dumpers_Nim_.../dummy.nimproject
// qtcreator qt_tst_dumpers_Nim_*/dummy.nimproject
Data nimData;
- nimData.configTest = "which nim";
+ nimData.configTest = {"which", {"nim"}};
nimData.allProfile =
"CONFIG -= qt\n"
"SOURCES += main.nim\n"
diff --git a/tests/auto/qml/codemodel/importscheck/004_cppOnly copy/QtQuick.2/plugins.qmltypes b/tests/auto/qml/codemodel/importscheck/004_cppOnly copy/QtQuick.2/plugins.qmltypes
index cadef10370..8a8bc257d7 100644
--- a/tests/auto/qml/codemodel/importscheck/004_cppOnly copy/QtQuick.2/plugins.qmltypes
+++ b/tests/auto/qml/codemodel/importscheck/004_cppOnly copy/QtQuick.2/plugins.qmltypes
@@ -4160,14 +4160,14 @@ Module {
exportMetaObjectRevisions: [0]
}
Component {
- name: "QRegExpValidator"
+ name: "QRegularExpressionValidator"
prototype: "QValidator"
- exports: ["QtQuick/RegExpValidator 2.0"]
+ exports: ["QtQuick/RegularExpressionValidator 2.14"]
exportMetaObjectRevisions: [0]
- Property { name: "regExp"; type: "QRegExp" }
+ Property { name: "regularExpression"; type: "QRegularExpression" }
Signal {
- name: "regExpChanged"
- Parameter { name: "regExp"; type: "QRegExp" }
+ name: "regularExpressionChanged"
+ Parameter { name: "regularExpression"; type: "QRegularExpression" }
}
}
Component {
diff --git a/tests/auto/qml/codemodel/importscheck/base/QtQuick.2/plugins.qmltypes b/tests/auto/qml/codemodel/importscheck/base/QtQuick.2/plugins.qmltypes
index cadef10370..8a8bc257d7 100644
--- a/tests/auto/qml/codemodel/importscheck/base/QtQuick.2/plugins.qmltypes
+++ b/tests/auto/qml/codemodel/importscheck/base/QtQuick.2/plugins.qmltypes
@@ -4160,14 +4160,14 @@ Module {
exportMetaObjectRevisions: [0]
}
Component {
- name: "QRegExpValidator"
+ name: "QRegularExpressionValidator"
prototype: "QValidator"
- exports: ["QtQuick/RegExpValidator 2.0"]
+ exports: ["QtQuick/RegularExpressionValidator 2.14"]
exportMetaObjectRevisions: [0]
- Property { name: "regExp"; type: "QRegExp" }
+ Property { name: "regularExpression"; type: "QRegularExpression" }
Signal {
- name: "regExpChanged"
- Parameter { name: "regExp"; type: "QRegExp" }
+ name: "regularExpressionChanged"
+ Parameter { name: "regularExpression"; type: "QRegularExpression" }
}
}
Component {
diff --git a/tests/auto/qml/codemodel/importscheck/importTypes/importQtQuick.qml b/tests/auto/qml/codemodel/importscheck/importTypes/importQtQuick.qml
new file mode 100644
index 0000000000..68c21087cb
--- /dev/null
+++ b/tests/auto/qml/codemodel/importscheck/importTypes/importQtQuick.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.15
+
+Item {
+
+}
diff --git a/tests/auto/qml/codemodel/importscheck/importTypes/imports-QtQuick-qmldir-import/QtQml/plugins.qmltypes b/tests/auto/qml/codemodel/importscheck/importTypes/imports-QtQuick-qmldir-import/QtQml/plugins.qmltypes
new file mode 100644
index 0000000000..39cb4f3ccc
--- /dev/null
+++ b/tests/auto/qml/codemodel/importscheck/importTypes/imports-QtQuick-qmldir-import/QtQml/plugins.qmltypes
@@ -0,0 +1,26 @@
+import QtQuick.tooling 1.1
+
+// This file describes the plugin-supplied types contained in the library.
+// It is used for QML tooling purposes only.
+//
+// This file was auto-generated by:
+// 'qmlplugindump -nonrelocatable -builtins'
+
+Module {
+ Component {
+ name: "QObject"
+ exports: ["QtQml/QtObject 2.0"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "objectName"; type: "string" }
+ Signal {
+ name: "objectNameChanged"
+ Parameter { name: "objectName"; type: "string" }
+ }
+ Method { name: "toString" }
+ Method { name: "destroy" }
+ Method {
+ name: "destroy"
+ Parameter { name: "delay"; type: "int" }
+ }
+ }
+}
diff --git a/tests/auto/qml/codemodel/importscheck/importTypes/imports-QtQuick-qmldir-import/QtQml/qmldir b/tests/auto/qml/codemodel/importscheck/importTypes/imports-QtQuick-qmldir-import/QtQml/qmldir
new file mode 100644
index 0000000000..8175ebb1a1
--- /dev/null
+++ b/tests/auto/qml/codemodel/importscheck/importTypes/imports-QtQuick-qmldir-import/QtQml/qmldir
@@ -0,0 +1,2 @@
+module QtQml
+typeinfo plugins.qmltypes
diff --git a/tests/auto/qml/codemodel/importscheck/importTypes/imports-QtQuick-qmldir-import/QtQuick.2/plugins.qmltypes b/tests/auto/qml/codemodel/importscheck/importTypes/imports-QtQuick-qmldir-import/QtQuick.2/plugins.qmltypes
new file mode 100644
index 0000000000..b6a7fc5697
--- /dev/null
+++ b/tests/auto/qml/codemodel/importscheck/importTypes/imports-QtQuick-qmldir-import/QtQuick.2/plugins.qmltypes
@@ -0,0 +1,175 @@
+import QtQuick.tooling 1.1
+
+// This file describes the plugin-supplied types contained in the library.
+// It is used for QML tooling purposes only.
+//
+// This file was auto-generated by:
+// 'qmlplugindump -nonrelocatable -builtins'
+
+Module {
+ Component {
+ name: "IsQtQuickQmldirImport"
+ exports: ["QtQuick/IsQtQuickQmldirImport 2.0"]
+ exportMetaObjectRevisions: [0]
+ }
+ Component {
+ name: "QQuickBehavior"
+ defaultProperty: "animation"
+ prototype: "QObject"
+ exports: [
+ "QtQuick/Behavior 2.0",
+ "QtQuick/Behavior 2.13",
+ "QtQuick/Behavior 2.15",
+ "QtQuick/Behavior 2.16"
+ ]
+ exportMetaObjectRevisions: [0, 13, 15, 16]
+ Property { name: "animation"; type: "QQuickAbstractAnimation"; isPointer: true }
+ Property { name: "enabled"; type: "bool" }
+ Property { name: "targetValue"; revision: 13; type: "QVariant"; isReadonly: true }
+ Property { name: "targetProperty"; revision: 15; type: "QQmlProperty"; isReadonly: true }
+ Method { name: "componentFinalized" }
+ }
+ Component {
+ name: "QQuickItem"
+ defaultProperty: "data"
+ prototype: "QObject"
+ exports: ["QtQuick/Item 2.0", "QtQuick/Item 2.1"]
+ exportMetaObjectRevisions: [0, 1]
+ Enum {
+ name: "TransformOrigin"
+ values: {
+ "TopLeft": 0,
+ "Top": 1,
+ "TopRight": 2,
+ "Left": 3,
+ "Center": 4,
+ "Right": 5,
+ "BottomLeft": 6,
+ "Bottom": 7,
+ "BottomRight": 8
+ }
+ }
+ Property { name: "parent"; type: "QQuickItem"; isPointer: true }
+ Property { name: "data"; type: "QObject"; isList: true; isReadonly: true }
+ Property { name: "resources"; type: "QObject"; isList: true; isReadonly: true }
+ Property { name: "children"; type: "QQuickItem"; isList: true; isReadonly: true }
+ Property { name: "x"; type: "double" }
+ Property { name: "y"; type: "double" }
+ Property { name: "z"; type: "double" }
+ Property { name: "width"; type: "double" }
+ Property { name: "height"; type: "double" }
+ Property { name: "opacity"; type: "double" }
+ Property { name: "enabled"; type: "bool" }
+ Property { name: "visible"; type: "bool" }
+ Property { name: "visibleChildren"; type: "QQuickItem"; isList: true; isReadonly: true }
+ Property { name: "states"; type: "QQuickState"; isList: true; isReadonly: true }
+ Property { name: "transitions"; type: "QQuickTransition"; isList: true; isReadonly: true }
+ Property { name: "state"; type: "string" }
+ Property { name: "childrenRect"; type: "QRectF"; isReadonly: true }
+ Property { name: "anchors"; type: "QQuickAnchors"; isReadonly: true; isPointer: true }
+ Property { name: "left"; type: "QQuickAnchorLine"; isReadonly: true }
+ Property { name: "right"; type: "QQuickAnchorLine"; isReadonly: true }
+ Property { name: "horizontalCenter"; type: "QQuickAnchorLine"; isReadonly: true }
+ Property { name: "top"; type: "QQuickAnchorLine"; isReadonly: true }
+ Property { name: "bottom"; type: "QQuickAnchorLine"; isReadonly: true }
+ Property { name: "verticalCenter"; type: "QQuickAnchorLine"; isReadonly: true }
+ Property { name: "baseline"; type: "QQuickAnchorLine"; isReadonly: true }
+ Property { name: "baselineOffset"; type: "double" }
+ Property { name: "clip"; type: "bool" }
+ Property { name: "focus"; type: "bool" }
+ Property { name: "activeFocus"; type: "bool"; isReadonly: true }
+ Property { name: "activeFocusOnTab"; revision: 1; type: "bool" }
+ Property { name: "rotation"; type: "double" }
+ Property { name: "scale"; type: "double" }
+ Property { name: "transformOrigin"; type: "TransformOrigin" }
+ Property { name: "transformOriginPoint"; type: "QPointF"; isReadonly: true }
+ Property { name: "transform"; type: "QQuickTransform"; isList: true; isReadonly: true }
+ Property { name: "smooth"; type: "bool" }
+ Property { name: "antialiasing"; type: "bool" }
+ Property { name: "implicitWidth"; type: "double" }
+ Property { name: "implicitHeight"; type: "double" }
+ Property { name: "layer"; type: "QQuickItemLayer"; isReadonly: true; isPointer: true }
+ Signal {
+ name: "childrenRectChanged"
+ Parameter { type: "QRectF" }
+ }
+ Signal {
+ name: "baselineOffsetChanged"
+ Parameter { type: "double" }
+ }
+ Signal {
+ name: "stateChanged"
+ Parameter { type: "string" }
+ }
+ Signal {
+ name: "focusChanged"
+ Parameter { type: "bool" }
+ }
+ Signal {
+ name: "activeFocusChanged"
+ Parameter { type: "bool" }
+ }
+ Signal {
+ name: "activeFocusOnTabChanged"
+ revision: 1
+ Parameter { type: "bool" }
+ }
+ Signal {
+ name: "parentChanged"
+ Parameter { type: "QQuickItem"; isPointer: true }
+ }
+ Signal {
+ name: "transformOriginChanged"
+ Parameter { type: "TransformOrigin" }
+ }
+ Signal {
+ name: "smoothChanged"
+ Parameter { type: "bool" }
+ }
+ Signal {
+ name: "antialiasingChanged"
+ Parameter { type: "bool" }
+ }
+ Signal {
+ name: "clipChanged"
+ Parameter { type: "bool" }
+ }
+ Signal {
+ name: "windowChanged"
+ revision: 1
+ Parameter { name: "window"; type: "QQuickWindow"; isPointer: true }
+ }
+ Method { name: "update" }
+ Method {
+ name: "contains"
+ type: "bool"
+ Parameter { name: "point"; type: "QPointF" }
+ }
+ Method {
+ name: "mapFromItem"
+ Parameter { type: "QQmlV4Function"; isPointer: true }
+ }
+ Method {
+ name: "mapToItem"
+ Parameter { type: "QQmlV4Function"; isPointer: true }
+ }
+ Method { name: "forceActiveFocus" }
+ Method {
+ name: "forceActiveFocus"
+ Parameter { name: "reason"; type: "Qt::FocusReason" }
+ }
+ Method {
+ name: "nextItemInFocusChain"
+ revision: 1
+ type: "QQuickItem*"
+ Parameter { name: "forward"; type: "bool" }
+ }
+ Method { name: "nextItemInFocusChain"; revision: 1; type: "QQuickItem*" }
+ Method {
+ name: "childAt"
+ type: "QQuickItem*"
+ Parameter { name: "x"; type: "double" }
+ Parameter { name: "y"; type: "double" }
+ }
+ }
+}
diff --git a/tests/auto/qml/codemodel/importscheck/importTypes/imports-QtQuick-qmldir-import/QtQuick.2/qmldir b/tests/auto/qml/codemodel/importscheck/importTypes/imports-QtQuick-qmldir-import/QtQuick.2/qmldir
new file mode 100644
index 0000000000..4bdfa4feb3
--- /dev/null
+++ b/tests/auto/qml/codemodel/importscheck/importTypes/imports-QtQuick-qmldir-import/QtQuick.2/qmldir
@@ -0,0 +1,5 @@
+module QtQuick
+plugin qtquick2plugin
+classname QtQuick2Plugin
+typeinfo plugins.qmltypes
+import QtQml
diff --git a/tests/auto/qml/codemodel/importscheck/importTypes/imports-QtQuick-simple/QtQuick.2/plugins.qmltypes b/tests/auto/qml/codemodel/importscheck/importTypes/imports-QtQuick-simple/QtQuick.2/plugins.qmltypes
new file mode 100644
index 0000000000..8771dbec91
--- /dev/null
+++ b/tests/auto/qml/codemodel/importscheck/importTypes/imports-QtQuick-simple/QtQuick.2/plugins.qmltypes
@@ -0,0 +1,174 @@
+import QtQuick.tooling 1.1
+
+// This file describes the plugin-supplied types contained in the library.
+// It is used for QML tooling purposes only.
+//
+// This file was auto-generated by:
+// 'qmlplugindump -nonrelocatable -builtins'
+
+Module {
+ Component {
+ name: "IsQtQuickSimple"
+ exports: ["QtQuick/IsQtQuickSimple 2.0"]
+ exportMetaObjectRevisions: [0]
+ }
+ Component {
+ name: "QObject"
+ exports: ["QtQml/QtObject 2.0", "QtQuick/QtObject 2.0"]
+ exportMetaObjectRevisions: [0, 0]
+ Property { name: "objectName"; type: "string" }
+ Signal {
+ name: "objectNameChanged"
+ Parameter { name: "objectName"; type: "string" }
+ }
+ Method { name: "toString" }
+ Method { name: "destroy" }
+ Method {
+ name: "destroy"
+ Parameter { name: "delay"; type: "int" }
+ }
+ }
+ Component {
+ name: "QQuickItem"
+ defaultProperty: "data"
+ prototype: "QObject"
+ exports: ["QtQuick/Item 2.0", "QtQuick/Item 2.1"]
+ exportMetaObjectRevisions: [0, 1]
+ Enum {
+ name: "TransformOrigin"
+ values: {
+ "TopLeft": 0,
+ "Top": 1,
+ "TopRight": 2,
+ "Left": 3,
+ "Center": 4,
+ "Right": 5,
+ "BottomLeft": 6,
+ "Bottom": 7,
+ "BottomRight": 8
+ }
+ }
+ Property { name: "parent"; type: "QQuickItem"; isPointer: true }
+ Property { name: "data"; type: "QObject"; isList: true; isReadonly: true }
+ Property { name: "resources"; type: "QObject"; isList: true; isReadonly: true }
+ Property { name: "children"; type: "QQuickItem"; isList: true; isReadonly: true }
+ Property { name: "x"; type: "double" }
+ Property { name: "y"; type: "double" }
+ Property { name: "z"; type: "double" }
+ Property { name: "width"; type: "double" }
+ Property { name: "height"; type: "double" }
+ Property { name: "opacity"; type: "double" }
+ Property { name: "enabled"; type: "bool" }
+ Property { name: "visible"; type: "bool" }
+ Property { name: "visibleChildren"; type: "QQuickItem"; isList: true; isReadonly: true }
+ Property { name: "states"; type: "QQuickState"; isList: true; isReadonly: true }
+ Property { name: "transitions"; type: "QQuickTransition"; isList: true; isReadonly: true }
+ Property { name: "state"; type: "string" }
+ Property { name: "childrenRect"; type: "QRectF"; isReadonly: true }
+ Property { name: "anchors"; type: "QQuickAnchors"; isReadonly: true; isPointer: true }
+ Property { name: "left"; type: "QQuickAnchorLine"; isReadonly: true }
+ Property { name: "right"; type: "QQuickAnchorLine"; isReadonly: true }
+ Property { name: "horizontalCenter"; type: "QQuickAnchorLine"; isReadonly: true }
+ Property { name: "top"; type: "QQuickAnchorLine"; isReadonly: true }
+ Property { name: "bottom"; type: "QQuickAnchorLine"; isReadonly: true }
+ Property { name: "verticalCenter"; type: "QQuickAnchorLine"; isReadonly: true }
+ Property { name: "baseline"; type: "QQuickAnchorLine"; isReadonly: true }
+ Property { name: "baselineOffset"; type: "double" }
+ Property { name: "clip"; type: "bool" }
+ Property { name: "focus"; type: "bool" }
+ Property { name: "activeFocus"; type: "bool"; isReadonly: true }
+ Property { name: "activeFocusOnTab"; revision: 1; type: "bool" }
+ Property { name: "rotation"; type: "double" }
+ Property { name: "scale"; type: "double" }
+ Property { name: "transformOrigin"; type: "TransformOrigin" }
+ Property { name: "transformOriginPoint"; type: "QPointF"; isReadonly: true }
+ Property { name: "transform"; type: "QQuickTransform"; isList: true; isReadonly: true }
+ Property { name: "smooth"; type: "bool" }
+ Property { name: "antialiasing"; type: "bool" }
+ Property { name: "implicitWidth"; type: "double" }
+ Property { name: "implicitHeight"; type: "double" }
+ Property { name: "layer"; type: "QQuickItemLayer"; isReadonly: true; isPointer: true }
+ Signal {
+ name: "childrenRectChanged"
+ Parameter { type: "QRectF" }
+ }
+ Signal {
+ name: "baselineOffsetChanged"
+ Parameter { type: "double" }
+ }
+ Signal {
+ name: "stateChanged"
+ Parameter { type: "string" }
+ }
+ Signal {
+ name: "focusChanged"
+ Parameter { type: "bool" }
+ }
+ Signal {
+ name: "activeFocusChanged"
+ Parameter { type: "bool" }
+ }
+ Signal {
+ name: "activeFocusOnTabChanged"
+ revision: 1
+ Parameter { type: "bool" }
+ }
+ Signal {
+ name: "parentChanged"
+ Parameter { type: "QQuickItem"; isPointer: true }
+ }
+ Signal {
+ name: "transformOriginChanged"
+ Parameter { type: "TransformOrigin" }
+ }
+ Signal {
+ name: "smoothChanged"
+ Parameter { type: "bool" }
+ }
+ Signal {
+ name: "antialiasingChanged"
+ Parameter { type: "bool" }
+ }
+ Signal {
+ name: "clipChanged"
+ Parameter { type: "bool" }
+ }
+ Signal {
+ name: "windowChanged"
+ revision: 1
+ Parameter { name: "window"; type: "QQuickWindow"; isPointer: true }
+ }
+ Method { name: "update" }
+ Method {
+ name: "contains"
+ type: "bool"
+ Parameter { name: "point"; type: "QPointF" }
+ }
+ Method {
+ name: "mapFromItem"
+ Parameter { type: "QQmlV4Function"; isPointer: true }
+ }
+ Method {
+ name: "mapToItem"
+ Parameter { type: "QQmlV4Function"; isPointer: true }
+ }
+ Method { name: "forceActiveFocus" }
+ Method {
+ name: "forceActiveFocus"
+ Parameter { name: "reason"; type: "Qt::FocusReason" }
+ }
+ Method {
+ name: "nextItemInFocusChain"
+ revision: 1
+ type: "QQuickItem*"
+ Parameter { name: "forward"; type: "bool" }
+ }
+ Method { name: "nextItemInFocusChain"; revision: 1; type: "QQuickItem*" }
+ Method {
+ name: "childAt"
+ type: "QQuickItem*"
+ Parameter { name: "x"; type: "double" }
+ Parameter { name: "y"; type: "double" }
+ }
+ }
+}
diff --git a/tests/auto/qml/codemodel/importscheck/importTypes/imports-QtQuick-simple/QtQuick.2/qmldir b/tests/auto/qml/codemodel/importscheck/importTypes/imports-QtQuick-simple/QtQuick.2/qmldir
new file mode 100644
index 0000000000..4a79c82e76
--- /dev/null
+++ b/tests/auto/qml/codemodel/importscheck/importTypes/imports-QtQuick-simple/QtQuick.2/qmldir
@@ -0,0 +1,4 @@
+module QtQuick
+plugin qtquick2plugin
+classname QtQuick2Plugin
+typeinfo plugins.qmltypes
diff --git a/tests/auto/qml/codemodel/importscheck/importTypes/imports-QtQuick-workaround-QtQml/QtQml/plugins.qmltypes b/tests/auto/qml/codemodel/importscheck/importTypes/imports-QtQuick-workaround-QtQml/QtQml/plugins.qmltypes
new file mode 100644
index 0000000000..39cb4f3ccc
--- /dev/null
+++ b/tests/auto/qml/codemodel/importscheck/importTypes/imports-QtQuick-workaround-QtQml/QtQml/plugins.qmltypes
@@ -0,0 +1,26 @@
+import QtQuick.tooling 1.1
+
+// This file describes the plugin-supplied types contained in the library.
+// It is used for QML tooling purposes only.
+//
+// This file was auto-generated by:
+// 'qmlplugindump -nonrelocatable -builtins'
+
+Module {
+ Component {
+ name: "QObject"
+ exports: ["QtQml/QtObject 2.0"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "objectName"; type: "string" }
+ Signal {
+ name: "objectNameChanged"
+ Parameter { name: "objectName"; type: "string" }
+ }
+ Method { name: "toString" }
+ Method { name: "destroy" }
+ Method {
+ name: "destroy"
+ Parameter { name: "delay"; type: "int" }
+ }
+ }
+}
diff --git a/tests/auto/qml/codemodel/importscheck/importTypes/imports-QtQuick-workaround-QtQml/QtQml/qmldir b/tests/auto/qml/codemodel/importscheck/importTypes/imports-QtQuick-workaround-QtQml/QtQml/qmldir
new file mode 100644
index 0000000000..8175ebb1a1
--- /dev/null
+++ b/tests/auto/qml/codemodel/importscheck/importTypes/imports-QtQuick-workaround-QtQml/QtQml/qmldir
@@ -0,0 +1,2 @@
+module QtQml
+typeinfo plugins.qmltypes
diff --git a/tests/auto/qml/codemodel/importscheck/importTypes/imports-QtQuick-workaround-QtQml/QtQuick.2/plugins.qmltypes b/tests/auto/qml/codemodel/importscheck/importTypes/imports-QtQuick-workaround-QtQml/QtQuick.2/plugins.qmltypes
new file mode 100644
index 0000000000..25d6c402a6
--- /dev/null
+++ b/tests/auto/qml/codemodel/importscheck/importTypes/imports-QtQuick-workaround-QtQml/QtQuick.2/plugins.qmltypes
@@ -0,0 +1,174 @@
+import QtQuick.tooling 1.1
+
+// This file describes the plugin-supplied types contained in the library.
+// It is used for QML tooling purposes only.
+//
+// This file was auto-generated by:
+// 'qmlplugindump -nonrelocatable -builtins'
+
+Module {
+ Component {
+ name: "IsQtQuickWorkaround"
+ exports: ["QtQuick/IsQtQuickWorkaround 2.0"]
+ exportMetaObjectRevisions: [0]
+ }
+ Component {
+ name: "QQuickBehavior"
+ defaultProperty: "animation"
+ prototype: "QObject"
+ exports: [
+ "QtQuick/Behavior 2.0",
+ "QtQuick/Behavior 2.13",
+ "QtQuick/Behavior 2.15"
+ ]
+ exportMetaObjectRevisions: [0, 13, 15]
+ Property { name: "animation"; type: "QQuickAbstractAnimation"; isPointer: true }
+ Property { name: "enabled"; type: "bool" }
+ Property { name: "targetValue"; revision: 13; type: "QVariant"; isReadonly: true }
+ Property { name: "targetProperty"; revision: 15; type: "QQmlProperty"; isReadonly: true }
+ Method { name: "componentFinalized" }
+ }
+ Component {
+ name: "QQuickItem"
+ defaultProperty: "data"
+ prototype: "QObject"
+ exports: ["QtQuick/Item 2.0", "QtQuick/Item 2.1"]
+ exportMetaObjectRevisions: [0, 1]
+ Enum {
+ name: "TransformOrigin"
+ values: {
+ "TopLeft": 0,
+ "Top": 1,
+ "TopRight": 2,
+ "Left": 3,
+ "Center": 4,
+ "Right": 5,
+ "BottomLeft": 6,
+ "Bottom": 7,
+ "BottomRight": 8
+ }
+ }
+ Property { name: "parent"; type: "QQuickItem"; isPointer: true }
+ Property { name: "data"; type: "QObject"; isList: true; isReadonly: true }
+ Property { name: "resources"; type: "QObject"; isList: true; isReadonly: true }
+ Property { name: "children"; type: "QQuickItem"; isList: true; isReadonly: true }
+ Property { name: "x"; type: "double" }
+ Property { name: "y"; type: "double" }
+ Property { name: "z"; type: "double" }
+ Property { name: "width"; type: "double" }
+ Property { name: "height"; type: "double" }
+ Property { name: "opacity"; type: "double" }
+ Property { name: "enabled"; type: "bool" }
+ Property { name: "visible"; type: "bool" }
+ Property { name: "visibleChildren"; type: "QQuickItem"; isList: true; isReadonly: true }
+ Property { name: "states"; type: "QQuickState"; isList: true; isReadonly: true }
+ Property { name: "transitions"; type: "QQuickTransition"; isList: true; isReadonly: true }
+ Property { name: "state"; type: "string" }
+ Property { name: "childrenRect"; type: "QRectF"; isReadonly: true }
+ Property { name: "anchors"; type: "QQuickAnchors"; isReadonly: true; isPointer: true }
+ Property { name: "left"; type: "QQuickAnchorLine"; isReadonly: true }
+ Property { name: "right"; type: "QQuickAnchorLine"; isReadonly: true }
+ Property { name: "horizontalCenter"; type: "QQuickAnchorLine"; isReadonly: true }
+ Property { name: "top"; type: "QQuickAnchorLine"; isReadonly: true }
+ Property { name: "bottom"; type: "QQuickAnchorLine"; isReadonly: true }
+ Property { name: "verticalCenter"; type: "QQuickAnchorLine"; isReadonly: true }
+ Property { name: "baseline"; type: "QQuickAnchorLine"; isReadonly: true }
+ Property { name: "baselineOffset"; type: "double" }
+ Property { name: "clip"; type: "bool" }
+ Property { name: "focus"; type: "bool" }
+ Property { name: "activeFocus"; type: "bool"; isReadonly: true }
+ Property { name: "activeFocusOnTab"; revision: 1; type: "bool" }
+ Property { name: "rotation"; type: "double" }
+ Property { name: "scale"; type: "double" }
+ Property { name: "transformOrigin"; type: "TransformOrigin" }
+ Property { name: "transformOriginPoint"; type: "QPointF"; isReadonly: true }
+ Property { name: "transform"; type: "QQuickTransform"; isList: true; isReadonly: true }
+ Property { name: "smooth"; type: "bool" }
+ Property { name: "antialiasing"; type: "bool" }
+ Property { name: "implicitWidth"; type: "double" }
+ Property { name: "implicitHeight"; type: "double" }
+ Property { name: "layer"; type: "QQuickItemLayer"; isReadonly: true; isPointer: true }
+ Signal {
+ name: "childrenRectChanged"
+ Parameter { type: "QRectF" }
+ }
+ Signal {
+ name: "baselineOffsetChanged"
+ Parameter { type: "double" }
+ }
+ Signal {
+ name: "stateChanged"
+ Parameter { type: "string" }
+ }
+ Signal {
+ name: "focusChanged"
+ Parameter { type: "bool" }
+ }
+ Signal {
+ name: "activeFocusChanged"
+ Parameter { type: "bool" }
+ }
+ Signal {
+ name: "activeFocusOnTabChanged"
+ revision: 1
+ Parameter { type: "bool" }
+ }
+ Signal {
+ name: "parentChanged"
+ Parameter { type: "QQuickItem"; isPointer: true }
+ }
+ Signal {
+ name: "transformOriginChanged"
+ Parameter { type: "TransformOrigin" }
+ }
+ Signal {
+ name: "smoothChanged"
+ Parameter { type: "bool" }
+ }
+ Signal {
+ name: "antialiasingChanged"
+ Parameter { type: "bool" }
+ }
+ Signal {
+ name: "clipChanged"
+ Parameter { type: "bool" }
+ }
+ Signal {
+ name: "windowChanged"
+ revision: 1
+ Parameter { name: "window"; type: "QQuickWindow"; isPointer: true }
+ }
+ Method { name: "update" }
+ Method {
+ name: "contains"
+ type: "bool"
+ Parameter { name: "point"; type: "QPointF" }
+ }
+ Method {
+ name: "mapFromItem"
+ Parameter { type: "QQmlV4Function"; isPointer: true }
+ }
+ Method {
+ name: "mapToItem"
+ Parameter { type: "QQmlV4Function"; isPointer: true }
+ }
+ Method { name: "forceActiveFocus" }
+ Method {
+ name: "forceActiveFocus"
+ Parameter { name: "reason"; type: "Qt::FocusReason" }
+ }
+ Method {
+ name: "nextItemInFocusChain"
+ revision: 1
+ type: "QQuickItem*"
+ Parameter { name: "forward"; type: "bool" }
+ }
+ Method { name: "nextItemInFocusChain"; revision: 1; type: "QQuickItem*" }
+ Method {
+ name: "childAt"
+ type: "QQuickItem*"
+ Parameter { name: "x"; type: "double" }
+ Parameter { name: "y"; type: "double" }
+ }
+ }
+}
diff --git a/tests/auto/qml/codemodel/importscheck/importTypes/imports-QtQuick-workaround-QtQml/QtQuick.2/qmldir b/tests/auto/qml/codemodel/importscheck/importTypes/imports-QtQuick-workaround-QtQml/QtQuick.2/qmldir
new file mode 100644
index 0000000000..4a79c82e76
--- /dev/null
+++ b/tests/auto/qml/codemodel/importscheck/importTypes/imports-QtQuick-workaround-QtQml/QtQuick.2/qmldir
@@ -0,0 +1,4 @@
+module QtQuick
+plugin qtquick2plugin
+classname QtQuick2Plugin
+typeinfo plugins.qmltypes
diff --git a/tests/auto/qml/codemodel/importscheck/tst_importscheck.cpp b/tests/auto/qml/codemodel/importscheck/tst_importscheck.cpp
index f6126b73af..2496f7341d 100644
--- a/tests/auto/qml/codemodel/importscheck/tst_importscheck.cpp
+++ b/tests/auto/qml/codemodel/importscheck/tst_importscheck.cpp
@@ -58,6 +58,9 @@ private slots:
void test();
void test_data();
+ void importTypes_data();
+ void importTypes();
+
void initTestCase();
private:
QStringList m_basePaths;
@@ -191,10 +194,12 @@ void tst_ImportCheck::test()
QStringList detectedFiles;
foreach (const ImportKey &importK, iDeps->libraryImports(vCtx))
detectedLibraries << importK.toString();
- foreach (const QString &path, paths)
+ foreach (const QString &path, paths) {
foreach (const ImportKey &importK, iDeps->subdirImports(ImportKey(ImportType::Directory,
- path), vCtx))
- detectedFiles << QFileInfo(importK.toString()).canonicalFilePath();
+ path), vCtx)) {
+ detectedFiles << QFileInfo(importK.toString()).canonicalFilePath();
+ }
+ }
expectedLibraries.sort();
expectedFiles.sort();
@@ -204,6 +209,92 @@ void tst_ImportCheck::test()
QCOMPARE(expectedFiles, detectedFiles);
}
+class MyModelManager : public ModelManagerInterface
+{
+public:
+ using ModelManagerInterface::setDefaultProject;
+ using ModelManagerInterface::updateImportPaths;
+};
+
+void tst_ImportCheck::importTypes_data()
+{
+ QTest::addColumn<QString>("qmlFile");
+ QTest::addColumn<QString>("importPath");
+ QTest::addColumn<QStringList>("expectedTypes");
+
+ QTest::newRow("base")
+ << QString(TESTSRCDIR "/importTypes/importQtQuick.qml")
+ << QString(TESTSRCDIR "/base")
+ << QStringList({ "Item", "Rectangle", "QtObject" });
+
+ // simple case, with everything in QtQuick/plugins.qmltypes
+ QTest::newRow("QtQuick-simple")
+ << QString(TESTSRCDIR "/importTypes/importQtQuick.qml")
+ << QString(TESTSRCDIR "/importTypes/imports-QtQuick-simple")
+ << QStringList({ "Item", "QtObject", "IsQtQuickSimple" });
+
+ // QtQuick/ and QtQml/ with an implicit dependency
+ // Seen in Qt 5.15.0.
+ QTest::newRow("QtQuick-workaround-QtQml")
+ << QString(TESTSRCDIR "/importTypes/importQtQuick.qml")
+ << QString(TESTSRCDIR "/importTypes/imports-QtQuick-workaround-QtQml")
+ << QStringList({ "Item", "QtObject", "IsQtQuickWorkaround" });
+
+ // QtQuick/ and QtQml/ with an "import" in the qmldir file
+ // Seen in Qt 6.
+ QTest::newRow("QtQuick-qmldir-import")
+ << QString(TESTSRCDIR "/importTypes/importQtQuick.qml")
+ << QString(TESTSRCDIR "/importTypes/imports-QtQuick-qmldir-import")
+ << QStringList({ "Item", "QtObject", "IsQtQuickQmldirImport" });
+}
+
+void tst_ImportCheck::importTypes()
+{
+ QFETCH(QString, qmlFile);
+ QFETCH(QString, importPath);
+ QFETCH(QStringList, expectedTypes);
+
+ // full reset
+ delete ModelManagerInterface::instance();
+ MyModelManager *modelManager = new MyModelManager;
+
+ // the default qtQmlPath is based on the Qt version in use otherwise
+ ModelManagerInterface::ProjectInfo defaultProject;
+ defaultProject.qtQmlPath = importPath;
+ modelManager->setDefaultProject(defaultProject, nullptr);
+ modelManager->activateScan();
+
+ modelManager->updateSourceFiles(QStringList(qmlFile), false);
+ modelManager->test_joinAllThreads();
+
+ Snapshot snapshot = modelManager->newestSnapshot();
+ Document::Ptr doc = snapshot.document(qmlFile);
+
+ // It's unfortunate, but nowadays linking can trigger async module loads,
+ // so do it once to start the process, then do it again for real once the
+ // dependencies are available.
+ const auto getContext = [&]() {
+ Link link(snapshot, modelManager->defaultVContext(doc->language(), doc),
+ modelManager->builtins(doc));
+ return link();
+ };
+ getContext();
+ modelManager->test_joinAllThreads();
+ snapshot = modelManager->newestSnapshot();
+ doc = snapshot.document(qmlFile);
+
+ ContextPtr context = getContext();
+
+ bool allFound = true;
+ for (const auto &expected : expectedTypes) {
+ if (!context->lookupType(doc.data(), QStringList(expected))) {
+ allFound = false;
+ qWarning() << "Type '" << expected << "' not found";
+ }
+ }
+ QVERIFY(allFound);
+}
+
#ifdef MANUAL_IMPORT_SCANNER
int main(int argc, char *argv[])
diff --git a/tests/manual/debugger/simple/simple_test_app.cpp b/tests/manual/debugger/simple/simple_test_app.cpp
index 20734abede..65e38d92e3 100644
--- a/tests/manual/debugger/simple/simple_test_app.cpp
+++ b/tests/manual/debugger/simple/simple_test_app.cpp
@@ -5304,7 +5304,7 @@ namespace basic {
// Continue.
// Manual: Toogle "Sort Member Alphabetically" in context menu
- // Manual: of "Locals and Expressions" view.
+ // Manual: of "Locals" and "Expressions" views.
// Manual: Check that order of displayed members changes.
dummyStatement(&c);
}
@@ -5436,7 +5436,7 @@ namespace basic {
void testTypeFormats()
{
// These tests should result in properly displayed umlauts in the
- // Locals and Expressions view. It is only support on gdb with Python.
+ // Locals and Expressions views. It is only support on gdb with Python.
const char *s = "aöa";
const char cs[] = "aöa";
diff --git a/tests/tests.qbs b/tests/tests.qbs
index 0b475afde5..4e04ae57d8 100644
--- a/tests/tests.qbs
+++ b/tests/tests.qbs
@@ -2,5 +2,8 @@ import qbs
Project {
name: "Tests"
- references: ["auto/auto.qbs"]
+ references: [
+ "auto/auto.qbs",
+ "unit/unit.qbs",
+ ]
}
diff --git a/tests/unit/echoserver/echoserver.qbs b/tests/unit/echoserver/echoserver.qbs
new file mode 100644
index 0000000000..77df73a6d6
--- /dev/null
+++ b/tests/unit/echoserver/echoserver.qbs
@@ -0,0 +1,30 @@
+import qbs.FileInfo
+
+QtcProduct {
+ name: "echoserver"
+ type: "application"
+ targetName: "echo"
+ consoleApplication: true
+ destinationDirectory: FileInfo.joinPaths(project.buildDirectory,
+ FileInfo.relativePath(project.ide_source_tree, sourceDirectory))
+ install: false
+
+ Depends { name: "qtc" }
+ Depends { name: "ClangSupport" }
+ Depends { name: "Sqlite" }
+ Depends { name: "Utils" }
+ Depends { name: "Qt.network" }
+
+ cpp.defines: ["CLANGSUPPORT_TESTS", "DONT_CHECK_MESSAGE_COUNTER"]
+ cpp.dynamicLibraries: qbs.targetOS.contains("unix:") ? ["dl"] : []
+ cpp.rpaths: [
+ FileInfo.joinPaths(project.buildDirectory, qtc.ide_library_path),
+ FileInfo.joinPaths(project.buildDirectory, qtc.ide_plugin_path)
+ ]
+
+ files: [
+ "echoclangcodemodelserver.cpp",
+ "echoclangcodemodelserver.h",
+ "echoserverprocessmain.cpp",
+ ]
+}
diff --git a/tests/unit/echoserver/echoserverprocessmain.cpp b/tests/unit/echoserver/echoserverprocessmain.cpp
index 07010b0b91..5225007617 100644
--- a/tests/unit/echoserver/echoserverprocessmain.cpp
+++ b/tests/unit/echoserver/echoserverprocessmain.cpp
@@ -43,12 +43,9 @@ int main(int argc, char *argv[])
QCoreApplication application(argc, argv);
-
if (application.arguments().count() < 2)
return 1;
- else if (application.arguments().count() == 3)
- *(int*)0 = 0;
- else if (application.arguments().contains("connectionName"))
+ if (application.arguments().contains("connectionName"))
return 0;
EchoClangCodeModelServer echoClangCodeModelServer;
diff --git a/tests/unit/unit.qbs b/tests/unit/unit.qbs
new file mode 100644
index 0000000000..cf73b27036
--- /dev/null
+++ b/tests/unit/unit.qbs
@@ -0,0 +1,7 @@
+Project {
+ name: "C++ unit tests"
+ references: [
+ "echoserver/echoserver.qbs",
+ "unittest/unittest.qbs",
+ ]
+}
diff --git a/tests/unit/unittest/CMakeLists.txt b/tests/unit/unittest/CMakeLists.txt
index 4e7b97d53b..3df5d88987 100644
--- a/tests/unit/unittest/CMakeLists.txt
+++ b/tests/unit/unittest/CMakeLists.txt
@@ -164,6 +164,14 @@ add_qtc_test(unittest GTEST
unittest-utility-functions.h
usedmacrofilter-test.cpp
utf8-test.cpp
+ sqlitecolumn-test.cpp
+ sqlitedatabasebackend-test.cpp
+ sqlitedatabase-test.cpp
+ sqlitestatement-test.cpp
+ sqlitetable-test.cpp
+ sqlstatementbuilder-test.cpp
+ createtablesqlstatementbuilder-test.cpp
+ sqlitevalue-test.cpp
)
# Do not work on the source directory data
@@ -183,8 +191,11 @@ string(REPLACE "$$QTCREATOR_COPYRIGHT_YEAR" "${IDE_COPYRIGHT_YEAR}" plugin_json_
string(REPLACE "$$dependencyList" "\"Dependencies\" : []" plugin_json_in ${plugin_json_in})
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/CppTools.json" ${plugin_json_in}})
-if (TARGET libclang)
- target_sources(unittest PRIVATE
+extend_qtc_test(unittest
+ CONDITION TARGET libclang
+ INCLUDES "${CLANG_INCLUDE_DIRS}"
+ DEPENDS libclang
+ SOURCES
activationsequencecontextprocessor-test.cpp
activationsequenceprocessor-test.cpp
chunksreportedmonitor.cpp
@@ -219,7 +230,6 @@ if (TARGET libclang)
codecompleter-test.cpp
codecompletionsextractor-test.cpp
completionchunkstotextconverter-test.cpp
- createtablesqlstatementbuilder-test.cpp
cursor-test.cpp
diagnosticset-test.cpp
diagnostic-test.cpp
@@ -228,12 +238,6 @@ if (TARGET libclang)
skippedsourceranges-test.cpp
sourcelocation-test.cpp
sourcerange-test.cpp
- sqlitecolumn-test.cpp
- sqlitedatabasebackend-test.cpp
- sqlitedatabase-test.cpp
- sqlitestatement-test.cpp
- sqlitetable-test.cpp
- sqlstatementbuilder-test.cpp
token-test.cpp
translationunitupdater-test.cpp
unsavedfiles-test.cpp
@@ -243,14 +247,13 @@ if (TARGET libclang)
clangasyncjob-base.h
clangcompareoperators.h
diagnosticcontainer-matcher.h
- )
- target_include_directories(unittest PRIVATE "${CLANG_INCLUDE_DIRS}")
- target_link_libraries(unittest PRIVATE libclang)
-endif()
+)
-if (TARGET clangTooling)
- target_compile_definitions(unittest PRIVATE CLANG_UNIT_TESTS)
- target_sources(unittest PRIVATE
+extend_qtc_test(unittest
+ CONDITION TARGET clangTooling
+ DEFINES CLANG_UNIT_TESTS
+ DEPENDS clangTooling clangIndex clangQuery
+ SOURCES
gtest-llvm-printing.cpp
clangquerygatherer-test.cpp
clangqueryprojectfindfilter-test.cpp
@@ -270,24 +273,21 @@ if (TARGET clangTooling)
builddependencycollector-test.cpp
mockrefactoringclient.h
mockrefactoringserver.h
- )
- target_link_libraries(unittest
- PRIVATE clangTooling clangIndex clangQuery)
-endif()
+)
-if (TARGET clangFormat)
- target_sources(unittest PRIVATE
+extend_qtc_test(unittest
+ CONDITION TARGET clangFormat
+ DEPENDS clangFormat
+ SOURCES
clangformat-test.cpp
- )
- target_link_libraries(unittest PRIVATE clangFormat)
-endif()
+)
-if (TARGET GoogleBenchmark)
- target_sources(unittest PRIVATE
+extend_qtc_test(unittest
+ CONDITION TARGET GoogleBenchmark
+ DEPENDS GoogleBenchmark
+ SOURCES
smallstring-benchmark.cpp
- )
- target_link_libraries(unittest PRIVATE GoogleBenchmark)
-endif()
+)
finalize_qtc_gtest(unittest)
@@ -300,7 +300,7 @@ target_include_directories(unittest
get_target_property(ClangSupportSources ClangSupport SOURCES)
get_target_property(ClangSupportSourcesDir ClangSupport SOURCES_DIR)
-extend_qtc_target(unittest
+extend_qtc_test(unittest
SOURCES_PREFIX "${ClangSupportSourcesDir}"
SOURCES ${ClangSupportSources}
DEFINES
@@ -311,7 +311,7 @@ extend_qtc_target(unittest
)
get_target_property(ClangCodeModelSourcesDir ClangCodeModel SOURCES_DIR)
-extend_qtc_target(unittest
+extend_qtc_test(unittest
SOURCES_PREFIX "${ClangCodeModelSourcesDir}"
SOURCES
clangactivationsequencecontextprocessor.cpp clangactivationsequencecontextprocessor.h
@@ -326,14 +326,14 @@ extend_qtc_target(unittest
)
get_target_property(CompilationDatabasePMSourcesDir CompilationDatabaseProjectManager SOURCES_DIR)
-extend_qtc_target(unittest
+extend_qtc_test(unittest
SOURCES_PREFIX "${CompilationDatabasePMSourcesDir}"
SOURCES
compilationdatabaseutils.cpp compilationdatabaseutils.h
)
get_target_property(CoreSourcesDir Core SOURCES_DIR)
-extend_qtc_target(unittest
+extend_qtc_test(unittest
SOURCES_PREFIX "${CoreSourcesDir}"
DEFINES CORE_STATIC_LIBRARY
SOURCES
@@ -344,7 +344,7 @@ extend_qtc_target(unittest
)
get_target_property(CppToolsSourcesDir CppTools SOURCES_DIR)
-extend_qtc_target(unittest
+extend_qtc_test(unittest
SOURCES_PREFIX "${CppToolsSourcesDir}"
DEFINES CPPTOOLS_STATIC_LIBRARY
SOURCES
@@ -360,7 +360,7 @@ extend_qtc_target(unittest
)
get_target_property(ProjectExplorerSourcesDir ProjectExplorer SOURCES_DIR)
-extend_qtc_target(unittest
+extend_qtc_test(unittest
SOURCES_PREFIX "${ProjectExplorerSourcesDir}"
DEFINES PROJECTEXPLORER_STATIC_LIBRARY
SOURCES
@@ -368,7 +368,7 @@ extend_qtc_target(unittest
)
get_target_property(ClangRefactoringSourcesDir ClangRefactoring SOURCES_DIR)
-extend_qtc_target(unittest
+extend_qtc_test(unittest
SOURCES_PREFIX "${ClangRefactoringSourcesDir}"
SOURCES
clangqueryexamplehighlighter.cpp clangqueryexamplehighlighter.h
@@ -392,7 +392,7 @@ extend_qtc_target(unittest
)
get_target_property(ClangPchManagerSourcesDir ClangPchManager SOURCES_DIR)
-extend_qtc_target(unittest
+extend_qtc_test(unittest
SOURCES_PREFIX "${ClangPchManagerSourcesDir}"
DEFINES CLANGPCHMANAGER_STATIC_LIB
SOURCES
@@ -410,7 +410,7 @@ extend_qtc_target(unittest
)
get_target_property(ClangFormatSourcesDir ClangFormat SOURCES_DIR)
-extend_qtc_target(unittest
+extend_qtc_test(unittest
SOURCES_PREFIX "${ClangFormatSourcesDir}"
DEFINES CLANGPCHMANAGER_STATIC_LIB
SOURCES
diff --git a/tests/unit/unittest/clangformat-test.cpp b/tests/unit/unittest/clangformat-test.cpp
index 172afb64c8..822f4b76d2 100644
--- a/tests/unit/unittest/clangformat-test.cpp
+++ b/tests/unit/unittest/clangformat-test.cpp
@@ -198,7 +198,14 @@ TEST_F(ClangFormat, IndentLambdaWithReturnType)
"}"));
}
-TEST_F(ClangFormat, IndentFunctionArgumentLambdaWithNextLineScope)
+#ifndef KEEP_LINE_BREAKS_FOR_NON_EMPTY_LINES_BACKPORTED
+# define DISABLED_FOR_VANILLA_CLANG(x) DISABLED_##x
+#else
+# define DISABLED_FOR_VANILLA_CLANG(x) x
+#endif
+
+// This test requires the custom clang patch https://code.qt.io/cgit/clang/llvm-project.git/commit/?h=release_100-based&id=9b992a0f7f160dd6c75f20a4dcfcf7c60a4894df
+TEST_F(ClangFormat, DISABLED_FOR_VANILLA_CLANG(IndentFunctionArgumentLambdaWithNextLineScope))
{
insertLines({"foo([]()",
"{",
diff --git a/tests/unit/unittest/clangsupportivetranslationunitinitializer-test.cpp b/tests/unit/unittest/clangsupportivetranslationunitinitializer-test.cpp
index 9e79cd744d..c62b803a71 100644
--- a/tests/unit/unittest/clangsupportivetranslationunitinitializer-test.cpp
+++ b/tests/unit/unittest/clangsupportivetranslationunitinitializer-test.cpp
@@ -31,7 +31,7 @@
#include <clangbackend_global.h>
#include <clangdocuments.h>
#include <clangexceptions.h>
-#include <clangsupportivetranslationunitinitializer.cpp>
+#include <clangsupportivetranslationunitinitializer.h>
#include <clangtranslationunit.h>
#include <clangtranslationunits.h>
#include <utf8string.h>
diff --git a/tests/unit/unittest/clangtooltipinfo-test.cpp b/tests/unit/unittest/clangtooltipinfo-test.cpp
index fb630e2aa3..26b6596cc5 100644
--- a/tests/unit/unittest/clangtooltipinfo-test.cpp
+++ b/tests/unit/unittest/clangtooltipinfo-test.cpp
@@ -385,6 +385,15 @@ TEST_F(ToolTipInfo, SizeForUnion)
ASSERT_THAT(actual.sizeInBytes, Utf8StringLiteral("1"));
}
+TEST_F(ToolTipInfo, constexprValue)
+{
+ // CLANG-UPGRADE-CHECK: Adapt the values below
+ ASSERT_THAT(tooltip(204, 12).value.toInt(), 4);
+ ASSERT_THAT(tooltip(204, 27).value.toInt(), 4); // 3 in clang 11
+ ASSERT_THAT(tooltip(204, 30).value.toInt(), 4);
+ ASSERT_THAT(tooltip(204, 32).value.toInt(), 4); // 1 in clang 11
+}
+
TEST_F(ToolTipInfo, Namespace)
{
::ToolTipInfo expected(Utf8StringLiteral("X"));
diff --git a/tests/unit/unittest/codecompleter-test.cpp b/tests/unit/unittest/codecompleter-test.cpp
index ec865aacbd..dcb1c1a57c 100644
--- a/tests/unit/unittest/codecompleter-test.cpp
+++ b/tests/unit/unittest/codecompleter-test.cpp
@@ -530,7 +530,9 @@ TEST_F(CodeCompleterSlowTest, NoDotArrowCorrectionForColonColon)
ASSERT_THAT(completions, Not(Contains(HasFixIts())));
}
-TEST_F(CodeCompleterSlowTest, NoGlobalCompletionAfterForwardDeclaredClassPointer)
+// Our workaround is not applicable with LLVM/Clang 10 anymore, so disable this test for that version.
+// Luckily, the workaround is not needed anymore with LLVM/Clang 11.
+TEST_F(CodeCompleterSlowTest, DISABLED_FOR_CLANG_10(NoGlobalCompletionAfterForwardDeclaredClassPointer))
{
auto myCompleter = setupCompleter(globalCompletionAfterForwardDeclaredClassPointer);
const ClangBackEnd::CodeCompletions completions = myCompleter.complete(5, 10);
diff --git a/tests/unit/unittest/conditionally-disabled-tests.h b/tests/unit/unittest/conditionally-disabled-tests.h
index 128520a881..91b2541fe9 100644
--- a/tests/unit/unittest/conditionally-disabled-tests.h
+++ b/tests/unit/unittest/conditionally-disabled-tests.h
@@ -25,6 +25,14 @@
#include <QtGlobal>
+#include <clang-c/Index.h>
+
+#if CINDEX_VERSION_MAJOR == 0 && CINDEX_VERSION_MINOR == 59
+# define DISABLED_FOR_CLANG_10(x) DISABLED_##x
+#else
+# define DISABLED_FOR_CLANG_10(x) x
+#endif
+
#ifdef Q_OS_WIN
# define DISABLED_ON_WINDOWS(x) DISABLED_##x
#else
diff --git a/tests/unit/unittest/creator_dependency.pri b/tests/unit/unittest/creator_dependency.pri
index 2e84e1cdca..e5b10f65ae 100644
--- a/tests/unit/unittest/creator_dependency.pri
+++ b/tests/unit/unittest/creator_dependency.pri
@@ -14,11 +14,11 @@ include($$PWD/../../../src/tools/clangpchmanagerbackend/source/clangpchmanagerba
include($$PWD/../../../src/plugins/clangrefactoring/clangrefactoring-source.pri)
include($$PWD/../../../src/plugins/clangpchmanager/clangpchmanager-source.pri)
include($$PWD/../../../src/plugins/cpptools/cpptoolsunittestfiles.pri)
-include($$PWD/../../../src/plugins/clangtools/clangtoolsunittestfiles.pri)
include($$PWD/../../../src/plugins/debugger/debuggerunittestfiles.pri)
include($$PWD/../../../src/plugins/compilationdatabaseprojectmanager/compilationdatabaseunittestfiles.pri)
include(cplusplus.pri)
!isEmpty(LLVM_VERSION) {
+include($$PWD/../../../src/plugins/clangtools/clangtoolsunittestfiles.pri)
include($$PWD/../../../src/shared/clang/clang_defines.pri)
include($$PWD/../../../src/tools/clangbackend/source/clangbackendclangipc-source.pri)
include($$PWD/../../../src/plugins/clangcodemodel/clangcodemodelunittestfiles.pri)
diff --git a/tests/unit/unittest/data/tooltipinfo.cpp b/tests/unit/unittest/data/tooltipinfo.cpp
index bfad1fdd0f..6844a823cc 100644
--- a/tests/unit/unittest/data/tooltipinfo.cpp
+++ b/tests/unit/unittest/data/tooltipinfo.cpp
@@ -199,3 +199,6 @@ Nuu **pointers(Nuu **p1)
{
return p1;
}
+
+static constexpr int calcValue() { return 1 + 2; }
+const auto val = calcValue() + sizeof(char);
diff --git a/tests/unit/unittest/diagnostic-test.cpp b/tests/unit/unittest/diagnostic-test.cpp
index 3ab382c46b..adfc503d3e 100644
--- a/tests/unit/unittest/diagnostic-test.cpp
+++ b/tests/unit/unittest/diagnostic-test.cpp
@@ -123,7 +123,11 @@ TEST_F(DiagnosticSlowTest, MoveSelfAssigment)
TEST_F(DiagnosticSlowTest, Text)
{
+#if CINDEX_VERSION_MAJOR == 0 && CINDEX_VERSION_MINOR >= 59 // >= LLVM/Clang 10
+ ASSERT_THAT(diagnostic.text(), Utf8StringLiteral("warning: non-void function does not return a value"));
+#else
ASSERT_THAT(diagnostic.text(), Utf8StringLiteral("warning: control reaches end of non-void function"));
+#endif
}
TEST_F(DiagnosticSlowTest, Category)
diff --git a/tests/unit/unittest/gtest-creator-printing.cpp b/tests/unit/unittest/gtest-creator-printing.cpp
index 2bbcdbaa45..62561d279b 100644
--- a/tests/unit/unittest/gtest-creator-printing.cpp
+++ b/tests/unit/unittest/gtest-creator-printing.cpp
@@ -37,6 +37,7 @@
#include <clangcodemodelservermessages.h>
#include <clangpathwatcher.h>
#include <clangrefactoringmessages.h>
+#include <clangtools/clangtoolsdiagnostic.h>
#include <coreplugin/find/searchresultitem.h>
#include <coreplugin/locator/ilocatorfilter.h>
#include <cpptools/usages.h>
@@ -57,6 +58,7 @@
#include <sourcedependency.h>
#include <sourcelocationentry.h>
#include <sourcelocationscontainer.h>
+#include <sqlitevalue.h>
#include <symbol.h>
#include <symbolentry.h>
#include <symbolindexertaskqueue.h>
@@ -64,12 +66,6 @@
#include <tooltipinfo.h>
#include <usedmacro.h>
#include <utils/link.h>
-#include <cpptools/usages.h>
-#include <projectexplorer/projectmacro.h>
-#include <projectexplorer/headerpath.h>
-#include <coreplugin/find/searchresultitem.h>
-#include <coreplugin/locator/ilocatorfilter.h>
-#include <clangtools/clangtoolsdiagnostic.h>
namespace {
ClangBackEnd::FilePathCaching *filePathCache = nullptr;
@@ -306,6 +302,27 @@ void PrintTo(const Utils::PathString &text, ::std::ostream *os)
} // namespace Utils
+namespace Sqlite {
+std::ostream &operator<<(std::ostream &out, const Value &value)
+{
+ out << "(";
+
+ switch (value.type()) {
+ case Sqlite::ValueType::Integer:
+ out << value.toInteger();
+ break;
+ case Sqlite::ValueType::Float:
+ out << value.toFloat();
+ break;
+ case Sqlite::ValueType::String:
+ out << "\"" << value.toStringView() << "\"";
+ break;
+ }
+
+ return out << ")";
+}
+} // namespace Sqlite
+
namespace ClangBackEnd {
std::ostream &operator<<(std::ostream &out, const FilePathId &id)
@@ -1330,6 +1347,7 @@ std::ostream &operator<<(std::ostream &out, const ExplainingStep &step)
std::ostream &operator<<(std::ostream &out, const Diagnostic &diag) {
return out << "("
+ << diag.name << ", "
<< diag.description << ", "
<< diag.category << ", "
<< diag.type << ", "
diff --git a/tests/unit/unittest/gtest-creator-printing.h b/tests/unit/unittest/gtest-creator-printing.h
index e26809ca51..b91c8d46be 100644
--- a/tests/unit/unittest/gtest-creator-printing.h
+++ b/tests/unit/unittest/gtest-creator-printing.h
@@ -64,6 +64,12 @@ void PrintTo(const TextRange &range, ::std::ostream *os);
} // namespace TextPosition
} // namespace TextPosition
+namespace Sqlite {
+class Value;
+
+std::ostream &operator<<(std::ostream &out, const Value &value);
+} // namespace Sqlite
+
namespace ProjectExplorer {
enum class MacroType;
diff --git a/tests/unit/unittest/readexporteddiagnostics-test.cpp b/tests/unit/unittest/readexporteddiagnostics-test.cpp
index 368c868233..cc52c51450 100644
--- a/tests/unit/unittest/readexporteddiagnostics-test.cpp
+++ b/tests/unit/unittest/readexporteddiagnostics-test.cpp
@@ -106,6 +106,7 @@ TEST_F(ReadExportedDiagnostics, Tidy)
const QString sourceFile = TESTDATA "tidy.modernize-use-nullptr.cpp";
const QString exportedFile = createFile(TESTDATA "tidy.modernize-use-nullptr.yaml", sourceFile);
Diagnostic expectedDiag;
+ expectedDiag.name = "modernize-use-nullptr";
expectedDiag.location = {sourceFile, 2, 25};
expectedDiag.description = "use nullptr [modernize-use-nullptr]";
expectedDiag.type = "warning";
@@ -143,6 +144,7 @@ TEST_F(ReadExportedDiagnostics, Tidy_Clang)
const QString sourceFile = TESTDATA "clang.unused-parameter.cpp";
const QString exportedFile = createFile(TESTDATA "clang.unused-parameter.yaml", sourceFile);
Diagnostic expectedDiag;
+ expectedDiag.name = "clang-diagnostic-unused-parameter";
expectedDiag.location = {sourceFile, 4, 12};
expectedDiag.description = "unused parameter 'g' [clang-diagnostic-unused-parameter]";
expectedDiag.type = "warning";
@@ -162,6 +164,7 @@ TEST_F(ReadExportedDiagnostics, Tidy_ClangAnalyzer)
const QString sourceFile = TESTDATA "clang-analyzer.dividezero.cpp";
const QString exportedFile = createFile(TESTDATA "clang-analyzer.dividezero.yaml", sourceFile);
Diagnostic expectedDiag;
+ expectedDiag.name = "clang-analyzer-core.DivideZero";
expectedDiag.location = {sourceFile, 4, 15};
expectedDiag.description = "Division by zero [clang-analyzer-core.DivideZero]";
expectedDiag.type = "warning";
@@ -197,6 +200,7 @@ TEST_F(ReadExportedDiagnostics, Clazy)
const QString sourceFile = TESTDATA "clazy.qgetenv.cpp";
const QString exportedFile = createFile(TESTDATA "clazy.qgetenv.yaml", sourceFile);
Diagnostic expectedDiag;
+ expectedDiag.name = "clazy-qgetenv";
expectedDiag.location = {sourceFile, 7, 5};
expectedDiag.description = "qgetenv().isEmpty() allocates. Use qEnvironmentVariableIsEmpty() instead [clazy-qgetenv]";
expectedDiag.type = "warning";
diff --git a/tests/unit/unittest/sqlitestatement-test.cpp b/tests/unit/unittest/sqlitestatement-test.cpp
index cb8206d875..c7da3971e4 100644
--- a/tests/unit/unittest/sqlitestatement-test.cpp
+++ b/tests/unit/unittest/sqlitestatement-test.cpp
@@ -40,11 +40,12 @@
namespace {
-using Sqlite::JournalMode;
-using Sqlite::Exception;
using Sqlite::Database;
+using Sqlite::Exception;
+using Sqlite::JournalMode;
using Sqlite::ReadStatement;
using Sqlite::ReadWriteStatement;
+using Sqlite::Value;
using Sqlite::WriteStatement;
MATCHER_P3(HasValues, value1, value2, rowid,
@@ -125,7 +126,7 @@ TEST_F(SqliteStatement, CountRows)
TEST_F(SqliteStatement, Value)
{
- SqliteTestStatement statement("SELECT name, number FROM test ORDER BY name", database);
+ SqliteTestStatement statement("SELECT name, number, value FROM test ORDER BY name", database);
statement.next();
statement.next();
@@ -142,6 +143,9 @@ TEST_F(SqliteStatement, Value)
ASSERT_THAT(statement.fetchValue<Utils::SmallString>(1), "23.3");
ASSERT_THAT(statement.fetchValue<Utils::PathString>(1), "23.3");
ASSERT_THAT(statement.fetchSmallStringViewValue(1), "23.3");
+ ASSERT_THAT(statement.fetchValueView(0), Eq("foo"));
+ ASSERT_THAT(statement.fetchValueView(1), Eq(23.3));
+ ASSERT_THAT(statement.fetchValueView(2), Eq(2));
}
TEST_F(SqliteStatement, ThrowNoValuesToFetchForNotSteppedStatement)
@@ -175,14 +179,14 @@ TEST_F(SqliteStatement, ThrowInvalidColumnFetchedForNotExistingColumn)
ASSERT_THROW(statement.fetchValue<int>(2), Sqlite::InvalidColumnFetched);
}
-TEST_F(SqliteStatement, ToIntergerValue)
+TEST_F(SqliteStatement, ToIntegerValue)
{
auto value = ReadStatement::toValue<int>("SELECT number FROM test WHERE name='foo'", database);
ASSERT_THAT(value, 23);
}
-TEST_F(SqliteStatement, ToLongIntergerValue)
+TEST_F(SqliteStatement, ToLongIntegerValue)
{
ASSERT_THAT(ReadStatement::toValue<qint64>("SELECT number FROM test WHERE name='foo'", database), Eq(23));
}
@@ -319,6 +323,15 @@ TEST_F(SqliteStatement, WriteValues)
ASSERT_THAT(statement, HasValues("see", "7.23", 1));
}
+TEST_F(SqliteStatement, WriteSqliteValues)
+{
+ WriteStatement statement("UPDATE test SET name=?, number=? WHERE rowid=?", database);
+
+ statement.write(Value{"see"}, Value{7.23}, Value{1});
+
+ ASSERT_THAT(statement, HasValues("see", "7.23", 1));
+}
+
TEST_F(SqliteStatement, BindNamedValues)
{
SqliteTestStatement statement("UPDATE test SET name=@name, number=@number WHERE rowid=@id", database);
@@ -375,6 +388,31 @@ TEST_F(SqliteStatement, GetSingleValuesWithoutArguments)
ASSERT_THAT(values, ElementsAre("bar", "foo", "poo"));
}
+class FooValue
+{
+public:
+ FooValue(Sqlite::ValueView value)
+ : value(value)
+ {}
+
+ Sqlite::Value value;
+
+ template<typename Type>
+ friend bool operator==(const FooValue &value, const Type &other)
+ {
+ return value.value == other;
+ }
+};
+
+TEST_F(SqliteStatement, GetSingleSqliteValuesWithoutArguments)
+{
+ ReadStatement statement("SELECT number FROM test", database);
+
+ std::vector<FooValue> values = statement.values<FooValue>(3);
+
+ ASSERT_THAT(values, ElementsAre(Eq("blah"), Eq(23.3), Eq(40)));
+}
+
TEST_F(SqliteStatement, GetStructValuesWithoutArguments)
{
ReadStatement statement("SELECT name, number, value FROM test", database);
diff --git a/tests/unit/unittest/sqlitevalue-test.cpp b/tests/unit/unittest/sqlitevalue-test.cpp
new file mode 100644
index 0000000000..e9cc5c9e40
--- /dev/null
+++ b/tests/unit/unittest/sqlitevalue-test.cpp
@@ -0,0 +1,348 @@
+/****************************************************************************
+**
+** 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 "googletest.h"
+
+#include <sqlitevalue.h>
+
+namespace {
+
+TEST(SqliteValue, ConstructLongLong)
+{
+ Sqlite::Value value{1LL};
+
+ ASSERT_THAT(value.toInteger(), Eq(1LL));
+}
+
+TEST(SqliteValue, Construct)
+{
+ Sqlite::Value value{1};
+
+ ASSERT_THAT(value.toInteger(), Eq(1LL));
+}
+
+TEST(SqliteValue, ConstructFloatingPoint)
+{
+ Sqlite::Value value{1.1};
+
+ ASSERT_THAT(value.toFloat(), Eq(1.1));
+}
+
+TEST(SqliteValue, ConstructStringFromCString)
+{
+ Sqlite::Value value{"foo"};
+
+ ASSERT_THAT(value.toStringView(), Eq("foo"));
+}
+
+TEST(SqliteValue, ConstructStringFromUtilsString)
+{
+ Sqlite::Value value{Utils::SmallString{"foo"}};
+
+ ASSERT_THAT(value.toStringView(), Eq("foo"));
+}
+
+TEST(SqliteValue, ConstructStringFromQString)
+{
+ Sqlite::Value value{QString{"foo"}};
+
+ ASSERT_THAT(value.toStringView(), Eq("foo"));
+}
+
+TEST(SqliteValue, ConstructStringFromIntQVariant)
+{
+ QVariant variant{1};
+
+ Sqlite::Value value{variant};
+
+ ASSERT_THAT(value.toInteger(), Eq(1));
+}
+
+TEST(SqliteValue, ConstructStringFromLongLongQVariant)
+{
+ QVariant variant{1LL};
+
+ Sqlite::Value value{variant};
+
+ ASSERT_THAT(value.toInteger(), Eq(1));
+}
+
+TEST(SqliteValue, ConstructStringFromUintQVariant)
+{
+ QVariant variant{1u};
+
+ Sqlite::Value value{variant};
+
+ ASSERT_THAT(value.toInteger(), Eq(1));
+}
+
+TEST(SqliteValue, ConstructStringFromFloatQVariant)
+{
+ QVariant variant{1.};
+
+ Sqlite::Value value{variant};
+
+ ASSERT_THAT(value.toFloat(), Eq(1));
+}
+
+TEST(SqliteValue, ConstructStringFromStringQVariant)
+{
+ QVariant variant{QString{"foo"}};
+
+ Sqlite::Value value{variant};
+
+ ASSERT_THAT(value.toStringView(), Eq("foo"));
+}
+
+TEST(SqliteValue, ConvertToStringQVariant)
+{
+ Sqlite::Value value{"foo"};
+
+ auto variant = QVariant{value};
+
+ ASSERT_THAT(variant, Eq("foo"));
+}
+
+TEST(SqliteValue, ConvertToIntegerQVariant)
+{
+ Sqlite::Value value{1};
+
+ auto variant = QVariant{value};
+
+ ASSERT_THAT(variant, Eq(1));
+}
+
+TEST(SqliteValue, ConvertToFloatQVariant)
+{
+ Sqlite::Value value{1.1};
+
+ auto variant = QVariant{value};
+
+ ASSERT_THAT(variant, Eq(1.1));
+}
+
+TEST(SqliteValue, IntegerEquals)
+{
+ bool isEqual = Sqlite::Value{1} == 1LL;
+
+ ASSERT_TRUE(isEqual);
+}
+
+TEST(SqliteValue, IntegerEqualsInverse)
+{
+ bool isEqual = 1LL == Sqlite::Value{1};
+
+ ASSERT_TRUE(isEqual);
+}
+
+TEST(SqliteValue, FloatEquals)
+{
+ bool isEqual = Sqlite::Value{1.0} == 1.;
+
+ ASSERT_TRUE(isEqual);
+}
+
+TEST(SqliteValue, FloatEqualsInverse)
+{
+ bool isEqual = 1. == Sqlite::Value{1.0};
+
+ ASSERT_TRUE(isEqual);
+}
+
+TEST(SqliteValue, StringEquals)
+{
+ bool isEqual = Sqlite::Value{"foo"} == "foo";
+
+ ASSERT_TRUE(isEqual);
+}
+
+TEST(SqliteValue, StringEqualsInverse)
+{
+ bool isEqual = "foo" == Sqlite::Value{"foo"};
+
+ ASSERT_TRUE(isEqual);
+}
+
+TEST(SqliteValue, IntegerAndFloatAreNotEquals)
+{
+ bool isEqual = Sqlite::Value{1} == 1.;
+
+ ASSERT_FALSE(isEqual);
+}
+
+TEST(SqliteValue, IntegerValuesAreEquals)
+{
+ bool isEqual = Sqlite::Value{1} == Sqlite::Value{1};
+
+ ASSERT_TRUE(isEqual);
+}
+
+TEST(SqliteValue, IntegerAndFloatValuesAreNotEquals)
+{
+ bool isEqual = Sqlite::Value{1} == Sqlite::Value{1.};
+
+ ASSERT_FALSE(isEqual);
+}
+
+TEST(SqliteValue, StringAndQStringAreEquals)
+{
+ bool isEqual = Sqlite::Value{"foo"} == QString{"foo"};
+
+ ASSERT_TRUE(isEqual);
+}
+
+TEST(SqliteValue, IntegerAndFloatValuesAreUnequal)
+{
+ bool isUnequal = Sqlite::Value{1} != Sqlite::Value{1.0};
+
+ ASSERT_TRUE(isUnequal);
+}
+
+TEST(SqliteValue, IntegerAndFloatAreUnequal)
+{
+ bool isUnequal = Sqlite::Value{1} != 1.0;
+
+ ASSERT_TRUE(isUnequal);
+}
+
+TEST(SqliteValue, IntegerAndFloatAreUnequalInverse)
+{
+ bool isUnequal = 1.0 != Sqlite::Value{1};
+
+ ASSERT_TRUE(isUnequal);
+}
+
+TEST(SqliteValue, IntegersAreUnequal)
+{
+ bool isUnequal = Sqlite::Value{1} != 2;
+
+ ASSERT_TRUE(isUnequal);
+}
+
+TEST(SqliteValue, IntegersAreUnequalInverse)
+{
+ bool isUnequal = 2 != Sqlite::Value{1};
+
+ ASSERT_TRUE(isUnequal);
+}
+
+TEST(SqliteValue, IntegerType)
+{
+ auto type = Sqlite::Value{1}.type();
+
+ ASSERT_THAT(type, Sqlite::ValueType::Integer);
+}
+
+TEST(SqliteValue, FloatType)
+{
+ auto type = Sqlite::Value{1.}.type();
+
+ ASSERT_THAT(type, Sqlite::ValueType::Float);
+}
+
+TEST(SqliteValue, StringType)
+{
+ auto type = Sqlite::Value{"foo"}.type();
+
+ ASSERT_THAT(type, Sqlite::ValueType::String);
+}
+
+TEST(SqliteValue, StringValueAndValueViewEquals)
+{
+ bool isEqual = Sqlite::ValueView::create("foo") == Sqlite::Value{"foo"};
+
+ ASSERT_TRUE(isEqual);
+}
+
+TEST(SqliteValue, StringValueAndValueViewEqualsInverse)
+{
+ bool isEqual = Sqlite::Value{"foo"} == Sqlite::ValueView::create("foo");
+
+ ASSERT_TRUE(isEqual);
+}
+
+TEST(SqliteValue, IntegerValueAndValueViewEquals)
+{
+ bool isEqual = Sqlite::ValueView::create(1) == Sqlite::Value{1};
+
+ ASSERT_TRUE(isEqual);
+}
+
+TEST(SqliteValue, IntegerValueAndValueViewEqualsInverse)
+{
+ bool isEqual = Sqlite::Value{2} == Sqlite::ValueView::create(2);
+
+ ASSERT_TRUE(isEqual);
+}
+
+TEST(SqliteValue, FloatValueAndValueViewEquals)
+{
+ bool isEqual = Sqlite::ValueView::create(1.1) == Sqlite::Value{1.1};
+
+ ASSERT_TRUE(isEqual);
+}
+
+TEST(SqliteValue, FloatValueAndValueViewEqualsInverse)
+{
+ bool isEqual = Sqlite::Value{1.1} == Sqlite::ValueView::create(1.1);
+
+ ASSERT_TRUE(isEqual);
+}
+
+TEST(SqliteValue, StringValueAndIntergerValueViewAreNotEqual)
+{
+ bool isEqual = Sqlite::Value{"foo"} == Sqlite::ValueView::create(1);
+
+ ASSERT_FALSE(isEqual);
+}
+
+TEST(SqliteValue, ConvertStringValueViewIntoValue)
+{
+ auto view = Sqlite::ValueView::create("foo");
+
+ Sqlite::Value value{view};
+
+ ASSERT_THAT(value, Eq("foo"));
+}
+
+TEST(SqliteValue, ConvertIntegerValueViewIntoValue)
+{
+ auto view = Sqlite::ValueView::create(1);
+
+ Sqlite::Value value{view};
+
+ ASSERT_THAT(value, Eq(1));
+}
+
+TEST(SqliteValue, ConvertFloatValueViewIntoValue)
+{
+ auto view = Sqlite::ValueView::create(1.4);
+
+ Sqlite::Value value{view};
+
+ ASSERT_THAT(value, Eq(1.4));
+}
+
+} // namespace
diff --git a/tests/unit/unittest/translationunitupdater-test.cpp b/tests/unit/unittest/translationunitupdater-test.cpp
index eecc06b8a7..ea71070351 100644
--- a/tests/unit/unittest/translationunitupdater-test.cpp
+++ b/tests/unit/unittest/translationunitupdater-test.cpp
@@ -124,6 +124,7 @@ TEST_F(TranslationUnitUpdaterSlowTest, UpdatesDependentOnFilesOnParse)
void TranslationUnitUpdater::TearDown()
{
+ clang_disposeTranslationUnit(cxTranslationUnit);
clang_disposeIndex(cxIndex);
}
diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro
index 1db48813e8..6155cf3212 100644
--- a/tests/unit/unittest/unittest.pro
+++ b/tests/unit/unittest/unittest.pro
@@ -80,6 +80,7 @@ SOURCES += \
smallstring-test.cpp \
sourcerangefilter-test.cpp \
spydummy.cpp \
+ sqlitevalue-test.cpp \
symbolindexer-test.cpp \
symbolsfindfilter-test.cpp \
stringcache-test.cpp \
@@ -122,7 +123,13 @@ SOURCES += \
headerpathfilter-test.cpp \
toolchainargumentscache-test.cpp \
modifiedtimechecker-test.cpp \
- readexporteddiagnostics-test.cpp
+ sqlitecolumn-test.cpp \
+ sqlitedatabasebackend-test.cpp \
+ sqlitedatabase-test.cpp \
+ sqlitestatement-test.cpp \
+ sqlitetable-test.cpp \
+ sqlstatementbuilder-test.cpp \
+ createtablesqlstatementbuilder-test.cpp
!isEmpty(LIBCLANG_LIBS) {
SOURCES += \
@@ -158,7 +165,6 @@ SOURCES += \
codecompleter-test.cpp \
codecompletionsextractor-test.cpp \
completionchunkstotextconverter-test.cpp \
- createtablesqlstatementbuilder-test.cpp \
cursor-test.cpp \
diagnosticset-test.cpp \
diagnostic-test.cpp \
@@ -168,17 +174,12 @@ SOURCES += \
skippedsourceranges-test.cpp \
sourcelocation-test.cpp \
sourcerange-test.cpp \
- sqlitecolumn-test.cpp \
- sqlitedatabasebackend-test.cpp \
- sqlitedatabase-test.cpp \
- sqlitestatement-test.cpp \
- sqlitetable-test.cpp \
- sqlstatementbuilder-test.cpp \
token-test.cpp \
translationunitupdater-test.cpp \
unsavedfiles-test.cpp \
unsavedfile-test.cpp \
- utf8positionfromlinecolumn-test.cpp
+ utf8positionfromlinecolumn-test.cpp \
+ readexporteddiagnostics-test.cpp
}
!isEmpty(LIBTOOLING_LIBS) {
diff --git a/tests/unit/unittest/unittest.qbs b/tests/unit/unittest/unittest.qbs
new file mode 100644
index 0000000000..4bc1087535
--- /dev/null
+++ b/tests/unit/unittest/unittest.qbs
@@ -0,0 +1,826 @@
+import qbs.File
+import qbs.FileInfo
+
+CppApplication {
+ condition: gtest.present && gmock.present
+ type: base.concat(["autotest", "json_copy"])
+ consoleApplication: true
+ destinationDirectory: FileInfo.joinPaths(project.buildDirectory,
+ FileInfo.relativePath(project.ide_source_tree, sourceDirectory))
+
+ Depends { name: "echoserver" }
+ Depends { name: "pluginjson" }
+ Depends { name: "libclang"; required: false }
+ Depends { name: "clang_defines" }
+
+ Depends { name: "Sqlite" }
+ Depends { name: "Core" }
+ Depends { name: "CPlusPlus" }
+ Depends { name: "yaml-cpp" }
+
+ Depends { name: "Qt"; submodules: ["network", "widgets", "testlib"] }
+
+ Depends { name: "pkgconfig"; required: false }
+ Depends { name: "benchmark"; required: false }
+ Depends { name: "gtest"; required: false }
+ Depends { name: "gmock"; required: false }
+
+ cpp.defines: {
+ var defines = [
+ "QT_NO_CAST_TO_ASCII",
+ "QT_RESTRICTED_CAST_FROM_ASCII",
+ "QT_USE_FAST_OPERATOR_PLUS",
+ "QT_USE_FAST_CONCATENATION",
+ "CLANG_UNIT_TESTS",
+ "UNIT_TESTS",
+ "DONT_CHECK_MESSAGE_COUNTER",
+ 'QTC_RESOURCE_DIR="' + path + "/../../../share/qtcreator" + '"',
+ 'TESTDATA_DIR="' + FileInfo.joinPaths(sourceDirectory, "data") + '"',
+ 'ECHOSERVER="' + FileInfo.joinPaths(project.buildDirectory, "tests", "unit",
+ "echoserver", "echo") + '"',
+ 'RELATIVE_DATA_PATH="' + FileInfo.relativePath(destinationDirectory,
+ FileInfo.joinPaths(project.sourceDirectory, "share", "qtcreator")) + '"',
+ 'CPPTOOLS_JSON="' + FileInfo.joinPaths(destinationDirectory, "CppTools.json") + '"',
+ ];
+ if (libclang.present && libclang.toolingEnabled)
+ defines = defines.concat(libclang.llvmToolingDefines);
+ return defines;
+ }
+ cpp.cxxFlags: {
+ var flags = [];
+ if (qbs.toolchain.contains("msvc"))
+ flags.push("-w34100", "/bigobj", "/wd4267", "/wd4141", "/wd4146");
+ if (qbs.toolchain.contains("gcc") && !qbs.toolchain.contains("clang"))
+ flags.push("-Wno-noexcept-type");
+ if (qbs.toolchain.contains("clang")) {
+ flags.push("-Wno-inconsistent-missing-override", "-Wno-self-move",
+ "-Wno-self-assign-overloaded");
+ flags.push("-Wno-unused-command-line-argument"); // gtest puts -lpthread on compiler command line
+ if (!qbs.hostOS.contains("darwin")
+ && Utilities.versionCompare(cpp.compilerVersion, "10") >= 0) {
+ flags.push("-Wno-deprecated-copy", "-Wno-constant-logical-operand");
+ }
+ }
+ if (qbs.toolchain.contains("gcc"))
+ flags.push("-Wno-unused-parameter");
+ if (libclang.present && libclang.toolingEnabled)
+ flags = flags.concat(libclang.llvmToolingCxxFlags);
+ return flags;
+ }
+ cpp.cxxLanguageVersion: "c++14"
+ cpp.dynamicLibraries: {
+ var libs = [];
+ if (libclang.present) {
+ libs = libs.concat(libclang.llvmLibs);
+ if (libclang.toolingEnabled)
+ libs = libs.concat(libclang.llvmToolingLibs);
+ if (libclang.llvmFormattingLibs.length
+ && (!qbs.targetOS.contains("windows") || libclang.llvmBuildModeMatches)) {
+ libs = libs.concat(libclang.llvmFormattingLibs);
+ }
+ }
+ return libs;
+ }
+ cpp.includePaths: {
+ var paths = [
+ ".",
+ "../mockup",
+ "../../../src/libs",
+ "../../../src/libs/3rdparty",
+ "../../../src/libs/clangsupport",
+ "../../../src/plugins",
+ "../../../src/plugins/clangcodemodel",
+ "../../../src/plugins/clangpchmanager",
+ "../../../src/plugins/clangrefactoring",
+ "../../../src/tools/clangbackend/source",
+ "../../../src/tools/clangpchmanagerbackend/source",
+ "../../../src/tools/clangrefactoringbackend/source",
+ ];
+ if (libclang.present) {
+ paths.push(libclang.llvmIncludeDir);
+ if (libclang.toolingEnabled)
+ paths = paths.concat(libclang.llvmToolingIncludes);
+ }
+ return paths;
+ }
+ cpp.libraryPaths: {
+ var paths = [];
+ if (libclang.present)
+ paths.push(libclang.llvmLibDir);
+ return paths;
+ }
+ cpp.rpaths: {
+ var paths = [
+ FileInfo.joinPaths(project.buildDirectory, qtc.ide_library_path),
+ FileInfo.joinPaths(project.buildDirectory, qtc.ide_plugin_path)
+ ];
+ if (libclang.present)
+ paths.push(libclang.llvmLibDir);
+ return paths;
+ }
+
+ files: [
+ "builddependenciesprovider-test.cpp",
+ "builddependenciesstorage-test.cpp",
+ "clangindexingsettingsmanager-test.cpp",
+ "clangpathwatcher-test.cpp",
+ "clangqueryexamplehighlightmarker-test.cpp",
+ "clangqueryhighlightmarker-test.cpp",
+ "clientserverinprocess-test.cpp",
+ "clientserveroutsideprocess-test.cpp",
+ "commandlinebuilder-test.cpp",
+ "compare-operators.h",
+ "compilationdatabaseutils-test.cpp",
+ "compileroptionsbuilder-test.cpp",
+ "conditionally-disabled-tests.h",
+ "cppprojectfilecategorizer-test.cpp",
+ "cppprojectinfogenerator-test.cpp",
+ "cppprojectpartchooser-test.cpp",
+ "createtablesqlstatementbuilder-test.cpp",
+ "directorypathcompressor-test.cpp",
+ "dummyclangipcclient.h",
+ "dynamicastmatcherdiagnosticcontainer-matcher.h",
+ "eventspy.cpp",
+ "eventspy.h",
+ "fakeprocess.cpp",
+ "fakeprocess.h",
+ "filepath-test.cpp",
+ "filepathcache-test.cpp",
+ "filepathstorage-test.cpp",
+ "filepathstoragesqlitestatementfactory-test.cpp",
+ "filepathview-test.cpp",
+ "filestatuscache-test.cpp",
+ "filesystem-utilities.h",
+ "generatedfiles-test.cpp",
+ "google-using-declarations.h",
+ "googletest.h",
+ "gtest-creator-printing.cpp",
+ "gtest-creator-printing.h",
+ "gtest-llvm-printing.h",
+ "gtest-qt-printing.cpp",
+ "gtest-qt-printing.h",
+ "headerpathfilter-test.cpp",
+ "lineprefixer-test.cpp",
+ "locatorfilter-test.cpp",
+ "matchingtext-test.cpp",
+ "mimedatabase-utilities.cpp",
+ "mimedatabase-utilities.h",
+ "mockbuilddependenciesprovider.h",
+ "mockbuilddependenciesstorage.h",
+ "mockbuilddependencygenerator.h",
+ "mockclangcodemodelclient.h",
+ "mockclangcodemodelserver.h",
+ "mockclangpathwatcher.h",
+ "mockclangpathwatchernotifier.h",
+ "mockcppmodelmanager.h",
+ "mockeditormanager.h",
+ "mockfilepathcaching.h",
+ "mockfilepathstorage.h",
+ "mockfilesystem.h",
+ "mockfutureinterface.h",
+ "mockgeneratedfiles.h",
+ "mockmodifiedtimechecker.h",
+ "mockmutex.h",
+ "mockpchcreator.h",
+ "mockpchmanagerclient.h",
+ "mockpchmanagernotifier.h",
+ "mockpchmanagerserver.h",
+ "mockpchtaskgenerator.h",
+ "mockpchtaskqueue.h",
+ "mockpchtasksmerger.h",
+ "mockprecompiledheaderstorage.h",
+ "mockprocessor.h",
+ "mockprocessormanager.h",
+ "mockprogressmanager.h",
+ "mockprojectpartprovider.h",
+ "mockprojectpartqueue.h",
+ "mockprojectpartsmanager.h",
+ "mockprojectpartsstorage.h",
+ "mockqfilesystemwatcher.h",
+ "mockqueue.h",
+ "mocksearch.h",
+ "mocksearchhandle.h",
+ "mocksearchresult.h",
+ "mocksqlitedatabase.h",
+ "mocksqlitereadstatement.cpp",
+ "mocksqlitereadstatement.h",
+ "mocksqlitestatement.h",
+ "mocksqlitetransactionbackend.h",
+ "mocksqlitewritestatement.h",
+ "mocksymbolindexertaskqueue.h",
+ "mocksymbolindexing.h",
+ "mocksymbolquery.h",
+ "mocksymbolscollector.h",
+ "mocksymbolstorage.h",
+ "mocksyntaxhighligher.h",
+ "mocktaskscheduler.h",
+ "mocktimer.cpp",
+ "mocktimer.h",
+ "modifiedtimechecker-test.cpp",
+ "nativefilepath-test.cpp",
+ "nativefilepathview-test.cpp",
+ "pchmanagerclient-test.cpp",
+ "pchmanagerclientserverinprocess-test.cpp",
+ "pchmanagerserver-test.cpp",
+ "pchtaskgenerator-test.cpp",
+ "pchtaskqueue-test.cpp",
+ "pchtasksmerger-test.cpp",
+ "precompiledheaderstorage-test.cpp",
+ "preprocessormacrocollector-test.cpp",
+ "processcreator-test.cpp",
+ "processevents-utilities.cpp",
+ "processevents-utilities.h",
+ "processormanager-test.cpp",
+ "progresscounter-test.cpp",
+ "projectpartartefact-test.cpp",
+ "projectpartsmanager-test.cpp",
+ "projectpartsstorage-test.cpp",
+ "projectupdater-test.cpp",
+ "readandwritemessageblock-test.cpp",
+ "refactoringdatabaseinitializer-test.cpp",
+ "refactoringprojectupdater-test.cpp",
+ "rundocumentparse-utility.h",
+ "sizedarray-test.cpp",
+ "smallstring-test.cpp",
+ "sourcerangecontainer-matcher.h",
+ "sourcerangefilter-test.cpp",
+ "sourcesmanager-test.cpp",
+ "spydummy.cpp",
+ "spydummy.h",
+ "sqlitecolumn-test.cpp",
+ "sqlitedatabase-test.cpp",
+ "sqlitedatabasebackend-test.cpp",
+ "sqliteindex-test.cpp",
+ "sqlitestatement-test.cpp",
+ "sqlitetable-test.cpp",
+ "sqliteteststatement.h",
+ "sqlitetransaction-test.cpp",
+ "sqlitevalue-test.cpp",
+ "sqlstatementbuilder-test.cpp",
+ "stringcache-test.cpp",
+ "symbolindexer-test.cpp",
+ "symbolindexertaskqueue-test.cpp",
+ "symbolquery-test.cpp",
+ "symbolsfindfilter-test.cpp",
+ "symbolstorage-test.cpp",
+ "task.cpp",
+ "taskscheduler-test.cpp",
+ "testenvironment.h",
+ "toolchainargumentscache-test.cpp",
+ "unittest-utility-functions.h",
+ "unittests-main.cpp",
+ "usedmacrofilter-test.cpp",
+ "utf8-test.cpp",
+ ]
+
+ Group {
+ name: "libclang tests"
+ condition: libclang.present
+ files: [
+ "activationsequencecontextprocessor-test.cpp",
+ "activationsequenceprocessor-test.cpp",
+ "chunksreportedmonitor.cpp",
+ "chunksreportedmonitor.h",
+ "clangasyncjob-base.cpp",
+ "clangasyncjob-base.h",
+ "clangcodecompleteresults-test.cpp",
+ "clangcodemodelserver-test.cpp",
+ "clangcompareoperators.h",
+ "clangcompletecodejob-test.cpp",
+ "clangcompletioncontextanalyzer-test.cpp",
+ "clangdiagnosticfilter-test.cpp",
+ "clangdocument-test.cpp",
+ "clangdocumentprocessor-test.cpp",
+ "clangdocumentprocessors-test.cpp",
+ "clangdocuments-test.cpp",
+ "clangfixitoperation-test.cpp",
+ "clangfollowsymbol-test.cpp",
+ "clangisdiagnosticrelatedtolocation-test.cpp",
+ "clangjobqueue-test.cpp",
+ "clangjobs-test.cpp",
+ "clangparsesupportivetranslationunitjob-test.cpp",
+ "clangrequestannotationsjob-test.cpp",
+ "clangrequestreferencesjob-test.cpp",
+ "clangresumedocumentjob-test.cpp",
+ "clangstring-test.cpp",
+ "clangsupportivetranslationunitinitializer-test.cpp",
+ "clangsuspenddocumentjob-test.cpp",
+ "clangtooltipinfo-test.cpp",
+ "clangtranslationunit-test.cpp",
+ "clangtranslationunits-test.cpp",
+ "clangupdateannotationsjob-test.cpp",
+ "codecompleter-test.cpp",
+ "codecompletionsextractor-test.cpp",
+ "completionchunkstotextconverter-test.cpp",
+ "cursor-test.cpp",
+ "diagnostic-test.cpp",
+ "diagnosticcontainer-matcher.h",
+ "diagnosticset-test.cpp",
+ "fixit-test.cpp",
+ "highlightingresultreporter-test.cpp",
+ "readexporteddiagnostics-test.cpp",
+ "senddocumenttracker-test.cpp",
+ "skippedsourceranges-test.cpp",
+ "sourcelocation-test.cpp",
+ "sourcerange-test.cpp",
+ "token-test.cpp",
+ "translationunitupdater-test.cpp",
+ "unsavedfile-test.cpp",
+ "unsavedfiles-test.cpp",
+ "utf8positionfromlinecolumn-test.cpp",
+ ]
+ }
+
+ Group {
+ name: "clang tooling tests"
+ condition: libclang.present && libclang.toolingEnabled
+ files: [
+ "builddependencycollector-test.cpp",
+ "clangdocumentsuspenderresumer-test.cpp",
+ "clangquery-test.cpp",
+ "clangquerygatherer-test.cpp",
+ "clangqueryprojectfindfilter-test.cpp",
+ "clangreferencescollector-test.cpp",
+ "gtest-clang-printing.cpp",
+ "gtest-clang-printing.h",
+ "gtest-llvm-printing.cpp",
+ "mockrefactoringclient.h",
+ "mockrefactoringserver.h",
+ "pchcreator-test.cpp",
+ "refactoringclient-test.cpp",
+ "refactoringclientserverinprocess-test.cpp",
+ "refactoringcompilationdatabase-test.cpp",
+ "refactoringengine-test.cpp",
+ "refactoringserver-test.cpp",
+ "sourcerangeextractor-test.cpp",
+ "symbolindexing-test.cpp",
+ "symbolscollector-test.cpp",
+ "testclangtool.cpp",
+ "testclangtool.h",
+ "tokenprocessor-test.cpp",
+ "usedmacrocollector-test.cpp",
+ ]
+ }
+
+ Group {
+ name: "ClangFormat tests"
+ condition: libclang.present
+ && libclang.llvmFormattingLibs.length
+ && (!qbs.targetOS.contains("windows") || libclang.llvmBuildModeMatches)
+ files: "clangformat-test.cpp"
+ }
+
+ Group {
+ name: "benchmark test"
+ condition: benchmark.present
+ files: "smallstring-benchmark.cpp"
+ }
+
+ Group {
+ name: "data"
+ files: [
+ "data/*",
+ "data/include/*",
+ ]
+ fileTags: []
+ }
+
+ Group {
+ name: "json.in file"
+ files: "../../../src/plugins/cpptools/CppTools.json.in"
+ fileTags: "pluginJsonIn"
+ }
+
+ Group {
+ name: "sources from pchmanager"
+ prefix: "../../../src/plugins/clangpchmanager/"
+ cpp.defines: outer.concat("CLANGPCHMANAGER_STATIC_LIB")
+ files: [
+ "clangindexingprojectsettings.cpp",
+ "clangindexingprojectsettings.h",
+ "clangindexingsettingsmanager.cpp",
+ "clangindexingsettingsmanager.h",
+ "clangpchmanager_global.h",
+ "pchmanagerclient.cpp",
+ "pchmanagerclient.h",
+ "pchmanagerconnectionclient.cpp",
+ "pchmanagerconnectionclient.h",
+ "pchmanagernotifierinterface.cpp",
+ "pchmanagernotifierinterface.h",
+ "pchmanagerprojectupdater.cpp",
+ "pchmanagerprojectupdater.h",
+ "preprocessormacrocollector.cpp",
+ "preprocessormacrocollector.h",
+ "progressmanager.h",
+ "progressmanagerinterface.h",
+ "projectupdater.cpp",
+ "projectupdater.h",
+ ]
+ }
+
+ Group {
+ name: "sources from pchmanager backend"
+ prefix: "../../../src/tools/clangpchmanagerbackend/source/"
+ files: [
+ "builddependenciesprovider.cpp",
+ "builddependenciesprovider.h",
+ "builddependenciesproviderinterface.h",
+ "builddependenciesstorage.h",
+ "builddependenciesstorageinterface.h",
+ "builddependency.h",
+ "builddependencygeneratorinterface.h",
+ "clangpchmanagerbackend_global.h",
+ "generatepchactionfactory.h",
+ "pchcreatorinterface.h",
+ "pchmanagerserver.cpp",
+ "pchmanagerserver.h",
+ "pchnotcreatederror.h",
+ "pchtask.h",
+ "pchtaskgenerator.cpp",
+ "pchtaskgenerator.h",
+ "pchtaskgeneratorinterface.h",
+ "pchtaskqueue.cpp",
+ "pchtaskqueue.h",
+ "pchtaskqueueinterface.h",
+ "pchtasksmerger.cpp",
+ "pchtasksmerger.h",
+ "pchtasksmergerinterface.h",
+ "precompiledheaderstorage.h",
+ "precompiledheaderstorageinterface.h",
+ "processorinterface.h",
+ "processormanagerinterface.h",
+ "projectpartsmanager.cpp",
+ "projectpartsmanager.h",
+ "projectpartsmanagerinterface.h",
+ "queueinterface.h",
+ "taskscheduler.h",
+ "taskschedulerinterface.h",
+ "toolchainargumentscache.h",
+ "usedmacrofilter.h",
+ ]
+
+ Group {
+ name: "tooling sources from pchmanager backend"
+ condition: libclang.toolingEnabled
+ files: [
+ "builddependencycollector.cpp",
+ "builddependencycollector.h",
+ "collectbuilddependencyaction.h",
+ "collectbuilddependencypreprocessorcallbacks.h",
+ "collectbuilddependencytoolaction.h",
+ "collectusedmacroactionfactory.h",
+ "collectusedmacrosaction.h",
+ "collectusedmacrosandsourcespreprocessorcallbacks.h",
+ "pchcreator.cpp",
+ "pchcreator.h",
+ "processormanager.h",
+ "usedmacrosandsourcescollector.cpp",
+ "usedmacrosandsourcescollector.h",
+ ]
+ }
+ }
+
+ Group {
+ name: "sources from clangrefactoring backend"
+ prefix: "../../../src/tools/clangrefactoringbackend/source/"
+ files: [
+ "clangrefactoringbackend_global.h",
+ "collectmacrospreprocessorcallbacks.h",
+ "projectpartentry.h",
+ "sourcedependency.h",
+ "sourcelocationentry.h",
+ "sourcerangefilter.cpp",
+ "sourcerangefilter.h",
+ "sourcesmanager.h",
+ "symbolentry.h",
+ "symbolindexer.cpp",
+ "symbolindexer.h",
+ "symbolindexertask.h",
+ "symbolindexertaskqueue.h",
+ "symbolindexertaskqueueinterface.h",
+ "symbolindexing.h",
+ "symbolindexinginterface.h",
+ "symbolscollectorinterface.h",
+ "symbolstorage.h",
+ "symbolstorageinterface.h",
+ "usedmacro.h",
+ ]
+
+ Group {
+ name: "tooling sources from clangrefactoring backend"
+ condition: libclang.toolingEnabled
+ files: [
+ "clangquery.cpp",
+ "clangquery.h",
+ "clangquerygatherer.cpp",
+ "clangquerygatherer.h",
+ "clangtool.cpp",
+ "clangtool.h",
+ "collectmacrossourcefilecallbacks.cpp",
+ "collectmacrossourcefilecallbacks.h",
+ "collectsymbolsaction.cpp",
+ "collectsymbolsaction.h",
+ "indexdataconsumer.cpp",
+ "indexdataconsumer.h",
+ "locationsourcefilecallbacks.cpp",
+ "locationsourcefilecallbacks.h",
+ "macropreprocessorcallbacks.cpp",
+ "macropreprocessorcallbacks.h",
+ "refactoringcompilationdatabase.cpp",
+ "refactoringcompilationdatabase.h",
+ "refactoringserver.cpp",
+ "refactoringserver.h",
+ "sourcelocationsutils.h",
+ "sourcerangeextractor.cpp",
+ "sourcerangeextractor.h",
+ "symbolindexing.cpp",
+ "symbolscollector.cpp",
+ "symbolscollector.h",
+ "symbolsvisitorbase.h",
+ ]
+ }
+ }
+
+ Group {
+ name: "sources from clangbackend"
+ condition: libclang.present
+ prefix: "../../../src/tools/clangbackend/source/"
+ files: [
+ "clangasyncjob.h",
+ "clangbackend_global.h",
+ "clangclock.h",
+ "clangcodecompleteresults.cpp",
+ "clangcodecompleteresults.h",
+ "clangcodemodelserver.cpp",
+ "clangcodemodelserver.h",
+ "clangcompletecodejob.cpp",
+ "clangcompletecodejob.h",
+ "clangdocument.cpp",
+ "clangdocument.h",
+ "clangdocumentjob.h",
+ "clangdocumentprocessor.cpp",
+ "clangdocumentprocessor.h",
+ "clangdocumentprocessors.cpp",
+ "clangdocumentprocessors.h",
+ "clangdocuments.cpp",
+ "clangdocuments.h",
+ "clangdocumentsuspenderresumer.cpp",
+ "clangdocumentsuspenderresumer.h",
+ "clangexceptions.cpp",
+ "clangexceptions.h",
+ "clangfilepath.cpp",
+ "clangfilepath.h",
+ "clangfilesystemwatcher.cpp",
+ "clangfilesystemwatcher.h",
+ "clangfollowsymbol.cpp",
+ "clangfollowsymbol.h",
+ "clangfollowsymboljob.cpp",
+ "clangfollowsymboljob.h",
+ "clangiasyncjob.cpp",
+ "clangiasyncjob.h",
+ "clangjobcontext.cpp",
+ "clangjobcontext.h",
+ "clangjobqueue.cpp",
+ "clangjobqueue.h",
+ "clangjobrequest.cpp",
+ "clangjobrequest.h",
+ "clangjobs.cpp",
+ "clangjobs.h",
+ "clangparsesupportivetranslationunitjob.cpp",
+ "clangparsesupportivetranslationunitjob.h",
+ "clangreferencescollector.cpp",
+ "clangreferencescollector.h",
+ "clangrequestannotationsjob.cpp",
+ "clangrequestannotationsjob.h",
+ "clangrequestreferencesjob.cpp",
+ "clangrequestreferencesjob.h",
+ "clangrequesttooltipjob.cpp",
+ "clangrequesttooltipjob.h",
+ "clangresumedocumentjob.cpp",
+ "clangresumedocumentjob.h",
+ "clangstring.h",
+ "clangsupportivetranslationunitinitializer.cpp",
+ "clangsupportivetranslationunitinitializer.h",
+ "clangsuspenddocumentjob.cpp",
+ "clangsuspenddocumentjob.h",
+ "clangtooltipinfocollector.cpp",
+ "clangtooltipinfocollector.h",
+ "clangtranslationunit.cpp",
+ "clangtranslationunit.h",
+ "clangtranslationunits.cpp",
+ "clangtranslationunits.h",
+ "clangtranslationunitupdater.cpp",
+ "clangtranslationunitupdater.h",
+ "clangtype.cpp",
+ "clangtype.h",
+ "clangunsavedfilesshallowarguments.cpp",
+ "clangunsavedfilesshallowarguments.h",
+ "clangupdateannotationsjob.cpp",
+ "clangupdateannotationsjob.h",
+ "clangupdateextraannotationsjob.cpp",
+ "clangupdateextraannotationsjob.h",
+ "codecompleter.cpp",
+ "codecompleter.h",
+ "codecompletionchunkconverter.cpp",
+ "codecompletionchunkconverter.h",
+ "codecompletionsextractor.cpp",
+ "codecompletionsextractor.h",
+ "commandlinearguments.cpp",
+ "commandlinearguments.h",
+ "cursor.cpp",
+ "cursor.h",
+ "diagnostic.cpp",
+ "diagnostic.h",
+ "diagnosticset.cpp",
+ "diagnosticset.h",
+ "diagnosticsetiterator.h",
+ "fixit.cpp",
+ "fixit.h",
+ "fulltokeninfo.cpp",
+ "fulltokeninfo.h",
+ "skippedsourceranges.cpp",
+ "skippedsourceranges.h",
+ "sourcelocation.cpp",
+ "sourcelocation.h",
+ "sourcerange.cpp",
+ "sourcerange.h",
+ "token.cpp",
+ "token.h",
+ "tokeninfo.cpp",
+ "tokeninfo.h",
+ "tokenprocessor.h",
+ "tokenprocessoriterator.h",
+ "unsavedfile.cpp",
+ "unsavedfile.h",
+ "unsavedfiles.cpp",
+ "unsavedfiles.h",
+ "utf8positionfromlinecolumn.cpp",
+ "utf8positionfromlinecolumn.h",
+ ]
+ }
+
+ Group {
+ name: "sources from clangsupport"
+ prefix: "../../../src/libs/clangsupport/"
+ cpp.defines: outer.concat("CLANGSUPPORT_STATIC_LIB")
+ files: [
+ "*.cpp",
+ "*.h",
+ ]
+ }
+
+ Group {
+ name: "sources from clangcodemodel"
+ prefix: "../../../src/plugins/clangcodemodel/"
+ files: [
+ "clangactivationsequencecontextprocessor.cpp",
+ "clangactivationsequencecontextprocessor.h",
+ "clangactivationsequenceprocessor.cpp",
+ "clangactivationsequenceprocessor.h",
+ "clangcompletionchunkstotextconverter.cpp",
+ "clangcompletionchunkstotextconverter.h",
+ "clangcompletioncontextanalyzer.cpp",
+ "clangcompletioncontextanalyzer.h",
+ "clangdiagnosticfilter.cpp",
+ "clangdiagnosticfilter.h",
+ "clangfixitoperation.cpp",
+ "clangfixitoperation.h",
+ "clanghighlightingresultreporter.cpp",
+ "clanghighlightingresultreporter.h",
+ "clangisdiagnosticrelatedtolocation.h",
+ "clanguiheaderondiskmanager.cpp",
+ "clanguiheaderondiskmanager.h",
+ ]
+ }
+
+ Group {
+ name: "sources from cpptools"
+ prefix: "../../../src/plugins/cpptools/"
+ cpp.defines: outer.concat("CPPTOOLS_STATIC_LIBRARY")
+ files: [
+ "compileroptionsbuilder.cpp",
+ "compileroptionsbuilder.h",
+ "cppprojectfile.cpp",
+ "cppprojectfile.h",
+ "cppprojectfilecategorizer.cpp",
+ "cppprojectfilecategorizer.h",
+ "cppprojectinfogenerator.cpp",
+ "cppprojectpartchooser.cpp",
+ "cppprojectpartchooser.h",
+ "headerpathfilter.cpp",
+ "headerpathfilter.h",
+ "projectinfo.cpp",
+ "projectinfo.h",
+ "projectpart.cpp",
+ "projectpart.h",
+ "senddocumenttracker.cpp",
+ "senddocumenttracker.h",
+ ]
+ }
+
+ Group {
+ name: "sources from clangtools"
+ condition: libclang.present
+ prefix: "../../../src/plugins/clangtools/"
+ cpp.defines: outer.concat("CLANGTOOLS_STATIC_LIBRARY")
+ files: [
+ "clangtoolsdiagnostic.cpp",
+ "clangtoolsdiagnostic.h",
+ "clangtoolslogfilereader.cpp",
+ "clangtoolslogfilereader.h",
+ ]
+ }
+
+ Group {
+ name: "sources from clangdbpm"
+ prefix: "../../../src/plugins/compilationdatabaseprojectmanager/"
+ files: [
+ "compilationdatabaseutils.cpp",
+ "compilationdatabaseutils.h",
+ ]
+ }
+
+ Group {
+ name: "sources from ProjectExplorer"
+ prefix: "../../../src/plugins/projectexplorer/"
+ cpp.defines: base.concat("PROJECTEXPLORER_STATIC_LIBRARY")
+ files: [
+ "projectmacro.cpp",
+ "projectmacro.h",
+ ]
+ }
+
+ Group {
+ name: "sources from ClangRefactoring"
+ prefix: "../../../src/plugins/clangrefactoring/"
+ files: [
+ "clangqueryexamplehighlighter.cpp",
+ "clangqueryexamplehighlighter.h",
+ "clangqueryexamplehighlightmarker.h",
+ "clangqueryhighlighter.cpp",
+ "clangqueryhighlighter.h",
+ "clangqueryhighlightmarker.h",
+ "clangqueryprojectsfindfilter.cpp",
+ "clangqueryprojectsfindfilter.h",
+ "editormanagerinterface.h",
+ "locatorfilter.cpp",
+ "locatorfilter.h",
+ "projectpartproviderinterface.h",
+ "projectpartutilities.cpp",
+ "projectpartutilities.h",
+ "refactoringclient.cpp",
+ "refactoringclient.h",
+ "refactoringconnectionclient.cpp",
+ "refactoringconnectionclient.h",
+ "refactoringengine.cpp",
+ "refactoringengine.h",
+ "refactoringprojectupdater.cpp",
+ "refactoringprojectupdater.h",
+ "searchhandle.cpp",
+ "searchhandle.h",
+ "searchinterface.h",
+ "symbol.h",
+ "symbolqueryinterface.h",
+ "symbolsfindfilter.cpp",
+ "symbolsfindfilter.h",
+ ]
+ }
+
+ Group {
+ name: "sources from ClangFormat"
+ prefix: "../../../src/plugins/clangformat/"
+ condition: libclang.present
+ && libclang.llvmFormattingLibs.length
+ && (!qbs.targetOS.contains("windows") || libclang.llvmBuildModeMatches)
+ files: [
+ "clangformatbaseindenter.cpp",
+ "clangformatbaseindenter.h",
+ "clangformatconstants.h",
+ ]
+ }
+
+ Group {
+ name: "sources from Debugger"
+ prefix: "../../../src/plugins/debugger/analyzer/"
+ cpp.defines: outer.concat("DEBUGGER_STATIC_LIBRARY")
+ files: [
+ "diagnosticlocation.cpp",
+ "diagnosticlocation.h",
+ ]
+ }
+
+ Rule {
+ inputs: "qt_plugin_metadata"
+ Artifact {
+ filePath: FileInfo.joinPaths(product.destinationDirectory, "CppTools.json")
+ fileTags: "json_copy"
+ }
+ prepare: {
+ var cmd = new JavaScriptCommand;
+ cmd.description = "copying " + input.fileName;
+ cmd.sourceCode = function() { File.copy(input.filePath, output.filePath); };
+ return cmd;
+ }
+ }
+
+}