aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/projectexplorer
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/projectexplorer')
-rw-r--r--src/plugins/projectexplorer/CMakeLists.txt215
-rw-r--r--src/plugins/projectexplorer/abi.cpp50
-rw-r--r--src/plugins/projectexplorer/abi.h10
-rw-r--r--src/plugins/projectexplorer/abiwidget.cpp22
-rw-r--r--src/plugins/projectexplorer/abiwidget.h7
-rw-r--r--src/plugins/projectexplorer/abstractprocessstep.cpp103
-rw-r--r--src/plugins/projectexplorer/abstractprocessstep.h7
-rw-r--r--src/plugins/projectexplorer/addrunconfigdialog.cpp192
-rw-r--r--src/plugins/projectexplorer/addrunconfigdialog.h (renamed from src/plugins/projectexplorer/kitconfigwidget.cpp)56
-rw-r--r--src/plugins/projectexplorer/allprojectsfilter.cpp2
-rw-r--r--src/plugins/projectexplorer/allprojectsfind.cpp2
-rw-r--r--src/plugins/projectexplorer/ansifilterparser.cpp2
-rw-r--r--src/plugins/projectexplorer/applicationlauncher.cpp11
-rw-r--r--src/plugins/projectexplorer/appoutputpane.cpp343
-rw-r--r--src/plugins/projectexplorer/appoutputpane.h43
-rw-r--r--src/plugins/projectexplorer/baseprojectwizarddialog.cpp2
-rw-r--r--src/plugins/projectexplorer/buildconfiguration.cpp114
-rw-r--r--src/plugins/projectexplorer/buildconfiguration.h35
-rw-r--r--src/plugins/projectexplorer/buildenvironmentwidget.cpp3
-rw-r--r--src/plugins/projectexplorer/buildinfo.h2
-rw-r--r--src/plugins/projectexplorer/buildmanager.cpp29
-rw-r--r--src/plugins/projectexplorer/buildmanager.h4
-rw-r--r--src/plugins/projectexplorer/buildsettingspropertiespage.cpp2
-rw-r--r--src/plugins/projectexplorer/buildstep.cpp8
-rw-r--r--src/plugins/projectexplorer/buildstep.h7
-rw-r--r--src/plugins/projectexplorer/buildstepspage.cpp15
-rw-r--r--src/plugins/projectexplorer/buildtargetinfo.h29
-rw-r--r--src/plugins/projectexplorer/clangparser.cpp52
-rw-r--r--src/plugins/projectexplorer/codestylesettingspropertiespage.cpp2
-rw-r--r--src/plugins/projectexplorer/compileoutputwindow.cpp198
-rw-r--r--src/plugins/projectexplorer/compileoutputwindow.h31
-rw-r--r--src/plugins/projectexplorer/currentprojectfilter.cpp2
-rw-r--r--src/plugins/projectexplorer/currentprojectfind.cpp2
-rw-r--r--src/plugins/projectexplorer/customexecutablerunconfiguration.cpp18
-rw-r--r--src/plugins/projectexplorer/customparser.cpp56
-rw-r--r--src/plugins/projectexplorer/customparser.h2
-rw-r--r--src/plugins/projectexplorer/customparserconfigdialog.cpp12
-rw-r--r--src/plugins/projectexplorer/customtoolchain.cpp95
-rw-r--r--src/plugins/projectexplorer/customtoolchain.h34
-rw-r--r--src/plugins/projectexplorer/customwizard/customwizard.cpp4
-rw-r--r--src/plugins/projectexplorer/deployablefile.cpp4
-rw-r--r--src/plugins/projectexplorer/deployablefile.h6
-rw-r--r--src/plugins/projectexplorer/deployconfiguration.cpp2
-rw-r--r--src/plugins/projectexplorer/deploymentdata.cpp2
-rw-r--r--src/plugins/projectexplorer/deploymentdata.h18
-rw-r--r--src/plugins/projectexplorer/devicesupport/desktopdevice.cpp14
-rw-r--r--src/plugins/projectexplorer/devicesupport/desktopdevice.h3
-rw-r--r--src/plugins/projectexplorer/devicesupport/desktopdeviceprocess.cpp2
-rw-r--r--src/plugins/projectexplorer/devicesupport/devicecheckbuildstep.cpp6
-rw-r--r--src/plugins/projectexplorer/devicesupport/devicemanager.cpp21
-rw-r--r--src/plugins/projectexplorer/devicesupport/devicemanager.h6
-rw-r--r--src/plugins/projectexplorer/devicesupport/deviceprocess.h1
-rw-r--r--src/plugins/projectexplorer/devicesupport/deviceprocessesdialog.cpp16
-rw-r--r--src/plugins/projectexplorer/devicesupport/deviceprocesslist.cpp103
-rw-r--r--src/plugins/projectexplorer/devicesupport/deviceprocesslist.h14
-rw-r--r--src/plugins/projectexplorer/devicesupport/devicesettingswidget.cpp2
-rw-r--r--src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.h2
-rw-r--r--src/plugins/projectexplorer/devicesupport/idevice.cpp34
-rw-r--r--src/plugins/projectexplorer/devicesupport/idevice.h15
-rw-r--r--src/plugins/projectexplorer/devicesupport/localprocesslist.cpp15
-rw-r--r--src/plugins/projectexplorer/devicesupport/localprocesslist.h3
-rw-r--r--src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp10
-rw-r--r--src/plugins/projectexplorer/devicesupport/sshdeviceprocesslist.cpp2
-rw-r--r--src/plugins/projectexplorer/devicesupport/sshsettingspage.cpp4
-rw-r--r--src/plugins/projectexplorer/editorconfiguration.cpp2
-rw-r--r--src/plugins/projectexplorer/editorsettingspropertiespage.cpp4
-rw-r--r--src/plugins/projectexplorer/environmentaspect.cpp68
-rw-r--r--src/plugins/projectexplorer/environmentaspect.h43
-rw-r--r--src/plugins/projectexplorer/environmentaspectwidget.cpp38
-rw-r--r--src/plugins/projectexplorer/environmentaspectwidget.h1
-rw-r--r--src/plugins/projectexplorer/environmentwidget.cpp119
-rw-r--r--src/plugins/projectexplorer/environmentwidget.h15
-rw-r--r--src/plugins/projectexplorer/extraabi.cpp2
-rw-r--r--src/plugins/projectexplorer/extracompiler.cpp48
-rw-r--r--src/plugins/projectexplorer/extracompiler.h48
-rw-r--r--src/plugins/projectexplorer/fileinsessionfinder.cpp89
-rw-r--r--src/plugins/projectexplorer/fileinsessionfinder.h36
-rw-r--r--src/plugins/projectexplorer/filterkitaspectsdialog.cpp163
-rw-r--r--src/plugins/projectexplorer/filterkitaspectsdialog.h (renamed from src/plugins/projectexplorer/kitconfigwidget.h)54
-rw-r--r--src/plugins/projectexplorer/foldernavigationwidget.cpp70
-rw-r--r--src/plugins/projectexplorer/foldernavigationwidget.h12
-rw-r--r--src/plugins/projectexplorer/gccparser.cpp278
-rw-r--r--src/plugins/projectexplorer/gcctoolchain.cpp707
-rw-r--r--src/plugins/projectexplorer/gcctoolchain.h86
-rw-r--r--src/plugins/projectexplorer/gcctoolchainfactories.h57
-rw-r--r--src/plugins/projectexplorer/gnumakeparser.cpp88
-rw-r--r--src/plugins/projectexplorer/images/fileoverlay_py.pngbin0 -> 304 bytes
-rw-r--r--src/plugins/projectexplorer/images/fileoverlay_py@2x.pngbin0 -> 533 bytes
-rw-r--r--src/plugins/projectexplorer/importwidget.cpp18
-rw-r--r--src/plugins/projectexplorer/importwidget.h8
-rw-r--r--src/plugins/projectexplorer/ioutputparser.cpp5
-rw-r--r--src/plugins/projectexplorer/ioutputparser.h1
-rw-r--r--src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp15
-rw-r--r--src/plugins/projectexplorer/jsonwizard/jsonkitspage.cpp2
-rw-r--r--src/plugins/projectexplorer/jsonwizard/jsonprojectpage.cpp2
-rw-r--r--src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp135
-rw-r--r--src/plugins/projectexplorer/jsonwizard/jsonwizard.h19
-rw-r--r--src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp58
-rw-r--r--src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.h25
-rw-r--r--src/plugins/projectexplorer/jsonwizard/jsonwizardfilegenerator.cpp4
-rw-r--r--src/plugins/projectexplorer/jsonwizard/jsonwizardgeneratorfactory.cpp2
-rw-r--r--src/plugins/projectexplorer/jsonwizard/jsonwizardscannergenerator.cpp25
-rw-r--r--src/plugins/projectexplorer/jsonwizard/jsonwizardscannergenerator.h2
-rw-r--r--src/plugins/projectexplorer/kit.cpp188
-rw-r--r--src/plugins/projectexplorer/kit.h27
-rw-r--r--src/plugins/projectexplorer/kitchooser.cpp19
-rw-r--r--src/plugins/projectexplorer/kitchooser.h3
-rw-r--r--src/plugins/projectexplorer/kitinformation.cpp760
-rw-r--r--src/plugins/projectexplorer/kitinformation.h67
-rw-r--r--src/plugins/projectexplorer/kitinformationconfigwidget.cpp529
-rw-r--r--src/plugins/projectexplorer/kitinformationconfigwidget.h196
-rw-r--r--src/plugins/projectexplorer/kitmanager.cpp299
-rw-r--r--src/plugins/projectexplorer/kitmanager.h105
-rw-r--r--src/plugins/projectexplorer/kitmanagerconfigwidget.cpp150
-rw-r--r--src/plugins/projectexplorer/kitmanagerconfigwidget.h12
-rw-r--r--src/plugins/projectexplorer/kitmodel.cpp92
-rw-r--r--src/plugins/projectexplorer/kitmodel.h5
-rw-r--r--src/plugins/projectexplorer/kitoptionspage.cpp34
-rw-r--r--src/plugins/projectexplorer/ldparser.cpp10
-rw-r--r--src/plugins/projectexplorer/linuxiccparser.cpp32
-rw-r--r--src/plugins/projectexplorer/localenvironmentaspect.cpp59
-rw-r--r--src/plugins/projectexplorer/localenvironmentaspect.h9
-rw-r--r--src/plugins/projectexplorer/makestep.cpp46
-rw-r--r--src/plugins/projectexplorer/makestep.h16
-rw-r--r--src/plugins/projectexplorer/miniprojecttargetselector.cpp34
-rw-r--r--src/plugins/projectexplorer/miniprojecttargetselector.h4
-rw-r--r--src/plugins/projectexplorer/msvcparser.cpp126
-rw-r--r--src/plugins/projectexplorer/msvctoolchain.cpp593
-rw-r--r--src/plugins/projectexplorer/msvctoolchain.h83
-rw-r--r--src/plugins/projectexplorer/namedwidget.h4
-rw-r--r--src/plugins/projectexplorer/osparser.cpp4
-rw-r--r--src/plugins/projectexplorer/outputparser_test.cpp4
-rw-r--r--src/plugins/projectexplorer/outputparser_test.h4
-rw-r--r--src/plugins/projectexplorer/parseissuesdialog.cpp171
-rw-r--r--src/plugins/projectexplorer/parseissuesdialog.h48
-rw-r--r--src/plugins/projectexplorer/processparameters.cpp40
-rw-r--r--src/plugins/projectexplorer/processparameters.h28
-rw-r--r--src/plugins/projectexplorer/processstep.cpp206
-rw-r--r--src/plugins/projectexplorer/processstep.h42
-rw-r--r--src/plugins/projectexplorer/processstep.ui62
-rw-r--r--src/plugins/projectexplorer/project.cpp117
-rw-r--r--src/plugins/projectexplorer/project.h28
-rw-r--r--src/plugins/projectexplorer/projectconfiguration.cpp23
-rw-r--r--src/plugins/projectexplorer/projectconfiguration.h27
-rw-r--r--src/plugins/projectexplorer/projectconfigurationaspects.cpp50
-rw-r--r--src/plugins/projectexplorer/projectconfigurationaspects.h12
-rw-r--r--src/plugins/projectexplorer/projectexplorer.cpp436
-rw-r--r--src/plugins/projectexplorer/projectexplorer.h15
-rw-r--r--src/plugins/projectexplorer/projectexplorer.pro26
-rw-r--r--src/plugins/projectexplorer/projectexplorer.qbs10
-rw-r--r--src/plugins/projectexplorer/projectexplorer.qrc2
-rw-r--r--src/plugins/projectexplorer/projectexplorerconstants.h4
-rw-r--r--src/plugins/projectexplorer/projectexplorersettings.h43
-rw-r--r--src/plugins/projectexplorer/projectexplorersettingspage.cpp35
-rw-r--r--src/plugins/projectexplorer/projectexplorersettingspage.ui292
-rw-r--r--src/plugins/projectexplorer/projectfilewizardextension.cpp2
-rw-r--r--src/plugins/projectexplorer/projectimporter.cpp68
-rw-r--r--src/plugins/projectexplorer/projectimporter.h17
-rw-r--r--src/plugins/projectexplorer/projectmanager.h8
-rw-r--r--src/plugins/projectexplorer/projectmodels.cpp321
-rw-r--r--src/plugins/projectexplorer/projectmodels.h6
-rw-r--r--src/plugins/projectexplorer/projectnodes.cpp143
-rw-r--r--src/plugins/projectexplorer/projectnodes.h115
-rw-r--r--src/plugins/projectexplorer/projecttree.cpp56
-rw-r--r--src/plugins/projectexplorer/projecttree.h10
-rw-r--r--src/plugins/projectexplorer/projecttreewidget.cpp33
-rw-r--r--src/plugins/projectexplorer/projecttreewidget.h6
-rw-r--r--src/plugins/projectexplorer/projectwelcomepage.cpp7
-rw-r--r--src/plugins/projectexplorer/projectwindow.cpp4
-rw-r--r--src/plugins/projectexplorer/projectwizardpage.cpp10
-rw-r--r--src/plugins/projectexplorer/runconfiguration.cpp1493
-rw-r--r--src/plugins/projectexplorer/runconfiguration.h271
-rw-r--r--src/plugins/projectexplorer/runconfigurationaspects.cpp66
-rw-r--r--src/plugins/projectexplorer/runconfigurationaspects.h26
-rw-r--r--src/plugins/projectexplorer/runcontrol.cpp1563
-rw-r--r--src/plugins/projectexplorer/runcontrol.h346
-rw-r--r--src/plugins/projectexplorer/runsettingspropertiespage.cpp47
-rw-r--r--src/plugins/projectexplorer/runsettingspropertiespage.h3
-rw-r--r--src/plugins/projectexplorer/selectablefilesmodel.cpp61
-rw-r--r--src/plugins/projectexplorer/selectablefilesmodel.h45
-rw-r--r--src/plugins/projectexplorer/session.cpp105
-rw-r--r--src/plugins/projectexplorer/session.h7
-rw-r--r--src/plugins/projectexplorer/sessiondialog.cpp24
-rw-r--r--src/plugins/projectexplorer/sessiondialog.h2
-rw-r--r--src/plugins/projectexplorer/sessionmodel.cpp8
-rw-r--r--src/plugins/projectexplorer/sessionmodel.h4
-rw-r--r--src/plugins/projectexplorer/sessionview.cpp41
-rw-r--r--src/plugins/projectexplorer/sessionview.h13
-rw-r--r--src/plugins/projectexplorer/target.cpp24
-rw-r--r--src/plugins/projectexplorer/target.h15
-rw-r--r--src/plugins/projectexplorer/targetsettingspanel.cpp89
-rw-r--r--src/plugins/projectexplorer/targetsetuppage.cpp15
-rw-r--r--src/plugins/projectexplorer/targetsetuppage.h5
-rw-r--r--src/plugins/projectexplorer/targetsetupwidget.cpp5
-rw-r--r--src/plugins/projectexplorer/task.cpp29
-rw-r--r--src/plugins/projectexplorer/task.h12
-rw-r--r--src/plugins/projectexplorer/taskhub.cpp10
-rw-r--r--src/plugins/projectexplorer/taskhub.h2
-rw-r--r--src/plugins/projectexplorer/taskmodel.cpp212
-rw-r--r--src/plugins/projectexplorer/taskmodel.h50
-rw-r--r--src/plugins/projectexplorer/taskwindow.cpp32
-rw-r--r--src/plugins/projectexplorer/taskwindow.h2
-rw-r--r--src/plugins/projectexplorer/toolchain.cpp151
-rw-r--r--src/plugins/projectexplorer/toolchain.h81
-rw-r--r--src/plugins/projectexplorer/toolchainmanager.cpp22
-rw-r--r--src/plugins/projectexplorer/toolchainmanager.h13
-rw-r--r--src/plugins/projectexplorer/toolchainoptionspage.cpp165
-rw-r--r--src/plugins/projectexplorer/toolchainsettingsaccessor.cpp123
-rw-r--r--src/plugins/projectexplorer/treescanner.cpp176
-rw-r--r--src/plugins/projectexplorer/treescanner.h101
-rw-r--r--src/plugins/projectexplorer/userfileaccessor.cpp67
-rw-r--r--src/plugins/projectexplorer/userfileaccessor.h6
-rw-r--r--src/plugins/projectexplorer/waitforstopdialog.h2
-rw-r--r--src/plugins/projectexplorer/xcodebuildparser.cpp38
214 files changed, 9430 insertions, 6656 deletions
diff --git a/src/plugins/projectexplorer/CMakeLists.txt b/src/plugins/projectexplorer/CMakeLists.txt
new file mode 100644
index 0000000000..c9413c2385
--- /dev/null
+++ b/src/plugins/projectexplorer/CMakeLists.txt
@@ -0,0 +1,215 @@
+add_qtc_plugin(ProjectExplorer
+ DEPENDS QtcSsh Qt5::Qml
+ PLUGIN_DEPENDS Core TextEditor
+ SOURCES
+ abi.cpp abi.h
+ abiwidget.cpp abiwidget.h
+ abstractprocessstep.cpp abstractprocessstep.h
+ 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
+ buildconfiguration.cpp buildconfiguration.h
+ buildenvironmentwidget.cpp buildenvironmentwidget.h
+ buildinfo.cpp buildinfo.h
+ buildmanager.cpp buildmanager.h
+ buildprogress.cpp buildprogress.h
+ buildsettingspropertiespage.cpp buildsettingspropertiespage.h
+ buildstep.cpp buildstep.h
+ buildsteplist.cpp buildsteplist.h
+ buildstepspage.cpp buildstepspage.h
+ buildtargetinfo.h
+ clangparser.cpp clangparser.h
+ codestylesettingspropertiespage.cpp codestylesettingspropertiespage.h codestylesettingspropertiespage.ui
+ compileoutputwindow.cpp compileoutputwindow.h
+ configtaskhandler.cpp configtaskhandler.h
+ copytaskhandler.cpp copytaskhandler.h
+ currentprojectfilter.cpp currentprojectfilter.h
+ currentprojectfind.cpp currentprojectfind.h
+ customexecutablerunconfiguration.cpp customexecutablerunconfiguration.h
+ customparser.cpp customparser.h
+ customparserconfigdialog.cpp customparserconfigdialog.h customparserconfigdialog.ui
+ customtoolchain.cpp customtoolchain.h
+ customwizard/customwizard.cpp customwizard/customwizard.h
+ customwizard/customwizardpage.cpp customwizard/customwizardpage.h
+ customwizard/customwizardparameters.cpp customwizard/customwizardparameters.h
+ customwizard/customwizardscriptgenerator.cpp customwizard/customwizardscriptgenerator.h
+ dependenciespanel.cpp dependenciespanel.h
+ deployablefile.cpp deployablefile.h
+ deployconfiguration.cpp deployconfiguration.h
+ deploymentdata.cpp deploymentdata.h
+ deploymentdatamodel.cpp deploymentdatamodel.h
+ deploymentdataview.cpp deploymentdataview.h deploymentdataview.ui
+ devicesupport/desktopdevice.cpp devicesupport/desktopdevice.h
+ devicesupport/desktopdeviceconfigurationwidget.cpp devicesupport/desktopdeviceconfigurationwidget.h devicesupport/desktopdeviceconfigurationwidget.ui
+ devicesupport/desktopdevicefactory.cpp devicesupport/desktopdevicefactory.h
+ devicesupport/desktopdeviceprocess.cpp devicesupport/desktopdeviceprocess.h
+ devicesupport/desktopprocesssignaloperation.cpp devicesupport/desktopprocesssignaloperation.h
+ devicesupport/devicecheckbuildstep.cpp devicesupport/devicecheckbuildstep.h
+ devicesupport/devicefactoryselectiondialog.cpp devicesupport/devicefactoryselectiondialog.h devicesupport/devicefactoryselectiondialog.ui
+ devicesupport/devicemanager.cpp devicesupport/devicemanager.h
+ devicesupport/devicemanagermodel.cpp devicesupport/devicemanagermodel.h
+ devicesupport/deviceprocess.cpp devicesupport/deviceprocess.h
+ devicesupport/deviceprocessesdialog.cpp devicesupport/deviceprocessesdialog.h
+ devicesupport/deviceprocesslist.cpp devicesupport/deviceprocesslist.h
+ devicesupport/devicesettingspage.cpp devicesupport/devicesettingspage.h
+ devicesupport/devicesettingswidget.cpp devicesupport/devicesettingswidget.h devicesupport/devicesettingswidget.ui
+ devicesupport/devicetestdialog.cpp devicesupport/devicetestdialog.h devicesupport/devicetestdialog.ui
+ devicesupport/deviceusedportsgatherer.cpp devicesupport/deviceusedportsgatherer.h
+ devicesupport/idevice.cpp devicesupport/idevice.h
+ devicesupport/idevicefactory.cpp devicesupport/idevicefactory.h
+ devicesupport/idevicewidget.h
+ devicesupport/localprocesslist.cpp devicesupport/localprocesslist.h
+ devicesupport/sshdeviceprocess.cpp devicesupport/sshdeviceprocess.h
+ devicesupport/sshdeviceprocess.cpp devicesupport/sshdeviceprocess.h
+ devicesupport/sshdeviceprocesslist.cpp devicesupport/sshdeviceprocesslist.h
+ devicesupport/sshsettingspage.cpp devicesupport/sshsettingspage.h
+ editorconfiguration.cpp editorconfiguration.h
+ editorsettingspropertiespage.cpp editorsettingspropertiespage.h editorsettingspropertiespage.ui
+ environmentaspect.cpp environmentaspect.h
+ environmentaspectwidget.cpp environmentaspectwidget.h
+ environmentwidget.cpp environmentwidget.h
+ expanddata.cpp expanddata.h
+ extraabi.cpp extraabi.h
+ extracompiler.cpp extracompiler.h
+ fileinsessionfinder.cpp fileinsessionfinder.h
+ filterkitaspectsdialog.cpp filterkitaspectsdialog.h
+ foldernavigationwidget.cpp foldernavigationwidget.h
+ gccparser.cpp gccparser.h
+ gcctoolchain.cpp gcctoolchain.h
+ gcctoolchainfactories.h
+ gnumakeparser.cpp gnumakeparser.h
+ headerpath.h
+ importwidget.cpp importwidget.h
+ ioutputparser.cpp ioutputparser.h
+ ipotentialkit.h
+ itaskhandler.h
+ jsonwizard/jsonfieldpage.cpp jsonwizard/jsonfieldpage.h jsonwizard/jsonfieldpage_p.h
+ jsonwizard/jsonfilepage.cpp jsonwizard/jsonfilepage.h
+ jsonwizard/jsonkitspage.cpp jsonwizard/jsonkitspage.h
+ jsonwizard/jsonprojectpage.cpp jsonwizard/jsonprojectpage.h
+ jsonwizard/jsonsummarypage.cpp jsonwizard/jsonsummarypage.h
+ jsonwizard/jsonwizard.cpp jsonwizard/jsonwizard.h
+ jsonwizard/jsonwizardfactory.cpp jsonwizard/jsonwizardfactory.h
+ jsonwizard/jsonwizardfilegenerator.cpp jsonwizard/jsonwizardfilegenerator.h
+ jsonwizard/jsonwizardgeneratorfactory.cpp jsonwizard/jsonwizardgeneratorfactory.h
+ jsonwizard/jsonwizardpagefactory.cpp jsonwizard/jsonwizardpagefactory.h
+ jsonwizard/jsonwizardpagefactory_p.cpp
+ jsonwizard/jsonwizardpagefactory_p.h
+ jsonwizard/jsonwizardscannergenerator.cpp jsonwizard/jsonwizardscannergenerator.h
+ kit.cpp kit.h
+ kitchooser.cpp kitchooser.h
+ kitfeatureprovider.h
+ kitinformation.cpp kitinformation.h
+ kitmanager.cpp kitmanager.h
+ kitmanagerconfigwidget.cpp kitmanagerconfigwidget.h
+ kitmodel.cpp kitmodel.h
+ kitoptionspage.cpp kitoptionspage.h
+ ldparser.cpp ldparser.h
+ linuxiccparser.cpp linuxiccparser.h
+ localenvironmentaspect.cpp localenvironmentaspect.h
+ makestep.cpp makestep.h makestep.ui
+ miniprojecttargetselector.cpp miniprojecttargetselector.h
+ msvcparser.cpp msvcparser.h
+ msvctoolchain.cpp msvctoolchain.h
+ namedwidget.cpp namedwidget.h
+ osparser.cpp osparser.h
+ panelswidget.cpp panelswidget.h
+ parseissuesdialog.cpp parseissuesdialog.h
+ processparameters.cpp processparameters.h
+ processstep.cpp processstep.h
+ project.cpp project.h
+ projectconfiguration.cpp projectconfiguration.h
+ projectconfigurationaspects.cpp projectconfigurationaspects.h
+ projectconfigurationmodel.cpp projectconfigurationmodel.h
+ projectexplorer.cpp projectexplorer.h
+ projectexplorer.qrc
+ projectexplorer_export.h
+ projectexplorer_global.h
+ projectexplorerconstants.h
+ projectexplorericons.cpp projectexplorericons.h
+ projectexplorersettings.h
+ projectexplorersettingspage.cpp projectexplorersettingspage.h projectexplorersettingspage.ui
+ projectfilewizardextension.cpp projectfilewizardextension.h
+ projectimporter.cpp projectimporter.h
+ projectmacro.cpp projectmacro.h
+ projectmacroexpander.cpp projectmacroexpander.h
+ projectmanager.h
+ projectmodels.cpp projectmodels.h
+ projectnodes.cpp projectnodes.h
+ projectpanelfactory.cpp projectpanelfactory.h
+ projecttree.cpp projecttree.h
+ projecttreewidget.cpp projecttreewidget.h
+ projectwelcomepage.cpp projectwelcomepage.h
+ projectwindow.cpp projectwindow.h
+ projectwizardpage.cpp projectwizardpage.h projectwizardpage.ui
+ removetaskhandler.cpp removetaskhandler.h
+ runconfiguration.cpp runconfiguration.h
+ runconfigurationaspects.cpp runconfigurationaspects.h
+ runcontrol.cpp runcontrol.h
+ runsettingspropertiespage.cpp runsettingspropertiespage.h
+ selectablefilesmodel.cpp selectablefilesmodel.h
+ session.cpp session.h
+ sessiondialog.cpp sessiondialog.h sessiondialog.ui
+ sessionmodel.cpp sessionmodel.h
+ sessionview.cpp sessionview.h
+ showineditortaskhandler.cpp showineditortaskhandler.h
+ showoutputtaskhandler.cpp showoutputtaskhandler.h
+ subscription.cpp subscription.h
+ target.cpp target.h
+ targetsettingspanel.cpp targetsettingspanel.h
+ targetsetuppage.cpp targetsetuppage.h
+ targetsetupwidget.cpp targetsetupwidget.h
+ task.cpp task.h
+ taskhub.cpp taskhub.h
+ taskmodel.cpp taskmodel.h
+ taskwindow.cpp taskwindow.h
+ toolchain.cpp toolchain.h
+ toolchaincache.h
+ toolchainconfigwidget.cpp toolchainconfigwidget.h
+ toolchainmanager.cpp toolchainmanager.h
+ toolchainoptionspage.cpp toolchainoptionspage.h
+ toolchainsettingsaccessor.cpp toolchainsettingsaccessor.h
+ treescanner.cpp treescanner.h
+ userfileaccessor.cpp userfileaccessor.h
+ vcsannotatetaskhandler.cpp vcsannotatetaskhandler.h
+ waitforstopdialog.cpp waitforstopdialog.h
+ xcodebuildparser.cpp xcodebuildparser.h
+)
+
+if (TARGET libclang)
+ set(CLANG_BINDIR "$<TARGET_FILE_DIR:libclang>")
+endif()
+extend_qtc_plugin(ProjectExplorer
+ DEFINES "CLANG_BINDIR=\"${CLANG_BINDIR}\""
+)
+
+extend_qtc_plugin(ProjectExplorer
+ CONDITION WIN32
+ SOURCES windebuginterface.cpp windebuginterface.h
+ DEFINES UNICODE _UNICODE
+)
+
+extend_qtc_plugin(ProjectExplorer
+ CONDITION journald
+ DEPENDS systemd
+ SOURCES journaldwatcher.cpp journaldwatcher.h
+ DEFINES WITH_JOURNALD
+)
+
+extend_qtc_plugin(ProjectExplorer
+ CONDITION WITH_TESTS
+ SOURCES
+ jsonwizard/jsonwizard_test.cpp
+ outputparser_test.cpp outputparser_test.h
+)
+qtc_plugin_enabled(_projectexplorer_enabled ProjectExplorer)
+if (WITH_TESTS AND _projectexplorer_enabled)
+ set_source_files_properties(jsonwizard/jsonwizard_test.cpp
+ PROPERTIES HEADER_FILE_ONLY ON
+ )
+endif()
+
diff --git a/src/plugins/projectexplorer/abi.cpp b/src/plugins/projectexplorer/abi.cpp
index 0de4ea655d..e4e4c13e64 100644
--- a/src/plugins/projectexplorer/abi.cpp
+++ b/src/plugins/projectexplorer/abi.cpp
@@ -219,9 +219,9 @@ static Abi macAbiForCpu(quint32 type) {
}
}
-static QList<Abi> parseCoffHeader(const QByteArray &data)
+static Abis parseCoffHeader(const QByteArray &data)
{
- QList<Abi> result;
+ Abis result;
if (data.size() < 20)
return result;
@@ -305,9 +305,9 @@ static QList<Abi> parseCoffHeader(const QByteArray &data)
return result;
}
-static QList<Abi> abiOf(const QByteArray &data)
+static Abis abiOf(const QByteArray &data)
{
- QList<Abi> result;
+ Abis result;
if (data.size() <= 8)
return result;
@@ -626,8 +626,10 @@ bool Abi::isCompatibleWith(const Abi &other) const
if (isCompat && (osFlavor() == AndroidLinuxFlavor || other.osFlavor() == AndroidLinuxFlavor))
isCompat = (architecture() == other.architecture()) && (osFlavor() == other.osFlavor());
- if (!isCompat && compatibleMSVCFlavors(osFlavor(), other.osFlavor()))
+ if (!isCompat && wordWidth() == other.wordWidth()
+ && compatibleMSVCFlavors(osFlavor(), other.osFlavor())) {
isCompat = true;
+ }
return isCompat;
}
@@ -661,6 +663,8 @@ QString Abi::toString(const Architecture &a)
return QLatin1String("xtensa");
case X86Architecture:
return QLatin1String("x86");
+ case Mcs51Architecture:
+ return QLatin1String("mcs51");
case MipsArchitecture:
return QLatin1String("mips");
case PowerPCArchitecture:
@@ -722,6 +726,10 @@ QString Abi::toString(const BinaryFormat &bf)
return QLatin1String("mach_o");
case RuntimeQmlFormat:
return QLatin1String("qml_rt");
+ case UbrofFormat:
+ return QLatin1String("ubrof");
+ case OmfFormat:
+ return QLatin1String("omf");
case UnknownFormat:
Q_FALLTHROUGH();
default:
@@ -789,6 +797,8 @@ Abi::Architecture Abi::architectureFromString(const QStringRef &a)
return AvrArchitecture;
if (a == "x86")
return X86Architecture;
+ if (a == "mcs51")
+ return Mcs51Architecture;
if (a == "mips")
return MipsArchitecture;
if (a == "ppc")
@@ -845,6 +855,10 @@ Abi::BinaryFormat Abi::binaryFormatFromString(const QStringRef &bf)
return PEFormat;
if (bf == "mach_o")
return MachOFormat;
+ if (bf == "ubrof")
+ return UbrofFormat;
+ if (bf == "omf")
+ return OmfFormat;
if (bf == "qml_rt")
return RuntimeQmlFormat;
return UnknownFormat;
@@ -969,9 +983,9 @@ Abi Abi::hostAbi()
}
//! Extract available ABIs from a binary using heuristics.
-QList<Abi> Abi::abisOfBinary(const Utils::FileName &path)
+Abis Abi::abisOfBinary(const Utils::FilePath &path)
{
- QList<Abi> tmp;
+ Abis tmp;
if (path.isEmpty())
return tmp;
@@ -1024,8 +1038,8 @@ QList<Abi> Abi::abisOfBinary(const Utils::FileName &path)
f.close();
// Remove duplicates:
- QList<Abi> result;
- foreach (const Abi &a, tmp) {
+ Abis result;
+ for (const Abi &a : qAsConst(tmp)) {
if (!result.contains(a))
result.append(a);
}
@@ -1219,7 +1233,7 @@ void ProjectExplorer::ProjectExplorerPlugin::testAbiOfBinary()
QFETCH(QString, file);
QFETCH(QStringList, abis);
- QList<Abi> result = Abi::abisOfBinary(Utils::FileName::fromString(file));
+ const Abis result = Abi::abisOfBinary(Utils::FilePath::fromString(file));
QCOMPARE(result.count(), abis.count());
for (int i = 0; i < abis.count(); ++i)
QCOMPARE(result.at(i).toString(), abis.at(i));
@@ -1301,26 +1315,10 @@ void ProjectExplorer::ProjectExplorerPlugin::testAbiFromTargetTriplet_data()
<< int(Abi::LinuxOS) << int(Abi::GenericFlavor)
<< int(Abi::ElfFormat) << 32;
- QTest::newRow("mipsel-linux-android") << int(Abi::MipsArchitecture)
- << int(Abi::LinuxOS) << int(Abi::AndroidLinuxFlavor)
- << int(Abi::ElfFormat) << 32;
-
- QTest::newRow("mipsel-unknown-linux-android") << int(Abi::MipsArchitecture)
- << int(Abi::LinuxOS) << int(Abi::AndroidLinuxFlavor)
- << int(Abi::ElfFormat) << 32;
-
QTest::newRow("mips-linux-gnu") << int(Abi::MipsArchitecture)
<< int(Abi::LinuxOS) << int(Abi::GenericFlavor)
<< int(Abi::ElfFormat) << 32;
- QTest::newRow("mips64el-linux-android") << int(Abi::MipsArchitecture)
- << int(Abi::LinuxOS) << int(Abi::AndroidLinuxFlavor)
- << int(Abi::ElfFormat) << 64;
-
- QTest::newRow("mips64el-unknown-linux-android") << int(Abi::MipsArchitecture)
- << int(Abi::LinuxOS) << int(Abi::AndroidLinuxFlavor)
- << int(Abi::ElfFormat) << 64;
-
QTest::newRow("mips64-linux-octeon-gnu") << int(Abi::MipsArchitecture)
<< int(Abi::LinuxOS) << int(Abi::GenericFlavor)
<< int(Abi::ElfFormat) << 64;
diff --git a/src/plugins/projectexplorer/abi.h b/src/plugins/projectexplorer/abi.h
index 43243847c8..ddca225896 100644
--- a/src/plugins/projectexplorer/abi.h
+++ b/src/plugins/projectexplorer/abi.h
@@ -34,7 +34,7 @@
#include <vector>
-namespace Utils { class FileName; }
+namespace Utils { class FilePath; }
namespace ProjectExplorer {
@@ -42,6 +42,9 @@ namespace ProjectExplorer {
// ABI (documentation inside)
// --------------------------------------------------------------------------
+class Abi;
+using Abis = QVector<Abi>;
+
class PROJECTEXPLORER_EXPORT Abi
{
public:
@@ -54,6 +57,7 @@ public:
ShArchitecture,
AvrArchitecture,
XtensaArchitecture,
+ Mcs51Architecture,
UnknownArchitecture
};
@@ -108,6 +112,8 @@ public:
MachOFormat,
PEFormat,
RuntimeQmlFormat,
+ UbrofFormat,
+ OmfFormat,
UnknownFormat
};
@@ -154,7 +160,7 @@ public:
static Abi fromString(const QString &abiString);
static Abi hostAbi();
- static QList<Abi> abisOfBinary(const Utils::FileName &path);
+ static Abis abisOfBinary(const Utils::FilePath &path);
private:
diff --git a/src/plugins/projectexplorer/abiwidget.cpp b/src/plugins/projectexplorer/abiwidget.cpp
index 80b88ac03e..5df9a3ee05 100644
--- a/src/plugins/projectexplorer/abiwidget.cpp
+++ b/src/plugins/projectexplorer/abiwidget.cpp
@@ -85,7 +85,7 @@ AbiWidget::AbiWidget(QWidget *parent) : QWidget(parent),
d->m_abi->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon);
d->m_abi->setMinimumContentsLength(4);
layout->addWidget(d->m_abi);
- connect(d->m_abi, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
+ connect(d->m_abi, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &AbiWidget::mainComboBoxChanged);
d->m_architectureComboBox = new QComboBox(this);
@@ -93,7 +93,7 @@ AbiWidget::AbiWidget(QWidget *parent) : QWidget(parent),
for (int i = 0; i <= static_cast<int>(Abi::UnknownArchitecture); ++i)
d->m_architectureComboBox->addItem(Abi::toString(static_cast<Abi::Architecture>(i)), i);
d->m_architectureComboBox->setCurrentIndex(static_cast<int>(Abi::UnknownArchitecture));
- connect(d->m_architectureComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
+ connect(d->m_architectureComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &AbiWidget::customComboBoxesChanged);
QLabel *separator1 = new QLabel(this);
@@ -106,7 +106,7 @@ AbiWidget::AbiWidget(QWidget *parent) : QWidget(parent),
for (int i = 0; i <= static_cast<int>(Abi::UnknownOS); ++i)
d->m_osComboBox->addItem(Abi::toString(static_cast<Abi::OS>(i)), i);
d->m_osComboBox->setCurrentIndex(static_cast<int>(Abi::UnknownOS));
- connect(d->m_osComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
+ connect(d->m_osComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &AbiWidget::customOsComboBoxChanged);
QLabel *separator2 = new QLabel(this);
@@ -116,7 +116,7 @@ AbiWidget::AbiWidget(QWidget *parent) : QWidget(parent),
d->m_osFlavorComboBox = new QComboBox(this);
layout->addWidget(d->m_osFlavorComboBox);
- connect(d->m_osFlavorComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
+ connect(d->m_osFlavorComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &AbiWidget::customComboBoxesChanged);
QLabel *separator3 = new QLabel(this);
@@ -129,7 +129,7 @@ AbiWidget::AbiWidget(QWidget *parent) : QWidget(parent),
for (int i = 0; i <= static_cast<int>(Abi::UnknownFormat); ++i)
d->m_binaryFormatComboBox->addItem(Abi::toString(static_cast<Abi::BinaryFormat>(i)), i);
d->m_binaryFormatComboBox->setCurrentIndex(static_cast<int>(Abi::UnknownFormat));
- connect(d->m_binaryFormatComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
+ connect(d->m_binaryFormatComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &AbiWidget::customComboBoxesChanged);
QLabel *separator4 = new QLabel(this);
@@ -146,17 +146,17 @@ AbiWidget::AbiWidget(QWidget *parent) : QWidget(parent),
d->m_wordWidthComboBox->addItem(Abi::toString(0), 0);
// Setup current word width of 0 by default.
d->m_wordWidthComboBox->setCurrentIndex(d->m_wordWidthComboBox->count() - 1);
- connect(d->m_wordWidthComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
+ connect(d->m_wordWidthComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &AbiWidget::customComboBoxesChanged);
layout->setStretchFactor(d->m_abi, 1);
- setAbis(QList<Abi>(), Abi::hostAbi());
+ setAbis(Abis(), Abi::hostAbi());
}
AbiWidget::~AbiWidget() = default;
-static Abi selectAbi(const Abi &current, const QList<Abi> &abiList)
+static Abi selectAbi(const Abi &current, const Abis &abiList)
{
if (!current.isNull())
return current;
@@ -165,7 +165,7 @@ static Abi selectAbi(const Abi &current, const QList<Abi> &abiList)
return Abi::hostAbi();
}
-void AbiWidget::setAbis(const QList<Abi> &abiList, const Abi &currentAbi)
+void AbiWidget::setAbis(const Abis &abiList, const Abi &currentAbi)
{
const Abi defaultAbi = selectAbi(currentAbi, abiList);
{
@@ -191,9 +191,9 @@ void AbiWidget::setAbis(const QList<Abi> &abiList, const Abi &currentAbi)
emitAbiChanged(defaultAbi);
}
-QList<Abi> AbiWidget::supportedAbis() const
+Abis AbiWidget::supportedAbis() const
{
- QList<Abi> result;
+ Abis result;
result.reserve(d->m_abi->count());
for (int i = 1; i < d->m_abi->count(); ++i)
result << Abi::fromString(d->m_abi->itemData(i).toString());
diff --git a/src/plugins/projectexplorer/abiwidget.h b/src/plugins/projectexplorer/abiwidget.h
index b8a64dd05c..6cd6699ce7 100644
--- a/src/plugins/projectexplorer/abiwidget.h
+++ b/src/plugins/projectexplorer/abiwidget.h
@@ -27,12 +27,13 @@
#include "projectexplorer_export.h"
+#include "abi.h"
+
#include <QWidget>
#include <memory>
namespace ProjectExplorer {
-class Abi;
namespace Internal { class AbiWidgetPrivate; }
@@ -48,9 +49,9 @@ public:
AbiWidget(QWidget *parent = nullptr);
~AbiWidget() override;
- void setAbis(const QList<Abi> &, const Abi &currentAbi);
+ void setAbis(const ProjectExplorer::Abis &, const Abi &currentAbi);
- QList<Abi> supportedAbis() const;
+ Abis supportedAbis() const;
bool isCustomAbi() const;
Abi currentAbi() const;
diff --git a/src/plugins/projectexplorer/abstractprocessstep.cpp b/src/plugins/projectexplorer/abstractprocessstep.cpp
index e85a9648ec..1d92fa9280 100644
--- a/src/plugins/projectexplorer/abstractprocessstep.cpp
+++ b/src/plugins/projectexplorer/abstractprocessstep.cpp
@@ -35,22 +35,20 @@
#include <coreplugin/reaper.h>
+#include <utils/fileinprojectfinder.h>
#include <utils/fileutils.h>
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
#include <QDir>
-#include <QTimer>
#include <QHash>
#include <QPair>
+#include <QUrl>
#include <algorithm>
#include <memory>
-namespace {
-const int CACHE_SOFT_LIMIT = 500;
-const int CACHE_HARD_LIMIT = 1000;
-} // namespace
+using namespace Utils;
namespace ProjectExplorer {
@@ -107,10 +105,8 @@ public:
std::unique_ptr<Utils::QtcProcess> m_process;
std::unique_ptr<IOutputParser> m_outputParserChain;
ProcessParameters m_param;
- QHash<QString, QPair<Utils::FileName, quint64>> m_filesCache;
- QHash<QString, Utils::FileNameList> m_candidates;
+ Utils::FileInProjectFinder m_fileFinder;
QByteArray deferredText;
- quint64 m_cacheCounter = 0;
bool m_ignoreReturnValue = false;
bool m_skipFlush = false;
@@ -194,11 +190,8 @@ void AbstractProcessStep::setIgnoreReturnValue(bool b)
bool AbstractProcessStep::init()
{
- d->m_candidates.clear();
- const Utils::FileNameList fl = project()->files(Project::AllFiles);
- for (const Utils::FileName &file : fl)
- d->m_candidates[file.fileName()].push_back(file);
-
+ d->m_fileFinder.setProjectDirectory(project()->projectDirectory());
+ d->m_fileFinder.setProjectFiles(project()->files(Project::AllFiles));
return !d->m_process;
}
@@ -209,7 +202,7 @@ bool AbstractProcessStep::init()
void AbstractProcessStep::doRun()
{
- QDir wd(d->m_param.effectiveWorkingDirectory());
+ QDir wd(d->m_param.effectiveWorkingDirectory().toString());
if (!wd.exists()) {
if (!wd.mkpath(wd.absolutePath())) {
emit addOutput(tr("Could not create directory \"%1\"")
@@ -220,8 +213,8 @@ void AbstractProcessStep::doRun()
}
}
- QString effectiveCommand = d->m_param.effectiveCommand();
- if (!QFileInfo::exists(effectiveCommand)) {
+ const CommandLine effectiveCommand{d->m_param.effectiveCommand(), d->m_param.effectiveArguments()};
+ if (!effectiveCommand.executable().exists()) {
processStartupFailed();
finish(false);
return;
@@ -231,13 +224,13 @@ void AbstractProcessStep::doRun()
d->m_process->setUseCtrlCStub(Utils::HostOsInfo::isWindowsHost());
d->m_process->setWorkingDirectory(wd.absolutePath());
d->m_process->setEnvironment(d->m_param.environment());
- d->m_process->setCommand(effectiveCommand, d->m_param.effectiveArguments());
+ d->m_process->setCommand(effectiveCommand);
connect(d->m_process.get(), &QProcess::readyReadStandardOutput,
this, &AbstractProcessStep::processReadyReadStdOutput);
connect(d->m_process.get(), &QProcess::readyReadStandardError,
this, &AbstractProcessStep::processReadyReadStdError);
- connect(d->m_process.get(), static_cast<void (QProcess::*)(int,QProcess::ExitStatus)>(&QProcess::finished),
+ connect(d->m_process.get(), QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
this, &AbstractProcessStep::slotProcessFinished);
d->m_process->start();
@@ -284,7 +277,7 @@ void AbstractProcessStep::cleanUp(QProcess *process)
void AbstractProcessStep::processStarted()
{
emit addOutput(tr("Starting: \"%1\" %2")
- .arg(QDir::toNativeSeparators(d->m_param.effectiveCommand()),
+ .arg(QDir::toNativeSeparators(d->m_param.effectiveCommand().toString()),
d->m_param.prettyArguments()),
BuildStep::OutputFormat::NormalMessage);
}
@@ -300,7 +293,7 @@ void AbstractProcessStep::processFinished(int exitCode, QProcess::ExitStatus sta
if (d->m_outputParserChain)
d->m_outputParserChain->flush();
- QString command = QDir::toNativeSeparators(d->m_param.effectiveCommand());
+ 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),
BuildStep::OutputFormat::NormalMessage);
@@ -322,7 +315,7 @@ void AbstractProcessStep::processFinished(int exitCode, QProcess::ExitStatus sta
void AbstractProcessStep::processStartupFailed()
{
emit addOutput(tr("Could not start process \"%1\" %2")
- .arg(QDir::toNativeSeparators(d->m_param.effectiveCommand()),
+ .arg(QDir::toNativeSeparators(d->m_param.effectiveCommand().toString()),
d->m_param.prettyArguments()),
BuildStep::OutputFormat::ErrorMessage);
}
@@ -437,44 +430,16 @@ void AbstractProcessStep::taskAdded(const Task &task, int linkedOutputLines, int
Task editable(task);
QString filePath = task.file.toString();
-
- auto it = d->m_filesCache.find(filePath);
- if (it != d->m_filesCache.end()) {
- editable.file = it.value().first;
- it.value().second = ++d->m_cacheCounter;
- } else if (!filePath.isEmpty() && !filePath.startsWith('<') && !QDir::isAbsolutePath(filePath)) {
- // We have no save way to decide which file in which subfolder
- // is meant. Therefore we apply following heuristics:
- // 1. Check if file is unique in whole project
- // 2. Otherwise try again without any ../
- // 3. give up.
-
- QString sourceFilePath = filePath;
- Utils::FileNameList possibleFiles = d->m_candidates.value(Utils::FileName::fromString(filePath).fileName());
-
- if (possibleFiles.count() == 1) {
- editable.file = possibleFiles.first();
- } else {
- // More then one filename, so do a better compare
- // Chop of any "../"
- while (filePath.startsWith("../"))
- filePath.remove(0, 3);
-
- int count = 0;
- Utils::FileName possibleFilePath;
- foreach (const Utils::FileName &fn, possibleFiles) {
- if (fn.endsWith(filePath)) {
- possibleFilePath = fn;
- ++count;
- }
- }
- if (count == 1)
- editable.file = possibleFilePath;
- else
- qWarning() << "Could not find absolute location of file " << filePath;
- }
-
- insertInCache(sourceFilePath, editable.file);
+ if (!filePath.isEmpty() && !filePath.startsWith('<') && !QDir::isAbsolutePath(filePath)) {
+ while (filePath.startsWith("../"))
+ filePath.remove(0, 3);
+ bool found = false;
+ const Utils::FilePathList 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);
@@ -499,27 +464,7 @@ void AbstractProcessStep::slotProcessFinished(int, QProcess::ExitStatus)
for (const QString &l : stdOutLine.split('\n'))
stdError(l);
- purgeCache(true);
cleanUp(process);
}
-void AbstractProcessStep::purgeCache(bool useSoftLimit)
-{
- const int limit = useSoftLimit ? CACHE_SOFT_LIMIT : CACHE_HARD_LIMIT;
- if (d->m_filesCache.size() <= limit)
- return;
-
- const quint64 minCounter = d->m_cacheCounter - static_cast<quint64>(limit);
- std::remove_if(d->m_filesCache.begin(), d->m_filesCache.end(),
- [minCounter](const QPair<Utils::FileName, quint64> &entry) {
- return entry.second <= minCounter;
- });
-}
-
-void AbstractProcessStep::insertInCache(const QString &relativePath, const Utils::FileName &absPath)
-{
- purgeCache(false);
- d->m_filesCache.insert(relativePath, qMakePair(absPath, ++d->m_cacheCounter));
-}
-
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/abstractprocessstep.h b/src/plugins/projectexplorer/abstractprocessstep.h
index 5d76bf7f4e..b21a6bdb25 100644
--- a/src/plugins/projectexplorer/abstractprocessstep.h
+++ b/src/plugins/projectexplorer/abstractprocessstep.h
@@ -29,7 +29,7 @@
#include <QProcess>
-namespace Utils { class FileName; }
+namespace Utils { class FilePath; }
namespace ProjectExplorer {
class IOutputParser;
@@ -57,6 +57,7 @@ protected:
~AbstractProcessStep() override;
bool init() override;
void doRun() override;
+ virtual void finish(bool success);
virtual void processStarted();
virtual void processFinished(int exitCode, QProcess::ExitStatus status);
@@ -68,7 +69,6 @@ protected:
void doCancel() override;
private:
- virtual void finish(bool success);
void processReadyReadStdOutput();
void processReadyReadStdError();
@@ -80,9 +80,6 @@ private:
void outputAdded(const QString &string, BuildStep::OutputFormat format);
- void purgeCache(bool useSoftLimit);
- void insertInCache(const QString &relativePath, const Utils::FileName &absPath);
-
class Private;
Private *d;
};
diff --git a/src/plugins/projectexplorer/addrunconfigdialog.cpp b/src/plugins/projectexplorer/addrunconfigdialog.cpp
new file mode 100644
index 0000000000..647959eb15
--- /dev/null
+++ b/src/plugins/projectexplorer/addrunconfigdialog.cpp
@@ -0,0 +1,192 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "addrunconfigdialog.h"
+
+#include "project.h"
+#include "target.h"
+
+#include <utils/itemviews.h>
+#include <utils/qtcassert.h>
+#include <utils/treemodel.h>
+
+#include <QDialogButtonBox>
+#include <QHeaderView>
+#include <QHBoxLayout>
+#include <QItemSelectionModel>
+#include <QLabel>
+#include <QLineEdit>
+#include <QPushButton>
+#include <QRegExp>
+#include <QSortFilterProxyModel>
+#include <QVBoxLayout>
+
+using namespace Utils;
+
+namespace ProjectExplorer {
+namespace Internal {
+
+const Qt::ItemDataRole IsCustomRole = Qt::UserRole;
+
+class CandidateTreeItem : public TreeItem
+{
+ Q_DECLARE_TR_FUNCTIONS(ProjectExplorer::Internal::AddRunConfigDialog)
+public:
+ CandidateTreeItem(const RunConfigurationCreationInfo &rci, const FilePath &projectRoot)
+ : m_creationInfo(rci), m_projectRoot(projectRoot)
+ { }
+
+ RunConfigurationCreationInfo creationInfo() const { return m_creationInfo; }
+
+private:
+ QVariant data(int column, int role) const override
+ {
+ QTC_ASSERT(column < 2, return QVariant());
+ if (role == IsCustomRole)
+ return m_creationInfo.projectFilePath.isEmpty();
+ if (column == 0 && role == Qt::DisplayRole)
+ return m_creationInfo.displayName;
+ if (column == 1 && role == Qt::DisplayRole) {
+ FilePath displayPath = m_creationInfo.projectFilePath.relativeChildPath(m_projectRoot);
+ if (displayPath.isEmpty()) {
+ displayPath = m_creationInfo.projectFilePath;
+ QTC_CHECK(displayPath.isEmpty());
+ }
+ return displayPath.isEmpty() ? tr("[none]") : displayPath.toUserOutput();
+ }
+ return QVariant();
+ }
+
+ const RunConfigurationCreationInfo m_creationInfo;
+ const FilePath m_projectRoot;
+};
+
+class CandidatesModel : public TreeModel<TreeItem, CandidateTreeItem>
+{
+ Q_DECLARE_TR_FUNCTIONS(ProjectExplorer::Internal::AddRunConfigDialog)
+public:
+ CandidatesModel(Target *target, QObject *parent) : TreeModel(parent)
+ {
+ setHeader({tr("Name"), tr("Source")});
+ for (const RunConfigurationCreationInfo &rci
+ : RunConfigurationFactory::creatorsForTarget(target)) {
+ rootItem()->appendChild(new CandidateTreeItem(rci,
+ target->project()->projectDirectory()));
+ }
+ }
+};
+
+class ProxyModel : public QSortFilterProxyModel
+{
+public:
+ ProxyModel(QObject *parent) : QSortFilterProxyModel(parent) { }
+
+private:
+ bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override
+ {
+ if (source_left.column() == 0) {
+ // Let's put the fallback candidates last.
+ const bool leftIsCustom = sourceModel()->data(source_left, IsCustomRole).toBool();
+ const bool rightIsCustom = sourceModel()->data(source_right, IsCustomRole).toBool();
+ if (leftIsCustom != rightIsCustom)
+ return rightIsCustom;
+ }
+ return QSortFilterProxyModel::lessThan(source_left, source_right);
+ }
+};
+
+class CandidatesTreeView : public TreeView
+{
+public:
+ CandidatesTreeView(QWidget *parent) : TreeView(parent)
+ {
+ setUniformRowHeights(true);
+ }
+
+private:
+ QSize sizeHint() const override
+ {
+ const int width = columnWidth(0) + columnWidth(1);
+ const int height = qMin(model()->rowCount() + 10, 10) * rowHeight(model()->index(0, 0))
+ + header()->sizeHint().height();
+ return {width, height};
+ }
+};
+
+AddRunConfigDialog::AddRunConfigDialog(Target *target, QWidget *parent)
+ : QDialog(parent), m_view(new CandidatesTreeView(this))
+{
+ setWindowTitle(tr("Create Run Configuration"));
+ const auto model = new CandidatesModel(target, this);
+ const auto proxyModel = new ProxyModel(this);
+ proxyModel->setSourceModel(model);
+ const auto filterEdit = new QLineEdit(this);
+ m_view->setSelectionMode(TreeView::SingleSelection);
+ m_view->setSelectionBehavior(TreeView::SelectRows);
+ m_view->setSortingEnabled(true);
+ m_view->setModel(proxyModel);
+ m_view->resizeColumnToContents(0);
+ m_view->resizeColumnToContents(1);
+ m_view->sortByColumn(0, Qt::AscendingOrder);
+ const auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
+ buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Create"));
+
+ connect(filterEdit, &QLineEdit::textChanged, this, [proxyModel](const QString &text) {
+ proxyModel->setFilterRegExp(QRegExp(text, Qt::CaseInsensitive));
+ });
+ connect(m_view, &TreeView::doubleClicked, this, [this] { accept(); });
+ const auto updateOkButton = [buttonBox, this] {
+ buttonBox->button(QDialogButtonBox::Ok)
+ ->setEnabled(m_view->selectionModel()->hasSelection());
+ };
+ connect(m_view->selectionModel(), &QItemSelectionModel::selectionChanged, this, updateOkButton);
+ updateOkButton();
+ connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
+ connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
+
+ const auto layout = new QVBoxLayout(this);
+ const auto filterLayout = new QHBoxLayout;
+ filterLayout->addWidget(new QLabel(tr("Filter candidates by name:"), this));
+ filterLayout->addWidget(filterEdit);
+ layout->addLayout(filterLayout);
+ layout->addWidget(m_view);
+ layout->addWidget(buttonBox);
+}
+
+void AddRunConfigDialog::accept()
+{
+ const QModelIndexList selected = m_view->selectionModel()->selectedRows();
+ QTC_ASSERT(selected.count() == 1, return);
+ const auto * const proxyModel = static_cast<ProxyModel *>(m_view->model());
+ const auto * const model = static_cast<CandidatesModel *>(proxyModel->sourceModel());
+ const TreeItem * const item = model->itemForIndex(proxyModel->mapToSource(selected.first()));
+ QTC_ASSERT(item, return);
+ m_creationInfo = static_cast<const CandidateTreeItem *>(item)->creationInfo();
+ QTC_ASSERT(m_creationInfo.id.isValid(), return);
+ QDialog::accept();
+}
+
+} // namespace Internal
+} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/kitconfigwidget.cpp b/src/plugins/projectexplorer/addrunconfigdialog.h
index 4b9fbebd60..2214bed5a1 100644
--- a/src/plugins/projectexplorer/kitconfigwidget.cpp
+++ b/src/plugins/projectexplorer/addrunconfigdialog.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -23,51 +23,33 @@
**
****************************************************************************/
-#include "kitconfigwidget.h"
+#pragma once
-#include "kit.h"
-#include "kitinformation.h"
+#include "runconfiguration.h"
-namespace ProjectExplorer {
+#include <QDialog>
-KitConfigWidget::KitConfigWidget(Kit *kit, const KitInformation *ki) : m_kit(kit),
- m_kitInformation(ki), m_isSticky(kit->isSticky(ki->id()))
-{ }
+namespace Utils { class TreeView; }
-Core::Id KitConfigWidget::kitInformationId() const
-{
- return m_kitInformation->id();
-}
+namespace ProjectExplorer {
+class Target;
-bool KitConfigWidget::isMutable() const
-{
- return m_kit->isMutable(m_kitInformation->id());
-}
+namespace Internal {
-void KitConfigWidget::setMutable(bool b)
+class AddRunConfigDialog : public QDialog
{
- m_kit->setMutable(m_kitInformation->id(), b);
-}
+ Q_OBJECT
+public:
+ AddRunConfigDialog(Target *target, QWidget *parent);
-QString KitConfigWidget::msgManage()
-{
- return tr("Manage...");
-}
+ RunConfigurationCreationInfo creationInfo() const { return m_creationInfo; }
-void KitConfigWidget::setPalette(const QPalette &p)
-{
- if (mainWidget())
- mainWidget()->setPalette(p);
- if (buttonWidget())
- buttonWidget()->setPalette(p);
-}
+private:
+ void accept() override;
-void KitConfigWidget::setStyle(QStyle *s)
-{
- if (mainWidget())
- mainWidget()->setStyle(s);
- if (buttonWidget())
- buttonWidget()->setStyle(s);
-}
+ Utils::TreeView * const m_view;
+ RunConfigurationCreationInfo m_creationInfo;
+};
+} // namespace Internal
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/allprojectsfilter.cpp b/src/plugins/projectexplorer/allprojectsfilter.cpp
index 24371ad4e1..ab17127d73 100644
--- a/src/plugins/projectexplorer/allprojectsfilter.cpp
+++ b/src/plugins/projectexplorer/allprojectsfilter.cpp
@@ -59,7 +59,7 @@ void AllProjectsFilter::prepareSearch(const QString &entry)
if (!fileIterator()) {
QStringList paths;
for (Project *project : SessionManager::projects())
- paths.append(Utils::transform(project->files(Project::AllFiles), &Utils::FileName::toString));
+ paths.append(Utils::transform(project->files(Project::AllFiles), &Utils::FilePath::toString));
Utils::sort(paths);
setFileIterator(new BaseFileFilter::ListIterator(paths));
}
diff --git a/src/plugins/projectexplorer/allprojectsfind.cpp b/src/plugins/projectexplorer/allprojectsfind.cpp
index aa0d7c6fbc..d41f21f1b7 100644
--- a/src/plugins/projectexplorer/allprojectsfind.cpp
+++ b/src/plugins/projectexplorer/allprojectsfind.cpp
@@ -88,7 +88,7 @@ Utils::FileIterator *AllProjectsFind::filesForProjects(const QStringList &nameFi
QTextCodec *projectCodec = config->useGlobalSettings()
? Core::EditorManager::defaultTextCodec()
: config->textCodec();
- const QStringList filteredFiles = filterFiles(Utils::transform(project->files(Project::AllFiles), &Utils::FileName::toString));
+ const QStringList filteredFiles = filterFiles(Utils::transform(project->files(Project::AllFiles), &Utils::FilePath::toString));
for (const QString &fileName : filteredFiles) {
QTextCodec *codec = openEditorEncodings.value(fileName);
if (!codec)
diff --git a/src/plugins/projectexplorer/ansifilterparser.cpp b/src/plugins/projectexplorer/ansifilterparser.cpp
index 402dcf6f9b..a2db2c1a6f 100644
--- a/src/plugins/projectexplorer/ansifilterparser.cpp
+++ b/src/plugins/projectexplorer/ansifilterparser.cpp
@@ -168,7 +168,7 @@ void ProjectExplorerPlugin::testAnsiFilterOutputParser()
QFETCH(QString, childStdErrLines);
testbench.testParsing(input, inputChannel,
- QList<Task>(), childStdOutLines, childStdErrLines,
+ Tasks(), childStdOutLines, childStdErrLines,
QString());
}
diff --git a/src/plugins/projectexplorer/applicationlauncher.cpp b/src/plugins/projectexplorer/applicationlauncher.cpp
index 3aef28f090..3a9cde2baf 100644
--- a/src/plugins/projectexplorer/applicationlauncher.cpp
+++ b/src/plugins/projectexplorer/applicationlauncher.cpp
@@ -39,6 +39,7 @@
#include "devicesupport/deviceprocess.h"
#include "projectexplorer.h"
#include "projectexplorersettings.h"
+#include "runcontrol.h"
#include <QTextCodec>
#include <QTimer>
@@ -63,7 +64,6 @@ using namespace Internal;
namespace Internal {
-
class ApplicationLauncherPrivate : public QObject
{
public:
@@ -126,7 +126,7 @@ public:
ApplicationLauncherPrivate::ApplicationLauncherPrivate(ApplicationLauncher *parent)
: q(parent), m_outputCodec(QTextCodec::codecForLocale())
{
- if (ProjectExplorerPlugin::projectExplorerSettings().mergeStdErrAndStdOut){
+ if (ProjectExplorerPlugin::appOutputSettings().mergeChannels) {
m_guiProcess.setProcessChannelMode(QProcess::MergedChannels);
} else {
m_guiProcess.setProcessChannelMode(QProcess::SeparateChannels);
@@ -137,7 +137,7 @@ ApplicationLauncherPrivate::ApplicationLauncherPrivate(ApplicationLauncher *pare
this, &ApplicationLauncherPrivate::readLocalStandardOutput);
connect(&m_guiProcess, &QProcess::errorOccurred,
this, &ApplicationLauncherPrivate::localGuiProcessError);
- connect(&m_guiProcess, static_cast<void (QProcess::*)(int,QProcess::ExitStatus)>(&QProcess::finished),
+ connect(&m_guiProcess, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
this, &ApplicationLauncherPrivate::localProcessDone);
connect(&m_guiProcess, &QProcess::started,
this, &ApplicationLauncherPrivate::handleProcessStarted);
@@ -152,8 +152,7 @@ ApplicationLauncherPrivate::ApplicationLauncherPrivate(ApplicationLauncher *pare
this, &ApplicationLauncherPrivate::localConsoleProcessError);
connect(&m_consoleProcess, &ConsoleProcess::processStopped,
this, &ApplicationLauncherPrivate::localProcessDone);
- connect(&m_consoleProcess,
- static_cast<void (ConsoleProcess::*)(QProcess::ProcessError)>(&ConsoleProcess::error),
+ connect(&m_consoleProcess, QOverload<QProcess::ProcessError>::of(&ConsoleProcess::error),
q, &ApplicationLauncher::error);
#ifdef Q_OS_WIN
@@ -379,7 +378,7 @@ void ApplicationLauncherPrivate::start(const Runnable &runnable, const IDevice::
#endif
if (!m_useTerminal) {
- m_guiProcess.setCommand(runnable.executable, runnable.commandLineArguments);
+ m_guiProcess.setCommand(runnable.commandLine());
m_guiProcess.closeWriteChannel();
m_guiProcess.start();
} else {
diff --git a/src/plugins/projectexplorer/appoutputpane.cpp b/src/plugins/projectexplorer/appoutputpane.cpp
index 34f71efc24..df9fd503ba 100644
--- a/src/plugins/projectexplorer/appoutputpane.cpp
+++ b/src/plugins/projectexplorer/appoutputpane.cpp
@@ -24,47 +24,54 @@
****************************************************************************/
#include "appoutputpane.h"
+
#include "projectexplorer.h"
+#include "projectexplorerconstants.h"
#include "projectexplorericons.h"
-#include "projectexplorersettings.h"
-#include "runconfiguration.h"
+#include "runcontrol.h"
#include "session.h"
#include "windebuginterface.h"
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/command.h>
-#include <coreplugin/outputwindow.h>
-#include <coreplugin/find/basetextfind.h>
#include <coreplugin/coreconstants.h>
+#include <coreplugin/find/basetextfind.h>
#include <coreplugin/icore.h>
+#include <coreplugin/outputwindow.h>
+#include <texteditor/behaviorsettings.h>
#include <texteditor/fontsettings.h>
#include <texteditor/texteditorsettings.h>
-#include <texteditor/behaviorsettings.h>
-#include <extensionsystem/pluginmanager.h>
-#include <extensionsystem/invoker.h>
+#include <extensionsystem/invoker.h>
+#include <extensionsystem/pluginmanager.h>
#include <utils/algorithm.h>
#include <utils/outputformatter.h>
#include <utils/qtcassert.h>
#include <utils/utilsicons.h>
#include <QAction>
-#include <QVBoxLayout>
+#include <QCheckBox>
+#include <QHBoxLayout>
+#include <QLabel>
+#include <QLoggingCategory>
+#include <QMenu>
+#include <QSpinBox>
+#include <QTabBar>
#include <QTabWidget>
#include <QToolButton>
-#include <QTabBar>
-#include <QMenu>
-
-#include <QDebug>
+#include <QVBoxLayout>
-enum { debug = 0 };
+static Q_LOGGING_CATEGORY(appOutputLog, "qtc.projectexplorer.appoutput", QtWarningMsg);
using namespace ProjectExplorer;
using namespace ProjectExplorer::Internal;
+const char OPTIONS_PAGE_ID[] = "B.ProjectExplorer.AppOutputOptions";
+
+
static QObject *debuggerPlugin()
{
- return ExtensionSystem::PluginManager::getObjectByName(QLatin1String("DebuggerPlugin"));
+ return ExtensionSystem::PluginManager::getObjectByName("DebuggerPlugin");
}
static QString msgAttachDebuggerTooltip(const QString &handleDescription = QString())
@@ -79,13 +86,19 @@ static void replaceAllChildWidgets(QLayout *layout, const QList<QWidget *> &newC
while (QLayoutItem *child = layout->takeAt(0))
delete child;
- foreach (QWidget *widget, newChildren)
+ for (QWidget *widget : newChildren)
layout->addWidget(widget);
}
namespace {
const char SETTINGS_KEY[] = "ProjectExplorer/AppOutput/Zoom";
const char C_APP_OUTPUT[] = "ProjectExplorer.ApplicationOutput";
+const char POP_UP_FOR_RUN_OUTPUT_KEY[] = "ProjectExplorer/Settings/ShowRunOutput";
+const char POP_UP_FOR_DEBUG_OUTPUT_KEY[] = "ProjectExplorer/Settings/ShowDebugOutput";
+const char CLEAN_OLD_OUTPUT_KEY[] = "ProjectExplorer/Settings/CleanOldAppOutput";
+const char MERGE_CHANNELS_KEY[] = "ProjectExplorer/Settings/MergeStdErrAndStdOut";
+const char WRAP_OUTPUT_KEY[] = "ProjectExplorer/Settings/WrapAppOutput";
+const char MAX_LINES_KEY[] = "ProjectExplorer/Settings/MaxAppOutputLines";
}
namespace ProjectExplorer {
@@ -147,11 +160,11 @@ void TabWidget::slotContextMenuRequested(const QPoint &pos)
emit contextMenuRequested(pos, tabBar()->tabAt(pos));
}
-AppOutputPane::RunControlTab::RunControlTab(RunControl *rc, Core::OutputWindow *w) :
- runControl(rc), window(w)
+AppOutputPane::RunControlTab::RunControlTab(RunControl *runControl, Core::OutputWindow *w) :
+ runControl(runControl), window(w)
{
- if (rc && w)
- w->setFormatter(rc->outputFormatter());
+ if (runControl && w)
+ w->setFormatter(runControl->outputFormatter());
}
AppOutputPane::AppOutputPane() :
@@ -164,16 +177,15 @@ AppOutputPane::AppOutputPane() :
m_reRunButton(new QToolButton),
m_stopButton(new QToolButton),
m_attachButton(new QToolButton),
- m_zoomInButton(new QToolButton),
- m_zoomOutButton(new QToolButton),
+ m_settingsButton(new QToolButton),
m_formatterWidget(new QWidget)
{
- setObjectName(QLatin1String("AppOutputPane")); // Used in valgrind engine
+ setObjectName("AppOutputPane"); // Used in valgrind engine
+ loadSettings();
// Rerun
m_reRunButton->setIcon(Utils::Icons::RUN_SMALL_TOOLBAR.icon());
m_reRunButton->setToolTip(tr("Re-run this run-configuration"));
- m_reRunButton->setAutoRaise(true);
m_reRunButton->setEnabled(false);
connect(m_reRunButton, &QToolButton::clicked,
this, &AppOutputPane::reRunRunControl);
@@ -187,7 +199,6 @@ AppOutputPane::AppOutputPane() :
cmd->setDescription(m_stopAction->toolTip());
m_stopButton->setDefaultAction(cmd->action());
- m_stopButton->setAutoRaise(true);
connect(m_stopAction, &QAction::triggered,
this, &AppOutputPane::stopRunControl);
@@ -196,24 +207,19 @@ AppOutputPane::AppOutputPane() :
m_attachButton->setToolTip(msgAttachDebuggerTooltip());
m_attachButton->setEnabled(false);
m_attachButton->setIcon(Icons::DEBUG_START_SMALL_TOOLBAR.icon());
- m_attachButton->setAutoRaise(true);
connect(m_attachButton, &QToolButton::clicked,
this, &AppOutputPane::attachToRunControl);
- m_zoomInButton->setToolTip(tr("Increase Font Size"));
- m_zoomInButton->setIcon(Utils::Icons::PLUS_TOOLBAR.icon());
- m_zoomInButton->setAutoRaise(true);
+ connect(this, &Core::IOutputPane::zoomIn, this, &AppOutputPane::zoomIn);
+ connect(this, &Core::IOutputPane::zoomOut, this, &AppOutputPane::zoomOut);
+ connect(this, &IOutputPane::resetZoom, this, &AppOutputPane::resetZoom);
- connect(m_zoomInButton, &QToolButton::clicked,
- this, &AppOutputPane::zoomIn);
-
- m_zoomOutButton->setToolTip(tr("Decrease Font Size"));
- m_zoomOutButton->setIcon(Utils::Icons::MINUS.icon());
- m_zoomOutButton->setAutoRaise(true);
-
- connect(m_zoomOutButton, &QToolButton::clicked,
- this, &AppOutputPane::zoomOut);
+ m_settingsButton->setToolTip(tr("Open Settings Page"));
+ m_settingsButton->setIcon(Utils::Icons::SETTINGS_TOOLBAR.icon());
+ connect(m_settingsButton, &QToolButton::clicked, this, [] {
+ Core::ICore::showOptionsDialog(OPTIONS_PAGE_ID);
+ });
auto formatterWidgetsLayout = new QHBoxLayout;
formatterWidgetsLayout->setContentsMargins(QMargins());
@@ -236,42 +242,26 @@ AppOutputPane::AppOutputPane() :
m_mainWidget->setLayout(layout);
- connect(TextEditor::TextEditorSettings::instance(), &TextEditor::TextEditorSettings::fontSettingsChanged,
- this, &AppOutputPane::updateFontSettings);
-
- connect(TextEditor::TextEditorSettings::instance(), &TextEditor::TextEditorSettings::behaviorSettingsChanged,
- this, &AppOutputPane::updateBehaviorSettings);
-
connect(SessionManager::instance(), &SessionManager::aboutToUnloadSession,
this, &AppOutputPane::aboutToUnloadSession);
- connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::settingsChanged,
- this, &AppOutputPane::updateFromSettings);
-
- QSettings *settings = Core::ICore::settings();
- m_zoom = settings->value(QLatin1String(SETTINGS_KEY), 0).toFloat();
- connect(Core::ICore::instance(), &Core::ICore::saveSettingsRequested,
- this, &AppOutputPane::saveSettings);
+ setupFilterUi("AppOutputPane.Filter");
+ setFilteringEnabled(false);
+ setZoomButtonsEnabled(false);
+ setupContext("Core.AppOutputPane", m_mainWidget);
}
AppOutputPane::~AppOutputPane()
{
- if (debug)
- qDebug() << "OutputPane::~OutputPane: Entries left" << m_runControlTabs.size();
+ qCDebug(appOutputLog) << "AppOutputPane::~AppOutputPane: Entries left" << m_runControlTabs.size();
- foreach (const RunControlTab &rt, m_runControlTabs) {
+ for (const RunControlTab &rt : qAsConst(m_runControlTabs)) {
delete rt.window;
delete rt.runControl;
}
delete m_mainWidget;
}
-void AppOutputPane::saveSettings()
-{
- QSettings *settings = Core::ICore::settings();
- settings->setValue(QLatin1String(SETTINGS_KEY), m_zoom);
-}
-
int AppOutputPane::currentIndex() const
{
if (const QWidget *w = m_tabWidget->currentWidget())
@@ -337,8 +327,8 @@ QWidget *AppOutputPane::outputWidget(QWidget *)
QList<QWidget*> AppOutputPane::toolBarWidgets() const
{
- return { m_reRunButton, m_stopButton, m_attachButton, m_zoomInButton,
- m_zoomOutButton, m_formatterWidget };
+ return QList<QWidget *>{m_reRunButton, m_stopButton, m_attachButton, m_settingsButton,
+ m_formatterWidget} + IOutputPane::toolBarWidgets();
}
QString AppOutputPane::displayName() const
@@ -381,18 +371,13 @@ void AppOutputPane::setFocus()
m_tabWidget->currentWidget()->setFocus();
}
-void AppOutputPane::updateFontSettings()
+void AppOutputPane::updateFilter()
{
- QFont f = TextEditor::TextEditorSettings::fontSettings().font();
- foreach (const RunControlTab &rcTab, m_runControlTabs)
- rcTab.window->setBaseFont(f);
-}
-
-void AppOutputPane::updateBehaviorSettings()
-{
- bool zoomEnabled = TextEditor::TextEditorSettings::behaviorSettings().m_scrollWheelZooming;
- foreach (const RunControlTab &rcTab, m_runControlTabs)
- rcTab.window->setWheelZoomEnabled(zoomEnabled);
+ const int index = currentIndex();
+ if (index != -1) {
+ m_runControlTabs.at(index).window->updateFilterProperties(
+ filterText(), filterCaseSensitivity(), filterUsesRegexp());
+ }
}
void AppOutputPane::createNewOutputWindow(RunControl *rc)
@@ -407,8 +392,10 @@ void AppOutputPane::createNewOutputWindow(RunControl *rc)
this, &AppOutputPane::slotRunControlFinished);
connect(rc, &RunControl::applicationProcessHandleChanged,
this, &AppOutputPane::enableDefaultButtons);
- connect(rc, &RunControl::appendMessageRequested,
- this, &AppOutputPane::appendMessage);
+ connect(rc, &RunControl::appendMessage,
+ this, [this, rc](const QString &out, Utils::OutputFormat format) {
+ appendMessage(rc, out, format);
+ });
// First look if we can reuse a tab
const Runnable thisRunnable = rc->runnable();
@@ -435,42 +422,55 @@ void AppOutputPane::createNewOutputWindow(RunControl *rc)
m_tabWidget->setTabText(tabIndex, rc->displayName());
tab.window->scrollToBottom();
- if (debug)
- qDebug() << "OutputPane::createNewOutputWindow: Reusing tab" << tabIndex << " for " << rc;
+ qCDebug(appOutputLog) << "AppOutputPane::createNewOutputWindow: Reusing tab"
+ << tabIndex << "for" << rc;
return;
}
// Create new
static int counter = 0;
Core::Id contextId = Core::Id(C_APP_OUTPUT).withSuffix(counter++);
Core::Context context(contextId);
- Core::OutputWindow *ow = new Core::OutputWindow(context, m_tabWidget);
+ Core::OutputWindow *ow = new Core::OutputWindow(context, SETTINGS_KEY, m_tabWidget);
ow->setWindowTitle(tr("Application Output Window"));
ow->setWindowIcon(Icons::WINDOW.icon());
- ow->setWordWrapEnabled(ProjectExplorerPlugin::projectExplorerSettings().wrapAppOutput);
- ow->setMaxCharCount(ProjectExplorerPlugin::projectExplorerSettings().maxAppOutputChars);
- ow->setWheelZoomEnabled(TextEditor::TextEditorSettings::behaviorSettings().m_scrollWheelZooming);
- ow->setBaseFont(TextEditor::TextEditorSettings::fontSettings().font());
- ow->setFontZoom(m_zoom);
+ ow->setWordWrapEnabled(m_settings.wrapOutput);
+ ow->setMaxCharCount(m_settings.maxCharCount);
+
+ auto updateFontSettings = [ow] {
+ ow->setBaseFont(TextEditor::TextEditorSettings::fontSettings().font());
+ };
+
+ auto updateBehaviorSettings = [ow] {
+ ow->setWheelZoomEnabled(
+ TextEditor::TextEditorSettings::behaviorSettings().m_scrollWheelZooming);
+ };
+
+ updateFontSettings();
+ updateBehaviorSettings();
connect(ow, &Core::OutputWindow::wheelZoom, this, [this, ow]() {
- m_zoom = ow->fontZoom();
- foreach (const RunControlTab &tab, m_runControlTabs)
- tab.window->setFontZoom(m_zoom);
+ float fontZoom = ow->fontZoom();
+ for (const RunControlTab &tab : qAsConst(m_runControlTabs))
+ tab.window->setFontZoom(fontZoom);
});
+ connect(TextEditor::TextEditorSettings::instance(), &TextEditor::TextEditorSettings::fontSettingsChanged,
+ this, updateFontSettings);
+ connect(TextEditor::TextEditorSettings::instance(), &TextEditor::TextEditorSettings::behaviorSettingsChanged,
+ this, updateBehaviorSettings);
auto *agg = new Aggregation::Aggregate;
agg->add(ow);
agg->add(new Core::BaseTextFind(ow));
m_runControlTabs.push_back(RunControlTab(rc, ow));
m_tabWidget->addTab(ow, rc->displayName());
- if (debug)
- qDebug() << "OutputPane::createNewOutputWindow: Adding tab for " << rc;
+ qCDebug(appOutputLog) << "AppOutputPane::createNewOutputWindow: Adding tab for" << rc;
updateCloseActions();
+ setFilteringEnabled(m_tabWidget->count() > 0);
}
void AppOutputPane::handleOldOutput(Core::OutputWindow *window) const
{
- if (ProjectExplorerPlugin::projectExplorerSettings().cleanOldAppOutput)
+ if (m_settings.cleanOldOutput)
window->clear();
else
window->grayOutOldContent();
@@ -478,9 +478,9 @@ void AppOutputPane::handleOldOutput(Core::OutputWindow *window) const
void AppOutputPane::updateFromSettings()
{
- foreach (const RunControlTab &tab, m_runControlTabs) {
- tab.window->setWordWrapEnabled(ProjectExplorerPlugin::projectExplorerSettings().wrapAppOutput);
- tab.window->setMaxCharCount(ProjectExplorerPlugin::projectExplorerSettings().maxAppOutputChars);
+ for (const RunControlTab &tab : qAsConst(m_runControlTabs)) {
+ tab.window->setWordWrapEnabled(m_settings.wrapOutput);
+ tab.window->setMaxCharCount(m_settings.maxCharCount);
}
}
@@ -492,7 +492,7 @@ void AppOutputPane::appendMessage(RunControl *rc, const QString &out, Utils::Out
QString stringToWrite;
if (format == Utils::NormalMessageFormat || format == Utils::ErrorMessageFormat) {
stringToWrite = QTime::currentTime().toString();
- stringToWrite += QLatin1String(": ");
+ stringToWrite += ": ";
}
stringToWrite += out;
window->appendMessage(stringToWrite, format);
@@ -505,6 +505,36 @@ void AppOutputPane::appendMessage(RunControl *rc, const QString &out, Utils::Out
}
}
+void AppOutputPane::setSettings(const AppOutputSettings &settings)
+{
+ m_settings = settings;
+ storeSettings();
+ updateFromSettings();
+}
+
+void AppOutputPane::storeSettings() const
+{
+ QSettings * const s = Core::ICore::settings();
+ s->setValue(POP_UP_FOR_RUN_OUTPUT_KEY, m_settings.popUpForRunOutput);
+ s->setValue(POP_UP_FOR_DEBUG_OUTPUT_KEY, m_settings.popUpForDebugOutput);
+ s->setValue(CLEAN_OLD_OUTPUT_KEY, m_settings.cleanOldOutput);
+ s->setValue(MERGE_CHANNELS_KEY, m_settings.mergeChannels);
+ s->setValue(WRAP_OUTPUT_KEY, m_settings.wrapOutput);
+ s->setValue(MAX_LINES_KEY, m_settings.maxCharCount / 100);
+}
+
+void AppOutputPane::loadSettings()
+{
+ QSettings * const s = Core::ICore::settings();
+ m_settings.popUpForRunOutput = s->value(POP_UP_FOR_RUN_OUTPUT_KEY, true).toBool();
+ m_settings.popUpForDebugOutput = s->value(POP_UP_FOR_DEBUG_OUTPUT_KEY, false).toBool();
+ m_settings.cleanOldOutput = s->value(CLEAN_OLD_OUTPUT_KEY, false).toBool();
+ m_settings.mergeChannels = s->value(MERGE_CHANNELS_KEY, false).toBool();
+ m_settings.wrapOutput = s->value(WRAP_OUTPUT_KEY, true).toBool();
+ m_settings.maxCharCount = s->value(MAX_LINES_KEY,
+ Core::Constants::DEFAULT_MAX_CHAR_COUNT).toInt() * 100;
+}
+
void AppOutputPane::showTabFor(RunControl *rc)
{
m_tabWidget->setCurrentIndex(tabWidgetIndexOf(indexOf(rc)));
@@ -552,8 +582,7 @@ void AppOutputPane::stopRunControl()
rc->forceStop();
}
- if (debug)
- qDebug() << "OutputPane::stopRunControl " << rc;
+ qCDebug(appOutputLog) << "AppOutputPane::stopRunControl" << rc;
}
void AppOutputPane::closeTabs(CloseTabMode mode)
@@ -577,8 +606,7 @@ void AppOutputPane::closeTab(int tabIndex, CloseTabMode closeTabMode)
RunControl *runControl = m_runControlTabs[index].runControl;
Core::OutputWindow *window = m_runControlTabs[index].window;
- if (debug)
- qDebug() << "OutputPane::closeTab tab " << tabIndex << runControl << window;
+ qCDebug(appOutputLog) << "AppOutputPane::closeTab tab" << tabIndex << runControl << window;
// Prompt user to stop
if (closeTabMode == CloseTabWithPrompt) {
QWidget *tabWidget = m_tabWidget->widget(tabIndex);
@@ -599,6 +627,7 @@ void AppOutputPane::closeTab(int tabIndex, CloseTabMode closeTabMode)
runControl->initiateFinish(); // Will self-destruct.
m_runControlTabs.removeAt(index);
updateCloseActions();
+ setFilteringEnabled(m_tabWidget->count() > 0);
if (m_runControlTabs.isEmpty())
hide();
@@ -623,22 +652,22 @@ void AppOutputPane::enableDefaultButtons()
enableButtons(currentRunControl());
}
-void AppOutputPane::zoomIn()
+void AppOutputPane::zoomIn(int range)
{
- foreach (const RunControlTab &tab, m_runControlTabs)
- tab.window->zoomIn(1);
- if (m_runControlTabs.isEmpty())
- return;
- m_zoom = m_runControlTabs.first().window->fontZoom();
+ for (const RunControlTab &tab : qAsConst(m_runControlTabs))
+ tab.window->zoomIn(range);
}
-void AppOutputPane::zoomOut()
+void AppOutputPane::zoomOut(int range)
{
- foreach (const RunControlTab &tab, m_runControlTabs)
- tab.window->zoomOut(1);
- if (m_runControlTabs.isEmpty())
- return;
- m_zoom = m_runControlTabs.first().window->fontZoom();
+ for (const RunControlTab &tab : qAsConst(m_runControlTabs))
+ tab.window->zoomOut(range);
+}
+
+void AppOutputPane::resetZoom()
+{
+ for (const RunControlTab &tab : qAsConst(m_runControlTabs))
+ tab.window->resetZoom();
}
void AppOutputPane::enableButtons(const RunControl *rc)
@@ -658,8 +687,7 @@ void AppOutputPane::enableButtons(const RunControl *rc)
m_attachButton->setEnabled(false);
m_attachButton->setToolTip(msgAttachDebuggerTooltip());
}
- m_zoomInButton->setEnabled(true);
- m_zoomOutButton->setEnabled(true);
+ setZoomButtonsEnabled(true);
replaceAllChildWidgets(m_formatterWidget->layout(), rc->outputFormatter() ?
rc->outputFormatter()->toolbarWidgets() :
@@ -670,8 +698,7 @@ void AppOutputPane::enableButtons(const RunControl *rc)
m_attachButton->setEnabled(false);
m_attachButton->setToolTip(msgAttachDebuggerTooltip());
m_stopAction->setEnabled(false);
- m_zoomInButton->setEnabled(false);
- m_zoomOutButton->setEnabled(false);
+ setZoomButtonsEnabled(false);
}
m_formatterWidget->setVisible(m_formatterWidget->layout()->count());
}
@@ -680,7 +707,10 @@ void AppOutputPane::tabChanged(int i)
{
const int index = indexOf(m_tabWidget->widget(i));
if (i != -1 && index != -1) {
- enableButtons(m_runControlTabs.at(index).runControl);
+ const RunControlTab &controlTab = m_runControlTabs[index];
+ controlTab.window->updateFilterProperties(filterText(), filterCaseSensitivity(),
+ filterUsesRegexp());
+ enableButtons(controlTab.runControl);
} else {
enableDefaultButtons();
}
@@ -729,9 +759,8 @@ void AppOutputPane::slotRunControlFinished2(RunControl *sender)
// Enable buttons for current
RunControl *current = currentRunControl();
- if (debug)
- qDebug() << "OutputPane::runControlFinished" << sender << senderIndex
- << " current " << current << m_runControlTabs.size();
+ qCDebug(appOutputLog) << "AppOutputPane::runControlFinished" << sender << senderIndex
+ << "current" << current << m_runControlTabs.size();
if (current && current == sender)
enableButtons(current);
@@ -773,5 +802,87 @@ bool AppOutputPane::canNavigate() const
return false;
}
+class AppOutputSettingsPage::SettingsWidget : public QWidget
+{
+ Q_DECLARE_TR_FUNCTIONS(ProjectExplorer::Internal::AppOutputSettingsPage)
+public:
+ SettingsWidget()
+ {
+ const AppOutputSettings &settings = ProjectExplorerPlugin::appOutputSettings();
+ m_wrapOutputCheckBox.setText(tr("Word-wrap output"));
+ m_wrapOutputCheckBox.setChecked(settings.wrapOutput);
+ m_cleanOldOutputCheckBox.setText(tr("Clear old output on a new run"));
+ m_cleanOldOutputCheckBox.setChecked(settings.cleanOldOutput);
+ m_mergeChannelsCheckBox.setText(tr("Merge stderr and stdout"));
+ m_mergeChannelsCheckBox.setChecked(settings.mergeChannels);
+ m_popUpForRunOutputCheckBox.setText(tr("Open pane on output when running"));
+ m_popUpForRunOutputCheckBox.setChecked(settings.popUpForRunOutput);
+ m_popUpForDebugOutputCheckBox.setText(tr("Open pane on output when debugging"));
+ m_popUpForDebugOutputCheckBox.setChecked(settings.popUpForDebugOutput);
+ m_maxCharsBox.setMaximum(100000000);
+ m_maxCharsBox.setValue(settings.maxCharCount);
+ const auto layout = new QVBoxLayout(this);
+ layout->addWidget(&m_wrapOutputCheckBox);
+ layout->addWidget(&m_cleanOldOutputCheckBox);
+ layout->addWidget(&m_mergeChannelsCheckBox);
+ layout->addWidget(&m_popUpForRunOutputCheckBox);
+ layout->addWidget(&m_popUpForDebugOutputCheckBox);
+ const auto maxCharsLayout = new QHBoxLayout;
+ const QString msg = tr("Limit output to %1 characters");
+ const QStringList parts = msg.split("%1") << QString() << QString();
+ maxCharsLayout->addWidget(new QLabel(parts.at(0).trimmed()));
+ maxCharsLayout->addWidget(&m_maxCharsBox);
+ maxCharsLayout->addWidget(new QLabel(parts.at(1).trimmed()));
+ maxCharsLayout->addStretch(1);
+ layout->addLayout(maxCharsLayout);
+ layout->addStretch(1);
+ }
+
+ AppOutputSettings settings() const
+ {
+ AppOutputSettings s;
+ s.wrapOutput = m_wrapOutputCheckBox.isChecked();
+ s.cleanOldOutput = m_cleanOldOutputCheckBox.isChecked();
+ s.mergeChannels = m_mergeChannelsCheckBox.isChecked();
+ s.popUpForRunOutput = m_popUpForRunOutputCheckBox.isChecked();
+ s.popUpForDebugOutput = m_popUpForDebugOutputCheckBox.isChecked();
+ s.maxCharCount = m_maxCharsBox.value();
+ return s;
+ }
+
+private:
+ QCheckBox m_wrapOutputCheckBox;
+ QCheckBox m_cleanOldOutputCheckBox;
+ QCheckBox m_mergeChannelsCheckBox;
+ QCheckBox m_popUpForRunOutputCheckBox;
+ QCheckBox m_popUpForDebugOutputCheckBox;
+ QSpinBox m_maxCharsBox;
+};
+
+AppOutputSettingsPage::AppOutputSettingsPage()
+{
+ setId(OPTIONS_PAGE_ID);
+ setDisplayName(tr("Application Output"));
+ setCategory(Constants::BUILD_AND_RUN_SETTINGS_CATEGORY);
+}
+
+QWidget *AppOutputSettingsPage::widget()
+{
+ if (!m_widget)
+ m_widget = new SettingsWidget;
+ return m_widget;
+}
+
+void AppOutputSettingsPage::apply()
+{
+ if (m_widget)
+ ProjectExplorerPlugin::setAppOutputSettings(m_widget->settings());
+}
+
+void AppOutputSettingsPage::finish()
+{
+ delete m_widget;
+}
+
#include "appoutputpane.moc"
diff --git a/src/plugins/projectexplorer/appoutputpane.h b/src/plugins/projectexplorer/appoutputpane.h
index fc7ac6e05e..6d7936042e 100644
--- a/src/plugins/projectexplorer/appoutputpane.h
+++ b/src/plugins/projectexplorer/appoutputpane.h
@@ -25,13 +25,16 @@
#pragma once
-#include <QPointer>
-#include <QVector>
+#include "projectexplorersettings.h"
#include <coreplugin/ioutputpane.h>
+#include <coreplugin/dialogs/ioptionspage.h>
#include <utils/outputformat.h>
+#include <QPointer>
+#include <QVector>
+
QT_BEGIN_NAMESPACE
class QTabWidget;
class QToolButton;
@@ -98,6 +101,9 @@ public:
void appendMessage(ProjectExplorer::RunControl *rc, const QString &out,
Utils::OutputFormat format);
+ const AppOutputSettings &settings() const { return m_settings; }
+ void setSettings(const AppOutputSettings &settings);
+
private:
void reRunRunControl();
void stopRunControl();
@@ -112,8 +118,9 @@ private:
void updateFromSettings();
void enableDefaultButtons();
- void zoomIn();
- void zoomOut();
+ void zoomIn(int range);
+ void zoomOut(int range);
+ void resetZoom();
void enableButtons(const RunControl *rc);
@@ -136,9 +143,10 @@ private:
int tabWidgetIndexOf(int runControlIndex) const;
void handleOldOutput(Core::OutputWindow *window) const;
void updateCloseActions();
- void updateFontSettings();
- void saveSettings();
- void updateBehaviorSettings();
+ void updateFilter() override;
+
+ void loadSettings();
+ void storeSettings() const;
QWidget *m_mainWidget;
TabWidget *m_tabWidget;
@@ -151,10 +159,25 @@ private:
QToolButton *m_reRunButton;
QToolButton *m_stopButton;
QToolButton *m_attachButton;
- QToolButton *m_zoomInButton;
- QToolButton *m_zoomOutButton;
+ QToolButton * const m_settingsButton;
QWidget *m_formatterWidget;
- float m_zoom;
+ AppOutputSettings m_settings;
+};
+
+class AppOutputSettingsPage : public Core::IOptionsPage
+{
+ Q_OBJECT
+
+public:
+ AppOutputSettingsPage();
+
+private:
+ QWidget *widget() override;
+ void apply() override;
+ void finish() override;
+
+ class SettingsWidget;
+ QPointer<SettingsWidget> m_widget;
};
} // namespace Internal
diff --git a/src/plugins/projectexplorer/baseprojectwizarddialog.cpp b/src/plugins/projectexplorer/baseprojectwizarddialog.cpp
index cb0734f226..14551d1d44 100644
--- a/src/plugins/projectexplorer/baseprojectwizarddialog.cpp
+++ b/src/plugins/projectexplorer/baseprojectwizarddialog.cpp
@@ -142,7 +142,7 @@ void BaseProjectWizardDialog::slotAccepted()
{
if (d->introPage->useAsDefaultPath()) {
// Store the path as default path for new projects if desired.
- Core::DocumentManager::setProjectsDirectory(Utils::FileName::fromString(path()));
+ Core::DocumentManager::setProjectsDirectory(Utils::FilePath::fromString(path()));
Core::DocumentManager::setUseProjectsDirectory(true);
}
}
diff --git a/src/plugins/projectexplorer/buildconfiguration.cpp b/src/plugins/projectexplorer/buildconfiguration.cpp
index 7973ed4c05..e267822b97 100644
--- a/src/plugins/projectexplorer/buildconfiguration.cpp
+++ b/src/plugins/projectexplorer/buildconfiguration.cpp
@@ -28,10 +28,12 @@
#include "buildenvironmentwidget.h"
#include "buildinfo.h"
#include "buildsteplist.h"
+#include "namedwidget.h"
#include "kit.h"
#include "kitinformation.h"
#include "kitmanager.h"
#include "project.h"
+#include "projectconfigurationaspects.h"
#include "projectexplorer.h"
#include "projectexplorerconstants.h"
#include "projectmacroexpander.h"
@@ -40,13 +42,15 @@
#include <coreplugin/idocument.h>
-#include <utils/qtcassert.h>
-#include <utils/macroexpander.h>
#include <utils/algorithm.h>
-#include <utils/mimetypes/mimetype.h>
+#include <utils/detailswidget.h>
+#include <utils/macroexpander.h>
#include <utils/mimetypes/mimedatabase.h>
+#include <utils/mimetypes/mimetype.h>
+#include <utils/qtcassert.h>
#include <QDebug>
+#include <QFormLayout>
static const char BUILD_STEP_LIST_COUNT[] = "ProjectExplorer.BuildConfiguration.BuildStepListCount";
static const char BUILD_STEP_LIST_PREFIX[] = "ProjectExplorer.BuildConfiguration.BuildStepList.";
@@ -82,27 +86,74 @@ BuildConfiguration::BuildConfiguration(Target *target, Core::Id id)
// Many macroexpanders are based on the current project, so they may change the environment:
connect(ProjectTree::instance(), &ProjectTree::currentProjectChanged,
this, &BuildConfiguration::updateCacheAndEmitEnvironmentChanged);
+
+ m_buildDirectoryAspect = addAspect<BaseStringAspect>();
+ m_buildDirectoryAspect->setSettingsKey(BUILDDIRECTORY_KEY);
+ m_buildDirectoryAspect->setLabelText(tr("Build directory:"));
+ m_buildDirectoryAspect->setDisplayStyle(BaseStringAspect::PathChooserDisplay);
+ m_buildDirectoryAspect->setExpectedKind(Utils::PathChooser::Directory);
+ m_buildDirectoryAspect->setBaseFileName(target->project()->projectDirectory());
+ m_buildDirectoryAspect->setEnvironment(environment());
+ connect(m_buildDirectoryAspect, &BaseStringAspect::changed,
+ this, &BuildConfiguration::buildDirectoryChanged);
+
+ connect(this, &BuildConfiguration::environmentChanged, this, [this] {
+ m_buildDirectoryAspect->setEnvironment(environment());
+ });
}
-Utils::FileName BuildConfiguration::buildDirectory() const
+Utils::FilePath BuildConfiguration::buildDirectory() const
{
- const QString path = QDir::cleanPath(macroExpander()->expand(environment().expandVariables(m_buildDirectory.toString())));
- return Utils::FileName::fromString(QDir::cleanPath(QDir(target()->project()->projectDirectory().toString()).absoluteFilePath(path)));
+ QString path = environment().expandVariables(m_buildDirectoryAspect->value().trimmed());
+ path = QDir::cleanPath(macroExpander()->expand(path));
+ return Utils::FilePath::fromString(QDir::cleanPath(QDir(target()->project()->projectDirectory().toString()).absoluteFilePath(path)));
}
-Utils::FileName BuildConfiguration::rawBuildDirectory() const
+Utils::FilePath BuildConfiguration::rawBuildDirectory() const
{
- return m_buildDirectory;
+ return m_buildDirectoryAspect->fileName();
}
-void BuildConfiguration::setBuildDirectory(const Utils::FileName &dir)
+void BuildConfiguration::setBuildDirectory(const Utils::FilePath &dir)
{
- if (dir == m_buildDirectory)
+ if (dir == m_buildDirectoryAspect->fileName())
return;
- m_buildDirectory = dir;
+ m_buildDirectoryAspect->setFileName(dir);
emitBuildDirectoryChanged();
}
+NamedWidget *BuildConfiguration::createConfigWidget()
+{
+ NamedWidget *named = new NamedWidget;
+ named->setDisplayName(m_configWidgetDisplayName);
+
+ QWidget *widget = nullptr;
+
+ if (m_configWidgetHasFrame) {
+ auto container = new Utils::DetailsWidget(named);
+ widget = new QWidget(container);
+ container->setState(Utils::DetailsWidget::NoSummary);
+ container->setWidget(widget);
+
+ auto vbox = new QVBoxLayout(named);
+ vbox->setMargin(0);
+ vbox->addWidget(container);
+ } else {
+ widget = named;
+ }
+
+ auto formLayout = new QFormLayout(widget);
+ formLayout->setMargin(0);
+ formLayout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
+
+ for (ProjectConfigurationAspect *aspect : aspects()) {
+ if (aspect->isVisible())
+ aspect->addToConfigurationLayout(formLayout);
+ }
+
+ return named;
+}
+
void BuildConfiguration::initialize(const BuildInfo &info)
{
setDisplayName(info.displayName);
@@ -133,7 +184,6 @@ QVariantMap BuildConfiguration::toMap() const
QVariantMap map(ProjectConfiguration::toMap());
map.insert(QLatin1String(CLEAR_SYSTEM_ENVIRONMENT_KEY), m_clearSystemEnvironment);
map.insert(QLatin1String(USER_ENVIRONMENT_CHANGES_KEY), Utils::EnvironmentItem::toStringList(m_userEnvironmentChanges));
- map.insert(QLatin1String(BUILDDIRECTORY_KEY), m_buildDirectory.toString());
map.insert(QLatin1String(BUILD_STEP_LIST_COUNT), m_stepLists.count());
for (int i = 0; i < m_stepLists.count(); ++i)
@@ -146,7 +196,6 @@ bool BuildConfiguration::fromMap(const QVariantMap &map)
{
m_clearSystemEnvironment = map.value(QLatin1String(CLEAR_SYSTEM_ENVIRONMENT_KEY)).toBool();
m_userEnvironmentChanges = Utils::EnvironmentItem::fromStringList(map.value(QLatin1String(USER_ENVIRONMENT_CHANGES_KEY)).toStringList());
- m_buildDirectory = Utils::FileName::fromString(map.value(QLatin1String(BUILDDIRECTORY_KEY)).toString());
updateCacheAndEmitEnvironmentChanged();
@@ -194,6 +243,31 @@ void BuildConfiguration::emitBuildDirectoryChanged()
}
}
+ProjectExplorer::BaseStringAspect *BuildConfiguration::buildDirectoryAspect() const
+{
+ return m_buildDirectoryAspect;
+}
+
+void BuildConfiguration::setConfigWidgetDisplayName(const QString &display)
+{
+ m_configWidgetDisplayName = display;
+}
+
+void BuildConfiguration::setBuildDirectoryHistoryCompleter(const QString &history)
+{
+ m_buildDirectoryAspect->setHistoryCompleter(history);
+}
+
+void BuildConfiguration::setConfigWidgetHasFrame(bool configWidgetHasFrame)
+{
+ m_configWidgetHasFrame = configWidgetHasFrame;
+}
+
+void BuildConfiguration::setBuildDirectorySettingsKey(const QString &key)
+{
+ m_buildDirectoryAspect->setSettingsKey(key);
+}
+
Target *BuildConfiguration::target() const
{
return static_cast<Target *>(parent());
@@ -299,20 +373,16 @@ bool BuildConfiguration::isActive() const
* PATH. This is used to in build configurations targeting broken build systems
* to provide hints about which compiler to use.
*/
-void BuildConfiguration::prependCompilerPathToEnvironment(Utils::Environment &env) const
-{
- return prependCompilerPathToEnvironment(target()->kit(), env);
-}
void BuildConfiguration::prependCompilerPathToEnvironment(Kit *k, Utils::Environment &env)
{
const ToolChain *tc
- = ToolChainKitInformation::toolChain(k, ProjectExplorer::Constants::CXX_LANGUAGE_ID);
+ = ToolChainKitAspect::toolChain(k, ProjectExplorer::Constants::CXX_LANGUAGE_ID);
if (!tc)
return;
- const Utils::FileName compilerDir = tc->compilerCommand().parentDir();
+ const Utils::FilePath compilerDir = tc->compilerCommand().parentDir();
if (!compilerDir.isEmpty())
env.prependOrSetPath(compilerDir.toString());
}
@@ -334,7 +404,7 @@ BuildConfigurationFactory::~BuildConfigurationFactory()
g_buildConfigurationFactories.removeOne(this);
}
-const QList<Task> BuildConfigurationFactory::reportIssues(ProjectExplorer::Kit *kit, const QString &projectPath,
+const Tasks BuildConfigurationFactory::reportIssues(ProjectExplorer::Kit *kit, const QString &projectPath,
const QString &buildDir) const
{
if (m_issueReporter)
@@ -363,7 +433,7 @@ bool BuildConfigurationFactory::supportsTargetDeviceType(Core::Id id) const
BuildConfigurationFactory *BuildConfigurationFactory::find(const Kit *k, const QString &projectPath)
{
QTC_ASSERT(k, return nullptr);
- const Core::Id deviceType = DeviceTypeKitInformation::deviceTypeId(k);
+ const Core::Id deviceType = DeviceTypeKitAspect::deviceTypeId(k);
for (BuildConfigurationFactory *factory : g_buildConfigurationFactories) {
if (Utils::mimeTypeForFile(projectPath).matchesName(factory->m_supportedProjectMimeTypeName)
&& factory->supportsTargetDeviceType(deviceType))
@@ -405,7 +475,7 @@ bool BuildConfigurationFactory::canHandle(const Target *target) const
if (containsType(target->project()->projectIssues(target->kit()), Task::TaskType::Error))
return false;
- if (!supportsTargetDeviceType(DeviceTypeKitInformation::deviceTypeId(target->kit())))
+ if (!supportsTargetDeviceType(DeviceTypeKitAspect::deviceTypeId(target->kit())))
return false;
return true;
diff --git a/src/plugins/projectexplorer/buildconfiguration.h b/src/plugins/projectexplorer/buildconfiguration.h
index c40a9d82a6..c9ba394946 100644
--- a/src/plugins/projectexplorer/buildconfiguration.h
+++ b/src/plugins/projectexplorer/buildconfiguration.h
@@ -27,20 +27,20 @@
#include "projectexplorer_export.h"
#include "projectconfiguration.h"
+#include "task.h"
#include <utils/environment.h>
#include <utils/fileutils.h>
namespace ProjectExplorer {
+class BaseStringAspect;
class BuildInfo;
-class NamedWidget;
class BuildStepList;
-class Node;
class Kit;
+class NamedWidget;
+class Node;
class Target;
-class Task;
-class IOutputParser;
class PROJECTEXPLORER_EXPORT BuildConfiguration : public ProjectConfiguration
{
@@ -51,11 +51,11 @@ protected:
explicit BuildConfiguration(Target *target, Core::Id id);
public:
- Utils::FileName buildDirectory() const;
- Utils::FileName rawBuildDirectory() const;
- void setBuildDirectory(const Utils::FileName &dir);
+ Utils::FilePath buildDirectory() const;
+ Utils::FilePath rawBuildDirectory() const;
+ void setBuildDirectory(const Utils::FilePath &dir);
- virtual NamedWidget *createConfigWidget() = 0;
+ virtual NamedWidget *createConfigWidget();
virtual QList<NamedWidget *> createSubConfigWidgets();
// Maybe the BuildConfiguration is not the best place for the environment
@@ -95,10 +95,15 @@ public:
bool isActive() const override;
- void prependCompilerPathToEnvironment(Utils::Environment &env) const;
static void prependCompilerPathToEnvironment(Kit *k, Utils::Environment &env);
void updateCacheAndEmitEnvironmentChanged();
+ ProjectExplorer::BaseStringAspect *buildDirectoryAspect() const;
+ void setConfigWidgetDisplayName(const QString &display);
+ void setBuildDirectoryHistoryCompleter(const QString &history);
+ void setConfigWidgetHasFrame(bool configWidgetHasFrame);
+ void setBuildDirectorySettingsKey(const QString &key);
+
signals:
void environmentChanged();
void buildDirectoryChanged();
@@ -114,9 +119,11 @@ private:
bool m_clearSystemEnvironment = false;
QList<Utils::EnvironmentItem> m_userEnvironmentChanges;
QList<BuildStepList *> m_stepLists;
- Utils::FileName m_buildDirectory;
- Utils::FileName m_lastEmmitedBuildDirectory;
+ ProjectExplorer::BaseStringAspect *m_buildDirectoryAspect = nullptr;
+ Utils::FilePath m_lastEmmitedBuildDirectory;
mutable Utils::Environment m_cachedEnvironment;
+ QString m_configWidgetDisplayName;
+ bool m_configWidgetHasFrame = false;
};
class PROJECTEXPLORER_EXPORT BuildConfigurationFactory : public QObject
@@ -143,10 +150,10 @@ public:
static BuildConfigurationFactory *find(const Kit *k, const QString &projectPath);
static BuildConfigurationFactory *find(Target *parent);
- using IssueReporter = std::function<QList<ProjectExplorer::Task>(Kit *, const QString &, const QString &)>;
+ using IssueReporter = std::function<Tasks(Kit *, const QString &, const QString &)>;
void setIssueReporter(const IssueReporter &issueReporter);
- const QList<Task> reportIssues(ProjectExplorer::Kit *kit,
- const QString &projectPath, const QString &buildDir) const;
+ const Tasks reportIssues(ProjectExplorer::Kit *kit,
+ const QString &projectPath, const QString &buildDir) const;
protected:
virtual QList<BuildInfo> availableBuilds(const Target *parent) const = 0;
diff --git a/src/plugins/projectexplorer/buildenvironmentwidget.cpp b/src/plugins/projectexplorer/buildenvironmentwidget.cpp
index 3177f7e6b1..047412fbf3 100644
--- a/src/plugins/projectexplorer/buildenvironmentwidget.cpp
+++ b/src/plugins/projectexplorer/buildenvironmentwidget.cpp
@@ -43,7 +43,8 @@ BuildEnvironmentWidget::BuildEnvironmentWidget(BuildConfiguration *bc) :
m_clearSystemEnvironmentCheckBox = new QCheckBox(this);
m_clearSystemEnvironmentCheckBox->setText(tr("Clear system environment"));
- m_buildEnvironmentWidget = new EnvironmentWidget(this, m_clearSystemEnvironmentCheckBox);
+ m_buildEnvironmentWidget = new EnvironmentWidget(this, EnvironmentWidget::TypeLocal,
+ m_clearSystemEnvironmentCheckBox);
vbox->addWidget(m_buildEnvironmentWidget);
connect(m_buildEnvironmentWidget, &EnvironmentWidget::userChangesChanged,
diff --git a/src/plugins/projectexplorer/buildinfo.h b/src/plugins/projectexplorer/buildinfo.h
index e135959352..41dfd78180 100644
--- a/src/plugins/projectexplorer/buildinfo.h
+++ b/src/plugins/projectexplorer/buildinfo.h
@@ -46,7 +46,7 @@ public:
QString displayName;
QString typeName;
- Utils::FileName buildDirectory;
+ Utils::FilePath buildDirectory;
Core::Id kitId;
BuildConfiguration::BuildType buildType = BuildConfiguration::Unknown;
diff --git a/src/plugins/projectexplorer/buildmanager.cpp b/src/plugins/projectexplorer/buildmanager.cpp
index 544677517a..eece545e07 100644
--- a/src/plugins/projectexplorer/buildmanager.cpp
+++ b/src/plugins/projectexplorer/buildmanager.cpp
@@ -143,6 +143,8 @@ void BuildManager::extensionsInitialized()
tr("Build System", "Category for build system issues listed under 'Issues'"));
TaskHub::addCategory(Constants::TASK_CATEGORY_DEPLOYMENT,
tr("Deployment", "Category for deployment issues listed under 'Issues'"));
+ TaskHub::addCategory(Constants::TASK_CATEGORY_AUTOTEST,
+ tr("Autotests", "Category for autotest issues listed under 'Issues'"));
}
BuildManager::~BuildManager()
@@ -186,6 +188,16 @@ int BuildManager::getErrorTaskCount()
return errors;
}
+void BuildManager::setCompileOutputSettings(const Internal::CompileOutputSettings &settings)
+{
+ d->m_outputWindow->setSettings(settings);
+}
+
+const Internal::CompileOutputSettings &BuildManager::compileOutputSettings()
+{
+ return d->m_outputWindow->settings();
+}
+
void BuildManager::cancel()
{
if (d->m_running) {
@@ -193,8 +205,6 @@ void BuildManager::cancel()
return;
d->m_canceling = true;
d->m_currentBuildStep->cancel();
- while (d->m_canceling)
- QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); // TODO: Is this really necessary?
}
}
@@ -366,7 +376,7 @@ void BuildManager::nextBuildQueue()
const QString projectName = d->m_currentBuildStep->project()->displayName();
const QString targetName = t->displayName();
addToOutputWindow(tr("Error while building/deploying project %1 (kit: %2)").arg(projectName, targetName), BuildStep::OutputFormat::Stderr);
- const QList<Task> kitTasks = t->kit()->validate();
+ const Tasks kitTasks = t->kit()->validate();
if (!kitTasks.isEmpty()) {
addToOutputWindow(tr("The kit %1 has configuration issues which might be the root cause for this problem.")
.arg(targetName), BuildStep::OutputFormat::Stderr);
@@ -436,9 +446,12 @@ bool BuildManager::buildQueueAppend(const QList<BuildStep *> &steps, QStringList
{
if (!d->m_running) {
d->m_outputWindow->clearContents();
- TaskHub::clearTasks(Constants::TASK_CATEGORY_COMPILE);
- TaskHub::clearTasks(Constants::TASK_CATEGORY_BUILDSYSTEM);
- TaskHub::clearTasks(Constants::TASK_CATEGORY_DEPLOYMENT);
+ if (ProjectExplorerPlugin::projectExplorerSettings().clearIssuesOnRebuild) {
+ TaskHub::clearTasks(Constants::TASK_CATEGORY_COMPILE);
+ TaskHub::clearTasks(Constants::TASK_CATEGORY_BUILDSYSTEM);
+ TaskHub::clearTasks(Constants::TASK_CATEGORY_DEPLOYMENT);
+ TaskHub::clearTasks(Constants::TASK_CATEGORY_AUTOTEST);
+ }
foreach (const QString &str, preambleMessage)
addToOutputWindow(str, BuildStep::OutputFormat::NormalMessage, BuildStep::DontAppendNewline);
@@ -513,7 +526,7 @@ bool BuildManager::buildLists(QList<BuildStepList *> bsls, const QStringList &pr
return false;
}
- if (ProjectExplorerPlugin::projectExplorerSettings().showCompilerOutput)
+ if (d->m_outputWindow->settings().popUp)
d->m_outputWindow->popup(IOutputPane::NoModeSwitch);
startBuildQueue();
return true;
@@ -526,7 +539,7 @@ void BuildManager::appendStep(BuildStep *step, const QString &name)
d->m_outputWindow->popup(IOutputPane::NoModeSwitch);
return;
}
- if (ProjectExplorerPlugin::projectExplorerSettings().showCompilerOutput)
+ if (d->m_outputWindow->settings().popUp)
d->m_outputWindow->popup(IOutputPane::NoModeSwitch);
startBuildQueue();
}
diff --git a/src/plugins/projectexplorer/buildmanager.h b/src/plugins/projectexplorer/buildmanager.h
index fc23bc851a..fe452d6965 100644
--- a/src/plugins/projectexplorer/buildmanager.h
+++ b/src/plugins/projectexplorer/buildmanager.h
@@ -32,6 +32,7 @@
#include <QStringList>
namespace ProjectExplorer {
+namespace Internal { class CompileOutputSettings; }
class Task;
class Project;
@@ -64,6 +65,9 @@ public:
static int getErrorTaskCount();
+ static void setCompileOutputSettings(const Internal::CompileOutputSettings &settings);
+ static const Internal::CompileOutputSettings &compileOutputSettings();
+
public slots:
static void cancel();
// Shows without focus
diff --git a/src/plugins/projectexplorer/buildsettingspropertiespage.cpp b/src/plugins/projectexplorer/buildsettingspropertiespage.cpp
index 772740abd2..481c37eef0 100644
--- a/src/plugins/projectexplorer/buildsettingspropertiespage.cpp
+++ b/src/plugins/projectexplorer/buildsettingspropertiespage.cpp
@@ -119,7 +119,7 @@ BuildSettingsWidget::BuildSettingsWidget(Target *target) :
updateAddButtonMenu();
updateBuildSettings();
- connect(m_buildConfigurationComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
+ connect(m_buildConfigurationComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &BuildSettingsWidget::currentIndexChanged);
connect(m_removeButton, &QAbstractButton::clicked,
diff --git a/src/plugins/projectexplorer/buildstep.cpp b/src/plugins/projectexplorer/buildstep.cpp
index d293b09290..35e02b8972 100644
--- a/src/plugins/projectexplorer/buildstep.cpp
+++ b/src/plugins/projectexplorer/buildstep.cpp
@@ -225,6 +225,12 @@ void BuildStep::setWidgetExpandedByDefault(bool widgetExpandedByDefault)
m_widgetExpandedByDefault = widgetExpandedByDefault;
}
+QVariant BuildStep::data(Core::Id id) const
+{
+ Q_UNUSED(id);
+ return {};
+}
+
/*!
\fn BuildStep::isImmutable()
@@ -299,7 +305,7 @@ bool BuildStepFactory::canHandle(BuildStepList *bsl) const
if (!m_supportedDeviceTypes.isEmpty()) {
Target *target = bsl->target();
QTC_ASSERT(target, return false);
- Core::Id deviceType = DeviceTypeKitInformation::deviceTypeId(target->kit());
+ Core::Id deviceType = DeviceTypeKitAspect::deviceTypeId(target->kit());
if (!m_supportedDeviceTypes.contains(deviceType))
return false;
}
diff --git a/src/plugins/projectexplorer/buildstep.h b/src/plugins/projectexplorer/buildstep.h
index 0796b87582..0abf7d5b78 100644
--- a/src/plugins/projectexplorer/buildstep.h
+++ b/src/plugins/projectexplorer/buildstep.h
@@ -28,6 +28,7 @@
#include "projectconfiguration.h"
#include "projectexplorer_export.h"
+#include <utils/optional.h>
#include <utils/qtcassert.h>
#include <QFutureInterface>
@@ -88,9 +89,14 @@ public:
bool widgetExpandedByDefault() const;
void setWidgetExpandedByDefault(bool widgetExpandedByDefault);
+ bool hasUserExpansionState() const { return m_wasExpanded.has_value(); }
+ bool wasUserExpanded() const { return m_wasExpanded.value_or(false); }
+ void setUserExpanded(bool expanded) { m_wasExpanded = expanded; }
+
bool isImmutable() const { return m_immutable; }
void setImmutable(bool immutable) { m_immutable = immutable; }
+ virtual QVariant data(Core::Id id) const;
signals:
/// Adds a \p task to the Issues pane.
/// Do note that for linking compile output with tasks, you should first emit the task
@@ -122,6 +128,7 @@ private:
bool m_immutable = false;
bool m_widgetExpandedByDefault = true;
bool m_runInGuiThread = true;
+ Utils::optional<bool> m_wasExpanded;
};
class PROJECTEXPLORER_EXPORT BuildStepInfo
diff --git a/src/plugins/projectexplorer/buildstepspage.cpp b/src/plugins/projectexplorer/buildstepspage.cpp
index a9897e610c..331ccd9f40 100644
--- a/src/plugins/projectexplorer/buildstepspage.cpp
+++ b/src/plugins/projectexplorer/buildstepspage.cpp
@@ -258,8 +258,11 @@ void BuildStepListWidget::init(BuildStepList *bsl)
for (int i = 0; i < bsl->count(); ++i) {
addBuildStep(i);
// addBuilStep expands the config widget by default, which we don't want here
- if (m_buildStepsData.at(i)->step->widgetExpandedByDefault())
- m_buildStepsData.at(i)->detailsWidget->setState(DetailsWidget::Collapsed);
+ if (m_buildStepsData.at(i)->step->widgetExpandedByDefault()) {
+ m_buildStepsData.at(i)->detailsWidget->setState(
+ m_buildStepsData.at(i)->step->wasUserExpanded()
+ ? DetailsWidget::Expanded : DetailsWidget::Collapsed);
+ }
}
m_noStepsLabel->setVisible(bsl->isEmpty());
@@ -323,10 +326,10 @@ void BuildStepListWidget::addBuildStep(int pos)
this, &BuildStepListWidget::updateEnabledState);
// Expand new build steps by default
- if (newStep->widgetExpandedByDefault())
- s->detailsWidget->setState(DetailsWidget::Expanded);
- else
- s->detailsWidget->setState(DetailsWidget::OnlySummary);
+ const bool expand = newStep->hasUserExpansionState()
+ ? newStep->wasUserExpanded() : newStep->widgetExpandedByDefault();
+ s->detailsWidget->setState(expand ? DetailsWidget::Expanded : DetailsWidget::OnlySummary);
+ connect(s->detailsWidget, &DetailsWidget::expanded, newStep, &BuildStep::setUserExpanded);
m_noStepsLabel->setVisible(false);
updateBuildStepButtonsState();
diff --git a/src/plugins/projectexplorer/buildtargetinfo.h b/src/plugins/projectexplorer/buildtargetinfo.h
index 38cadea991..28af0330a4 100644
--- a/src/plugins/projectexplorer/buildtargetinfo.h
+++ b/src/plugins/projectexplorer/buildtargetinfo.h
@@ -32,7 +32,6 @@
#include <utils/fileutils.h>
#include <QList>
-#include <QSet>
namespace ProjectExplorer {
@@ -43,9 +42,9 @@ public:
QString displayName;
QString displayNameUniquifier;
- Utils::FileName targetFilePath;
- Utils::FileName projectFilePath;
- Utils::FileName workingDirectory;
+ Utils::FilePath targetFilePath;
+ Utils::FilePath projectFilePath;
+ Utils::FilePath workingDirectory;
bool isQtcRunnable = true;
bool usesTerminal = false;
@@ -76,26 +75,4 @@ inline uint qHash(const BuildTargetInfo &ti)
return qHash(ti.displayName) ^ qHash(ti.buildKey);
}
-class PROJECTEXPLORER_EXPORT BuildTargetInfoList
-{
-public:
- BuildTargetInfo buildTargetInfo(const QString &buildKey) {
- return Utils::findOrDefault(list, [&buildKey](const BuildTargetInfo &ti) {
- return ti.buildKey == buildKey;
- });
- }
-
- QList<BuildTargetInfo> list;
-};
-
-inline bool operator==(const BuildTargetInfoList &til1, const BuildTargetInfoList &til2)
-{
- return til1.list.toSet() == til2.list.toSet();
-}
-
-inline bool operator!=(const BuildTargetInfoList &til1, const BuildTargetInfoList &til2)
-{
- return !(til1 == til2);
-}
-
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/clangparser.cpp b/src/plugins/projectexplorer/clangparser.cpp
index 98d733e69f..1859f25896 100644
--- a/src/plugins/projectexplorer/clangparser.cpp
+++ b/src/plugins/projectexplorer/clangparser.cpp
@@ -68,7 +68,7 @@ void ClangParser::stdError(const QString &line)
m_expectSnippet = true;
Task task(taskType(match.captured(3)),
match.captured(4),
- Utils::FileName(), /* filename */
+ Utils::FilePath(), /* filename */
-1, /* line */
Constants::TASK_CATEGORY_COMPILE);
newTask(task);
@@ -80,7 +80,7 @@ void ClangParser::stdError(const QString &line)
m_expectSnippet = true;
newTask(Task(Task::Unknown,
lne.trimmed(),
- Utils::FileName::fromUserInput(match.captured(2)), /* filename */
+ Utils::FilePath::fromUserInput(match.captured(2)), /* filename */
match.captured(3).toInt(), /* line */
Constants::TASK_CATEGORY_COMPILE));
return;
@@ -95,7 +95,7 @@ void ClangParser::stdError(const QString &line)
lineNo = match.captured(5).toInt(&ok);
Task task(taskType(match.captured(7)),
match.captured(8),
- Utils::FileName::fromUserInput(match.captured(1)), /* filename */
+ Utils::FilePath::fromUserInput(match.captured(1)), /* filename */
lineNo,
Core::Id(Constants::TASK_CATEGORY_COMPILE));
newTask(task);
@@ -107,7 +107,7 @@ void ClangParser::stdError(const QString &line)
m_expectSnippet = true;
Task task(Task::Error,
match.captured(1),
- Utils::FileName(),
+ Utils::FilePath(),
-1,
Core::Id(Constants::TASK_CATEGORY_COMPILE));
newTask(task);
@@ -141,7 +141,7 @@ void ProjectExplorerPlugin::testClangOutputParser_data()
QTest::addColumn<OutputParserTester::Channel>("inputChannel");
QTest::addColumn<QString>("childStdOutLines");
QTest::addColumn<QString>("childStdErrLines");
- QTest::addColumn<QList<Task> >("tasks");
+ QTest::addColumn<Tasks >("tasks");
QTest::addColumn<QString>("outputLines");
const Core::Id categoryCompile = Constants::TASK_CATEGORY_COMPILE;
@@ -149,32 +149,32 @@ void ProjectExplorerPlugin::testClangOutputParser_data()
QTest::newRow("pass-through stdout")
<< QString::fromLatin1("Sometext") << OutputParserTester::STDOUT
<< QString::fromLatin1("Sometext\n") << QString()
- << QList<Task>()
+ << Tasks()
<< QString();
QTest::newRow("pass-through stderr")
<< QString::fromLatin1("Sometext") << OutputParserTester::STDERR
<< QString() << QString::fromLatin1("Sometext\n")
- << QList<Task>()
+ << Tasks()
<< QString();
QTest::newRow("clang++ warning")
<< QString::fromLatin1("clang++: warning: argument unused during compilation: '-mthreads'")
<< OutputParserTester::STDERR
<< QString() << QString()
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Warning,
QLatin1String("argument unused during compilation: '-mthreads'"),
- Utils::FileName(), -1,
+ Utils::FilePath(), -1,
categoryCompile))
<< QString();
QTest::newRow("clang++ error")
<< QString::fromLatin1("clang++: error: no input files [err_drv_no_input_files]")
<< OutputParserTester::STDERR
<< QString() << QString()
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Error,
QLatin1String("no input files [err_drv_no_input_files]"),
- Utils::FileName(), -1,
+ Utils::FilePath(), -1,
categoryCompile))
<< QString();
QTest::newRow("complex warning")
@@ -184,16 +184,16 @@ void ProjectExplorerPlugin::testClangOutputParser_data()
" ^")
<< OutputParserTester::STDERR
<< QString() << QString()
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Unknown,
QLatin1String("In file included from ..\\..\\..\\QtSDK1.1\\Desktop\\Qt\\4.7.3\\mingw\\include/QtCore/qnamespace.h:45:"),
- Utils::FileName::fromUserInput(QLatin1String("..\\..\\..\\QtSDK1.1\\Desktop\\Qt\\4.7.3\\mingw\\include/QtCore/qnamespace.h")), 45,
+ Utils::FilePath::fromUserInput(QLatin1String("..\\..\\..\\QtSDK1.1\\Desktop\\Qt\\4.7.3\\mingw\\include/QtCore/qnamespace.h")), 45,
categoryCompile)
<< Task(Task::Warning,
QLatin1String("unknown attribute 'dllimport' ignored [-Wunknown-attributes]\n"
"class Q_CORE_EXPORT QSysInfo {\n"
" ^"),
- Utils::FileName::fromUserInput(QLatin1String("..\\..\\..\\QtSDK1.1\\Desktop\\Qt\\4.7.3\\mingw\\include/QtCore/qglobal.h")), 1425,
+ Utils::FilePath::fromUserInput(QLatin1String("..\\..\\..\\QtSDK1.1\\Desktop\\Qt\\4.7.3\\mingw\\include/QtCore/qglobal.h")), 1425,
categoryCompile))
<< QString();
QTest::newRow("note")
@@ -202,12 +202,12 @@ void ProjectExplorerPlugin::testClangOutputParser_data()
" ^")
<< OutputParserTester::STDERR
<< QString() << QString()
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Unknown,
QLatin1String("instantiated from:\n"
"# define Q_CORE_EXPORT Q_DECL_IMPORT\n"
" ^"),
- Utils::FileName::fromUserInput(QLatin1String("..\\..\\..\\QtSDK1.1\\Desktop\\Qt\\4.7.3\\mingw\\include/QtCore/qglobal.h")), 1289,
+ Utils::FilePath::fromUserInput(QLatin1String("..\\..\\..\\QtSDK1.1\\Desktop\\Qt\\4.7.3\\mingw\\include/QtCore/qglobal.h")), 1289,
categoryCompile))
<< QString();
QTest::newRow("fatal error")
@@ -216,12 +216,12 @@ void ProjectExplorerPlugin::testClangOutputParser_data()
" ^")
<< OutputParserTester::STDERR
<< QString() << QString()
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Error,
QLatin1String("'bits/c++config.h' file not found\n"
"#include <bits/c++config.h>\n"
" ^"),
- Utils::FileName::fromUserInput(QLatin1String("/usr/include/c++/4.6/utility")), 68,
+ Utils::FilePath::fromUserInput(QLatin1String("/usr/include/c++/4.6/utility")), 68,
categoryCompile))
<< QString();
@@ -231,12 +231,12 @@ void ProjectExplorerPlugin::testClangOutputParser_data()
" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^")
<< OutputParserTester::STDERR
<< QString() << QString()
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Warning,
QLatin1String("?: has lower precedence than +; + will be evaluated first [-Wparentheses]\n"
" int x = option->rect.x() + horizontal ? 2 : 6;\n"
" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^"),
- Utils::FileName::fromUserInput(QLatin1String("/home/code/src/creator/src/plugins/coreplugin/manhattanstyle.cpp")), 567,
+ Utils::FilePath::fromUserInput(QLatin1String("/home/code/src/creator/src/plugins/coreplugin/manhattanstyle.cpp")), 567,
categoryCompile))
<< QString();
QTest::newRow("code sign error")
@@ -245,24 +245,24 @@ void ProjectExplorerPlugin::testClangOutputParser_data()
"CodeSign error: code signing is required for product type 'Application' in SDK 'iOS 7.0'")
<< OutputParserTester::STDERR
<< QString() << QString::fromLatin1("Check dependencies\n")
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Error,
QLatin1String("No matching provisioning profiles found: No provisioning profiles with a valid signing identity (i.e. certificate and private key pair) were found."),
- Utils::FileName(), -1,
+ Utils::FilePath(), -1,
categoryCompile)
<< Task(Task::Error,
QLatin1String("code signing is required for product type 'Application' in SDK 'iOS 7.0'"),
- Utils::FileName(), -1,
+ Utils::FilePath(), -1,
categoryCompile))
<< QString();
QTest::newRow("moc note")
<< QString::fromLatin1("/home/qtwebkithelpviewer.h:0: Note: No relevant classes found. No output generated.")
<< OutputParserTester::STDERR
<< QString() << QString()
- << (QList<ProjectExplorer::Task>()
+ << (Tasks()
<< Task(Task::Unknown,
QLatin1String("Note: No relevant classes found. No output generated."),
- Utils::FileName::fromUserInput(QLatin1String("/home/qtwebkithelpviewer.h")), 0,
+ Utils::FilePath::fromUserInput(QLatin1String("/home/qtwebkithelpviewer.h")), 0,
categoryCompile)
)
<< QString();
@@ -274,7 +274,7 @@ void ProjectExplorerPlugin::testClangOutputParser()
testbench.appendOutputParser(new ClangParser);
QFETCH(QString, input);
QFETCH(OutputParserTester::Channel, inputChannel);
- QFETCH(QList<Task>, tasks);
+ QFETCH(Tasks, tasks);
QFETCH(QString, childStdOutLines);
QFETCH(QString, childStdErrLines);
QFETCH(QString, outputLines);
diff --git a/src/plugins/projectexplorer/codestylesettingspropertiespage.cpp b/src/plugins/projectexplorer/codestylesettingspropertiespage.cpp
index 9410c49931..5c25cb83d8 100644
--- a/src/plugins/projectexplorer/codestylesettingspropertiespage.cpp
+++ b/src/plugins/projectexplorer/codestylesettingspropertiespage.cpp
@@ -56,7 +56,7 @@ CodeStyleSettingsWidget::CodeStyleSettingsWidget(Project *project) : QWidget(),
m_ui.languageComboBox->addItem(factory->displayName());
}
- connect(m_ui.languageComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
+ connect(m_ui.languageComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
m_ui.stackedWidget, &QStackedWidget::setCurrentIndex);
}
diff --git a/src/plugins/projectexplorer/compileoutputwindow.cpp b/src/plugins/projectexplorer/compileoutputwindow.cpp
index a76ea49ea7..d92bcc4bbe 100644
--- a/src/plugins/projectexplorer/compileoutputwindow.cpp
+++ b/src/plugins/projectexplorer/compileoutputwindow.cpp
@@ -45,12 +45,17 @@
#include <utils/theme/theme.h>
#include <utils/utilsicons.h>
+#include <QCheckBox>
+#include <QHBoxLayout>
#include <QIcon>
-#include <QTextCharFormat>
+#include <QLabel>
+#include <QPlainTextEdit>
+#include <QSpinBox>
#include <QTextBlock>
+#include <QTextCharFormat>
#include <QTextCursor>
-#include <QPlainTextEdit>
#include <QToolButton>
+#include <QVBoxLayout>
using namespace ProjectExplorer;
using namespace ProjectExplorer::Internal;
@@ -58,6 +63,10 @@ using namespace ProjectExplorer::Internal;
namespace {
const char SETTINGS_KEY[] = "ProjectExplorer/CompileOutput/Zoom";
const char C_COMPILE_OUTPUT[] = "ProjectExplorer.CompileOutput";
+const char POP_UP_KEY[] = "ProjectExplorer/Settings/ShowCompilerOutput";
+const char WRAP_OUTPUT_KEY[] = "ProjectExplorer/Settings/WrapBuildOutput";
+const char MAX_LINES_KEY[] = "ProjectExplorer/Settings/MaxBuildOutputLines";
+const char OPTIONS_PAGE_ID[] = "C.ProjectExplorer.CompileOutputOptions";
}
namespace ProjectExplorer {
@@ -67,31 +76,11 @@ class CompileOutputTextEdit : public Core::OutputWindow
{
Q_OBJECT
public:
- CompileOutputTextEdit(const Core::Context &context) : Core::OutputWindow(context)
+ CompileOutputTextEdit(const Core::Context &context) : Core::OutputWindow(context, SETTINGS_KEY)
{
- setWheelZoomEnabled(true);
-
- QSettings *settings = Core::ICore::settings();
- float zoom = settings->value(QLatin1String(SETTINGS_KEY), 0).toFloat();
- setFontZoom(zoom);
-
- fontSettingsChanged();
-
- connect(TextEditor::TextEditorSettings::instance(), &TextEditor::TextEditorSettings::fontSettingsChanged,
- this, &CompileOutputTextEdit::fontSettingsChanged);
-
- connect(Core::ICore::instance(), &Core::ICore::saveSettingsRequested,
- this, &CompileOutputTextEdit::saveSettings);
-
setMouseTracking(true);
}
- void saveSettings()
- {
- QSettings *settings = Core::ICore::settings();
- settings->setValue(QLatin1String(SETTINGS_KEY), fontZoom());
- }
-
void addTask(const Task &task, int blocknumber)
{
m_taskids.insert(blocknumber, task.taskId);
@@ -101,11 +90,6 @@ public:
{
m_taskids.clear();
}
-private:
- void fontSettingsChanged()
- {
- setBaseFont(TextEditor::TextEditorSettings::fontSettings().font());
- }
protected:
void mouseMoveEvent(QMouseEvent *ev) override
@@ -149,8 +133,7 @@ private:
CompileOutputWindow::CompileOutputWindow(QAction *cancelBuildAction) :
m_cancelBuildButton(new QToolButton),
- m_zoomInButton(new QToolButton),
- m_zoomOutButton(new QToolButton),
+ m_settingsButton(new QToolButton),
m_formatter(new Utils::OutputFormatter)
{
Core::Context context(C_COMPILE_OUTPUT);
@@ -175,21 +158,34 @@ CompileOutputWindow::CompileOutputWindow(QAction *cancelBuildAction) :
Utils::ProxyAction::proxyActionWithIcon(cancelBuildAction,
Utils::Icons::STOP_SMALL_TOOLBAR.icon());
m_cancelBuildButton->setDefaultAction(cancelBuildProxyButton);
- m_zoomInButton->setToolTip(tr("Increase Font Size"));
- m_zoomInButton->setIcon(Utils::Icons::PLUS_TOOLBAR.icon());
- m_zoomOutButton->setToolTip(tr("Decrease Font Size"));
- m_zoomOutButton->setIcon(Utils::Icons::MINUS.icon());
+ m_settingsButton->setToolTip(tr("Open Settings Page"));
+ m_settingsButton->setIcon(Utils::Icons::SETTINGS_TOOLBAR.icon());
+
+ auto updateFontSettings = [this] {
+ m_outputWindow->setBaseFont(TextEditor::TextEditorSettings::fontSettings().font());
+ };
+ auto updateZoomEnabled = [this] {
+ m_outputWindow->setWheelZoomEnabled(
+ TextEditor::TextEditorSettings::behaviorSettings().m_scrollWheelZooming);
+ };
+
+ updateFontSettings();
updateZoomEnabled();
+ setupFilterUi("CompileOutputPane.Filter");
+ setFilteringEnabled(true);
- connect(TextEditor::TextEditorSettings::instance(),
- &TextEditor::TextEditorSettings::behaviorSettingsChanged,
- this, &CompileOutputWindow::updateZoomEnabled);
+ connect(this, &IOutputPane::zoomIn, m_outputWindow, &Core::OutputWindow::zoomIn);
+ connect(this, &IOutputPane::zoomOut, m_outputWindow, &Core::OutputWindow::zoomOut);
+ connect(this, &IOutputPane::resetZoom, m_outputWindow, &Core::OutputWindow::resetZoom);
+ connect(TextEditor::TextEditorSettings::instance(), &TextEditor::TextEditorSettings::fontSettingsChanged,
+ this, updateFontSettings);
+ connect(TextEditor::TextEditorSettings::instance(), &TextEditor::TextEditorSettings::behaviorSettingsChanged,
+ this, updateZoomEnabled);
- connect(m_zoomInButton, &QToolButton::clicked,
- this, [this]() { m_outputWindow->zoomIn(1); });
- connect(m_zoomOutButton, &QToolButton::clicked,
- this, [this]() { m_outputWindow->zoomOut(1); });
+ connect(m_settingsButton, &QToolButton::clicked, this, [] {
+ Core::ICore::showOptionsDialog(OPTIONS_PAGE_ID);
+ });
auto agg = new Aggregation::Aggregate;
agg->add(m_outputWindow);
@@ -199,8 +195,8 @@ CompileOutputWindow::CompileOutputWindow(QAction *cancelBuildAction) :
m_handler = new ShowOutputTaskHandler(this);
ExtensionSystem::PluginManager::addObject(m_handler);
- connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::settingsChanged,
- this, &CompileOutputWindow::updateFromSettings);
+ setupContext(C_COMPILE_OUTPUT, m_outputWindow);
+ loadSettings();
updateFromSettings();
}
@@ -209,25 +205,14 @@ CompileOutputWindow::~CompileOutputWindow()
ExtensionSystem::PluginManager::removeObject(m_handler);
delete m_handler;
delete m_cancelBuildButton;
- delete m_zoomInButton;
- delete m_zoomOutButton;
+ delete m_settingsButton;
delete m_formatter;
}
-void CompileOutputWindow::updateZoomEnabled()
-{
- const TextEditor::BehaviorSettings &settings
- = TextEditor::TextEditorSettings::behaviorSettings();
- bool zoomEnabled = settings.m_scrollWheelZooming;
- m_zoomInButton->setEnabled(zoomEnabled);
- m_zoomOutButton->setEnabled(zoomEnabled);
- m_outputWindow->setWheelZoomEnabled(zoomEnabled);
-}
-
void CompileOutputWindow::updateFromSettings()
{
- m_outputWindow->setWordWrapEnabled(ProjectExplorerPlugin::projectExplorerSettings().wrapAppOutput);
- m_outputWindow->setMaxCharCount(ProjectExplorerPlugin::projectExplorerSettings().maxBuildOutputChars);
+ m_outputWindow->setWordWrapEnabled(m_settings.wrapOutput);
+ m_outputWindow->setMaxCharCount(m_settings.maxCharCount);
}
bool CompileOutputWindow::hasFocus() const
@@ -252,7 +237,7 @@ QWidget *CompileOutputWindow::outputWidget(QWidget *)
QList<QWidget *> CompileOutputWindow::toolBarWidgets() const
{
- return {m_cancelBuildButton, m_zoomInButton, m_zoomOutButton};
+ return QList<QWidget *>{m_cancelBuildButton, m_settingsButton} + IOutputPane::toolBarWidgets();
}
void CompileOutputWindow::appendText(const QString &text, BuildStep::OutputFormat format)
@@ -359,4 +344,101 @@ void CompileOutputWindow::flush()
m_formatter->flush();
}
+void CompileOutputWindow::setSettings(const CompileOutputSettings &settings)
+{
+ m_settings = settings;
+ storeSettings();
+ updateFromSettings();
+}
+
+void CompileOutputWindow::updateFilter()
+{
+ m_outputWindow->updateFilterProperties(filterText(), filterCaseSensitivity(),
+ filterUsesRegexp());
+}
+
+void CompileOutputWindow::loadSettings()
+{
+ QSettings * const s = Core::ICore::settings();
+ m_settings.popUp = s->value(POP_UP_KEY, false).toBool();
+ m_settings.wrapOutput = s->value(WRAP_OUTPUT_KEY, true).toBool();
+ m_settings.maxCharCount = s->value(MAX_LINES_KEY,
+ Core::Constants::DEFAULT_MAX_CHAR_COUNT).toInt() * 100;
+}
+
+void CompileOutputWindow::storeSettings() const
+{
+ QSettings * const s = Core::ICore::settings();
+ s->setValue(POP_UP_KEY, m_settings.popUp);
+ s->setValue(WRAP_OUTPUT_KEY, m_settings.wrapOutput);
+ s->setValue(MAX_LINES_KEY, m_settings.maxCharCount / 100);
+}
+
+class CompileOutputSettingsPage::SettingsWidget : public QWidget
+{
+ Q_DECLARE_TR_FUNCTIONS(ProjectExplorer::Internal::CompileOutputSettingsPage)
+public:
+ SettingsWidget()
+ {
+ const CompileOutputSettings &settings = BuildManager::compileOutputSettings();
+ m_wrapOutputCheckBox.setText(tr("Word-wrap output"));
+ m_wrapOutputCheckBox.setChecked(settings.wrapOutput);
+ m_popUpCheckBox.setText(tr("Open pane when building"));
+ m_popUpCheckBox.setChecked(settings.popUp);
+ m_maxCharsBox.setMaximum(100000000);
+ m_maxCharsBox.setValue(settings.maxCharCount);
+ const auto layout = new QVBoxLayout(this);
+ layout->addWidget(&m_wrapOutputCheckBox);
+ layout->addWidget(&m_popUpCheckBox);
+ const auto maxCharsLayout = new QHBoxLayout;
+ const QString msg = tr("Limit output to %1 characters");
+ const QStringList parts = msg.split("%1") << QString() << QString();
+ maxCharsLayout->addWidget(new QLabel(parts.at(0).trimmed()));
+ maxCharsLayout->addWidget(&m_maxCharsBox);
+ maxCharsLayout->addWidget(new QLabel(parts.at(1).trimmed()));
+ maxCharsLayout->addStretch(1);
+ layout->addLayout(maxCharsLayout);
+ layout->addStretch(1);
+ }
+
+ CompileOutputSettings settings() const
+ {
+ CompileOutputSettings s;
+ s.wrapOutput = m_wrapOutputCheckBox.isChecked();
+ s.popUp = m_popUpCheckBox.isChecked();
+ s.maxCharCount = m_maxCharsBox.value();
+ return s;
+ }
+
+private:
+ QCheckBox m_wrapOutputCheckBox;
+ QCheckBox m_popUpCheckBox;
+ QSpinBox m_maxCharsBox;
+};
+
+CompileOutputSettingsPage::CompileOutputSettingsPage()
+{
+ setId(OPTIONS_PAGE_ID);
+ setDisplayName(tr("Compile Output"));
+ setCategory(Constants::BUILD_AND_RUN_SETTINGS_CATEGORY);
+}
+
+QWidget *CompileOutputSettingsPage::widget()
+{
+ if (!m_widget)
+ m_widget = new SettingsWidget;
+ return m_widget;
+}
+
+void CompileOutputSettingsPage::apply()
+{
+ if (m_widget)
+ BuildManager::setCompileOutputSettings(m_widget->settings());
+}
+
+void CompileOutputSettingsPage::finish()
+{
+ delete m_widget;
+}
+
#include "compileoutputwindow.moc"
diff --git a/src/plugins/projectexplorer/compileoutputwindow.h b/src/plugins/projectexplorer/compileoutputwindow.h
index 9ff9c8ac92..a8a5303fc6 100644
--- a/src/plugins/projectexplorer/compileoutputwindow.h
+++ b/src/plugins/projectexplorer/compileoutputwindow.h
@@ -26,10 +26,13 @@
#pragma once
#include "buildstep.h"
+#include "projectexplorersettings.h"
+#include <coreplugin/dialogs/ioptionspage.h>
#include <coreplugin/ioutputpane.h>
#include <QHash>
#include <QPair>
+#include <QPointer>
QT_BEGIN_NAMESPACE
class QPlainTextEdit;
@@ -81,17 +84,39 @@ public:
void flush();
+ const CompileOutputSettings &settings() const { return m_settings; }
+ void setSettings(const CompileOutputSettings &settings);
+
private:
+ void updateFilter() override;
+
+ void loadSettings();
+ void storeSettings() const;
void updateFromSettings();
- void updateZoomEnabled();
CompileOutputTextEdit *m_outputWindow;
QHash<unsigned int, QPair<int, int>> m_taskPositions;
ShowOutputTaskHandler *m_handler;
QToolButton *m_cancelBuildButton;
- QToolButton *m_zoomInButton;
- QToolButton *m_zoomOutButton;
+ QToolButton * const m_settingsButton;
Utils::OutputFormatter *m_formatter;
+ CompileOutputSettings m_settings;
+};
+
+class CompileOutputSettingsPage : public Core::IOptionsPage
+{
+ Q_OBJECT
+
+public:
+ CompileOutputSettingsPage();
+
+private:
+ QWidget *widget() override;
+ void apply() override;
+ void finish() override;
+
+ class SettingsWidget;
+ QPointer<SettingsWidget> m_widget;
};
} // namespace Internal
diff --git a/src/plugins/projectexplorer/currentprojectfilter.cpp b/src/plugins/projectexplorer/currentprojectfilter.cpp
index 13c0d308db..0e924eeb2a 100644
--- a/src/plugins/projectexplorer/currentprojectfilter.cpp
+++ b/src/plugins/projectexplorer/currentprojectfilter.cpp
@@ -58,7 +58,7 @@ void CurrentProjectFilter::prepareSearch(const QString &entry)
if (!fileIterator()) {
QStringList paths;
if (m_project)
- paths = Utils::transform(m_project->files(Project::AllFiles), &Utils::FileName::toString);
+ paths = Utils::transform(m_project->files(Project::AllFiles), &Utils::FilePath::toString);
setFileIterator(new BaseFileFilter::ListIterator(paths));
}
BaseFileFilter::prepareSearch(entry);
diff --git a/src/plugins/projectexplorer/currentprojectfind.cpp b/src/plugins/projectexplorer/currentprojectfind.cpp
index 75aaf3e601..ca8093f78b 100644
--- a/src/plugins/projectexplorer/currentprojectfind.cpp
+++ b/src/plugins/projectexplorer/currentprojectfind.cpp
@@ -73,7 +73,7 @@ QVariant CurrentProjectFind::additionalParameters() const
{
Project *project = ProjectTree::currentProject();
if (project && project->document())
- return qVariantFromValue(project->projectFilePath().toString());
+ return QVariant::fromValue(project->projectFilePath().toString());
return QVariant();
}
diff --git a/src/plugins/projectexplorer/customexecutablerunconfiguration.cpp b/src/plugins/projectexplorer/customexecutablerunconfiguration.cpp
index aa23dc69c9..957b742474 100644
--- a/src/plugins/projectexplorer/customexecutablerunconfiguration.cpp
+++ b/src/plugins/projectexplorer/customexecutablerunconfiguration.cpp
@@ -31,7 +31,7 @@
#include "environmentaspect.h"
#include "localenvironmentaspect.h"
#include "project.h"
-#include "runconfigurationaspects.h"
+#include "runcontrol.h"
#include "target.h"
#include <coreplugin/icore.h>
@@ -94,8 +94,7 @@ private:
CustomExecutableDialog::CustomExecutableDialog(RunConfiguration *rc)
: QDialog(Core::ICore::dialogParent()),
- m_rc(rc),
- m_workingDirectory(rc->aspect<EnvironmentAspect>())
+ m_rc(rc)
{
auto vbox = new QVBoxLayout(this);
vbox->addWidget(new QLabel(tr("Could not find the executable, please specify one.")));
@@ -146,7 +145,7 @@ CustomExecutableDialog::CustomExecutableDialog(RunConfiguration *rc)
void CustomExecutableDialog::accept()
{
- auto executable = FileName::fromString(m_executableChooser->path());
+ auto executable = FilePath::fromString(m_executableChooser->path());
m_rc->aspect<ExecutableAspect>()->setExecutable(executable);
copyAspect(&m_arguments, m_rc->aspect<ArgumentsAspect>());
copyAspect(&m_workingDirectory, m_rc->aspect<WorkingDirectoryAspect>());
@@ -184,8 +183,7 @@ CustomExecutableRunConfiguration::CustomExecutableRunConfiguration(Target *targe
CustomExecutableRunConfiguration::CustomExecutableRunConfiguration(Target *target, Core::Id id)
: RunConfiguration(target, id)
{
- auto envAspect = addAspect<LocalEnvironmentAspect>
- (target, LocalEnvironmentAspect::BaseEnvironmentModifier());
+ auto envAspect = addAspect<LocalEnvironmentAspect>(target);
auto exeAspect = addAspect<ExecutableAspect>();
exeAspect->setSettingsKey("ProjectExplorer.CustomExecutableRunConfiguration.Executable");
@@ -195,7 +193,7 @@ CustomExecutableRunConfiguration::CustomExecutableRunConfiguration(Target *targe
exeAspect->setEnvironment(envAspect->environment());
addAspect<ArgumentsAspect>();
- addAspect<WorkingDirectoryAspect>(envAspect);
+ addAspect<WorkingDirectoryAspect>();
addAspect<TerminalAspect>();
connect(envAspect, &EnvironmentAspect::environmentChanged,
@@ -253,11 +251,11 @@ bool CustomExecutableRunConfiguration::isConfigured() const
Runnable CustomExecutableRunConfiguration::runnable() const
{
- FileName workingDirectory =
+ FilePath workingDirectory =
aspect<WorkingDirectoryAspect>()->workingDirectory(macroExpander());
Runnable r;
- r.executable = aspect<ExecutableAspect>()->executable().toString();
+ r.executable = executable().toString();
r.commandLineArguments = aspect<ArgumentsAspect>()->arguments(macroExpander());
r.environment = aspect<EnvironmentAspect>()->environment();
r.workingDirectory = workingDirectory.toString();
@@ -285,8 +283,6 @@ CustomExecutableRunConfigurationFactory::CustomExecutableRunConfigurationFactory
FixedRunConfigurationFactory(CustomExecutableRunConfiguration::tr("Custom Executable"))
{
registerRunConfiguration<CustomExecutableRunConfiguration>(CUSTOM_EXECUTABLE_ID);
-
- addRunWorkerFactory<SimpleTargetRunner>(ProjectExplorer::Constants::NORMAL_RUN_MODE);
}
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/customparser.cpp b/src/plugins/projectexplorer/customparser.cpp
index 8c0b287ce4..c408dfc2c6 100644
--- a/src/plugins/projectexplorer/customparser.cpp
+++ b/src/plugins/projectexplorer/customparser.cpp
@@ -150,12 +150,12 @@ Core::Id CustomParser::id()
return Core::Id("ProjectExplorer.OutputParser.Custom");
}
-FileName CustomParser::absoluteFilePath(const QString &filePath) const
+FilePath CustomParser::absoluteFilePath(const QString &filePath) const
{
if (m_workingDirectory.isEmpty())
- return FileName::fromUserInput(filePath);
+ return FilePath::fromUserInput(filePath);
- return FileName::fromString(FileUtils::resolvePath(m_workingDirectory, filePath));
+ return FilePath::fromString(FileUtils::resolvePath(m_workingDirectory, filePath));
}
bool CustomParser::hasMatch(const QString &line, CustomParserExpression::CustomParserChannel channel,
@@ -171,7 +171,7 @@ bool CustomParser::hasMatch(const QString &line, CustomParserExpression::CustomP
if (!match.hasMatch())
return false;
- const FileName fileName = absoluteFilePath(match.captured(expression.fileNameCap()));
+ const FilePath fileName = absoluteFilePath(match.captured(expression.fileNameCap()));
const int lineNumber = match.captured(expression.lineNumberCap()).toInt();
const QString message = match.captured(expression.messageCap());
@@ -215,12 +215,12 @@ void ProjectExplorerPlugin::testCustomOutputParsers_data()
QTest::addColumn<int>("warningMessageCap");
QTest::addColumn<QString>("childStdOutLines");
QTest::addColumn<QString>("childStdErrLines");
- QTest::addColumn<QList<Task> >("tasks");
+ QTest::addColumn<Tasks >("tasks");
QTest::addColumn<QString>("outputLines");
const Core::Id categoryCompile = Constants::TASK_CATEGORY_COMPILE;
const QString simplePattern = "^([a-z]+\\.[a-z]+):(\\d+): error: ([^\\s].+)$";
- const FileName fileName = FileName::fromUserInput("main.c");
+ const FilePath fileName = FilePath::fromUserInput("main.c");
QTest::newRow("empty patterns")
<< QString::fromLatin1("Sometext")
@@ -230,7 +230,7 @@ void ProjectExplorerPlugin::testCustomOutputParsers_data()
<< QString() << 1 << 2 << 3
<< QString() << 1 << 2 << 3
<< QString::fromLatin1("Sometext\n") << QString()
- << QList<Task>()
+ << Tasks()
<< QString();
QTest::newRow("pass-through stdout")
@@ -241,7 +241,7 @@ void ProjectExplorerPlugin::testCustomOutputParsers_data()
<< simplePattern << 1 << 2 << 3
<< QString() << 1 << 2 << 3
<< QString::fromLatin1("Sometext\n") << QString()
- << QList<Task>()
+ << Tasks()
<< QString();
QTest::newRow("pass-through stderr")
@@ -252,7 +252,7 @@ void ProjectExplorerPlugin::testCustomOutputParsers_data()
<< simplePattern << 1 << 2 << 3
<< QString() << 1 << 2 << 3
<< QString() << QString::fromLatin1("Sometext\n")
- << QList<Task>()
+ << Tasks()
<< QString();
const QString simpleError = "main.c:9: error: `sfasdf' undeclared (first use this function)";
@@ -267,12 +267,12 @@ void ProjectExplorerPlugin::testCustomOutputParsers_data()
<< simplePattern << 1 << 2 << 3
<< QString() << 0 << 0 << 0
<< QString() << QString()
- << QList<Task>{Task(Task::Error, message, fileName, 9, categoryCompile)}
+ << Tasks{Task(Task::Error, message, fileName, 9, categoryCompile)}
<< QString();
const QString pathPattern = "^([a-z\\./]+):(\\d+): error: ([^\\s].+)$";
QString workingDir = "/home/src/project";
- FileName expandedFileName = FileName::fromString("/home/src/project/main.c");
+ FilePath expandedFileName = FilePath::fromString("/home/src/project/main.c");
QTest::newRow("simple error with expanded path")
<< "main.c:9: error: `sfasdf' undeclared (first use this function)"
@@ -282,10 +282,10 @@ void ProjectExplorerPlugin::testCustomOutputParsers_data()
<< pathPattern << 1 << 2 << 3
<< QString() << 0 << 0 << 0
<< QString() << QString()
- << QList<Task>{Task(Task::Error, message, expandedFileName, 9, categoryCompile)}
+ << Tasks{Task(Task::Error, message, expandedFileName, 9, categoryCompile)}
<< QString();
- expandedFileName = FileName::fromString("/home/src/project/subdir/main.c");
+ expandedFileName = FilePath::fromString("/home/src/project/subdir/main.c");
QTest::newRow("simple error with subdir path")
<< "subdir/main.c:9: error: `sfasdf' undeclared (first use this function)"
<< workingDir
@@ -294,7 +294,7 @@ void ProjectExplorerPlugin::testCustomOutputParsers_data()
<< pathPattern << 1 << 2 << 3
<< QString() << 0 << 0 << 0
<< QString() << QString()
- << QList<Task>{Task(Task::Error, message, expandedFileName, 9, categoryCompile)}
+ << Tasks{Task(Task::Error, message, expandedFileName, 9, categoryCompile)}
<< QString();
workingDir = "/home/src/build-project";
@@ -306,7 +306,7 @@ void ProjectExplorerPlugin::testCustomOutputParsers_data()
<< pathPattern << 1 << 2 << 3
<< QString() << 0 << 0 << 0
<< QString() << QString()
- << QList<Task>{Task(Task::Error, message, expandedFileName, 9, categoryCompile)}
+ << Tasks{Task(Task::Error, message, expandedFileName, 9, categoryCompile)}
<< QString();
QTest::newRow("simple error on wrong channel")
@@ -317,7 +317,7 @@ void ProjectExplorerPlugin::testCustomOutputParsers_data()
<< simplePattern << 1 << 2 << 3
<< QString() << 0 << 0 << 0
<< simpleErrorPassThrough << QString()
- << QList<Task>()
+ << Tasks()
<< QString();
QTest::newRow("simple error on other wrong channel")
@@ -328,7 +328,7 @@ void ProjectExplorerPlugin::testCustomOutputParsers_data()
<< simplePattern << 1 << 2 << 3
<< QString() << 0 << 0 << 0
<< QString() << simpleErrorPassThrough
- << QList<Task>()
+ << Tasks()
<< QString();
const QString simpleError2 = "Error: Line 19 in main.c: `sfasdf' undeclared (first use this function)";
@@ -343,7 +343,7 @@ void ProjectExplorerPlugin::testCustomOutputParsers_data()
<< simplePattern2 << 2 << 1 << 3
<< QString() << 1 << 2 << 3
<< QString() << QString()
- << QList<Task>{Task(Task::Error, message, fileName, lineNumber2, categoryCompile)}
+ << Tasks{Task(Task::Error, message, fileName, lineNumber2, categoryCompile)}
<< QString();
QTest::newRow("another simple error on stdout")
@@ -354,7 +354,7 @@ void ProjectExplorerPlugin::testCustomOutputParsers_data()
<< simplePattern2 << 2 << 1 << 3
<< QString() << 1 << 2 << 3
<< QString() << QString()
- << QList<Task>{Task(Task::Error, message, fileName, lineNumber2, categoryCompile)}
+ << Tasks{Task(Task::Error, message, fileName, lineNumber2, categoryCompile)}
<< QString();
const QString simpleWarningPattern = "^([a-z]+\\.[a-z]+):(\\d+): warning: ([^\\s].+)$";
@@ -369,7 +369,7 @@ void ProjectExplorerPlugin::testCustomOutputParsers_data()
<< QString() << 1 << 2 << 3
<< simpleWarningPattern << 1 << 2 << 3
<< QString() << QString()
- << QList<Task>{Task(Task::Warning, warningMessage, fileName, 1234, categoryCompile)}
+ << Tasks{Task(Task::Warning, warningMessage, fileName, 1234, categoryCompile)}
<< QString();
const QString simpleWarning2 = "Warning: `helloWorld' declared but not used (main.c:19)";
@@ -384,7 +384,7 @@ void ProjectExplorerPlugin::testCustomOutputParsers_data()
<< simplePattern2 << 1 << 2 << 3
<< simpleWarningPattern2 << 2 << 3 << 1
<< QString() << QString()
- << QList<Task>{Task(Task::Warning, warningMessage, fileName, lineNumber2, categoryCompile)}
+ << Tasks{Task(Task::Warning, warningMessage, fileName, lineNumber2, categoryCompile)}
<< QString();
QTest::newRow("warning on wrong channel")
@@ -395,7 +395,7 @@ void ProjectExplorerPlugin::testCustomOutputParsers_data()
<< QString() << 1 << 2 << 3
<< simpleWarningPattern2 << 2 << 3 << 1
<< simpleWarningPassThrough2 << QString()
- << QList<Task>()
+ << Tasks()
<< QString();
QTest::newRow("warning on other wrong channel")
@@ -406,7 +406,7 @@ void ProjectExplorerPlugin::testCustomOutputParsers_data()
<< QString() << 1 << 2 << 3
<< simpleWarningPattern2 << 2 << 3 << 1
<< QString() << simpleWarningPassThrough2
- << QList<Task>()
+ << Tasks()
<< QString();
QTest::newRow("error and *warning*")
@@ -417,7 +417,7 @@ void ProjectExplorerPlugin::testCustomOutputParsers_data()
<< simplePattern << 1 << 2 << 3
<< simpleWarningPattern << 1 << 2 << 3
<< QString() << QString()
- << QList<Task>{Task(Task::Warning, warningMessage, fileName, 1234, categoryCompile)}
+ << Tasks{Task(Task::Warning, warningMessage, fileName, 1234, categoryCompile)}
<< QString();
QTest::newRow("*error* when equal pattern")
@@ -428,11 +428,11 @@ void ProjectExplorerPlugin::testCustomOutputParsers_data()
<< simplePattern << 1 << 2 << 3
<< simplePattern << 1 << 2 << 3
<< QString() << QString()
- << QList<Task>{Task(Task::Error, message, fileName, 9, categoryCompile)}
+ << Tasks{Task(Task::Error, message, fileName, 9, categoryCompile)}
<< QString();
const QString unitTestError = "../LedDriver/LedDriverTest.c:63: FAIL: Expected 0x0080 Was 0xffff";
- const FileName unitTestFileName = FileName::fromUserInput("../LedDriver/LedDriverTest.c");
+ const FilePath unitTestFileName = FilePath::fromUserInput("../LedDriver/LedDriverTest.c");
const QString unitTestMessage = "Expected 0x0080 Was 0xffff";
const QString unitTestPattern = "^([^:]+):(\\d+): FAIL: ([^\\s].+)$";
const int unitTestLineNumber = 63;
@@ -445,7 +445,7 @@ void ProjectExplorerPlugin::testCustomOutputParsers_data()
<< unitTestPattern << 1 << 2 << 3
<< QString() << 1 << 2 << 3
<< QString() << QString()
- << QList<Task>{Task(Task::Error, unitTestMessage, unitTestFileName, unitTestLineNumber, categoryCompile)}
+ << Tasks{Task(Task::Error, unitTestMessage, unitTestFileName, unitTestLineNumber, categoryCompile)}
<< QString();
}
@@ -466,7 +466,7 @@ void ProjectExplorerPlugin::testCustomOutputParsers()
QFETCH(int, warningMessageCap);
QFETCH(QString, childStdOutLines);
QFETCH(QString, childStdErrLines);
- QFETCH(QList<Task>, tasks);
+ QFETCH(Tasks, tasks);
QFETCH(QString, outputLines);
CustomParserSettings settings;
diff --git a/src/plugins/projectexplorer/customparser.h b/src/plugins/projectexplorer/customparser.h
index b7c70d4759..dafb0e8da1 100644
--- a/src/plugins/projectexplorer/customparser.h
+++ b/src/plugins/projectexplorer/customparser.h
@@ -96,7 +96,7 @@ public:
static Core::Id id();
private:
- Utils::FileName absoluteFilePath(const QString &filePath) const;
+ 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);
diff --git a/src/plugins/projectexplorer/customparserconfigdialog.cpp b/src/plugins/projectexplorer/customparserconfigdialog.cpp
index b688e8aca1..061d1814ed 100644
--- a/src/plugins/projectexplorer/customparserconfigdialog.cpp
+++ b/src/plugins/projectexplorer/customparserconfigdialog.cpp
@@ -42,20 +42,20 @@ CustomParserConfigDialog::CustomParserConfigDialog(QDialog *parent) :
connect(ui->errorPattern, &QLineEdit::textChanged, this, &CustomParserConfigDialog::changed);
connect(ui->errorOutputMessage, &QLineEdit::textChanged,
this, &CustomParserConfigDialog::changed);
- connect(ui->errorFileNameCap, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
+ connect(ui->errorFileNameCap, QOverload<int>::of(&QSpinBox::valueChanged),
this, &CustomParserConfigDialog::changed);
- connect(ui->errorLineNumberCap, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
+ connect(ui->errorLineNumberCap, QOverload<int>::of(&QSpinBox::valueChanged),
this, &CustomParserConfigDialog::changed);
- connect(ui->errorMessageCap, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
+ connect(ui->errorMessageCap, QOverload<int>::of(&QSpinBox::valueChanged),
this, &CustomParserConfigDialog::changed);
connect(ui->warningPattern, &QLineEdit::textChanged, this, &CustomParserConfigDialog::changed);
connect(ui->warningOutputMessage, &QLineEdit::textChanged,
this, &CustomParserConfigDialog::changed);
- connect(ui->warningFileNameCap, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
+ connect(ui->warningFileNameCap, QOverload<int>::of(&QSpinBox::valueChanged),
this, &CustomParserConfigDialog::changed);
- connect(ui->warningLineNumberCap, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
+ connect(ui->warningLineNumberCap, QOverload<int>::of(&QSpinBox::valueChanged),
this, &CustomParserConfigDialog::changed);
- connect(ui->warningMessageCap, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
+ connect(ui->warningMessageCap, QOverload<int>::of(&QSpinBox::valueChanged),
this, &CustomParserConfigDialog::changed);
changed();
diff --git a/src/plugins/projectexplorer/customtoolchain.cpp b/src/plugins/projectexplorer/customtoolchain.cpp
index 1833875102..e1175963ea 100644
--- a/src/plugins/projectexplorer/customtoolchain.cpp
+++ b/src/plugins/projectexplorer/customtoolchain.cpp
@@ -81,17 +81,11 @@ static const char warningExampleKeyC[] = "ProjectExplorer.CustomToolChain.Warnin
// CustomToolChain
// --------------------------------------------------------------------------
-CustomToolChain::CustomToolChain(Detection d) :
- ToolChain(Constants::CUSTOM_TOOLCHAIN_TYPEID, d),
+CustomToolChain::CustomToolChain() :
+ ToolChain(Constants::CUSTOM_TOOLCHAIN_TYPEID),
m_outputParserId(GccParser::id())
{ }
-CustomToolChain::CustomToolChain(Core::Id language, Detection d) : CustomToolChain(d)
-{
- setLanguage(language);
-}
-
-
QString CustomToolChain::typeDisplayName() const
{
return Internal::CustomToolChainFactory::tr("Custom");
@@ -169,7 +163,7 @@ ToolChain::BuiltInHeaderPathsRunner CustomToolChain::createBuiltInHeaderPathsRun
const HeaderPaths builtInHeaderPaths = m_builtInHeaderPaths;
// This runner must be thread-safe!
- return [builtInHeaderPaths](const QStringList &cxxFlags, const QString &) {
+ return [builtInHeaderPaths](const QStringList &cxxFlags, const QString &, const QString &) {
HeaderPaths flagHeaderPaths;
for (const QString &cxxFlag : cxxFlags) {
if (cxxFlag.startsWith(QLatin1String("-I"))) {
@@ -182,23 +176,23 @@ ToolChain::BuiltInHeaderPathsRunner CustomToolChain::createBuiltInHeaderPathsRun
}
HeaderPaths CustomToolChain::builtInHeaderPaths(const QStringList &cxxFlags,
- const FileName &fileName) const
+ const FilePath &fileName) const
{
- return createBuiltInHeaderPathsRunner()(cxxFlags, fileName.toString());
+ return createBuiltInHeaderPathsRunner()(cxxFlags, fileName.toString(), "");
}
void CustomToolChain::addToEnvironment(Environment &env) const
{
if (!m_compilerCommand.isEmpty()) {
- FileName path = m_compilerCommand.parentDir();
+ FilePath path = m_compilerCommand.parentDir();
env.prependOrSetPath(path.toString());
- FileName makePath = m_makeCommand.parentDir();
+ FilePath makePath = m_makeCommand.parentDir();
if (makePath != path)
env.prependOrSetPath(makePath.toString());
}
}
-FileNameList CustomToolChain::suggestedMkspecList() const
+QStringList CustomToolChain::suggestedMkspecList() const
{
return m_mkspecs;
}
@@ -235,7 +229,7 @@ void CustomToolChain::setHeaderPaths(const QStringList &list)
toolChainUpdated();
}
-void CustomToolChain::setCompilerCommand(const FileName &path)
+void CustomToolChain::setCompilerCommand(const FilePath &path)
{
if (path == m_compilerCommand)
return;
@@ -243,12 +237,12 @@ void CustomToolChain::setCompilerCommand(const FileName &path)
toolChainUpdated();
}
-FileName CustomToolChain::compilerCommand() const
+FilePath CustomToolChain::compilerCommand() const
{
return m_compilerCommand;
}
-void CustomToolChain::setMakeCommand(const FileName &path)
+void CustomToolChain::setMakeCommand(const FilePath &path)
{
if (path == m_makeCommand)
return;
@@ -256,9 +250,9 @@ void CustomToolChain::setMakeCommand(const FileName &path)
toolChainUpdated();
}
-QString CustomToolChain::makeCommand(const Environment &) const
+FilePath CustomToolChain::makeCommand(const Environment &) const
{
- return m_makeCommand.toString();
+ return m_makeCommand;
}
void CustomToolChain::setCxx11Flags(const QStringList &flags)
@@ -276,10 +270,7 @@ const QStringList &CustomToolChain::cxx11Flags() const
void CustomToolChain::setMkspecs(const QString &specs)
{
- Utils::FileNameList tmp
- = Utils::transform(specs.split(QLatin1Char(',')),
- [](QString fn) { return FileName::fromString(fn); });
-
+ const QStringList tmp = specs.split(',');
if (tmp == m_mkspecs)
return;
m_mkspecs = tmp;
@@ -288,16 +279,7 @@ void CustomToolChain::setMkspecs(const QString &specs)
QString CustomToolChain::mkspecs() const
{
- QString list;
- for (const FileName &spec : m_mkspecs)
- list.append(spec.toString() + QLatin1Char(','));
- list.chop(1);
- return list;
-}
-
-ToolChain *CustomToolChain::clone() const
-{
- return new CustomToolChain(*this);
+ return m_mkspecs.join(',');
}
QVariantMap CustomToolChain::toMap() const
@@ -333,8 +315,8 @@ bool CustomToolChain::fromMap(const QVariantMap &data)
if (!ToolChain::fromMap(data))
return false;
- m_compilerCommand = FileName::fromString(data.value(QLatin1String(compilerCommandKeyC)).toString());
- m_makeCommand = FileName::fromString(data.value(QLatin1String(makeCommandKeyC)).toString());
+ m_compilerCommand = FilePath::fromString(data.value(QLatin1String(compilerCommandKeyC)).toString());
+ m_makeCommand = FilePath::fromString(data.value(QLatin1String(makeCommandKeyC)).toString());
m_targetAbi = Abi::fromString(data.value(QLatin1String(targetAbiKeyC)).toString());
const QStringList macros = data.value(QLatin1String(predefinedMacrosKeyC)).toStringList();
m_predefinedMacros = Macro::toMacros(macros.join('\n').toUtf8());
@@ -425,37 +407,10 @@ namespace Internal {
CustomToolChainFactory::CustomToolChainFactory()
{
setDisplayName(tr("Custom"));
-}
-
-QSet<Core::Id> CustomToolChainFactory::supportedLanguages() const
-{
- return ToolChainManager::allLanguages();
-}
-
-bool CustomToolChainFactory::canCreate()
-{
- return true;
-}
-
-ToolChain *CustomToolChainFactory::create(Core::Id language)
-{
- return new CustomToolChain(language, ToolChain::ManualDetection);
-}
-
-// Used by the ToolChainManager to restore user-generated tool chains
-bool CustomToolChainFactory::canRestore(const QVariantMap &data)
-{
- return typeIdFromMap(data) == Constants::CUSTOM_TOOLCHAIN_TYPEID;
-}
-
-ToolChain *CustomToolChainFactory::restore(const QVariantMap &data)
-{
- auto tc = new CustomToolChain(ToolChain::ManualDetection);
- if (tc->fromMap(data))
- return tc;
-
- delete tc;
- return nullptr;
+ setSupportedToolChainType(Constants::CUSTOM_TOOLCHAIN_TYPEID);
+ setSupportsAllLanguages(true);
+ setToolchainConstructor([] { return new CustomToolChain; });
+ setUserCreatable(true);
}
// --------------------------------------------------------------------------
@@ -566,7 +521,7 @@ CustomToolChainConfigWidget::CustomToolChainConfigWidget(CustomToolChain *tc) :
this, &CustomToolChainConfigWidget::updateSummaries);
connect(m_cxx11Flags, &QLineEdit::textChanged, this, &ToolChainConfigWidget::dirty);
connect(m_mkspecs, &QLineEdit::textChanged, this, &ToolChainConfigWidget::dirty);
- connect(m_errorParserComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
+ connect(m_errorParserComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &CustomToolChainConfigWidget::errorParserChanged);
connect(m_customParserSettingsButton, &QAbstractButton::clicked,
this, &CustomToolChainConfigWidget::openCustomParserSettingsDialog);
@@ -635,8 +590,8 @@ void CustomToolChainConfigWidget::setFromToolchain()
QSignalBlocker blocker(this);
auto tc = static_cast<CustomToolChain *>(toolChain());
m_compilerCommand->setFileName(tc->compilerCommand());
- m_makeCommand->setFileName(FileName::fromString(tc->makeCommand(Environment())));
- m_abiWidget->setAbis(QList<Abi>(), tc->targetAbi());
+ m_makeCommand->setFileName(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()));
});
@@ -654,7 +609,7 @@ 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())
+ || m_makeCommand->path() != tc->makeCommand(Environment()).toString()
|| m_abiWidget->currentAbi() != tc->targetAbi()
|| Macro::toMacros(m_predefinedDetails->text().toUtf8()) != tc->rawPredefinedMacros()
|| m_headerDetails->entries() != tc->headerPathsList()
diff --git a/src/plugins/projectexplorer/customtoolchain.h b/src/plugins/projectexplorer/customtoolchain.h
index 37ca6abd15..415cf89abd 100644
--- a/src/plugins/projectexplorer/customtoolchain.h
+++ b/src/plugins/projectexplorer/customtoolchain.h
@@ -80,9 +80,9 @@ public:
BuiltInHeaderPathsRunner createBuiltInHeaderPathsRunner() const override;
HeaderPaths builtInHeaderPaths(const QStringList &cxxFlags,
- const Utils::FileName &) const override;
+ const Utils::FilePath &) const override;
void addToEnvironment(Utils::Environment &env) const override;
- Utils::FileNameList suggestedMkspecList() const override;
+ QStringList suggestedMkspecList() const override;
IOutputParser *outputParser() const override;
QStringList headerPathsList() const;
void setHeaderPaths(const QStringList &list);
@@ -94,10 +94,10 @@ public:
bool operator ==(const ToolChain &) const override;
- void setCompilerCommand(const Utils::FileName &);
- Utils::FileName compilerCommand() const override;
- void setMakeCommand(const Utils::FileName &);
- QString makeCommand(const Utils::Environment &environment) const override;
+ void setCompilerCommand(const Utils::FilePath &);
+ Utils::FilePath compilerCommand() const override;
+ void setMakeCommand(const Utils::FilePath &);
+ Utils::FilePath makeCommand(const Utils::Environment &environment) const override;
void setCxx11Flags(const QStringList &);
const QStringList &cxx11Flags() const;
@@ -105,29 +105,23 @@ public:
void setMkspecs(const QString &);
QString mkspecs() const;
- ToolChain *clone() const override;
-
Core::Id outputParserId() const;
void setOutputParserId(Core::Id parserId);
CustomParserSettings customParserSettings() const;
void setCustomParserSettings(const CustomParserSettings &settings);
static QList<CustomToolChain::Parser> parsers();
-protected:
- CustomToolChain(const CustomToolChain &) = default;
-
private:
- explicit CustomToolChain(Detection d);
- explicit CustomToolChain(Core::Id language, Detection d);
+ CustomToolChain();
- Utils::FileName m_compilerCommand;
- Utils::FileName m_makeCommand;
+ Utils::FilePath m_compilerCommand;
+ Utils::FilePath m_makeCommand;
Abi m_targetAbi;
Macros m_predefinedMacros;
HeaderPaths m_builtInHeaderPaths;
QStringList m_cxx11Flags;
- Utils::FileNameList m_mkspecs;
+ QStringList m_mkspecs;
Core::Id m_outputParserId;
CustomParserSettings m_customParserSettings;
@@ -144,14 +138,6 @@ class CustomToolChainFactory : public ToolChainFactory
public:
CustomToolChainFactory();
- QSet<Core::Id> supportedLanguages() const override;
-
- bool canCreate() override;
- ToolChain *create(Core::Id language) override;
-
- // Used by the ToolChainManager to restore user-generated tool chains
- bool canRestore(const QVariantMap &data) override;
- ToolChain *restore(const QVariantMap &data) override;
};
// --------------------------------------------------------------------------
diff --git a/src/plugins/projectexplorer/customwizard/customwizard.cpp b/src/plugins/projectexplorer/customwizard/customwizard.cpp
index 9a3ea42a4e..1f92543431 100644
--- a/src/plugins/projectexplorer/customwizard/customwizard.cpp
+++ b/src/plugins/projectexplorer/customwizard/customwizard.cpp
@@ -406,7 +406,7 @@ QList<Core::IWizardFactory *> CustomWizard::createWizards()
const QDir::Filters filters = QDir::Dirs|QDir::Readable|QDir::NoDotAndDotDot;
const QDir::SortFlags sortflags = QDir::Name|QDir::IgnoreCase;
- QList<QFileInfo> dirs;
+ QFileInfoList dirs;
if (userTemplateDir.exists()) {
if (CustomWizardPrivate::verbose)
verboseLog += QString::fromLatin1("### CustomWizard: userTemplateDir \"%1\" found, adding\n").arg(userTemplateDirName);
@@ -446,7 +446,7 @@ QList<Core::IWizardFactory *> CustomWizard::createWizards()
break;
}
} else {
- QList<QFileInfo> subDirs = dir.entryInfoList(filters, sortflags);
+ QFileInfoList subDirs = dir.entryInfoList(filters, sortflags);
if (!subDirs.isEmpty()) {
// There is no QList::prepend(QList)...
dirs.swap(subDirs);
diff --git a/src/plugins/projectexplorer/deployablefile.cpp b/src/plugins/projectexplorer/deployablefile.cpp
index 1d7b6132c1..d8ea6cd33a 100644
--- a/src/plugins/projectexplorer/deployablefile.cpp
+++ b/src/plugins/projectexplorer/deployablefile.cpp
@@ -34,10 +34,10 @@ using namespace Utils;
namespace ProjectExplorer {
DeployableFile::DeployableFile(const QString &localFilePath, const QString &remoteDir, Type type)
- : m_localFilePath(FileName::fromUserInput(localFilePath)), m_remoteDir(remoteDir), m_type(type)
+ : m_localFilePath(FilePath::fromUserInput(localFilePath)), m_remoteDir(remoteDir), m_type(type)
{ }
-DeployableFile::DeployableFile(const FileName &localFilePath, const QString &remoteDir, Type type)
+DeployableFile::DeployableFile(const FilePath &localFilePath, const QString &remoteDir, Type type)
: m_localFilePath(localFilePath), m_remoteDir(remoteDir), m_type(type)
{ }
diff --git a/src/plugins/projectexplorer/deployablefile.h b/src/plugins/projectexplorer/deployablefile.h
index 70d05c29e8..b1a6c6a1d6 100644
--- a/src/plugins/projectexplorer/deployablefile.h
+++ b/src/plugins/projectexplorer/deployablefile.h
@@ -45,10 +45,10 @@ public:
DeployableFile() = default;
DeployableFile(const QString &m_localFilePath, const QString &m_remoteDir,
Type type = TypeNormal);
- DeployableFile(const Utils::FileName &localFilePath, const QString &remoteDir,
+ DeployableFile(const Utils::FilePath &localFilePath, const QString &remoteDir,
Type type = TypeNormal);
- Utils::FileName localFilePath() const { return m_localFilePath; }
+ Utils::FilePath localFilePath() const { return m_localFilePath; }
QString remoteDirectory() const { return m_remoteDir; }
QString remoteFilePath() const;
@@ -57,7 +57,7 @@ public:
bool isExecutable() const;
private:
- Utils::FileName m_localFilePath;
+ Utils::FilePath m_localFilePath;
QString m_remoteDir;
Type m_type = TypeNormal;
};
diff --git a/src/plugins/projectexplorer/deployconfiguration.cpp b/src/plugins/projectexplorer/deployconfiguration.cpp
index 7619a06ca2..4d16599a12 100644
--- a/src/plugins/projectexplorer/deployconfiguration.cpp
+++ b/src/plugins/projectexplorer/deployconfiguration.cpp
@@ -162,7 +162,7 @@ bool DeployConfigurationFactory::canHandle(Target *target) const
if (!m_supportedTargetDeviceTypes.isEmpty()) {
if (!m_supportedTargetDeviceTypes.contains(
- DeviceTypeKitInformation::deviceTypeId(target->kit())))
+ DeviceTypeKitAspect::deviceTypeId(target->kit())))
return false;
}
diff --git a/src/plugins/projectexplorer/deploymentdata.cpp b/src/plugins/projectexplorer/deploymentdata.cpp
index c34b6a4044..7cdc4a1185 100644
--- a/src/plugins/projectexplorer/deploymentdata.cpp
+++ b/src/plugins/projectexplorer/deploymentdata.cpp
@@ -33,7 +33,7 @@
namespace ProjectExplorer {
-void DeploymentData::setLocalInstallRoot(const Utils::FileName &installRoot)
+void DeploymentData::setLocalInstallRoot(const Utils::FilePath &installRoot)
{
m_localInstallRoot = installRoot;
}
diff --git a/src/plugins/projectexplorer/deploymentdata.h b/src/plugins/projectexplorer/deploymentdata.h
index 7297ad84b2..e45427ebf8 100644
--- a/src/plugins/projectexplorer/deploymentdata.h
+++ b/src/plugins/projectexplorer/deploymentdata.h
@@ -28,18 +28,30 @@
#include "deployablefile.h"
#include "projectexplorer_export.h"
+#include <utils/environment.h>
+
#include <QList>
namespace ProjectExplorer {
+enum class DeploymentKnowledge { Perfect, Approximative, Bad };
+
+class PROJECTEXPLORER_EXPORT MakeInstallCommand
+{
+public:
+ Utils::FilePath command;
+ QStringList arguments;
+ Utils::Environment environment;
+};
+
class PROJECTEXPLORER_EXPORT DeploymentData
{
public:
void setFileList(const QList<DeployableFile> &files) { m_files = files; }
QList<DeployableFile> allFiles() const { return m_files; }
- void setLocalInstallRoot(const Utils::FileName &installRoot);
- Utils::FileName localInstallRoot() const { return m_localInstallRoot; }
+ void setLocalInstallRoot(const Utils::FilePath &installRoot);
+ Utils::FilePath localInstallRoot() const { return m_localInstallRoot; }
void addFile(const DeployableFile &file);
void addFile(const QString &localFilePath, const QString &remoteDirectory,
@@ -54,7 +66,7 @@ public:
private:
QList<DeployableFile> m_files;
- Utils::FileName m_localInstallRoot;
+ Utils::FilePath m_localInstallRoot;
};
inline bool operator!=(const DeploymentData &d1, const DeploymentData &d2) { return !(d1 == d2); }
diff --git a/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp b/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp
index 283e921d92..a725658b9b 100644
--- a/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp
+++ b/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp
@@ -30,8 +30,10 @@
#include "desktopdeviceconfigurationwidget.h"
#include "desktopprocesssignaloperation.h"
+#include <coreplugin/fileutils.h>
+
#include <projectexplorer/projectexplorerconstants.h>
-#include <projectexplorer/runconfiguration.h>
+#include <projectexplorer/runcontrol.h>
#include <ssh/sshconnection.h>
@@ -58,10 +60,11 @@ DesktopDevice::DesktopDevice()
const QString portRange =
QString::fromLatin1("%1-%2").arg(DESKTOP_PORT_START).arg(DESKTOP_PORT_END);
setFreePorts(Utils::PortList::fromString(portRange));
+ setOpenTerminal([](const Utils::Environment &env, const QString &workingDir) {
+ Core::FileUtils::openTerminal(workingDir, env);
+ });
}
-DesktopDevice::DesktopDevice(const DesktopDevice &other) = default;
-
IDevice::DeviceInfo DesktopDevice::deviceInformation() const
{
return DeviceInfo();
@@ -177,9 +180,4 @@ Utils::OsType DesktopDevice::osType() const
return Utils::HostOsInfo::hostOs();
}
-IDevice::Ptr DesktopDevice::clone() const
-{
- return Ptr(new DesktopDevice(*this));
-}
-
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/devicesupport/desktopdevice.h b/src/plugins/projectexplorer/devicesupport/desktopdevice.h
index da57cf95bd..dec063b5e5 100644
--- a/src/plugins/projectexplorer/devicesupport/desktopdevice.h
+++ b/src/plugins/projectexplorer/devicesupport/desktopdevice.h
@@ -53,11 +53,8 @@ public:
QUrl toolControlChannel(const ControlChannelHint &) const override;
Utils::OsType osType() const override;
- IDevice::Ptr clone() const override;
-
protected:
DesktopDevice();
- DesktopDevice(const DesktopDevice &other);
friend class ProjectExplorerPlugin;
friend class Internal::DesktopDeviceFactory;
diff --git a/src/plugins/projectexplorer/devicesupport/desktopdeviceprocess.cpp b/src/plugins/projectexplorer/devicesupport/desktopdeviceprocess.cpp
index d57b765bb0..bb9f6c8f43 100644
--- a/src/plugins/projectexplorer/devicesupport/desktopdeviceprocess.cpp
+++ b/src/plugins/projectexplorer/devicesupport/desktopdeviceprocess.cpp
@@ -26,7 +26,7 @@
#include "desktopdeviceprocess.h"
#include "idevice.h"
-#include "../runconfiguration.h"
+#include "../runcontrol.h"
#include <utils/environment.h>
#include <utils/qtcassert.h>
diff --git a/src/plugins/projectexplorer/devicesupport/devicecheckbuildstep.cpp b/src/plugins/projectexplorer/devicesupport/devicecheckbuildstep.cpp
index 7935efb5fc..29e95751f6 100644
--- a/src/plugins/projectexplorer/devicesupport/devicecheckbuildstep.cpp
+++ b/src/plugins/projectexplorer/devicesupport/devicecheckbuildstep.cpp
@@ -44,9 +44,9 @@ DeviceCheckBuildStep::DeviceCheckBuildStep(BuildStepList *bsl)
bool DeviceCheckBuildStep::init()
{
- IDevice::ConstPtr device = DeviceKitInformation::device(target()->kit());
+ IDevice::ConstPtr device = DeviceKitAspect::device(target()->kit());
if (!device) {
- Core::Id deviceTypeId = DeviceTypeKitInformation::deviceTypeId(target()->kit());
+ Core::Id deviceTypeId = DeviceTypeKitAspect::deviceTypeId(target()->kit());
IDeviceFactory *factory = IDeviceFactory::find(deviceTypeId);
if (!factory || !factory->canCreate()) {
emit addOutput(tr("No device configured."), BuildStep::OutputFormat::ErrorMessage);
@@ -71,7 +71,7 @@ bool DeviceCheckBuildStep::init()
DeviceManager *dm = DeviceManager::instance();
dm->addDevice(newDevice);
- DeviceKitInformation::setDevice(target()->kit(), newDevice);
+ DeviceKitAspect::setDevice(target()->kit(), newDevice);
}
return true;
diff --git a/src/plugins/projectexplorer/devicesupport/devicemanager.cpp b/src/plugins/projectexplorer/devicesupport/devicemanager.cpp
index d8c72aa354..cd6e7421aa 100644
--- a/src/plugins/projectexplorer/devicesupport/devicemanager.cpp
+++ b/src/plugins/projectexplorer/devicesupport/devicemanager.cpp
@@ -221,14 +221,14 @@ QVariantMap DeviceManager::toMap() const
return map;
}
-Utils::FileName DeviceManager::settingsFilePath(const QString &extension)
+Utils::FilePath DeviceManager::settingsFilePath(const QString &extension)
{
- return Utils::FileName::fromString(Core::ICore::userResourcePath() + extension);
+ return Utils::FilePath::fromString(Core::ICore::userResourcePath() + extension);
}
-Utils::FileName DeviceManager::systemSettingsFilePath(const QString &deviceFileRelativePath)
+Utils::FilePath DeviceManager::systemSettingsFilePath(const QString &deviceFileRelativePath)
{
- return Utils::FileName::fromString(Core::ICore::installerResourcePath()
+ return Utils::FilePath::fromString(Core::ICore::installerResourcePath()
+ deviceFileRelativePath);
}
@@ -414,10 +414,8 @@ public:
static Core::Id testTypeId() { return "TestType"; }
private:
- TestDevice(const TestDevice &other) = default;
QString displayType() const override { return QLatin1String("blubb"); }
IDeviceWidget *createWidget() override { return nullptr; }
- Ptr clone() const override { return Ptr(new TestDevice(*this)); }
DeviceProcessSignalOperation::Ptr signalOperation() const override
{
return DeviceProcessSignalOperation::Ptr();
@@ -425,8 +423,19 @@ private:
Utils::OsType osType() const override { return Utils::HostOsInfo::hostOs(); }
};
+class TestDeviceFactory : public IDeviceFactory
+{
+public:
+ TestDeviceFactory() : IDeviceFactory(TestDevice::testTypeId())
+ {
+ setConstructionFunction([] { return IDevice::Ptr(new TestDevice); });
+ }
+};
+
void ProjectExplorerPlugin::testDeviceManager()
{
+ TestDeviceFactory factory;
+
TestDevice::Ptr dev = IDevice::Ptr(new TestDevice);
dev->setDisplayName(QLatin1String("blubbdiblubbfurz!"));
QVERIFY(dev->isAutoDetected());
diff --git a/src/plugins/projectexplorer/devicesupport/devicemanager.h b/src/plugins/projectexplorer/devicesupport/devicemanager.h
index bd9c2b606e..6f286845dd 100644
--- a/src/plugins/projectexplorer/devicesupport/devicemanager.h
+++ b/src/plugins/projectexplorer/devicesupport/devicemanager.h
@@ -33,7 +33,7 @@
#include <memory>
-namespace Utils { class FileName; }
+namespace Utils { class FilePath; }
namespace ProjectExplorer {
class IDevice;
@@ -96,8 +96,8 @@ private:
static void replaceInstance();
static void removeClonedInstance();
- static Utils::FileName settingsFilePath(const QString &extension);
- static Utils::FileName systemSettingsFilePath(const QString &deviceFileRelativePath);
+ static Utils::FilePath settingsFilePath(const QString &extension);
+ static Utils::FilePath systemSettingsFilePath(const QString &deviceFileRelativePath);
static void copy(const DeviceManager *source, DeviceManager *target, bool deep);
const std::unique_ptr<Internal::DeviceManagerPrivate> d;
diff --git a/src/plugins/projectexplorer/devicesupport/deviceprocess.h b/src/plugins/projectexplorer/devicesupport/deviceprocess.h
index e26151d251..4aa197666c 100644
--- a/src/plugins/projectexplorer/devicesupport/deviceprocess.h
+++ b/src/plugins/projectexplorer/devicesupport/deviceprocess.h
@@ -26,7 +26,6 @@
#pragma once
#include "../projectexplorer_export.h"
-#include "../runconfiguration.h"
#include <QObject>
#include <QProcess>
diff --git a/src/plugins/projectexplorer/devicesupport/deviceprocessesdialog.cpp b/src/plugins/projectexplorer/devicesupport/deviceprocessesdialog.cpp
index dd6a851929..2e0cf6a660 100644
--- a/src/plugins/projectexplorer/devicesupport/deviceprocessesdialog.cpp
+++ b/src/plugins/projectexplorer/devicesupport/deviceprocessesdialog.cpp
@@ -185,14 +185,10 @@ DeviceProcessesDialogPrivate::DeviceProcessesDialogPrivate(KitChooser *chooser,
proxyModel.setFilterRegExp(processFilterLineEdit->text());
- connect(processFilterLineEdit,
- static_cast<void (FancyLineEdit::*)(const QString &)>(&FancyLineEdit::textChanged),
- &proxyModel,
- static_cast<void (ProcessListFilterModel::*)(const QString &)>(
- &ProcessListFilterModel::setFilterRegExp));
- connect(procView->selectionModel(),
- &QItemSelectionModel::selectionChanged,
- this, &DeviceProcessesDialogPrivate::updateButtons);
+ connect(processFilterLineEdit, QOverload<const QString &>::of(&FancyLineEdit::textChanged),
+ &proxyModel, QOverload<const QString &>::of(&ProcessListFilterModel::setFilterRegExp));
+ connect(procView->selectionModel(), &QItemSelectionModel::selectionChanged,
+ this, &DeviceProcessesDialogPrivate::updateButtons);
connect(updateListButton, &QAbstractButton::clicked,
this, &DeviceProcessesDialogPrivate::updateProcessList);
connect(kitChooser, &KitChooser::currentIndexChanged,
@@ -219,7 +215,7 @@ void DeviceProcessesDialogPrivate::setDevice(const IDevice::ConstPtr &device)
processList = device->createProcessListModel();
QTC_ASSERT(processList, return);
- proxyModel.setSourceModel(processList);
+ proxyModel.setSourceModel(processList->model());
connect(processList, &DeviceProcessList::error,
this, &DeviceProcessesDialogPrivate::handleRemoteError);
@@ -267,7 +263,7 @@ void DeviceProcessesDialogPrivate::killProcess()
void DeviceProcessesDialogPrivate::updateDevice()
{
- setDevice(DeviceKitInformation::device(kitChooser->currentKit()));
+ setDevice(DeviceKitAspect::device(kitChooser->currentKit()));
}
void DeviceProcessesDialogPrivate::handleProcessKilled()
diff --git a/src/plugins/projectexplorer/devicesupport/deviceprocesslist.cpp b/src/plugins/projectexplorer/devicesupport/deviceprocesslist.cpp
index e6075da516..0405956100 100644
--- a/src/plugins/projectexplorer/devicesupport/deviceprocesslist.cpp
+++ b/src/plugins/projectexplorer/devicesupport/deviceprocesslist.cpp
@@ -27,23 +27,38 @@
#include "localprocesslist.h"
#include <utils/qtcassert.h>
+#include <utils/treemodel.h>
+
+using namespace Utils;
namespace ProjectExplorer {
namespace Internal {
enum State { Inactive, Listing, Killing };
+class DeviceProcessTreeItem : public TreeItem
+{
+public:
+ DeviceProcessTreeItem(const DeviceProcessItem &p, Qt::ItemFlags f) : process(p), fl(f) {}
+
+ QVariant data(int column, int role) const final;
+ Qt::ItemFlags flags(int) const final { return fl; }
+
+ DeviceProcessItem process;
+ Qt::ItemFlags fl;
+};
+
class DeviceProcessListPrivate
{
public:
DeviceProcessListPrivate(const IDevice::ConstPtr &device)
- : device(device),
- state(Inactive)
+ : device(device)
{ }
+ qint64 ownPid = -1;
const IDevice::ConstPtr device;
- QList<DeviceProcessItem> remoteProcesses;
- State state;
+ State state = Inactive;
+ TreeModel<TypedTreeItem<DeviceProcessTreeItem>, DeviceProcessTreeItem> model;
};
} // namespace Internal
@@ -51,39 +66,19 @@ public:
using namespace Internal;
DeviceProcessList::DeviceProcessList(const IDevice::ConstPtr &device, QObject *parent)
- : QAbstractItemModel(parent), d(std::make_unique<DeviceProcessListPrivate>(device))
-{ }
-
-DeviceProcessList::~DeviceProcessList() = default;
-
-QModelIndex DeviceProcessList::parent(const QModelIndex &) const
+ : QObject(parent), d(std::make_unique<DeviceProcessListPrivate>(device))
{
- return QModelIndex();
-}
-
-bool DeviceProcessList::hasChildren(const QModelIndex &parent) const
-{
- if (!parent.isValid())
- return rowCount(parent) > 0 && columnCount(parent) > 0;
- return false;
-}
-
-QModelIndex DeviceProcessList::index(int row, int column, const QModelIndex &parent) const
-{
- return hasIndex(row, column, parent) ? createIndex(row, column) : QModelIndex();
+ d->model.setHeader({tr("Process ID"), tr("Command Line")});
}
+DeviceProcessList::~DeviceProcessList() = default;
void DeviceProcessList::update()
{
QTC_ASSERT(d->state == Inactive, return);
QTC_ASSERT(device(), return);
- if (!d->remoteProcesses.isEmpty()) {
- beginRemoveRows(QModelIndex(), 0, d->remoteProcesses.count() - 1);
- d->remoteProcesses.clear();
- endRemoveRows();
- }
+ d->model.clear();
d->state = Listing;
doUpdate();
}
@@ -92,22 +87,29 @@ void DeviceProcessList::reportProcessListUpdated(const QList<DeviceProcessItem>
{
QTC_ASSERT(d->state == Listing, return);
setFinished();
- if (!processes.isEmpty()) {
- beginInsertRows(QModelIndex(), 0, processes.count() - 1);
- d->remoteProcesses = processes;
- endInsertRows();
+ for (const DeviceProcessItem &process : processes) {
+ Qt::ItemFlags fl;
+ if (process.pid != d->ownPid)
+ fl = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
+ d->model.rootItem()->appendChild(new DeviceProcessTreeItem(process, fl));
}
+
emit processListUpdated();
}
void DeviceProcessList::killProcess(int row)
{
- QTC_ASSERT(row >= 0 && row < d->remoteProcesses.count(), return);
+ QTC_ASSERT(row >= 0 && row < d->model.rootItem()->childCount(), return);
QTC_ASSERT(d->state == Inactive, return);
QTC_ASSERT(device(), return);
d->state = Killing;
- doKillProcess(d->remoteProcesses.at(row));
+ doKillProcess(at(row));
+}
+
+void DeviceProcessList::setOwnPid(qint64 pid)
+{
+ d->ownPid = pid;
}
void DeviceProcessList::reportProcessKilled()
@@ -119,40 +121,21 @@ void DeviceProcessList::reportProcessKilled()
DeviceProcessItem DeviceProcessList::at(int row) const
{
- return d->remoteProcesses.at(row);
+ return d->model.rootItem()->childAt(row)->process;
}
-int DeviceProcessList::rowCount(const QModelIndex &parent) const
+QAbstractItemModel *DeviceProcessList::model() const
{
- return parent.isValid() ? 0 : d->remoteProcesses.count();
+ return &d->model;
}
-int DeviceProcessList::columnCount(const QModelIndex &) const
+QVariant DeviceProcessTreeItem::data(int column, int role) const
{
- return 2;
-}
-
-QVariant DeviceProcessList::headerData(int section, Qt::Orientation orientation,
- int role) const
-{
- if (orientation != Qt::Horizontal || role != Qt::DisplayRole || section < 0
- || section >= columnCount())
- return QVariant();
- return section == 0? tr("Process ID") : tr("Command Line");
-}
-
-QVariant DeviceProcessList::data(const QModelIndex &index, int role) const
-{
- if (!index.isValid() || index.row() >= rowCount(index.parent())
- || index.column() >= columnCount())
- return QVariant();
-
if (role == Qt::DisplayRole || role == Qt::ToolTipRole) {
- const DeviceProcessItem &proc = d->remoteProcesses.at(index.row());
- if (index.column() == 0)
- return proc.pid;
+ if (column == 0)
+ return process.pid;
else
- return proc.cmdLine;
+ return process.cmdLine;
}
return QVariant();
}
diff --git a/src/plugins/projectexplorer/devicesupport/deviceprocesslist.h b/src/plugins/projectexplorer/devicesupport/deviceprocesslist.h
index 18fa97337d..c7959dc3a5 100644
--- a/src/plugins/projectexplorer/devicesupport/deviceprocesslist.h
+++ b/src/plugins/projectexplorer/devicesupport/deviceprocesslist.h
@@ -46,7 +46,7 @@ public:
QString exe;
};
-class PROJECTEXPLORER_EXPORT DeviceProcessList : public QAbstractItemModel
+class PROJECTEXPLORER_EXPORT DeviceProcessList : public QObject
{
Q_OBJECT
@@ -56,7 +56,10 @@ public:
void update();
void killProcess(int row);
+ void setOwnPid(qint64 pid);
+
DeviceProcessItem at(int row) const;
+ QAbstractItemModel *model() const;
static QList<DeviceProcessItem> localProcesses();
@@ -73,15 +76,6 @@ protected:
IDevice::ConstPtr device() const;
private:
- QModelIndex index(int row, int column, const QModelIndex &parent) const override;
- int rowCount(const QModelIndex &parent = QModelIndex()) const override;
- int columnCount(const QModelIndex &parent = QModelIndex()) 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;
- QModelIndex parent(const QModelIndex &) const override;
- bool hasChildren(const QModelIndex &parent) const override;
-
virtual void doUpdate() = 0;
virtual void doKillProcess(const DeviceProcessItem &process) = 0;
diff --git a/src/plugins/projectexplorer/devicesupport/devicesettingswidget.cpp b/src/plugins/projectexplorer/devicesupport/devicesettingswidget.cpp
index 5cb6623f1c..af42589622 100644
--- a/src/plugins/projectexplorer/devicesupport/devicesettingswidget.cpp
+++ b/src/plugins/projectexplorer/devicesupport/devicesettingswidget.cpp
@@ -122,7 +122,7 @@ void DeviceSettingsWidget::initGui()
lastIndex = 0;
if (lastIndex < m_ui->configurationComboBox->count())
m_ui->configurationComboBox->setCurrentIndex(lastIndex);
- connect(m_ui->configurationComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
+ connect(m_ui->configurationComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &DeviceSettingsWidget::currentDeviceChanged);
currentDeviceChanged(currentIndex());
connect(m_ui->defaultDeviceButton, &QAbstractButton::clicked,
diff --git a/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.h b/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.h
index e739af3163..4344f059a5 100644
--- a/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.h
+++ b/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.h
@@ -27,7 +27,7 @@
#include "idevice.h"
-#include <projectexplorer/runconfiguration.h>
+#include <projectexplorer/runcontrol.h>
#include <utils/portlist.h>
diff --git a/src/plugins/projectexplorer/devicesupport/idevice.cpp b/src/plugins/projectexplorer/devicesupport/idevice.cpp
index 54caab5f99..86d783a6d9 100644
--- a/src/plugins/projectexplorer/devicesupport/idevice.cpp
+++ b/src/plugins/projectexplorer/devicesupport/idevice.cpp
@@ -27,6 +27,7 @@
#include "devicemanager.h"
#include "deviceprocesslist.h"
+#include "idevicefactory.h"
#include "../kit.h"
#include "../kitinformation.h"
@@ -152,6 +153,7 @@ public:
QList<Utils::Icon> deviceIcons;
QList<IDevice::DeviceAction> deviceActions;
QVariantMap extraData;
+ IDevice::OpenTerminal openTerminal;
};
} // namespace Internal
@@ -161,6 +163,11 @@ IDevice::IDevice() : d(new Internal::IDevicePrivate)
{
}
+void IDevice::setOpenTerminal(const IDevice::OpenTerminal &openTerminal)
+{
+ d->openTerminal = openTerminal;
+}
+
void IDevice::setupId(Origin origin, Core::Id id)
{
d->origin = origin;
@@ -168,11 +175,15 @@ void IDevice::setupId(Origin origin, Core::Id id)
d->id = id.isValid() ? id : newId();
}
-IDevice::IDevice(const IDevice &other)
- : QEnableSharedFromThis<IDevice>(other)
- , d(std::make_unique<Internal::IDevicePrivate>())
+bool IDevice::canOpenTerminal() const
{
- *d = *other.d;
+ return bool(d->openTerminal);
+}
+
+void IDevice::openTerminal(const Utils::Environment &env, const QString &workingDir) const
+{
+ QTC_ASSERT(canOpenTerminal(), return);
+ d->openTerminal(env, workingDir);
}
IDevice::~IDevice() = default;
@@ -249,7 +260,7 @@ Core::Id IDevice::id() const
*/
bool IDevice::isCompatibleWith(const Kit *k) const
{
- return DeviceTypeKitInformation::deviceTypeId(k) == type();
+ return DeviceTypeKitAspect::deviceTypeId(k) == type();
}
void IDevice::addDeviceAction(const DeviceAction &deviceAction)
@@ -395,6 +406,19 @@ QVariantMap IDevice::toMap() const
return map;
}
+IDevice::Ptr IDevice::clone() const
+{
+ IDeviceFactory *factory = IDeviceFactory::find(d->type);
+ QTC_ASSERT(factory, return {});
+ IDevice::Ptr device = factory->construct();
+ QTC_ASSERT(device, return {});
+ device->d->deviceState = d->deviceState;
+ device->d->deviceActions = d->deviceActions;
+ device->d->deviceIcons = d->deviceIcons;
+ device->fromMap(toMap());
+ return device;
+}
+
QString IDevice::deviceStateToString() const
{
const char context[] = "ProjectExplorer::IDevice";
diff --git a/src/plugins/projectexplorer/devicesupport/idevice.h b/src/plugins/projectexplorer/devicesupport/idevice.h
index 560325617c..b263544000 100644
--- a/src/plugins/projectexplorer/devicesupport/idevice.h
+++ b/src/plugins/projectexplorer/devicesupport/idevice.h
@@ -120,6 +120,7 @@ public:
// See cpp file for documentation.
class PROJECTEXPLORER_EXPORT IDevice : public QEnableSharedFromThis<IDevice>
{
+ friend class Internal::IDevicePrivate;
public:
using Ptr = QSharedPointer<IDevice>;
using ConstPtr = QSharedPointer<const IDevice>;
@@ -127,9 +128,10 @@ public:
enum Origin { ManuallyAdded, AutoDetected };
enum MachineType { Hardware, Emulator };
- IDevice &operator=(const IDevice &) = delete;
virtual ~IDevice();
+ Ptr clone() const;
+
QString displayName() const;
void setDisplayName(const QString &name);
@@ -187,7 +189,6 @@ public:
virtual void fromMap(const QVariantMap &map);
virtual QVariantMap toMap() const;
- virtual Ptr clone() const = 0;
static Core::Id typeFromMap(const QVariantMap &map);
static Core::Id idFromMap(const QVariantMap &map);
@@ -218,11 +219,19 @@ public:
void setupId(Origin origin, Core::Id id = Core::Id());
+ bool canOpenTerminal() const;
+ void openTerminal(const Utils::Environment &env, const QString &workingDir) const;
+
protected:
IDevice();
- IDevice(const IDevice &other);
+
+ using OpenTerminal = std::function<void(const Utils::Environment &, const QString &)>;
+ void setOpenTerminal(const OpenTerminal &openTerminal);
private:
+ IDevice(const IDevice &) = delete;
+ IDevice &operator=(const IDevice &) = delete;
+
int version() const;
const std::unique_ptr<Internal::IDevicePrivate> d;
diff --git a/src/plugins/projectexplorer/devicesupport/localprocesslist.cpp b/src/plugins/projectexplorer/devicesupport/localprocesslist.cpp
index b0d95c6474..832cbd5246 100644
--- a/src/plugins/projectexplorer/devicesupport/localprocesslist.cpp
+++ b/src/plugins/projectexplorer/devicesupport/localprocesslist.cpp
@@ -56,8 +56,8 @@ namespace Internal {
LocalProcessList::LocalProcessList(const IDevice::ConstPtr &device, QObject *parent)
: DeviceProcessList(device, parent)
- , m_myPid(GetCurrentProcessId())
{
+ setOwnPid(GetCurrentProcessId());
}
QList<DeviceProcessItem> LocalProcessList::getLocalProcesses()
@@ -89,8 +89,9 @@ QList<DeviceProcessItem> LocalProcessList::getLocalProcesses()
#ifdef Q_OS_UNIX
LocalProcessList::LocalProcessList(const IDevice::ConstPtr &device, QObject *parent)
: DeviceProcessList(device, parent)
- , m_myPid(getpid())
-{}
+{
+ setOwnPid(getpid());
+}
static bool isUnixProcessId(const QString &procname)
{
@@ -206,14 +207,6 @@ void LocalProcessList::doKillProcess(const DeviceProcessItem &process)
signalOperation->killProcess(process.pid);
}
-Qt::ItemFlags LocalProcessList::flags(const QModelIndex &index) const
-{
- Qt::ItemFlags flags = DeviceProcessList::flags(index);
- if (index.isValid() && at(index.row()).pid == m_myPid)
- flags &= ~(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
- return flags;
-}
-
void LocalProcessList::handleUpdate()
{
reportProcessListUpdated(getLocalProcesses());
diff --git a/src/plugins/projectexplorer/devicesupport/localprocesslist.h b/src/plugins/projectexplorer/devicesupport/localprocesslist.h
index 599f20ed3e..8e10086849 100644
--- a/src/plugins/projectexplorer/devicesupport/localprocesslist.h
+++ b/src/plugins/projectexplorer/devicesupport/localprocesslist.h
@@ -36,7 +36,6 @@ class LocalProcessList : public DeviceProcessList
public:
explicit LocalProcessList(const IDevice::ConstPtr &device, QObject *parent = nullptr);
- Qt::ItemFlags flags(const QModelIndex &index) const override;
static QList<DeviceProcessItem> getLocalProcesses();
@@ -47,8 +46,6 @@ private:
private:
void handleUpdate();
void reportDelayedKillStatus(const QString &errorMessage);
-
- const qint64 m_myPid;
};
} // namespace Internal
diff --git a/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp b/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp
index f094cb1473..7e8be72c65 100644
--- a/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp
+++ b/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp
@@ -26,7 +26,7 @@
#include "sshdeviceprocess.h"
#include "idevice.h"
-#include "../runconfiguration.h"
+#include "../runcontrol.h"
#include <ssh/sshconnection.h>
#include <ssh/sshconnectionmanager.h>
@@ -188,21 +188,21 @@ void SshDeviceProcess::handleConnected()
d->process = runInTerminal() && d->runnable.executable.isEmpty()
? d->connection->createRemoteShell()
- : d->connection->createRemoteProcess(fullCommandLine(d->runnable).toUtf8());
+ : d->connection->createRemoteProcess(fullCommandLine(d->runnable));
const QString display = d->displayName();
if (!display.isEmpty())
d->process->requestX11Forwarding(display);
if (runInTerminal()) {
d->process->requestTerminal();
const QStringList cmdLine = d->process->fullLocalCommandLine();
- connect(&d->consoleProcess,
- static_cast<void (ConsoleProcess::*)(QProcess::ProcessError)>(&ConsoleProcess::error),
+ connect(&d->consoleProcess, QOverload<QProcess::ProcessError>::of(&ConsoleProcess::error),
this, &DeviceProcess::error);
connect(&d->consoleProcess, &ConsoleProcess::processStarted,
this, &SshDeviceProcess::handleProcessStarted);
connect(&d->consoleProcess, &ConsoleProcess::stubStopped,
this, [this] { handleProcessFinished(d->consoleProcess.errorString()); });
- d->consoleProcess.start(cmdLine.first(), cmdLine.mid(1).join(' '));
+ d->consoleProcess.start(cmdLine.first(), cmdLine.mid(1).join(' '),
+ ConsoleProcess::MetaCharMode::Ignore);
} else {
connect(d->process.get(), &QSsh::SshRemoteProcess::started,
this, &SshDeviceProcess::handleProcessStarted);
diff --git a/src/plugins/projectexplorer/devicesupport/sshdeviceprocesslist.cpp b/src/plugins/projectexplorer/devicesupport/sshdeviceprocesslist.cpp
index c1c7b0a45f..d8107458fd 100644
--- a/src/plugins/projectexplorer/devicesupport/sshdeviceprocesslist.cpp
+++ b/src/plugins/projectexplorer/devicesupport/sshdeviceprocesslist.cpp
@@ -54,7 +54,7 @@ void SshDeviceProcessList::doUpdate()
this, &SshDeviceProcessList::handleConnectionError);
connect(&d->process, &SshRemoteProcessRunner::processClosed,
this, &SshDeviceProcessList::handleListProcessFinished);
- d->process.run(listProcessesCommandLine().toUtf8(), device()->sshParameters());
+ d->process.run(listProcessesCommandLine(), device()->sshParameters());
}
void SshDeviceProcessList::doKillProcess(const DeviceProcessItem &process)
diff --git a/src/plugins/projectexplorer/devicesupport/sshsettingspage.cpp b/src/plugins/projectexplorer/devicesupport/sshsettingspage.cpp
index 32b6b3e83e..152467c93e 100644
--- a/src/plugins/projectexplorer/devicesupport/sshsettingspage.cpp
+++ b/src/plugins/projectexplorer/devicesupport/sshsettingspage.cpp
@@ -58,7 +58,7 @@ private:
void setupSftpPathChooser();
void setupAskpassPathChooser();
void setupKeygenPathChooser();
- void setupPathChooser(PathChooser &chooser, const FileName &initialPath, bool &changedFlag);
+ void setupPathChooser(PathChooser &chooser, const FilePath &initialPath, bool &changedFlag);
void updateCheckboxEnabled();
void updateSpinboxEnabled();
@@ -170,7 +170,7 @@ void SshSettingsWidget::setupKeygenPathChooser()
setupPathChooser(m_keygenChooser, SshSettings::keygenFilePath(), m_keygenPathChanged);
}
-void SshSettingsWidget::setupPathChooser(PathChooser &chooser, const FileName &initialPath,
+void SshSettingsWidget::setupPathChooser(PathChooser &chooser, const FilePath &initialPath,
bool &changedFlag)
{
chooser.setExpectedKind(PathChooser::ExistingCommand);
diff --git a/src/plugins/projectexplorer/editorconfiguration.cpp b/src/plugins/projectexplorer/editorconfiguration.cpp
index 43f7b79c69..40e08d368e 100644
--- a/src/plugins/projectexplorer/editorconfiguration.cpp
+++ b/src/plugins/projectexplorer/editorconfiguration.cpp
@@ -395,7 +395,7 @@ TabSettings actualTabSettings(const QString &fileName,
{
if (baseTextdocument)
return baseTextdocument->tabSettings();
- if (Project *project = SessionManager::projectForFile(Utils::FileName::fromString(fileName)))
+ if (Project *project = SessionManager::projectForFile(Utils::FilePath::fromString(fileName)))
return project->editorConfiguration()->codeStyle()->tabSettings();
return TextEditorSettings::codeStyle()->tabSettings();
}
diff --git a/src/plugins/projectexplorer/editorsettingspropertiespage.cpp b/src/plugins/projectexplorer/editorsettingspropertiespage.cpp
index 83fc49dcea..ba76cb078e 100644
--- a/src/plugins/projectexplorer/editorsettingspropertiespage.cpp
+++ b/src/plugins/projectexplorer/editorsettingspropertiespage.cpp
@@ -43,14 +43,14 @@ EditorSettingsWidget::EditorSettingsWidget(Project *project) : QWidget(), m_proj
globalSettingsActivated(config->useGlobalSettings() ? 0 : 1);
- connect(m_ui.globalSelector, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated),
+ connect(m_ui.globalSelector, QOverload<int>::of(&QComboBox::activated),
this, &EditorSettingsWidget::globalSettingsActivated);
connect(m_ui.restoreButton, &QAbstractButton::clicked,
this, &EditorSettingsWidget::restoreDefaultValues);
connect(m_ui.showWrapColumn, &QAbstractButton::toggled,
config, &EditorConfiguration::setShowWrapColumn);
- connect(m_ui.wrapColumn, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
+ connect(m_ui.wrapColumn, QOverload<int>::of(&QSpinBox::valueChanged),
config, &EditorConfiguration::setWrapColumn);
connect(m_ui.behaviorSettingsWidget, &TextEditor::BehaviorSettingsWidget::typingSettingsChanged,
diff --git a/src/plugins/projectexplorer/environmentaspect.cpp b/src/plugins/projectexplorer/environmentaspect.cpp
index d0b0845a3e..0b0eff1e37 100644
--- a/src/plugins/projectexplorer/environmentaspect.cpp
+++ b/src/plugins/projectexplorer/environmentaspect.cpp
@@ -30,6 +30,8 @@
#include <utils/qtcassert.h>
+using namespace Utils;
+
static const char BASE_KEY[] = "PE.EnvironmentAspect.Base";
static const char CHANGES_KEY[] = "PE.EnvironmentAspect.Changes";
@@ -53,9 +55,7 @@ int EnvironmentAspect::baseEnvironmentBase() const
void EnvironmentAspect::setBaseEnvironmentBase(int base)
{
- QTC_ASSERT(base >= 0, return);
- QTC_ASSERT(possibleBaseEnvironments().contains(base), return);
-
+ QTC_ASSERT(base >= 0 && base < m_baseEnvironments.size(), return);
if (m_base != base) {
m_base = base;
emit baseEnvironmentChanged();
@@ -64,53 +64,81 @@ void EnvironmentAspect::setBaseEnvironmentBase(int base)
void EnvironmentAspect::setUserEnvironmentChanges(const QList<Utils::EnvironmentItem> &diff)
{
- if (m_changes != diff) {
- m_changes = diff;
- emit userEnvironmentChangesChanged(m_changes);
+ if (m_userChanges != diff) {
+ m_userChanges = diff;
+ emit userEnvironmentChangesChanged(m_userChanges);
emit environmentChanged();
}
}
Utils::Environment EnvironmentAspect::environment() const
{
- Utils::Environment env = baseEnvironment();
- env.modify(m_changes);
+ QTC_ASSERT(m_base >= 0 && m_base < m_baseEnvironments.size(), return Environment());
+ Environment env = m_baseEnvironments.at(m_base).unmodifiedBaseEnvironment();
+ for (const EnvironmentModifier &modifier : m_modifiers)
+ modifier(env);
+ env.modify(m_userChanges);
return env;
}
-QList<int> EnvironmentAspect::possibleBaseEnvironments() const
+const QStringList EnvironmentAspect::displayNames() const
{
- return m_displayNames.keys();
+ return Utils::transform(m_baseEnvironments, &BaseEnvironment::displayName);
}
-QString EnvironmentAspect::baseEnvironmentDisplayName(int base) const
+void EnvironmentAspect::addModifier(const EnvironmentAspect::EnvironmentModifier &modifier)
{
- return m_displayNames[base];
+ m_modifiers.append(modifier);
}
-void EnvironmentAspect::addSupportedBaseEnvironment(int base, const QString &displayName)
+void EnvironmentAspect::addSupportedBaseEnvironment(const QString &displayName,
+ const std::function<Environment()> &getter)
{
- m_displayNames[base] = displayName;
+ BaseEnvironment baseEnv;
+ baseEnv.displayName = displayName;
+ baseEnv.getter = getter;
+ m_baseEnvironments.append(baseEnv);
if (m_base == -1)
- setBaseEnvironmentBase(base);
+ setBaseEnvironmentBase(m_baseEnvironments.size() - 1);
}
-void EnvironmentAspect::addPreferredBaseEnvironment(int base, const QString &displayName)
+void EnvironmentAspect::addPreferredBaseEnvironment(const QString &displayName,
+ const std::function<Environment()> &getter)
{
- m_displayNames[base] = displayName;
- setBaseEnvironmentBase(base);
+ BaseEnvironment baseEnv;
+ baseEnv.displayName = displayName;
+ baseEnv.getter = getter;
+ m_baseEnvironments.append(baseEnv);
+ setBaseEnvironmentBase(m_baseEnvironments.size() - 1);
}
void EnvironmentAspect::fromMap(const QVariantMap &map)
{
m_base = map.value(QLatin1String(BASE_KEY), -1).toInt();
- m_changes = Utils::EnvironmentItem::fromStringList(map.value(QLatin1String(CHANGES_KEY)).toStringList());
+ m_userChanges = Utils::EnvironmentItem::fromStringList(map.value(QLatin1String(CHANGES_KEY)).toStringList());
}
void EnvironmentAspect::toMap(QVariantMap &data) const
{
data.insert(QLatin1String(BASE_KEY), m_base);
- data.insert(QLatin1String(CHANGES_KEY), Utils::EnvironmentItem::toStringList(m_changes));
+ data.insert(QLatin1String(CHANGES_KEY), Utils::EnvironmentItem::toStringList(m_userChanges));
+}
+
+Environment EnvironmentAspect::currentUnmodifiedBaseEnvironment() const
+{
+ QTC_ASSERT(m_base >= 0 && m_base < m_baseEnvironments.size(), return Environment());
+ return m_baseEnvironments.at(m_base).unmodifiedBaseEnvironment();
+}
+
+QString EnvironmentAspect::currentDisplayName() const
+{
+ QTC_ASSERT(m_base >= 0 && m_base < m_baseEnvironments.size(), return {});
+ return m_baseEnvironments[m_base].displayName;
+}
+
+Environment EnvironmentAspect::BaseEnvironment::unmodifiedBaseEnvironment() const
+{
+ return getter ? getter() : Environment();
}
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/environmentaspect.h b/src/plugins/projectexplorer/environmentaspect.h
index 7d0ecbe406..6657d1dfe8 100644
--- a/src/plugins/projectexplorer/environmentaspect.h
+++ b/src/plugins/projectexplorer/environmentaspect.h
@@ -41,22 +41,32 @@ class PROJECTEXPLORER_EXPORT EnvironmentAspect : public ProjectConfigurationAspe
Q_OBJECT
public:
- // The environment the user chose as base for his modifications.
- virtual Utils::Environment baseEnvironment() const = 0;
+ EnvironmentAspect();
+
// The environment including the user's modifications.
Utils::Environment environment() const;
- QList<int> possibleBaseEnvironments() const;
- QString baseEnvironmentDisplayName(int base) const;
-
int baseEnvironmentBase() const;
void setBaseEnvironmentBase(int base);
- QList<Utils::EnvironmentItem> userEnvironmentChanges() const { return m_changes; }
+ QList<Utils::EnvironmentItem> userEnvironmentChanges() const { return m_userChanges; }
void setUserEnvironmentChanges(const QList<Utils::EnvironmentItem> &diff);
- void addSupportedBaseEnvironment(int base, const QString &displayName);
- void addPreferredBaseEnvironment(int base, const QString &displayName);
+ void addSupportedBaseEnvironment(const QString &displayName,
+ const std::function<Utils::Environment()> &getter);
+ void addPreferredBaseEnvironment(const QString &displayName,
+ const std::function<Utils::Environment()> &getter);
+
+ // The environment the user chose as base for his modifications.
+ Utils::Environment currentUnmodifiedBaseEnvironment() const;
+ QString currentDisplayName() const;
+
+ const QStringList displayNames() const;
+
+ using EnvironmentModifier = std::function<void(Utils::Environment &)>;
+ void addModifier(const EnvironmentModifier &);
+
+ bool isLocal() const { return m_isLocal; }
signals:
void baseEnvironmentChanged();
@@ -64,14 +74,25 @@ signals:
void environmentChanged();
protected:
- EnvironmentAspect();
void fromMap(const QVariantMap &map) override;
void toMap(QVariantMap &map) const override;
+ void setIsLocal(bool local) { m_isLocal = local; }
+
private:
+ // One possible choice in the Environment aspect.
+ struct BaseEnvironment {
+ Utils::Environment unmodifiedBaseEnvironment() const;
+
+ std::function<Utils::Environment()> getter;
+ QString displayName;
+ };
+
+ QList<Utils::EnvironmentItem> m_userChanges;
+ QList<EnvironmentModifier> m_modifiers;
+ QList<BaseEnvironment> m_baseEnvironments;
int m_base = -1;
- QList<Utils::EnvironmentItem> m_changes;
- QMap<int, QString> m_displayNames;
+ bool m_isLocal = false;
};
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/environmentaspectwidget.cpp b/src/plugins/projectexplorer/environmentaspectwidget.cpp
index 7b5c9e5e5f..0898a3f1b6 100644
--- a/src/plugins/projectexplorer/environmentaspectwidget.cpp
+++ b/src/plugins/projectexplorer/environmentaspectwidget.cpp
@@ -56,22 +56,15 @@ EnvironmentAspectWidget::EnvironmentAspectWidget(EnvironmentAspect *aspect, QWid
baseLayout->setMargin(0);
auto label = new QLabel(tr("Base environment for this run configuration:"), this);
baseLayout->addWidget(label);
+
m_baseEnvironmentComboBox = new QComboBox;
- QList<int> bases = m_aspect->possibleBaseEnvironments();
- int currentBase = m_aspect->baseEnvironmentBase();
- QString baseDisplayName;
- foreach (int i, bases) {
- const QString displayName = m_aspect->baseEnvironmentDisplayName(i);
- m_baseEnvironmentComboBox->addItem(displayName, i);
- if (i == currentBase) {
- m_baseEnvironmentComboBox->setCurrentIndex(m_baseEnvironmentComboBox->count() - 1);
- baseDisplayName = displayName;
- }
- }
+ for (const QString &displayName : m_aspect->displayNames())
+ m_baseEnvironmentComboBox->addItem(displayName);
if (m_baseEnvironmentComboBox->count() == 1)
m_baseEnvironmentComboBox->setEnabled(false);
+ m_baseEnvironmentComboBox->setCurrentIndex(m_aspect->baseEnvironmentBase());
- connect(m_baseEnvironmentComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
+ connect(m_baseEnvironmentComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &EnvironmentAspectWidget::baseEnvironmentSelected);
baseLayout->addWidget(m_baseEnvironmentComboBox);
@@ -79,9 +72,11 @@ EnvironmentAspectWidget::EnvironmentAspectWidget(EnvironmentAspect *aspect, QWid
if (additionalWidget)
baseLayout->addWidget(additionalWidget);
- m_environmentWidget = new EnvironmentWidget(this, baseEnvironmentWidget);
- m_environmentWidget->setBaseEnvironment(m_aspect->baseEnvironment());
- m_environmentWidget->setBaseEnvironmentText(baseDisplayName);
+ const EnvironmentWidget::Type widgetType = aspect->isLocal()
+ ? EnvironmentWidget::TypeLocal : EnvironmentWidget::TypeRemote;
+ m_environmentWidget = new EnvironmentWidget(this, widgetType, baseEnvironmentWidget);
+ m_environmentWidget->setBaseEnvironment(m_aspect->currentUnmodifiedBaseEnvironment());
+ m_environmentWidget->setBaseEnvironmentText(m_aspect->currentDisplayName());
m_environmentWidget->setUserChanges(m_aspect->userEnvironmentChanges());
m_environmentWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
topLayout->addWidget(m_environmentWidget);
@@ -110,10 +105,9 @@ QWidget *EnvironmentAspectWidget::additionalWidget() const
void EnvironmentAspectWidget::baseEnvironmentSelected(int idx)
{
m_ignoreChange = true;
- int base = m_baseEnvironmentComboBox->itemData(idx).toInt();
- m_aspect->setBaseEnvironmentBase(base);
- m_environmentWidget->setBaseEnvironment(m_aspect->baseEnvironment());
- m_environmentWidget->setBaseEnvironmentText(m_aspect->baseEnvironmentDisplayName(base));
+ m_aspect->setBaseEnvironmentBase(idx);
+ m_environmentWidget->setBaseEnvironment(m_aspect->currentUnmodifiedBaseEnvironment());
+ m_environmentWidget->setBaseEnvironmentText(m_aspect->currentDisplayName());
m_ignoreChange = false;
}
@@ -127,8 +121,8 @@ void EnvironmentAspectWidget::changeBaseEnvironment()
if (m_baseEnvironmentComboBox->itemData(i).toInt() == base)
m_baseEnvironmentComboBox->setCurrentIndex(i);
}
- m_environmentWidget->setBaseEnvironmentText(m_aspect->baseEnvironmentDisplayName(base));
- m_environmentWidget->setBaseEnvironment(m_aspect->baseEnvironment());
+ m_environmentWidget->setBaseEnvironmentText(m_aspect->currentDisplayName());
+ m_environmentWidget->setBaseEnvironment(m_aspect->currentUnmodifiedBaseEnvironment());
}
void EnvironmentAspectWidget::userChangesEdited()
@@ -149,7 +143,7 @@ void EnvironmentAspectWidget::environmentChanged()
{
if (m_ignoreChange)
return;
- m_environmentWidget->setBaseEnvironment(m_aspect->baseEnvironment());
+ m_environmentWidget->setBaseEnvironment(m_aspect->currentUnmodifiedBaseEnvironment());
}
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/environmentaspectwidget.h b/src/plugins/projectexplorer/environmentaspectwidget.h
index b5127d889e..6ca8164f05 100644
--- a/src/plugins/projectexplorer/environmentaspectwidget.h
+++ b/src/plugins/projectexplorer/environmentaspectwidget.h
@@ -53,6 +53,7 @@ public:
explicit EnvironmentAspectWidget(EnvironmentAspect *aspect, QWidget *additionalWidget = nullptr);
virtual EnvironmentAspect *aspect() const;
+ EnvironmentWidget *envWidget() const { return m_environmentWidget; }
QWidget *additionalWidget() const;
diff --git a/src/plugins/projectexplorer/environmentwidget.cpp b/src/plugins/projectexplorer/environmentwidget.cpp
index ad643e78be..1a6e424960 100644
--- a/src/plugins/projectexplorer/environmentwidget.cpp
+++ b/src/plugins/projectexplorer/environmentwidget.cpp
@@ -33,10 +33,13 @@
#include <utils/environmentmodel.h>
#include <utils/environmentdialog.h>
#include <utils/headerviewstretcher.h>
+#include <utils/hostosinfo.h>
#include <utils/itemviews.h>
#include <utils/tooltip/tooltip.h>
#include <QDir>
+#include <QFileDialog>
+#include <QFileInfo>
#include <QString>
#include <QPushButton>
#include <QTreeView>
@@ -124,6 +127,7 @@ public:
Utils::EnvironmentModel *m_model;
QString m_baseEnvironmentText;
+ EnvironmentWidget::OpenTerminalFunc m_openTerminalFunc;
Utils::DetailsWidget *m_detailsContainer;
QTreeView *m_environmentView;
QPushButton *m_editButton;
@@ -131,10 +135,12 @@ public:
QPushButton *m_resetButton;
QPushButton *m_unsetButton;
QPushButton *m_batchEditButton;
+ QPushButton *m_appendPathButton = nullptr;
+ QPushButton *m_prependPathButton = nullptr;
QPushButton *m_terminalButton;
};
-EnvironmentWidget::EnvironmentWidget(QWidget *parent, QWidget *additionalDetailsWidget)
+EnvironmentWidget::EnvironmentWidget(QWidget *parent, Type type, QWidget *additionalDetailsWidget)
: QWidget(parent), d(std::make_unique<EnvironmentWidgetPrivate>())
{
d->m_model = new Utils::EnvironmentModel();
@@ -200,6 +206,21 @@ EnvironmentWidget::EnvironmentWidget(QWidget *parent, QWidget *additionalDetails
d->m_unsetButton->setText(tr("&Unset"));
buttonLayout->addWidget(d->m_unsetButton);
+ if (type == TypeLocal) {
+ d->m_appendPathButton = new QPushButton(this);
+ d->m_appendPathButton->setEnabled(false);
+ d->m_appendPathButton->setText(tr("Append Path..."));
+ buttonLayout->addWidget(d->m_appendPathButton);
+ d->m_prependPathButton = new QPushButton(this);
+ d->m_prependPathButton->setEnabled(false);
+ d->m_prependPathButton->setText(tr("Prepend Path..."));
+ buttonLayout->addWidget(d->m_prependPathButton);
+ connect(d->m_appendPathButton, &QAbstractButton::clicked,
+ this, &EnvironmentWidget::appendPathButtonClicked);
+ connect(d->m_prependPathButton, &QAbstractButton::clicked,
+ this, &EnvironmentWidget::prependPathButtonClicked);
+ }
+
d->m_batchEditButton = new QPushButton(this);
d->m_batchEditButton->setText(tr("&Batch Edit..."));
buttonLayout->addWidget(d->m_batchEditButton);
@@ -207,10 +228,8 @@ EnvironmentWidget::EnvironmentWidget(QWidget *parent, QWidget *additionalDetails
d->m_terminalButton = new QPushButton(this);
d->m_terminalButton->setText(tr("Open &Terminal"));
d->m_terminalButton->setToolTip(tr("Open a terminal with this environment set up."));
+ d->m_terminalButton->setEnabled(type == TypeLocal);
buttonLayout->addWidget(d->m_terminalButton);
-#if defined(Q_OS_UNIX) && QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
- d->m_terminalButton->setVisible(false);
-#endif
buttonLayout->addStretch();
horizontalLayout->addLayout(buttonLayout);
@@ -234,7 +253,14 @@ EnvironmentWidget::EnvironmentWidget(QWidget *parent, QWidget *additionalDetails
connect(d->m_environmentView->selectionModel(), &QItemSelectionModel::currentChanged,
this, &EnvironmentWidget::environmentCurrentIndexChanged);
connect(d->m_terminalButton, &QAbstractButton::clicked,
- this, &EnvironmentWidget::openTerminal);
+ this, [this] {
+ Utils::Environment env = d->m_model->baseEnvironment();
+ env.modify(d->m_model->userChanges());
+ if (d->m_openTerminalFunc)
+ d->m_openTerminalFunc(env);
+ else
+ Core::FileUtils::openTerminal(QDir::currentPath(), env);
+ });
connect(d->m_detailsContainer, &Utils::DetailsWidget::linkActivated,
this, &EnvironmentWidget::linkActivated);
@@ -286,6 +312,12 @@ void EnvironmentWidget::setUserChanges(const QList<Utils::EnvironmentItem> &list
updateSummaryText();
}
+void EnvironmentWidget::setOpenTerminalFunc(const EnvironmentWidget::OpenTerminalFunc &func)
+{
+ d->m_openTerminalFunc = func;
+ d->m_terminalButton->setEnabled(bool(func));
+}
+
void EnvironmentWidget::updateSummaryText()
{
QList<Utils::EnvironmentItem> list = d->m_model->userChanges();
@@ -321,6 +353,36 @@ void EnvironmentWidget::linkActivated(const QString &link)
focusIndex(idx);
}
+bool EnvironmentWidget::currentEntryIsPathList(const QModelIndex &current) const
+{
+ if (!current.isValid())
+ return false;
+
+ // Look at the name first and check it against some well-known path variables. Extend as needed.
+ const QString varName = d->m_model->indexToVariable(current);
+ if (varName.compare("PATH", Utils::HostOsInfo::fileNameCaseSensitivity()) == 0)
+ return true;
+ if (Utils::HostOsInfo::isMacHost() && varName == "DYLD_LIBRARY_PATH")
+ return true;
+ if (Utils::HostOsInfo::isAnyUnixHost() && varName == "LD_LIBRARY_PATH")
+ return true;
+
+ // Now check the value: If it's a list of strings separated by the platform's path separator
+ // and at least one of the strings is an existing directory, then that's enough proof for us.
+ QModelIndex valueIndex = current;
+ if (valueIndex.column() == 0)
+ valueIndex = valueIndex.siblingAtColumn(1);
+ const QStringList entries = d->m_model->data(valueIndex).toString()
+ .split(Utils::HostOsInfo::pathListSeparator(), QString::SkipEmptyParts);
+ if (entries.length() < 2)
+ return false;
+ for (const QString &potentialDir : entries) {
+ if (QFileInfo(potentialDir).isDir())
+ return true;
+ }
+ return false;
+}
+
void EnvironmentWidget::updateButtons()
{
environmentCurrentIndexChanged(d->m_environmentView->currentIndex());
@@ -355,6 +417,42 @@ void EnvironmentWidget::unsetEnvironmentButtonClicked()
d->m_model->unsetVariable(name);
}
+void EnvironmentWidget::amendPathList(const PathListModifier &modifier)
+{
+ const QString varName = d->m_model->indexToVariable(d->m_environmentView->currentIndex());
+ const QString dir = QDir::toNativeSeparators(
+ QFileDialog::getExistingDirectory(this, tr("Choose Directory")));
+ if (dir.isEmpty())
+ return;
+ QModelIndex index = d->m_model->variableToIndex(varName);
+ if (!index.isValid())
+ return;
+ if (index.column() == 0)
+ index = index.siblingAtColumn(1);
+ const QString value = d->m_model->data(index).toString();
+ d->m_model->setData(index, modifier(value, dir));
+}
+
+void EnvironmentWidget::appendPathButtonClicked()
+{
+ amendPathList([](const QString &pathList, const QString &dir) {
+ QString newPathList = dir;
+ if (!pathList.isEmpty())
+ newPathList.prepend(Utils::HostOsInfo::pathListSeparator()).prepend(pathList);
+ return newPathList;
+ });
+}
+
+void EnvironmentWidget::prependPathButtonClicked()
+{
+ amendPathList([](const QString &pathList, const QString &dir) {
+ QString newPathList = dir;
+ if (!pathList.isEmpty())
+ newPathList.append(Utils::HostOsInfo::pathListSeparator()).append(pathList);
+ return newPathList;
+ });
+}
+
void EnvironmentWidget::batchEditEnvironmentButtonClicked()
{
const QList<Utils::EnvironmentItem> changes = d->m_model->userChanges();
@@ -367,13 +465,6 @@ void EnvironmentWidget::batchEditEnvironmentButtonClicked()
d->m_model->setUserChanges(newChanges);
}
-void EnvironmentWidget::openTerminal()
-{
- Utils::Environment env = d->m_model->baseEnvironment();
- env.modify(d->m_model->userChanges());
- Core::FileUtils::openTerminal(QDir::currentPath(), env);
-}
-
void EnvironmentWidget::environmentCurrentIndexChanged(const QModelIndex &current)
{
if (current.isValid()) {
@@ -388,6 +479,10 @@ void EnvironmentWidget::environmentCurrentIndexChanged(const QModelIndex &curren
d->m_resetButton->setEnabled(false);
d->m_unsetButton->setEnabled(false);
}
+ if (d->m_appendPathButton) {
+ d->m_appendPathButton->setEnabled(currentEntryIsPathList(current));
+ d->m_prependPathButton->setEnabled(currentEntryIsPathList(current));
+ }
}
void EnvironmentWidget::invalidateCurrentIndex()
diff --git a/src/plugins/projectexplorer/environmentwidget.h b/src/plugins/projectexplorer/environmentwidget.h
index 3eb85bcc8d..927dc9b0c1 100644
--- a/src/plugins/projectexplorer/environmentwidget.h
+++ b/src/plugins/projectexplorer/environmentwidget.h
@@ -29,6 +29,7 @@
#include <QWidget>
+#include <functional>
#include <memory>
QT_FORWARD_DECLARE_CLASS(QModelIndex)
@@ -47,7 +48,9 @@ class PROJECTEXPLORER_EXPORT EnvironmentWidget : public QWidget
Q_OBJECT
public:
- explicit EnvironmentWidget(QWidget *parent, QWidget *additionalDetailsWidget = nullptr);
+ enum Type { TypeLocal, TypeRemote };
+ explicit EnvironmentWidget(QWidget *parent, Type type,
+ QWidget *additionalDetailsWidget = nullptr);
~EnvironmentWidget() override;
void setBaseEnvironmentText(const QString &text);
@@ -56,6 +59,9 @@ public:
QList<Utils::EnvironmentItem> userChanges() const;
void setUserChanges(const QList<Utils::EnvironmentItem> &list);
+ using OpenTerminalFunc = std::function<void(const Utils::Environment &env)>;
+ void setOpenTerminalFunc(const OpenTerminalFunc &func);
+
signals:
void userChangesChanged();
void detailsVisibleChanged(bool visible);
@@ -65,14 +71,19 @@ private:
void addEnvironmentButtonClicked();
void removeEnvironmentButtonClicked();
void unsetEnvironmentButtonClicked();
+ void appendPathButtonClicked();
+ void prependPathButtonClicked();
void batchEditEnvironmentButtonClicked();
- void openTerminal();
void environmentCurrentIndexChanged(const QModelIndex &current);
void invalidateCurrentIndex();
void updateSummaryText();
void focusIndex(const QModelIndex &index);
void updateButtons();
void linkActivated(const QString &link);
+ bool currentEntryIsPathList(const QModelIndex &current) const;
+
+ using PathListModifier = std::function<QString(const QString &oldList, const QString &newDir)>;
+ void amendPathList(const PathListModifier &modifier);
const std::unique_ptr<EnvironmentWidgetPrivate> d;
};
diff --git a/src/plugins/projectexplorer/extraabi.cpp b/src/plugins/projectexplorer/extraabi.cpp
index a1da2193fd..434994125c 100644
--- a/src/plugins/projectexplorer/extraabi.cpp
+++ b/src/plugins/projectexplorer/extraabi.cpp
@@ -65,7 +65,7 @@ AbiFlavorAccessor::AbiFlavorAccessor() :
QCoreApplication::translate("ProjectExplorer::ToolChainManager", "ABI"),
Core::Constants::IDE_DISPLAY_NAME)
{
- setBaseFilePath(FileName::fromString(Core::ICore::installerResourcePath() + "/abi.xml"));
+ setBaseFilePath(FilePath::fromString(Core::ICore::installerResourcePath() + "/abi.xml"));
addVersionUpgrader(std::make_unique<AbiFlavorUpgraderV0>());
}
diff --git a/src/plugins/projectexplorer/extracompiler.cpp b/src/plugins/projectexplorer/extracompiler.cpp
index df7297c33d..adcc8f180e 100644
--- a/src/plugins/projectexplorer/extracompiler.cpp
+++ b/src/plugins/projectexplorer/extracompiler.cpp
@@ -57,9 +57,9 @@ class ExtraCompilerPrivate
{
public:
const Project *project;
- Utils::FileName source;
+ Utils::FilePath source;
FileNameToContentsHash contents;
- QList<Task> issues;
+ Tasks issues;
QDateTime compileTime;
Core::IEditor *lastEditor = nullptr;
QMetaObject::Connection activeBuildConfigConnection;
@@ -70,13 +70,13 @@ public:
void updateIssues();
};
-ExtraCompiler::ExtraCompiler(const Project *project, const Utils::FileName &source,
- const Utils::FileNameList &targets, QObject *parent) :
+ExtraCompiler::ExtraCompiler(const Project *project, const Utils::FilePath &source,
+ const Utils::FilePathList &targets, QObject *parent) :
QObject(parent), d(std::make_unique<ExtraCompilerPrivate>())
{
d->project = project;
d->source = source;
- foreach (const Utils::FileName &target, targets)
+ foreach (const Utils::FilePath &target, targets)
d->contents.insert(target, QByteArray());
d->timer.setSingleShot(true);
@@ -104,7 +104,7 @@ ExtraCompiler::ExtraCompiler(const Project *project, const Utils::FileName &sour
// Use existing target files, where possible. Otherwise run the compiler.
QDateTime sourceTime = d->source.toFileInfo().lastModified();
- foreach (const Utils::FileName &target, targets) {
+ foreach (const Utils::FilePath &target, targets) {
QFileInfo targetFileInfo(target.toFileInfo());
if (!targetFileInfo.exists()) {
d->dirty = true;
@@ -136,22 +136,22 @@ const Project *ExtraCompiler::project() const
return d->project;
}
-Utils::FileName ExtraCompiler::source() const
+Utils::FilePath ExtraCompiler::source() const
{
return d->source;
}
-QByteArray ExtraCompiler::content(const Utils::FileName &file) const
+QByteArray ExtraCompiler::content(const Utils::FilePath &file) const
{
return d->contents.value(file);
}
-Utils::FileNameList ExtraCompiler::targets() const
+Utils::FilePathList ExtraCompiler::targets() const
{
return d->contents.keys();
}
-void ExtraCompiler::forEachTarget(std::function<void (const Utils::FileName &)> func)
+void ExtraCompiler::forEachTarget(std::function<void (const Utils::FilePath &)> func)
{
for (auto it = d->contents.constBegin(), end = d->contents.constEnd(); it != end; ++it)
func(it.key());
@@ -183,7 +183,7 @@ void ExtraCompiler::onTargetsBuilt(Project *project)
if (d->compileTime.isValid() && d->compileTime >= sourceTime)
return;
- forEachTarget([&](const Utils::FileName &target) {
+ forEachTarget([&](const Utils::FilePath &target) {
QFileInfo fi(target.toFileInfo());
QDateTime generateTime = fi.exists() ? fi.lastModified() : QDateTime();
if (generateTime.isValid() && (generateTime > sourceTime)) {
@@ -255,7 +255,7 @@ Utils::Environment ExtraCompiler::buildEnvironment() const
return bc->environment();
} else {
QList<Utils::EnvironmentItem> changes =
- EnvironmentKitInformation::environmentChanges(target->kit());
+ EnvironmentKitAspect::environmentChanges(target->kit());
Utils::Environment env = Utils::Environment::systemEnvironment();
env.modify(changes);
return env;
@@ -265,7 +265,7 @@ Utils::Environment ExtraCompiler::buildEnvironment() const
return Utils::Environment::systemEnvironment();
}
-void ExtraCompiler::setCompileIssues(const QList<Task> &issues)
+void ExtraCompiler::setCompileIssues(const Tasks &issues)
{
d->issues = issues;
d->updateIssues();
@@ -299,7 +299,7 @@ void ExtraCompilerPrivate::updateIssues()
widget->setExtraSelections(TextEditor::TextEditorWidget::CodeWarningsSelection, selections);
}
-void ExtraCompiler::setContent(const Utils::FileName &file, const QByteArray &contents)
+void ExtraCompiler::setContent(const Utils::FilePath &file, const QByteArray &contents)
{
auto it = d->contents.find(file);
if (it != d->contents.end()) {
@@ -322,8 +322,8 @@ ExtraCompilerFactory::~ExtraCompilerFactory()
}
void ExtraCompilerFactory::annouceCreation(const Project *project,
- const Utils::FileName &source,
- const Utils::FileNameList &targets)
+ const Utils::FilePath &source,
+ const Utils::FilePathList &targets)
{
for (ExtraCompilerFactoryObserver *observer : *observers)
observer->newExtraCompiler(project, source, targets);
@@ -334,8 +334,8 @@ QList<ExtraCompilerFactory *> ExtraCompilerFactory::extraCompilerFactories()
return *factories();
}
-ProcessExtraCompiler::ProcessExtraCompiler(const Project *project, const Utils::FileName &source,
- const Utils::FileNameList &targets, QObject *parent) :
+ProcessExtraCompiler::ProcessExtraCompiler(const Project *project, const Utils::FilePath &source,
+ const Utils::FilePathList &targets, QObject *parent) :
ExtraCompiler(project, source, targets, parent)
{ }
@@ -353,7 +353,7 @@ void ProcessExtraCompiler::run(const QByteArray &sourceContents)
runImpl(contents);
}
-void ProcessExtraCompiler::run(const Utils::FileName &fileName)
+void ProcessExtraCompiler::run(const Utils::FilePath &fileName)
{
ContentProvider contents = [fileName]() {
QFile file(fileName.toString());
@@ -364,9 +364,9 @@ void ProcessExtraCompiler::run(const Utils::FileName &fileName)
runImpl(contents);
}
-Utils::FileName ProcessExtraCompiler::workingDirectory() const
+Utils::FilePath ProcessExtraCompiler::workingDirectory() const
{
- return Utils::FileName();
+ return Utils::FilePath();
}
QStringList ProcessExtraCompiler::arguments() const
@@ -380,10 +380,10 @@ bool ProcessExtraCompiler::prepareToRun(const QByteArray &sourceContents)
return true;
}
-QList<Task> ProcessExtraCompiler::parseIssues(const QByteArray &stdErr)
+Tasks ProcessExtraCompiler::parseIssues(const QByteArray &stdErr)
{
Q_UNUSED(stdErr);
- return QList<Task>();
+ return {};
}
void ProcessExtraCompiler::runImpl(const ContentProvider &provider)
@@ -403,7 +403,7 @@ void ProcessExtraCompiler::runImpl(const ContentProvider &provider)
void ProcessExtraCompiler::runInThread(
QFutureInterface<FileNameToContentsHash> &futureInterface,
- const Utils::FileName &cmd, const Utils::FileName &workDir,
+ const Utils::FilePath &cmd, const Utils::FilePath &workDir,
const QStringList &args, const ContentProvider &provider,
const Utils::Environment &env)
{
diff --git a/src/plugins/projectexplorer/extracompiler.h b/src/plugins/projectexplorer/extracompiler.h
index 006555ffc6..ba9c6774f7 100644
--- a/src/plugins/projectexplorer/extracompiler.h
+++ b/src/plugins/projectexplorer/extracompiler.h
@@ -47,27 +47,27 @@ QT_FORWARD_DECLARE_CLASS(QThreadPool);
namespace ProjectExplorer {
class ExtraCompilerPrivate;
-using FileNameToContentsHash = QHash<Utils::FileName, QByteArray>;
+using FileNameToContentsHash = QHash<Utils::FilePath, QByteArray>;
class PROJECTEXPLORER_EXPORT ExtraCompiler : public QObject
{
Q_OBJECT
public:
- ExtraCompiler(const Project *project, const Utils::FileName &source,
- const Utils::FileNameList &targets, QObject *parent = nullptr);
+ ExtraCompiler(const Project *project, const Utils::FilePath &source,
+ const Utils::FilePathList &targets, QObject *parent = nullptr);
~ExtraCompiler() override;
const Project *project() const;
- Utils::FileName source() const;
+ Utils::FilePath source() const;
// You can set the contents from the outside. This is done if the file has been (re)created by
// the regular build process.
- void setContent(const Utils::FileName &file, const QByteArray &content);
- QByteArray content(const Utils::FileName &file) const;
+ void setContent(const Utils::FilePath &file, const QByteArray &content);
+ QByteArray content(const Utils::FilePath &file) const;
- Utils::FileNameList targets() const;
- void forEachTarget(std::function<void(const Utils::FileName &)> func);
+ Utils::FilePathList targets() const;
+ void forEachTarget(std::function<void(const Utils::FilePath &)> func);
void setCompileTime(const QDateTime &time);
QDateTime compileTime() const;
@@ -75,11 +75,11 @@ public:
static QThreadPool *extraCompilerThreadPool();
signals:
- void contentsChanged(const Utils::FileName &file);
+ void contentsChanged(const Utils::FilePath &file);
protected:
Utils::Environment buildEnvironment() const;
- void setCompileIssues(const QList<Task> &issues);
+ void setCompileIssues(const Tasks &issues);
private:
void onTargetsBuilt(Project *project);
@@ -88,7 +88,7 @@ private:
void setDirty();
// This method may not block!
virtual void run(const QByteArray &sourceContent) = 0;
- virtual void run(const Utils::FileName &file) = 0;
+ virtual void run(const Utils::FilePath &file) = 0;
const std::unique_ptr<ExtraCompilerPrivate> d;
};
@@ -98,8 +98,8 @@ class PROJECTEXPLORER_EXPORT ProcessExtraCompiler : public ExtraCompiler
Q_OBJECT
public:
- ProcessExtraCompiler(const Project *project, const Utils::FileName &source,
- const Utils::FileNameList &targets, QObject *parent = nullptr);
+ ProcessExtraCompiler(const Project *project, const Utils::FilePath &source,
+ const Utils::FilePathList &targets, QObject *parent = nullptr);
~ProcessExtraCompiler() override;
protected:
@@ -109,11 +109,11 @@ protected:
// * prepareToRun returns true
// * The process is not yet running
void run(const QByteArray &sourceContents) override;
- void run(const Utils::FileName &fileName) override;
+ void run(const Utils::FilePath &fileName) override;
// Information about the process to run:
- virtual Utils::FileName workingDirectory() const;
- virtual Utils::FileName command() const = 0;
+ virtual Utils::FilePath workingDirectory() const;
+ virtual Utils::FilePath command() const = 0;
virtual QStringList arguments() const;
virtual bool prepareToRun(const QByteArray &sourceContents);
@@ -123,13 +123,13 @@ protected:
{ Q_UNUSED(process); Q_UNUSED(sourceContents); }
virtual FileNameToContentsHash handleProcessFinished(QProcess *process) = 0;
- virtual QList<Task> parseIssues(const QByteArray &stdErr);
+ virtual Tasks parseIssues(const QByteArray &stdErr);
private:
using ContentProvider = std::function<QByteArray()>;
void runImpl(const ContentProvider &sourceContents);
void runInThread(QFutureInterface<FileNameToContentsHash> &futureInterface,
- const Utils::FileName &cmd, const Utils::FileName &workDir,
+ const Utils::FilePath &cmd, const Utils::FilePath &workDir,
const QStringList &args, const ContentProvider &provider,
const Utils::Environment &env);
void cleanUp();
@@ -146,8 +146,8 @@ protected:
~ExtraCompilerFactoryObserver();
virtual void newExtraCompiler(const Project *project,
- const Utils::FileName &source,
- const Utils::FileNameList &targets)
+ const Utils::FilePath &source,
+ const Utils::FilePathList &targets)
= 0;
};
@@ -162,13 +162,13 @@ public:
virtual QString sourceTag() const = 0;
virtual ExtraCompiler *create(const Project *project,
- const Utils::FileName &source,
- const Utils::FileNameList &targets)
+ const Utils::FilePath &source,
+ const Utils::FilePathList &targets)
= 0;
void annouceCreation(const Project *project,
- const Utils::FileName &source,
- const Utils::FileNameList &targets);
+ const Utils::FilePath &source,
+ const Utils::FilePathList &targets);
static QList<ExtraCompilerFactory *> extraCompilerFactories();
};
diff --git a/src/plugins/projectexplorer/fileinsessionfinder.cpp b/src/plugins/projectexplorer/fileinsessionfinder.cpp
new file mode 100644
index 0000000000..e4c62e405f
--- /dev/null
+++ b/src/plugins/projectexplorer/fileinsessionfinder.cpp
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "fileinsessionfinder.h"
+
+#include "project.h"
+#include "session.h"
+
+#include <utils/fileinprojectfinder.h>
+
+#include <QUrl>
+
+using namespace Utils;
+
+namespace ProjectExplorer {
+namespace Internal {
+
+class FileInSessionFinder : public QObject
+{
+public:
+ FileInSessionFinder();
+
+ FilePathList doFindFile(const FilePath &filePath);
+ void invalidateFinder() { m_finderIsUpToDate = false; }
+
+private:
+ FileInProjectFinder m_finder;
+ bool m_finderIsUpToDate = false;
+};
+
+FileInSessionFinder::FileInSessionFinder()
+{
+ connect(SessionManager::instance(), &SessionManager::projectAdded,
+ this, [this](const Project *p) {
+ invalidateFinder();
+ connect(p, &Project::fileListChanged, this, &FileInSessionFinder::invalidateFinder);
+ });
+ connect(SessionManager::instance(), &SessionManager::projectRemoved,
+ this, [this](const Project *p) {
+ invalidateFinder();
+ p->disconnect(this);
+ });
+}
+
+FilePathList FileInSessionFinder::doFindFile(const FilePath &filePath)
+{
+ if (!m_finderIsUpToDate) {
+ m_finder.setProjectDirectory(SessionManager::startupProject()
+ ? SessionManager::startupProject()->projectDirectory()
+ : FilePath());
+ FilePathList allFiles;
+ for (const Project * const p : SessionManager::projects())
+ allFiles << p->files(Project::AllFiles);
+ m_finder.setProjectFiles(allFiles);
+ m_finderIsUpToDate = true;
+ }
+ return m_finder.findFile(QUrl::fromLocalFile(filePath.toString()));
+}
+
+FilePathList findFileInSession(const FilePath &filePath)
+{
+ static FileInSessionFinder finder;
+ return finder.doFindFile(filePath);
+}
+
+} // namespace Internal
+} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/fileinsessionfinder.h b/src/plugins/projectexplorer/fileinsessionfinder.h
new file mode 100644
index 0000000000..f14b3708f3
--- /dev/null
+++ b/src/plugins/projectexplorer/fileinsessionfinder.h
@@ -0,0 +1,36 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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/fileutils.h>
+
+namespace ProjectExplorer {
+namespace Internal {
+
+Utils::FilePathList findFileInSession(const Utils::FilePath &filePath);
+
+} // namespace Internal
+} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/filterkitaspectsdialog.cpp b/src/plugins/projectexplorer/filterkitaspectsdialog.cpp
new file mode 100644
index 0000000000..418ae03564
--- /dev/null
+++ b/src/plugins/projectexplorer/filterkitaspectsdialog.cpp
@@ -0,0 +1,163 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "filterkitaspectsdialog.h"
+
+#include "kitmanager.h"
+
+#include <utils/itemviews.h>
+#include <utils/qtcassert.h>
+#include <utils/treemodel.h>
+
+#include <QDialogButtonBox>
+#include <QHeaderView>
+#include <QString>
+#include <QVBoxLayout>
+
+using namespace Utils;
+
+namespace ProjectExplorer {
+namespace Internal {
+
+class FilterTreeItem : public TreeItem
+{
+public:
+ FilterTreeItem(const KitAspect *aspect, bool enabled) : m_aspect(aspect), m_enabled(enabled)
+ { }
+
+ QString displayName() const { return m_aspect->displayName(); }
+ Core::Id id() const { return m_aspect->id(); }
+ bool enabled() const { return m_enabled; }
+
+private:
+ QVariant data(int column, int role) const override
+ {
+ QTC_ASSERT(column < 2, return QVariant());
+ if (column == 0 && role == Qt::DisplayRole)
+ return displayName();
+ if (column == 1 && role == Qt::CheckStateRole)
+ return m_enabled ? Qt::Checked : Qt::Unchecked;
+ return QVariant();
+ }
+
+ bool setData(int column, const QVariant &data, int role) override
+ {
+ QTC_ASSERT(column == 1 && !m_aspect->isEssential(), return false);
+ if (role == Qt::CheckStateRole) {
+ m_enabled = data.toInt() == Qt::Checked;
+ return true;
+ }
+ return false;
+ }
+
+ Qt::ItemFlags flags(int column) const override
+ {
+ QTC_ASSERT(column < 2, return Qt::ItemFlags());
+ Qt::ItemFlags flags = Qt::ItemIsSelectable;
+ if (column == 0 || !m_aspect->isEssential())
+ flags |= Qt::ItemIsEnabled;
+ if (column == 1 && !m_aspect->isEssential())
+ flags |= Qt::ItemIsUserCheckable;
+ return flags;
+ }
+
+ const KitAspect * const m_aspect;
+ bool m_enabled;
+};
+
+class FilterKitAspectsModel : public TreeModel<TreeItem, FilterTreeItem>
+{
+public:
+ FilterKitAspectsModel(const Kit *kit, QObject *parent) : TreeModel(parent)
+ {
+ setHeader({tr("Setting"), tr("Visible")});
+ for (const KitAspect * const aspect : KitManager::kitAspects()) {
+ if (kit && !aspect->isApplicableToKit(kit))
+ continue;
+ const QSet<Core::Id> irrelevantAspects = kit ? kit->irrelevantAspects()
+ : KitManager::irrelevantAspects();
+ auto * const item = new FilterTreeItem(aspect,
+ !irrelevantAspects.contains(aspect->id()));
+ rootItem()->appendChild(item);
+ }
+ static const auto cmp = [](const TreeItem *item1, const TreeItem *item2) {
+ return static_cast<const FilterTreeItem *>(item1)->displayName()
+ < static_cast<const FilterTreeItem *>(item2)->displayName();
+ };
+ rootItem()->sortChildren(cmp);
+ }
+
+ QSet<Core::Id> disabledItems() const
+ {
+ QSet<Core::Id> ids;
+ for (int i = 0; i < rootItem()->childCount(); ++i) {
+ const FilterTreeItem * const item
+ = static_cast<FilterTreeItem *>(rootItem()->childAt(i));
+ if (!item->enabled())
+ ids << item->id();
+ }
+ return ids;
+ }
+};
+
+class FilterTreeView : public TreeView
+{
+public:
+ FilterTreeView(QWidget *parent) : TreeView(parent)
+ {
+ setUniformRowHeights(true);
+ }
+
+private:
+ QSize sizeHint() const override
+ {
+ const int width = columnWidth(0) + columnWidth(1);
+ const int height = model()->rowCount() * rowHeight(model()->index(0, 0))
+ + header()->sizeHint().height();
+ return {width, height};
+ }
+};
+
+FilterKitAspectsDialog::FilterKitAspectsDialog(const Kit *kit, QWidget *parent)
+ : QDialog(parent), m_model(new FilterKitAspectsModel(kit, this))
+{
+ auto * const layout = new QVBoxLayout(this);
+ auto * const view = new FilterTreeView(this);
+ view->setModel(m_model);
+ view->resizeColumnToContents(0);
+ layout->addWidget(view);
+ auto * const buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
+ layout->addWidget(buttonBox);
+ connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
+ connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
+}
+
+QSet<Core::Id> FilterKitAspectsDialog::irrelevantAspects() const
+{
+ return static_cast<FilterKitAspectsModel *>(m_model)->disabledItems();
+}
+
+} // namespace Internal
+} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/kitconfigwidget.h b/src/plugins/projectexplorer/filterkitaspectsdialog.h
index 05c7ea058b..441abd658d 100644
--- a/src/plugins/projectexplorer/kitconfigwidget.h
+++ b/src/plugins/projectexplorer/filterkitaspectsdialog.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -25,57 +25,25 @@
#pragma once
-#include "projectexplorer_export.h"
-
#include <coreplugin/id.h>
-#include <QWidget>
+#include <QDialog>
-namespace ProjectExplorer {
+namespace Utils { class BaseTreeModel; }
+namespace ProjectExplorer {
class Kit;
-class KitInformation;
-
-// --------------------------------------------------------------------------
-// KitConfigWidget
-// --------------------------------------------------------------------------
+namespace Internal {
-class PROJECTEXPLORER_EXPORT KitConfigWidget : public QObject
+class FilterKitAspectsDialog : public QDialog
{
- Q_OBJECT
-
public:
- KitConfigWidget(Kit *kit, const KitInformation *ki);
-
- Core::Id kitInformationId() const;
-
- virtual QString displayName() const = 0;
- virtual QString toolTip() const { return QString(); }
- virtual void makeReadOnly() = 0;
- virtual void refresh() = 0;
- virtual bool visibleInKit() { return true; }
-
- virtual QWidget *mainWidget() const = 0;
- virtual QWidget *buttonWidget() const { return nullptr; }
-
- bool isSticky() const { return m_isSticky; }
- bool isMutable() const;
- void setMutable(bool b);
-
- static QString msgManage();
-
- Kit *kit() const { return m_kit; }
-
- virtual void setPalette(const QPalette &p);
- virtual void setStyle(QStyle *s);
-
-signals:
- void dirty();
+ FilterKitAspectsDialog(const Kit *kit, QWidget *parent);
+ QSet<Core::Id> irrelevantAspects() const;
-protected:
- Kit *m_kit;
- const KitInformation *m_kitInformation;
- bool m_isSticky;
+private:
+ Utils::BaseTreeModel * const m_model;
};
+} // namespace Internal
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/foldernavigationwidget.cpp b/src/plugins/projectexplorer/foldernavigationwidget.cpp
index 04948cb219..6ff9c9719a 100644
--- a/src/plugins/projectexplorer/foldernavigationwidget.cpp
+++ b/src/plugins/projectexplorer/foldernavigationwidget.cpp
@@ -168,7 +168,7 @@ bool FolderSortProxyModel::lessThan(const QModelIndex &source_left, const QModel
}
const QString leftName = src->data(source_left, QFileSystemModel::FileNameRole).toString();
const QString rightName = src->data(source_right, QFileSystemModel::FileNameRole).toString();
- return Utils::FileName::fromString(leftName) < Utils::FileName::fromString(rightName);
+ return Utils::FilePath::fromString(leftName) < Utils::FilePath::fromString(rightName);
}
FolderNavigationModel::FolderNavigationModel(QObject *parent) : QFileSystemModel(parent)
@@ -196,12 +196,13 @@ Qt::ItemFlags FolderNavigationModel::flags(const QModelIndex &index) const
return QFileSystemModel::flags(index);
}
-static QVector<FolderNode *> renamableFolderNodes(const Utils::FileName &before,
- const Utils::FileName &after)
+static QVector<FolderNode *> renamableFolderNodes(const Utils::FilePath &before,
+ const Utils::FilePath &after)
{
QVector<FolderNode *> folderNodes;
ProjectTree::forEachNode([&](Node *node) {
- if (node->nodeType() == NodeType::File && node->filePath() == before
+ if (node->asFileNode()
+ && node->filePath() == before
&& node->parentFolderNode()
&& node->parentFolderNode()->canRenameFile(before.toString(), after.toString())) {
folderNodes.append(node->parentFolderNode());
@@ -235,8 +236,8 @@ bool FolderNavigationModel::setData(const QModelIndex &index, const QVariant &va
if (success && fileInfo(index).isFile()) {
Core::DocumentManager::renamedFile(beforeFilePath, afterFilePath);
const QVector<FolderNode *> folderNodes
- = renamableFolderNodes(Utils::FileName::fromString(beforeFilePath),
- Utils::FileName::fromString(afterFilePath));
+ = renamableFolderNodes(Utils::FilePath::fromString(beforeFilePath),
+ Utils::FilePath::fromString(afterFilePath));
QVector<FolderNode *> failedNodes;
for (FolderNode *folder : folderNodes) {
if (!folder->renameFile(beforeFilePath, afterFilePath))
@@ -382,7 +383,7 @@ FolderNavigationWidget::FolderNavigationWidget(QWidget *parent) : QWidget(parent
this,
[this](const QModelIndex &index) {
const QModelIndex sourceIndex = m_sortProxyModel->mapToSource(index);
- const auto filePath = Utils::FileName::fromString(
+ const auto filePath = Utils::FilePath::fromString(
m_fileSystemModel->filePath(sourceIndex));
// QTimer::singleShot only posts directly onto the event loop if you use the SLOT("...")
// notation, so using a singleShot with a lambda would flicker
@@ -390,9 +391,9 @@ FolderNavigationWidget::FolderNavigationWidget(QWidget *parent) : QWidget(parent
QMetaObject::invokeMethod(this,
"setCrumblePath",
Qt::QueuedConnection,
- Q_ARG(Utils::FileName, filePath));
+ Q_ARG(Utils::FilePath, filePath));
});
- connect(m_crumbLabel, &Utils::FileCrumbLabel::pathClicked, [this](const Utils::FileName &path) {
+ connect(m_crumbLabel, &Utils::FileCrumbLabel::pathClicked, [this](const Utils::FilePath &path) {
const QModelIndex rootIndex = m_sortProxyModel->mapToSource(m_listView->rootIndex());
const QModelIndex fileIndex = m_fileSystemModel->index(path.toString());
if (!isChildOf(fileIndex, rootIndex))
@@ -418,10 +419,10 @@ FolderNavigationWidget::FolderNavigationWidget(QWidget *parent) : QWidget(parent
connect(m_toggleRootSync, &QAbstractButton::clicked,
this, [this]() { setRootAutoSynchronization(!m_rootAutoSync); });
connect(m_rootSelector,
- static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
+ QOverload<int>::of(&QComboBox::currentIndexChanged),
this,
[this](int index) {
- const auto directory = m_rootSelector->itemData(index).value<Utils::FileName>();
+ const auto directory = m_rootSelector->itemData(index).value<Utils::FilePath>();
m_rootSelector->setToolTip(directory.toString());
setRootDirectory(directory);
const QModelIndex rootIndex = m_sortProxyModel->mapToSource(m_listView->rootIndex());
@@ -481,7 +482,7 @@ void FolderNavigationWidget::insertRootDirectory(
m_rootSelector->insertItem(index, directory.displayName);
if (index <= previousIndex) // item was inserted, update previousIndex
++previousIndex;
- m_rootSelector->setItemData(index, qVariantFromValue(directory.path), PATH_ROLE);
+ m_rootSelector->setItemData(index, QVariant::fromValue(directory.path), PATH_ROLE);
m_rootSelector->setItemData(index, directory.id, ID_ROLE);
m_rootSelector->setItemData(index, directory.sortValue, SORT_ROLE);
m_rootSelector->setItemData(index, directory.path.toUserOutput(), Qt::ToolTipRole);
@@ -511,8 +512,8 @@ void FolderNavigationWidget::addNewItem()
const QModelIndex current = m_sortProxyModel->mapToSource(m_listView->currentIndex());
if (!current.isValid())
return;
- const auto filePath = Utils::FileName::fromString(m_fileSystemModel->filePath(current));
- const Utils::FileName path = filePath.toFileInfo().isDir() ? filePath : filePath.parentDir();
+ const auto filePath = Utils::FilePath::fromString(m_fileSystemModel->filePath(current));
+ const Utils::FilePath path = filePath.toFileInfo().isDir() ? filePath : filePath.parentDir();
Core::ICore::showNewItemDialog(ProjectExplorerPlugin::tr("New File", "Title of dialog"),
Utils::filtered(Core::IWizardFactory::allWizardFactories(),
Utils::equal(&Core::IWizardFactory::kind,
@@ -527,11 +528,12 @@ void FolderNavigationWidget::editCurrentItem()
m_listView->edit(current);
}
-static QVector<FolderNode *> removableFolderNodes(const Utils::FileName &filePath)
+static QVector<FolderNode *> removableFolderNodes(const Utils::FilePath &filePath)
{
QVector<FolderNode *> folderNodes;
ProjectTree::forEachNode([&](Node *node) {
- if (node->nodeType() == NodeType::File && node->filePath() == filePath
+ if (node->asFileNode()
+ && node->filePath() == filePath
&& node->parentFolderNode()
&& node->parentFolderNode()->supportsAction(RemoveFile, node)) {
folderNodes.append(node->parentFolderNode());
@@ -550,7 +552,7 @@ void FolderNavigationWidget::removeCurrentItem()
dialog.setDeleteFileVisible(false);
if (dialog.exec() == QDialog::Accepted) {
const QVector<FolderNode *> folderNodes = removableFolderNodes(
- Utils::FileName::fromString(filePath));
+ Utils::FilePath::fromString(filePath));
const QVector<FolderNode *> failedNodes = Utils::filtered(folderNodes,
[filePath](FolderNode *folder) {
return !folder->removeFiles(
@@ -604,19 +606,19 @@ void FolderNavigationWidget::handleCurrentEditorChanged(Core::IEditor *editor)
if (!m_autoSync || !editor || editor->document()->filePath().isEmpty()
|| editor->document()->isTemporary())
return;
- const Utils::FileName filePath = editor->document()->filePath();
+ const Utils::FilePath filePath = editor->document()->filePath();
if (m_rootAutoSync)
selectBestRootForFile(filePath);
selectFile(filePath);
}
-void FolderNavigationWidget::selectBestRootForFile(const Utils::FileName &filePath)
+void FolderNavigationWidget::selectBestRootForFile(const Utils::FilePath &filePath)
{
const int bestRootIndex = bestRootForFile(filePath);
m_rootSelector->setCurrentIndex(bestRootIndex);
}
-void FolderNavigationWidget::selectFile(const Utils::FileName &filePath)
+void FolderNavigationWidget::selectFile(const Utils::FilePath &filePath)
{
const QModelIndex fileIndex = m_sortProxyModel->mapFromSource(
m_fileSystemModel->index(filePath.toString()));
@@ -640,22 +642,22 @@ void FolderNavigationWidget::selectFile(const Utils::FileName &filePath)
}
}
-void FolderNavigationWidget::setRootDirectory(const Utils::FileName &directory)
+void FolderNavigationWidget::setRootDirectory(const Utils::FilePath &directory)
{
const QModelIndex index = m_sortProxyModel->mapFromSource(
m_fileSystemModel->setRootPath(directory.toString()));
m_listView->setRootIndex(index);
}
-int FolderNavigationWidget::bestRootForFile(const Utils::FileName &filePath)
+int FolderNavigationWidget::bestRootForFile(const Utils::FilePath &filePath)
{
int index = 0; // Computer is default
int commonLength = 0;
for (int i = 1; i < m_rootSelector->count(); ++i) {
- const auto root = m_rootSelector->itemData(i).value<Utils::FileName>();
- if (filePath.isChildOf(root) && root.length() > commonLength) {
+ const auto root = m_rootSelector->itemData(i).value<Utils::FilePath>();
+ if (filePath.isChildOf(root) && root.toString().size() > commonLength) {
index = i;
- commonLength = root.length();
+ commonLength = root.toString().size();
}
}
return index;
@@ -695,12 +697,12 @@ void FolderNavigationWidget::createNewFolder(const QModelIndex &parent)
static const QString baseName = tr("New Folder");
// find non-existing name
const QDir dir(m_fileSystemModel->filePath(parent));
- const QSet<Utils::FileName> existingItems
+ const QSet<Utils::FilePath> existingItems
= Utils::transform<QSet>(dir.entryList({baseName + '*'}, QDir::AllEntries),
[](const QString &entry) {
- return Utils::FileName::fromString(entry);
+ return Utils::FilePath::fromString(entry);
});
- const Utils::FileName name = Utils::makeUniquelyNumbered(Utils::FileName::fromString(baseName),
+ const Utils::FilePath name = Utils::makeUniquelyNumbered(Utils::FilePath::fromString(baseName),
existingItems);
// create directory and edit
const QModelIndex index = m_sortProxyModel->mapFromSource(
@@ -711,7 +713,7 @@ void FolderNavigationWidget::createNewFolder(const QModelIndex &parent)
m_listView->edit(index);
}
-void FolderNavigationWidget::setCrumblePath(const Utils::FileName &filePath)
+void FolderNavigationWidget::setCrumblePath(const Utils::FilePath &filePath)
{
const QModelIndex index = m_fileSystemModel->index(filePath.toString());
const int width = m_crumbLabel->width();
@@ -750,9 +752,9 @@ void FolderNavigationWidget::contextMenuEvent(QContextMenuEvent *ev)
QAction *actionOpenAsProject = nullptr;
QAction *newFolder = nullptr;
const bool isDir = m_fileSystemModel->isDir(current);
- const Utils::FileName filePath = hasCurrentItem ? Utils::FileName::fromString(
+ const Utils::FilePath filePath = hasCurrentItem ? Utils::FilePath::fromString(
m_fileSystemModel->filePath(current))
- : Utils::FileName();
+ : Utils::FilePath();
if (hasCurrentItem) {
const QString fileName = m_fileSystemModel->fileName(current);
if (isDir) {
@@ -761,7 +763,7 @@ void FolderNavigationWidget::contextMenuEvent(QContextMenuEvent *ev)
actionOpenProjects->setEnabled(false);
} else {
actionOpenFile = menu.addAction(tr("Open \"%1\"").arg(fileName));
- if (ProjectExplorerPlugin::isProjectFile(Utils::FileName::fromString(fileName)))
+ if (ProjectExplorerPlugin::isProjectFile(Utils::FilePath::fromString(fileName)))
actionOpenAsProject = menu.addAction(tr("Open Project \"%1\"").arg(fileName));
}
}
@@ -864,12 +866,12 @@ FolderNavigationWidgetFactory::FolderNavigationWidgetFactory()
insertRootDirectory({QLatin1String("A.Computer"),
0 /*sortValue*/,
FolderNavigationWidget::tr("Computer"),
- Utils::FileName(),
+ Utils::FilePath(),
Icons::DESKTOP_DEVICE_SMALL.icon()});
insertRootDirectory({QLatin1String("A.Home"),
10 /*sortValue*/,
FolderNavigationWidget::tr("Home"),
- Utils::FileName::fromString(QDir::homePath()),
+ Utils::FilePath::fromString(QDir::homePath()),
Utils::Icons::HOME.icon()});
updateProjectsDirectoryRoot();
connect(Core::DocumentManager::instance(),
diff --git a/src/plugins/projectexplorer/foldernavigationwidget.h b/src/plugins/projectexplorer/foldernavigationwidget.h
index b741de7cfe..b6268b66d6 100644
--- a/src/plugins/projectexplorer/foldernavigationwidget.h
+++ b/src/plugins/projectexplorer/foldernavigationwidget.h
@@ -63,7 +63,7 @@ public:
QString id;
int sortValue;
QString displayName;
- Utils::FileName path;
+ Utils::FilePath path;
QIcon icon;
};
@@ -119,17 +119,17 @@ protected:
void contextMenuEvent(QContextMenuEvent *ev) override;
private slots:
- void setCrumblePath(const Utils::FileName &filePath);
+ void setCrumblePath(const Utils::FilePath &filePath);
private:
bool rootAutoSynchronization() const;
void setRootAutoSynchronization(bool sync);
void setHiddenFilesFilter(bool filter);
- void selectBestRootForFile(const Utils::FileName &filePath);
+ void selectBestRootForFile(const Utils::FilePath &filePath);
void handleCurrentEditorChanged(Core::IEditor *editor);
- void selectFile(const Utils::FileName &filePath);
- void setRootDirectory(const Utils::FileName &directory);
- int bestRootForFile(const Utils::FileName &filePath);
+ void selectFile(const Utils::FilePath &filePath);
+ void setRootDirectory(const Utils::FilePath &directory);
+ int bestRootForFile(const Utils::FilePath &filePath);
void openItem(const QModelIndex &index);
QStringList projectsInDirectory(const QModelIndex &index) const;
void openProjectsInDirectory(const QModelIndex &index);
diff --git a/src/plugins/projectexplorer/gccparser.cpp b/src/plugins/projectexplorer/gccparser.cpp
index 9b1fe34256..fff0606889 100644
--- a/src/plugins/projectexplorer/gccparser.cpp
+++ b/src/plugins/projectexplorer/gccparser.cpp
@@ -77,7 +77,7 @@ void GccParser::stdError(const QString &line)
lne == QLatin1String("* cpp failed")) {
newTask(Task(Task::Error,
lne /* description */,
- Utils::FileName() /* filename */,
+ Utils::FilePath() /* filename */,
-1 /* linenumber */,
Constants::TASK_CATEGORY_COMPILE));
return;
@@ -93,7 +93,7 @@ void GccParser::stdError(const QString &line)
} else if (description.startsWith(QLatin1String("fatal: "))) {
description = description.mid(7);
}
- Task task(type, description, Utils::FileName(), /* filename */
+ Task task(type, description, Utils::FilePath(), /* filename */
-1, /* line */ Constants::TASK_CATEGORY_COMPILE);
newTask(task);
return;
@@ -101,7 +101,7 @@ void GccParser::stdError(const QString &line)
match = m_regExp.match(lne);
if (match.hasMatch()) {
- Utils::FileName filename = Utils::FileName::fromUserInput(match.captured(1));
+ 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);
@@ -125,7 +125,7 @@ void GccParser::stdError(const QString &line)
if (match.hasMatch()) {
newTask(Task(Task::Unknown,
lne.trimmed() /* description */,
- Utils::FileName::fromUserInput(match.captured(1)) /* filename */,
+ Utils::FilePath::fromUserInput(match.captured(1)) /* filename */,
match.captured(3).toInt() /* linenumber */,
Constants::TASK_CATEGORY_COMPILE));
return;
@@ -199,7 +199,7 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
QTest::addColumn<OutputParserTester::Channel>("inputChannel");
QTest::addColumn<QString>("childStdOutLines");
QTest::addColumn<QString>("childStdErrLines");
- QTest::addColumn<QList<Task> >("tasks");
+ QTest::addColumn<Tasks >("tasks");
QTest::addColumn<QString>("outputLines");
const Core::Id categoryCompile = Constants::TASK_CATEGORY_COMPILE;
@@ -207,18 +207,18 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
QTest::newRow("pass-through stdout")
<< QString::fromLatin1("Sometext") << OutputParserTester::STDOUT
<< QString::fromLatin1("Sometext\n") << QString()
- << QList<Task>()
+ << Tasks()
<< QString();
QTest::newRow("pass-through stderr")
<< QString::fromLatin1("Sometext") << OutputParserTester::STDERR
<< QString() << QString::fromLatin1("Sometext\n")
- << QList<Task>()
+ << Tasks()
<< QString();
QTest::newRow("ar output")
<< QString::fromLatin1("../../../../x86/i686-unknown-linux-gnu/bin/i686-unknown-linux-gnu-ar: creating lib/libSkyView.a") << OutputParserTester::STDERR
<< QString() << QString::fromLatin1("../../../../x86/i686-unknown-linux-gnu/bin/i686-unknown-linux-gnu-ar: creating lib/libSkyView.a\n")
- << QList<Task>()
+ << Tasks()
<< QString();
QTest::newRow("GCCE error")
@@ -227,18 +227,18 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
"/temp/test/untitled8/main.cpp:9: error: (Each undeclared identifier is reported only once for each function it appears in.)")
<< OutputParserTester::STDERR
<< QString() << QString()
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Unknown,
QLatin1String("In function `int main(int, char**)':"),
- Utils::FileName::fromUserInput(QLatin1String("/temp/test/untitled8/main.cpp")), -1,
+ Utils::FilePath::fromUserInput(QLatin1String("/temp/test/untitled8/main.cpp")), -1,
categoryCompile)
<< Task(Task::Error,
QLatin1String("`sfasdf' undeclared (first use this function)"),
- Utils::FileName::fromUserInput(QLatin1String("/temp/test/untitled8/main.cpp")), 9,
+ Utils::FilePath::fromUserInput(QLatin1String("/temp/test/untitled8/main.cpp")), 9,
categoryCompile)
<< Task(Task::Error,
QLatin1String("(Each undeclared identifier is reported only once for each function it appears in.)"),
- Utils::FileName::fromUserInput(QLatin1String("/temp/test/untitled8/main.cpp")), 9,
+ Utils::FilePath::fromUserInput(QLatin1String("/temp/test/untitled8/main.cpp")), 9,
categoryCompile)
)
<< QString();
@@ -246,29 +246,29 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
<< QString::fromLatin1("/src/corelib/global/qglobal.h:1635: warning: inline function `QDebug qDebug()' used but never defined")
<< OutputParserTester::STDERR
<< QString() << QString()
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Warning,
QLatin1String("inline function `QDebug qDebug()' used but never defined"),
- Utils::FileName::fromUserInput(QLatin1String("/src/corelib/global/qglobal.h")), 1635,
+ Utils::FilePath::fromUserInput(QLatin1String("/src/corelib/global/qglobal.h")), 1635,
categoryCompile))
<< QString();
QTest::newRow("warning")
<< QString::fromLatin1("main.cpp:7:2: warning: Some warning")
<< OutputParserTester::STDERR
<< QString() << QString()
- << (QList<Task>() << Task(Task::Warning,
+ << (Tasks() << Task(Task::Warning,
QLatin1String("Some warning"),
- Utils::FileName::fromUserInput(QLatin1String("main.cpp")), 7,
+ Utils::FilePath::fromUserInput(QLatin1String("main.cpp")), 7,
categoryCompile))
<< QString();
QTest::newRow("GCCE #error")
<< QString::fromLatin1("C:\\temp\\test\\untitled8\\main.cpp:7: #error Symbian error")
<< OutputParserTester::STDERR
<< QString() << QString()
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Error,
QLatin1String("#error Symbian error"),
- Utils::FileName::fromUserInput(QLatin1String("C:\\temp\\test\\untitled8\\main.cpp")), 7,
+ Utils::FilePath::fromUserInput(QLatin1String("C:\\temp\\test\\untitled8\\main.cpp")), 7,
categoryCompile))
<< QString();
// Symbian reports #warning(s) twice (using different syntax).
@@ -276,20 +276,20 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
<< QString::fromLatin1("C:\\temp\\test\\untitled8\\main.cpp:8: warning: #warning Symbian warning")
<< OutputParserTester::STDERR
<< QString() << QString()
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Warning,
QLatin1String("#warning Symbian warning"),
- Utils::FileName::fromUserInput(QLatin1String("C:\\temp\\test\\untitled8\\main.cpp")), 8,
+ Utils::FilePath::fromUserInput(QLatin1String("C:\\temp\\test\\untitled8\\main.cpp")), 8,
categoryCompile))
<< QString();
QTest::newRow("GCCE #warning2")
<< QString::fromLatin1("/temp/test/untitled8/main.cpp:8:2: warning: #warning Symbian warning")
<< OutputParserTester::STDERR
<< QString() << QString()
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Warning,
QLatin1String("#warning Symbian warning"),
- Utils::FileName::fromUserInput(QLatin1String("/temp/test/untitled8/main.cpp")), 8,
+ Utils::FilePath::fromUserInput(QLatin1String("/temp/test/untitled8/main.cpp")), 8,
categoryCompile))
<< QString();
QTest::newRow("Undefined reference (debug)")
@@ -298,18 +298,18 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
"collect2: ld returned 1 exit status")
<< OutputParserTester::STDERR
<< QString() << QString()
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Unknown,
QLatin1String("In function `main':"),
- Utils::FileName::fromUserInput(QLatin1String("main.o")), -1,
+ Utils::FilePath::fromUserInput(QLatin1String("main.o")), -1,
categoryCompile)
<< Task(Task::Error,
QLatin1String("undefined reference to `MainWindow::doSomething()'"),
- Utils::FileName::fromUserInput(QLatin1String("C:\\temp\\test\\untitled8/main.cpp")), 8,
+ Utils::FilePath::fromUserInput(QLatin1String("C:\\temp\\test\\untitled8/main.cpp")), 8,
categoryCompile)
<< Task(Task::Error,
QLatin1String("collect2: ld returned 1 exit status"),
- Utils::FileName(), -1,
+ Utils::FilePath(), -1,
categoryCompile)
)
<< QString();
@@ -319,18 +319,18 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
"collect2: ld returned 1 exit status")
<< OutputParserTester::STDERR
<< QString() << QString()
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Unknown,
QLatin1String("In function `main':"),
- Utils::FileName::fromUserInput(QLatin1String("main.o")), -1,
+ Utils::FilePath::fromUserInput(QLatin1String("main.o")), -1,
categoryCompile)
<< Task(Task::Error,
QLatin1String("undefined reference to `MainWindow::doSomething()'"),
- Utils::FileName::fromUserInput(QLatin1String("C:\\temp\\test\\untitled8/main.cpp")), -1,
+ Utils::FilePath::fromUserInput(QLatin1String("C:\\temp\\test\\untitled8/main.cpp")), -1,
categoryCompile)
<< Task(Task::Error,
QLatin1String("collect2: ld returned 1 exit status"),
- Utils::FileName(), -1,
+ Utils::FilePath(), -1,
categoryCompile)
)
<< QString();
@@ -338,20 +338,20 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
<< QString::fromLatin1("c:\\Qt\\4.6\\lib/QtGuid4.dll: file not recognized: File format not recognized")
<< OutputParserTester::STDERR
<< QString() << QString()
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Error,
QLatin1String("file not recognized: File format not recognized"),
- Utils::FileName::fromUserInput(QLatin1String("c:\\Qt\\4.6\\lib/QtGuid4.dll")), -1,
+ Utils::FilePath::fromUserInput(QLatin1String("c:\\Qt\\4.6\\lib/QtGuid4.dll")), -1,
categoryCompile))
<< QString();
QTest::newRow("Invalid rpath")
<< QString::fromLatin1("g++: /usr/local/lib: No such file or directory")
<< OutputParserTester::STDERR
<< QString() << QString()
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Error,
QLatin1String("/usr/local/lib: No such file or directory"),
- Utils::FileName(), -1,
+ Utils::FilePath(), -1,
categoryCompile))
<< QString();
@@ -361,18 +361,18 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
"../../../../master/src/plugins/debugger/gdb/gdbengine.cpp:2115: warning: unused variable 'handler'")
<< OutputParserTester::STDERR
<< QString() << QString()
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Unknown,
QLatin1String("In member function 'void Debugger::Internal::GdbEngine::handleBreakInsert2(const Debugger::Internal::GdbResponse&)':"),
- Utils::FileName::fromUserInput(QLatin1String("../../../../master/src/plugins/debugger/gdb/gdbengine.cpp")), -1,
+ Utils::FilePath::fromUserInput(QLatin1String("../../../../master/src/plugins/debugger/gdb/gdbengine.cpp")), -1,
categoryCompile)
<< Task(Task::Warning,
QLatin1String("unused variable 'index'"),
- Utils::FileName::fromUserInput(QLatin1String("../../../../master/src/plugins/debugger/gdb/gdbengine.cpp")), 2114,
+ Utils::FilePath::fromUserInput(QLatin1String("../../../../master/src/plugins/debugger/gdb/gdbengine.cpp")), 2114,
categoryCompile)
<< Task(Task::Warning,
QLatin1String("unused variable 'handler'"),
- Utils::FileName::fromUserInput(QLatin1String("../../../../master/src/plugins/debugger/gdb/gdbengine.cpp")), 2115,
+ Utils::FilePath::fromUserInput(QLatin1String("../../../../master/src/plugins/debugger/gdb/gdbengine.cpp")), 2115,
categoryCompile))
<< QString();
QTest::newRow("gnumakeparser.cpp errors")
@@ -381,18 +381,18 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
"/home/code/src/creator/src/plugins/projectexplorer/gnumakeparser.cpp:264: error: expected ';' before ':' token")
<< OutputParserTester::STDERR
<< QString() << QString()
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Unknown,
QLatin1String("In member function 'void ProjectExplorer::ProjectExplorerPlugin::testGnuMakeParserTaskMangling_data()':"),
- Utils::FileName::fromUserInput(QLatin1String("/home/code/src/creator/src/plugins/projectexplorer/gnumakeparser.cpp")), -1,
+ Utils::FilePath::fromUserInput(QLatin1String("/home/code/src/creator/src/plugins/projectexplorer/gnumakeparser.cpp")), -1,
categoryCompile)
<< Task(Task::Error,
QLatin1String("expected primary-expression before ':' token"),
- Utils::FileName::fromUserInput(QLatin1String("/home/code/src/creator/src/plugins/projectexplorer/gnumakeparser.cpp")), 264,
+ Utils::FilePath::fromUserInput(QLatin1String("/home/code/src/creator/src/plugins/projectexplorer/gnumakeparser.cpp")), 264,
categoryCompile)
<< Task(Task::Error,
QLatin1String("expected ';' before ':' token"),
- Utils::FileName::fromUserInput(QLatin1String("/home/code/src/creator/src/plugins/projectexplorer/gnumakeparser.cpp")), 264,
+ Utils::FilePath::fromUserInput(QLatin1String("/home/code/src/creator/src/plugins/projectexplorer/gnumakeparser.cpp")), 264,
categoryCompile))
<< QString();
QTest::newRow("distcc error(QTCREATORBUG-904)")
@@ -401,42 +401,42 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
<< OutputParserTester::STDERR
<< QString() << QString::fromLatin1("distcc[73168] (dcc_get_hostlist) Warning: no hostlist is set; can't distribute work\n"
"distcc[73168] (dcc_build_somewhere) Warning: failed to distribute, running locally instead\n")
- << QList<Task>()
+ << Tasks()
<< QString();
QTest::newRow("ld warning (QTCREATORBUG-905)")
<< QString::fromLatin1("ld: warning: Core::IEditor* QVariant::value<Core::IEditor*>() const has different visibility (hidden) in .obj/debug-shared/openeditorsview.o and (default) in .obj/debug-shared/editormanager.o")
<< OutputParserTester::STDERR
<< QString() << QString()
- << ( QList<Task>()
+ << ( Tasks()
<< Task(Task::Warning,
QLatin1String("Core::IEditor* QVariant::value<Core::IEditor*>() const has different visibility (hidden) in .obj/debug-shared/openeditorsview.o and (default) in .obj/debug-shared/editormanager.o"),
- Utils::FileName(), -1,
+ Utils::FilePath(), -1,
categoryCompile))
<< QString();
QTest::newRow("ld fatal")
<< QString::fromLatin1("ld: fatal: Symbol referencing errors. No output written to testproject")
<< OutputParserTester::STDERR
<< QString() << QString()
- << ( QList<Task>()
+ << ( Tasks()
<< Task(Task::Error,
QLatin1String("Symbol referencing errors. No output written to testproject"),
- Utils::FileName(), -1,
+ Utils::FilePath(), -1,
categoryCompile))
<< QString();
QTest::newRow("Teambuilder issues")
<< QString::fromLatin1("TeamBuilder Client:: error: could not find Scheduler, running Job locally...")
<< OutputParserTester::STDERR
<< QString() << QString::fromLatin1("TeamBuilder Client:: error: could not find Scheduler, running Job locally...\n")
- << QList<Task>()
+ << Tasks()
<< QString();
QTest::newRow("note")
<< QString::fromLatin1("/home/dev/creator/share/qtcreator/debugger/dumper.cpp:1079: note: initialized from here")
<< OutputParserTester::STDERR
<< QString() << QString()
- << ( QList<Task>()
+ << ( Tasks()
<< Task(Task::Unknown,
QLatin1String("initialized from here"),
- Utils::FileName::fromUserInput(QLatin1String("/home/dev/creator/share/qtcreator/debugger/dumper.cpp")), 1079,
+ Utils::FilePath::fromUserInput(QLatin1String("/home/dev/creator/share/qtcreator/debugger/dumper.cpp")), 1079,
categoryCompile))
<< QString();
QTest::newRow("static member function")
@@ -444,30 +444,30 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
"/Qt/4.6.2-Symbian/s60sdk/epoc32/include/stdapis/stlport/stl/_tree.c:194: warning: suggest explicit braces to avoid ambiguous 'else'")
<< OutputParserTester::STDERR
<< QString() << QString()
- << ( QList<Task>()
+ << ( Tasks()
<< Task(Task::Unknown,
QLatin1String("In static member function 'static std::_Rb_tree_node_base* std::_Rb_global<_Dummy>::_Rebalance_for_erase(std::_Rb_tree_node_base*, std::_Rb_tree_node_base*&, std::_Rb_tree_node_base*&, std::_Rb_tree_node_base*&)':"),
- Utils::FileName::fromUserInput(QLatin1String("/Qt/4.6.2-Symbian/s60sdk/epoc32/include/stdapis/stlport/stl/_tree.c")), -1,
+ Utils::FilePath::fromUserInput(QLatin1String("/Qt/4.6.2-Symbian/s60sdk/epoc32/include/stdapis/stlport/stl/_tree.c")), -1,
categoryCompile)
<< Task(Task::Warning,
QLatin1String("suggest explicit braces to avoid ambiguous 'else'"),
- Utils::FileName::fromUserInput(QLatin1String("/Qt/4.6.2-Symbian/s60sdk/epoc32/include/stdapis/stlport/stl/_tree.c")), 194,
+ Utils::FilePath::fromUserInput(QLatin1String("/Qt/4.6.2-Symbian/s60sdk/epoc32/include/stdapis/stlport/stl/_tree.c")), 194,
categoryCompile))
<< QString();
QTest::newRow("rm false positive")
<< QString::fromLatin1("rm: cannot remove `release/moc_mainwindow.cpp': No such file or directory")
<< OutputParserTester::STDERR
<< QString() << QString::fromLatin1("rm: cannot remove `release/moc_mainwindow.cpp': No such file or directory\n")
- << QList<Task>()
+ << Tasks()
<< QString();
QTest::newRow("ld: missing library")
<< QString::fromLatin1("/usr/bin/ld: cannot find -ldoesnotexist")
<< OutputParserTester::STDERR
<< QString() << QString()
- << ( QList<Task>()
+ << ( Tasks()
<< Task(Task::Error,
QLatin1String("cannot find -ldoesnotexist"),
- Utils::FileName(), -1,
+ Utils::FilePath(), -1,
categoryCompile))
<< QString();
QTest::newRow("In function")
@@ -476,38 +476,38 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
"../../scriptbug/main.cpp:8: warning: unused variable c")
<< OutputParserTester::STDERR
<< QString() << QString()
- << ( QList<Task>()
+ << ( Tasks()
<< Task(Task::Unknown,
QLatin1String("In function void foo(i) [with i = double]:"),
- Utils::FileName::fromUserInput(QLatin1String("../../scriptbug/main.cpp")), -1,
+ Utils::FilePath::fromUserInput(QLatin1String("../../scriptbug/main.cpp")), -1,
categoryCompile)
<< Task(Task::Unknown,
QLatin1String("instantiated from here"),
- Utils::FileName::fromUserInput(QLatin1String("../../scriptbug/main.cpp")), 22,
+ Utils::FilePath::fromUserInput(QLatin1String("../../scriptbug/main.cpp")), 22,
categoryCompile)
<< Task(Task::Warning,
QLatin1String("unused variable c"),
- Utils::FileName::fromUserInput(QLatin1String("../../scriptbug/main.cpp")), 8,
+ Utils::FilePath::fromUserInput(QLatin1String("../../scriptbug/main.cpp")), 8,
categoryCompile))
<< QString();
QTest::newRow("instanciated from here")
<< QString::fromLatin1("main.cpp:10: instantiated from here ")
<< OutputParserTester::STDERR
<< QString() << QString()
- << ( QList<Task>()
+ << ( Tasks()
<< Task(Task::Unknown,
QLatin1String("instantiated from here"),
- Utils::FileName::fromUserInput(QLatin1String("main.cpp")), 10,
+ Utils::FilePath::fromUserInput(QLatin1String("main.cpp")), 10,
categoryCompile))
<< QString();
QTest::newRow("In constructor")
<< QString::fromLatin1("/dev/creator/src/plugins/find/basetextfind.h: In constructor 'Find::BaseTextFind::BaseTextFind(QTextEdit*)':")
<< OutputParserTester::STDERR
<< QString() << QString()
- << ( QList<Task>()
+ << ( Tasks()
<< Task(Task::Unknown,
QLatin1String("In constructor 'Find::BaseTextFind::BaseTextFind(QTextEdit*)':"),
- Utils::FileName::fromUserInput(QLatin1String("/dev/creator/src/plugins/find/basetextfind.h")), -1,
+ Utils::FilePath::fromUserInput(QLatin1String("/dev/creator/src/plugins/find/basetextfind.h")), -1,
categoryCompile))
<< QString();
@@ -519,26 +519,26 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
"../../scriptbug/main.cpp:5: warning: unused parameter v")
<< OutputParserTester::STDERR
<< QString() << QString()
- << ( QList<Task>()
+ << ( Tasks()
<< Task(Task::Unknown,
QLatin1String("At global scope:"),
- Utils::FileName::fromUserInput(QLatin1String("../../scriptbug/main.cpp")), -1,
+ Utils::FilePath::fromUserInput(QLatin1String("../../scriptbug/main.cpp")), -1,
categoryCompile)
<< Task(Task::Unknown,
QLatin1String("In instantiation of void bar(i) [with i = double]:"),
- Utils::FileName::fromUserInput(QLatin1String("../../scriptbug/main.cpp")), -1,
+ Utils::FilePath::fromUserInput(QLatin1String("../../scriptbug/main.cpp")), -1,
categoryCompile)
<< Task(Task::Unknown,
QLatin1String("instantiated from void foo(i) [with i = double]"),
- Utils::FileName::fromUserInput(QLatin1String("../../scriptbug/main.cpp")), 8,
+ Utils::FilePath::fromUserInput(QLatin1String("../../scriptbug/main.cpp")), 8,
categoryCompile)
<< Task(Task::Unknown,
QLatin1String("instantiated from here"),
- Utils::FileName::fromUserInput(QLatin1String("../../scriptbug/main.cpp")), 22,
+ Utils::FilePath::fromUserInput(QLatin1String("../../scriptbug/main.cpp")), 22,
categoryCompile)
<< Task(Task::Warning,
QLatin1String("unused parameter v"),
- Utils::FileName::fromUserInput(QLatin1String("../../scriptbug/main.cpp")), 5,
+ Utils::FilePath::fromUserInput(QLatin1String("../../scriptbug/main.cpp")), 5,
categoryCompile))
<< QString();
@@ -546,10 +546,10 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
<< QString::fromLatin1("/home/code/test.cpp:54:38: fatal error: test.moc: No such file or directory")
<< OutputParserTester::STDERR
<< QString() << QString()
- << ( QList<Task>()
+ << ( Tasks()
<< Task(Task::Error,
QLatin1String("test.moc: No such file or directory"),
- Utils::FileName::fromUserInput(QLatin1String("/home/code/test.cpp")), 54,
+ Utils::FilePath::fromUserInput(QLatin1String("/home/code/test.cpp")), 54,
categoryCompile))
<< QString();
@@ -560,22 +560,22 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
"collect2: ld returned 1 exit status")
<< OutputParserTester::STDERR
<< QString() << QString()
- << ( QList<Task>()
+ << ( Tasks()
<< Task(Task::Unknown,
QLatin1String("In function `QPlotAxis':"),
- Utils::FileName::fromUserInput(QLatin1String("debug/qplotaxis.o")), -1,
+ Utils::FilePath::fromUserInput(QLatin1String("debug/qplotaxis.o")), -1,
categoryCompile)
<< Task(Task::Error,
QLatin1String("undefined reference to `vtable for QPlotAxis'"),
- Utils::FileName::fromUserInput(QLatin1String("M:\\Development\\x64\\QtPlot/qplotaxis.cpp")), 26,
+ Utils::FilePath::fromUserInput(QLatin1String("M:\\Development\\x64\\QtPlot/qplotaxis.cpp")), 26,
categoryCompile)
<< Task(Task::Error,
QLatin1String("undefined reference to `vtable for QPlotAxis'"),
- Utils::FileName::fromUserInput(QLatin1String("M:\\Development\\x64\\QtPlot/qplotaxis.cpp")), 26,
+ Utils::FilePath::fromUserInput(QLatin1String("M:\\Development\\x64\\QtPlot/qplotaxis.cpp")), 26,
categoryCompile)
<< Task(Task::Error,
QLatin1String("collect2: ld returned 1 exit status"),
- Utils::FileName(), -1,
+ Utils::FilePath(), -1,
categoryCompile))
<< QString();
@@ -587,26 +587,26 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
"../stl/main.cpp:31: warning: unused parameter index")
<< OutputParserTester::STDERR
<< QString() << QString()
- << ( QList<Task>()
+ << ( Tasks()
<< Task(Task::Unknown,
QLatin1String("In member function typename _Vector_base<_Tp, _Alloc>::_Tp_alloc_type::const_reference Vector<_Tp, _Alloc>::at(int) [with _Tp = Point, _Alloc = Allocator<Point>]:"),
- Utils::FileName::fromUserInput(QLatin1String("../stl/main.cpp")), -1,
+ Utils::FilePath::fromUserInput(QLatin1String("../stl/main.cpp")), -1,
categoryCompile)
<< Task(Task::Unknown,
QLatin1String("instantiated from here"),
- Utils::FileName::fromUserInput(QLatin1String("../stl/main.cpp")), 38,
+ Utils::FilePath::fromUserInput(QLatin1String("../stl/main.cpp")), 38,
categoryCompile)
<< Task(Task::Warning,
QLatin1String("returning reference to temporary"),
- Utils::FileName::fromUserInput(QLatin1String("../stl/main.cpp")), 31,
+ Utils::FilePath::fromUserInput(QLatin1String("../stl/main.cpp")), 31,
categoryCompile)
<< Task(Task::Unknown,
QLatin1String("At global scope:"),
- Utils::FileName::fromUserInput(QLatin1String("../stl/main.cpp")), -1,
+ Utils::FilePath::fromUserInput(QLatin1String("../stl/main.cpp")), -1,
categoryCompile)
<< Task(Task::Warning,
QLatin1String("unused parameter index"),
- Utils::FileName::fromUserInput(QLatin1String("../stl/main.cpp")), 31,
+ Utils::FilePath::fromUserInput(QLatin1String("../stl/main.cpp")), 31,
categoryCompile))
<< QString();
@@ -617,22 +617,22 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
"C:/Symbian_SDK/epoc32/include/e32cmn.inl:7094: warning: returning reference to temporary")
<< OutputParserTester::STDERR
<< QString() << QString()
- << ( QList<Task>()
+ << ( Tasks()
<< Task(Task::Unknown,
QLatin1String("In file included from C:/Symbian_SDK/epoc32/include/e32cmn.h:6792,"),
- Utils::FileName::fromUserInput(QLatin1String("C:/Symbian_SDK/epoc32/include/e32cmn.h")), 6792,
+ Utils::FilePath::fromUserInput(QLatin1String("C:/Symbian_SDK/epoc32/include/e32cmn.h")), 6792,
categoryCompile)
<< Task(Task::Unknown,
QLatin1String("from C:/Symbian_SDK/epoc32/include/e32std.h:25,"),
- Utils::FileName::fromUserInput(QLatin1String("C:/Symbian_SDK/epoc32/include/e32std.h")), 25,
+ Utils::FilePath::fromUserInput(QLatin1String("C:/Symbian_SDK/epoc32/include/e32std.h")), 25,
categoryCompile)
<< Task(Task::Unknown,
QLatin1String("In member function 'SSecureId::operator const TSecureId&() const':"),
- Utils::FileName::fromUserInput(QLatin1String("C:/Symbian_SDK/epoc32/include/e32cmn.inl")), -1,
+ Utils::FilePath::fromUserInput(QLatin1String("C:/Symbian_SDK/epoc32/include/e32cmn.inl")), -1,
categoryCompile)
<< Task(Task::Warning,
QLatin1String("returning reference to temporary"),
- Utils::FileName::fromUserInput(QLatin1String("C:/Symbian_SDK/epoc32/include/e32cmn.inl")), 7094,
+ Utils::FilePath::fromUserInput(QLatin1String("C:/Symbian_SDK/epoc32/include/e32cmn.inl")), 7094,
categoryCompile))
<< QString();
@@ -640,10 +640,10 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
<< QString::fromLatin1("../../../src/XmlUg/targetdelete.c: At top level:")
<< OutputParserTester::STDERR
<< QString() << QString()
- << ( QList<Task>()
+ << ( Tasks()
<< Task(Task::Unknown,
QLatin1String("At top level:"),
- Utils::FileName::fromUserInput(QLatin1String("../../../src/XmlUg/targetdelete.c")), -1,
+ Utils::FilePath::fromUserInput(QLatin1String("../../../src/XmlUg/targetdelete.c")), -1,
categoryCompile))
<< QString();
@@ -653,18 +653,18 @@ 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()
- << ( QList<Task>()
+ << ( Tasks()
<< Task(Task::Unknown,
QLatin1String("In file included from /Symbian/SDK/EPOC32/INCLUDE/GCCE/GCCE.h:15,"),
- Utils::FileName::fromUserInput(QLatin1String("/Symbian/SDK/EPOC32/INCLUDE/GCCE/GCCE.h")), 15,
+ Utils::FilePath::fromUserInput(QLatin1String("/Symbian/SDK/EPOC32/INCLUDE/GCCE/GCCE.h")), 15,
categoryCompile)
<< Task(Task::Unknown,
QLatin1String("from <command line>:26:"),
- Utils::FileName::fromUserInput(QLatin1String("<command line>")), 26,
+ Utils::FilePath::fromUserInput(QLatin1String("<command line>")), 26,
categoryCompile)
<< Task(Task::Warning,
QLatin1String("no newline at end of file"),
- Utils::FileName::fromUserInput(QLatin1String("/Symbian/SDK/epoc32/include/variant/Symbian_OS.hrh")), 1134,
+ Utils::FilePath::fromUserInput(QLatin1String("/Symbian/SDK/epoc32/include/variant/Symbian_OS.hrh")), 1134,
categoryCompile))
<< QString();
@@ -672,10 +672,10 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
<< QString::fromLatin1("release/main.o:main.cpp:(.text+0x42): undefined reference to `MainWindow::doSomething()'")
<< OutputParserTester::STDERR
<< QString() << QString()
- << ( QList<Task>()
+ << ( Tasks()
<< Task(Task::Error,
QLatin1String("undefined reference to `MainWindow::doSomething()'"),
- Utils::FileName::fromUserInput(QLatin1String("main.cpp")), -1,
+ Utils::FilePath::fromUserInput(QLatin1String("main.cpp")), -1,
categoryCompile))
<< QString();
@@ -684,14 +684,14 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
"../../../src/shared/proparser/profileevaluator.cpp:2817:9: warning: case value '0' not in enumerated type 'ProFileEvaluator::Private::TestFunc'")
<< OutputParserTester::STDERR
<< QString() << QString()
- << ( QList<Task>()
+ << ( Tasks()
<< Task(Task::Unknown,
QLatin1String("In member function 'ProFileEvaluator::Private::VisitReturn ProFileEvaluator::Private::evaluateConditionalFunction(const ProString&, const ProStringList&)':"),
- Utils::FileName::fromUserInput(QLatin1String("../../../src/shared/proparser/profileevaluator.cpp")), -1,
+ Utils::FilePath::fromUserInput(QLatin1String("../../../src/shared/proparser/profileevaluator.cpp")), -1,
categoryCompile)
<< Task(Task::Warning,
QLatin1String("case value '0' not in enumerated type 'ProFileEvaluator::Private::TestFunc'"),
- Utils::FileName::fromUserInput(QLatin1String("../../../src/shared/proparser/profileevaluator.cpp")), 2817,
+ Utils::FilePath::fromUserInput(QLatin1String("../../../src/shared/proparser/profileevaluator.cpp")), 2817,
categoryCompile))
<< QString();
@@ -700,14 +700,14 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
"./mw.h:4:0: warning: \"STUPID_DEFINE\" redefined")
<< OutputParserTester::STDERR
<< QString() << QString()
- << ( QList<Task>()
+ << ( Tasks()
<< Task(Task::Unknown,
QLatin1String("In file included from <command-line>:0:0:"),
- Utils::FileName::fromUserInput(QLatin1String("<command-line>")), 0,
+ Utils::FilePath::fromUserInput(QLatin1String("<command-line>")), 0,
categoryCompile)
<< Task(Task::Warning,
QLatin1String("\"STUPID_DEFINE\" redefined"),
- Utils::FileName::fromUserInput(QLatin1String("./mw.h")), 4,
+ Utils::FilePath::fromUserInput(QLatin1String("./mw.h")), 4,
categoryCompile))
<< QString();
QTest::newRow("instanciation with line:column info")
@@ -716,28 +716,28 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
"file.h:21:5: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]")
<< OutputParserTester::STDERR
<< QString() << QString()
- << ( QList<Task>()
+ << ( Tasks()
<< Task(Task::Unknown,
QLatin1String("In function 'void UnitTest::CheckEqual(UnitTest::TestResults&, const Expected&, const Actual&, const UnitTest::TestDetails&) [with Expected = unsigned int, Actual = int]':"),
- Utils::FileName::fromUserInput(QLatin1String("file.h")), -1,
+ Utils::FilePath::fromUserInput(QLatin1String("file.h")), -1,
categoryCompile)
<< Task(Task::Unknown,
QLatin1String("instantiated from here"),
- Utils::FileName::fromUserInput(QLatin1String("file.cpp")), 87,
+ Utils::FilePath::fromUserInput(QLatin1String("file.cpp")), 87,
categoryCompile)
<< Task(Task::Warning,
QLatin1String("comparison between signed and unsigned integer expressions [-Wsign-compare]"),
- Utils::FileName::fromUserInput(QLatin1String("file.h")), 21,
+ Utils::FilePath::fromUserInput(QLatin1String("file.h")), 21,
categoryCompile))
<< QString();
QTest::newRow("linker error") // QTCREATORBUG-3107
<< QString::fromLatin1("cns5k_ins_parser_tests.cpp:(.text._ZN20CNS5kINSParserEngine21DropBytesUntilStartedEP14CircularBufferIhE[CNS5kINSParserEngine::DropBytesUntilStarted(CircularBuffer<unsigned char>*)]+0x6d): undefined reference to `CNS5kINSPacket::SOH_BYTE'")
<< OutputParserTester::STDERR
<< QString() << QString()
- << ( QList<Task>()
+ << ( Tasks()
<< Task(Task::Error,
QLatin1String("undefined reference to `CNS5kINSPacket::SOH_BYTE'"),
- Utils::FileName::fromUserInput(QLatin1String("cns5k_ins_parser_tests.cpp")), -1,
+ Utils::FilePath::fromUserInput(QLatin1String("cns5k_ins_parser_tests.cpp")), -1,
categoryCompile))
<< QString();
@@ -745,10 +745,10 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
<< QString::fromLatin1("mainwindow.ui: Warning: The name 'pushButton' (QPushButton) is already in use, defaulting to 'pushButton1'.")
<< OutputParserTester::STDERR
<< QString() << QString()
- << ( QList<Task>()
+ << ( Tasks()
<< Task(Task::Warning,
QLatin1String("The name 'pushButton' (QPushButton) is already in use, defaulting to 'pushButton1'."),
- Utils::FileName::fromUserInput(QLatin1String("mainwindow.ui")), -1,
+ Utils::FilePath::fromUserInput(QLatin1String("mainwindow.ui")), -1,
Constants::TASK_CATEGORY_COMPILE))
<< QString();
@@ -756,10 +756,10 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
<< QString::fromLatin1("libimf.so: warning: warning: feupdateenv is not implemented and will always fail")
<< OutputParserTester::STDERR
<< QString() << QString()
- << ( QList<Task>()
+ << ( Tasks()
<< Task(Task::Warning,
QLatin1String("warning: feupdateenv is not implemented and will always fail"),
- Utils::FileName::fromUserInput(QLatin1String("libimf.so")), -1,
+ Utils::FilePath::fromUserInput(QLatin1String("libimf.so")), -1,
Constants::TASK_CATEGORY_COMPILE))
<< QString();
@@ -770,16 +770,16 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
" ^")
<< OutputParserTester::STDERR
<< QString() << QString()
- << ( QList<Task>()
+ << ( Tasks()
<< Task(Task::Unknown,
QLatin1String("In file included from /home/code/src/creator/src/libs/extensionsystem/pluginerrorview.cpp:31:0:"),
- Utils::FileName::fromUserInput(QLatin1String("/home/code/src/creator/src/libs/extensionsystem/pluginerrorview.cpp")), 31,
+ Utils::FilePath::fromUserInput(QLatin1String("/home/code/src/creator/src/libs/extensionsystem/pluginerrorview.cpp")), 31,
categoryCompile)
<< Task(Task::Error,
QLatin1String("QtGui/QAction: No such file or directory\n"
" #include <QtGui/QAction>\n"
" ^"),
- Utils::FileName::fromUserInput(QLatin1String(".uic/ui_pluginerrorview.h")), 14,
+ Utils::FilePath::fromUserInput(QLatin1String(".uic/ui_pluginerrorview.h")), 14,
categoryCompile))
<< QString();
@@ -791,26 +791,26 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
"main.cpp:7:22: error: within this context")
<< OutputParserTester::STDERR
<< QString() << QString()
- << ( QList<Task>()
+ << ( Tasks()
<< Task(Task::Unknown,
QLatin1String("In file included from /usr/include/qt4/QtCore/QString:1:0,"),
- Utils::FileName::fromUserInput(QLatin1String("/usr/include/qt4/QtCore/QString")), 1,
+ Utils::FilePath::fromUserInput(QLatin1String("/usr/include/qt4/QtCore/QString")), 1,
categoryCompile)
<< Task(Task::Unknown,
QLatin1String("from main.cpp:3:"),
- Utils::FileName::fromUserInput(QLatin1String("main.cpp")), 3,
+ Utils::FilePath::fromUserInput(QLatin1String("main.cpp")), 3,
categoryCompile)
<< Task(Task::Unknown,
QLatin1String("In function 'void foo()':"),
- Utils::FileName::fromUserInput(QLatin1String("/usr/include/qt4/QtCore/qstring.h")), -1,
+ Utils::FilePath::fromUserInput(QLatin1String("/usr/include/qt4/QtCore/qstring.h")), -1,
categoryCompile)
<< Task(Task::Error,
QLatin1String("'QString::QString(const char*)' is private"),
- Utils::FileName::fromUserInput(QLatin1String("/usr/include/qt4/QtCore/qstring.h")), 597,
+ Utils::FilePath::fromUserInput(QLatin1String("/usr/include/qt4/QtCore/qstring.h")), 597,
categoryCompile)
<< Task(Task::Error,
QLatin1String("within this context"),
- Utils::FileName::fromUserInput(QLatin1String("main.cpp")), 7,
+ Utils::FilePath::fromUserInput(QLatin1String("main.cpp")), 7,
categoryCompile))
<< QString();
@@ -821,22 +821,22 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
"collect2: error: ld returned 1 exit status")
<< OutputParserTester::STDERR
<< QString() << QString()
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Unknown,
QLatin1String("In function `foo()':"),
- Utils::FileName::fromUserInput(QLatin1String("foo.o")), -1,
+ Utils::FilePath::fromUserInput(QLatin1String("foo.o")), -1,
categoryCompile)
<< Task(Task::Error,
QLatin1String("multiple definition of `foo()'"),
- Utils::FileName::fromUserInput(QLatin1String("/home/user/test/foo.cpp")), 2,
+ Utils::FilePath::fromUserInput(QLatin1String("/home/user/test/foo.cpp")), 2,
categoryCompile)
<< Task(Task::Unknown,
QLatin1String("first defined here"),
- Utils::FileName::fromUserInput(QLatin1String("/home/user/test/bar.cpp")), 4,
+ Utils::FilePath::fromUserInput(QLatin1String("/home/user/test/bar.cpp")), 4,
categoryCompile)
<< Task(Task::Error,
QLatin1String("collect2: error: ld returned 1 exit status"),
- Utils::FileName(), -1,
+ Utils::FilePath(), -1,
categoryCompile)
)
<< QString();
@@ -847,18 +847,18 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
"collect2: error: ld returned 1 exit status")
<< OutputParserTester::STDERR
<< QString() << QString()
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Error,
QLatin1String("multiple definition of `foo'"),
- Utils::FileName::fromUserInput(QLatin1String("foo.o")), -1,
+ Utils::FilePath::fromUserInput(QLatin1String("foo.o")), -1,
categoryCompile)
<< Task(Task::Unknown,
QLatin1String("first defined here"),
- Utils::FileName::fromUserInput(QLatin1String("bar.o")), -1,
+ Utils::FilePath::fromUserInput(QLatin1String("bar.o")), -1,
categoryCompile)
<< Task(Task::Error,
QLatin1String("collect2: error: ld returned 1 exit status"),
- Utils::FileName(), -1,
+ Utils::FilePath(), -1,
categoryCompile)
)
<< QString();
@@ -867,10 +867,10 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
<< "obj/gtest-clang-printing.o:gtest-clang-printing.cpp:llvm::VerifyDisableABIBreakingChecks: error: undefined reference to 'llvm::DisableABIBreakingChecks'"
<< OutputParserTester::STDERR
<< QString() << QString()
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Error,
QLatin1String("error: undefined reference to 'llvm::DisableABIBreakingChecks'"),
- Utils::FileName::fromString("gtest-clang-printing.cpp"), -1,
+ Utils::FilePath::fromString("gtest-clang-printing.cpp"), -1,
categoryCompile)
)
<< QString();
@@ -879,10 +879,10 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
<< QString::fromLatin1("ranlib: file: lib/libtest.a(Test0.cpp.o) has no symbols")
<< OutputParserTester::STDERR
<< QString() << QString()
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Warning,
QLatin1String("file: lib/libtest.a(Test0.cpp.o) has no symbols"),
- Utils::FileName(), -1,
+ Utils::FilePath(), -1,
categoryCompile)
)
<< QString();
@@ -890,10 +890,10 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
<< QString::fromLatin1("/path/to/XCode/and/ranlib: file: lib/libtest.a(Test0.cpp.o) has no symbols")
<< OutputParserTester::STDERR
<< QString() << QString()
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Warning,
QLatin1String("file: lib/libtest.a(Test0.cpp.o) has no symbols"),
- Utils::FileName(), -1,
+ Utils::FilePath(), -1,
categoryCompile)
)
<< QString();
@@ -901,10 +901,10 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
<< QString::fromLatin1("/home/qtwebkithelpviewer.h:0: Note: No relevant classes found. No output generated.")
<< OutputParserTester::STDERR
<< QString() << QString()
- << (QList<ProjectExplorer::Task>()
+ << (Tasks()
<< Task(Task::Unknown,
QLatin1String("Note: No relevant classes found. No output generated."),
- Utils::FileName::fromUserInput(QLatin1String("/home/qtwebkithelpviewer.h")), 0,
+ Utils::FilePath::fromUserInput(QLatin1String("/home/qtwebkithelpviewer.h")), 0,
categoryCompile)
)
<< QString();
@@ -916,7 +916,7 @@ void ProjectExplorerPlugin::testGccOutputParsers()
testbench.appendOutputParser(new GccParser);
QFETCH(QString, input);
QFETCH(OutputParserTester::Channel, inputChannel);
- QFETCH(QList<Task>, tasks);
+ QFETCH(Tasks, tasks);
QFETCH(QString, childStdOutLines);
QFETCH(QString, childStdErrLines);
QFETCH(QString, outputLines);
diff --git a/src/plugins/projectexplorer/gcctoolchain.cpp b/src/plugins/projectexplorer/gcctoolchain.cpp
index c9c28846f6..66db003212 100644
--- a/src/plugins/projectexplorer/gcctoolchain.cpp
+++ b/src/plugins/projectexplorer/gcctoolchain.cpp
@@ -77,7 +77,7 @@ static const char supportedAbisKeyC[] = "ProjectExplorer.GccToolChain.SupportedA
static const char parentToolChainIdKeyC[] = "ProjectExplorer.ClangToolChain.ParentToolChainId";
static const char binaryRegexp[] = "(?:^|-|\\b)(?:gcc|g\\+\\+|clang(?:\\+\\+)?)(?:-([\\d.]+))?$";
-static QByteArray runGcc(const FileName &gcc, const QStringList &arguments, const QStringList &env)
+static QByteArray runGcc(const FilePath &gcc, const QStringList &arguments, const QStringList &env)
{
if (gcc.isEmpty() || !gcc.toFileInfo().isExecutable())
return QByteArray();
@@ -98,7 +98,7 @@ static QByteArray runGcc(const FileName &gcc, const QStringList &arguments, cons
return response.allOutput().toUtf8();
}
-static ProjectExplorer::Macros gccPredefinedMacros(const FileName &gcc,
+static ProjectExplorer::Macros gccPredefinedMacros(const FilePath &gcc,
const QStringList &args,
const QStringList &env)
{
@@ -124,7 +124,7 @@ static ProjectExplorer::Macros gccPredefinedMacros(const FileName &gcc,
return predefinedMacros;
}
-HeaderPaths GccToolChain::gccHeaderPaths(const FileName &gcc, const QStringList &arguments,
+HeaderPaths GccToolChain::gccHeaderPaths(const FilePath &gcc, const QStringList &arguments,
const QStringList &env)
{
HeaderPaths builtInHeaderPaths;
@@ -167,16 +167,9 @@ HeaderPaths GccToolChain::gccHeaderPaths(const FileName &gcc, const QStringList
return builtInHeaderPaths;
}
-void GccToolChain::toolChainUpdated()
+static Abis guessGccAbi(const QString &m, const ProjectExplorer::Macros &macros)
{
- m_predefinedMacrosCache->invalidate();
- m_headerPathsCache->invalidate();
- ToolChain::toolChainUpdated();
-}
-
-static QList<Abi> guessGccAbi(const QString &m, const ProjectExplorer::Macros &macros)
-{
- QList<Abi> abiList;
+ Abis abiList;
Abi guessed = Abi::abiFromTargetTriplet(m);
if (guessed.isNull())
@@ -203,7 +196,10 @@ static QList<Abi> guessGccAbi(const QString &m, const ProjectExplorer::Macros &m
abiList << Abi(arch, os, flavor, format, width == 64 ? 32 : 64);
} else if (arch == Abi::X86Architecture && (width == 0 || width == 64)) {
abiList << Abi(arch, os, flavor, format, 64);
- abiList << Abi(arch, os, flavor, format, 32);
+ if (width != 64 || (!m.contains("mingw")
+ && ToolChainManager::detectionSettings().detectX64AsX32)) {
+ abiList << Abi(arch, os, flavor, format, 32);
+ }
} else {
abiList << Abi(arch, os, flavor, format, width);
}
@@ -211,7 +207,7 @@ static QList<Abi> guessGccAbi(const QString &m, const ProjectExplorer::Macros &m
}
-static GccToolChain::DetectedAbisResult guessGccAbi(const FileName &path, const QStringList &env,
+static GccToolChain::DetectedAbisResult guessGccAbi(const FilePath &path, const QStringList &env,
const ProjectExplorer::Macros &macros,
const QStringList &extraArgs = QStringList())
{
@@ -226,7 +222,7 @@ static GccToolChain::DetectedAbisResult guessGccAbi(const FileName &path, const
return GccToolChain::DetectedAbisResult(guessGccAbi(machine, macros), machine);
}
-static QString gccVersion(const FileName &path, const QStringList &env)
+static QString gccVersion(const FilePath &path, const QStringList &env)
{
QStringList arguments("-dumpversion");
return QString::fromLocal8Bit(runGcc(path, arguments, env)).trimmed();
@@ -236,17 +232,15 @@ static QString gccVersion(const FileName &path, const QStringList &env)
// GccToolChain
// --------------------------------------------------------------------------
-GccToolChain::GccToolChain(Detection d) :
- GccToolChain(Constants::GCC_TOOLCHAIN_TYPEID, d)
+GccToolChain::GccToolChain() :
+ GccToolChain(Constants::GCC_TOOLCHAIN_TYPEID)
{ }
-GccToolChain::GccToolChain(Core::Id typeId, Detection d) :
- ToolChain(typeId, d),
- m_predefinedMacrosCache(std::make_shared<Cache<MacroInspectionReport, 64>>()),
- m_headerPathsCache(std::make_shared<Cache<HeaderPaths>>())
+GccToolChain::GccToolChain(Core::Id typeId) :
+ ToolChain(typeId)
{ }
-void GccToolChain::setCompilerCommand(const FileName &path)
+void GccToolChain::setCompilerCommand(const FilePath &path)
{
if (path == m_compilerCommand)
return;
@@ -255,12 +249,12 @@ void GccToolChain::setCompilerCommand(const FileName &path)
toolChainUpdated();
}
-void GccToolChain::setSupportedAbis(const QList<Abi> &m_abis)
+void GccToolChain::setSupportedAbis(const Abis &abis)
{
- if (m_supportedAbis == m_abis)
+ if (m_supportedAbis == abis)
return;
- m_supportedAbis = m_abis;
+ m_supportedAbis = abis;
toolChainUpdated();
}
@@ -328,14 +322,14 @@ void GccToolChain::setTargetAbi(const Abi &abi)
toolChainUpdated();
}
-QList<Abi> GccToolChain::supportedAbis() const
+Abis GccToolChain::supportedAbis() const
{
return m_supportedAbis;
}
bool GccToolChain::isValid() const
{
- if (m_compilerCommand.isNull())
+ if (m_compilerCommand.isEmpty())
return false;
QFileInfo fi = compilerCommand().toFileInfo();
@@ -347,7 +341,7 @@ static bool isNetworkCompiler(const QString &dirPath)
return dirPath.contains("icecc") || dirPath.contains("distcc");
}
-static Utils::FileName findLocalCompiler(const Utils::FileName &compilerPath,
+static Utils::FilePath findLocalCompiler(const Utils::FilePath &compilerPath,
const Environment &env)
{
// Find the "real" compiler if icecc, distcc or similar are in use. Ignore ccache, since that
@@ -359,13 +353,13 @@ static Utils::FileName findLocalCompiler(const Utils::FileName &compilerPath,
return compilerPath;
// Filter out network compilers
- const FileNameList pathComponents = Utils::filtered(env.path(), [] (const FileName &dirPath) {
+ const FilePathList pathComponents = Utils::filtered(env.path(), [] (const FilePath &dirPath) {
return !isNetworkCompiler(dirPath.toString());
});
// This effectively searches the PATH twice, once via pathComponents and once via PATH itself:
// searchInPath filters duplicates, so that will not hurt.
- const Utils::FileName path = env.searchInPath(compilerPath.fileName(), pathComponents);
+ const Utils::FilePath path = env.searchInPath(compilerPath.fileName(), pathComponents);
return path.isEmpty() ? compilerPath : path;
}
@@ -375,11 +369,11 @@ ToolChain::MacroInspectionRunner GccToolChain::createMacroInspectionRunner() con
// Using a clean environment breaks ccache/distcc/etc.
Environment env = Environment::systemEnvironment();
addToEnvironment(env);
- const Utils::FileName compilerCommand = m_compilerCommand;
+ const Utils::FilePath compilerCommand = m_compilerCommand;
const QStringList platformCodeGenFlags = m_platformCodeGenFlags;
OptionsReinterpreter reinterpretOptions = m_optionsReinterpreter;
QTC_CHECK(reinterpretOptions);
- std::shared_ptr<Cache<MacroInspectionReport, 64>> macroCache = m_predefinedMacrosCache;
+ MacrosCache macroCache = predefinedMacrosCache();
Core::Id lang = language();
// This runner must be thread-safe!
@@ -566,63 +560,92 @@ void GccToolChain::initExtraHeaderPathsFunction(ExtraHeaderPathsFunction &&extra
m_extraHeaderPathsFunction = std::move(extraHeaderPathsFunction);
}
+HeaderPaths GccToolChain::builtInHeaderPaths(const Utils::Environment &env,
+ const Utils::FilePath &compilerCommand,
+ const QStringList &platformCodeGenFlags,
+ OptionsReinterpreter reinterpretOptions,
+ HeaderPathsCache headerCache,
+ Core::Id languageId,
+ ExtraHeaderPathsFunction extraHeaderPathsFunction,
+ const QStringList &flags,
+ const QString &sysRoot,
+ const QString &originalTargetTriple)
+{
+ QStringList arguments = gccPrepareArguments(flags,
+ sysRoot,
+ platformCodeGenFlags,
+ languageId,
+ reinterpretOptions);
+
+ // Must be clang case only.
+ if (!originalTargetTriple.isEmpty())
+ arguments << "-target" << originalTargetTriple;
+
+ const Utils::optional<HeaderPaths> cachedPaths = headerCache->check(arguments);
+ if (cachedPaths)
+ return cachedPaths.value();
+
+ HeaderPaths paths = gccHeaderPaths(findLocalCompiler(compilerCommand, env),
+ arguments,
+ env.toStringList());
+ extraHeaderPathsFunction(paths);
+ headerCache->insert(arguments, paths);
+
+ qCDebug(gccLog) << "Reporting header paths to code model:";
+ for (const HeaderPath &hp : paths) {
+ qCDebug(gccLog) << compilerCommand.toUserOutput()
+ << (languageId == Constants::CXX_LANGUAGE_ID ? ": C++ [" : ": C [")
+ << arguments.join(", ") << "]" << hp.path;
+ }
+
+ return paths;
+}
+
ToolChain::BuiltInHeaderPathsRunner GccToolChain::createBuiltInHeaderPathsRunner() const
{
// Using a clean environment breaks ccache/distcc/etc.
Environment env = Environment::systemEnvironment();
addToEnvironment(env);
- const Utils::FileName compilerCommand = m_compilerCommand;
- const QStringList platformCodeGenFlags = m_platformCodeGenFlags;
- OptionsReinterpreter reinterpretOptions = m_optionsReinterpreter;
- QTC_CHECK(reinterpretOptions);
- std::shared_ptr<Cache<HeaderPaths>> headerCache = m_headerPathsCache;
- Core::Id languageId = language();
-
// This runner must be thread-safe!
- return [env, compilerCommand, platformCodeGenFlags, reinterpretOptions, headerCache, languageId,
- extraHeaderPathsFunction = m_extraHeaderPathsFunction]
- (const QStringList &flags, const QString &sysRoot) {
-
- QStringList arguments = gccPrepareArguments(flags, sysRoot, platformCodeGenFlags,
- languageId, reinterpretOptions);
-
- const Utils::optional<HeaderPaths> cachedPaths = headerCache->check(arguments);
- if (cachedPaths)
- return cachedPaths.value();
-
- HeaderPaths paths = gccHeaderPaths(findLocalCompiler(compilerCommand, env),
- arguments, env.toStringList());
- extraHeaderPathsFunction(paths);
- headerCache->insert(arguments, paths);
-
- qCDebug(gccLog) << "Reporting header paths to code model:";
- for (const HeaderPath &hp : paths) {
- qCDebug(gccLog) << compilerCommand.toUserOutput()
- << (languageId == Constants::CXX_LANGUAGE_ID ? ": C++ [" : ": C [")
- << arguments.join(", ") << "]"
- << hp.path;
- }
-
- return paths;
+ return [env,
+ compilerCommand = m_compilerCommand,
+ platformCodeGenFlags = m_platformCodeGenFlags,
+ reinterpretOptions = m_optionsReinterpreter,
+ headerCache = headerPathsCache(),
+ languageId = language(),
+ extraHeaderPathsFunction = m_extraHeaderPathsFunction](const QStringList &flags,
+ const QString &sysRoot,
+ const QString &) {
+ return builtInHeaderPaths(env,
+ compilerCommand,
+ platformCodeGenFlags,
+ reinterpretOptions,
+ headerCache,
+ languageId,
+ extraHeaderPathsFunction,
+ flags,
+ sysRoot,
+ /*target=*/""); // Target must be empty for gcc.
};
}
HeaderPaths GccToolChain::builtInHeaderPaths(const QStringList &flags,
- const FileName &sysRoot) const
+ const FilePath &sysRootPath) const
{
- return createBuiltInHeaderPathsRunner()(flags, sysRoot.toString());
+ return createBuiltInHeaderPathsRunner()(flags,
+ sysRootPath.isEmpty() ? sysRoot()
+ : sysRootPath.toString(),
+ originalTargetTriple());
}
-void GccToolChain::addCommandPathToEnvironment(const FileName &command, Environment &env)
+void GccToolChain::addCommandPathToEnvironment(const FilePath &command, Environment &env)
{
- const Utils::FileName compilerDir = command.parentDir();
+ const Utils::FilePath compilerDir = command.parentDir();
if (!compilerDir.isEmpty())
env.prependOrSetPath(compilerDir.toString());
}
-GccToolChain::GccToolChain(const GccToolChain &) = default;
-
void GccToolChain::addToEnvironment(Environment &env) const
{
// On Windows gcc invokes cc1plus which is in libexec directory.
@@ -631,50 +654,48 @@ void GccToolChain::addToEnvironment(Environment &env) const
addCommandPathToEnvironment(m_compilerCommand, env);
}
-FileNameList GccToolChain::suggestedMkspecList() const
+QStringList GccToolChain::suggestedMkspecList() const
{
- Abi abi = targetAbi();
- Abi host = Abi::hostAbi();
+ const Abi abi = targetAbi();
+ const Abi host = Abi::hostAbi();
// Cross compile: Leave the mkspec alone!
if (abi.architecture() != host.architecture()
|| abi.os() != host.os()
|| abi.osFlavor() != host.osFlavor()) // Note: This can fail:-(
- return FileNameList();
+ return {};
if (abi.os() == Abi::DarwinOS) {
QString v = version();
// prefer versioned g++ on macOS. This is required to enable building for older macOS versions
if (v.startsWith("4.0") && m_compilerCommand.endsWith("-4.0"))
- return FileNameList() << FileName::fromLatin1("macx-g++40");
+ return {"macx-g++40"};
if (v.startsWith("4.2") && m_compilerCommand.endsWith("-4.2"))
- return FileNameList() << FileName::fromLatin1("macx-g++42");
- return FileNameList() << FileName::fromLatin1("macx-g++");
+ return {"macx-g++42"};
+ return {"macx-g++"};
}
if (abi.os() == Abi::LinuxOS) {
if (abi.osFlavor() != Abi::GenericFlavor)
- return FileNameList(); // most likely not a desktop, so leave the mkspec alone.
+ return {}; // most likely not a desktop, so leave the mkspec alone.
if (abi.wordWidth() == host.wordWidth()) {
// no need to explicitly set the word width, but provide that mkspec anyway to make sure
// that the correct compiler is picked if a mkspec with a wordwidth is given.
- return FileNameList() << FileName::fromLatin1("linux-g++")
- << FileName::fromString(QString::fromLatin1("linux-g++-") + QString::number(m_targetAbi.wordWidth()));
+ return {"linux-g++", "linux-g++-" + QString::number(m_targetAbi.wordWidth())};
}
- return FileNameList() << FileName::fromString(QString::fromLatin1("linux-g++-") + QString::number(m_targetAbi.wordWidth()));
+ return {"linux-g++-" + QString::number(m_targetAbi.wordWidth())};
}
if (abi.os() == Abi::BsdOS && abi.osFlavor() == Abi::FreeBsdFlavor)
- return FileNameList() << FileName::fromLatin1("freebsd-g++");
+ return {"freebsd-g++"};
- return FileNameList();
+ return {};
}
-QString GccToolChain::makeCommand(const Environment &environment) const
+FilePath GccToolChain::makeCommand(const Environment &environment) const
{
- QString make = "make";
- FileName tmp = environment.searchInPath(make);
- return tmp.isEmpty() ? make : tmp.toString();
+ const FilePath tmp = environment.searchInPath("make");
+ return tmp.isEmpty() ? FilePath::fromString("make") : tmp;
}
IOutputParser *GccToolChain::outputParser() const
@@ -682,7 +703,7 @@ IOutputParser *GccToolChain::outputParser() const
return new GccParser;
}
-void GccToolChain::resetToolChain(const FileName &path)
+void GccToolChain::resetToolChain(const FilePath &path)
{
bool resetDisplayName = (displayName() == defaultDisplayName());
@@ -707,7 +728,7 @@ void GccToolChain::resetToolChain(const FileName &path)
toolChainUpdated();
}
-FileName GccToolChain::compilerCommand() const
+FilePath GccToolChain::compilerCommand() const
{
return m_compilerCommand;
}
@@ -751,11 +772,6 @@ QStringList GccToolChain::platformLinkerFlags() const
return m_platformLinkerFlags;
}
-ToolChain *GccToolChain::clone() const
-{
- return new GccToolChain(*this);
-}
-
QVariantMap GccToolChain::toMap() const
{
QVariantMap data = ToolChain::toMap();
@@ -764,8 +780,7 @@ QVariantMap GccToolChain::toMap() const
data.insert(compilerPlatformLinkerFlagsKeyC, m_platformLinkerFlags);
data.insert(targetAbiKeyC, m_targetAbi.toString());
data.insert(originalTargetTripleKeyC, m_originalTargetTriple);
- QStringList abiList = Utils::transform(m_supportedAbis, &Abi::toString);
- data.insert(supportedAbisKeyC, abiList);
+ data.insert(supportedAbisKeyC, Utils::transform<QStringList>(m_supportedAbis, &Abi::toString));
return data;
}
@@ -774,7 +789,7 @@ bool GccToolChain::fromMap(const QVariantMap &data)
if (!ToolChain::fromMap(data))
return false;
- m_compilerCommand = FileName::fromString(data.value(compilerCommandKeyC).toString());
+ m_compilerCommand = FilePath::fromString(data.value(compilerCommandKeyC).toString());
m_platformCodeGenFlags = data.value(compilerPlatformCodeGenFlagsKeyC).toStringList();
m_platformLinkerFlags = data.value(compilerPlatformLinkerFlagsKeyC).toStringList();
const QString targetAbiString = data.value(targetAbiKeyC).toString();
@@ -850,168 +865,154 @@ QString GccToolChain::detectVersion() const
GccToolChainFactory::GccToolChainFactory()
{
setDisplayName(tr("GCC"));
-}
-
-QSet<Core::Id> GccToolChainFactory::supportedLanguages() const
-{
- return {Constants::C_LANGUAGE_ID, Constants::CXX_LANGUAGE_ID};
-}
-
-bool GccToolChainFactory::canCreate()
-{
- return true;
-}
-
-ToolChain *GccToolChainFactory::create(Core::Id language)
-{
- ToolChain *tc = createToolChain(false);
- tc->setLanguage(language);
- return tc;
-}
-
-void GccToolChainFactory::versionProbe(const QString &name, Core::Id language, Core::Id type,
- QList<ToolChain *> &tcs, QList<ToolChain *> &known,
- const QSet<QString> &filteredNames)
-{
- if (!HostOsInfo::isLinuxHost())
- return;
- const QRegularExpression regexp(binaryRegexp);
- for (const QString &dir : QStringList({ "/usr/bin", "/usr/local/bin" })) {
- QDir binDir(dir);
- for (const QString &entry : binDir.entryList(
- {"*-" + name, name + "-*", "*-" + name + "-*"},
- QDir::Files | QDir::Executable)) {
- const QString fileName = FileName::fromString(entry).fileName();
- if (filteredNames.contains(fileName))
- continue;
- const QRegularExpressionMatch match = regexp.match(fileName);
- if (!match.hasMatch())
- continue;
- const bool isNative = fileName.startsWith(name);
- const Abi abi = isNative ? Abi::hostAbi() : Abi();
- tcs.append(autoDetectToolchains(compilerPathFromEnvironment(entry), abi, language, type,
- known));
- known.append(tcs);
- }
- }
+ setSupportedToolChainType(Constants::GCC_TOOLCHAIN_TYPEID);
+ setSupportedLanguages({Constants::C_LANGUAGE_ID, Constants::CXX_LANGUAGE_ID});
+ setToolchainConstructor([] { return new GccToolChain; });
+ setUserCreatable(true);
}
QList<ToolChain *> GccToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown)
{
QList<ToolChain *> tcs;
QList<ToolChain *> known = alreadyKnown;
- tcs.append(autoDetectToolchains(compilerPathFromEnvironment("g++"), Abi::hostAbi(),
- Constants::CXX_LANGUAGE_ID, Constants::GCC_TOOLCHAIN_TYPEID,
- alreadyKnown));
- tcs.append(autoDetectToolchains(compilerPathFromEnvironment("gcc"), Abi::hostAbi(),
- Constants::C_LANGUAGE_ID, Constants::GCC_TOOLCHAIN_TYPEID,
- alreadyKnown));
- known.append(tcs);
- versionProbe("g++", Constants::CXX_LANGUAGE_ID, Constants::GCC_TOOLCHAIN_TYPEID, tcs, known);
- versionProbe("gcc", Constants::C_LANGUAGE_ID, Constants::GCC_TOOLCHAIN_TYPEID, tcs, known,
- {"c89-gcc", "c99-gcc"});
-
+ static const auto tcChecker = [](const ToolChain *tc) {
+ return tc->targetAbi().osFlavor() != Abi::WindowsMSysFlavor
+ && tc->compilerCommand().fileName() != "c89-gcc"
+ && tc->compilerCommand().fileName() != "c99-gcc";
+ };
+ tcs.append(autoDetectToolchains("g++", DetectVariants::Yes, Constants::CXX_LANGUAGE_ID,
+ Constants::GCC_TOOLCHAIN_TYPEID, alreadyKnown, tcChecker));
+ tcs.append(autoDetectToolchains("gcc", DetectVariants::Yes, Constants::C_LANGUAGE_ID,
+ Constants::GCC_TOOLCHAIN_TYPEID, alreadyKnown, tcChecker));
return tcs;
}
-QList<ToolChain *> GccToolChainFactory::autoDetect(const FileName &compilerPath, const Core::Id &language)
+QList<ToolChain *> GccToolChainFactory::autoDetect(const FilePath &compilerPath, const Core::Id &language)
{
const QString fileName = compilerPath.fileName();
if ((language == Constants::C_LANGUAGE_ID && (fileName.startsWith("gcc")
|| fileName.endsWith("gcc")))
|| (language == Constants::CXX_LANGUAGE_ID && (fileName.startsWith("g++")
|| fileName.endsWith("g++"))))
- return autoDetectToolChain(compilerPath, language);
+ return autoDetectToolChain(compilerPath, language, [](const ToolChain *tc) {
+ return tc->targetAbi().osFlavor() != Abi::WindowsMSysFlavor;
+ });
return QList<ToolChain *>();
}
-// Used by the ToolChainManager to restore user-generated tool chains
-bool GccToolChainFactory::canRestore(const QVariantMap &data)
-{
- return typeIdFromMap(data) == Constants::GCC_TOOLCHAIN_TYPEID;
-}
-
-ToolChain *GccToolChainFactory::restore(const QVariantMap &data)
-{
- GccToolChain *tc = createToolChain(false);
- if (tc->fromMap(data))
- return tc;
-
- delete tc;
- return nullptr;
-}
-
-GccToolChain *GccToolChainFactory::createToolChain(bool autoDetect)
-{
- return new GccToolChain(autoDetect ? ToolChain::AutoDetection : ToolChain::ManualDetection);
-}
-
-Utils::FileName GccToolChainFactory::compilerPathFromEnvironment(const QString &compilerName)
-{
- Environment systemEnvironment = Environment::systemEnvironment();
- return systemEnvironment.searchInPath(compilerName);
-}
-
-QList<ToolChain *> GccToolChainFactory::autoDetectToolchains(const FileName &compilerPath,
- const Abi &requiredAbi,
- Core::Id language,
- const Core::Id requiredTypeId,
- const QList<ToolChain *> &alreadyKnown)
+QList<ToolChain *> GccToolChainFactory::autoDetectToolchains(
+ const QString &compilerName, DetectVariants detectVariants, Core::Id language,
+ const Core::Id requiredTypeId, const QList<ToolChain *> &alreadyKnown,
+ const ToolchainChecker &checker)
{
- QList<ToolChain *> result;
-
- if (compilerPath.isEmpty())
- return result;
+ FilePathList compilerPaths;
+ QFileInfo fi(compilerName);
+ if (fi.isAbsolute()) {
+ if (fi.isFile())
+ compilerPaths << FilePath::fromString(compilerName);
+ } else {
+ const FilePathList searchPaths = Environment::systemEnvironment().path();
+ for (const FilePath &dir : searchPaths) {
+ static const QRegularExpression regexp(binaryRegexp);
+ QDir binDir(dir.toString());
+ QStringList nameFilters(compilerName);
+ if (detectVariants == DetectVariants::Yes) {
+ nameFilters
+ << compilerName + "-[1-9]*" // "clang-8", "gcc-5"
+ << ("*-*-*-" + compilerName) // "arm-none-eabi-gcc"
+ << ("*-*-*-" + compilerName + "-[1-9]*") // "arm-none-eabi-gcc-9.1.0"
+ << ("*-*-*-*-" + compilerName) // "x86_64-pc-linux-gnu-gcc"
+ << ("*-*-*-*-" + compilerName
+ + "-[1-9]*"); // "x86_64-pc-linux-gnu-gcc-7.4.1"
+ }
+ nameFilters = transform(nameFilters, [](const QString &baseName) {
+ return HostOsInfo::withExecutableSuffix(baseName);
+ });
+ const QStringList fileNames = binDir.entryList(nameFilters,
+ QDir::Files | QDir::Executable);
+ for (const QString &fileName : fileNames) {
+ if (fileName != compilerName &&
+ !regexp.match(QFileInfo(fileName).completeBaseName()).hasMatch()) {
+ continue;
+ }
+ compilerPaths << FilePath::fromString(binDir.filePath(fileName));
+ }
+ }
+ }
- result = Utils::filtered(alreadyKnown, [=](ToolChain *tc) {
- return tc->typeId() == requiredTypeId && tc->compilerCommand() == compilerPath
- && tc->language() == language;
+ QList<ToolChain *> existingCandidates
+ = filtered(alreadyKnown, [requiredTypeId, language, &checker](const ToolChain *tc) {
+ if (tc->typeId() != requiredTypeId)
+ return false;
+ if (tc->language() != language)
+ return false;
+ if (checker && !checker(tc))
+ return false;
+ return true;
});
- if (!result.isEmpty()) {
- for (ToolChain *tc : result) {
- if (tc->isAutoDetected())
- tc->setLanguage(language);
+ QList<ToolChain *> result;
+ for (const FilePath &compilerPath : compilerPaths) {
+ bool alreadyExists = false;
+ for (ToolChain * const existingTc : existingCandidates) {
+ // We have a match if the existing toolchain ultimately refers to the same file
+ // as the candidate path, either directly or via a hard or soft link.
+ // Exceptions:
+ // - clang++ is often a soft link to clang, but behaves differently.
+ // - ccache and icecc also create soft links that must not be followed here.
+ bool existingTcMatches = false;
+ const FilePath existingCommand = existingTc->compilerCommand();
+ if ((requiredTypeId == Constants::CLANG_TOOLCHAIN_TYPEID
+ && language == Constants::CXX_LANGUAGE_ID
+ && !existingCommand.fileName().contains("clang++"))
+ || compilerPath.toString().contains("icecc")
+ || compilerPath.toString().contains("ccache")) {
+ existingTcMatches = existingCommand == compilerPath;
+ } else {
+ existingTcMatches = Environment::systemEnvironment().isSameExecutable(
+ existingCommand.toString(), compilerPath.toString())
+ || (HostOsInfo::isWindowsHost() && existingCommand.toFileInfo().size()
+ == compilerPath.toFileInfo().size());
+ }
+ if (existingTcMatches) {
+ if (!result.contains(existingTc))
+ result << existingTc;
+ alreadyExists = true;
+ }
+ }
+ if (!alreadyExists) {
+ const QList<ToolChain *> newToolchains = autoDetectToolChain(compilerPath, language,
+ checker);
+ result << newToolchains;
+ existingCandidates << newToolchains;
}
- return result;
}
- result = autoDetectToolChain(compilerPath, language, requiredAbi);
-
return result;
}
-QList<ToolChain *> GccToolChainFactory::autoDetectToolChain(const FileName &compilerPath,
+QList<ToolChain *> GccToolChainFactory::autoDetectToolChain(const FilePath &compilerPath,
const Core::Id language,
- const Abi &requiredAbi)
+ const ToolchainChecker &checker)
{
QList<ToolChain *> result;
Environment systemEnvironment = Environment::systemEnvironment();
GccToolChain::addCommandPathToEnvironment(compilerPath, systemEnvironment);
- const FileName localCompilerPath = findLocalCompiler(compilerPath, systemEnvironment);
+ const FilePath localCompilerPath = findLocalCompiler(compilerPath, systemEnvironment);
Macros macros
= gccPredefinedMacros(localCompilerPath, gccPredefinedMacrosOptions(language),
systemEnvironment.toStringList());
const GccToolChain::DetectedAbisResult detectedAbis = guessGccAbi(localCompilerPath,
systemEnvironment.toStringList(),
macros);
-
- const QList<Abi> abiList = detectedAbis.supportedAbis;
- if (!requiredAbi.isNull() && !abiList.contains(requiredAbi)) {
- if (requiredAbi.wordWidth() != 64
- || !abiList.contains(Abi(requiredAbi.architecture(), requiredAbi.os(), requiredAbi.osFlavor(),
- requiredAbi.binaryFormat(), 32))) {
- return result;
- }
- }
-
- for (const Abi &abi : abiList) {
- std::unique_ptr<GccToolChain> tc(createToolChain(true));
+ for (const Abi &abi : detectedAbis.supportedAbis) {
+ std::unique_ptr<GccToolChain> tc(dynamic_cast<GccToolChain *>(create()));
if (!tc)
return result;
tc->setLanguage(language);
- tc->m_predefinedMacrosCache
+ tc->setDetection(ToolChain::AutoDetection);
+ tc->predefinedMacrosCache()
->insert(QStringList(),
ToolChain::MacroInspectionReport{macros,
ToolChain::languageVersion(language, macros)});
@@ -1020,8 +1021,8 @@ QList<ToolChain *> GccToolChainFactory::autoDetectToolChain(const FileName &comp
tc->setTargetAbi(abi);
tc->setOriginalTargetTriple(detectedAbis.originalTargetTriple);
tc->setDisplayName(tc->defaultDisplayName()); // reset displayname
-
- result.append(tc.release());
+ if (!checker || checker(tc.get()))
+ result.append(tc.release());
}
return result;
}
@@ -1085,7 +1086,7 @@ void GccToolChainConfigWidget::applyImpl()
if (m_macros.isEmpty())
return;
- tc->m_predefinedMacrosCache
+ tc->predefinedMacrosCache()
->insert(tc->platformCodeGenFlags(),
ToolChain::MacroInspectionReport{m_macros,
ToolChain::languageVersion(tc->language(),
@@ -1153,8 +1154,8 @@ void GccToolChainConfigWidget::handleCompilerCommandChange()
bool haveCompiler = false;
Abi currentAbi = m_abiWidget->currentAbi();
bool customAbi = m_abiWidget->isCustomAbi() && m_abiWidget->isEnabled();
- FileName path = m_compilerCommand->fileName();
- QList<Abi> abiList;
+ FilePath path = m_compilerCommand->fileName();
+ Abis abiList;
if (!path.isEmpty()) {
QFileInfo fi(path.toFileInfo());
@@ -1165,7 +1166,7 @@ void GccToolChainConfigWidget::handleCompilerCommandChange()
GccToolChain::addCommandPathToEnvironment(path, env);
QStringList args = gccPredefinedMacrosOptions(Constants::CXX_LANGUAGE_ID)
+ splitString(m_platformCodeGenFlagsLineEdit->text());
- const FileName localCompilerPath = findLocalCompiler(path, env);
+ const FilePath localCompilerPath = findLocalCompiler(path, env);
m_macros = gccPredefinedMacros(localCompilerPath, args, env.toStringList());
abiList = guessGccAbi(localCompilerPath, env.toStringList(), m_macros,
splitString(m_platformCodeGenFlagsLineEdit->text())).supportedAbis;
@@ -1263,40 +1264,41 @@ void ClangToolChain::syncAutodetectedWithParentToolchains()
});
}
-ClangToolChain::ClangToolChain(Detection d) :
- GccToolChain(Constants::CLANG_TOOLCHAIN_TYPEID, d)
+ClangToolChain::ClangToolChain() :
+ GccToolChain(Constants::CLANG_TOOLCHAIN_TYPEID)
{
syncAutodetectedWithParentToolchains();
}
-ClangToolChain::ClangToolChain(Core::Id typeId, ToolChain::Detection d) :
- GccToolChain(typeId, d)
+ClangToolChain::ClangToolChain(Core::Id typeId) :
+ GccToolChain(typeId)
{
syncAutodetectedWithParentToolchains();
}
-ClangToolChain::ClangToolChain(const ClangToolChain &other)
- : GccToolChain(other)
- , m_parentToolChainId(other.m_parentToolChainId)
-{}
+ClangToolChain::~ClangToolChain()
+{
+ QObject::disconnect(m_thisToolchainRemovedConnection);
+ QObject::disconnect(m_mingwToolchainAddedConnection);
+}
QString ClangToolChain::typeDisplayName() const
{
return ClangToolChainFactory::tr("Clang");
}
-QString ClangToolChain::makeCommand(const Environment &environment) const
+FilePath ClangToolChain::makeCommand(const Environment &environment) const
{
const QStringList makes
= HostOsInfo::isWindowsHost() ? QStringList({"mingw32-make.exe", "make.exe"}) : QStringList({"make"});
- FileName tmp;
+ FilePath tmp;
for (const QString &make : makes) {
tmp = environment.searchInPath(make);
if (!tmp.isEmpty())
- return tmp.toString();
+ return tmp;
}
- return makes.first();
+ return FilePath::fromString(makes.first());
}
/**
@@ -1323,23 +1325,16 @@ WarningFlags ClangToolChain::warningFlags(const QStringList &cflags) const
return flags;
}
-FileNameList ClangToolChain::suggestedMkspecList() const
+QStringList ClangToolChain::suggestedMkspecList() const
{
- Abi abi = targetAbi();
- if (abi.os() == Abi::DarwinOS) {
- return FileNameList()
- << FileName::fromLatin1("macx-clang")
- << FileName::fromLatin1("macx-clang-32")
- << FileName::fromLatin1("unsupported/macx-clang")
- << FileName::fromLatin1("macx-ios-clang");
- } else if (abi.os() == Abi::LinuxOS) {
- return FileNameList()
- << FileName::fromLatin1("linux-clang")
- << FileName::fromLatin1("unsupported/linux-clang");
- } else if (abi.os() == Abi::WindowsOS) {
- return FileNameList() << FileName::fromLatin1("win32-clang-g++");
- }
- return FileNameList(); // Note: Not supported by Qt yet, so default to the mkspec the Qt was build with
+ const Abi abi = targetAbi();
+ if (abi.os() == Abi::DarwinOS)
+ return {"macx-clang", "macx-clang-32", "unsupported/macx-clang", "macx-ios-clang"};
+ if (abi.os() == Abi::LinuxOS)
+ return {"linux-clang", "unsupported/linux-clang"};
+ if (abi.os() == Abi::WindowsOS)
+ return {"win32-clang-g++"};
+ return {}; // Note: Not supported by Qt yet, so default to the mkspec the Qt was build with
}
void ClangToolChain::addToEnvironment(Environment &env) const
@@ -1372,10 +1367,39 @@ QString ClangToolChain::sysRoot() const
if (!parentTC)
return QString();
- const FileName mingwCompiler = parentTC->compilerCommand();
+ const FilePath mingwCompiler = parentTC->compilerCommand();
return mingwCompiler.parentDir().parentDir().toString();
}
+ToolChain::BuiltInHeaderPathsRunner ClangToolChain::createBuiltInHeaderPathsRunner() const
+{
+ // Using a clean environment breaks ccache/distcc/etc.
+ Environment env = Environment::systemEnvironment();
+ addToEnvironment(env);
+
+ // This runner must be thread-safe!
+ return [env,
+ compilerCommand = m_compilerCommand,
+ platformCodeGenFlags = m_platformCodeGenFlags,
+ reinterpretOptions = m_optionsReinterpreter,
+ headerCache = headerPathsCache(),
+ languageId = language(),
+ extraHeaderPathsFunction = m_extraHeaderPathsFunction](const QStringList &flags,
+ const QString &sysRoot,
+ const QString &target) {
+ return builtInHeaderPaths(env,
+ compilerCommand,
+ platformCodeGenFlags,
+ reinterpretOptions,
+ headerCache,
+ languageId,
+ extraHeaderPathsFunction,
+ flags,
+ sysRoot,
+ target);
+ };
+}
+
std::unique_ptr<ToolChainConfigWidget> ClangToolChain::createConfigurationWidget()
{
return std::make_unique<ClangToolChainConfigWidget>(this);
@@ -1408,11 +1432,6 @@ IOutputParser *ClangToolChain::outputParser() const
return new ClangParser;
}
-ToolChain *ClangToolChain::clone() const
-{
- return new ClangToolChain(*this);
-}
-
// --------------------------------------------------------------------------
// ClangToolChainFactory
// --------------------------------------------------------------------------
@@ -1420,12 +1439,9 @@ ToolChain *ClangToolChain::clone() const
ClangToolChainFactory::ClangToolChainFactory()
{
setDisplayName(tr("Clang"));
-}
-
-QSet<Core::Id> ClangToolChainFactory::supportedLanguages() const
-{
- return {Constants::CXX_LANGUAGE_ID,
- Constants::C_LANGUAGE_ID};
+ setSupportedToolChainType(Constants::CLANG_TOOLCHAIN_TYPEID);
+ setSupportedLanguages({Constants::CXX_LANGUAGE_ID, Constants::C_LANGUAGE_ID});
+ setToolchainConstructor([] { return new ClangToolChain; });
}
QList<ToolChain *> ClangToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown)
@@ -1433,33 +1449,25 @@ QList<ToolChain *> ClangToolChainFactory::autoDetect(const QList<ToolChain *> &a
QList<ToolChain *> tcs;
QList<ToolChain *> known = alreadyKnown;
- const Abi hostAbi = Abi::hostAbi();
- tcs.append(autoDetectToolchains(compilerPathFromEnvironment("clang++"), hostAbi,
- Constants::CXX_LANGUAGE_ID, Constants::CLANG_TOOLCHAIN_TYPEID,
- alreadyKnown));
- tcs.append(autoDetectToolchains(compilerPathFromEnvironment("clang"), hostAbi,
- Constants::C_LANGUAGE_ID, Constants::CLANG_TOOLCHAIN_TYPEID,
- alreadyKnown));
+ tcs.append(autoDetectToolchains("clang++", DetectVariants::Yes, Constants::CXX_LANGUAGE_ID,
+ Constants::CLANG_TOOLCHAIN_TYPEID, alreadyKnown));
+ tcs.append(autoDetectToolchains("clang", DetectVariants::Yes, Constants::C_LANGUAGE_ID,
+ Constants::CLANG_TOOLCHAIN_TYPEID, alreadyKnown));
known.append(tcs);
- versionProbe("clang++", Constants::CXX_LANGUAGE_ID, Constants::CLANG_TOOLCHAIN_TYPEID, tcs, known);
- versionProbe("clang", Constants::C_LANGUAGE_ID, Constants::CLANG_TOOLCHAIN_TYPEID, tcs, known);
- const FileName compilerPath = FileName::fromString(Core::ICore::clangExecutable(CLANG_BINDIR));
+ const FilePath compilerPath = FilePath::fromString(Core::ICore::clangExecutable(CLANG_BINDIR));
if (!compilerPath.isEmpty()) {
- const FileName clang = compilerPath.parentDir().appendPath(
+ const FilePath clang = compilerPath.parentDir().pathAppended(
HostOsInfo::withExecutableSuffix("clang"));
- tcs.append(autoDetectToolchains(clang,
- hostAbi, Constants::CXX_LANGUAGE_ID,
- Constants::CLANG_TOOLCHAIN_TYPEID, alreadyKnown));
- tcs.append(autoDetectToolchains(clang,
- hostAbi, Constants::C_LANGUAGE_ID,
- Constants::CLANG_TOOLCHAIN_TYPEID, alreadyKnown));
+ tcs.append(autoDetectToolchains(clang.toString(), DetectVariants::No,
+ Constants::C_LANGUAGE_ID, Constants::CLANG_TOOLCHAIN_TYPEID,
+ tcs));
}
return tcs;
}
-QList<ToolChain *> ClangToolChainFactory::autoDetect(const FileName &compilerPath, const Core::Id &language)
+QList<ToolChain *> ClangToolChainFactory::autoDetect(const FilePath &compilerPath, const Core::Id &language)
{
const QString fileName = compilerPath.fileName();
if ((language == Constants::C_LANGUAGE_ID && fileName.startsWith("clang") && !fileName.startsWith("clang++"))
@@ -1468,16 +1476,6 @@ QList<ToolChain *> ClangToolChainFactory::autoDetect(const FileName &compilerPat
return QList<ToolChain *>();
}
-bool ClangToolChainFactory::canRestore(const QVariantMap &data)
-{
- return typeIdFromMap(data) == Constants::CLANG_TOOLCHAIN_TYPEID;
-}
-
-GccToolChain *ClangToolChainFactory::createToolChain(bool autoDetect)
-{
- return new ClangToolChain(autoDetect ? ToolChain::AutoDetection : ToolChain::ManualDetection);
-}
-
ClangToolChainConfigWidget::ClangToolChainConfigWidget(ClangToolChain *tc) :
GccToolChainConfigWidget(tc)
{
@@ -1594,8 +1592,8 @@ void ClangToolChainConfigWidget::makeReadOnlyImpl()
// MingwToolChain
// --------------------------------------------------------------------------
-MingwToolChain::MingwToolChain(Detection d) :
- GccToolChain(Constants::MINGW_TOOLCHAIN_TYPEID, d)
+MingwToolChain::MingwToolChain() :
+ GccToolChain(Constants::MINGW_TOOLCHAIN_TYPEID)
{ }
QString MingwToolChain::typeDisplayName() const
@@ -1603,40 +1601,30 @@ QString MingwToolChain::typeDisplayName() const
return MingwToolChainFactory::tr("MinGW");
}
-FileNameList MingwToolChain::suggestedMkspecList() const
+QStringList MingwToolChain::suggestedMkspecList() const
{
if (HostOsInfo::isWindowsHost())
- return FileNameList() << FileName::fromLatin1("win32-g++");
+ return {"win32-g++"};
if (HostOsInfo::isLinuxHost()) {
if (version().startsWith("4.6."))
- return FileNameList()
- << FileName::fromLatin1("win32-g++-4.6-cross")
- << FileName::fromLatin1("unsupported/win32-g++-4.6-cross");
- else
- return FileNameList()
- << FileName::fromLatin1("win32-g++-cross")
- << FileName::fromLatin1("unsupported/win32-g++-cross");
+ return {"win32-g++-4.6-cross", "unsupported/win32-g++-4.6-cross"};
+ return {"win32-g++-cross", "unsupported/win32-g++-cross"};
}
- return FileNameList();
+ return {};
}
-QString MingwToolChain::makeCommand(const Environment &environment) const
+FilePath MingwToolChain::makeCommand(const Environment &environment) const
{
const QStringList makes
= HostOsInfo::isWindowsHost() ? QStringList({"mingw32-make.exe", "make.exe"}) : QStringList({"make"});
- FileName tmp;
+ FilePath tmp;
foreach (const QString &make, makes) {
tmp = environment.searchInPath(make);
if (!tmp.isEmpty())
- return tmp.toString();
+ return tmp;
}
- return makes.first();
-}
-
-ToolChain *MingwToolChain::clone() const
-{
- return new MingwToolChain(*this);
+ return FilePath::fromString(makes.first());
}
// --------------------------------------------------------------------------
@@ -1646,56 +1634,45 @@ ToolChain *MingwToolChain::clone() const
MingwToolChainFactory::MingwToolChainFactory()
{
setDisplayName(tr("MinGW"));
-}
-
-QSet<Core::Id> MingwToolChainFactory::supportedLanguages() const
-{
- return {Constants::CXX_LANGUAGE_ID,
- Constants::C_LANGUAGE_ID};
+ setSupportedToolChainType(Constants::MINGW_TOOLCHAIN_TYPEID);
+ setSupportedLanguages({Constants::CXX_LANGUAGE_ID, Constants::C_LANGUAGE_ID});
+ setToolchainConstructor([] { return new MingwToolChain; });
}
QList<ToolChain *> MingwToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown)
{
Abi ha = Abi::hostAbi();
ha = Abi(ha.architecture(), Abi::WindowsOS, Abi::WindowsMSysFlavor, Abi::PEFormat, ha.wordWidth());
+ static const auto tcChecker = [](const ToolChain *tc) {
+ return tc->targetAbi().osFlavor() == Abi::WindowsMSysFlavor;
+ };
QList<ToolChain *> result = autoDetectToolchains(
- compilerPathFromEnvironment("g++"), ha, Constants::CXX_LANGUAGE_ID,
- Constants::MINGW_TOOLCHAIN_TYPEID, alreadyKnown);
- result += autoDetectToolchains(
- compilerPathFromEnvironment("gcc"), ha, Constants::C_LANGUAGE_ID,
- Constants::MINGW_TOOLCHAIN_TYPEID, alreadyKnown);
+ "g++", DetectVariants::Yes, Constants::CXX_LANGUAGE_ID,
+ Constants::MINGW_TOOLCHAIN_TYPEID, alreadyKnown, tcChecker);
+ result += autoDetectToolchains("gcc", DetectVariants::Yes, Constants::C_LANGUAGE_ID,
+ Constants::MINGW_TOOLCHAIN_TYPEID, alreadyKnown, tcChecker);
return result;
}
-QList<ToolChain *> MingwToolChainFactory::autoDetect(const FileName &compilerPath, const Core::Id &language)
+QList<ToolChain *> MingwToolChainFactory::autoDetect(const FilePath &compilerPath, const Core::Id &language)
{
- Abi ha = Abi::hostAbi();
- ha = Abi(ha.architecture(), Abi::WindowsOS, Abi::WindowsMSysFlavor, Abi::PEFormat, ha.wordWidth());
const QString fileName = compilerPath.fileName();
if ((language == Constants::C_LANGUAGE_ID && (fileName.startsWith("gcc")
|| fileName.endsWith("gcc")))
|| (language == Constants::CXX_LANGUAGE_ID && (fileName.startsWith("g++")
|| fileName.endsWith("g++"))))
- return autoDetectToolChain(compilerPath, language, ha);
+ return autoDetectToolChain(compilerPath, language, [](const ToolChain *tc) {
+ return tc->targetAbi().osFlavor() == Abi::WindowsMSysFlavor;
+ });
return QList<ToolChain *>();
}
-bool MingwToolChainFactory::canRestore(const QVariantMap &data)
-{
- return typeIdFromMap(data) == Constants::MINGW_TOOLCHAIN_TYPEID;
-}
-
-GccToolChain *MingwToolChainFactory::createToolChain(bool autoDetect)
-{
- return new MingwToolChain(autoDetect ? ToolChain::AutoDetection : ToolChain::ManualDetection);
-}
-
// --------------------------------------------------------------------------
// LinuxIccToolChain
// --------------------------------------------------------------------------
-LinuxIccToolChain::LinuxIccToolChain(Detection d) :
- GccToolChain(Constants::LINUXICC_TOOLCHAIN_TYPEID, d)
+LinuxIccToolChain::LinuxIccToolChain() :
+ GccToolChain(Constants::LINUXICC_TOOLCHAIN_TYPEID)
{ }
QString LinuxIccToolChain::typeDisplayName() const
@@ -1730,15 +1707,9 @@ IOutputParser *LinuxIccToolChain::outputParser() const
return new LinuxIccParser;
}
-FileNameList LinuxIccToolChain::suggestedMkspecList() const
+QStringList LinuxIccToolChain::suggestedMkspecList() const
{
- return FileNameList()
- << FileName::fromString(QString::fromLatin1("linux-icc-") + QString::number(targetAbi().wordWidth()));
-}
-
-ToolChain *LinuxIccToolChain::clone() const
-{
- return new LinuxIccToolChain(*this);
+ return {QString("linux-icc-%1").arg(targetAbi().wordWidth())};
}
// --------------------------------------------------------------------------
@@ -1748,26 +1719,22 @@ ToolChain *LinuxIccToolChain::clone() const
LinuxIccToolChainFactory::LinuxIccToolChainFactory()
{
setDisplayName(tr("Linux ICC"));
-}
-
-QSet<Core::Id> LinuxIccToolChainFactory::supportedLanguages() const
-{
- return {Constants::CXX_LANGUAGE_ID, Constants::C_LANGUAGE_ID};
+ setSupportedToolChainType(Constants::LINUXICC_TOOLCHAIN_TYPEID);
+ setSupportedLanguages({Constants::CXX_LANGUAGE_ID, Constants::C_LANGUAGE_ID});
+ setToolchainConstructor([] { return new LinuxIccToolChain; });
}
QList<ToolChain *> LinuxIccToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown)
{
QList<ToolChain *> result
- = autoDetectToolchains(compilerPathFromEnvironment("icpc"),
- Abi::hostAbi(), Constants::CXX_LANGUAGE_ID,
+ = autoDetectToolchains("icpc", DetectVariants::No, Constants::CXX_LANGUAGE_ID,
Constants::LINUXICC_TOOLCHAIN_TYPEID, alreadyKnown);
- result += autoDetectToolchains(compilerPathFromEnvironment("icc"),
- Abi::hostAbi(), Constants::C_LANGUAGE_ID,
+ result += autoDetectToolchains("icc", DetectVariants::Yes, Constants::C_LANGUAGE_ID,
Constants::LINUXICC_TOOLCHAIN_TYPEID, alreadyKnown);
return result;
}
-QList<ToolChain *> LinuxIccToolChainFactory::autoDetect(const FileName &compilerPath, const Core::Id &language)
+QList<ToolChain *> LinuxIccToolChainFactory::autoDetect(const FilePath &compilerPath, const Core::Id &language)
{
const QString fileName = compilerPath.fileName();
if ((language == Constants::CXX_LANGUAGE_ID && fileName.startsWith("icpc")) ||
@@ -1776,16 +1743,6 @@ QList<ToolChain *> LinuxIccToolChainFactory::autoDetect(const FileName &compiler
return {};
}
-bool LinuxIccToolChainFactory::canRestore(const QVariantMap &data)
-{
- return typeIdFromMap(data) == Constants::LINUXICC_TOOLCHAIN_TYPEID;
-}
-
-GccToolChain *LinuxIccToolChainFactory::createToolChain(bool autoDetect)
-{
- return new LinuxIccToolChain(autoDetect ? ToolChain::AutoDetection : ToolChain::ManualDetection);
-}
-
GccToolChain::WarningFlagAdder::WarningFlagAdder(const QString &flag, WarningFlags &flags) :
m_flags(flags)
{
@@ -1873,7 +1830,7 @@ void ProjectExplorerPlugin::testGccAbiGuessing_data()
QTest::newRow("Linux 3 (64bit intel)")
<< QString::fromLatin1("x86_64-linux-gnu")
<< QByteArray("#define __SIZEOF_SIZE_T__ 8\n")
- << QStringList({"x86-linux-generic-elf-64bit", "x86-linux-generic-elf-32bit"});
+ << QStringList("x86-linux-generic-elf-64bit");
QTest::newRow("Linux 3 (64bit intel -- non 64bit)")
<< QString::fromLatin1("x86_64-linux-gnu")
<< QByteArray("#define __SIZEOF_SIZE_T__ 4\n")
@@ -1885,11 +1842,11 @@ void ProjectExplorerPlugin::testGccAbiGuessing_data()
QTest::newRow("Linux 5 (QTCREATORBUG-4690)") // from QTCREATORBUG-4690
<< QString::fromLatin1("x86_64-redhat-linux6E")
<< QByteArray("#define __SIZEOF_SIZE_T__ 8\n")
- << QStringList({"x86-linux-generic-elf-64bit", "x86-linux-generic-elf-32bit"});
+ << QStringList("x86-linux-generic-elf-64bit");
QTest::newRow("Linux 6 (QTCREATORBUG-4690)") // from QTCREATORBUG-4690
<< QString::fromLatin1("x86_64-redhat-linux")
<< QByteArray("#define __SIZEOF_SIZE_T__ 8\n")
- << QStringList({"x86-linux-generic-elf-64bit", "x86-linux-generic-elf-32bit"});
+ << QStringList("x86-linux-generic-elf-64bit");
QTest::newRow("Linux 7 (arm)")
<< QString::fromLatin1("armv5tl-montavista-linux-gnueabi")
<< QByteArray("#define __SIZEOF_SIZE_T__ 4\n")
@@ -1918,7 +1875,7 @@ void ProjectExplorerPlugin::testGccAbiGuessing_data()
QTest::newRow("Mingw 2 (64bit)")
<< QString::fromLatin1("i686-w64-mingw32")
<< QByteArray("#define __SIZEOF_SIZE_T__ 8\r\n")
- << QStringList({"x86-windows-msys-pe-64bit", "x86-windows-msys-pe-32bit"});
+ << QStringList({"x86-windows-msys-pe-64bit"});
QTest::newRow("Mingw 3 (32 bit)")
<< QString::fromLatin1("mingw32")
<< QByteArray("#define __SIZEOF_SIZE_T__ 4\r\n")
@@ -1926,7 +1883,7 @@ void ProjectExplorerPlugin::testGccAbiGuessing_data()
QTest::newRow("Cross Mingw 1 (64bit)")
<< QString::fromLatin1("amd64-mingw32msvc")
<< QByteArray("#define __SIZEOF_SIZE_T__ 8\r\n")
- << QStringList({"x86-windows-msys-pe-64bit", "x86-windows-msys-pe-32bit"});
+ << QStringList({"x86-windows-msys-pe-64bit"});
QTest::newRow("Cross Mingw 2 (32bit)")
<< QString::fromLatin1("i586-mingw32msvc")
<< QByteArray("#define __SIZEOF_SIZE_T__ 4\r\n")
@@ -1934,11 +1891,11 @@ void ProjectExplorerPlugin::testGccAbiGuessing_data()
QTest::newRow("Clang 1: windows")
<< QString::fromLatin1("x86_64-pc-win32")
<< QByteArray("#define __SIZEOF_SIZE_T__ 8\r\n")
- << QStringList({"x86-windows-msys-pe-64bit", "x86-windows-msys-pe-32bit"});
+ << QStringList("x86-windows-msys-pe-64bit");
QTest::newRow("Clang 1: linux")
<< QString::fromLatin1("x86_64-unknown-linux-gnu")
<< QByteArray("#define __SIZEOF_SIZE_T__ 8\n")
- << QStringList({"x86-linux-generic-elf-64bit", "x86-linux-generic-elf-32bit"});
+ << QStringList("x86-linux-generic-elf-64bit");
QTest::newRow("Mac 1")
<< QString::fromLatin1("i686-apple-darwin10")
<< QByteArray("#define __SIZEOF_SIZE_T__ 8\n")
@@ -1958,7 +1915,7 @@ void ProjectExplorerPlugin::testGccAbiGuessing_data()
QTest::newRow("Intel 1")
<< QString::fromLatin1("86_64 x86_64 GNU/Linux")
<< QByteArray("#define __SIZEOF_SIZE_T__ 8\n")
- << QStringList({"x86-linux-generic-elf-64bit", "x86-linux-generic-elf-32bit"});
+ << QStringList("x86-linux-generic-elf-64bit");
QTest::newRow("FreeBSD 1")
<< QString::fromLatin1("i386-portbld-freebsd9.0")
<< QByteArray("#define __SIZEOF_SIZE_T__ 4\n")
@@ -1975,7 +1932,7 @@ void ProjectExplorerPlugin::testGccAbiGuessing()
QFETCH(QByteArray, macros);
QFETCH(QStringList, abiList);
- QList<Abi> al = guessGccAbi(input, ProjectExplorer::Macro::toMacros(macros));
+ const Abis al = guessGccAbi(input, ProjectExplorer::Macro::toMacros(macros));
QCOMPARE(al.count(), abiList.count());
for (int i = 0; i < al.count(); ++i)
QCOMPARE(al.at(i).toString(), abiList.at(i));
diff --git a/src/plugins/projectexplorer/gcctoolchain.h b/src/plugins/projectexplorer/gcctoolchain.h
index b34614cde8..240ae34247 100644
--- a/src/plugins/projectexplorer/gcctoolchain.h
+++ b/src/plugins/projectexplorer/gcctoolchain.h
@@ -29,7 +29,6 @@
#include "projectexplorerconstants.h"
#include "toolchain.h"
-#include "toolchaincache.h"
#include "abi.h"
#include "headerpath.h"
@@ -68,12 +67,12 @@ inline const QStringList gccPredefinedMacrosOptions(Core::Id languageId)
class PROJECTEXPLORER_EXPORT GccToolChain : public ToolChain
{
public:
- GccToolChain(Core::Id typeId, Detection d);
+ GccToolChain(Core::Id typeId);
QString typeDisplayName() const override;
Abi targetAbi() const override;
QString originalTargetTriple() const override;
QString version() const;
- QList<Abi> supportedAbis() const override;
+ Abis supportedAbis() const override;
void setTargetAbi(const Abi &);
bool isValid() const override;
@@ -86,11 +85,11 @@ public:
BuiltInHeaderPathsRunner createBuiltInHeaderPathsRunner() const override;
HeaderPaths builtInHeaderPaths(const QStringList &flags,
- const Utils::FileName &sysRoot) const override;
+ const Utils::FilePath &sysRootPath) const override;
void addToEnvironment(Utils::Environment &env) const override;
- QString makeCommand(const Utils::Environment &environment) const override;
- Utils::FileNameList suggestedMkspecList() const override;
+ Utils::FilePath makeCommand(const Utils::Environment &environment) const override;
+ QStringList suggestedMkspecList() const override;
IOutputParser *outputParser() const override;
QVariantMap toMap() const override;
@@ -100,28 +99,25 @@ public:
bool operator ==(const ToolChain &) const override;
- void resetToolChain(const Utils::FileName &);
- Utils::FileName compilerCommand() const override;
+ void resetToolChain(const Utils::FilePath &);
+ Utils::FilePath compilerCommand() const override;
void setPlatformCodeGenFlags(const QStringList &);
QStringList extraCodeModelFlags() const override;
QStringList platformCodeGenFlags() const;
void setPlatformLinkerFlags(const QStringList &);
QStringList platformLinkerFlags() const;
- ToolChain *clone() const override;
-
- static void addCommandPathToEnvironment(const Utils::FileName &command, Utils::Environment &env);
+ static void addCommandPathToEnvironment(const Utils::FilePath &command, Utils::Environment &env);
class DetectedAbisResult {
public:
DetectedAbisResult() = default;
- DetectedAbisResult(const QList<Abi> &supportedAbis,
- const QString &originalTargetTriple = QString()) :
+ DetectedAbisResult(const Abis &supportedAbis, const QString &originalTargetTriple = {}) :
supportedAbis(supportedAbis),
originalTargetTriple(originalTargetTriple)
{ }
- QList<Abi> supportedAbis;
+ Abis supportedAbis;
QString originalTargetTriple;
};
@@ -129,10 +125,8 @@ protected:
using CacheItem = QPair<QStringList, Macros>;
using GccCache = QVector<CacheItem>;
- GccToolChain(const GccToolChain &);
-
- void setCompilerCommand(const Utils::FileName &path);
- void setSupportedAbis(const QList<Abi> &m_abis);
+ void setCompilerCommand(const Utils::FilePath &path);
+ void setSupportedAbis(const Abis &abis);
void setOriginalTargetTriple(const QString &targetTriple);
void setMacroCache(const QStringList &allCxxflags, const Macros &macroCache) const;
Macros macroCache(const QStringList &allCxxflags) const;
@@ -151,7 +145,18 @@ protected:
using ExtraHeaderPathsFunction = std::function<void(HeaderPaths &)>;
void initExtraHeaderPathsFunction(ExtraHeaderPathsFunction &&extraHeaderPathsFunction) const;
- static HeaderPaths gccHeaderPaths(const Utils::FileName &gcc, const QStringList &args,
+ static HeaderPaths builtInHeaderPaths(const Utils::Environment &env,
+ const Utils::FilePath &compilerCommand,
+ const QStringList &platformCodeGenFlags,
+ OptionsReinterpreter reinterpretOptions,
+ HeaderPathsCache headerCache,
+ Core::Id languageId,
+ ExtraHeaderPathsFunction extraHeaderPathsFunction,
+ const QStringList &flags,
+ const QString &sysRoot,
+ const QString &originalTargetTriple);
+
+ static HeaderPaths gccHeaderPaths(const Utils::FilePath &gcc, const QStringList &args,
const QStringList &env);
class WarningFlagAdder
@@ -167,10 +172,9 @@ protected:
bool m_doesEnable = false;
bool m_triggered = false;
};
- void toolChainUpdated() override;
private:
- explicit GccToolChain(Detection d);
+ explicit GccToolChain();
void updateSupportedAbis() const;
static QStringList gccPrepareArguments(const QStringList &flags,
@@ -179,22 +183,21 @@ private:
Core::Id languageId,
OptionsReinterpreter reinterpretOptions);
- Utils::FileName m_compilerCommand;
+protected:
+ Utils::FilePath m_compilerCommand;
QStringList m_platformCodeGenFlags;
QStringList m_platformLinkerFlags;
OptionsReinterpreter m_optionsReinterpreter = [](const QStringList &v) { return v; };
+ mutable ExtraHeaderPathsFunction m_extraHeaderPathsFunction = [](HeaderPaths &) {};
+private:
Abi m_targetAbi;
- mutable QList<Abi> m_supportedAbis;
+ mutable Abis m_supportedAbis;
mutable QString m_originalTargetTriple;
mutable HeaderPaths m_headerPaths;
mutable QString m_version;
- mutable std::shared_ptr<Cache<MacroInspectionReport, 64>> m_predefinedMacrosCache;
- mutable std::shared_ptr<Cache<HeaderPaths>> m_headerPathsCache;
- mutable ExtraHeaderPathsFunction m_extraHeaderPathsFunction = [](HeaderPaths &) {};
-
friend class Internal::GccToolChainConfigWidget;
friend class Internal::GccToolChainFactory;
friend class ToolChainFactory;
@@ -207,25 +210,26 @@ private:
class PROJECTEXPLORER_EXPORT ClangToolChain : public GccToolChain
{
public:
- explicit ClangToolChain(Detection d);
- ClangToolChain(Core::Id typeId, Detection d);
- ClangToolChain(const ClangToolChain &other);
+ ClangToolChain();
+ explicit ClangToolChain(Core::Id typeId);
+ ~ClangToolChain() override;
+
QString typeDisplayName() const override;
- QString makeCommand(const Utils::Environment &environment) const override;
+ Utils::FilePath makeCommand(const Utils::Environment &environment) const override;
Utils::LanguageExtensions languageExtensions(const QStringList &cxxflags) const override;
WarningFlags warningFlags(const QStringList &cflags) const override;
IOutputParser *outputParser() const override;
- ToolChain *clone() const override;
-
- Utils::FileNameList suggestedMkspecList() const override;
+ QStringList suggestedMkspecList() const override;
void addToEnvironment(Utils::Environment &env) const override;
QString originalTargetTriple() const override;
QString sysRoot() const override;
+ BuiltInHeaderPathsRunner createBuiltInHeaderPathsRunner() const override;
+
std::unique_ptr<ToolChainConfigWidget> createConfigurationWidget() override;
QVariantMap toMap() const override;
@@ -253,14 +257,12 @@ class PROJECTEXPLORER_EXPORT MingwToolChain : public GccToolChain
{
public:
QString typeDisplayName() const override;
- QString makeCommand(const Utils::Environment &environment) const override;
-
- ToolChain *clone() const override;
+ Utils::FilePath makeCommand(const Utils::Environment &environment) const override;
- Utils::FileNameList suggestedMkspecList() const override;
+ QStringList suggestedMkspecList() const override;
private:
- explicit MingwToolChain(Detection d);
+ MingwToolChain();
friend class Internal::MingwToolChainFactory;
friend class ToolChainFactory;
@@ -278,12 +280,10 @@ public:
Utils::LanguageExtensions languageExtensions(const QStringList &cxxflags) const override;
IOutputParser *outputParser() const override;
- ToolChain *clone() const override;
-
- Utils::FileNameList suggestedMkspecList() const override;
+ QStringList suggestedMkspecList() const override;
private:
- explicit LinuxIccToolChain(Detection d);
+ LinuxIccToolChain();
friend class Internal::LinuxIccToolChainFactory;
friend class ToolChainFactory;
diff --git a/src/plugins/projectexplorer/gcctoolchainfactories.h b/src/plugins/projectexplorer/gcctoolchainfactories.h
index 775e0db675..e33ebcaa03 100644
--- a/src/plugins/projectexplorer/gcctoolchainfactories.h
+++ b/src/plugins/projectexplorer/gcctoolchainfactories.h
@@ -33,6 +33,8 @@
#include <QList>
#include <QSet>
+#include <functional>
+
QT_BEGIN_NAMESPACE
class QComboBox;
QT_END_NAMESPACE
@@ -51,33 +53,20 @@ class GccToolChainFactory : public ToolChainFactory
public:
GccToolChainFactory();
- QSet<Core::Id> supportedLanguages() const override;
QList<ToolChain *> autoDetect(const QList<ToolChain *> &alreadyKnown) override;
- QList<ToolChain *> autoDetect(const Utils::FileName &compilerPath, const Core::Id &language) override;
-
- bool canCreate() override;
- ToolChain *create(Core::Id language) override;
-
- bool canRestore(const QVariantMap &data) override;
- ToolChain *restore(const QVariantMap &data) override;
+ QList<ToolChain *> autoDetect(const Utils::FilePath &compilerPath, const Core::Id &language) override;
protected:
- virtual GccToolChain *createToolChain(bool autoDetect);
- void versionProbe(const QString &name,
- Core::Id language,
- Core::Id type,
- QList<ToolChain *> &tcs,
- QList<ToolChain *> &known,
- const QSet<QString> &filteredNames = {});
-
- Utils::FileName compilerPathFromEnvironment(const QString &compilerName);
-
+ enum class DetectVariants { Yes, No };
+ using ToolchainChecker = std::function<bool(const ToolChain *)>;
QList<ToolChain *> autoDetectToolchains(
- const Utils::FileName &compilerPath, const Abi &requiredAbi, Core::Id language,
- const Core::Id requiredTypeId, const QList<ToolChain *> &alreadyKnown);
- QList<ToolChain *> autoDetectToolChain(const Utils::FileName &compilerPath, const Core::Id language,
- const Abi &requiredAbi = Abi());
+ const QString &compilerName, DetectVariants detectVariants, Core::Id language,
+ const Core::Id requiredTypeId, const QList<ToolChain *> &alreadyKnown,
+ const ToolchainChecker &checker = {});
+ QList<ToolChain *> autoDetectToolChain(
+ const Utils::FilePath &compilerPath, const Core::Id language,
+ const ToolchainChecker &checker = {});
};
// --------------------------------------------------------------------------
@@ -147,15 +136,9 @@ class ClangToolChainFactory : public GccToolChainFactory
public:
ClangToolChainFactory();
- QSet<Core::Id> supportedLanguages() const override;
QList<ToolChain *> autoDetect(const QList<ToolChain *> &alreadyKnown) override;
- QList<ToolChain *> autoDetect(const Utils::FileName &compilerPath, const Core::Id &language) final;
-
- bool canRestore(const QVariantMap &data) override;
-
-protected:
- GccToolChain *createToolChain(bool autoDetect) override;
+ QList<ToolChain *> autoDetect(const Utils::FilePath &compilerPath, const Core::Id &language) final;
};
// --------------------------------------------------------------------------
@@ -168,15 +151,9 @@ class MingwToolChainFactory : public GccToolChainFactory
public:
MingwToolChainFactory();
- QSet<Core::Id> supportedLanguages() const override;
QList<ToolChain *> autoDetect(const QList<ToolChain *> &alreadyKnown) override;
- QList<ToolChain *> autoDetect(const Utils::FileName &compilerPath, const Core::Id &language) final;
-
- bool canRestore(const QVariantMap &data) override;
-
-protected:
- GccToolChain *createToolChain(bool autoDetect) override;
+ QList<ToolChain *> autoDetect(const Utils::FilePath &compilerPath, const Core::Id &language) final;
};
// --------------------------------------------------------------------------
@@ -189,15 +166,9 @@ class LinuxIccToolChainFactory : public GccToolChainFactory
public:
LinuxIccToolChainFactory();
- QSet<Core::Id> supportedLanguages() const override;
QList<ToolChain *> autoDetect(const QList<ToolChain *> &alreadyKnown) override;
- QList<ToolChain *> autoDetect(const Utils::FileName &compilerPath, const Core::Id &language) final;
-
- bool canRestore(const QVariantMap &data) override;
-
-protected:
- GccToolChain *createToolChain(bool autoDetect) override;
+ QList<ToolChain *> autoDetect(const Utils::FilePath &compilerPath, const Core::Id &language) final;
};
} // namespace Internal
diff --git a/src/plugins/projectexplorer/gnumakeparser.cpp b/src/plugins/projectexplorer/gnumakeparser.cpp
index 2b9c0820cc..dc14301117 100644
--- a/src/plugins/projectexplorer/gnumakeparser.cpp
+++ b/src/plugins/projectexplorer/gnumakeparser.cpp
@@ -90,6 +90,18 @@ public:
Task::TaskType type = Task::Error;
};
+static Task::TaskType taskTypeFromDescription(const QString &description)
+{
+ if (description.contains(". Stop."))
+ return Task::Error;
+ if (description.contains("not found"))
+ return Task::Error;
+ if (description.contains("No rule to make target"))
+ return Task::Error;
+ // Extend as needed.
+ return Task::Warning;
+}
+
static Result parseDescription(const QString &description)
{
Result result;
@@ -103,7 +115,7 @@ static Result parseDescription(const QString &description)
result.isFatal = true;
} else {
result.description = description;
- result.type = Task::Error;
+ result.type = taskTypeFromDescription(description);
result.isFatal = false;
}
return result;
@@ -121,7 +133,7 @@ void GnuMakeParser::stdError(const QString &line)
++m_fatalErrorCount;
if (!m_suppressIssues) {
taskAdded(Task(res.type, res.description,
- Utils::FileName::fromUserInput(match.captured(1)) /* filename */,
+ Utils::FilePath::fromUserInput(match.captured(1)) /* filename */,
match.captured(4).toInt(), /* line */
Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM)), 1, 0);
}
@@ -135,7 +147,7 @@ void GnuMakeParser::stdError(const QString &line)
++m_fatalErrorCount;
if (!m_suppressIssues) {
Task task = Task(res.type, res.description,
- Utils::FileName() /* filename */, -1, /* line */
+ Utils::FilePath() /* filename */, -1, /* line */
Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM));
taskAdded(task, 1, 0);
}
@@ -169,7 +181,7 @@ void GnuMakeParser::taskAdded(const Task &task, int linkedLines, int skippedLine
QString filePath(task.file.toString());
if (!filePath.isEmpty() && !QDir::isAbsolutePath(filePath)) {
- QList<QFileInfo> possibleFiles;
+ QFileInfoList possibleFiles;
foreach (const QString &dir, m_directories) {
QFileInfo candidate(dir + QLatin1Char('/') + filePath);
if (candidate.exists()
@@ -178,7 +190,7 @@ void GnuMakeParser::taskAdded(const Task &task, int linkedLines, int skippedLine
}
}
if (possibleFiles.size() == 1)
- editable.file = Utils::FileName(possibleFiles.first());
+ 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!
@@ -222,7 +234,7 @@ void ProjectExplorerPlugin::testGnuMakeParserParsing_data()
QTest::addColumn<OutputParserTester::Channel>("inputChannel");
QTest::addColumn<QString>("childStdOutLines");
QTest::addColumn<QString>("childStdErrLines");
- QTest::addColumn<QList<Task> >("tasks");
+ QTest::addColumn<Tasks >("tasks");
QTest::addColumn<QString>("outputLines");
QTest::addColumn<QStringList>("additionalSearchDirs");
@@ -230,14 +242,14 @@ void ProjectExplorerPlugin::testGnuMakeParserParsing_data()
<< QStringList()
<< QString::fromLatin1("Sometext") << OutputParserTester::STDOUT
<< QString::fromLatin1("Sometext\n") << QString()
- << QList<Task>()
+ << Tasks()
<< QString()
<< QStringList();
QTest::newRow("pass-through stderr")
<< QStringList()
<< QString::fromLatin1("Sometext") << OutputParserTester::STDERR
<< QString() << QString::fromLatin1("Sometext\n")
- << QList<Task>()
+ << Tasks()
<< QString()
<< QStringList();
QTest::newRow("pass-through gcc infos")
@@ -254,7 +266,7 @@ void ProjectExplorerPlugin::testGnuMakeParserParsing_data()
"../../scriptbug/main.cpp: In instantiation of void bar(i) [with i = double]:\n"
"../../scriptbug/main.cpp:8: instantiated from void foo(i) [with i = double]\n"
"../../scriptbug/main.cpp:22: instantiated from here\n")
- << QList<Task>()
+ << Tasks()
<< QString()
<< QStringList();
@@ -265,7 +277,7 @@ void ProjectExplorerPlugin::testGnuMakeParserParsing_data()
"make[4]: Entering directory `/home/code/build/qt/examples/opengl/grabber'")
<< OutputParserTester::STDOUT
<< QString() << QString()
- << QList<Task>()
+ << Tasks()
<< QString()
<< QStringList({"/home/code/build/qt/examples/opengl/grabber",
"/home/code/build/qt/examples/opengl/grabber", "/test/dir"});
@@ -274,7 +286,7 @@ void ProjectExplorerPlugin::testGnuMakeParserParsing_data()
<< QString::fromLatin1("make[4]: Leaving directory `/home/code/build/qt/examples/opengl/grabber'")
<< OutputParserTester::STDOUT
<< QString() << QString()
- << QList<Task>()
+ << Tasks()
<< QString()
<< QStringList("/test/dir");
QTest::newRow("make error")
@@ -282,10 +294,10 @@ void ProjectExplorerPlugin::testGnuMakeParserParsing_data()
<< QString::fromLatin1("make: *** No rule to make target `hello.c', needed by `hello.o'. Stop.")
<< OutputParserTester::STDERR
<< QString() << QString()
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Error,
QString::fromLatin1("No rule to make target `hello.c', needed by `hello.o'. Stop."),
- Utils::FileName(), -1,
+ Utils::FilePath(), -1,
Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM)))
<< QString()
<< QStringList();
@@ -296,10 +308,10 @@ void ProjectExplorerPlugin::testGnuMakeParserParsing_data()
"make[2]: *** [sub-projectexplorer-make_default] Error 2")
<< OutputParserTester::STDERR
<< QString() << QString()
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Error,
QString::fromLatin1("[.obj/debug-shared/gnumakeparser.o] Error 1"),
- Utils::FileName(), -1,
+ Utils::FilePath(), -1,
Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM)))
<< QString()
<< QStringList();
@@ -308,10 +320,10 @@ void ProjectExplorerPlugin::testGnuMakeParserParsing_data()
<< QString::fromLatin1("Makefile:360: *** missing separator (did you mean TAB instead of 8 spaces?). Stop.")
<< OutputParserTester::STDERR
<< QString() << QString()
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Error,
QString::fromLatin1("missing separator (did you mean TAB instead of 8 spaces?). Stop."),
- Utils::FileName::fromUserInput(QLatin1String("Makefile")), 360,
+ Utils::FilePath::fromUserInput(QLatin1String("Makefile")), 360,
Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM)))
<< QString()
<< QStringList();
@@ -321,10 +333,10 @@ void ProjectExplorerPlugin::testGnuMakeParserParsing_data()
"mingw32-make: *** [debug] Error 2")
<< OutputParserTester::STDERR
<< QString() << QString()
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Error,
QString::fromLatin1("[debug/qplotaxis.o] Error 1"),
- Utils::FileName(), -1,
+ Utils::FilePath(), -1,
Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM)))
<< QString()
<< QStringList();
@@ -333,10 +345,10 @@ void ProjectExplorerPlugin::testGnuMakeParserParsing_data()
<< QString::fromLatin1("mingw64-make.exe[1]: *** [dynlib.inst] Error -1073741819")
<< OutputParserTester::STDERR
<< QString() << QString()
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Error,
QString::fromLatin1("[dynlib.inst] Error -1073741819"),
- Utils::FileName(), -1,
+ Utils::FilePath(), -1,
Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM)))
<< QString()
<< QStringList();
@@ -345,10 +357,10 @@ void ProjectExplorerPlugin::testGnuMakeParserParsing_data()
<< QString::fromLatin1("make[2]: warning: jobserver unavailable: using -j1. Add `+' to parent make rule.")
<< OutputParserTester::STDERR
<< QString() << QString()
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Warning,
QString::fromLatin1("jobserver unavailable: using -j1. Add `+' to parent make rule."),
- Utils::FileName(), -1,
+ Utils::FilePath(), -1,
Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM)))
<< QString()
<< QStringList();
@@ -357,7 +369,7 @@ void ProjectExplorerPlugin::testGnuMakeParserParsing_data()
<< QString::fromLatin1("/home/dev/creator/share/qtcreator/debugger/dumper.cpp:1079: note: initialized from here")
<< OutputParserTester::STDERR
<< QString() << QString::fromLatin1("/home/dev/creator/share/qtcreator/debugger/dumper.cpp:1079: note: initialized from here\n")
- << QList<Task>()
+ << Tasks()
<< QString()
<< QStringList();
QTest::newRow("Full path make exe")
@@ -365,10 +377,10 @@ void ProjectExplorerPlugin::testGnuMakeParserParsing_data()
<< QString::fromLatin1("C:\\Qt\\4.6.2-Symbian\\s60sdk\\epoc32\\tools\\make.exe: *** [sis] Error 2")
<< OutputParserTester::STDERR
<< QString() << QString()
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Error,
QString::fromLatin1("[sis] Error 2"),
- Utils::FileName(), -1,
+ Utils::FilePath(), -1,
Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM)))
<< QString()
<< QStringList();
@@ -377,10 +389,10 @@ void ProjectExplorerPlugin::testGnuMakeParserParsing_data()
<< QString::fromLatin1("make: g++: Command not found")
<< OutputParserTester::STDERR
<< QString() << QString()
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Error,
QString::fromLatin1("g++: Command not found"),
- Utils::FileName(), -1,
+ Utils::FilePath(), -1,
Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM)))
<< QString()
<< QStringList();
@@ -389,10 +401,10 @@ void ProjectExplorerPlugin::testGnuMakeParserParsing_data()
<< QString::fromLatin1("Makefile:794: warning: overriding commands for target `xxxx.app/Contents/Info.plist'")
<< OutputParserTester::STDERR
<< QString() << QString()
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Warning,
QString::fromLatin1("overriding commands for target `xxxx.app/Contents/Info.plist'"),
- Utils::FileName::fromString(QLatin1String("Makefile")), 794,
+ Utils::FilePath::fromString(QLatin1String("Makefile")), 794,
Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM)))
<< QString()
<< QStringList();
@@ -410,7 +422,7 @@ void ProjectExplorerPlugin::testGnuMakeParserParsing()
QFETCH(QStringList, extraSearchDirs);
QFETCH(QString, input);
QFETCH(OutputParserTester::Channel, inputChannel);
- QFETCH(QList<Task>, tasks);
+ QFETCH(Tasks, tasks);
QFETCH(QString, childStdOutLines);
QFETCH(QString, childStdErrLines);
QFETCH(QString, outputLines);
@@ -455,12 +467,12 @@ void ProjectExplorerPlugin::testGnuMakeParserTaskMangling_data()
<< QStringList()
<< Task(Task::Error,
QLatin1String("no filename, no mangling"),
- Utils::FileName(),
+ Utils::FilePath(),
-1,
Constants::TASK_CATEGORY_COMPILE)
<< Task(Task::Error,
QLatin1String("no filename, no mangling"),
- Utils::FileName(),
+ Utils::FilePath(),
-1,
Constants::TASK_CATEGORY_COMPILE);
QTest::newRow("no mangling")
@@ -468,12 +480,12 @@ void ProjectExplorerPlugin::testGnuMakeParserTaskMangling_data()
<< QStringList()
<< Task(Task::Error,
QLatin1String("unknown filename, no mangling"),
- Utils::FileName::fromUserInput(QLatin1String("some/path/unknown.cpp")),
+ Utils::FilePath::fromUserInput(QLatin1String("some/path/unknown.cpp")),
-1,
Constants::TASK_CATEGORY_COMPILE)
<< Task(Task::Error,
QLatin1String("unknown filename, no mangling"),
- Utils::FileName::fromUserInput(QLatin1String("some/path/unknown.cpp")),
+ Utils::FilePath::fromUserInput(QLatin1String("some/path/unknown.cpp")),
-1,
Constants::TASK_CATEGORY_COMPILE);
QTest::newRow("find file")
@@ -481,12 +493,12 @@ void ProjectExplorerPlugin::testGnuMakeParserTaskMangling_data()
<< QStringList("test")
<< Task(Task::Error,
QLatin1String("mangling"),
- Utils::FileName::fromUserInput(QLatin1String("file.cpp")),
+ Utils::FilePath::fromUserInput(QLatin1String("file.cpp")),
10,
Constants::TASK_CATEGORY_COMPILE)
<< Task(Task::Error,
QLatin1String("mangling"),
- Utils::FileName::fromUserInput(QLatin1String("$TMPDIR/test/file.cpp")),
+ Utils::FilePath::fromUserInput(QLatin1String("$TMPDIR/test/file.cpp")),
10,
Constants::TASK_CATEGORY_COMPILE);
}
@@ -529,7 +541,7 @@ void ProjectExplorerPlugin::testGnuMakeParserTaskMangling()
// fix up output task file:
QString filePath = outputTask.file.toString();
if (filePath.startsWith(QLatin1String("$TMPDIR/")))
- outputTask.file = Utils::FileName::fromString(filePath.replace(QLatin1String("$TMPDIR/"), tempdir));
+ outputTask.file = Utils::FilePath::fromString(filePath.replace(QLatin1String("$TMPDIR/"), tempdir));
// test mangling:
testbench.testTaskMangling(inputTask, outputTask);
diff --git a/src/plugins/projectexplorer/images/fileoverlay_py.png b/src/plugins/projectexplorer/images/fileoverlay_py.png
new file mode 100644
index 0000000000..3cda889a4b
--- /dev/null
+++ b/src/plugins/projectexplorer/images/fileoverlay_py.png
Binary files differ
diff --git a/src/plugins/projectexplorer/images/fileoverlay_py@2x.png b/src/plugins/projectexplorer/images/fileoverlay_py@2x.png
new file mode 100644
index 0000000000..071c946456
--- /dev/null
+++ b/src/plugins/projectexplorer/images/fileoverlay_py@2x.png
Binary files differ
diff --git a/src/plugins/projectexplorer/importwidget.cpp b/src/plugins/projectexplorer/importwidget.cpp
index d9bd629179..eac2c44c94 100644
--- a/src/plugins/projectexplorer/importwidget.cpp
+++ b/src/plugins/projectexplorer/importwidget.cpp
@@ -29,6 +29,7 @@
#include <utils/pathchooser.h>
#include <QPushButton>
+#include <QTimer>
#include <QVBoxLayout>
namespace ProjectExplorer {
@@ -60,19 +61,32 @@ ImportWidget::ImportWidget(QWidget *parent) :
layout->addWidget(importButton);
connect(importButton, &QAbstractButton::clicked, this, &ImportWidget::handleImportRequest);
+ connect(m_pathChooser->lineEdit(), &QLineEdit::returnPressed, this, [this] {
+ if (m_pathChooser->isValid()) {
+ handleImportRequest();
+
+ // The next return should trigger the "Configure" button.
+ QTimer::singleShot(0, this, QOverload<>::of(&QWidget::setFocus));
+ }
+ });
detailsWidget->setWidget(widget);
}
-void ImportWidget::setCurrentDirectory(const Utils::FileName &dir)
+void ImportWidget::setCurrentDirectory(const Utils::FilePath &dir)
{
m_pathChooser->setBaseFileName(dir);
m_pathChooser->setFileName(dir);
}
+bool ImportWidget::lineEditHasFocus() const
+{
+ return m_pathChooser->lineEdit()->hasFocus();
+}
+
void ImportWidget::handleImportRequest()
{
- Utils::FileName dir = m_pathChooser->fileName();
+ Utils::FilePath dir = m_pathChooser->fileName();
emit importFrom(dir);
m_pathChooser->setFileName(m_pathChooser->baseFileName());
diff --git a/src/plugins/projectexplorer/importwidget.h b/src/plugins/projectexplorer/importwidget.h
index 9a55f64e1b..8999bc117d 100644
--- a/src/plugins/projectexplorer/importwidget.h
+++ b/src/plugins/projectexplorer/importwidget.h
@@ -29,7 +29,7 @@
namespace Utils {
class PathChooser;
-class FileName;
+class FilePath;
} // namespace Utils
namespace ProjectExplorer {
@@ -42,10 +42,12 @@ class ImportWidget : public QWidget
public:
explicit ImportWidget(QWidget *parent = nullptr);
- void setCurrentDirectory(const Utils::FileName &dir);
+ void setCurrentDirectory(const Utils::FilePath &dir);
+
+ bool lineEditHasFocus() const;
signals:
- void importFrom(const Utils::FileName &dir);
+ void importFrom(const Utils::FilePath &dir);
private:
void handleImportRequest();
diff --git a/src/plugins/projectexplorer/ioutputparser.cpp b/src/plugins/projectexplorer/ioutputparser.cpp
index 0da7005948..8dd6d99264 100644
--- a/src/plugins/projectexplorer/ioutputparser.cpp
+++ b/src/plugins/projectexplorer/ioutputparser.cpp
@@ -207,6 +207,11 @@ void IOutputParser::setWorkingDirectory(const QString &workingDirectory)
m_parser->setWorkingDirectory(workingDirectory);
}
+void IOutputParser::setWorkingDirectory(const Utils::FilePath &fn)
+{
+ setWorkingDirectory(fn.toString());
+}
+
void IOutputParser::flush()
{
doFlush();
diff --git a/src/plugins/projectexplorer/ioutputparser.h b/src/plugins/projectexplorer/ioutputparser.h
index 47c8f4f1c0..1872461cbb 100644
--- a/src/plugins/projectexplorer/ioutputparser.h
+++ b/src/plugins/projectexplorer/ioutputparser.h
@@ -53,6 +53,7 @@ public:
virtual bool hasFatalErrors() const;
virtual void setWorkingDirectory(const QString &workingDirectory);
+ void setWorkingDirectory(const Utils::FilePath &fn);
void flush(); // flush out pending tasks
diff --git a/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp b/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp
index d99f5fe0ec..835f3a0429 100644
--- a/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp
+++ b/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp
@@ -388,6 +388,7 @@ QWidget *LabelField::createWidget(const QString &displayName, JsonFieldPage *pag
auto w = new QLabel;
w->setWordWrap(m_wordWrap);
w->setText(m_text);
+ w->setSizePolicy(QSizePolicy::Expanding, w->sizePolicy().verticalPolicy());
return w;
}
@@ -809,7 +810,7 @@ std::unique_ptr<QStandardItem> createStandardItemFromListItem(const QVariant &it
if (item.type() == QVariant::Map) {
QVariantMap tmp = item.toMap();
const QString key = JsonWizardFactory::localizedString(consumeValue(tmp, "trKey", QString()).toString());
- const QString value = consumeValue(tmp, "value", key).toString();
+ const QVariant value = consumeValue(tmp, "value", key);
if (key.isNull() || key.isEmpty()) {
*errorMessage = QCoreApplication::translate("ProjectExplorer::JsonFieldPage",
@@ -919,7 +920,7 @@ void ListField::initializeData(MacroExpander *expander)
if (item.get() == currentItem)
currentItem = expandedValuesItem;
expandedValuesItem->setText(expander->expand(item->text()));
- expandedValuesItem->setData(expander->expand(item->data(ValueRole).toString()), ValueRole);
+ expandedValuesItem->setData(expander->expandVariant(item->data(ValueRole)), ValueRole);
expandedValuesItem->setData(expander->expand(item->data(IconStringRole).toString()), IconStringRole);
expandedValuesItem->setData(condition, ConditionRole);
@@ -1006,7 +1007,7 @@ void ComboBoxField::setup(JsonFieldPage *page, const QString &name)
// the selectionModel does not behave like expected and wanted - so we block signals here
// (for example there was some losing focus thing when hovering over items, ...)
selectionModel()->blockSignals(true);
- QObject::connect(w, static_cast<void(QComboBox::*)(int)>(&QComboBox::activated), [w, this](int index) {
+ QObject::connect(w, QOverload<int>::of(&QComboBox::activated), [w, this](int index) {
w->blockSignals(true);
selectionModel()->clearSelection();
@@ -1019,8 +1020,8 @@ void ComboBoxField::setup(JsonFieldPage *page, const QString &name)
page->registerObjectAsFieldWithName<QItemSelectionModel>(name, selectionModel(), &QItemSelectionModel::selectionChanged, [this]() {
const QModelIndex i = selectionModel()->currentIndex();
if (i.isValid())
- return i.data(ValueRole).toString();
- return QString();
+ return i.data(ValueRole);
+ return QVariant();
});
QObject::connect(selectionModel(), &QItemSelectionModel::selectionChanged, page, [page]() {
emit page->completeChanged();
@@ -1057,8 +1058,8 @@ void IconListField::setup(JsonFieldPage *page, const QString &name)
page->registerObjectAsFieldWithName<QItemSelectionModel>(name, selectionModel(), &QItemSelectionModel::selectionChanged, [this]() {
const QModelIndex i = selectionModel()->currentIndex();
if (i.isValid())
- return i.data(ValueRole).toString();
- return QString();
+ return i.data(ValueRole);
+ return QVariant();
});
QObject::connect(selectionModel(), &QItemSelectionModel::selectionChanged, page, [page]() {
emit page->completeChanged();
diff --git a/src/plugins/projectexplorer/jsonwizard/jsonkitspage.cpp b/src/plugins/projectexplorer/jsonwizard/jsonkitspage.cpp
index 5faa5c3642..7501521be7 100644
--- a/src/plugins/projectexplorer/jsonwizard/jsonkitspage.cpp
+++ b/src/plugins/projectexplorer/jsonwizard/jsonkitspage.cpp
@@ -107,7 +107,7 @@ void JsonKitsPage::setupProjectFiles(const JsonWizard::GeneratorFiles &files)
const QFileInfo fi(f.file.path());
const QString path = fi.absoluteFilePath();
Project *project = ProjectManager::openProject(Utils::mimeTypeForFile(fi),
- Utils::FileName::fromString(path));
+ Utils::FilePath::fromString(path));
if (project) {
if (setupProject(project))
project->saveSettings();
diff --git a/src/plugins/projectexplorer/jsonwizard/jsonprojectpage.cpp b/src/plugins/projectexplorer/jsonwizard/jsonprojectpage.cpp
index 45f332a2de..fcddd7ffd8 100644
--- a/src/plugins/projectexplorer/jsonwizard/jsonprojectpage.cpp
+++ b/src/plugins/projectexplorer/jsonwizard/jsonprojectpage.cpp
@@ -52,7 +52,7 @@ bool JsonProjectPage::validatePage()
{
if (isComplete() && useAsDefaultPath()) {
// Store the path as default path for new projects if desired.
- Core::DocumentManager::setProjectsDirectory(Utils::FileName::fromString(path()));
+ Core::DocumentManager::setProjectsDirectory(Utils::FilePath::fromString(path()));
Core::DocumentManager::setUseProjectsDirectory(true);
}
diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp
index a3bad8656f..7684de0795 100644
--- a/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp
+++ b/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp
@@ -36,11 +36,20 @@
#include <coreplugin/messagemanager.h>
#include <utils/algorithm.h>
+#include <utils/itemviews.h>
#include <utils/qtcassert.h>
+#include <utils/treemodel.h>
#include <utils/wizardpage.h>
+#include <QDialog>
+#include <QDialogButtonBox>
+#include <QDir>
#include <QFileInfo>
+#include <QJSEngine>
+#include <QLabel>
#include <QMessageBox>
+#include <QPushButton>
+#include <QVBoxLayout>
#include <QVariant>
#ifdef WITH_TESTS
@@ -49,7 +58,94 @@
namespace ProjectExplorer {
-JsonWizard::JsonWizard(QWidget *parent) : Utils::Wizard(parent)
+namespace Internal {
+
+class ProjectFileTreeItem : public Utils::TreeItem
+{
+public:
+ ProjectFileTreeItem(JsonWizard::GeneratorFile *candidate) : m_candidate(candidate)
+ {
+ toggleProjectFileStatus(false);
+ }
+
+ void toggleProjectFileStatus(bool on)
+ {
+ m_candidate->file.setAttributes(m_candidate->file.attributes()
+ .setFlag(Core::GeneratedFile::OpenProjectAttribute, on));
+ }
+
+private:
+ QVariant data(int column, int role) const override
+ {
+ if (column != 0 || role != Qt::DisplayRole)
+ return QVariant();
+ return QDir::toNativeSeparators(m_candidate->file.path());
+ }
+
+ JsonWizard::GeneratorFile * const m_candidate;
+};
+
+class ProjectFilesModel : public Utils::TreeModel<Utils::TreeItem, ProjectFileTreeItem>
+{
+public:
+ ProjectFilesModel(const QList<JsonWizard::GeneratorFile *> &candidates, QObject *parent)
+ : TreeModel(parent)
+ {
+ setHeader({QCoreApplication::translate("ProjectExplorer::JsonWizard", "Project File")});
+ for (JsonWizard::GeneratorFile * const candidate : candidates)
+ rootItem()->appendChild(new ProjectFileTreeItem(candidate));
+ }
+};
+
+class ProjectFileChooser : public QDialog
+{
+public:
+ ProjectFileChooser(const QList<JsonWizard::GeneratorFile *> &candidates, QWidget *parent)
+ : QDialog(parent), m_view(new Utils::TreeView(this))
+ {
+ setWindowTitle(QCoreApplication::translate("ProjectExplorer::JsonWizard",
+ "Choose Project File"));
+ const auto model = new ProjectFilesModel(candidates, this);
+ m_view->setSelectionMode(Utils::TreeView::ExtendedSelection);
+ m_view->setSelectionBehavior(Utils::TreeView::SelectRows);
+ m_view->setModel(model);
+ const auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok);
+ const auto updateOkButton = [buttonBox, this] {
+ buttonBox->button(QDialogButtonBox::Ok)
+ ->setEnabled(m_view->selectionModel()->hasSelection());
+ };
+ connect(m_view->selectionModel(), &QItemSelectionModel::selectionChanged,
+ this, updateOkButton);
+ updateOkButton();
+ connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
+ const auto layout = new QVBoxLayout(this);
+ layout->addWidget(new QLabel(QCoreApplication::translate("ProjectExplorer::JsonWizard",
+ "The project contains more than one project file. "
+ "Select the one you would like to use.")));
+ layout->addWidget(m_view);
+ layout->addWidget(buttonBox);
+ }
+
+private:
+ void accept() override
+ {
+ const QModelIndexList selected = m_view->selectionModel()->selectedRows();
+ const auto * const model = static_cast<ProjectFilesModel *>(m_view->model());
+ for (const QModelIndex &index : selected) {
+ const auto item = static_cast<ProjectFileTreeItem *>(model->itemForIndex(index));
+ QTC_ASSERT(item, continue);
+ item->toggleProjectFileStatus(true);
+ }
+ QDialog::accept();
+ }
+
+ Utils::TreeView * const m_view;
+};
+
+} // namespace Internal
+
+JsonWizard::JsonWizard(QWidget *parent)
+ : Utils::Wizard(parent)
{
setMinimumSize(800, 500);
m_expander.registerExtraResolver([this](const QString &name, QString *ret) -> bool {
@@ -63,7 +159,10 @@ JsonWizard::JsonWizard(QWidget *parent) : Utils::Wizard(parent)
const QString key = QString::fromLatin1("%{") + value + QLatin1Char('}');
return m_expander.expand(key) == key ? QString() : QLatin1String("true");
});
-
+ // override default JS macro by custom one that adds Wizard specific features
+ m_jsExpander.registerObject("Wizard", new Internal::JsonWizardJsExtension(this));
+ m_jsExpander.engine().evaluate("var value = Wizard.value");
+ m_jsExpander.registerForExpander(&m_expander);
}
JsonWizard::~JsonWizard()
@@ -113,6 +212,14 @@ JsonWizard::GeneratorFiles JsonWizard::generateFileList()
return GeneratorFiles();
}
+ QList<GeneratorFile *> projectFiles;
+ for (JsonWizard::GeneratorFile &f : list) {
+ if (f.file.attributes().testFlag(Core::GeneratedFile::OpenProjectAttribute))
+ projectFiles << &f;
+ }
+ if (projectFiles.count() > 1)
+ Internal::ProjectFileChooser(projectFiles, this).exec();
+
return list;
}
@@ -392,11 +499,16 @@ void JsonWizard::openProjectForNode(Node *node)
{
using namespace Utils;
- ProjectNode *projNode = node->asProjectNode() ? node->asProjectNode() : node->parentProjectNode();
-
+ const ProjectNode *projNode = node->asProjectNode();
+ if (!projNode) {
+ if (ContainerNode * const cn = node->asContainerNode())
+ projNode = cn->rootProjectNode();
+ else
+ projNode = node->parentProjectNode();
+ }
QTC_ASSERT(projNode, return);
- Utils::optional<FileName> projFilePath = projNode->visibleAfterAddFileAction();
+ Utils::optional<FilePath> projFilePath = projNode->visibleAfterAddFileAction();
if (projFilePath && !Core::EditorManager::openEditor(projFilePath.value().toString())) {
auto errorMessage = QCoreApplication::translate("ProjectExplorer::JsonWizard",
@@ -418,4 +530,17 @@ bool JsonWizard::OptionDefinition::condition(Utils::MacroExpander &expander) con
return JsonWizard::boolFromVariant(m_condition, &expander);
}
+namespace Internal {
+
+JsonWizardJsExtension::JsonWizardJsExtension(JsonWizard *wizard)
+ : m_wizard(wizard)
+{}
+
+QVariant JsonWizardJsExtension::value(const QString &name) const
+{
+ const QVariant value = m_wizard->value(name);
+ return m_wizard->expander()->expandVariant(m_wizard->value(name));
+}
+
+} // namespace Internal
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizard.h b/src/plugins/projectexplorer/jsonwizard/jsonwizard.h
index 1f8aca7741..99a9ce4952 100644
--- a/src/plugins/projectexplorer/jsonwizard/jsonwizard.h
+++ b/src/plugins/projectexplorer/jsonwizard/jsonwizard.h
@@ -29,6 +29,7 @@
#include <projectexplorer/projectnodes.h>
#include <coreplugin/generatedfile.h>
+#include <coreplugin/jsexpander.h>
#include <utils/wizard.h>
#include <utils/macroexpander.h>
@@ -37,8 +38,25 @@
namespace ProjectExplorer {
+class JsonWizard;
class JsonWizardGenerator;
+namespace Internal {
+
+class JsonWizardJsExtension : public QObject
+{
+ Q_OBJECT
+public:
+ JsonWizardJsExtension(JsonWizard *wizard);
+
+ Q_INVOKABLE QVariant value(const QString &name) const;
+
+private:
+ JsonWizard *m_wizard;
+};
+
+} // namespace Internal
+
// Documentation inside.
class PROJECTEXPLORER_EXPORT JsonWizard : public Utils::Wizard
{
@@ -126,6 +144,7 @@ private:
GeneratorFiles m_files;
Utils::MacroExpander m_expander;
+ Core::JsExpander m_jsExpander;
};
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp
index 3a01d9e045..530ace9ca7 100644
--- a/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp
+++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp
@@ -34,6 +34,7 @@
#include <coreplugin/coreconstants.h>
#include <coreplugin/icontext.h>
#include <coreplugin/icore.h>
+#include <coreplugin/jsexpander.h>
#include <coreplugin/messagemanager.h>
#include <extensionsystem/pluginmanager.h>
@@ -46,10 +47,11 @@
#include <QDebug>
#include <QDir>
-#include <QMap>
+#include <QJSEngine>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonParseError>
+#include <QMap>
#include <QUuid>
namespace ProjectExplorer {
@@ -209,7 +211,7 @@ QList<Core::IWizardFactory *> JsonWizardFactory::createWizardFactories()
const QString wizardFileName = QLatin1String(WIZARD_FILE);
QList <Core::IWizardFactory *> result;
- foreach (const Utils::FileName &path, searchPaths()) {
+ foreach (const Utils::FilePath &path, searchPaths()) {
if (path.isEmpty())
continue;
@@ -223,7 +225,7 @@ QList<Core::IWizardFactory *> JsonWizardFactory::createWizardFactories()
const QDir::Filters filters = QDir::Dirs|QDir::Readable|QDir::NoDotAndDotDot;
const QDir::SortFlags sortflags = QDir::Name|QDir::IgnoreCase;
- QList<QFileInfo> dirs = dir.entryInfoList(filters, sortflags);
+ QFileInfoList dirs = dir.entryInfoList(filters, sortflags);
while (!dirs.isEmpty()) {
const QFileInfo dirFi = dirs.takeFirst();
@@ -283,7 +285,7 @@ QList<Core::IWizardFactory *> JsonWizardFactory::createWizardFactories()
result << factory;
} else {
- QList<QFileInfo> subDirs = current.entryInfoList(filters, sortflags);
+ QFileInfoList subDirs = current.entryInfoList(filters, sortflags);
if (!subDirs.isEmpty()) {
// There is no QList::prepend(QList)...
dirs.swap(subDirs);
@@ -332,20 +334,20 @@ static QStringList environmentTemplatesPaths()
return paths;
}
-Utils::FileNameList &JsonWizardFactory::searchPaths()
+Utils::FilePathList &JsonWizardFactory::searchPaths()
{
- static Utils::FileNameList m_searchPaths = Utils::FileNameList()
- << Utils::FileName::fromString(Core::ICore::userResourcePath() + QLatin1Char('/') +
+ static Utils::FilePathList m_searchPaths = Utils::FilePathList()
+ << Utils::FilePath::fromString(Core::ICore::userResourcePath() + QLatin1Char('/') +
QLatin1String(WIZARD_PATH))
- << Utils::FileName::fromString(Core::ICore::resourcePath() + QLatin1Char('/') +
+ << Utils::FilePath::fromString(Core::ICore::resourcePath() + QLatin1Char('/') +
QLatin1String(WIZARD_PATH));
for (const QString &environmentTemplateDirName : environmentTemplatesPaths())
- m_searchPaths << Utils::FileName::fromString(environmentTemplateDirName);
+ m_searchPaths << Utils::FilePath::fromString(environmentTemplateDirName);
return m_searchPaths;
}
-void JsonWizardFactory::addWizardPath(const Utils::FileName &path)
+void JsonWizardFactory::addWizardPath(const Utils::FilePath &path)
{
searchPaths().append(path);
}
@@ -513,9 +515,17 @@ bool JsonWizardFactory::isAvailable(Core::Id platformId) const
[platformId]() { return platformId.toString(); });
expander.registerVariable("Features", tr("The features available to this wizard."),
[this, e, platformId]() { return JsonWizard::stringListToArrayString(Core::Id::toStringList(availableFeatures(platformId)), e); });
- expander.registerVariable("Plugins", tr("The plugins loaded."),
- [this, e]() { return JsonWizard::stringListToArrayString(Core::Id::toStringList(pluginFeatures()), e); });
-
+ expander.registerVariable("Plugins", tr("The plugins loaded."), [this, e]() {
+ return JsonWizard::stringListToArrayString(Core::Id::toStringList(pluginFeatures()), e);
+ });
+ Core::JsExpander jsExpander;
+ jsExpander.registerObject("Wizard",
+ new Internal::JsonWizardFactoryJsExtension(platformId,
+ availableFeatures(
+ platformId),
+ pluginFeatures()));
+ jsExpander.engine().evaluate("var value = Wizard.value");
+ jsExpander.registerForExpander(e);
return JsonWizard::boolFromVariant(m_enabledExpression, &expander);
}
@@ -660,4 +670,26 @@ bool JsonWizardFactory::initialize(const QVariantMap &data, const QDir &baseDir,
return errorMessage->isEmpty();
}
+namespace Internal {
+
+JsonWizardFactoryJsExtension::JsonWizardFactoryJsExtension(Core::Id platformId,
+ const QSet<Core::Id> &availableFeatures,
+ const QSet<Core::Id> &pluginFeatures)
+ : m_platformId(platformId)
+ , m_availableFeatures(availableFeatures)
+ , m_pluginFeatures(pluginFeatures)
+{}
+
+QVariant JsonWizardFactoryJsExtension::value(const QString &name) const
+{
+ if (name == "Platform")
+ return m_platformId.toString();
+ if (name == "Features")
+ return Core::Id::toStringList(m_availableFeatures);
+ if (name == "Plugins")
+ return Core::Id::toStringList(m_pluginFeatures);
+ return QVariant();
+}
+
+} // namespace Internal
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.h b/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.h
index ead93f4841..5573bb2979 100644
--- a/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.h
+++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.h
@@ -55,7 +55,7 @@ class PROJECTEXPLORER_EXPORT JsonWizardFactory : public Core::IWizardFactory
public:
// Add search paths for wizard.json files. All subdirs are going to be checked.
- static void addWizardPath(const Utils::FileName &path);
+ static void addWizardPath(const Utils::FilePath &path);
// actual interface of the wizard factory:
class Generator {
@@ -96,7 +96,7 @@ private:
static QList<IWizardFactory *> createWizardFactories();
static JsonWizardFactory *createWizardFactory(const QVariantMap &data, const QDir &baseDir,
QString *errorMessage);
- static Utils::FileNameList &searchPaths();
+ static Utils::FilePathList &searchPaths();
static void setVerbose(int level);
static int verbose();
@@ -119,4 +119,23 @@ private:
friend class ProjectExplorerPluginPrivate;
};
-} //namespace ProjectExplorer
+namespace Internal {
+
+class JsonWizardFactoryJsExtension : public QObject
+{
+ Q_OBJECT
+public:
+ JsonWizardFactoryJsExtension(Core::Id platformId,
+ const QSet<Core::Id> &availableFeatures,
+ const QSet<Core::Id> &pluginFeatures);
+
+ Q_INVOKABLE QVariant value(const QString &name) const;
+
+private:
+ Core::Id m_platformId;
+ QSet<Core::Id> m_availableFeatures;
+ QSet<Core::Id> m_pluginFeatures;
+};
+
+} // namespace Internal
+} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardfilegenerator.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizardfilegenerator.cpp
index ee7da5b419..a168fea084 100644
--- a/src/plugins/projectexplorer/jsonwizard/jsonwizardfilegenerator.cpp
+++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardfilegenerator.cpp
@@ -127,7 +127,9 @@ Core::GeneratedFile JsonWizardFileGenerator::generateFile(const File &file,
*ret = options.value(n);
return true;
});
- nested.registerExtraResolver([expander](QString n, QString *ret) { return expander->resolveMacro(n, ret); });
+ nested.registerExtraResolver([expander](QString n, QString *ret) {
+ return expander->resolveMacro(n, ret);
+ });
gf.setContents(Utils::TemplateEngine::processText(&nested, QString::fromUtf8(reader.data()),
errorMessage));
diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardgeneratorfactory.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizardgeneratorfactory.cpp
index e0a06c824e..cf84f8b5e4 100644
--- a/src/plugins/projectexplorer/jsonwizard/jsonwizardgeneratorfactory.cpp
+++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardgeneratorfactory.cpp
@@ -98,7 +98,7 @@ bool JsonWizardGenerator::formatFile(const JsonWizard *wizard, GeneratedFile *fi
Indenter *indenter = nullptr;
if (factory) {
indenter = factory->createIndenter(&doc);
- indenter->setFileName(Utils::FileName::fromString(file->path()));
+ indenter->setFileName(Utils::FilePath::fromString(file->path()));
}
if (!indenter)
indenter = new NormalIndenter(&doc);
diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardscannergenerator.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizardscannergenerator.cpp
index 08d3ed1f88..9f24f00718 100644
--- a/src/plugins/projectexplorer/jsonwizard/jsonwizardscannergenerator.cpp
+++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardscannergenerator.cpp
@@ -42,6 +42,8 @@
#include <QDir>
#include <QVariant>
+#include <limits>
+
namespace ProjectExplorer {
namespace Internal {
@@ -70,8 +72,6 @@ bool JsonWizardScannerGenerator::setup(const QVariant &data, QString *errorMessa
m_subDirectoryExpressions << regexp;
}
- m_firstProjectOnly = gen.value(QLatin1String("firstProjectOnly"), QLatin1String("true")).toString();
-
return true;
}
@@ -97,17 +97,28 @@ Core::GeneratedFiles JsonWizardScannerGenerator::fileList(Utils::MacroExpander *
}
}
- bool onlyFirst = JsonWizard::boolFromVariant(m_firstProjectOnly, expander);
-
result = scan(project.absolutePath(), project);
- int projectCount = 0;
+ static const auto getDepth = [](const QString &filePath) { return filePath.count('/'); };
+ int minDepth = std::numeric_limits<int>::max();
for (auto it = result.begin(); it != result.end(); ++it) {
const QString relPath = project.relativeFilePath(it->path());
it->setBinary(binaryPattern.match(relPath).hasMatch());
bool found = ProjectManager::canOpenProjectForMimeType(Utils::mimeTypeForFile(relPath));
- if (found && !(onlyFirst && projectCount++))
+ if (found) {
it->setAttributes(it->attributes() | Core::GeneratedFile::OpenProjectAttribute);
+ minDepth = std::min(minDepth, getDepth(it->path()));
+ }
+ }
+
+ // Project files that appear on a lower level in the file system hierarchy than
+ // other project files are not candidates for opening.
+ for (Core::GeneratedFile &f : result) {
+ if (f.attributes().testFlag(Core::GeneratedFile::OpenProjectAttribute)
+ && getDepth(f.path()) > minDepth) {
+ f.setAttributes(f.attributes().setFlag(Core::GeneratedFile::OpenProjectAttribute,
+ false));
+ }
}
return result;
@@ -130,7 +141,7 @@ Core::GeneratedFiles JsonWizardScannerGenerator::scan(const QString &dir, const
if (!directory.exists())
return result;
- QList<QFileInfo> entries = directory.entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot,
+ QFileInfoList entries = directory.entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot,
QDir::DirsLast | QDir::Name);
foreach (const QFileInfo &fi, entries) {
const QString relativePath = base.relativeFilePath(fi.absoluteFilePath());
diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardscannergenerator.h b/src/plugins/projectexplorer/jsonwizard/jsonwizardscannergenerator.h
index e852ad1fe0..76475d4f97 100644
--- a/src/plugins/projectexplorer/jsonwizard/jsonwizardscannergenerator.h
+++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardscannergenerator.h
@@ -43,13 +43,11 @@ public:
Core::GeneratedFiles fileList(Utils::MacroExpander *expander,
const QString &wizardDir, const QString &projectDir,
QString *errorMessage) override;
-
private:
Core::GeneratedFiles scan(const QString &dir, const QDir &base);
bool matchesSubdirectoryPattern(const QString &path);
QString m_binaryPattern;
- QString m_firstProjectOnly;
QList<QRegularExpression> m_subDirectoryExpressions;
};
diff --git a/src/plugins/projectexplorer/kit.cpp b/src/plugins/projectexplorer/kit.cpp
index 5376f0c766..88e2e65ada 100644
--- a/src/plugins/projectexplorer/kit.cpp
+++ b/src/plugins/projectexplorer/kit.cpp
@@ -36,7 +36,10 @@
#include <utils/fileutils.h>
#include <utils/icon.h>
#include <utils/macroexpander.h>
+#include <utils/optional.h>
#include <utils/qtcassert.h>
+#include <utils/stringutils.h>
+#include <utils/utilsicons.h>
#include <QApplication>
#include <QFileInfo>
@@ -45,6 +48,8 @@
#include <QTextStream>
#include <QUuid>
+#include <numeric>
+
using namespace Core;
using namespace Utils;
@@ -56,8 +61,10 @@ const char AUTODETECTIONSOURCE_KEY[] = "PE.Profile.AutoDetectionSource";
const char SDK_PROVIDED_KEY[] = "PE.Profile.SDK";
const char DATA_KEY[] = "PE.Profile.Data";
const char ICON_KEY[] = "PE.Profile.Icon";
+const char DEVICE_TYPE_FOR_ICON_KEY[] = "PE.Profile.DeviceTypeForIcon";
const char MUTABLE_INFO_KEY[] = "PE.Profile.MutableInfo";
const char STICKY_INFO_KEY[] = "PE.Profile.StickyInfo";
+const char IRRELEVANT_ASPECTS_KEY[] = "PE.Kit.IrrelevantAspects";
namespace ProjectExplorer {
namespace Internal {
@@ -86,8 +93,8 @@ public:
[kit] { return kit->id().toString(); });
m_macroExpander.registerVariable("Kit:FileSystemName", tr("Kit filesystem-friendly name"),
[kit] { return kit->fileSystemFriendlyName(); });
- foreach (KitInformation *ki, KitManager::kitInformation())
- ki->addToMacroExpander(kit, &m_macroExpander);
+ for (KitAspect *aspect : KitManager::kitAspects())
+ aspect->addToMacroExpander(kit, &m_macroExpander);
// This provides the same global fall back as the global expander
// without relying on the currentKit() discovery process there.
@@ -117,11 +124,13 @@ public:
bool m_hasValidityInfo = false;
bool m_mustNotify = false;
QIcon m_cachedIcon;
- FileName m_iconPath;
+ FilePath m_iconPath;
+ Id m_deviceTypeForIcon;
QHash<Id, QVariant> m_data;
QSet<Id> m_sticky;
QSet<Id> m_mutable;
+ optional<QSet<Id>> m_irrelevantAspects;
MacroExpander m_macroExpander;
};
@@ -134,8 +143,6 @@ public:
Kit::Kit(Id id) :
d(std::make_unique<Internal::KitPrivate>(id, this))
{
- foreach (KitInformation *sti, KitManager::kitInformation())
- d->m_data.insert(sti->id(), sti->defaultValue(this));
}
Kit::Kit(const QVariantMap &data) :
@@ -156,8 +163,12 @@ Kit::Kit(const QVariantMap &data) :
d->m_unexpandedDisplayName = data.value(QLatin1String(DISPLAYNAME_KEY),
d->m_unexpandedDisplayName).toString();
d->m_fileSystemFriendlyName = data.value(QLatin1String(FILESYSTEMFRIENDLYNAME_KEY)).toString();
- d->m_iconPath = FileName::fromString(data.value(QLatin1String(ICON_KEY),
+ d->m_iconPath = FilePath::fromString(data.value(QLatin1String(ICON_KEY),
d->m_iconPath.toString()).toString());
+ d->m_deviceTypeForIcon = Id::fromSetting(data.value(DEVICE_TYPE_FOR_ICON_KEY));
+ const auto it = data.constFind(IRRELEVANT_ASPECTS_KEY);
+ if (it != data.constEnd())
+ d->m_irrelevantAspects = transform<QSet<Id>>(it.value().toList(), &Id::fromSetting);
QVariantMap extra = data.value(QLatin1String(DATA_KEY)).toMap();
d->m_data.clear(); // remove default values
@@ -190,38 +201,40 @@ void Kit::unblockNotification()
kitUpdated();
}
+void Kit::copyKitCommon(Kit *target, const Kit *source)
+{
+ target->d->m_data = source->d->m_data;
+ target->d->m_iconPath = source->d->m_iconPath;
+ target->d->m_deviceTypeForIcon = source->d->m_deviceTypeForIcon;
+ target->d->m_cachedIcon = source->d->m_cachedIcon;
+ target->d->m_sticky = source->d->m_sticky;
+ target->d->m_mutable = source->d->m_mutable;
+ target->d->m_irrelevantAspects = source->d->m_irrelevantAspects;
+}
+
Kit *Kit::clone(bool keepName) const
{
auto k = new Kit;
+ copyKitCommon(k, this);
if (keepName)
k->d->m_unexpandedDisplayName = d->m_unexpandedDisplayName;
else
- k->d->m_unexpandedDisplayName = QCoreApplication::translate("ProjectExplorer::Kit", "Clone of %1")
- .arg(d->m_unexpandedDisplayName);
+ k->d->m_unexpandedDisplayName = newKitName(KitManager::kits());
k->d->m_autodetected = false;
- k->d->m_data = d->m_data;
// Do not clone m_fileSystemFriendlyName, needs to be unique
- k->d->m_hasError = d->m_hasError;
- k->d->m_cachedIcon = d->m_cachedIcon;
- k->d->m_iconPath = d->m_iconPath;
- k->d->m_sticky = d->m_sticky;
- k->d->m_mutable = d->m_mutable;
+ k->d->m_hasError = d->m_hasError; // TODO: Is this intentionally not done for copyFrom()?
return k;
}
void Kit::copyFrom(const Kit *k)
{
KitGuard g(this);
- d->m_data = k->d->m_data;
- d->m_iconPath = k->d->m_iconPath;
- d->m_cachedIcon = k->d->m_cachedIcon;
+ copyKitCommon(this, k);
d->m_autodetected = k->d->m_autodetected;
d->m_autoDetectionSource = k->d->m_autoDetectionSource;
d->m_unexpandedDisplayName = k->d->m_unexpandedDisplayName;
d->m_fileSystemFriendlyName = k->d->m_fileSystemFriendlyName;
d->m_mustNotify = true;
- d->m_sticky = k->d->m_sticky;
- d->m_mutable = k->d->m_mutable;
}
bool Kit::isValid() const
@@ -243,14 +256,12 @@ bool Kit::hasWarning() const
return d->m_hasWarning;
}
-QList<Task> Kit::validate() const
+Tasks Kit::validate() const
{
- QList<Task> result;
- QList<KitInformation *> infoList = KitManager::kitInformation();
- for (KitInformation *i : infoList) {
- QList<Task> tmp = i->validate(this);
- result.append(tmp);
- }
+ Tasks result;
+ for (KitAspect *aspect : KitManager::kitAspects())
+ result.append(aspect->validate(this));
+
d->m_hasError = containsType(result, Task::TaskType::Error);
d->m_hasWarning = containsType(result, Task::TaskType::Warning);
@@ -262,25 +273,25 @@ QList<Task> Kit::validate() const
void Kit::fix()
{
KitGuard g(this);
- foreach (KitInformation *i, KitManager::kitInformation())
- i->fix(this);
+ for (KitAspect *aspect : KitManager::kitAspects())
+ aspect->fix(this);
}
void Kit::setup()
{
KitGuard g(this);
- const QList<KitInformation *> info = KitManager::kitInformation();
- for (KitInformation * const ki : info)
- ki->setup(this);
+ const QList<KitAspect *> aspects = KitManager::kitAspects();
+ for (KitAspect * const aspect : aspects)
+ aspect->setup(this);
}
void Kit::upgrade()
{
KitGuard g(this);
- // Process the KitInfos in reverse order: They may only be based on other information lower in
- // the stack.
- for (KitInformation *ki : KitManager::kitInformation())
- ki->upgrade(this);
+ // Process the KitAspects in reverse order: They may only be based on other information
+ // lower in the stack.
+ for (KitAspect *aspect : KitManager::kitAspects())
+ aspect->upgrade(this);
}
QString Kit::unexpandedDisplayName() const
@@ -350,6 +361,15 @@ Id Kit::id() const
return d->m_id;
}
+int Kit::weight() const
+{
+ const QList<KitAspect *> &aspects = KitManager::kitAspects();
+ return std::accumulate(aspects.begin(), aspects.end(), 0,
+ [this](int sum, const KitAspect *aspect) {
+ return sum + aspect->weight(this);
+ });
+}
+
static QIcon iconForDeviceType(Core::Id deviceType)
{
const IDeviceFactory *factory = Utils::findOrDefault(IDeviceFactory::allDeviceFactories(),
@@ -364,12 +384,13 @@ QIcon Kit::icon() const
if (!d->m_cachedIcon.isNull())
return d->m_cachedIcon;
- if (!d->m_iconPath.isEmpty() && d->m_iconPath.exists()) {
+ if (!d->m_deviceTypeForIcon.isValid() && !d->m_iconPath.isEmpty() && d->m_iconPath.exists()) {
d->m_cachedIcon = QIcon(d->m_iconPath.toString());
return d->m_cachedIcon;
}
- const Core::Id deviceType = DeviceTypeKitInformation::deviceTypeId(this);
+ const Core::Id deviceType = d->m_deviceTypeForIcon.isValid()
+ ? d->m_deviceTypeForIcon : DeviceTypeKitAspect::deviceTypeId(this);
const QIcon deviceTypeIcon = iconForDeviceType(deviceType);
if (!deviceTypeIcon.isNull()) {
d->m_cachedIcon = deviceTypeIcon;
@@ -380,19 +401,43 @@ QIcon Kit::icon() const
return d->m_cachedIcon;
}
-FileName Kit::iconPath() const
+QIcon Kit::displayIcon() const
+{
+ QIcon result = icon();
+ if (hasWarning()) {
+ static const QIcon warningIcon(Utils::Icons::WARNING.icon());
+ result = warningIcon;
+ }
+ if (!isValid()) {
+ static const QIcon errorIcon(Utils::Icons::CRITICAL.icon());
+ result = errorIcon;
+ }
+ return result;
+}
+
+FilePath Kit::iconPath() const
{
return d->m_iconPath;
}
-void Kit::setIconPath(const FileName &path)
+void Kit::setIconPath(const FilePath &path)
{
if (d->m_iconPath == path)
return;
+ d->m_deviceTypeForIcon = Id();
d->m_iconPath = path;
kitUpdated();
}
+void Kit::setDeviceTypeForIcon(Id deviceType)
+{
+ if (d->m_deviceTypeForIcon == deviceType)
+ return;
+ d->m_iconPath.clear();
+ d->m_deviceTypeForIcon = deviceType;
+ kitUpdated();
+}
+
QList<Id> Kit::allKeys() const
{
return d->m_data.keys();
@@ -459,10 +504,11 @@ bool Kit::isEqual(const Kit *other) const
{
return isDataEqual(other)
&& d->m_iconPath == other->d->m_iconPath
+ && d->m_deviceTypeForIcon == other->d->m_deviceTypeForIcon
&& d->m_unexpandedDisplayName == other->d->m_unexpandedDisplayName
&& d->m_fileSystemFriendlyName == other->d->m_fileSystemFriendlyName
+ && d->m_irrelevantAspects == other->d->m_irrelevantAspects
&& d->m_mutable == other->d->m_mutable;
-
}
QVariantMap Kit::toMap() const
@@ -478,6 +524,7 @@ QVariantMap Kit::toMap() const
data.insert(QLatin1String(AUTODETECTIONSOURCE_KEY), d->m_autoDetectionSource);
data.insert(QLatin1String(SDK_PROVIDED_KEY), d->m_sdkProvided);
data.insert(QLatin1String(ICON_KEY), d->m_iconPath.toString());
+ data.insert(DEVICE_TYPE_FOR_ICON_KEY, d->m_deviceTypeForIcon.toSetting());
QStringList mutableInfo;
foreach (Id id, d->m_mutable)
@@ -489,6 +536,11 @@ QVariantMap Kit::toMap() const
stickyInfo << id.toString();
data.insert(QLatin1String(STICKY_INFO_KEY), stickyInfo);
+ if (d->m_irrelevantAspects) {
+ data.insert(IRRELEVANT_ASPECTS_KEY, transform<QVariantList>(d->m_irrelevantAspects.value(),
+ &Id::toSetting));
+ }
+
QVariantMap extra;
const IdVariantConstIt cend = d->m_data.constEnd();
@@ -501,21 +553,19 @@ QVariantMap Kit::toMap() const
void Kit::addToEnvironment(Environment &env) const
{
- QList<KitInformation *> infoList = KitManager::kitInformation();
- foreach (KitInformation *ki, infoList)
- ki->addToEnvironment(this, env);
+ for (KitAspect *aspect : KitManager::kitAspects())
+ aspect->addToEnvironment(this, env);
}
IOutputParser *Kit::createOutputParser() const
{
auto first = new OsParser;
- QList<KitInformation *> infoList = KitManager::kitInformation();
- foreach (KitInformation *ki, infoList)
- first->appendOutputParser(ki->createOutputParser(this));
+ for (KitAspect *aspect : KitManager::kitAspects())
+ first->appendOutputParser(aspect->createOutputParser(this));
return first;
}
-QString Kit::toHtml(const QList<Task> &additional) const
+QString Kit::toHtml(const Tasks &additional) const
{
QString result;
QTextStream str(&result);
@@ -526,10 +576,9 @@ QString Kit::toHtml(const QList<Task> &additional) const
str << "<p>" << ProjectExplorer::toHtml(additional + validate()) << "</p>";
str << "<table>";
- QList<KitInformation *> infoList = KitManager::kitInformation();
- foreach (KitInformation *ki, infoList) {
- KitInformation::ItemList list = ki->toUserOutput(this);
- foreach (const KitInformation::Item &j, list) {
+ for (KitAspect *aspect : KitManager::kitAspects()) {
+ const KitAspect::ItemList list = aspect->toUserOutput(this);
+ for (const KitAspect::Item &j : list) {
QString contents = j.second;
if (contents.count() > 256) {
int pos = contents.lastIndexOf("<br>", 256);
@@ -571,9 +620,9 @@ void Kit::setSdkProvided(bool sdkProvided)
void Kit::makeSticky()
{
- foreach (KitInformation *ki, KitManager::kitInformation()) {
- if (hasValue(ki->id()))
- setSticky(ki->id(), true);
+ for (KitAspect *aspect : KitManager::kitAspects()) {
+ if (hasValue(aspect->id()))
+ setSticky(aspect->id(), true);
}
}
@@ -614,11 +663,21 @@ bool Kit::isMutable(Id id) const
return d->m_mutable.contains(id);
}
+void Kit::setIrrelevantAspects(const QSet<Id> &irrelevant)
+{
+ d->m_irrelevantAspects = irrelevant;
+}
+
+QSet<Id> Kit::irrelevantAspects() const
+{
+ return d->m_irrelevantAspects.value_or(KitManager::irrelevantAspects());
+}
+
QSet<Id> Kit::supportedPlatforms() const
{
QSet<Id> platforms;
- foreach (const KitInformation *ki, KitManager::kitInformation()) {
- const QSet<Id> ip = ki->supportedPlatforms(this);
+ for (const KitAspect *aspect : KitManager::kitAspects()) {
+ const QSet<Id> ip = aspect->supportedPlatforms(this);
if (ip.isEmpty())
continue;
if (platforms.isEmpty())
@@ -632,8 +691,8 @@ QSet<Id> Kit::supportedPlatforms() const
QSet<Id> Kit::availableFeatures() const
{
QSet<Id> features;
- foreach (const KitInformation *ki, KitManager::kitInformation())
- features |= ki->availableFeatures(this);
+ for (const KitAspect *aspect : KitManager::kitAspects())
+ features |= aspect->availableFeatures(this);
return features;
}
@@ -647,6 +706,19 @@ MacroExpander *Kit::macroExpander() const
return &d->m_macroExpander;
}
+QString Kit::newKitName(const QList<Kit *> &allKits) const
+{
+ return newKitName(unexpandedDisplayName(), allKits);
+}
+
+QString Kit::newKitName(const QString &name, const QList<Kit *> &allKits)
+{
+ const QString baseName = name.isEmpty()
+ ? QCoreApplication::translate("ProjectExplorer::Kit", "Unnamed")
+ : QCoreApplication::translate("ProjectExplorer::Kit", "Clone of %1").arg(name);
+ return Utils::makeUniquelyNumbered(baseName, transform(allKits, &Kit::unexpandedDisplayName));
+}
+
void Kit::kitUpdated()
{
if (d->m_nestedBlockingLevel > 0) {
diff --git a/src/plugins/projectexplorer/kit.h b/src/plugins/projectexplorer/kit.h
index ab9b1681f6..8e45911d17 100644
--- a/src/plugins/projectexplorer/kit.h
+++ b/src/plugins/projectexplorer/kit.h
@@ -71,7 +71,7 @@ public:
bool isValid() const;
bool hasWarning() const;
- QList<Task> validate() const;
+ Tasks validate() const;
void fix(); // Fix the individual kit information: Make sure it contains a valid value.
// Fix will not look at other information in the kit!
void setup(); // Apply advanced magic(TM). Used only once on each kit during initial setup.
@@ -90,9 +90,17 @@ public:
bool isSdkProvided() const;
Core::Id id() const;
- QIcon icon() const;
- Utils::FileName iconPath() const;
- void setIconPath(const Utils::FileName &path);
+ // The higher the weight, the more aspects have sensible values for this kit.
+ // For instance, a kit where a matching debugger was found for the toolchain will have a
+ // higher weight than one whose toolchain does not match a known debugger, assuming
+ // all other aspects are equal.
+ int weight() const;
+
+ QIcon icon() const; // Raw device icon, independent of warning or error.
+ QIcon displayIcon() const; // Error or warning or device icon.
+ Utils::FilePath iconPath() const;
+ void setIconPath(const Utils::FilePath &path);
+ void setDeviceTypeForIcon(Core::Id deviceType);
QList<Core::Id> allKeys() const;
QVariant value(Core::Id key, const QVariant &unset = QVariant()) const;
@@ -109,7 +117,7 @@ public:
void addToEnvironment(Utils::Environment &env) const;
IOutputParser *createOutputParser() const;
- QString toHtml(const QList<Task> &additional = QList<Task>()) const;
+ QString toHtml(const Tasks &additional = Tasks()) const;
Kit *clone(bool keepName = false) const;
void copyFrom(const Kit *k);
@@ -123,12 +131,19 @@ public:
void setMutable(Core::Id id, bool b);
bool isMutable(Core::Id id) const;
+ void setIrrelevantAspects(const QSet<Core::Id> &irrelevant);
+ QSet<Core::Id> irrelevantAspects() const;
+
QSet<Core::Id> supportedPlatforms() const;
QSet<Core::Id> availableFeatures() const;
bool hasFeatures(const QSet<Core::Id> &features) const;
Utils::MacroExpander *macroExpander() const;
+ QString newKitName(const QList<Kit *> &allKits) const;
+ static QString newKitName(const QString &name, const QList<Kit *> &allKits);
+
private:
+ static void copyKitCommon(Kit *target, const Kit *source);
void setSdkProvided(bool sdkProvided);
// Unimplemented.
@@ -142,7 +157,7 @@ private:
const std::unique_ptr<Internal::KitPrivate> d;
- friend class KitInformation;
+ friend class KitAspect;
friend class KitManager;
friend class Internal::KitManagerPrivate;
friend class Internal::KitModel; // needed for setAutoDetected() when cloning kits
diff --git a/src/plugins/projectexplorer/kitchooser.cpp b/src/plugins/projectexplorer/kitchooser.cpp
index 9e0b4b25f1..c3a0204fba 100644
--- a/src/plugins/projectexplorer/kitchooser.cpp
+++ b/src/plugins/projectexplorer/kitchooser.cpp
@@ -25,7 +25,6 @@
#include "kitchooser.h"
-#include "kitconfigwidget.h"
#include "kitinformation.h"
#include "kitmanager.h"
#include "project.h"
@@ -52,7 +51,7 @@ KitChooser::KitChooser(QWidget *parent) :
{
m_chooser = new QComboBox(this);
m_chooser->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
- m_manageButton = new QPushButton(KitConfigWidget::msgManage(), this);
+ m_manageButton = new QPushButton(KitAspectWidget::msgManage(), this);
auto layout = new QHBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
@@ -60,9 +59,9 @@ KitChooser::KitChooser(QWidget *parent) :
layout->addWidget(m_manageButton);
setFocusProxy(m_manageButton);
- connect(m_chooser, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
+ connect(m_chooser, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &KitChooser::onCurrentIndexChanged);
- connect(m_chooser, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated),
+ connect(m_chooser, QOverload<int>::of(&QComboBox::activated),
this, &KitChooser::onActivated);
connect(m_manageButton, &QAbstractButton::clicked, this, &KitChooser::onManageButtonClicked);
connect(KitManager::instance(), &KitManager::kitsChanged, this, &KitChooser::populate);
@@ -73,6 +72,11 @@ void KitChooser::onManageButtonClicked()
Core::ICore::showOptionsDialog(Constants::KITS_SETTINGS_PAGE_ID, this);
}
+void KitChooser::setShowIcons(bool showIcons)
+{
+ m_showIcons = showIcons;
+}
+
void KitChooser::onCurrentIndexChanged()
{
const Id id = Id::fromSetting(m_chooser->currentData());
@@ -128,9 +132,12 @@ void KitChooser::populate()
foreach (Kit *kit, KitManager::sortKits(KitManager::kits())) {
if (m_kitPredicate(kit)) {
m_chooser->addItem(kitText(kit), kit->id().toSetting());
- m_chooser->setItemData(m_chooser->count() - 1, kitToolTip(kit), Qt::ToolTipRole);
+ const int pos = m_chooser->count() - 1;
+ m_chooser->setItemData(pos, kitToolTip(kit), Qt::ToolTipRole);
+ if (m_showIcons)
+ m_chooser->setItemData(pos, kit->displayIcon(), Qt::DecorationRole);
if (!didActivate && kit->id() == lastKit) {
- m_chooser->setCurrentIndex(m_chooser->count() - 1);
+ m_chooser->setCurrentIndex(pos);
didActivate = true;
}
}
diff --git a/src/plugins/projectexplorer/kitchooser.h b/src/plugins/projectexplorer/kitchooser.h
index bd7b8ce5cf..046c18f571 100644
--- a/src/plugins/projectexplorer/kitchooser.h
+++ b/src/plugins/projectexplorer/kitchooser.h
@@ -54,8 +54,10 @@ public:
Core::Id currentKitId() const;
void setKitPredicate(const Kit::Predicate &predicate);
+ void setShowIcons(bool showIcons);
Kit *currentKit() const;
+ bool hasStartupKit() const { return m_hasStartupKit; }
signals:
void currentIndexChanged();
@@ -77,6 +79,7 @@ private:
QComboBox *m_chooser;
QPushButton *m_manageButton;
bool m_hasStartupKit = false;
+ bool m_showIcons = false;
};
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/kitinformation.cpp b/src/plugins/projectexplorer/kitinformation.cpp
index f4da43f095..4ca258df1a 100644
--- a/src/plugins/projectexplorer/kitinformation.cpp
+++ b/src/plugins/projectexplorer/kitinformation.cpp
@@ -28,20 +28,32 @@
#include "abi.h"
#include "devicesupport/desktopdevice.h"
#include "devicesupport/devicemanager.h"
+#include "devicesupport/devicemanagermodel.h"
+#include "devicesupport/idevicefactory.h"
#include "projectexplorerconstants.h"
#include "kit.h"
-#include "kitinformationconfigwidget.h"
#include "toolchain.h"
#include "toolchainmanager.h"
+#include <coreplugin/icore.h>
+#include <coreplugin/variablechooser.h>
#include <ssh/sshconnection.h>
-
#include <utils/algorithm.h>
+#include <utils/environment.h>
+#include <utils/environmentdialog.h>
#include <utils/macroexpander.h>
+#include <utils/pathchooser.h>
#include <utils/qtcassert.h>
+#include <QCheckBox>
+#include <QComboBox>
#include <QDir>
#include <QFileInfo>
+#include <QFontMetrics>
+#include <QGridLayout>
+#include <QLabel>
+#include <QPushButton>
+#include <QVBoxLayout>
namespace ProjectExplorer {
@@ -50,26 +62,70 @@ const char KITINFORMATION_ID_V2[] = "PE.Profile.ToolChains";
const char KITINFORMATION_ID_V3[] = "PE.Profile.ToolChainsV3";
// --------------------------------------------------------------------------
-// SysRootKitInformation:
+// SysRootKitAspect:
// --------------------------------------------------------------------------
-SysRootKitInformation::SysRootKitInformation()
+namespace Internal {
+class SysRootKitAspectWidget : public KitAspectWidget
{
- setObjectName(QLatin1String("SysRootInformation"));
- setId(SysRootKitInformation::id());
- setPriority(31000);
-}
+ Q_DECLARE_TR_FUNCTIONS(ProjectExplorer::SysRootKitAspect)
+
+public:
+ SysRootKitAspectWidget(Kit *k, const KitAspect *ki) : KitAspectWidget(k, ki)
+ {
+ m_chooser = new Utils::PathChooser;
+ m_chooser->setExpectedKind(Utils::PathChooser::ExistingDirectory);
+ m_chooser->setHistoryCompleter(QLatin1String("PE.SysRoot.History"));
+ m_chooser->setFileName(SysRootKitAspect::sysRoot(k));
+ connect(m_chooser, &Utils::PathChooser::pathChanged,
+ this, &SysRootKitAspectWidget::pathWasChanged);
+ }
+
+ ~SysRootKitAspectWidget() override { delete m_chooser; }
+
+private:
+ void makeReadOnly() override { m_chooser->setReadOnly(true); }
+ QWidget *buttonWidget() const override { return m_chooser->buttonAtIndex(0); }
+ QWidget *mainWidget() const override { return m_chooser->lineEdit(); }
+
+ void refresh() override
+ {
+ if (!m_ignoreChange)
+ m_chooser->setFileName(SysRootKitAspect::sysRoot(m_kit));
+ }
+
+ void setPalette(const QPalette &p) override
+ {
+ KitAspectWidget::setPalette(p);
+ m_chooser->setOkColor(p.color(QPalette::Active, QPalette::Text));
+ }
+
+ void pathWasChanged()
+ {
+ m_ignoreChange = true;
+ SysRootKitAspect::setSysRoot(m_kit, m_chooser->fileName());
+ m_ignoreChange = false;
+ }
+
+ Utils::PathChooser *m_chooser;
+ bool m_ignoreChange = false;
+};
+} // namespace Internal
-QVariant SysRootKitInformation::defaultValue(const Kit *k) const
+SysRootKitAspect::SysRootKitAspect()
{
- Q_UNUSED(k)
- return QString();
+ setObjectName(QLatin1String("SysRootInformation"));
+ setId(SysRootKitAspect::id());
+ setDisplayName(tr("Sysroot"));
+ setDescription(tr("The root directory of the system image to use.<br>"
+ "Leave empty when building for the desktop."));
+ setPriority(31000);
}
-QList<Task> SysRootKitInformation::validate(const Kit *k) const
+Tasks SysRootKitAspect::validate(const Kit *k) const
{
- QList<Task> result;
- const Utils::FileName dir = SysRootKitInformation::sysRoot(k);
+ Tasks result;
+ const Utils::FilePath dir = SysRootKitAspect::sysRoot(k);
if (dir.isEmpty())
return result;
@@ -80,65 +136,65 @@ QList<Task> SysRootKitInformation::validate(const Kit *k) const
if (!fi.exists()) {
result << Task(Task::Warning, tr("Sys Root \"%1\" does not exist in the file system.").arg(dir.toUserOutput()),
- Utils::FileName(), -1, Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM));
+ Utils::FilePath(), -1, Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM));
} else if (!fi.isDir()) {
result << Task(Task::Warning, tr("Sys Root \"%1\" is not a directory.").arg(dir.toUserOutput()),
- Utils::FileName(), -1, Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM));
+ Utils::FilePath(), -1, Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM));
} else if (QDir(dir.toString()).entryList(QDir::AllEntries | QDir::NoDotAndDotDot).isEmpty()) {
result << Task(Task::Warning, tr("Sys Root \"%1\" is empty.").arg(dir.toUserOutput()),
- Utils::FileName(), -1, Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM));
+ Utils::FilePath(), -1, Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM));
}
return result;
}
-KitConfigWidget *SysRootKitInformation::createConfigWidget(Kit *k) const
+KitAspectWidget *SysRootKitAspect::createConfigWidget(Kit *k) const
{
QTC_ASSERT(k, return nullptr);
- return new Internal::SysRootInformationConfigWidget(k, this);
+ return new Internal::SysRootKitAspectWidget(k, this);
}
-KitInformation::ItemList SysRootKitInformation::toUserOutput(const Kit *k) const
+KitAspect::ItemList SysRootKitAspect::toUserOutput(const Kit *k) const
{
- return ItemList() << qMakePair(tr("Sys Root"), sysRoot(k).toUserOutput());
+ return {{tr("Sys Root"), sysRoot(k).toUserOutput()}};
}
-void SysRootKitInformation::addToMacroExpander(Kit *kit, Utils::MacroExpander *expander) const
+void SysRootKitAspect::addToMacroExpander(Kit *kit, Utils::MacroExpander *expander) const
{
QTC_ASSERT(kit, return);
expander->registerFileVariables("SysRoot", tr("Sys Root"), [kit]() -> QString {
- return SysRootKitInformation::sysRoot(kit).toString();
+ return SysRootKitAspect::sysRoot(kit).toString();
});
}
-Core::Id SysRootKitInformation::id()
+Core::Id SysRootKitAspect::id()
{
return "PE.Profile.SysRoot";
}
-Utils::FileName SysRootKitInformation::sysRoot(const Kit *k)
+Utils::FilePath SysRootKitAspect::sysRoot(const Kit *k)
{
if (!k)
- return Utils::FileName();
+ return Utils::FilePath();
- if (!k->value(SysRootKitInformation::id()).toString().isEmpty())
- return Utils::FileName::fromString(k->value(SysRootKitInformation::id()).toString());
+ if (!k->value(SysRootKitAspect::id()).toString().isEmpty())
+ return Utils::FilePath::fromString(k->value(SysRootKitAspect::id()).toString());
- for (ToolChain *tc : ToolChainKitInformation::toolChains(k)) {
+ for (ToolChain *tc : ToolChainKitAspect::toolChains(k)) {
if (!tc->sysRoot().isEmpty())
- return Utils::FileName::fromString(tc->sysRoot());
+ return Utils::FilePath::fromString(tc->sysRoot());
}
- return Utils::FileName();
+ return Utils::FilePath();
}
-void SysRootKitInformation::setSysRoot(Kit *k, const Utils::FileName &v)
+void SysRootKitAspect::setSysRoot(Kit *k, const Utils::FilePath &v)
{
if (!k)
return;
- for (ToolChain *tc : ToolChainKitInformation::toolChains(k)) {
+ for (ToolChain *tc : ToolChainKitAspect::toolChains(k)) {
if (!tc->sysRoot().isEmpty()) {
// It's the sysroot from toolchain, don't set it.
if (tc->sysRoot() == v.toString())
@@ -148,21 +204,145 @@ void SysRootKitInformation::setSysRoot(Kit *k, const Utils::FileName &v)
break;
}
}
- k->setValue(SysRootKitInformation::id(), v.toString());
+ k->setValue(SysRootKitAspect::id(), v.toString());
}
// --------------------------------------------------------------------------
-// ToolChainKitInformation:
+// ToolChainKitAspect:
// --------------------------------------------------------------------------
-ToolChainKitInformation::ToolChainKitInformation()
+namespace Internal {
+class ToolChainKitAspectWidget : public KitAspectWidget
+{
+ Q_DECLARE_TR_FUNCTIONS(ProjectExplorer::ToolChainKitAspect)
+
+public:
+ ToolChainKitAspectWidget(Kit *k, const KitAspect *ki) : KitAspectWidget(k, ki)
+ {
+ m_mainWidget = new QWidget;
+ m_mainWidget->setContentsMargins(0, 0, 0, 0);
+
+ auto layout = new QGridLayout(m_mainWidget);
+ layout->setContentsMargins(0, 0, 0, 0);
+ layout->setColumnStretch(1, 2);
+
+ QList<Core::Id> languageList = ToolChainManager::allLanguages().toList();
+ Utils::sort(languageList, [](Core::Id l1, Core::Id l2) {
+ return ToolChainManager::displayNameOfLanguageId(l1)
+ < ToolChainManager::displayNameOfLanguageId(l2);
+ });
+ QTC_ASSERT(!languageList.isEmpty(), return);
+ int row = 0;
+ foreach (Core::Id l, languageList) {
+ layout->addWidget(new QLabel(ToolChainManager::displayNameOfLanguageId(l) + ':'), row, 0);
+ auto cb = new QComboBox;
+ cb->setSizePolicy(QSizePolicy::Ignored, cb->sizePolicy().verticalPolicy());
+ cb->setToolTip(ki->description());
+
+ m_languageComboboxMap.insert(l, cb);
+ layout->addWidget(cb, row, 1);
+ ++row;
+
+ connect(cb, QOverload<int>::of(&QComboBox::currentIndexChanged),
+ this, [this, l](int idx) { currentToolChainChanged(l, idx); });
+ }
+
+ refresh();
+
+ m_manageButton = new QPushButton(KitAspectWidget::msgManage());
+ m_manageButton->setContentsMargins(0, 0, 0, 0);
+ connect(m_manageButton, &QAbstractButton::clicked,
+ this, &ToolChainKitAspectWidget::manageToolChains);
+ }
+
+ ~ToolChainKitAspectWidget() override
+ {
+ delete m_mainWidget;
+ delete m_manageButton;
+ }
+
+private:
+ QWidget *mainWidget() const override { return m_mainWidget; }
+ QWidget *buttonWidget() const override { return m_manageButton; }
+
+ void refresh() override
+ {
+ m_ignoreChanges = true;
+ foreach (Core::Id l, m_languageComboboxMap.keys()) {
+ const QList<ToolChain *> ltcList
+ = ToolChainManager::toolChains(Utils::equal(&ToolChain::language, l));
+
+ QComboBox *cb = m_languageComboboxMap.value(l);
+ cb->clear();
+ cb->addItem(tr("<No compiler>"), QByteArray());
+
+ foreach (ToolChain *tc, ltcList)
+ cb->addItem(tc->displayName(), tc->id());
+
+ cb->setEnabled(cb->count() > 1 && !m_isReadOnly);
+ const int index = indexOf(cb, ToolChainKitAspect::toolChain(m_kit, l));
+ cb->setCurrentIndex(index);
+ }
+ m_ignoreChanges = false;
+ }
+
+ void makeReadOnly() override
+ {
+ m_isReadOnly = true;
+ foreach (Core::Id l, m_languageComboboxMap.keys()) {
+ m_languageComboboxMap.value(l)->setEnabled(false);
+ }
+ }
+
+ void manageToolChains()
+ {
+ Core::ICore::showOptionsDialog(Constants::TOOLCHAIN_SETTINGS_PAGE_ID, buttonWidget());
+ }
+
+ void currentToolChainChanged(Core::Id language, int idx)
+ {
+ if (m_ignoreChanges || idx < 0)
+ return;
+
+ const QByteArray id = m_languageComboboxMap.value(language)->itemData(idx).toByteArray();
+ ToolChain *tc = ToolChainManager::findToolChain(id);
+ QTC_ASSERT(!tc || tc->language() == language, return);
+ if (tc)
+ ToolChainKitAspect::setToolChain(m_kit, tc);
+ else
+ ToolChainKitAspect::clearToolChain(m_kit, language);
+ }
+
+ int indexOf(QComboBox *cb, const ToolChain *tc)
+ {
+ const QByteArray id = tc ? tc->id() : QByteArray();
+ for (int i = 0; i < cb->count(); ++i) {
+ if (id == cb->itemData(i).toByteArray())
+ return i;
+ }
+ return -1;
+ }
+
+ QWidget *m_mainWidget = nullptr;
+ QPushButton *m_manageButton = nullptr;
+ QHash<Core::Id, QComboBox *> m_languageComboboxMap;
+ bool m_ignoreChanges = false;
+ bool m_isReadOnly = false;
+};
+} // namespace Internal
+
+ToolChainKitAspect::ToolChainKitAspect()
{
setObjectName(QLatin1String("ToolChainInformation"));
- setId(ToolChainKitInformation::id());
+ setId(ToolChainKitAspect::id());
+ setDisplayName(tr("Compiler"));
+ setDescription(tr("The compiler to use for building.<br>"
+ "Make sure the compiler will produce binaries compatible "
+ "with the target device, Qt version and other libraries used."));
setPriority(30000);
connect(KitManager::instance(), &KitManager::kitsLoaded,
- this, &ToolChainKitInformation::kitsWereLoaded);
+ this, &ToolChainKitAspect::kitsWereLoaded);
}
// language id -> tool chain id
@@ -189,20 +369,14 @@ static QVariant defaultToolChainValue()
return result;
}
-QVariant ToolChainKitInformation::defaultValue(const Kit *k) const
+Tasks ToolChainKitAspect::validate(const Kit *k) const
{
- Q_UNUSED(k);
- return defaultToolChainValue();
-}
-
-QList<Task> ToolChainKitInformation::validate(const Kit *k) const
-{
- QList<Task> result;
+ Tasks result;
const QList<ToolChain*> tcList = toolChains(k);
if (tcList.isEmpty()) {
- result << Task(Task::Warning, ToolChainKitInformation::msgNoToolChainInTarget(),
- Utils::FileName(), -1, Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM));
+ result << Task(Task::Warning, ToolChainKitAspect::msgNoToolChainInTarget(),
+ Utils::FilePath(), -1, Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM));
} else {
QSet<Abi> targetAbis;
foreach (ToolChain *tc, tcList) {
@@ -212,13 +386,13 @@ QList<Task> ToolChainKitInformation::validate(const Kit *k) const
if (targetAbis.count() != 1) {
result << Task(Task::Error, tr("Compilers produce code for different ABIs: %1")
.arg(Utils::transform(targetAbis, &Abi::toString).toList().join(", ")),
- Utils::FileName(), -1, Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM));
+ Utils::FilePath(), -1, Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM));
}
}
return result;
}
-void ToolChainKitInformation::upgrade(Kit *k)
+void ToolChainKitAspect::upgrade(Kit *k)
{
QTC_ASSERT(k, return);
@@ -238,7 +412,7 @@ void ToolChainKitInformation::upgrade(Kit *k)
// Used up to 4.1:
newValue.insert(Deprecated::Toolchain::languageId(Deprecated::Toolchain::Cxx), oldValue.toString());
- const Core::Id typeId = DeviceTypeKitInformation::deviceTypeId(k);
+ const Core::Id typeId = DeviceTypeKitAspect::deviceTypeId(k);
if (typeId == Constants::DESKTOP_DEVICE_TYPE) {
// insert default C compiler which did not exist before
newValue.insert(Deprecated::Toolchain::languageId(Deprecated::Toolchain::C),
@@ -253,7 +427,7 @@ void ToolChainKitInformation::upgrade(Kit *k)
// upgrade 4.2 to 4.3 (keep old settings around for now)
{
const QVariant oldValue = k->value(oldIdV2);
- const QVariant value = k->value(ToolChainKitInformation::id());
+ const QVariant value = k->value(ToolChainKitAspect::id());
if (value.isNull() && !oldValue.isNull()) {
QVariantMap newValue = oldValue.toMap();
QVariantMap::iterator it = newValue.find(Deprecated::Toolchain::languageId(Deprecated::Toolchain::C));
@@ -262,14 +436,14 @@ void ToolChainKitInformation::upgrade(Kit *k)
it = newValue.find(Deprecated::Toolchain::languageId(Deprecated::Toolchain::Cxx));
if (it != newValue.end())
newValue.insert(Core::Id(Constants::CXX_LANGUAGE_ID).toString(), it.value());
- k->setValue(ToolChainKitInformation::id(), newValue);
- k->setSticky(ToolChainKitInformation::id(), k->isSticky(oldIdV2));
+ k->setValue(ToolChainKitAspect::id(), newValue);
+ k->setSticky(ToolChainKitAspect::id(), k->isSticky(oldIdV2));
}
}
// upgrade 4.3-temporary-master-state to 4.3:
{
- const QVariantMap valueMap = k->value(ToolChainKitInformation::id()).toMap();
+ const QVariantMap valueMap = k->value(ToolChainKitAspect::id()).toMap();
QVariantMap result;
for (const QString &key : valueMap.keys()) {
const int pos = key.lastIndexOf('.');
@@ -278,11 +452,11 @@ void ToolChainKitInformation::upgrade(Kit *k)
else
result.insert(key, valueMap.value(key));
}
- k->setValue(ToolChainKitInformation::id(), result);
+ k->setValue(ToolChainKitAspect::id(), result);
}
}
-void ToolChainKitInformation::fix(Kit *k)
+void ToolChainKitAspect::fix(Kit *k)
{
QTC_ASSERT(ToolChainManager::isLoaded(), return);
foreach (const Core::Id& l, ToolChainManager::allLanguages()) {
@@ -303,12 +477,14 @@ static Core::Id findLanguage(const QString &ls)
[lsUpper](Core::Id l) { return lsUpper == l.toString().toUpper(); });
}
-void ToolChainKitInformation::setup(Kit *k)
+void ToolChainKitAspect::setup(Kit *k)
{
QTC_ASSERT(ToolChainManager::isLoaded(), return);
QTC_ASSERT(k, return);
- const QVariantMap value = k->value(ToolChainKitInformation::id()).toMap();
+ QVariantMap value = k->value(id()).toMap();
+ if (value.empty())
+ value = defaultToolChainValue().toMap();
for (auto i = value.constBegin(); i != value.constEnd(); ++i) {
Core::Id l = findLanguage(i.key());
@@ -333,32 +509,32 @@ void ToolChainKitInformation::setup(Kit *k)
}
}
-KitConfigWidget *ToolChainKitInformation::createConfigWidget(Kit *k) const
+KitAspectWidget *ToolChainKitAspect::createConfigWidget(Kit *k) const
{
QTC_ASSERT(k, return nullptr);
- return new Internal::ToolChainInformationConfigWidget(k, this);
+ return new Internal::ToolChainKitAspectWidget(k, this);
}
-QString ToolChainKitInformation::displayNamePostfix(const Kit *k) const
+QString ToolChainKitAspect::displayNamePostfix(const Kit *k) const
{
ToolChain *tc = toolChain(k, Constants::CXX_LANGUAGE_ID);
return tc ? tc->displayName() : QString();
}
-KitInformation::ItemList ToolChainKitInformation::toUserOutput(const Kit *k) const
+KitAspect::ItemList ToolChainKitAspect::toUserOutput(const Kit *k) const
{
ToolChain *tc = toolChain(k, Constants::CXX_LANGUAGE_ID);
- return ItemList() << qMakePair(tr("Compiler"), tc ? tc->displayName() : tr("None"));
+ return {{tr("Compiler"), tc ? tc->displayName() : tr("None")}};
}
-void ToolChainKitInformation::addToEnvironment(const Kit *k, Utils::Environment &env) const
+void ToolChainKitAspect::addToEnvironment(const Kit *k, Utils::Environment &env) const
{
ToolChain *tc = toolChain(k, Constants::CXX_LANGUAGE_ID);
if (tc)
tc->addToEnvironment(env);
}
-void ToolChainKitInformation::addToMacroExpander(Kit *kit, Utils::MacroExpander *expander) const
+void ToolChainKitAspect::addToMacroExpander(Kit *kit, Utils::MacroExpander *expander) const
{
QTC_ASSERT(kit, return);
@@ -388,7 +564,7 @@ void ToolChainKitInformation::addToMacroExpander(Kit *kit, Utils::MacroExpander
}
-IOutputParser *ToolChainKitInformation::createOutputParser(const Kit *k) const
+IOutputParser *ToolChainKitAspect::createOutputParser(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))
@@ -397,7 +573,7 @@ IOutputParser *ToolChainKitInformation::createOutputParser(const Kit *k) const
return nullptr;
}
-QSet<Core::Id> ToolChainKitInformation::availableFeatures(const Kit *k) const
+QSet<Core::Id> ToolChainKitAspect::availableFeatures(const Kit *k) const
{
QSet<Core::Id> result;
for (ToolChain *tc : toolChains(k))
@@ -405,30 +581,30 @@ QSet<Core::Id> ToolChainKitInformation::availableFeatures(const Kit *k) const
return result;
}
-Core::Id ToolChainKitInformation::id()
+Core::Id ToolChainKitAspect::id()
{
return KITINFORMATION_ID_V3;
}
-QByteArray ToolChainKitInformation::toolChainId(const Kit *k, Core::Id language)
+QByteArray ToolChainKitAspect::toolChainId(const Kit *k, Core::Id language)
{
QTC_ASSERT(ToolChainManager::isLoaded(), return nullptr);
if (!k)
return QByteArray();
- QVariantMap value = k->value(ToolChainKitInformation::id()).toMap();
+ QVariantMap value = k->value(ToolChainKitAspect::id()).toMap();
return value.value(language.toString(), QByteArray()).toByteArray();
}
-ToolChain *ToolChainKitInformation::toolChain(const Kit *k, Core::Id language)
+ToolChain *ToolChainKitAspect::toolChain(const Kit *k, Core::Id language)
{
return ToolChainManager::findToolChain(toolChainId(k, language));
}
-QList<ToolChain *> ToolChainKitInformation::toolChains(const Kit *k)
+QList<ToolChain *> ToolChainKitAspect::toolChains(const Kit *k)
{
QTC_ASSERT(k, return QList<ToolChain *>());
- const QVariantMap value = k->value(ToolChainKitInformation::id()).toMap();
+ const QVariantMap value = k->value(ToolChainKitAspect::id()).toMap();
const QList<ToolChain *> tcList
= Utils::transform(ToolChainManager::allLanguages().toList(),
[&value](Core::Id l) -> ToolChain * {
@@ -437,18 +613,18 @@ QList<ToolChain *> ToolChainKitInformation::toolChains(const Kit *k)
return Utils::filtered(tcList, [](ToolChain *tc) { return tc; });
}
-void ToolChainKitInformation::setToolChain(Kit *k, ToolChain *tc)
+void ToolChainKitAspect::setToolChain(Kit *k, ToolChain *tc)
{
QTC_ASSERT(tc, return);
QTC_ASSERT(k, return);
- QVariantMap result = k->value(ToolChainKitInformation::id()).toMap();
+ QVariantMap result = k->value(ToolChainKitAspect::id()).toMap();
result.insert(tc->language().toString(), tc->id());
k->setValue(id(), result);
}
/**
- * @brief ToolChainKitInformation::setAllToolChainsToMatch
+ * @brief ToolChainKitAspect::setAllToolChainsToMatch
*
* Set up all toolchains to be similar to the one toolchain provided. Similar ideally means
* that all toolchains use the "same" compiler from the same installation, but we will
@@ -457,7 +633,7 @@ void ToolChainKitInformation::setToolChain(Kit *k, ToolChain *tc)
* @param k The kit to set up
* @param tc The toolchain to match other languages for.
*/
-void ToolChainKitInformation::setAllToolChainsToMatch(Kit *k, ToolChain *tc)
+void ToolChainKitAspect::setAllToolChainsToMatch(Kit *k, ToolChain *tc)
{
QTC_ASSERT(tc, return);
QTC_ASSERT(k, return);
@@ -465,7 +641,7 @@ void ToolChainKitInformation::setAllToolChainsToMatch(Kit *k, ToolChain *tc)
const QList<ToolChain *> allTcList = ToolChainManager::toolChains();
QTC_ASSERT(allTcList.contains(tc), return);
- QVariantMap result = k->value(ToolChainKitInformation::id()).toMap();
+ QVariantMap result = k->value(ToolChainKitAspect::id()).toMap();
result.insert(tc->language().toString(), tc->id());
for (Core::Id l : ToolChainManager::allLanguages()) {
@@ -496,17 +672,17 @@ void ToolChainKitInformation::setAllToolChainsToMatch(Kit *k, ToolChain *tc)
k->setValue(id(), result);
}
-void ToolChainKitInformation::clearToolChain(Kit *k, Core::Id language)
+void ToolChainKitAspect::clearToolChain(Kit *k, Core::Id language)
{
QTC_ASSERT(language.isValid(), return);
QTC_ASSERT(k, return);
- QVariantMap result = k->value(ToolChainKitInformation::id()).toMap();
+ QVariantMap result = k->value(ToolChainKitAspect::id()).toMap();
result.insert(language.toString(), QByteArray());
k->setValue(id(), result);
}
-Abi ToolChainKitInformation::targetAbi(const Kit *k)
+Abi ToolChainKitAspect::targetAbi(const Kit *k)
{
QList<ToolChain *> tcList = toolChains(k);
// Find the best possible ABI for all the tool chains...
@@ -539,29 +715,29 @@ Abi ToolChainKitInformation::targetAbi(const Kit *k)
return candidates.at(0); // Use basically a random Abi...
}
-QString ToolChainKitInformation::msgNoToolChainInTarget()
+QString ToolChainKitAspect::msgNoToolChainInTarget()
{
return tr("No compiler set in kit.");
}
-void ToolChainKitInformation::kitsWereLoaded()
+void ToolChainKitAspect::kitsWereLoaded()
{
foreach (Kit *k, KitManager::kits())
fix(k);
connect(ToolChainManager::instance(), &ToolChainManager::toolChainRemoved,
- this, &ToolChainKitInformation::toolChainRemoved);
+ this, &ToolChainKitAspect::toolChainRemoved);
connect(ToolChainManager::instance(), &ToolChainManager::toolChainUpdated,
- this, &ToolChainKitInformation::toolChainUpdated);
+ this, &ToolChainKitAspect::toolChainUpdated);
}
-void ToolChainKitInformation::toolChainUpdated(ToolChain *tc)
+void ToolChainKitAspect::toolChainUpdated(ToolChain *tc)
{
for (Kit *k : KitManager::kits([tc](const Kit *k) { return toolChain(k, tc->language()) == tc; }))
notifyAboutUpdate(k);
}
-void ToolChainKitInformation::toolChainRemoved(ToolChain *tc)
+void ToolChainKitAspect::toolChainRemoved(ToolChain *tc)
{
Q_UNUSED(tc);
foreach (Kit *k, KitManager::kits())
@@ -569,35 +745,83 @@ void ToolChainKitInformation::toolChainRemoved(ToolChain *tc)
}
// --------------------------------------------------------------------------
-// DeviceTypeKitInformation:
+// DeviceTypeKitAspect:
// --------------------------------------------------------------------------
+namespace Internal {
+class DeviceTypeKitAspectWidget : public KitAspectWidget
+{
+ Q_DECLARE_TR_FUNCTIONS(ProjectExplorer::DeviceTypeKitAspect)
+
+public:
+ DeviceTypeKitAspectWidget(Kit *workingCopy, const KitAspect *ki)
+ : KitAspectWidget(workingCopy, ki), m_comboBox(new QComboBox)
+ {
+ for (IDeviceFactory *factory : IDeviceFactory::allDeviceFactories())
+ m_comboBox->addItem(factory->displayName(), factory->deviceType().toSetting());
+ m_comboBox->setToolTip(ki->description());
+ refresh();
+ connect(m_comboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
+ this, &DeviceTypeKitAspectWidget::currentTypeChanged);
+ }
-DeviceTypeKitInformation::DeviceTypeKitInformation()
+ ~DeviceTypeKitAspectWidget() override { delete m_comboBox; }
+
+private:
+ QWidget *mainWidget() const override { return m_comboBox; }
+ void makeReadOnly() override { m_comboBox->setEnabled(false); }
+
+ void refresh() override
+ {
+ Core::Id devType = DeviceTypeKitAspect::deviceTypeId(m_kit);
+ if (!devType.isValid())
+ m_comboBox->setCurrentIndex(-1);
+ for (int i = 0; i < m_comboBox->count(); ++i) {
+ if (m_comboBox->itemData(i) == devType.toSetting()) {
+ m_comboBox->setCurrentIndex(i);
+ break;
+ }
+ }
+ }
+
+ void currentTypeChanged(int idx)
+ {
+ Core::Id type = idx < 0 ? Core::Id() : Core::Id::fromSetting(m_comboBox->itemData(idx));
+ DeviceTypeKitAspect::setDeviceTypeId(m_kit, type);
+ }
+
+ QComboBox *m_comboBox;
+};
+} // namespace Internal
+
+DeviceTypeKitAspect::DeviceTypeKitAspect()
{
setObjectName(QLatin1String("DeviceTypeInformation"));
- setId(DeviceTypeKitInformation::id());
+ setId(DeviceTypeKitAspect::id());
+ setDisplayName(tr("Device type"));
+ setDescription(tr("The type of device to run applications on."));
setPriority(33000);
+ makeEssential();
}
-QVariant DeviceTypeKitInformation::defaultValue(const Kit *k) const
+void DeviceTypeKitAspect::setup(Kit *k)
{
- Q_UNUSED(k);
- return QByteArray(Constants::DESKTOP_DEVICE_TYPE);
+ if (k && !k->hasValue(id()))
+ k->setValue(id(), QByteArray(Constants::DESKTOP_DEVICE_TYPE));
}
-QList<Task> DeviceTypeKitInformation::validate(const Kit *k) const
+Tasks DeviceTypeKitAspect::validate(const Kit *k) const
{
Q_UNUSED(k);
- return QList<Task>();
+ return {};
}
-KitConfigWidget *DeviceTypeKitInformation::createConfigWidget(Kit *k) const
+KitAspectWidget *DeviceTypeKitAspect::createConfigWidget(Kit *k) const
{
QTC_ASSERT(k, return nullptr);
- return new Internal::DeviceTypeInformationConfigWidget(k, this);
+ return new Internal::DeviceTypeKitAspectWidget(k, this);
}
-KitInformation::ItemList DeviceTypeKitInformation::toUserOutput(const Kit *k) const
+KitAspect::ItemList DeviceTypeKitAspect::toUserOutput(const Kit *k) const
{
QTC_ASSERT(k, return {});
Core::Id type = deviceTypeId(k);
@@ -606,60 +830,133 @@ KitInformation::ItemList DeviceTypeKitInformation::toUserOutput(const Kit *k) co
if (IDeviceFactory *factory = IDeviceFactory::find(type))
typeDisplayName = factory->displayName();
}
- return ItemList() << qMakePair(tr("Device type"), typeDisplayName);
+ return {{tr("Device type"), typeDisplayName}};
}
-const Core::Id DeviceTypeKitInformation::id()
+const Core::Id DeviceTypeKitAspect::id()
{
return "PE.Profile.DeviceType";
}
-const Core::Id DeviceTypeKitInformation::deviceTypeId(const Kit *k)
+const Core::Id DeviceTypeKitAspect::deviceTypeId(const Kit *k)
{
- return k ? Core::Id::fromSetting(k->value(DeviceTypeKitInformation::id())) : Core::Id();
+ return k ? Core::Id::fromSetting(k->value(DeviceTypeKitAspect::id())) : Core::Id();
}
-void DeviceTypeKitInformation::setDeviceTypeId(Kit *k, Core::Id type)
+void DeviceTypeKitAspect::setDeviceTypeId(Kit *k, Core::Id type)
{
QTC_ASSERT(k, return);
- k->setValue(DeviceTypeKitInformation::id(), type.toSetting());
+ k->setValue(DeviceTypeKitAspect::id(), type.toSetting());
}
-Kit::Predicate DeviceTypeKitInformation::deviceTypePredicate(Core::Id type)
-{
- return [type](const Kit *kit) { return type.isValid() && deviceTypeId(kit) == type; };
-}
-
-QSet<Core::Id> DeviceTypeKitInformation::supportedPlatforms(const Kit *k) const
+QSet<Core::Id> DeviceTypeKitAspect::supportedPlatforms(const Kit *k) const
{
return {deviceTypeId(k)};
}
-QSet<Core::Id> DeviceTypeKitInformation::availableFeatures(const Kit *k) const
+QSet<Core::Id> DeviceTypeKitAspect::availableFeatures(const Kit *k) const
{
- Core::Id id = DeviceTypeKitInformation::deviceTypeId(k);
+ Core::Id id = DeviceTypeKitAspect::deviceTypeId(k);
if (id.isValid())
return {id.withPrefix("DeviceType.")};
return QSet<Core::Id>();
}
// --------------------------------------------------------------------------
-// DeviceKitInformation:
+// DeviceKitAspect:
// --------------------------------------------------------------------------
+namespace Internal {
+class DeviceKitAspectWidget : public KitAspectWidget
+{
+ Q_DECLARE_TR_FUNCTIONS(ProjectExplorer::DeviceKitAspect)
-DeviceKitInformation::DeviceKitInformation()
+public:
+ DeviceKitAspectWidget(Kit *workingCopy, const KitAspect *ki)
+ : KitAspectWidget(workingCopy, ki), m_comboBox(new QComboBox),
+ m_model(new DeviceManagerModel(DeviceManager::instance()))
+ {
+ m_comboBox->setSizePolicy(QSizePolicy::Ignored, m_comboBox->sizePolicy().verticalPolicy());
+ m_comboBox->setModel(m_model);
+ m_manageButton = new QPushButton(KitAspectWidget::msgManage());
+ refresh();
+ m_comboBox->setToolTip(ki->description());
+
+ connect(m_model, &QAbstractItemModel::modelAboutToBeReset,
+ this, &DeviceKitAspectWidget::modelAboutToReset);
+ connect(m_model, &QAbstractItemModel::modelReset,
+ this, &DeviceKitAspectWidget::modelReset);
+ connect(m_comboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
+ this, &DeviceKitAspectWidget::currentDeviceChanged);
+ connect(m_manageButton, &QAbstractButton::clicked,
+ this, &DeviceKitAspectWidget::manageDevices);
+ }
+
+ ~DeviceKitAspectWidget() override
+ {
+ delete m_comboBox;
+ delete m_model;
+ delete m_manageButton;
+ }
+
+private:
+ QWidget *mainWidget() const override { return m_comboBox; }
+ QWidget *buttonWidget() const override { return m_manageButton; }
+ void makeReadOnly() override { m_comboBox->setEnabled(false); }
+
+ void refresh() override
+ {
+ m_model->setTypeFilter(DeviceTypeKitAspect::deviceTypeId(m_kit));
+ m_comboBox->setCurrentIndex(m_model->indexOf(DeviceKitAspect::device(m_kit)));
+ }
+
+ void manageDevices()
+ {
+ Core::ICore::showOptionsDialog(Constants::DEVICE_SETTINGS_PAGE_ID, buttonWidget());
+ }
+
+ void modelAboutToReset()
+ {
+ m_selectedId = m_model->deviceId(m_comboBox->currentIndex());
+ m_ignoreChange = true;
+ }
+
+ void modelReset()
+ {
+ m_comboBox->setCurrentIndex(m_model->indexForId(m_selectedId));
+ m_ignoreChange = false;
+ }
+
+ void currentDeviceChanged()
+ {
+ if (m_ignoreChange)
+ return;
+ DeviceKitAspect::setDeviceId(m_kit, m_model->deviceId(m_comboBox->currentIndex()));
+ }
+
+ bool m_isReadOnly = false;
+ bool m_ignoreChange = false;
+ QComboBox *m_comboBox;
+ QPushButton *m_manageButton;
+ DeviceManagerModel *m_model;
+ Core::Id m_selectedId;
+};
+} // namespace Internal
+
+DeviceKitAspect::DeviceKitAspect()
{
setObjectName(QLatin1String("DeviceInformation"));
- setId(DeviceKitInformation::id());
+ setId(DeviceKitAspect::id());
+ setDisplayName(tr("Device"));
+ setDescription(tr("The device to run the applications on."));
setPriority(32000);
connect(KitManager::instance(), &KitManager::kitsLoaded,
- this, &DeviceKitInformation::kitsWereLoaded);
+ this, &DeviceKitAspect::kitsWereLoaded);
}
-QVariant DeviceKitInformation::defaultValue(const Kit *k) const
+QVariant DeviceKitAspect::defaultValue(const Kit *k) const
{
- Core::Id type = DeviceTypeKitInformation::deviceTypeId(k);
+ Core::Id type = DeviceTypeKitAspect::deviceTypeId(k);
// Use default device if that is compatible:
IDevice::ConstPtr dev = DeviceManager::instance()->defaultDevice(type);
if (dev && dev->isCompatibleWith(k))
@@ -674,23 +971,23 @@ QVariant DeviceKitInformation::defaultValue(const Kit *k) const
return QString();
}
-QList<Task> DeviceKitInformation::validate(const Kit *k) const
+Tasks DeviceKitAspect::validate(const Kit *k) const
{
- IDevice::ConstPtr dev = DeviceKitInformation::device(k);
- QList<Task> result;
+ IDevice::ConstPtr dev = DeviceKitAspect::device(k);
+ Tasks result;
if (dev.isNull())
result.append(Task(Task::Warning, tr("No device set."),
- Utils::FileName(), -1, Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM)));
+ Utils::FilePath(), -1, Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM)));
else if (!dev->isCompatibleWith(k))
result.append(Task(Task::Error, tr("Device is incompatible with this kit."),
- Utils::FileName(), -1, Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM)));
+ Utils::FilePath(), -1, Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM)));
return result;
}
-void DeviceKitInformation::fix(Kit *k)
+void DeviceKitAspect::fix(Kit *k)
{
- IDevice::ConstPtr dev = DeviceKitInformation::device(k);
+ IDevice::ConstPtr dev = DeviceKitAspect::device(k);
if (!dev.isNull() && !dev->isCompatibleWith(k)) {
qWarning("Device is no longer compatible with kit \"%s\", removing it.",
qPrintable(k->displayName()));
@@ -698,109 +995,109 @@ void DeviceKitInformation::fix(Kit *k)
}
}
-void DeviceKitInformation::setup(Kit *k)
+void DeviceKitAspect::setup(Kit *k)
{
QTC_ASSERT(DeviceManager::instance()->isLoaded(), return);
- IDevice::ConstPtr dev = DeviceKitInformation::device(k);
+ IDevice::ConstPtr dev = DeviceKitAspect::device(k);
if (!dev.isNull() && dev->isCompatibleWith(k))
return;
setDeviceId(k, Core::Id::fromSetting(defaultValue(k)));
}
-KitConfigWidget *DeviceKitInformation::createConfigWidget(Kit *k) const
+KitAspectWidget *DeviceKitAspect::createConfigWidget(Kit *k) const
{
QTC_ASSERT(k, return nullptr);
- return new Internal::DeviceInformationConfigWidget(k, this);
+ return new Internal::DeviceKitAspectWidget(k, this);
}
-QString DeviceKitInformation::displayNamePostfix(const Kit *k) const
+QString DeviceKitAspect::displayNamePostfix(const Kit *k) const
{
IDevice::ConstPtr dev = device(k);
return dev.isNull() ? QString() : dev->displayName();
}
-KitInformation::ItemList DeviceKitInformation::toUserOutput(const Kit *k) const
+KitAspect::ItemList DeviceKitAspect::toUserOutput(const Kit *k) const
{
IDevice::ConstPtr dev = device(k);
- return ItemList() << qMakePair(tr("Device"), dev.isNull() ? tr("Unconfigured") : dev->displayName());
+ return {{tr("Device"), dev.isNull() ? tr("Unconfigured") : dev->displayName()}};
}
-void DeviceKitInformation::addToMacroExpander(Kit *kit, Utils::MacroExpander *expander) const
+void DeviceKitAspect::addToMacroExpander(Kit *kit, Utils::MacroExpander *expander) const
{
QTC_ASSERT(kit, return);
expander->registerVariable("Device:HostAddress", tr("Host address"),
[kit]() -> QString {
- const IDevice::ConstPtr device = DeviceKitInformation::device(kit);
+ const IDevice::ConstPtr device = DeviceKitAspect::device(kit);
return device ? device->sshParameters().host() : QString();
});
expander->registerVariable("Device:SshPort", tr("SSH port"),
[kit]() -> QString {
- const IDevice::ConstPtr device = DeviceKitInformation::device(kit);
+ const IDevice::ConstPtr device = DeviceKitAspect::device(kit);
return device ? QString::number(device->sshParameters().port()) : QString();
});
expander->registerVariable("Device:UserName", tr("User name"),
[kit]() -> QString {
- const IDevice::ConstPtr device = DeviceKitInformation::device(kit);
+ const IDevice::ConstPtr device = DeviceKitAspect::device(kit);
return device ? device->sshParameters().userName() : QString();
});
expander->registerVariable("Device:KeyFile", tr("Private key file"),
[kit]() -> QString {
- const IDevice::ConstPtr device = DeviceKitInformation::device(kit);
+ const IDevice::ConstPtr device = DeviceKitAspect::device(kit);
return device ? device->sshParameters().privateKeyFile : QString();
});
expander->registerVariable("Device:Name", tr("Device name"),
[kit]() -> QString {
- const IDevice::ConstPtr device = DeviceKitInformation::device(kit);
+ const IDevice::ConstPtr device = DeviceKitAspect::device(kit);
return device ? device->displayName() : QString();
});
}
-Core::Id DeviceKitInformation::id()
+Core::Id DeviceKitAspect::id()
{
return "PE.Profile.Device";
}
-IDevice::ConstPtr DeviceKitInformation::device(const Kit *k)
+IDevice::ConstPtr DeviceKitAspect::device(const Kit *k)
{
QTC_ASSERT(DeviceManager::instance()->isLoaded(), return IDevice::ConstPtr());
return DeviceManager::instance()->find(deviceId(k));
}
-Core::Id DeviceKitInformation::deviceId(const Kit *k)
+Core::Id DeviceKitAspect::deviceId(const Kit *k)
{
- return k ? Core::Id::fromSetting(k->value(DeviceKitInformation::id())) : Core::Id();
+ return k ? Core::Id::fromSetting(k->value(DeviceKitAspect::id())) : Core::Id();
}
-void DeviceKitInformation::setDevice(Kit *k, IDevice::ConstPtr dev)
+void DeviceKitAspect::setDevice(Kit *k, IDevice::ConstPtr dev)
{
setDeviceId(k, dev ? dev->id() : Core::Id());
}
-void DeviceKitInformation::setDeviceId(Kit *k, Core::Id id)
+void DeviceKitAspect::setDeviceId(Kit *k, Core::Id id)
{
QTC_ASSERT(k, return);
- k->setValue(DeviceKitInformation::id(), id.toSetting());
+ k->setValue(DeviceKitAspect::id(), id.toSetting());
}
-void DeviceKitInformation::kitsWereLoaded()
+void DeviceKitAspect::kitsWereLoaded()
{
foreach (Kit *k, KitManager::kits())
fix(k);
DeviceManager *dm = DeviceManager::instance();
- connect(dm, &DeviceManager::deviceListReplaced, this, &DeviceKitInformation::devicesChanged);
- connect(dm, &DeviceManager::deviceAdded, this, &DeviceKitInformation::devicesChanged);
- connect(dm, &DeviceManager::deviceRemoved, this, &DeviceKitInformation::devicesChanged);
- connect(dm, &DeviceManager::deviceUpdated, this, &DeviceKitInformation::deviceUpdated);
+ connect(dm, &DeviceManager::deviceListReplaced, this, &DeviceKitAspect::devicesChanged);
+ connect(dm, &DeviceManager::deviceAdded, this, &DeviceKitAspect::devicesChanged);
+ connect(dm, &DeviceManager::deviceRemoved, this, &DeviceKitAspect::devicesChanged);
+ connect(dm, &DeviceManager::deviceUpdated, this, &DeviceKitAspect::deviceUpdated);
connect(KitManager::instance(), &KitManager::kitUpdated,
- this, &DeviceKitInformation::kitUpdated);
+ this, &DeviceKitAspect::kitUpdated);
connect(KitManager::instance(), &KitManager::unmanagedKitUpdated,
- this, &DeviceKitInformation::kitUpdated);
+ this, &DeviceKitAspect::kitUpdated);
}
-void DeviceKitInformation::deviceUpdated(Core::Id id)
+void DeviceKitAspect::deviceUpdated(Core::Id id)
{
foreach (Kit *k, KitManager::kits()) {
if (deviceId(k) == id)
@@ -808,59 +1105,160 @@ void DeviceKitInformation::deviceUpdated(Core::Id id)
}
}
-void DeviceKitInformation::kitUpdated(Kit *k)
+void DeviceKitAspect::kitUpdated(Kit *k)
{
setup(k); // Set default device if necessary
}
-void DeviceKitInformation::devicesChanged()
+void DeviceKitAspect::devicesChanged()
{
foreach (Kit *k, KitManager::kits())
setup(k); // Set default device if necessary
}
// --------------------------------------------------------------------------
-// EnvironmentKitInformation:
+// EnvironmentKitAspect:
// --------------------------------------------------------------------------
-
-EnvironmentKitInformation::EnvironmentKitInformation()
+namespace Internal {
+class EnvironmentKitAspectWidget : public KitAspectWidget
{
- setObjectName(QLatin1String("EnvironmentKitInformation"));
- setId(EnvironmentKitInformation::id());
- setPriority(29000);
-}
+ Q_DECLARE_TR_FUNCTIONS(ProjectExplorer::EnvironmentKitAspect)
-QVariant EnvironmentKitInformation::defaultValue(const Kit *k) const
+public:
+ EnvironmentKitAspectWidget(Kit *workingCopy, const KitAspect *ki)
+ : KitAspectWidget(workingCopy, ki),
+ m_summaryLabel(new QLabel),
+ m_manageButton(new QPushButton),
+ m_mainWidget(new QWidget)
+ {
+ auto *layout = new QVBoxLayout;
+ layout->setContentsMargins(0, 0, 0, 0);
+ layout->addWidget(m_summaryLabel);
+ if (Utils::HostOsInfo::isWindowsHost())
+ initMSVCOutputSwitch(layout);
+ m_mainWidget->setLayout(layout);
+ refresh();
+ m_manageButton->setText(tr("Change..."));
+ connect(m_manageButton, &QAbstractButton::clicked,
+ this, &EnvironmentKitAspectWidget::editEnvironmentChanges);
+ }
+
+private:
+ QWidget *mainWidget() const override { return m_mainWidget; }
+ QWidget *buttonWidget() const override { return m_manageButton; }
+ void makeReadOnly() override { m_manageButton->setEnabled(false); }
+
+ void refresh() override
+ {
+ const QList<Utils::EnvironmentItem> changes = currentEnvironment();
+ QString shortSummary = Utils::EnvironmentItem::toStringList(changes).join(QLatin1String("; "));
+ QFontMetrics fm(m_summaryLabel->font());
+ shortSummary = fm.elidedText(shortSummary, Qt::ElideRight, m_summaryLabel->width());
+ m_summaryLabel->setText(shortSummary.isEmpty() ? tr("No changes to apply.") : shortSummary);
+ }
+
+ void editEnvironmentChanges()
+ {
+ bool ok;
+ Utils::MacroExpander *expander = m_kit->macroExpander();
+ Utils::EnvironmentDialog::Polisher polisher = [expander](QWidget *w) {
+ Core::VariableChooser::addSupportForChildWidgets(w, expander);
+ };
+ QList<Utils::EnvironmentItem>
+ changes = Utils::EnvironmentDialog::getEnvironmentItems(&ok,
+ m_summaryLabel,
+ currentEnvironment(),
+ QString(),
+ polisher);
+ if (!ok)
+ return;
+
+ if (Utils::HostOsInfo::isWindowsHost()) {
+ const Utils::EnvironmentItem forceMSVCEnglishItem("VSLANG", "1033");
+ if (m_vslangCheckbox->isChecked() && changes.indexOf(forceMSVCEnglishItem) < 0)
+ changes.append(forceMSVCEnglishItem);
+ }
+
+ EnvironmentKitAspect::setEnvironmentChanges(m_kit, changes);
+ }
+
+ QList<Utils::EnvironmentItem> currentEnvironment() const
+ {
+ QList<Utils::EnvironmentItem> changes = EnvironmentKitAspect::environmentChanges(m_kit);
+
+ if (Utils::HostOsInfo::isWindowsHost()) {
+ const Utils::EnvironmentItem forceMSVCEnglishItem("VSLANG", "1033");
+ if (changes.indexOf(forceMSVCEnglishItem) >= 0) {
+ m_vslangCheckbox->setCheckState(Qt::Checked);
+ changes.removeAll(forceMSVCEnglishItem);
+ }
+ }
+
+ Utils::sort(changes, [](const Utils::EnvironmentItem &lhs, const Utils::EnvironmentItem &rhs)
+ { return QString::localeAwareCompare(lhs.name, rhs.name) < 0; });
+ return changes;
+ }
+
+ void initMSVCOutputSwitch(QVBoxLayout *layout)
+ {
+ m_vslangCheckbox = new QCheckBox(tr("Force UTF-8 MSVC compiler output"));
+ layout->addWidget(m_vslangCheckbox);
+ m_vslangCheckbox->setToolTip(tr("Either switches MSVC to English or keeps the language and "
+ "just forces UTF-8 output (may vary depending on the used MSVC "
+ "compiler)."));
+ connect(m_vslangCheckbox, &QCheckBox::toggled, this, [this](bool checked) {
+ QList<Utils::EnvironmentItem> changes
+ = EnvironmentKitAspect::environmentChanges(m_kit);
+ const Utils::EnvironmentItem forceMSVCEnglishItem("VSLANG", "1033");
+ if (!checked && changes.indexOf(forceMSVCEnglishItem) >= 0)
+ changes.removeAll(forceMSVCEnglishItem);
+ if (checked && changes.indexOf(forceMSVCEnglishItem) < 0)
+ changes.append(forceMSVCEnglishItem);
+ EnvironmentKitAspect::setEnvironmentChanges(m_kit, changes);
+ });
+ }
+
+ QLabel *m_summaryLabel;
+ QPushButton *m_manageButton;
+ QCheckBox *m_vslangCheckbox;
+ QWidget *m_mainWidget;
+};
+} // namespace Internal
+
+EnvironmentKitAspect::EnvironmentKitAspect()
{
- Q_UNUSED(k)
- return QStringList();
+ setObjectName(QLatin1String("EnvironmentKitAspect"));
+ setId(EnvironmentKitAspect::id());
+ setDisplayName(tr("Environment"));
+ setDescription(tr("Additional build environment settings when using this kit."));
+ setPriority(29000);
}
-QList<Task> EnvironmentKitInformation::validate(const Kit *k) const
+Tasks EnvironmentKitAspect::validate(const Kit *k) const
{
- QList<Task> result;
+ Tasks result;
QTC_ASSERT(k, return result);
- const QVariant variant = k->value(EnvironmentKitInformation::id());
+ const QVariant variant = k->value(EnvironmentKitAspect::id());
if (!variant.isNull() && !variant.canConvert(QVariant::List)) {
result.append(Task(Task::Error, tr("The environment setting value is invalid."),
- Utils::FileName(), -1, Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM)));
+ Utils::FilePath(), -1, Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM)));
}
return result;
}
-void EnvironmentKitInformation::fix(Kit *k)
+void EnvironmentKitAspect::fix(Kit *k)
{
QTC_ASSERT(k, return);
- const QVariant variant = k->value(EnvironmentKitInformation::id());
+ const QVariant variant = k->value(EnvironmentKitAspect::id());
if (!variant.isNull() && !variant.canConvert(QVariant::List)) {
qWarning("Kit \"%s\" has a wrong environment value set.", qPrintable(k->displayName()));
setEnvironmentChanges(k, QList<Utils::EnvironmentItem>());
}
}
-void EnvironmentKitInformation::addToEnvironment(const Kit *k, Utils::Environment &env) const
+void EnvironmentKitAspect::addToEnvironment(const Kit *k, Utils::Environment &env) const
{
const QStringList values
= Utils::transform(Utils::EnvironmentItem::toStringList(environmentChanges(k)),
@@ -868,34 +1266,34 @@ void EnvironmentKitInformation::addToEnvironment(const Kit *k, Utils::Environmen
env.modify(Utils::EnvironmentItem::fromStringList(values));
}
-KitConfigWidget *EnvironmentKitInformation::createConfigWidget(Kit *k) const
+KitAspectWidget *EnvironmentKitAspect::createConfigWidget(Kit *k) const
{
QTC_ASSERT(k, return nullptr);
- return new Internal::KitEnvironmentConfigWidget(k, this);
+ return new Internal::EnvironmentKitAspectWidget(k, this);
}
-KitInformation::ItemList EnvironmentKitInformation::toUserOutput(const Kit *k) const
+KitAspect::ItemList EnvironmentKitAspect::toUserOutput(const Kit *k) const
{
return { qMakePair(tr("Environment"),
Utils::EnvironmentItem::toStringList(environmentChanges(k)).join("<br>")) };
}
-Core::Id EnvironmentKitInformation::id()
+Core::Id EnvironmentKitAspect::id()
{
return "PE.Profile.Environment";
}
-QList<Utils::EnvironmentItem> EnvironmentKitInformation::environmentChanges(const Kit *k)
+QList<Utils::EnvironmentItem> EnvironmentKitAspect::environmentChanges(const Kit *k)
{
if (k)
- return Utils::EnvironmentItem::fromStringList(k->value(EnvironmentKitInformation::id()).toStringList());
+ return Utils::EnvironmentItem::fromStringList(k->value(EnvironmentKitAspect::id()).toStringList());
return QList<Utils::EnvironmentItem>();
}
-void EnvironmentKitInformation::setEnvironmentChanges(Kit *k, const QList<Utils::EnvironmentItem> &changes)
+void EnvironmentKitAspect::setEnvironmentChanges(Kit *k, const QList<Utils::EnvironmentItem> &changes)
{
if (k)
- k->setValue(EnvironmentKitInformation::id(), Utils::EnvironmentItem::toStringList(changes));
+ k->setValue(EnvironmentKitAspect::id(), Utils::EnvironmentItem::toStringList(changes));
}
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/kitinformation.h b/src/plugins/projectexplorer/kitinformation.h
index c32dbefa27..037b4b9394 100644
--- a/src/plugins/projectexplorer/kitinformation.h
+++ b/src/plugins/projectexplorer/kitinformation.h
@@ -37,52 +37,46 @@
namespace ProjectExplorer {
-class KitConfigWidget;
+class KitAspectWidget;
// --------------------------------------------------------------------------
// SysRootInformation:
// --------------------------------------------------------------------------
-class PROJECTEXPLORER_EXPORT SysRootKitInformation : public KitInformation
+class PROJECTEXPLORER_EXPORT SysRootKitAspect : public KitAspect
{
Q_OBJECT
public:
- SysRootKitInformation();
-
- QVariant defaultValue(const Kit *k) const override;
-
- QList<Task> validate(const Kit *k) const override;
-
- KitConfigWidget *createConfigWidget(Kit *k) const override;
+ SysRootKitAspect();
+ Tasks validate(const Kit *k) const override;
+ KitAspectWidget *createConfigWidget(Kit *k) const override;
ItemList toUserOutput(const Kit *k) const override;
void addToMacroExpander(Kit *kit, Utils::MacroExpander *expander) const override;
static Core::Id id();
- static Utils::FileName sysRoot(const Kit *k);
- static void setSysRoot(Kit *k, const Utils::FileName &v);
+ static Utils::FilePath sysRoot(const Kit *k);
+ static void setSysRoot(Kit *k, const Utils::FilePath &v);
};
// --------------------------------------------------------------------------
// ToolChainInformation:
// --------------------------------------------------------------------------
-class PROJECTEXPLORER_EXPORT ToolChainKitInformation : public KitInformation
+class PROJECTEXPLORER_EXPORT ToolChainKitAspect : public KitAspect
{
Q_OBJECT
public:
- ToolChainKitInformation();
+ ToolChainKitAspect();
- QVariant defaultValue(const Kit *k) const override;
-
- QList<Task> validate(const Kit *k) const override;
+ Tasks validate(const Kit *k) const override;
void upgrade(Kit *k) override;
void fix(Kit *k) override;
void setup(Kit *k) override;
- KitConfigWidget *createConfigWidget(Kit *k) const override;
+ KitAspectWidget *createConfigWidget(Kit *k) const override;
QString displayNamePostfix(const Kit *k) const override;
@@ -114,27 +108,22 @@ private:
// DeviceTypeInformation:
// --------------------------------------------------------------------------
-class PROJECTEXPLORER_EXPORT DeviceTypeKitInformation : public KitInformation
+class PROJECTEXPLORER_EXPORT DeviceTypeKitAspect : public KitAspect
{
Q_OBJECT
public:
- DeviceTypeKitInformation();
-
- QVariant defaultValue(const Kit *k) const override;
-
- QList<Task> validate(const Kit *k) const override;
-
- KitConfigWidget *createConfigWidget(Kit *k) const override;
+ DeviceTypeKitAspect();
+ void setup(Kit *k) override;
+ Tasks validate(const Kit *k) const override;
+ KitAspectWidget *createConfigWidget(Kit *k) const override;
ItemList toUserOutput(const Kit *k) const override;
static const Core::Id id();
static const Core::Id deviceTypeId(const Kit *k);
static void setDeviceTypeId(Kit *k, Core::Id type);
- static Kit::Predicate deviceTypePredicate(Core::Id type);
-
QSet<Core::Id> supportedPlatforms(const Kit *k) const override;
QSet<Core::Id> availableFeatures(const Kit *k) const override;
};
@@ -143,20 +132,18 @@ public:
// DeviceInformation:
// --------------------------------------------------------------------------
-class PROJECTEXPLORER_EXPORT DeviceKitInformation : public KitInformation
+class PROJECTEXPLORER_EXPORT DeviceKitAspect : public KitAspect
{
Q_OBJECT
public:
- DeviceKitInformation();
+ DeviceKitAspect();
- QVariant defaultValue(const Kit *k) const override;
-
- QList<Task> validate(const Kit *k) const override;
+ Tasks validate(const Kit *k) const override;
void fix(Kit *k) override;
void setup(Kit *k) override;
- KitConfigWidget *createConfigWidget(Kit *k) const override;
+ KitAspectWidget *createConfigWidget(Kit *k) const override;
QString displayNamePostfix(const Kit *k) const override;
@@ -171,6 +158,8 @@ public:
static void setDeviceId(Kit *k, Core::Id dataId);
private:
+ QVariant defaultValue(const Kit *k) const;
+
void kitsWereLoaded();
void deviceUpdated(Core::Id dataId);
void devicesChanged();
@@ -178,23 +167,21 @@ private:
};
// --------------------------------------------------------------------------
-// EnvironmentKitInformation:
+// EnvironmentKitAspect:
// --------------------------------------------------------------------------
-class PROJECTEXPLORER_EXPORT EnvironmentKitInformation : public KitInformation
+class PROJECTEXPLORER_EXPORT EnvironmentKitAspect : public KitAspect
{
Q_OBJECT
public:
- EnvironmentKitInformation();
-
- QVariant defaultValue(const Kit *k) const override;
+ EnvironmentKitAspect();
- QList<Task> validate(const Kit *k) const override;
+ Tasks validate(const Kit *k) const override;
void fix(Kit *k) override;
void addToEnvironment(const Kit *k, Utils::Environment &env) const override;
- KitConfigWidget *createConfigWidget(Kit *k) const override;
+ KitAspectWidget *createConfigWidget(Kit *k) const override;
ItemList toUserOutput(const Kit *k) const override;
diff --git a/src/plugins/projectexplorer/kitinformationconfigwidget.cpp b/src/plugins/projectexplorer/kitinformationconfigwidget.cpp
deleted file mode 100644
index a366d84646..0000000000
--- a/src/plugins/projectexplorer/kitinformationconfigwidget.cpp
+++ /dev/null
@@ -1,529 +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 "kitinformationconfigwidget.h"
-
-#include "devicesupport/devicemanager.h"
-#include "devicesupport/devicemanagermodel.h"
-#include "devicesupport/idevicefactory.h"
-#include "projectexplorerconstants.h"
-#include "kit.h"
-#include "kitinformation.h"
-#include "toolchain.h"
-#include "toolchainmanager.h"
-#include "environmentwidget.h"
-
-#include <coreplugin/icore.h>
-#include <coreplugin/variablechooser.h>
-
-#include <utils/algorithm.h>
-#include <utils/fancylineedit.h>
-#include <utils/environment.h>
-#include <utils/qtcassert.h>
-#include <utils/pathchooser.h>
-#include <utils/environmentdialog.h>
-
-#include <QCheckBox>
-#include <QComboBox>
-#include <QDialog>
-#include <QDialogButtonBox>
-#include <QFontMetrics>
-#include <QLabel>
-#include <QPlainTextEdit>
-#include <QPushButton>
-#include <QVBoxLayout>
-
-using namespace Core;
-
-namespace ProjectExplorer {
-namespace Internal {
-
-// --------------------------------------------------------------------------
-// SysRootInformationConfigWidget:
-// --------------------------------------------------------------------------
-
-SysRootInformationConfigWidget::SysRootInformationConfigWidget(Kit *k, const KitInformation *ki) :
- KitConfigWidget(k, ki)
-{
- m_chooser = new Utils::PathChooser;
- m_chooser->setExpectedKind(Utils::PathChooser::ExistingDirectory);
- m_chooser->setHistoryCompleter(QLatin1String("PE.SysRoot.History"));
- m_chooser->setFileName(SysRootKitInformation::sysRoot(k));
- connect(m_chooser, &Utils::PathChooser::pathChanged,
- this, &SysRootInformationConfigWidget::pathWasChanged);
-}
-
-SysRootInformationConfigWidget::~SysRootInformationConfigWidget()
-{
- delete m_chooser;
-}
-
-QString SysRootInformationConfigWidget::displayName() const
-{
- return tr("Sysroot");
-}
-
-QString SysRootInformationConfigWidget::toolTip() const
-{
- return tr("The root directory of the system image to use.<br>"
- "Leave empty when building for the desktop.");
-}
-
-void SysRootInformationConfigWidget::setPalette(const QPalette &p)
-{
- KitConfigWidget::setPalette(p);
- m_chooser->setOkColor(p.color(QPalette::Active, QPalette::Text));
-}
-
-void SysRootInformationConfigWidget::refresh()
-{
- if (!m_ignoreChange)
- m_chooser->setFileName(SysRootKitInformation::sysRoot(m_kit));
-}
-
-void SysRootInformationConfigWidget::makeReadOnly()
-{
- m_chooser->setReadOnly(true);
-}
-
-QWidget *SysRootInformationConfigWidget::mainWidget() const
-{
- return m_chooser->lineEdit();
-}
-
-QWidget *SysRootInformationConfigWidget::buttonWidget() const
-{
- return m_chooser->buttonAtIndex(0);
-}
-
-void SysRootInformationConfigWidget::pathWasChanged()
-{
- m_ignoreChange = true;
- SysRootKitInformation::setSysRoot(m_kit, m_chooser->fileName());
- m_ignoreChange = false;
-}
-
-// --------------------------------------------------------------------------
-// ToolChainInformationConfigWidget:
-// --------------------------------------------------------------------------
-
-ToolChainInformationConfigWidget::ToolChainInformationConfigWidget(Kit *k, const KitInformation *ki) :
- KitConfigWidget(k, ki)
-{
- m_mainWidget = new QWidget;
- m_mainWidget->setContentsMargins(0, 0, 0, 0);
-
- auto layout = new QGridLayout(m_mainWidget);
- layout->setContentsMargins(0, 0, 0, 0);
- layout->setColumnStretch(1, 2);
-
- int row = 0;
- QList<Core::Id> languageList = ToolChainManager::allLanguages().toList();
- Utils::sort(languageList, [](Core::Id l1, Core::Id l2) {
- return ToolChainManager::displayNameOfLanguageId(l1) < ToolChainManager::displayNameOfLanguageId(l2);
- });
-
- QTC_ASSERT(!languageList.isEmpty(), return);
-
- foreach (Core::Id l, languageList) {
- layout->addWidget(new QLabel(ToolChainManager::displayNameOfLanguageId(l) + ':'), row, 0);
- auto cb = new QComboBox;
- cb->setSizePolicy(QSizePolicy::Ignored, cb->sizePolicy().verticalPolicy());
- cb->setToolTip(toolTip());
-
- m_languageComboboxMap.insert(l, cb);
- layout->addWidget(cb, row, 1);
- ++row;
-
- connect(cb, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
- this, [this, l](int idx) { currentToolChainChanged(l, idx); });
- }
-
- refresh();
-
- m_manageButton = new QPushButton(KitConfigWidget::msgManage());
- m_manageButton->setContentsMargins(0, 0, 0, 0);
- connect(m_manageButton, &QAbstractButton::clicked,
- this, &ToolChainInformationConfigWidget::manageToolChains);
-}
-
-ToolChainInformationConfigWidget::~ToolChainInformationConfigWidget()
-{
- delete m_mainWidget;
- delete m_manageButton;
-}
-
-QString ToolChainInformationConfigWidget::displayName() const
-{
- return tr("Compiler");
-}
-
-QString ToolChainInformationConfigWidget::toolTip() const
-{
- return tr("The compiler to use for building.<br>"
- "Make sure the compiler will produce binaries compatible with the target device, "
- "Qt version and other libraries used.");
-}
-
-void ToolChainInformationConfigWidget::refresh()
-{
- m_ignoreChanges = true;
-
- foreach (Core::Id l, m_languageComboboxMap.keys()) {
- const QList<ToolChain *> ltcList
- = ToolChainManager::toolChains(Utils::equal(&ToolChain::language, l));
-
- QComboBox *cb = m_languageComboboxMap.value(l);
- cb->clear();
- cb->addItem(tr("<No compiler>"), QByteArray());
-
- foreach (ToolChain *tc, ltcList)
- cb->addItem(tc->displayName(), tc->id());
-
- cb->setEnabled(cb->count() > 1 && !m_isReadOnly);
- const int index = indexOf(cb, ToolChainKitInformation::toolChain(m_kit, l));
- cb->setCurrentIndex(index);
- }
- m_ignoreChanges = false;
-}
-
-void ToolChainInformationConfigWidget::makeReadOnly()
-{
- m_isReadOnly = true;
- foreach (Core::Id l, m_languageComboboxMap.keys()) {
- m_languageComboboxMap.value(l)->setEnabled(false);
- }
-}
-
-QWidget *ToolChainInformationConfigWidget::mainWidget() const
-{
- return m_mainWidget;
-}
-
-QWidget *ToolChainInformationConfigWidget::buttonWidget() const
-{
- return m_manageButton;
-}
-
-void ToolChainInformationConfigWidget::manageToolChains()
-{
- ICore::showOptionsDialog(Constants::TOOLCHAIN_SETTINGS_PAGE_ID, buttonWidget());
-}
-
-void ToolChainInformationConfigWidget::currentToolChainChanged(Id language, int idx)
-{
- if (m_ignoreChanges || idx < 0)
- return;
-
- const QByteArray id = m_languageComboboxMap.value(language)->itemData(idx).toByteArray();
- ToolChain *tc = ToolChainManager::findToolChain(id);
- QTC_ASSERT(!tc || tc->language() == language, return);
- if (tc)
- ToolChainKitInformation::setToolChain(m_kit, tc);
- else
- ToolChainKitInformation::clearToolChain(m_kit, language);
-}
-
-int ToolChainInformationConfigWidget::indexOf(QComboBox *cb, const ToolChain *tc)
-{
- const QByteArray id = tc ? tc->id() : QByteArray();
- for (int i = 0; i < cb->count(); ++i) {
- if (id == cb->itemData(i).toByteArray())
- return i;
- }
- return -1;
-}
-
-// --------------------------------------------------------------------------
-// DeviceTypeInformationConfigWidget:
-// --------------------------------------------------------------------------
-
-DeviceTypeInformationConfigWidget::DeviceTypeInformationConfigWidget(Kit *workingCopy, const KitInformation *ki) :
- KitConfigWidget(workingCopy, ki), m_comboBox(new QComboBox)
-{
- for (IDeviceFactory *factory : IDeviceFactory::allDeviceFactories())
- m_comboBox->addItem(factory->displayName(), factory->deviceType().toSetting());
-
- m_comboBox->setToolTip(toolTip());
-
- refresh();
- connect(m_comboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
- this, &DeviceTypeInformationConfigWidget::currentTypeChanged);
-}
-
-DeviceTypeInformationConfigWidget::~DeviceTypeInformationConfigWidget()
-{
- delete m_comboBox;
-}
-
-QWidget *DeviceTypeInformationConfigWidget::mainWidget() const
-{
- return m_comboBox;
-}
-
-QString DeviceTypeInformationConfigWidget::displayName() const
-{
- return tr("Device type");
-}
-
-QString DeviceTypeInformationConfigWidget::toolTip() const
-{
- return tr("The type of device to run applications on.");
-}
-
-void DeviceTypeInformationConfigWidget::refresh()
-{
- Id devType = DeviceTypeKitInformation::deviceTypeId(m_kit);
- if (!devType.isValid())
- m_comboBox->setCurrentIndex(-1);
- for (int i = 0; i < m_comboBox->count(); ++i) {
- if (m_comboBox->itemData(i) == devType.toSetting()) {
- m_comboBox->setCurrentIndex(i);
- break;
- }
- }
-}
-
-void DeviceTypeInformationConfigWidget::makeReadOnly()
-{
- m_comboBox->setEnabled(false);
-}
-
-void DeviceTypeInformationConfigWidget::currentTypeChanged(int idx)
-{
- Id type = idx < 0 ? Id() : Id::fromSetting(m_comboBox->itemData(idx));
- DeviceTypeKitInformation::setDeviceTypeId(m_kit, type);
-}
-
-// --------------------------------------------------------------------------
-// DeviceInformationConfigWidget:
-// --------------------------------------------------------------------------
-
-DeviceInformationConfigWidget::DeviceInformationConfigWidget(Kit *workingCopy, const KitInformation *ki) :
- KitConfigWidget(workingCopy, ki),
- m_comboBox(new QComboBox),
- m_model(new DeviceManagerModel(DeviceManager::instance()))
-{
- m_comboBox->setSizePolicy(QSizePolicy::Ignored, m_comboBox->sizePolicy().verticalPolicy());
- m_comboBox->setModel(m_model);
-
- m_manageButton = new QPushButton(KitConfigWidget::msgManage());
-
- refresh();
- m_comboBox->setToolTip(toolTip());
-
- connect(m_model, &QAbstractItemModel::modelAboutToBeReset,
- this, &DeviceInformationConfigWidget::modelAboutToReset);
- connect(m_model, &QAbstractItemModel::modelReset,
- this, &DeviceInformationConfigWidget::modelReset);
- connect(m_comboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
- this, &DeviceInformationConfigWidget::currentDeviceChanged);
- connect(m_manageButton, &QAbstractButton::clicked,
- this, &DeviceInformationConfigWidget::manageDevices);
-}
-
-DeviceInformationConfigWidget::~DeviceInformationConfigWidget()
-{
- delete m_comboBox;
- delete m_model;
- delete m_manageButton;
-}
-
-QWidget *DeviceInformationConfigWidget::mainWidget() const
-{
- return m_comboBox;
-}
-
-QString DeviceInformationConfigWidget::displayName() const
-{
- return tr("Device");
-}
-
-QString DeviceInformationConfigWidget::toolTip() const
-{
- return tr("The device to run the applications on.");
-}
-
-void DeviceInformationConfigWidget::refresh()
-{
- m_model->setTypeFilter(DeviceTypeKitInformation::deviceTypeId(m_kit));
- m_comboBox->setCurrentIndex(m_model->indexOf(DeviceKitInformation::device(m_kit)));
-}
-
-void DeviceInformationConfigWidget::makeReadOnly()
-{
- m_comboBox->setEnabled(false);
-}
-
-QWidget *DeviceInformationConfigWidget::buttonWidget() const
-{
- return m_manageButton;
-}
-
-void DeviceInformationConfigWidget::manageDevices()
-{
- ICore::showOptionsDialog(Constants::DEVICE_SETTINGS_PAGE_ID, buttonWidget());
-}
-
-void DeviceInformationConfigWidget::modelAboutToReset()
-{
- m_selectedId = m_model->deviceId(m_comboBox->currentIndex());
- m_ignoreChange = true;
-}
-
-void DeviceInformationConfigWidget::modelReset()
-{
- m_comboBox->setCurrentIndex(m_model->indexForId(m_selectedId));
- m_ignoreChange = false;
-}
-
-void DeviceInformationConfigWidget::currentDeviceChanged()
-{
- if (m_ignoreChange)
- return;
- DeviceKitInformation::setDeviceId(m_kit, m_model->deviceId(m_comboBox->currentIndex()));
-}
-
-// --------------------------------------------------------------------
-// KitEnvironmentConfigWidget:
-// --------------------------------------------------------------------
-
-KitEnvironmentConfigWidget::KitEnvironmentConfigWidget(Kit *workingCopy, const KitInformation *ki) :
- KitConfigWidget(workingCopy, ki),
- m_summaryLabel(new QLabel),
- m_manageButton(new QPushButton),
- m_mainWidget(new QWidget)
-{
- auto *layout = new QVBoxLayout;
- layout->setContentsMargins(0, 0, 0, 0);
- layout->addWidget(m_summaryLabel);
- if (Utils::HostOsInfo::isWindowsHost())
- initMSVCOutputSwitch(layout);
-
- m_mainWidget->setLayout(layout);
-
- refresh();
- m_manageButton->setText(tr("Change..."));
- connect(m_manageButton, &QAbstractButton::clicked,
- this, &KitEnvironmentConfigWidget::editEnvironmentChanges);
-}
-
-QWidget *KitEnvironmentConfigWidget::mainWidget() const
-{
- return m_mainWidget;
-}
-
-QString KitEnvironmentConfigWidget::displayName() const
-{
- return tr("Environment");
-}
-
-QString KitEnvironmentConfigWidget::toolTip() const
-{
- return tr("Additional build environment settings when using this kit.");
-}
-
-void KitEnvironmentConfigWidget::refresh()
-{
- const QList<Utils::EnvironmentItem> changes = currentEnvironment();
- QString shortSummary = Utils::EnvironmentItem::toStringList(changes).join(QLatin1String("; "));
- QFontMetrics fm(m_summaryLabel->font());
- shortSummary = fm.elidedText(shortSummary, Qt::ElideRight, m_summaryLabel->width());
- m_summaryLabel->setText(shortSummary.isEmpty() ? tr("No changes to apply.") : shortSummary);
-}
-
-void KitEnvironmentConfigWidget::makeReadOnly()
-{
- m_manageButton->setEnabled(false);
-}
-
-QList<Utils::EnvironmentItem> KitEnvironmentConfigWidget::currentEnvironment() const
-{
- QList<Utils::EnvironmentItem> changes = EnvironmentKitInformation::environmentChanges(m_kit);
-
- if (Utils::HostOsInfo::isWindowsHost()) {
- const Utils::EnvironmentItem forceMSVCEnglishItem("VSLANG", "1033");
- if (changes.indexOf(forceMSVCEnglishItem) >= 0) {
- m_vslangCheckbox->setCheckState(Qt::Checked);
- changes.removeAll(forceMSVCEnglishItem);
- }
- }
-
- Utils::sort(changes, [](const Utils::EnvironmentItem &lhs, const Utils::EnvironmentItem &rhs)
- { return QString::localeAwareCompare(lhs.name, rhs.name) < 0; });
- return changes;
-}
-
-void KitEnvironmentConfigWidget::editEnvironmentChanges()
-{
- bool ok;
- Utils::MacroExpander *expander = m_kit->macroExpander();
- Utils::EnvironmentDialog::Polisher polisher = [expander](QWidget *w) {
- Core::VariableChooser::addSupportForChildWidgets(w, expander);
- };
- QList<Utils::EnvironmentItem>
- changes = Utils::EnvironmentDialog::getEnvironmentItems(&ok,
- m_summaryLabel,
- currentEnvironment(),
- QString(),
- polisher);
- if (!ok)
- return;
-
- if (Utils::HostOsInfo::isWindowsHost()) {
- const Utils::EnvironmentItem forceMSVCEnglishItem("VSLANG", "1033");
- if (m_vslangCheckbox->isChecked() && changes.indexOf(forceMSVCEnglishItem) < 0)
- changes.append(forceMSVCEnglishItem);
- }
-
- EnvironmentKitInformation::setEnvironmentChanges(m_kit, changes);
-}
-
-QWidget *KitEnvironmentConfigWidget::buttonWidget() const
-{
- return m_manageButton;
-}
-
-void KitEnvironmentConfigWidget::initMSVCOutputSwitch(QVBoxLayout *layout)
-{
- m_vslangCheckbox = new QCheckBox(tr("Force UTF-8 MSVC compiler output"));
- layout->addWidget(m_vslangCheckbox);
- m_vslangCheckbox->setToolTip(tr("Either switches MSVC to English or keeps the language and "
- "just forces UTF-8 output (may vary depending on the used MSVC "
- "compiler)."));
- connect(m_vslangCheckbox, &QCheckBox::toggled, this, [this](bool checked) {
- QList<Utils::EnvironmentItem> changes
- = EnvironmentKitInformation::environmentChanges(m_kit);
- const Utils::EnvironmentItem forceMSVCEnglishItem("VSLANG", "1033");
- if (!checked && changes.indexOf(forceMSVCEnglishItem) >= 0)
- changes.removeAll(forceMSVCEnglishItem);
- if (checked && changes.indexOf(forceMSVCEnglishItem) < 0)
- changes.append(forceMSVCEnglishItem);
- EnvironmentKitInformation::setEnvironmentChanges(m_kit, changes);
- });
-}
-
-} // namespace Internal
-} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/kitinformationconfigwidget.h b/src/plugins/projectexplorer/kitinformationconfigwidget.h
deleted file mode 100644
index 5fb6016d8c..0000000000
--- a/src/plugins/projectexplorer/kitinformationconfigwidget.h
+++ /dev/null
@@ -1,196 +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 "kitconfigwidget.h"
-#include "toolchain.h"
-
-#include <coreplugin/id.h>
-
-#include <utils/environment.h>
-
-QT_BEGIN_NAMESPACE
-class QCheckBox;
-class QComboBox;
-class QLabel;
-class QPlainTextEdit;
-class QPushButton;
-class QVBoxLayout;
-QT_END_NAMESPACE
-
-namespace Utils { class PathChooser; }
-
-namespace ProjectExplorer {
-
-class DeviceManagerModel;
-
-namespace Internal {
-
-// --------------------------------------------------------------------------
-// SysRootInformationConfigWidget:
-// --------------------------------------------------------------------------
-
-class SysRootInformationConfigWidget : public KitConfigWidget
-{
- Q_OBJECT
-
-public:
- SysRootInformationConfigWidget(Kit *k, const KitInformation *ki);
- ~SysRootInformationConfigWidget() override;
-
- QString displayName() const override;
- void refresh() override;
- void makeReadOnly() override;
- QWidget *buttonWidget() const override;
- QWidget *mainWidget() const override;
- QString toolTip() const override;
-
- void setPalette(const QPalette &p) override;
-
-private:
- void pathWasChanged();
-
- Utils::PathChooser *m_chooser;
- bool m_ignoreChange = false;
-};
-
-// --------------------------------------------------------------------------
-// ToolChainInformationConfigWidget:
-// --------------------------------------------------------------------------
-
-class ToolChainInformationConfigWidget : public KitConfigWidget
-{
- Q_OBJECT
-
-public:
- ToolChainInformationConfigWidget(Kit *k, const KitInformation *ki);
- ~ToolChainInformationConfigWidget() override;
-
- QString displayName() const override;
- void refresh() override;
- void makeReadOnly() override;
- QWidget *mainWidget() const override;
- QWidget *buttonWidget() const override;
- QString toolTip() const override;
-
-private:
- void manageToolChains();
- void currentToolChainChanged(Core::Id language, int idx);
-
- int indexOf(QComboBox *cb, const ToolChain *tc);
-
- QWidget *m_mainWidget = nullptr;
- QPushButton *m_manageButton = nullptr;
- QHash<Core::Id, QComboBox *> m_languageComboboxMap;
- bool m_ignoreChanges = false;
- bool m_isReadOnly = false;
-};
-
-// --------------------------------------------------------------------------
-// DeviceTypeInformationConfigWidget:
-// --------------------------------------------------------------------------
-
-class DeviceTypeInformationConfigWidget : public KitConfigWidget
-{
- Q_OBJECT
-
-public:
- DeviceTypeInformationConfigWidget(Kit *workingCopy, const KitInformation *ki);
- ~DeviceTypeInformationConfigWidget() override;
-
- QWidget *mainWidget() const override;
- QString displayName() const override;
- QString toolTip() const override;
- void refresh() override;
- void makeReadOnly() override;
-
-private:
- void currentTypeChanged(int idx);
-
- QComboBox *m_comboBox;
-};
-
-// --------------------------------------------------------------------------
-// DeviceInformationConfigWidget:
-// --------------------------------------------------------------------------
-
-class DeviceInformationConfigWidget : public KitConfigWidget
-{
- Q_OBJECT
-
-public:
- DeviceInformationConfigWidget(Kit *workingCopy, const KitInformation *ki);
- ~DeviceInformationConfigWidget() override;
-
- QWidget *mainWidget() const override;
- QWidget *buttonWidget() const override;
- QString displayName() const override;
- QString toolTip() const override;
- void refresh() override;
- void makeReadOnly() override;
-
-private:
- void manageDevices();
- void modelAboutToReset();
- void modelReset();
- void currentDeviceChanged();
-
- bool m_isReadOnly = false;
- bool m_ignoreChange = false;
- QComboBox *m_comboBox;
- QPushButton *m_manageButton;
- DeviceManagerModel *m_model;
- Core::Id m_selectedId;
-};
-
-class KitEnvironmentConfigWidget : public KitConfigWidget
-{
- Q_OBJECT
-
-public:
- KitEnvironmentConfigWidget(Kit *workingCopy, const KitInformation *ki);
-
- QWidget *mainWidget() const override;
- QWidget *buttonWidget() const override;
- QString displayName() const override;
- QString toolTip() const override;
- void refresh() override;
- void makeReadOnly() override;
-
-private:
- void editEnvironmentChanges();
- QList<Utils::EnvironmentItem> currentEnvironment() const;
-
- void initMSVCOutputSwitch(QVBoxLayout *layout);
-
- QLabel *m_summaryLabel;
- QPushButton *m_manageButton;
- QCheckBox *m_vslangCheckbox;
- QWidget *m_mainWidget;
-};
-
-} // namespace Internal
-} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/kitmanager.cpp b/src/plugins/projectexplorer/kitmanager.cpp
index 0b6e5a8b16..91d04b6f5d 100644
--- a/src/plugins/projectexplorer/kitmanager.cpp
+++ b/src/plugins/projectexplorer/kitmanager.cpp
@@ -25,12 +25,16 @@
#include "kitmanager.h"
+#include "abi.h"
#include "devicesupport/idevicefactory.h"
#include "kit.h"
#include "kitfeatureprovider.h"
+#include "kitinformation.h"
#include "kitmanagerconfigwidget.h"
#include "project.h"
+#include "projectexplorerconstants.h"
#include "task.h"
+#include "toolchainmanager.h"
#include <coreplugin/icore.h>
@@ -40,24 +44,37 @@
#include <utils/qtcassert.h>
#include <utils/stringutils.h>
+#include <QHash>
#include <QSettings>
+#include <QStyle>
using namespace Core;
using namespace Utils;
using namespace ProjectExplorer::Internal;
namespace ProjectExplorer {
+
+class KitList
+{
+public:
+ Core::Id defaultKit;
+ std::vector<std::unique_ptr<Kit>> kits;
+};
+
+static KitList restoreKitsHelper(const Utils::FilePath &fileName);
+
namespace Internal {
const char KIT_DATA_KEY[] = "Profile.";
const char KIT_COUNT_KEY[] = "Profile.Count";
const char KIT_FILE_VERSION_KEY[] = "Version";
const char KIT_DEFAULT_KEY[] = "Profile.Default";
+const char KIT_IRRELEVANT_ASPECTS_KEY[] = "Kit.IrrelevantAspects";
const char KIT_FILENAME[] = "/profiles.xml";
-static FileName settingsFileName()
+static FilePath settingsFileName()
{
- return FileName::fromString(ICore::userResourcePath() + KIT_FILENAME);
+ return FilePath::fromString(ICore::userResourcePath() + KIT_FILENAME);
}
// --------------------------------------------------------------------------
@@ -71,9 +88,37 @@ public:
bool m_initialized = false;
std::vector<std::unique_ptr<Kit>> m_kitList;
std::unique_ptr<PersistentSettingsWriter> m_writer;
+ QSet<Id> m_irrelevantAspects;
+
+ void addKitAspect(KitAspect *ki)
+ {
+ QTC_ASSERT(!m_aspectList.contains(ki), return);
+ m_aspectList.append(ki);
+ m_aspectListIsSorted = false;
+ }
- // Sorted by priority, in descending order.
- std::vector<std::unique_ptr<KitInformation>> m_informationList;
+ void removeKitAspect(KitAspect *ki)
+ {
+ int removed = m_aspectList.removeAll(ki);
+ QTC_CHECK(removed == 1);
+ }
+
+ const QList<KitAspect *> kitAspects()
+ {
+ if (!m_aspectListIsSorted) {
+ Utils::sort(m_aspectList, [](const KitAspect *a, const KitAspect *b) {
+ return a->priority() > b->priority();
+ });
+ m_aspectListIsSorted = true;
+ }
+ return m_aspectList;
+ }
+
+private:
+ // Sorted by priority, in descending order...
+ QList<KitAspect *> m_aspectList;
+ // ... if this here is set:
+ bool m_aspectListIsSorted = true;
};
} // namespace Internal
@@ -87,11 +132,12 @@ static KitManager *m_instance = nullptr;
KitManager *KitManager::instance()
{
+ if (!m_instance)
+ m_instance = new KitManager;
return m_instance;
}
-KitManager::KitManager(QObject *parent)
- : QObject(parent)
+KitManager::KitManager()
{
d = new KitManagerPrivate;
QTC_CHECK(!m_instance);
@@ -104,6 +150,14 @@ KitManager::KitManager(QObject *parent)
connect(this, &KitManager::kitUpdated, this, &KitManager::kitsChanged);
}
+void KitManager::destroy()
+{
+ delete d;
+ d = nullptr;
+ delete m_instance;
+ m_instance = nullptr;
+}
+
void KitManager::restoreKits()
{
QTC_ASSERT(!d->m_initialized, return );
@@ -114,7 +168,7 @@ void KitManager::restoreKits()
Core::Id defaultUserKit;
std::vector<std::unique_ptr<Kit>> kitsToCheck;
{
- KitList userKits = restoreKits(settingsFileName());
+ KitList userKits = restoreKitsHelper(settingsFileName());
defaultUserKit = userKits.defaultKit;
for (auto &k : userKits.kits) {
@@ -129,8 +183,8 @@ void KitManager::restoreKits()
// read all kits from SDK
{
- KitList system
- = restoreKits(FileName::fromString(ICore::installerResourcePath() + KIT_FILENAME));
+ KitList system = restoreKitsHelper
+ (FilePath::fromString(ICore::installerResourcePath() + KIT_FILENAME));
// SDK kits need to get updated with the user-provided extra settings:
for (auto &current : system.kits) {
@@ -153,11 +207,11 @@ void KitManager::restoreKits()
Kit *ptr = i->get();
// Overwrite settings that the SDK sets to those values:
- foreach (const KitInformation *ki, KitManager::kitInformation()) {
+ for (const KitAspect *aspect : KitManager::kitAspects()) {
// Copy sticky settings over:
- if (ptr->isSticky(ki->id())) {
- ptr->setValue(ki->id(), toStore->value(ki->id()));
- ptr->setSticky(ki->id(), true);
+ if (ptr->isSticky(aspect->id())) {
+ ptr->setValue(aspect->id(), toStore->value(aspect->id()));
+ ptr->setSticky(aspect->id(), true);
}
}
toStore = std::move(*i);
@@ -171,16 +225,69 @@ void KitManager::restoreKits()
// Delete all loaded autodetected kits that were not rediscovered:
kitsToCheck.clear();
- if (resultList.size() == 0) {
- auto defaultKit = std::make_unique<Kit>(); // One kit using default values
- defaultKit->setUnexpandedDisplayName(tr("Desktop"));
- defaultKit->setSdkProvided(false);
- defaultKit->setAutoDetected(false);
+ if (resultList.empty()) {
+ // No kits exist yet, so let's try to autoconfigure some from the toolchains we know.
+ // We consider only host toolchains, because for other ones we lack the knowledge how to
+ // map them to their respective device type.
+ static const auto isHostToolchain = [](const ToolChain *tc) {
+ static const Abi hostAbi = Abi::hostAbi();
+ const Abi tcAbi = tc->targetAbi();
+ return tcAbi.os() == hostAbi.os() && tcAbi.architecture() == hostAbi.architecture()
+ && (tcAbi.os() != Abi::LinuxOS || tcAbi.osFlavor() == hostAbi.osFlavor());
+ };
+ const QList<ToolChain *> allToolchains = ToolChainManager::toolChains(isHostToolchain);
+ QHash<Abi, QHash<Core::Id, ToolChain *>> uniqueToolchains;
+
+ // On Linux systems, we usually detect a plethora of same-ish toolchains. The following
+ // algorithm gives precedence to icecc and ccache and otherwise simply chooses the one with
+ // the shortest path. This should also take care of ensuring matching C/C++ pairs.
+ // TODO: This should not need to be done here. Instead, it should be a convenience
+ // operation on some lower level, e.g. in the toolchain class(es).
+ // Also, we shouldn't detect so many doublets in the first place.
+ for (ToolChain * const tc : allToolchains) {
+ ToolChain *&bestTc = uniqueToolchains[tc->targetAbi()][tc->language()];
+ if (!bestTc) {
+ bestTc = tc;
+ continue;
+ }
+ const QString bestFilePath = bestTc->compilerCommand().toString();
+ const QString currentFilePath = tc->compilerCommand().toString();
+ if (bestFilePath.contains("icecc"))
+ continue;
+ if (currentFilePath.contains("icecc")) {
+ bestTc = tc;
+ continue;
+ }
- defaultKit->setup();
+ if (bestFilePath.contains("ccache"))
+ continue;
+ if (currentFilePath.contains("ccache")) {
+ bestTc = tc;
+ continue;
+ }
+ if (bestFilePath.length() > currentFilePath.length())
+ bestTc = tc;
+ }
- completeKit(defaultKit.get()); // Store manual kits
- resultList.emplace_back(std::move(defaultKit));
+ int maxWeight = 0;
+ for (auto it = uniqueToolchains.cbegin(); it != uniqueToolchains.cend(); ++it) {
+ auto kit = std::make_unique<Kit>();
+ kit->setSdkProvided(false);
+ kit->setAutoDetected(false); // TODO: Why false? What does autodetected mean here?
+ for (ToolChain * const tc : it.value())
+ ToolChainKitAspect::setToolChain(kit.get(), tc);
+ kit->setUnexpandedDisplayName(tr("Desktop (%1)").arg(it.key().toString()));
+ kit->setup();
+ if (kit->weight() < maxWeight)
+ continue;
+ if (kit->weight() > maxWeight) {
+ maxWeight = kit->weight();
+ resultList.clear();
+ }
+ resultList.emplace_back(std::move(kit));
+ }
+ if (resultList.size() == 1)
+ resultList.front()->setUnexpandedDisplayName(tr("Desktop"));
}
Kit *k = Utils::findOrDefault(resultList, Utils::equal(&Kit::id, defaultUserKit));
@@ -191,19 +298,17 @@ void KitManager::restoreKits()
d->m_writer = std::make_unique<PersistentSettingsWriter>(settingsFileName(), "QtCreatorProfiles");
d->m_initialized = true;
- emit kitsLoaded();
- emit kitsChanged();
+ emit m_instance->kitsLoaded();
+ emit m_instance->kitsChanged();
}
KitManager::~KitManager()
{
- delete d;
- d = nullptr;
- m_instance = nullptr;
}
void KitManager::saveKits()
{
+ QTC_ASSERT(d, return);
if (!d->m_writer) // ignore save requests while we are not initialized.
return;
@@ -221,6 +326,8 @@ void KitManager::saveKits()
data.insert(QLatin1String(KIT_COUNT_KEY), count);
data.insert(QLatin1String(KIT_DEFAULT_KEY),
d->m_defaultKit ? QString::fromLatin1(d->m_defaultKit->id().name()) : QString());
+ data.insert(KIT_IRRELEVANT_ASPECTS_KEY,
+ transform<QVariantList>(d->m_irrelevantAspects, &Id::toSetting));
d->m_writer->save(data, ICore::mainWindow());
}
@@ -229,28 +336,27 @@ bool KitManager::isLoaded()
return d->m_initialized;
}
-void KitManager::registerKitInformation(std::unique_ptr<KitInformation> &&ki)
+void KitManager::registerKitAspect(KitAspect *ki)
{
- QTC_ASSERT(ki->id().isValid(), return );
- QTC_ASSERT(!Utils::contains(d->m_informationList, ki.get()), return );
-
- auto it = std::lower_bound(std::begin(d->m_informationList),
- std::end(d->m_informationList),
- ki,
- [](const std::unique_ptr<KitInformation> &a,
- const std::unique_ptr<KitInformation> &b) {
- return a->priority() > b->priority();
- });
- d->m_informationList.insert(it, std::move(ki));
+ instance();
+ QTC_ASSERT(d, return);
+ d->addKitAspect(ki);
- foreach (Kit *k, kits()) {
- if (!k->hasValue(ki->id()))
- k->setValue(ki->id(), ki->defaultValue(k));
- else
- ki->fix(k);
- }
+ // Adding this aspect to possibly already existing kits is currently not
+ // needed here as kits are only created after all aspects are created
+ // in *Plugin::initialize().
+ // Make sure we notice when this assumption breaks:
+ QTC_CHECK(d->m_kitList.empty());
+}
- return;
+void KitManager::deregisterKitAspect(KitAspect *ki)
+{
+ // Happens regularly for the aspects from the ProjectExplorerPlugin as these
+ // are destroyed after the manual call to KitManager::destroy() there, but as
+ // this here is just for sanity reasons that the KitManager does not access
+ // a destroyed aspect, a destroyed KitManager is not a problem.
+ if (d)
+ d->removeKitAspect(ki);
}
QSet<Id> KitManager::supportedPlatforms()
@@ -291,7 +397,7 @@ QList<Kit *> KitManager::sortKits(const QList<Kit *> &kits)
return Utils::transform(sortList, &QPair<QString, Kit *>::second);
}
-KitManager::KitList KitManager::restoreKits(const FileName &fileName)
+static KitList restoreKitsHelper(const FilePath &fileName)
{
KitList result;
@@ -336,6 +442,9 @@ KitManager::KitList KitManager::restoreKits(const FileName &fileName)
if (Utils::contains(result.kits, [id](const std::unique_ptr<Kit> &k) { return k->id() == id; }))
result.defaultKit = id;
+ const auto it = data.constFind(KIT_IRRELEVANT_ASPECTS_KEY);
+ if (it != data.constEnd())
+ d->m_irrelevantAspects = transform<QSet<Id>>(it.value().toList(), &Id::fromSetting);
return result;
}
@@ -366,20 +475,19 @@ Kit *KitManager::defaultKit()
return d->m_defaultKit;
}
-QList<KitInformation *> KitManager::kitInformation()
+const QList<KitAspect *> KitManager::kitAspects()
{
- return Utils::toRawPointer<QList>(d->m_informationList);
+ return d->kitAspects();
}
-KitManagerConfigWidget *KitManager::createConfigWidget(Kit *k)
+const QSet<Id> KitManager::irrelevantAspects()
{
- auto *result = new KitManagerConfigWidget(k);
- foreach (KitInformation *ki, kitInformation())
- result->addConfigWidget(ki->createConfigWidget(result->workingCopy()));
-
- result->updateVisibility();
+ return d->m_irrelevantAspects;
+}
- return result;
+void KitManager::setIrrelevantAspects(const QSet<Id> &aspects)
+{
+ d->m_irrelevantAspects = aspects;
}
void KitManager::notifyAboutUpdate(Kit *k)
@@ -393,18 +501,16 @@ void KitManager::notifyAboutUpdate(Kit *k)
emit m_instance->unmanagedKitUpdated(k);
}
-bool KitManager::registerKit(std::unique_ptr<Kit> &&k)
+Kit *KitManager::registerKit(const std::function<void (Kit *)> &init, Core::Id id)
{
- QTC_ASSERT(isLoaded(), return false);
+ QTC_ASSERT(isLoaded(), return nullptr);
- if (!k)
- return true;
-
- QTC_ASSERT(k->id().isValid(), return false);
+ auto k = std::make_unique<Kit>(id);
+ QTC_ASSERT(k->id().isValid(), return nullptr);
Kit *kptr = k.get();
- if (Utils::contains(d->m_kitList, kptr))
- return false;
+ if (init)
+ init(kptr);
// make sure we have all the information in our kits:
completeKit(kptr);
@@ -415,7 +521,7 @@ bool KitManager::registerKit(std::unique_ptr<Kit> &&k)
setDefaultKit(kptr);
emit m_instance->kitAdded(kptr);
- return true;
+ return kptr;
}
void KitManager::deregisterKit(Kit *k)
@@ -444,61 +550,106 @@ void KitManager::completeKit(Kit *k)
{
QTC_ASSERT(k, return);
KitGuard g(k);
- for (const std::unique_ptr<KitInformation> &ki : d->m_informationList) {
+ for (KitAspect *ki : d->kitAspects()) {
ki->upgrade(k);
if (!k->hasValue(ki->id()))
- k->setValue(ki->id(), ki->defaultValue(k));
+ ki->setup(k);
else
ki->fix(k);
}
}
// --------------------------------------------------------------------
-// KitInformation:
+// KitAspect:
// --------------------------------------------------------------------
-void KitInformation::addToEnvironment(const Kit *k, Environment &env) const
+KitAspect::KitAspect()
+{
+ KitManager::registerKitAspect(this);
+}
+
+KitAspect::~KitAspect()
+{
+ KitManager::deregisterKitAspect(this);
+}
+
+int KitAspect::weight(const Kit *k) const
+{
+ return k->value(id()).isValid() ? 1 : 0;
+}
+
+void KitAspect::addToEnvironment(const Kit *k, Environment &env) const
{
Q_UNUSED(k);
Q_UNUSED(env);
}
-IOutputParser *KitInformation::createOutputParser(const Kit *k) const
+IOutputParser *KitAspect::createOutputParser(const Kit *k) const
{
Q_UNUSED(k);
return nullptr;
}
-QString KitInformation::displayNamePostfix(const Kit *k) const
+QString KitAspect::displayNamePostfix(const Kit *k) const
{
Q_UNUSED(k);
return QString();
}
-QSet<Id> KitInformation::supportedPlatforms(const Kit *k) const
+QSet<Id> KitAspect::supportedPlatforms(const Kit *k) const
{
Q_UNUSED(k);
return QSet<Id>();
}
-QSet<Id> KitInformation::availableFeatures(const Kit *k) const
+QSet<Id> KitAspect::availableFeatures(const Kit *k) const
{
Q_UNUSED(k);
return QSet<Id>();
}
-void KitInformation::addToMacroExpander(Kit *k, MacroExpander *expander) const
+void KitAspect::addToMacroExpander(Kit *k, MacroExpander *expander) const
{
Q_UNUSED(k);
Q_UNUSED(expander);
}
-void KitInformation::notifyAboutUpdate(Kit *k)
+void KitAspect::notifyAboutUpdate(Kit *k)
{
if (k)
k->kitUpdated();
}
+KitAspectWidget::KitAspectWidget(Kit *kit, const KitAspect *ki) : m_kit(kit),
+ m_kitInformation(ki), m_isSticky(kit->isSticky(ki->id()))
+{ }
+
+Core::Id KitAspectWidget::kitInformationId() const
+{
+ return m_kitInformation->id();
+}
+
+QString KitAspectWidget::msgManage()
+{
+ return tr("Manage...");
+}
+
+void KitAspectWidget::setPalette(const QPalette &p)
+{
+ if (mainWidget())
+ mainWidget()->setPalette(p);
+ if (buttonWidget())
+ buttonWidget()->setPalette(p);
+}
+
+void KitAspectWidget::setStyle(QStyle *s)
+{
+ if (mainWidget())
+ mainWidget()->setStyle(s);
+ if (buttonWidget())
+ buttonWidget()->setStyle(s);
+}
+
// --------------------------------------------------------------------
// KitFeatureProvider:
// --------------------------------------------------------------------
diff --git a/src/plugins/projectexplorer/kitmanager.h b/src/plugins/projectexplorer/kitmanager.h
index 189dc1c216..4cc80230c6 100644
--- a/src/plugins/projectexplorer/kitmanager.h
+++ b/src/plugins/projectexplorer/kitmanager.h
@@ -34,34 +34,38 @@
#include <QObject>
#include <QPair>
+#include <QSet>
#include <functional>
+QT_BEGIN_NAMESPACE
+class QStyle;
+QT_END_NAMESPACE
+
namespace Utils {
class Environment;
-class FileName;
+class FilePath;
class MacroExpander;
} // namespace Utils
namespace ProjectExplorer {
class Task;
class IOutputParser;
-class KitConfigWidget;
+class KitAspectWidget;
class KitManager;
namespace Internal {
-class KitManagerConfigWidget;
class KitModel;
} // namespace Internal
/**
- * @brief The KitInformation class
+ * @brief The KitAspect class
*
* One piece of information stored in the kit.
*
- * This needs to get registered with the \a KitManager.
+ * They auto-register with the \a KitManager for their life time
*/
-class PROJECTEXPLORER_EXPORT KitInformation : public QObject
+class PROJECTEXPLORER_EXPORT KitAspect : public QObject
{
Q_OBJECT
@@ -71,11 +75,12 @@ public:
Core::Id id() const { return m_id; }
int priority() const { return m_priority; }
-
- virtual QVariant defaultValue(const Kit *) const = 0;
+ QString displayName() const { return m_displayName; }
+ QString description() const { return m_description; }
+ bool isEssential() const { return m_essential; }
// called to find issues with the kit
- virtual QList<Task> validate(const Kit *) const = 0;
+ virtual Tasks validate(const Kit *) const = 0;
// called after restoring a kit, so upgrading of kit information settings can be done
virtual void upgrade(Kit *) { return; }
// called to fix issues with this kitinformation. Does not modify the rest of the kit.
@@ -83,9 +88,11 @@ public:
// called on initial setup of a kit.
virtual void setup(Kit *) { return; }
+ virtual int weight(const Kit *k) const;
+
virtual ItemList toUserOutput(const Kit *) const = 0;
- virtual KitConfigWidget *createConfigWidget(Kit *) const = 0;
+ virtual KitAspectWidget *createConfigWidget(Kit *) const = 0;
virtual void addToEnvironment(const Kit *k, Utils::Environment &env) const;
virtual IOutputParser *createOutputParser(const Kit *k) const;
@@ -97,14 +104,59 @@ public:
virtual void addToMacroExpander(ProjectExplorer::Kit *kit, Utils::MacroExpander *expander) const;
+ virtual bool isApplicableToKit(const Kit *) const { return true; }
+
protected:
+ KitAspect();
+ ~KitAspect();
+
void setId(Core::Id id) { m_id = id; }
+ void setDisplayName(const QString &name) { m_displayName = name; }
+ void setDescription(const QString &desc) { m_description = desc; }
+ void makeEssential() { m_essential = true; }
void setPriority(int priority) { m_priority = priority; }
void notifyAboutUpdate(Kit *k);
private:
+ QString m_displayName;
+ QString m_description;
Core::Id m_id;
int m_priority = 0; // The higher the closer to the top.
+ bool m_essential = false;
+};
+
+class PROJECTEXPLORER_EXPORT KitAspectWidget : public QObject
+{
+ Q_OBJECT
+
+public:
+ KitAspectWidget(Kit *kit, const KitAspect *ki);
+
+ Core::Id kitInformationId() const;
+
+ virtual void makeReadOnly() = 0;
+ virtual void refresh() = 0;
+ bool visibleInKit() { return m_kitInformation->isApplicableToKit(m_kit); }
+
+ virtual QWidget *mainWidget() const = 0;
+ virtual QWidget *buttonWidget() const { return nullptr; }
+
+ bool isSticky() const { return m_isSticky; }
+
+ static QString msgManage();
+
+ Kit *kit() const { return m_kit; }
+
+ virtual void setPalette(const QPalette &p);
+ virtual void setStyle(QStyle *s);
+
+signals:
+ void dirty();
+
+protected:
+ Kit *m_kit;
+ const KitAspect *m_kitInformation;
+ bool m_isSticky;
};
class PROJECTEXPLORER_EXPORT KitManager : public QObject
@@ -120,19 +172,14 @@ public:
static Kit *kit(Core::Id id);
static Kit *defaultKit();
- static QList<KitInformation *> kitInformation();
+ static const QList<KitAspect *> kitAspects();
+ static const QSet<Core::Id> irrelevantAspects();
+ static void setIrrelevantAspects(const QSet<Core::Id> &aspects);
- static Internal::KitManagerConfigWidget *createConfigWidget(Kit *k);
-
- static bool registerKit(std::unique_ptr<Kit> &&k);
+ static Kit *registerKit(const std::function<void(Kit *)> &init, Core::Id id = {});
static void deregisterKit(Kit *k);
static void setDefaultKit(Kit *k);
- template<typename KI, typename... Args>
- static void registerKitInformation(Args&&... args) {
- registerKitInformation(std::make_unique<KI>(std::forward<Args>(args)...));
- }
-
static QSet<Core::Id> supportedPlatforms();
static QSet<Core::Id> availableFeatures(Core::Id platformId);
@@ -157,20 +204,16 @@ signals:
void kitsLoaded();
private:
- explicit KitManager(QObject *parent = nullptr);
+ KitManager();
+
+ static void destroy();
- static void registerKitInformation(std::unique_ptr<KitInformation> &&ki);
+ static void registerKitAspect(KitAspect *ki);
+ static void deregisterKitAspect(KitAspect *ki);
// Make sure the this is only called after all
- // KitInformation are registered!
- void restoreKits();
- class KitList
- {
- public:
- Core::Id defaultKit;
- std::vector<std::unique_ptr<Kit>> kits;
- };
- KitList restoreKits(const Utils::FileName &fileName);
+ // KitAspects are registered!
+ static void restoreKits();
static void notifyAboutUpdate(Kit *k);
static void completeKit(Kit *k);
@@ -178,7 +221,7 @@ private:
friend class ProjectExplorerPlugin; // for constructor
friend class Kit;
friend class Internal::KitModel;
- friend class KitInformation; // for notifyAbutUpdate
+ friend class KitAspect; // for notifyAboutUpdate and self-registration
};
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp b/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp
index 473c8455e2..cdd508b078 100644
--- a/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp
+++ b/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp
@@ -24,18 +24,22 @@
****************************************************************************/
#include "kitmanagerconfigwidget.h"
-#include "projectexplorerconstants.h"
+#include "devicesupport/idevicefactory.h"
#include "kit.h"
+#include "kitinformation.h"
#include "kitmanager.h"
+#include "projectexplorerconstants.h"
#include "task.h"
#include <coreplugin/variablechooser.h>
#include <utils/algorithm.h>
#include <utils/detailswidget.h>
-#include <utils/qtcassert.h>
#include <utils/macroexpander.h>
+#include <utils/pathchooser.h>
+#include <utils/qtcassert.h>
+#include <utils/utilsicons.h>
#include <QAction>
#include <QRegularExpression>
@@ -44,7 +48,9 @@
#include <QGridLayout>
#include <QLabel>
#include <QLineEdit>
+#include <QMenu>
#include <QPainter>
+#include <QPushButton>
#include <QToolButton>
#include <QScrollArea>
#include <QSizePolicy>
@@ -92,11 +98,10 @@ KitManagerConfigWidget::KitManagerConfigWidget(Kit *k) :
mainLayout->setMargin(1);
mainLayout->addWidget(inner, 0, 0);
- toolTip = tr("Kit name and icon.");
- label = createLabel(tr("Name:"), toolTip);
+ label = createLabel(tr("Name:"), tr("Kit name and icon."));
m_layout->addWidget(label, 0, LabelColumn, alignment);
- m_iconButton->setToolTip(toolTip);
- auto setIconAction = new QAction(tr("Select Icon File"), this);
+ m_iconButton->setToolTip(tr("Kit icon."));
+ auto setIconAction = new QAction(tr("Select Icon..."), this);
m_iconButton->addAction(setIconAction);
auto resetIconAction = new QAction(tr("Reset to Device Default Icon"), this);
m_iconButton->addAction(resetIconAction);
@@ -121,6 +126,15 @@ KitManagerConfigWidget::KitManagerConfigWidget(Kit *k) :
auto chooser = new Core::VariableChooser(this);
chooser->addSupportedWidget(m_nameEdit);
chooser->addMacroExpanderProvider([this]() { return m_modifiedKit->macroExpander(); });
+
+ for (KitAspect *aspect : KitManager::kitAspects())
+ addAspectToWorkingCopy(aspect);
+
+ updateVisibility();
+
+ if (k && k->isAutoDetected())
+ makeStickySubWidgetsReadOnly();
+ setVisible(false);
}
KitManagerConfigWidget::~KitManagerConfigWidget()
@@ -142,28 +156,29 @@ QString KitManagerConfigWidget::displayName() const
return m_cachedDisplayName;
}
-QIcon KitManagerConfigWidget::icon() const
+QIcon KitManagerConfigWidget::displayIcon() const
{
- return m_modifiedKit->icon();
+ // Special case: Extra warning if there are no errors but name is not unique.
+ if (m_modifiedKit->isValid() && !m_hasUniqueName) {
+ static const QIcon warningIcon(Utils::Icons::WARNING.icon());
+ return warningIcon;
+ }
+
+ return m_modifiedKit->displayIcon();
}
void KitManagerConfigWidget::apply()
{
- bool mustSetDefault = m_isDefaultKit;
- bool mustRegister = false;
- auto toRegister = std::make_unique<Kit>();
- if (!m_kit) {
- mustRegister = true;
- m_kit = toRegister.get();
+ const auto copyIntoKit = [this](Kit *k) { k->copyFrom(m_modifiedKit.get()); };
+ if (m_kit) {
+ copyIntoKit(m_kit);
+ } else {
+ m_isRegistering = true;
+ m_kit = KitManager::registerKit(copyIntoKit);
+ m_isRegistering = false;
}
- m_kit->copyFrom(m_modifiedKit.get()); //m_isDefaultKit is reset in discard() here.
- if (mustRegister)
- KitManager::registerKit(std::move(toRegister));
-
- if (mustSetDefault)
+ if (m_isDefaultKit)
KitManager::setDefaultKit(m_kit);
-
- m_isDefaultKit = mustSetDefault;
emit dirty();
}
@@ -191,42 +206,35 @@ bool KitManagerConfigWidget::isDirty() const
|| m_isDefaultKit != (KitManager::defaultKit() == m_kit);
}
-bool KitManagerConfigWidget::isValid() const
-{
- return m_modifiedKit->isValid();
-}
-
-bool KitManagerConfigWidget::hasWarning() const
-{
- return m_modifiedKit->hasWarning() || !m_hasUniqueName;
-}
-
QString KitManagerConfigWidget::validityMessage() const
{
- QList<Task> tmp;
+ Tasks tmp;
if (!m_hasUniqueName) {
- tmp.append(Task(Task::Warning, tr("Display name is not unique."), Utils::FileName(), -1,
+ tmp.append(Task(Task::Warning, tr("Display name is not unique."), Utils::FilePath(), -1,
ProjectExplorer::Constants::TASK_CATEGORY_COMPILE));
}
return m_modifiedKit->toHtml(tmp);
}
-void KitManagerConfigWidget::addConfigWidget(KitConfigWidget *widget)
+void KitManagerConfigWidget::addAspectToWorkingCopy(KitAspect *aspect)
{
+ QTC_ASSERT(aspect, return);
+ KitAspectWidget *widget = aspect->createConfigWidget(workingCopy());
QTC_ASSERT(widget, return);
QTC_ASSERT(!m_widgets.contains(widget), return);
- const QString name = widget->displayName() + ':';
- QString toolTip = widget->toolTip();
+ const QString name = aspect->displayName() + ':';
+ QString toolTip = aspect->description();
auto action = new QAction(tr("Mark as Mutable"), nullptr);
action->setCheckable(true);
- action->setChecked(widget->isMutable());
+ action->setChecked(workingCopy()->isMutable(aspect->id()));
+
action->setEnabled(!widget->isSticky());
widget->mainWidget()->addAction(action);
widget->mainWidget()->setContextMenuPolicy(Qt::ActionsContextMenu);
- connect(action, &QAction::toggled, this, [this, widget, action] {
- widget->setMutable(action->isChecked());
+ connect(action, &QAction::toggled, this, [this, aspect, action] {
+ workingCopy()->setMutable(aspect->id(), action->isChecked());
emit dirty();
});
@@ -249,8 +257,9 @@ void KitManagerConfigWidget::updateVisibility()
{
int count = m_widgets.count();
for (int i = 0; i < count; ++i) {
- KitConfigWidget *widget = m_widgets.at(i);
- bool visible = widget->visibleInKit();
+ KitAspectWidget *widget = m_widgets.at(i);
+ const bool visible = widget->visibleInKit()
+ && !m_modifiedKit->irrelevantAspects().contains(widget->kitInformationId());
widget->mainWidget()->setVisible(visible);
if (widget->buttonWidget())
widget->buttonWidget()->setVisible(visible);
@@ -265,7 +274,7 @@ void KitManagerConfigWidget::setHasUniqueName(bool unique)
void KitManagerConfigWidget::makeStickySubWidgetsReadOnly()
{
- foreach (KitConfigWidget *w, m_widgets) {
+ foreach (KitAspectWidget *w, m_widgets) {
if (w->isSticky())
w->makeReadOnly();
}
@@ -303,24 +312,49 @@ void KitManagerConfigWidget::removeKit()
void KitManagerConfigWidget::setIcon()
{
- const QString path = QFileDialog::getOpenFileName(this, tr("Select Icon"),
- m_modifiedKit->iconPath().toString(),
- tr("Images (*.png *.xpm *.jpg)"));
- if (path.isEmpty())
- return;
-
- const QIcon icon(path);
- if (icon.isNull())
- return;
-
- m_iconButton->setIcon(icon);
- m_modifiedKit->setIconPath(Utils::FileName::fromString(path));
- emit dirty();
+ const Core::Id deviceType = DeviceTypeKitAspect::deviceTypeId(m_modifiedKit.get());
+ QList<IDeviceFactory *> allDeviceFactories = IDeviceFactory::allDeviceFactories();
+ if (deviceType.isValid()) {
+ const auto less = [deviceType](const IDeviceFactory *f1, const IDeviceFactory *f2) {
+ if (f1->deviceType() == deviceType)
+ return true;
+ if (f2->deviceType() == deviceType)
+ return false;
+ return f1->displayName() < f2->displayName();
+ };
+ Utils::sort(allDeviceFactories, less);
+ }
+ QMenu iconMenu;
+ for (const IDeviceFactory * const factory : qAsConst(allDeviceFactories)) {
+ if (factory->icon().isNull())
+ continue;
+ iconMenu.addAction(factory->icon(), tr("Default for %1").arg(factory->displayName()),
+ [this, factory] {
+ m_iconButton->setIcon(factory->icon());
+ m_modifiedKit->setDeviceTypeForIcon(factory->deviceType());
+ emit dirty();
+ });
+ }
+ iconMenu.addSeparator();
+ iconMenu.addAction(Utils::PathChooser::browseButtonLabel(), [this] {
+ const QString path = QFileDialog::getOpenFileName(this, tr("Select Icon"),
+ m_modifiedKit->iconPath().toString(),
+ tr("Images (*.png *.xpm *.jpg)"));
+ if (path.isEmpty())
+ return;
+ const QIcon icon(path);
+ if (icon.isNull())
+ return;
+ m_iconButton->setIcon(icon);
+ m_modifiedKit->setIconPath(Utils::FilePath::fromString(path));
+ emit dirty();
+ });
+ iconMenu.exec(mapToGlobal(m_iconButton->pos()));
}
void KitManagerConfigWidget::resetIcon()
{
- m_modifiedKit->setIconPath(Utils::FileName());
+ m_modifiedKit->setIconPath(Utils::FilePath());
emit dirty();
}
@@ -348,7 +382,7 @@ void KitManagerConfigWidget::workingCopyWasUpdated(Kit *k)
k->fix();
m_fixingKit = false;
- foreach (KitConfigWidget *w, m_widgets)
+ foreach (KitAspectWidget *w, m_widgets)
w->refresh();
m_cachedDisplayName.clear();
@@ -376,7 +410,7 @@ void KitManagerConfigWidget::kitWasUpdated(Kit *k)
void KitManagerConfigWidget::showEvent(QShowEvent *event)
{
Q_UNUSED(event);
- foreach (KitConfigWidget *widget, m_widgets)
+ foreach (KitAspectWidget *widget, m_widgets)
widget->refresh();
}
diff --git a/src/plugins/projectexplorer/kitmanagerconfigwidget.h b/src/plugins/projectexplorer/kitmanagerconfigwidget.h
index 026a8e25b4..cf1b6b44d6 100644
--- a/src/plugins/projectexplorer/kitmanagerconfigwidget.h
+++ b/src/plugins/projectexplorer/kitmanagerconfigwidget.h
@@ -25,7 +25,7 @@
#pragma once
-#include "kitconfigwidget.h"
+#include "kitmanager.h"
#include <QWidget>
@@ -52,19 +52,18 @@ public:
~KitManagerConfigWidget() override;
QString displayName() const;
- QIcon icon() const;
+ QIcon displayIcon() const;
void apply();
void discard();
bool isDirty() const;
- bool isValid() const;
- bool hasWarning() const;
QString validityMessage() const;
- void addConfigWidget(KitConfigWidget *widget);
+ void addAspectToWorkingCopy(KitAspect *aspect);
void makeStickySubWidgetsReadOnly();
Kit *workingCopy() const;
bool configures(Kit *k) const;
+ bool isRegistering() const { return m_isRegistering; }
void setIsDefaultKit(bool d);
bool isDefaultKit() const;
void removeKit();
@@ -97,13 +96,14 @@ private:
QToolButton *m_iconButton;
QLineEdit *m_nameEdit;
QLineEdit *m_fileSystemFriendlyNameLineEdit;
- QList<KitConfigWidget *> m_widgets;
+ QList<KitAspectWidget *> m_widgets;
QList<QLabel *> m_labels;
Kit *m_kit;
std::unique_ptr<Kit> m_modifiedKit;
bool m_isDefaultKit = false;
bool m_fixingKit = false;
bool m_hasUniqueName = true;
+ bool m_isRegistering = false;
QList<QAction *> m_actions;
mutable QString m_cachedDisplayName;
};
diff --git a/src/plugins/projectexplorer/kitmodel.cpp b/src/plugins/projectexplorer/kitmodel.cpp
index dbc04d559f..5f157dcbb3 100644
--- a/src/plugins/projectexplorer/kitmodel.cpp
+++ b/src/plugins/projectexplorer/kitmodel.cpp
@@ -44,14 +44,21 @@ namespace Internal {
class KitNode : public TreeItem
{
public:
- KitNode(Kit *k)
+ KitNode(Kit *k, KitModel *m)
{
- widget = KitManager::createConfigWidget(k);
- if (widget) {
- if (k && k->isAutoDetected())
- widget->makeStickySubWidgetsReadOnly();
- widget->setVisible(false);
- }
+ widget = new KitManagerConfigWidget(k);
+
+ QObject::connect(widget, &KitManagerConfigWidget::dirty, m, [this] { update(); });
+
+ QObject::connect(widget, &KitManagerConfigWidget::isAutoDetectedChanged, m, [this, m] {
+ TreeItem *oldParent = parent();
+ TreeItem *newParent =
+ m->rootItem()->childAt(widget->workingCopy()->isAutoDetected() ? 0 : 1);
+ if (oldParent && oldParent != newParent) {
+ m->takeItem(this);
+ newParent->appendChild(this);
+ }
+ });
}
~KitNode() override
@@ -78,15 +85,7 @@ public:
return baseName;
}
if (role == Qt::DecorationRole) {
- if (!widget->isValid()) {
- static const QIcon errorIcon(Utils::Icons::CRITICAL.icon());
- return errorIcon;
- }
- if (widget->hasWarning()) {
- static const QIcon warningIcon(Utils::Icons::WARNING.icon());
- return warningIcon;
- }
- return widget->icon();
+ return widget->displayIcon();
}
if (role == Qt::ToolTipRole) {
return widget->validityMessage();
@@ -164,35 +163,6 @@ KitManagerConfigWidget *KitModel::widget(const QModelIndex &index)
return n ? n->widget : nullptr;
}
-void KitModel::isAutoDetectedChanged()
-{
- auto w = qobject_cast<KitManagerConfigWidget *>(sender());
- int idx = -1;
- idx = Utils::indexOf(*m_manualRoot, [w](TreeItem *node) {
- return static_cast<KitNode *>(node)->widget == w;
- });
- TreeItem *oldParent = nullptr;
- TreeItem *newParent = w->workingCopy()->isAutoDetected() ? m_autoRoot : m_manualRoot;
- if (idx != -1) {
- oldParent = m_manualRoot;
- } else {
- idx = Utils::indexOf(*m_autoRoot, [w](TreeItem *node) {
- return static_cast<KitNode *>(node)->widget == w;
- });
- if (idx != -1) {
- oldParent = m_autoRoot;
- }
- }
-
- if (oldParent && oldParent != newParent) {
- beginMoveRows(indexForItem(oldParent), idx, idx, indexForItem(newParent), newParent->childCount());
- TreeItem *n = oldParent->childAt(idx);
- takeItem(n);
- newParent->appendChild(n);
- endMoveRows();
- }
-}
-
void KitModel::validateKitNames()
{
QHash<QString, int> nameHash;
@@ -248,10 +218,12 @@ void KitModel::markForRemoval(Kit *k)
delete node;
else
m_toRemoveList.append(node);
+ validateKitNames();
}
Kit *KitModel::markForAddition(Kit *baseKit)
{
+ const QString newName = newKitName(baseKit ? baseKit->unexpandedDisplayName() : QString());
KitNode *node = createNode(nullptr);
m_manualRoot->appendChild(node);
Kit *k = node->widget->workingCopy();
@@ -260,10 +232,10 @@ Kit *KitModel::markForAddition(Kit *baseKit)
k->copyFrom(baseKit);
k->setAutoDetected(false); // Make sure we have a manual kit!
k->setSdkProvided(false);
- k->setUnexpandedDisplayName(tr("Clone of %1").arg(k->unexpandedDisplayName()));
} else {
k->setup();
}
+ k->setUnexpandedDisplayName(newName);
if (!m_defaultNode)
setDefaultNode(node);
@@ -271,6 +243,22 @@ Kit *KitModel::markForAddition(Kit *baseKit)
return k;
}
+void KitModel::updateVisibility()
+{
+ forItemsAtLevel<2>([](const TreeItem *ti) {
+ static_cast<const KitNode *>(ti)->widget->updateVisibility();
+ });
+}
+
+QString KitModel::newKitName(const QString &sourceName) const
+{
+ QList<Kit *> allKits;
+ forItemsAtLevel<2>([&allKits](const TreeItem *ti) {
+ allKits << static_cast<const KitNode *>(ti)->widget->workingCopy();
+ });
+ return Kit::newKitName(sourceName, allKits);
+}
+
KitNode *KitModel::findWorkingCopy(Kit *k) const
{
return findItemAtLevel<2>([k](KitNode *n) { return n->widget->workingCopy() == k; });
@@ -278,15 +266,8 @@ KitNode *KitModel::findWorkingCopy(Kit *k) const
KitNode *KitModel::createNode(Kit *k)
{
- auto node = new KitNode(k);
+ auto node = new KitNode(k, this);
m_parentLayout->addWidget(node->widget);
- connect(node->widget, &KitManagerConfigWidget::dirty, [this, node] {
- if (m_autoRoot->indexOf(node) != -1 || m_manualRoot->indexOf(node) != -1)
- node->update();
- });
- connect(node->widget, &KitManagerConfigWidget::isAutoDetectedChanged,
- this, &KitModel::isAutoDetectedChanged);
-
return node;
}
@@ -307,7 +288,7 @@ void KitModel::addKit(Kit *k)
{
for (TreeItem *n : *m_manualRoot) {
// Was added by us
- if (static_cast<KitNode *>(n)->widget->configures(k))
+ if (static_cast<KitNode *>(n)->widget->isRegistering())
return;
}
@@ -333,6 +314,7 @@ void KitModel::removeKit(Kit *k)
if (m_defaultNode == n)
m_defaultNode = nullptr;
delete n;
+ validateKitNames();
return;
}
}
diff --git a/src/plugins/projectexplorer/kitmodel.h b/src/plugins/projectexplorer/kitmodel.h
index 8070eefe30..6e9dbed6f4 100644
--- a/src/plugins/projectexplorer/kitmodel.h
+++ b/src/plugins/projectexplorer/kitmodel.h
@@ -69,6 +69,10 @@ public:
void markForRemoval(Kit *k);
Kit *markForAddition(Kit *baseKit);
+ void updateVisibility();
+
+ QString newKitName(const QString &sourceName) const;
+
signals:
void kitStateChanged();
@@ -78,7 +82,6 @@ private:
void removeKit(ProjectExplorer::Kit *k);
void changeDefaultKit();
void validateKitNames();
- void isAutoDetectedChanged();
KitNode *findWorkingCopy(Kit *k) const;
KitNode *createNode(Kit *k);
diff --git a/src/plugins/projectexplorer/kitoptionspage.cpp b/src/plugins/projectexplorer/kitoptionspage.cpp
index 262d6c2706..d9ebe3f0e0 100644
--- a/src/plugins/projectexplorer/kitoptionspage.cpp
+++ b/src/plugins/projectexplorer/kitoptionspage.cpp
@@ -25,6 +25,7 @@
#include "kitoptionspage.h"
+#include "filterkitaspectsdialog.h"
#include "kitmodel.h"
#include "kit.h"
#include "projectexplorerconstants.h"
@@ -32,6 +33,8 @@
#include "kitmanagerconfigwidget.h"
#include "kitmanager.h"
+#include <utils/qtcassert.h>
+
#include <QHBoxLayout>
#include <QHeaderView>
#include <QItemSelectionModel>
@@ -67,10 +70,12 @@ public:
QPushButton *m_cloneButton = nullptr;
QPushButton *m_delButton = nullptr;
QPushButton *m_makeDefaultButton = nullptr;
+ QPushButton *m_filterButton = nullptr;
+ QPushButton *m_defaultFilterButton = nullptr;
KitModel *m_model = nullptr;
QItemSelectionModel *m_selectionModel = nullptr;
- QWidget *m_currentWidget = nullptr;
+ KitManagerConfigWidget *m_currentWidget = nullptr;
};
KitOptionsPageWidget::KitOptionsPageWidget()
@@ -85,6 +90,12 @@ KitOptionsPageWidget::KitOptionsPageWidget()
m_cloneButton = new QPushButton(KitOptionsPage::tr("Clone"), this);
m_delButton = new QPushButton(KitOptionsPage::tr("Remove"), this);
m_makeDefaultButton = new QPushButton(KitOptionsPage::tr("Make Default"), this);
+ m_filterButton = new QPushButton(KitOptionsPage::tr("Settings Filter..."), this);
+ m_filterButton->setToolTip(KitOptionsPage::tr(
+ "Choose which settings to display for this kit."));
+ m_defaultFilterButton = new QPushButton(KitOptionsPage::tr("Default Settings Filter..."), this);
+ m_defaultFilterButton->setToolTip(KitOptionsPage::tr(
+ "Choose which kit settings to display by default."));
auto buttonLayout = new QVBoxLayout;
buttonLayout->setSpacing(6);
@@ -93,6 +104,8 @@ KitOptionsPageWidget::KitOptionsPageWidget()
buttonLayout->addWidget(m_cloneButton);
buttonLayout->addWidget(m_delButton);
buttonLayout->addWidget(m_makeDefaultButton);
+ buttonLayout->addWidget(m_filterButton);
+ buttonLayout->addWidget(m_defaultFilterButton);
buttonLayout->addStretch();
auto horizontalLayout = new QHBoxLayout;
@@ -131,14 +144,28 @@ KitOptionsPageWidget::KitOptionsPageWidget()
this, &KitOptionsPageWidget::removeKit);
connect(m_makeDefaultButton, &QAbstractButton::clicked,
this, &KitOptionsPageWidget::makeDefaultKit);
-
+ connect(m_filterButton, &QAbstractButton::clicked, this, [this] {
+ QTC_ASSERT(m_currentWidget, return);
+ FilterKitAspectsDialog dlg(m_currentWidget->workingCopy(), this);
+ if (dlg.exec() == QDialog::Accepted) {
+ m_currentWidget->workingCopy()->setIrrelevantAspects(dlg.irrelevantAspects());
+ m_currentWidget->updateVisibility();
+ }
+ });
+ connect(m_defaultFilterButton, &QAbstractButton::clicked, this, [this] {
+ FilterKitAspectsDialog dlg(nullptr, this);
+ if (dlg.exec() == QDialog::Accepted) {
+ KitManager::setIrrelevantAspects(dlg.irrelevantAspects());
+ m_model->updateVisibility();
+ }
+ });
updateState();
}
void KitOptionsPageWidget::kitSelectionChanged()
{
QModelIndex current = currentIndex();
- QWidget *newWidget = m_model->widget(current);
+ KitManagerConfigWidget * const newWidget = m_model->widget(current);
if (newWidget == m_currentWidget)
return;
@@ -216,6 +243,7 @@ void KitOptionsPageWidget::updateState()
m_cloneButton->setEnabled(canCopy);
m_delButton->setEnabled(canDelete);
m_makeDefaultButton->setEnabled(canMakeDefault);
+ m_filterButton->setEnabled(canCopy);
}
QModelIndex KitOptionsPageWidget::currentIndex() const
diff --git a/src/plugins/projectexplorer/ldparser.cpp b/src/plugins/projectexplorer/ldparser.cpp
index 6da77cee9c..9ce56bf7dd 100644
--- a/src/plugins/projectexplorer/ldparser.cpp
+++ b/src/plugins/projectexplorer/ldparser.cpp
@@ -68,7 +68,7 @@ void LdParser::stdError(const QString &line)
if (lne.startsWith(QLatin1String("collect2:"))) {
Task task = Task(Task::Error,
lne /* description */,
- Utils::FileName() /* filename */,
+ Utils::FilePath() /* filename */,
-1 /* linenumber */,
Constants::TASK_CATEGORY_COMPILE);
emit addTask(task, 1);
@@ -79,7 +79,7 @@ void LdParser::stdError(const QString &line)
if (match.hasMatch()) {
QString description = match.captured(2);
Task task(Task::Warning, description,
- Utils::FileName(), -1,
+ Utils::FilePath(), -1,
Constants::TASK_CATEGORY_COMPILE);
emit addTask(task, 1);
return;
@@ -95,7 +95,7 @@ void LdParser::stdError(const QString &line)
} else if (description.startsWith(QLatin1String("fatal: "))) {
description = description.mid(7);
}
- Task task(type, description, Utils::FileName() /* filename */, -1 /* line */,
+ Task task(type, description, Utils::FilePath() /* filename */, -1 /* line */,
Constants::TASK_CATEGORY_COMPILE);
emit addTask(task, 1);
return;
@@ -107,12 +107,12 @@ void LdParser::stdError(const QString &line)
int lineno = match.captured(7).toInt(&ok);
if (!ok)
lineno = -1;
- Utils::FileName filename = Utils::FileName::fromUserInput(match.captured(1));
+ Utils::FilePath filename = Utils::FilePath::fromUserInput(match.captured(1));
const QString sourceFileName = match.captured(4);
if (!sourceFileName.isEmpty()
&& !sourceFileName.startsWith(QLatin1String("(.text"))
&& !sourceFileName.startsWith(QLatin1String("(.data"))) {
- filename = Utils::FileName::fromUserInput(sourceFileName);
+ filename = Utils::FilePath::fromUserInput(sourceFileName);
}
QString description = match.captured(8).trimmed();
Task::TaskType type = Task::Error;
diff --git a/src/plugins/projectexplorer/linuxiccparser.cpp b/src/plugins/projectexplorer/linuxiccparser.cpp
index 04dbb6c65f..6572f47d66 100644
--- a/src/plugins/projectexplorer/linuxiccparser.cpp
+++ b/src/plugins/projectexplorer/linuxiccparser.cpp
@@ -81,7 +81,7 @@ void LinuxIccParser::stdError(const QString &line)
else if (category == QLatin1String("warning"))
type = Task::Warning;
m_temporary = Task(type, m_firstLine.cap(6).trimmed(),
- Utils::FileName::fromUserInput(m_firstLine.cap(1)),
+ Utils::FilePath::fromUserInput(m_firstLine.cap(1)),
m_firstLine.cap(2).toInt(),
Constants::TASK_CATEGORY_COMPILE);
@@ -141,25 +141,25 @@ void ProjectExplorerPlugin::testLinuxIccOutputParsers_data()
QTest::addColumn<OutputParserTester::Channel>("inputChannel");
QTest::addColumn<QString>("childStdOutLines");
QTest::addColumn<QString>("childStdErrLines");
- QTest::addColumn<QList<Task> >("tasks");
+ QTest::addColumn<Tasks >("tasks");
QTest::addColumn<QString>("outputLines");
QTest::newRow("pass-through stdout")
<< QString::fromLatin1("Sometext") << OutputParserTester::STDOUT
<< QString::fromLatin1("Sometext\n") << QString()
- << QList<Task>()
+ << Tasks()
<< QString();
QTest::newRow("pass-through stderr")
<< QString::fromLatin1("Sometext") << OutputParserTester::STDERR
<< QString() << QString::fromLatin1("Sometext\n")
- << QList<Task>()
+ << Tasks()
<< QString();
QTest::newRow("pch creation")
<< QString::fromLatin1("\".pch/Qt5Core.pchi.cpp\": creating precompiled header file \".pch/Qt5Core.pchi\"")
<< OutputParserTester::STDERR
<< QString() << QString()
- << QList<Task>()
+ << Tasks()
<< QString();
QTest::newRow("undeclared function")
@@ -169,10 +169,10 @@ void ProjectExplorerPlugin::testLinuxIccOutputParsers_data()
"\n")
<< OutputParserTester::STDERR
<< QString() << QString::fromLatin1("\n")
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Error,
QLatin1String("identifier \"f\" is undefined\nf(0);"),
- Utils::FileName::fromUserInput(QLatin1String("main.cpp")), 13,
+ Utils::FilePath::fromUserInput(QLatin1String("main.cpp")), 13,
Constants::TASK_CATEGORY_COMPILE))
<< QString();
@@ -185,10 +185,10 @@ void ProjectExplorerPlugin::testLinuxIccOutputParsers_data()
"\n")
<< OutputParserTester::STDERR
<< QString() << QString::fromLatin1("\n")
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Error,
QLatin1String("identifier \"f\" is undefined\nf(0);"),
- Utils::FileName::fromUserInput(QLatin1String("main.cpp")), 13,
+ Utils::FilePath::fromUserInput(QLatin1String("main.cpp")), 13,
Constants::TASK_CATEGORY_COMPILE))
<< QString();
@@ -200,10 +200,10 @@ void ProjectExplorerPlugin::testLinuxIccOutputParsers_data()
"\n")
<< OutputParserTester::STDERR
<< QString() << QString::fromLatin1("\n")
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Error,
QLatin1String("function \"AClass::privatefunc\" (declared at line 4 of \"main.h\") is inaccessible\nb.privatefunc();"),
- Utils::FileName::fromUserInput(QLatin1String("main.cpp")), 53,
+ Utils::FilePath::fromUserInput(QLatin1String("main.cpp")), 53,
Constants::TASK_CATEGORY_COMPILE))
<< QString();
@@ -214,20 +214,20 @@ void ProjectExplorerPlugin::testLinuxIccOutputParsers_data()
"\n")
<< OutputParserTester::STDERR
<< QString() << QString::fromLatin1("\n")
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Warning,
QLatin1String("use of \"=\" where \"==\" may have been intended\nwhile (a = true)"),
- Utils::FileName::fromUserInput(QLatin1String("main.cpp")), 41,
+ Utils::FilePath::fromUserInput(QLatin1String("main.cpp")), 41,
Constants::TASK_CATEGORY_COMPILE))
<< QString();
QTest::newRow("moc note")
<< QString::fromLatin1("/home/qtwebkithelpviewer.h:0: Note: No relevant classes found. No output generated.")
<< OutputParserTester::STDERR
<< QString() << QString()
- << (QList<ProjectExplorer::Task>()
+ << (Tasks()
<< Task(Task::Unknown,
QLatin1String("Note: No relevant classes found. No output generated."),
- Utils::FileName::fromUserInput(QLatin1String("/home/qtwebkithelpviewer.h")), 0,
+ Utils::FilePath::fromUserInput(QLatin1String("/home/qtwebkithelpviewer.h")), 0,
Constants::TASK_CATEGORY_COMPILE)
)
<< QString();
@@ -239,7 +239,7 @@ void ProjectExplorerPlugin::testLinuxIccOutputParsers()
testbench.appendOutputParser(new LinuxIccParser);
QFETCH(QString, input);
QFETCH(OutputParserTester::Channel, inputChannel);
- QFETCH(QList<Task>, tasks);
+ QFETCH(Tasks, tasks);
QFETCH(QString, childStdOutLines);
QFETCH(QString, childStdErrLines);
QFETCH(QString, outputLines);
diff --git a/src/plugins/projectexplorer/localenvironmentaspect.cpp b/src/plugins/projectexplorer/localenvironmentaspect.cpp
index 2a6eee97c5..366b938ed4 100644
--- a/src/plugins/projectexplorer/localenvironmentaspect.cpp
+++ b/src/plugins/projectexplorer/localenvironmentaspect.cpp
@@ -32,54 +32,39 @@
#include <utils/qtcassert.h>
-namespace ProjectExplorer {
+using namespace Utils;
-enum BaseEnvironmentBase {
- CleanEnvironmentBase = 0,
- SystemEnvironmentBase,
- BuildEnvironmentBase
-};
+namespace ProjectExplorer {
-Utils::Environment LocalEnvironmentAspect::baseEnvironment() const
+LocalEnvironmentAspect::LocalEnvironmentAspect(Target *target)
{
- int base = baseEnvironmentBase();
- Utils::Environment env;
- if (base == static_cast<int>(BuildEnvironmentBase)) {
- if (BuildConfiguration *bc = m_target->activeBuildConfiguration()) {
+ setIsLocal(true);
+ addSupportedBaseEnvironment(tr("Clean Environment"), {});
+
+ addSupportedBaseEnvironment(tr("System Environment"), [] {
+ return Environment::systemEnvironment();
+ });
+
+ addPreferredBaseEnvironment(tr("Build Environment"), [target] {
+ Environment env;
+ if (BuildConfiguration *bc = target->activeBuildConfiguration()) {
env = bc->environment();
} else { // Fallback for targets without buildconfigurations:
- env = Utils::Environment::systemEnvironment();
- m_target->kit()->addToEnvironment(env);
+ env = Environment::systemEnvironment();
+ target->kit()->addToEnvironment(env);
}
- } else if (base == static_cast<int>(SystemEnvironmentBase)) {
- env = Utils::Environment::systemEnvironment();
- }
-
- if (m_baseEnvironmentModifier)
- m_baseEnvironmentModifier(env);
+ return env;
+ });
- return env;
+ target->subscribeSignal(&BuildConfiguration::environmentChanged,
+ this, &LocalEnvironmentAspect::buildEnvironmentHasChanged);
+ connect(target, &Target::activeBuildConfigurationChanged,
+ this, &LocalEnvironmentAspect::buildEnvironmentHasChanged);
}
void LocalEnvironmentAspect::buildEnvironmentHasChanged()
{
- if (baseEnvironmentBase() == static_cast<int>(BuildEnvironmentBase))
- emit environmentChanged();
-}
-
-LocalEnvironmentAspect::LocalEnvironmentAspect(Target *target,
- const BaseEnvironmentModifier &modifier) :
- m_baseEnvironmentModifier(modifier),
- m_target(target)
-{
- addPreferredBaseEnvironment(BuildEnvironmentBase, tr("Build Environment"));
- addSupportedBaseEnvironment(SystemEnvironmentBase, tr("System Environment"));
- addSupportedBaseEnvironment(CleanEnvironmentBase, tr("Clean Environment"));
-
- m_target->subscribeSignal(&BuildConfiguration::environmentChanged,
- this, &LocalEnvironmentAspect::buildEnvironmentHasChanged);
- connect(m_target, &Target::activeBuildConfigurationChanged,
- this, &LocalEnvironmentAspect::buildEnvironmentHasChanged);
+ emit environmentChanged();
}
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/localenvironmentaspect.h b/src/plugins/projectexplorer/localenvironmentaspect.h
index 967a985e8f..05653899b2 100644
--- a/src/plugins/projectexplorer/localenvironmentaspect.h
+++ b/src/plugins/projectexplorer/localenvironmentaspect.h
@@ -34,16 +34,9 @@ class PROJECTEXPLORER_EXPORT LocalEnvironmentAspect : public EnvironmentAspect
Q_OBJECT
public:
- using BaseEnvironmentModifier = std::function<void(Utils::Environment &)>;
- LocalEnvironmentAspect(Target *parent, const BaseEnvironmentModifier &modifier);
-
- Utils::Environment baseEnvironment() const override;
+ explicit LocalEnvironmentAspect(Target *parent);
void buildEnvironmentHasChanged();
-
-private:
- BaseEnvironmentModifier m_baseEnvironmentModifier;
- Target *m_target;
};
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/makestep.cpp b/src/plugins/projectexplorer/makestep.cpp
index b909962ce9..fecaacc89c 100644
--- a/src/plugins/projectexplorer/makestep.cpp
+++ b/src/plugins/projectexplorer/makestep.cpp
@@ -47,6 +47,7 @@
#include <QThread>
using namespace Core;
+using namespace Utils;
const char BUILD_TARGETS_SUFFIX[] = ".BuildTargets";
const char MAKE_ARGUMENTS_SUFFIX[] = ".MakeArguments";
@@ -78,7 +79,7 @@ bool MakeStep::init()
if (!bc)
emit addTask(Task::buildConfigurationMissingTask());
- const QString make = effectiveMakeCommand();
+ const FilePath make = effectiveMakeCommand();
if (make.isEmpty())
emit addTask(makeCommandMissingTask());
@@ -89,7 +90,7 @@ bool MakeStep::init()
ProcessParameters *pp = processParameters();
pp->setMacroExpander(bc->macroExpander());
- pp->setWorkingDirectory(bc->buildDirectory().toString());
+ pp->setWorkingDirectory(bc->buildDirectory());
pp->setEnvironment(environment(bc));
pp->setCommand(make);
pp->setArguments(allArguments());
@@ -104,7 +105,7 @@ bool MakeStep::init()
IOutputParser *parser = target()->kit()->createOutputParser();
if (parser)
appendOutputParser(parser);
- outputParser()->setWorkingDirectory(pp->effectiveWorkingDirectory());
+ outputParser()->setWorkingDirectory(pp->effectiveWorkingDirectory().toString());
return AbstractProcessStep::init();
}
@@ -126,7 +127,7 @@ QString MakeStep::defaultDisplayName()
static const QList<ToolChain *> preferredToolChains(const Kit *kit)
{
- QList<ToolChain *> tcs = ToolChainKitInformation::toolChains(kit);
+ QList<ToolChain *> tcs = ToolChainKitAspect::toolChains(kit);
// prefer CXX, then C, then others
Utils::sort(tcs, [](ToolChain *tcA, ToolChain *tcB) {
if (tcA->language() == tcB->language())
@@ -142,18 +143,18 @@ static const QList<ToolChain *> preferredToolChains(const Kit *kit)
return tcs;
}
-QString MakeStep::defaultMakeCommand() const
+FilePath MakeStep::defaultMakeCommand() const
{
BuildConfiguration *bc = buildConfiguration();
if (!bc)
- return QString();
+ return {};
const Utils::Environment env = environment(bc);
for (const ToolChain *tc : preferredToolChains(target()->kit())) {
- const QString make = tc->makeCommand(env);
+ FilePath make = tc->makeCommand(env);
if (!make.isEmpty())
return make;
}
- return QString();
+ return {};
}
QString MakeStep::msgNoMakeCommand()
@@ -165,7 +166,7 @@ Task MakeStep::makeCommandMissingTask()
{
return Task(Task::Error,
msgNoMakeCommand(),
- Utils::FileName(),
+ Utils::FilePath(),
-1,
Constants::TASK_CATEGORY_BUILDSYSTEM);
}
@@ -174,9 +175,7 @@ bool MakeStep::isJobCountSupported() const
{
const QList<ToolChain *> tcs = preferredToolChains(target()->kit());
const ToolChain *tc = tcs.isEmpty() ? nullptr : tcs.constFirst();
- return tc
- && (tc->targetAbi().os() != Abi::WindowsOS
- || tc->targetAbi().osFlavor() == Abi::WindowsMSysFlavor);
+ return tc && tc->isJobCountSupported();
}
int MakeStep::jobCount() const
@@ -261,7 +260,7 @@ Utils::Environment MakeStep::environment(BuildConfiguration *bc) const
return env;
}
-void MakeStep::setMakeCommand(const QString &command)
+void MakeStep::setMakeCommand(const FilePath &command)
{
m_makeCommand = command;
}
@@ -272,7 +271,7 @@ QVariantMap MakeStep::toMap() const
map.insert(id().withSuffix(BUILD_TARGETS_SUFFIX).toString(), m_buildTargets);
map.insert(id().withSuffix(MAKE_ARGUMENTS_SUFFIX).toString(), m_makeArguments);
- map.insert(id().withSuffix(MAKE_COMMAND_SUFFIX).toString(), m_makeCommand);
+ map.insert(id().withSuffix(MAKE_COMMAND_SUFFIX).toString(), m_makeCommand.toString());
map.insert(id().withSuffix(CLEAN_SUFFIX).toString(), m_clean);
const QString jobCountKey = id().withSuffix(JOBCOUNT_SUFFIX).toString();
if (m_userJobCount != defaultJobCount())
@@ -287,7 +286,8 @@ bool MakeStep::fromMap(const QVariantMap &map)
{
m_buildTargets = map.value(id().withSuffix(BUILD_TARGETS_SUFFIX).toString()).toStringList();
m_makeArguments = map.value(id().withSuffix(MAKE_ARGUMENTS_SUFFIX).toString()).toString();
- m_makeCommand = map.value(id().withSuffix(MAKE_COMMAND_SUFFIX).toString()).toString();
+ m_makeCommand = FilePath::fromString(
+ map.value(id().withSuffix(MAKE_COMMAND_SUFFIX).toString()).toString());
m_clean = map.value(id().withSuffix(CLEAN_SUFFIX).toString()).toBool();
m_overrideMakeflags = map.value(id().withSuffix(OVERRIDE_MAKEFLAGS_SUFFIX).toString(), false).toBool();
m_userJobCount = map.value(id().withSuffix(JOBCOUNT_SUFFIX).toString(), defaultJobCount()).toInt();
@@ -325,12 +325,12 @@ void MakeStep::setUserArguments(const QString &args)
m_makeArguments = args;
}
-QString MakeStep::makeCommand() const
+FilePath MakeStep::makeCommand() const
{
return m_makeCommand;
}
-QString MakeStep::effectiveMakeCommand() const
+FilePath MakeStep::effectiveMakeCommand() const
{
if (!m_makeCommand.isEmpty())
return m_makeCommand;
@@ -387,7 +387,7 @@ MakeStepConfigWidget::MakeStepConfigWidget(MakeStep *makeStep)
m_ui->makeLineEdit->setExpectedKind(Utils::PathChooser::ExistingCommand);
m_ui->makeLineEdit->setBaseDirectory(Utils::PathChooser::homePath());
m_ui->makeLineEdit->setHistoryCompleter("PE.MakeCommand.History");
- m_ui->makeLineEdit->setPath(m_makeStep->makeCommand());
+ m_ui->makeLineEdit->setPath(m_makeStep->makeCommand().toString());
m_ui->makeArgumentsLineEdit->setText(m_makeStep->userArguments());
m_ui->nonOverrideWarning->setToolTip("<html><body><p>" +
tr("<code>MAKEFLAGS</code> specifies parallel jobs. Check \"%1\" to override.")
@@ -460,7 +460,7 @@ void MakeStepConfigWidget::updateDetails()
{
BuildConfiguration *bc = m_makeStep->buildConfiguration();
- const QString defaultMake = m_makeStep->defaultMakeCommand();
+ const QString defaultMake = m_makeStep->defaultMakeCommand().toString();
if (defaultMake.isEmpty())
m_ui->makeLabel->setText(tr("Make:"));
else
@@ -485,14 +485,14 @@ void MakeStepConfigWidget::updateDetails()
ProcessParameters param;
param.setMacroExpander(bc->macroExpander());
- param.setWorkingDirectory(bc->buildDirectory().toString());
+ param.setWorkingDirectory(bc->buildDirectory());
param.setCommand(m_makeStep->effectiveMakeCommand());
-
param.setArguments(m_makeStep->allArguments());
param.setEnvironment(m_makeStep->environment(bc));
if (param.commandMissing())
- setSummaryText(tr("<b>Make:</b> %1 not found in the environment.").arg(param.command())); // Override display text
+ setSummaryText(tr("<b>Make:</b> %1 not found in the environment.")
+ .arg(param.command().toString())); // Override display text
else
setSummaryText(param.summaryInWorkdir(displayName()));
}
@@ -505,7 +505,7 @@ void MakeStepConfigWidget::itemChanged(QListWidgetItem *item)
void MakeStepConfigWidget::makeLineEditTextEdited()
{
- m_makeStep->setMakeCommand(m_ui->makeLineEdit->rawPath());
+ m_makeStep->setMakeCommand(FilePath::fromString(m_ui->makeLineEdit->rawPath()));
updateDetails();
}
diff --git a/src/plugins/projectexplorer/makestep.h b/src/plugins/projectexplorer/makestep.h
index 036b55e254..e44b52851e 100644
--- a/src/plugins/projectexplorer/makestep.h
+++ b/src/plugins/projectexplorer/makestep.h
@@ -28,6 +28,8 @@
#include "abstractprocessstep.h"
#include "projectexplorer_global.h"
+#include <utils/fileutils.h>
+
QT_FORWARD_DECLARE_CLASS(QListWidgetItem);
namespace Utils { class Environment; }
@@ -56,16 +58,16 @@ public:
QString allArguments() const;
QString userArguments() const;
void setUserArguments(const QString &args);
- QString makeCommand() const;
- void setMakeCommand(const QString &command);
- QString effectiveMakeCommand() const;
+ Utils::FilePath makeCommand() const;
+ void setMakeCommand(const Utils::FilePath &command);
+ Utils::FilePath effectiveMakeCommand() const;
void setClean(bool clean);
bool isClean() const;
static QString defaultDisplayName();
- QString defaultMakeCommand() const;
+ Utils::FilePath defaultMakeCommand() const;
static QString msgNoMakeCommand();
static Task makeCommandMissingTask();
@@ -80,16 +82,18 @@ public:
Utils::Environment environment(BuildConfiguration *bc) const;
+protected:
+ bool fromMap(const QVariantMap &map) override;
+
private:
QVariantMap toMap() const override;
- bool fromMap(const QVariantMap &map) override;
static int defaultJobCount();
QStringList jobArguments() const;
QStringList m_buildTargets;
QStringList m_availableTargets;
QString m_makeArguments;
- QString m_makeCommand;
+ Utils::FilePath m_makeCommand;
int m_userJobCount = 4;
bool m_overrideMakeflags = false;
bool m_clean = false;
diff --git a/src/plugins/projectexplorer/miniprojecttargetselector.cpp b/src/plugins/projectexplorer/miniprojecttargetselector.cpp
index 7d0573b0ac..aa01c0f9b6 100644
--- a/src/plugins/projectexplorer/miniprojecttargetselector.cpp
+++ b/src/plugins/projectexplorer/miniprojecttargetselector.cpp
@@ -25,10 +25,8 @@
#include "buildconfiguration.h"
#include "deployconfiguration.h"
-#include "kitconfigwidget.h"
#include "kit.h"
#include "kitmanager.h"
-#include "kitmanager.h"
#include "miniprojecttargetselector.h"
#include "projectexplorer.h"
#include "projectexplorericons.h"
@@ -298,7 +296,7 @@ void ProjectListWidget::addProject(Project *project)
setCurrentItem(item);
QFontMetrics fn(font());
- int width = fn.width(displayName) + padding();
+ int width = fn.horizontalAdvance(displayName) + padding();
if (width > optimalWidth())
setOptimalWidth(width);
@@ -333,7 +331,7 @@ void ProjectListWidget::removeProject(Project *project)
// recheck optimal width
int width = 0;
for (int i = 0; i < count(); ++i)
- width = qMax(fn.width(item(i)->text()) + padding(), width);
+ width = qMax(fn.horizontalAdvance(item(i)->text()) + padding(), width);
setOptimalWidth(width);
m_ignoreIndexChange = false;
@@ -377,7 +375,7 @@ void ProjectListWidget::projectDisplayNameChanged(Project *project)
QFontMetrics fn(font());
int width = 0;
for (int i = 0; i < count(); ++i)
- width = qMax(fn.width(item(i)->text()) + padding(), width);
+ width = qMax(fn.horizontalAdvance(item(i)->text()) + padding(), width);
setOptimalWidth(width);
m_ignoreIndexChange = false;
@@ -424,7 +422,7 @@ void GenericListWidget::setProjectConfigurations(const QList<ProjectConfiguratio
int width = 0;
foreach (ProjectConfiguration *pc, list) {
addProjectConfiguration(pc);
- width = qMax(width, fn.width(pc->displayName()) + padding());
+ width = qMax(width, fn.horizontalAdvance(pc->displayName()) + padding());
}
setOptimalWidth(width);
setActiveProjectConfiguration(active);
@@ -463,7 +461,7 @@ void GenericListWidget::addProjectConfiguration(ProjectConfiguration *pc)
connect(pc, &ProjectConfiguration::toolTipChanged, this, &GenericListWidget::toolTipChanged);
QFontMetrics fn(font());
- int width = fn.width(pc->displayName()) + padding();
+ int width = fn.horizontalAdvance(pc->displayName()) + padding();
if (width > optimalWidth())
setOptimalWidth(width);
@@ -481,7 +479,7 @@ void GenericListWidget::removeProjectConfiguration(ProjectConfiguration *pc)
int width = 0;
for (int i = 0; i < count(); ++i) {
auto *p = item(i)->data(Qt::UserRole).value<ProjectConfiguration *>();
- width = qMax(width, fn.width(p->displayName()) + padding());
+ width = qMax(width, fn.horizontalAdvance(p->displayName()) + padding());
}
setOptimalWidth(width);
@@ -534,7 +532,7 @@ void GenericListWidget::displayNameChanged()
int width = 0;
for (int i = 0; i < count(); ++i) {
auto *p = item(i)->data(Qt::UserRole).value<ProjectConfiguration *>();
- width = qMax(width, fn.width(p->displayName()) + padding());
+ width = qMax(width, fn.horizontalAdvance(p->displayName()) + padding());
}
setOptimalWidth(width);
@@ -579,7 +577,7 @@ KitAreaWidget::~KitAreaWidget()
void KitAreaWidget::setKit(Kit *k)
{
- foreach (KitConfigWidget *w, m_widgets)
+ foreach (KitAspectWidget *w, m_widgets)
delete(w);
m_widgets.clear();
@@ -591,11 +589,11 @@ void KitAreaWidget::setKit(Kit *k)
m_labels.clear();
int row = 0;
- foreach (KitInformation *ki, KitManager::kitInformation()) {
- if (k && k->isMutable(ki->id())) {
- KitConfigWidget *widget = ki->createConfigWidget(k);
+ for (KitAspect *aspect : KitManager::kitAspects()) {
+ if (k && k->isMutable(aspect->id())) {
+ KitAspectWidget *widget = aspect->createConfigWidget(k);
m_widgets << widget;
- QLabel *label = new QLabel(widget->displayName());
+ QLabel *label = new QLabel(aspect->displayName());
m_labels << label;
widget->setStyle(QStyleFactory::create(QLatin1String("fusion")));
@@ -619,10 +617,10 @@ void KitAreaWidget::updateKit(Kit *k)
return;
bool addedMutables = false;
- QList<Core::Id> knownIdList = Utils::transform(m_widgets, &KitConfigWidget::kitInformationId);
+ QList<Core::Id> knownIdList = Utils::transform(m_widgets, &KitAspectWidget::kitInformationId);
- foreach (KitInformation *ki, KitManager::kitInformation()) {
- Core::Id currentId = ki->id();
+ for (KitAspect *aspect : KitManager::kitAspects()) {
+ const Core::Id currentId = aspect->id();
if (m_kit->isMutable(currentId) && !knownIdList.removeOne(currentId)) {
addedMutables = true;
break;
@@ -635,7 +633,7 @@ void KitAreaWidget::updateKit(Kit *k)
setKit(m_kit);
} else {
// Refresh all widgets if the number of mutable settings did not change
- foreach (KitConfigWidget *w, m_widgets)
+ foreach (KitAspectWidget *w, m_widgets)
w->refresh();
}
}
diff --git a/src/plugins/projectexplorer/miniprojecttargetselector.h b/src/plugins/projectexplorer/miniprojecttargetselector.h
index 0c2e51a4f4..032f69f7eb 100644
--- a/src/plugins/projectexplorer/miniprojecttargetselector.h
+++ b/src/plugins/projectexplorer/miniprojecttargetselector.h
@@ -37,7 +37,7 @@ QT_END_NAMESPACE
namespace ProjectExplorer {
class Kit;
-class KitConfigWidget;
+class KitAspectWidget;
class Project;
class Target;
class BuildConfiguration;
@@ -101,7 +101,7 @@ private:
QGridLayout *m_layout;
Kit *m_kit = nullptr;
- QList<KitConfigWidget *> m_widgets;
+ QList<KitAspectWidget *> m_widgets;
QList<QLabel *> m_labels;
};
diff --git a/src/plugins/projectexplorer/msvcparser.cpp b/src/plugins/projectexplorer/msvcparser.cpp
index b99880252a..2d3095c168 100644
--- a/src/plugins/projectexplorer/msvcparser.cpp
+++ b/src/plugins/projectexplorer/msvcparser.cpp
@@ -35,11 +35,11 @@ using namespace Utils;
// As of MSVC 2015: "foo.cpp(42) :" -> "foo.cpp(42):"
static const char FILE_POS_PATTERN[] = "^(?:\\d+>)?(cl|LINK|.+[^ ]) ?: ";
-static QPair<FileName, int> parseFileName(const QString &input)
+static QPair<FilePath, int> parseFileName(const QString &input)
{
QString fileName = input;
if (fileName.startsWith("LINK") || fileName.startsWith("cl"))
- return qMakePair(FileName(), -1);
+ return qMakePair(FilePath(), -1);
// Extract linenumber (if it is there):
int linenumber = -1;
@@ -59,7 +59,7 @@ static QPair<FileName, int> parseFileName(const QString &input)
}
}
const QString normalized = FileUtils::normalizePathName(fileName);
- return qMakePair(FileName::fromUserInput(normalized), linenumber);
+ return qMakePair(FilePath::fromUserInput(normalized), linenumber);
}
using namespace ProjectExplorer;
@@ -78,7 +78,7 @@ static bool handleNmakeJomMessage(const QString &line, Task *task)
*task = Task(Task::Error,
line.mid(matchLength).trimmed(), /* description */
- FileName(), /* fileName */
+ FilePath(), /* fileName */
-1, /* linenumber */
Constants::TASK_CATEGORY_COMPILE);
return true;
@@ -146,7 +146,7 @@ void MsvcParser::stdOutput(const QString &line)
if (!match.captured(1).isEmpty())
description.chop(1); // Remove trailing quote
m_lastTask = Task(Task::Unknown, description,
- FileName::fromUserInput(match.captured(2)), /* fileName */
+ FilePath::fromUserInput(match.captured(2)), /* fileName */
match.captured(3).toInt(), /* linenumber */
Constants::TASK_CATEGORY_COMPILE);
m_lines = 1;
@@ -178,7 +178,7 @@ bool MsvcParser::processCompileLine(const QString &line)
QRegularExpressionMatch match = m_compileRegExp.match(line);
if (match.hasMatch()) {
- QPair<FileName, int> position = parseFileName(match.captured(1));
+ QPair<FilePath, int> position = parseFileName(match.captured(1));
m_lastTask = Task(taskType(match.captured(2)),
match.captured(3) + match.captured(4).trimmed(), // description
position.first, position.second,
@@ -261,7 +261,7 @@ void ClangClParser::stdError(const QString &lineIn)
QRegularExpressionMatch match = m_compileRegExp.match(line);
if (match.hasMatch()) {
doFlush();
- const QPair<FileName, int> position = parseFileName(match.captured(1));
+ const QPair<FilePath, int> position = parseFileName(match.captured(1));
m_lastTask = Task(taskType(match.captured(2)), match.captured(3).trimmed(),
position.first, position.second,
Constants::TASK_CATEGORY_COMPILE);
@@ -307,28 +307,28 @@ void ProjectExplorerPlugin::testMsvcOutputParsers_data()
QTest::addColumn<OutputParserTester::Channel>("inputChannel");
QTest::addColumn<QString>("childStdOutLines");
QTest::addColumn<QString>("childStdErrLines");
- QTest::addColumn<QList<Task> >("tasks");
+ QTest::addColumn<Tasks >("tasks");
QTest::addColumn<QString>("outputLines");
QTest::newRow("pass-through stdout")
<< "Sometext" << OutputParserTester::STDOUT
<< "Sometext\n" << ""
- << QList<Task>()
+ << Tasks()
<< "";
QTest::newRow("pass-through stderr")
<< "Sometext" << OutputParserTester::STDERR
<< "" << "Sometext\n"
- << QList<Task>()
+ << Tasks()
<< "";
QTest::newRow("labeled error")
<< "qmlstandalone\\main.cpp(54) : error C4716: 'findUnresolvedModule' : must return a value"
<< OutputParserTester::STDOUT
<< "" << ""
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Error,
"C4716: 'findUnresolvedModule' : must return a value",
- FileName::fromUserInput("qmlstandalone\\main.cpp"), 54,
+ FilePath::fromUserInput("qmlstandalone\\main.cpp"), 54,
Constants::TASK_CATEGORY_COMPILE))
<< "";
@@ -336,10 +336,10 @@ void ProjectExplorerPlugin::testMsvcOutputParsers_data()
<< "qmlstandalone\\main.cpp(54): error C4716: 'findUnresolvedModule' : must return a value"
<< OutputParserTester::STDOUT
<< "" << ""
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Error,
"C4716: 'findUnresolvedModule' : must return a value",
- FileName::fromUserInput("qmlstandalone\\main.cpp"), 54,
+ FilePath::fromUserInput("qmlstandalone\\main.cpp"), 54,
Constants::TASK_CATEGORY_COMPILE))
<< "";
@@ -347,10 +347,10 @@ void ProjectExplorerPlugin::testMsvcOutputParsers_data()
<< "1>qmlstandalone\\main.cpp(54) : error C4716: 'findUnresolvedModule' : must return a value"
<< OutputParserTester::STDOUT
<< "" << ""
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Error,
"C4716: 'findUnresolvedModule' : must return a value",
- FileName::fromUserInput("qmlstandalone\\main.cpp"), 54,
+ FilePath::fromUserInput("qmlstandalone\\main.cpp"), 54,
Constants::TASK_CATEGORY_COMPILE))
<< "";
@@ -358,10 +358,10 @@ void ProjectExplorerPlugin::testMsvcOutputParsers_data()
<< "x:\\src\\plugins\\projectexplorer\\msvcparser.cpp(69) : warning C4100: 'something' : unreferenced formal parameter"
<< OutputParserTester::STDOUT
<< "" << ""
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Warning,
"C4100: 'something' : unreferenced formal parameter",
- FileName::fromUserInput("x:\\src\\plugins\\projectexplorer\\msvcparser.cpp"), 69,
+ FilePath::fromUserInput("x:\\src\\plugins\\projectexplorer\\msvcparser.cpp"), 69,
Constants::TASK_CATEGORY_COMPILE))
<< "";
@@ -370,10 +370,10 @@ void ProjectExplorerPlugin::testMsvcOutputParsers_data()
<< "1>x:\\src\\plugins\\projectexplorer\\msvcparser.cpp(69) : warning C4100: 'something' : unreferenced formal parameter"
<< OutputParserTester::STDOUT
<< "" << ""
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Warning,
"C4100: 'something' : unreferenced formal parameter",
- FileName::fromUserInput("x:\\src\\plugins\\projectexplorer\\msvcparser.cpp"), 69,
+ FilePath::fromUserInput("x:\\src\\plugins\\projectexplorer\\msvcparser.cpp"), 69,
Constants::TASK_CATEGORY_COMPILE))
<< "";
@@ -382,14 +382,14 @@ void ProjectExplorerPlugin::testMsvcOutputParsers_data()
" x:\\src\\plugins\\texteditor\\completionsupport.h(39) : see declaration of 'TextEditor::CompletionItem'"
<< OutputParserTester::STDOUT
<< "" << ""
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Warning,
"C4099: 'TextEditor::CompletionItem' : type name first seen using 'struct' now seen using 'class'",
- FileName::fromUserInput("x:\\src\\plugins\\texteditor\\icompletioncollector.h"), 50,
+ FilePath::fromUserInput("x:\\src\\plugins\\texteditor\\icompletioncollector.h"), 50,
Constants::TASK_CATEGORY_COMPILE)
<< Task(Task::Unknown,
"see declaration of 'TextEditor::CompletionItem'",
- FileName::fromUserInput("x:\\src\\plugins\\texteditor\\completionsupport.h"), 39,
+ FilePath::fromUserInput("x:\\src\\plugins\\texteditor\\completionsupport.h"), 39,
Constants::TASK_CATEGORY_COMPILE))
<< "";
@@ -398,14 +398,14 @@ void ProjectExplorerPlugin::testMsvcOutputParsers_data()
" x:\\src\\plugins\\texteditor\\completionsupport.h(39) : see declaration of 'TextEditor::CompletionItem'"
<< OutputParserTester::STDOUT
<< "" << ""
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Warning,
"C4099: 'TextEditor::CompletionItem' : type name first seen using 'struct' now seen using 'class'",
- FileName::fromUserInput("x:\\src\\plugins\\texteditor\\icompletioncollector.h"), 50,
+ FilePath::fromUserInput("x:\\src\\plugins\\texteditor\\icompletioncollector.h"), 50,
Constants::TASK_CATEGORY_COMPILE)
<< Task(Task::Unknown,
"see declaration of 'TextEditor::CompletionItem'",
- FileName::fromUserInput("x:\\src\\plugins\\texteditor\\completionsupport.h"), 39,
+ FilePath::fromUserInput("x:\\src\\plugins\\texteditor\\completionsupport.h"), 39,
Constants::TASK_CATEGORY_COMPILE))
<< "";
@@ -413,10 +413,10 @@ void ProjectExplorerPlugin::testMsvcOutputParsers_data()
<< "LINK : fatal error LNK1146: no argument specified with option '/LIBPATH:'"
<< OutputParserTester::STDOUT
<< "" << ""
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Error,
"LNK1146: no argument specified with option '/LIBPATH:'",
- FileName(), -1,
+ FilePath(), -1,
Constants::TASK_CATEGORY_COMPILE))
<< "";
@@ -425,10 +425,10 @@ void ProjectExplorerPlugin::testMsvcOutputParsers_data()
<< "cl : Command line warning D9002 : ignoring unknown option '-fopenmp'"
<< OutputParserTester::STDERR
<< "" << ""
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Warning,
"D9002 : ignoring unknown option '-fopenmp'",
- FileName(), -1,
+ FilePath(), -1,
Constants::TASK_CATEGORY_COMPILE))
<< "";
QTest::newRow("complex error")
@@ -440,7 +440,7 @@ void ProjectExplorerPlugin::testMsvcOutputParsers_data()
" No constructor could take the source type, or constructor overload resolution was ambiguous"
<< OutputParserTester::STDOUT
<< "" << ""
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Error,
"C2440: 'initializing' : cannot convert from 'int' to 'std::_Tree<_Traits>::iterator'\n"
"with\n"
@@ -448,27 +448,27 @@ void ProjectExplorerPlugin::testMsvcOutputParsers_data()
" _Traits=std::_Tmap_traits<int,double,std::less<int>,std::allocator<std::pair<const int,double>>,false>\n"
"]\n"
"No constructor could take the source type, or constructor overload resolution was ambiguous",
- FileName::fromUserInput("..\\untitled\\main.cpp"), 19,
+ FilePath::fromUserInput("..\\untitled\\main.cpp"), 19,
Constants::TASK_CATEGORY_COMPILE))
<< "";
QTest::newRow("Linker error 1")
<< "main.obj : error LNK2019: unresolved external symbol \"public: void __thiscall Data::doit(void)\" (?doit@Data@@QAEXXZ) referenced in function _main"
<< OutputParserTester::STDOUT
<< "" << ""
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Error,
"LNK2019: unresolved external symbol \"public: void __thiscall Data::doit(void)\" (?doit@Data@@QAEXXZ) referenced in function _main",
- FileName::fromUserInput("main.obj"), -1,
+ FilePath::fromUserInput("main.obj"), -1,
Constants::TASK_CATEGORY_COMPILE))
<< "";
QTest::newRow("Linker error 2")
<< "debug\\Experimentation.exe : fatal error LNK1120: 1 unresolved externals"
<< OutputParserTester::STDOUT
<< "" << ""
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Error,
"LNK1120: 1 unresolved externals",
- FileName::fromUserInput("debug\\Experimentation.exe"), -1,
+ FilePath::fromUserInput("debug\\Experimentation.exe"), -1,
Constants::TASK_CATEGORY_COMPILE))
<< "";
@@ -476,20 +476,20 @@ void ProjectExplorerPlugin::testMsvcOutputParsers_data()
<< "Error: dependent '..\\..\\..\\..\\creator-2.5\\src\\plugins\\coreplugin\\ifile.h' does not exist."
<< OutputParserTester::STDOUT
<< "" << ""
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Error,
"dependent '..\\..\\..\\..\\creator-2.5\\src\\plugins\\coreplugin\\ifile.h' does not exist.",
- FileName(), -1,
+ FilePath(), -1,
Constants::TASK_CATEGORY_COMPILE))
<< "";
QTest::newRow("jom error")
<< "Error: dependent 'main.cpp' does not exist."
<< OutputParserTester::STDERR
<< "" << ""
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Error,
"dependent 'main.cpp' does not exist.",
- FileName(), -1,
+ FilePath(), -1,
Constants::TASK_CATEGORY_COMPILE))
<< "";
@@ -504,14 +504,14 @@ void ProjectExplorerPlugin::testMsvcOutputParsers_data()
" ]"
<< OutputParserTester::STDOUT
<< "" << ""
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Warning,
"C4996: 'std::_Copy_impl': Function call with parameters that may be unsafe - this call relies on the caller to check that the passed values are correct. To disable this warning, use -D_SCL_SECURE_NO_WARNINGS. See documentation on how to use Visual C++ 'Checked Iterators'",
- FileName::fromUserInput("c:\\Program Files (x86)\\Microsoft Visual Studio 10.0\\VC\\INCLUDE\\xutility"), 2227,
+ FilePath::fromUserInput("c:\\Program Files (x86)\\Microsoft Visual Studio 10.0\\VC\\INCLUDE\\xutility"), 2227,
Constants::TASK_CATEGORY_COMPILE)
<< Task(Task::Unknown,
"see declaration of 'std::_Copy_impl'",
- FileName::fromUserInput("c:\\Program Files (x86)\\Microsoft Visual Studio 10.0\\VC\\INCLUDE\\xutility"), 2212,
+ FilePath::fromUserInput("c:\\Program Files (x86)\\Microsoft Visual Studio 10.0\\VC\\INCLUDE\\xutility"), 2212,
Constants::TASK_CATEGORY_COMPILE)
<< Task(Task::Unknown,
"see reference to function template instantiation '_OutIt std::copy<const unsigned char*,unsigned short*>(_InIt,_InIt,_OutIt)' being compiled\n"
@@ -520,7 +520,7 @@ void ProjectExplorerPlugin::testMsvcOutputParsers_data()
" _OutIt=unsigned short *,\n"
" _InIt=const unsigned char *\n"
"]",
- FileName::fromUserInput("symbolgroupvalue.cpp"), 2314,
+ FilePath::fromUserInput("symbolgroupvalue.cpp"), 2314,
Constants::TASK_CATEGORY_COMPILE))
<< "";
@@ -530,25 +530,25 @@ void ProjectExplorerPlugin::testMsvcOutputParsers_data()
" or 'D:\\Project\\types.h(71) : Types::UINT64'"
<< OutputParserTester::STDOUT
<< "" << ""
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Error,
"C2872: 'UINT64' : ambiguous symbol",
- FileName::fromUserInput("D:\\Project\\file.h"), 98,
+ FilePath::fromUserInput("D:\\Project\\file.h"), 98,
Constants::TASK_CATEGORY_COMPILE)
<< Task(Task::Unknown,
"could be unsigned __int64 UINT64",
- FileName::fromUserInput("C:\\Program Files (x86)\\Microsoft SDKs\\Windows\\v7.0A\\include\\basetsd.h"), 83,
+ FilePath::fromUserInput("C:\\Program Files (x86)\\Microsoft SDKs\\Windows\\v7.0A\\include\\basetsd.h"), 83,
Constants::TASK_CATEGORY_COMPILE)
<< Task(Task::Unknown,
"or Types::UINT64",
- FileName::fromUserInput("D:\\Project\\types.h"), 71,
+ FilePath::fromUserInput("D:\\Project\\types.h"), 71,
Constants::TASK_CATEGORY_COMPILE))
<< "";
QTest::newRow("ignore moc note")
<< "/home/qtwebkithelpviewer.h:0: Note: No relevant classes found. No output generated."
<< OutputParserTester::STDERR
<< "" << "/home/qtwebkithelpviewer.h:0: Note: No relevant classes found. No output generated.\n"
- << (QList<ProjectExplorer::Task>())
+ << (Tasks())
<< "";
QTest::newRow("error with note")
@@ -556,14 +556,14 @@ void ProjectExplorerPlugin::testMsvcOutputParsers_data()
"main.cpp(6): note: see declaration of 'func'"
<< OutputParserTester::STDOUT
<< "" << ""
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Error,
"C2733: 'func': second C linkage of overloaded function not allowed",
- FileName::fromUserInput("main.cpp"), 7,
+ FilePath::fromUserInput("main.cpp"), 7,
Constants::TASK_CATEGORY_COMPILE)
<< Task(Task::Unknown,
"see declaration of 'func'",
- FileName::fromUserInput("main.cpp"), 6,
+ FilePath::fromUserInput("main.cpp"), 6,
Constants::TASK_CATEGORY_COMPILE))
<< "";
@@ -571,10 +571,10 @@ void ProjectExplorerPlugin::testMsvcOutputParsers_data()
<< QString::fromUtf8("cl: командная строка warning D9025: переопределение \"/MDd\" на \"/MTd\"")
<< OutputParserTester::STDERR
<< "" << ""
- << (QList<ProjectExplorer::Task>()
+ << (Tasks()
<< Task(Task::Warning,
QString::fromUtf8("D9025: переопределение \"/MDd\" на \"/MTd\""),
- FileName(), -1, Constants::TASK_CATEGORY_COMPILE))
+ FilePath(), -1, Constants::TASK_CATEGORY_COMPILE))
<< "";
}
@@ -584,7 +584,7 @@ void ProjectExplorerPlugin::testMsvcOutputParsers()
testbench.appendOutputParser(new MsvcParser);
QFETCH(QString, input);
QFETCH(OutputParserTester::Channel, inputChannel);
- QFETCH(QList<Task>, tasks);
+ QFETCH(Tasks, tasks);
QFETCH(QString, childStdOutLines);
QFETCH(QString, childStdErrLines);
QFETCH(QString, outputLines);
@@ -600,7 +600,7 @@ void ProjectExplorerPlugin::testClangClOutputParsers_data()
QTest::addColumn<OutputParserTester::Channel>("inputChannel");
QTest::addColumn<QString>("childStdOutLines");
QTest::addColumn<QString>("childStdErrLines");
- QTest::addColumn<QList<Task> >("tasks");
+ QTest::addColumn<Tasks >("tasks");
QTest::addColumn<QString>("outputLines");
const QString warning1 = "private field 'm_version' is not used [-Wunused-private-field]\n"
@@ -643,21 +643,21 @@ void ProjectExplorerPlugin::testClangClOutputParsers_data()
<< input
<< OutputParserTester::STDERR
<< "" << expectedStderr
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Warning, warning1.trimmed(),
- FileName::fromUserInput("./qwindowseglcontext.h"), 282,
+ FilePath::fromUserInput("./qwindowseglcontext.h"), 282,
Constants::TASK_CATEGORY_COMPILE)
<< Task(Task::Warning, warning2.trimmed(),
- FileName::fromUserInput(".\\qwindowsclipboard.cpp"), 60,
+ FilePath::fromUserInput(".\\qwindowsclipboard.cpp"), 60,
Constants::TASK_CATEGORY_COMPILE)
<< Task(Task::Warning, warning3.trimmed(),
- FileName::fromUserInput(".\\qwindowsclipboard.cpp"), 61,
+ FilePath::fromUserInput(".\\qwindowsclipboard.cpp"), 61,
Constants::TASK_CATEGORY_COMPILE)
<< Task(Task::Error, expectedError1,
- FileName::fromUserInput(".\\qwindowsgdinativeinterface.cpp"), 48,
+ FilePath::fromUserInput(".\\qwindowsgdinativeinterface.cpp"), 48,
Constants::TASK_CATEGORY_COMPILE)
<< Task(Task::Error, error2.trimmed(),
- FileName::fromUserInput(".\\qwindowsgdinativeinterface.cpp"), 51,
+ FilePath::fromUserInput(".\\qwindowsgdinativeinterface.cpp"), 51,
Constants::TASK_CATEGORY_COMPILE))
<< "";
}
@@ -668,7 +668,7 @@ void ProjectExplorerPlugin::testClangClOutputParsers()
testbench.appendOutputParser(new ClangClParser);
QFETCH(QString, input);
QFETCH(OutputParserTester::Channel, inputChannel);
- QFETCH(QList<Task>, tasks);
+ QFETCH(Tasks, tasks);
QFETCH(QString, childStdOutLines);
QFETCH(QString, childStdErrLines);
QFETCH(QString, outputLines);
diff --git a/src/plugins/projectexplorer/msvctoolchain.cpp b/src/plugins/projectexplorer/msvctoolchain.cpp
index 9c86a70686..24b528154d 100644
--- a/src/plugins/projectexplorer/msvctoolchain.cpp
+++ b/src/plugins/projectexplorer/msvctoolchain.cpp
@@ -60,10 +60,13 @@
#include <QComboBox>
#include <QFormLayout>
+using namespace Utils;
+
#define KEY_ROOT "ProjectExplorer.MsvcToolChain."
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 };
@@ -206,7 +209,7 @@ static Utils::optional<VisualStudioInstallation> installationFromPathAndVersion(
installation.vsName = versionString;
installation.vcVarsPath = vcVarsPath;
installation.vcVarsAll = vcVarsAllPath;
- return std::move(installation);
+ return installation;
}
// Detect build tools introduced with MSVC2017
@@ -349,33 +352,50 @@ static QVector<VisualStudioInstallation> detectVisualStudio()
return detectVisualStudioFromRegistry();
}
+static unsigned char wordWidthForPlatform(MsvcToolChain::Platform platform)
+{
+ switch (platform) {
+ case ProjectExplorer::Internal::MsvcToolChain::x86:
+ case ProjectExplorer::Internal::MsvcToolChain::arm:
+ case ProjectExplorer::Internal::MsvcToolChain::x86_arm:
+ case ProjectExplorer::Internal::MsvcToolChain::amd64_arm:
+ case ProjectExplorer::Internal::MsvcToolChain::amd64_x86:
+ return 32;
+ case ProjectExplorer::Internal::MsvcToolChain::amd64:
+ case ProjectExplorer::Internal::MsvcToolChain::x86_amd64:
+ case ProjectExplorer::Internal::MsvcToolChain::ia64:
+ case ProjectExplorer::Internal::MsvcToolChain::x86_ia64:
+ return 64;
+ }
+
+ return 0;
+}
+
+static Abi::Architecture archForPlatform(MsvcToolChain::Platform platform)
+{
+ switch (platform) {
+ case ProjectExplorer::Internal::MsvcToolChain::x86:
+ case ProjectExplorer::Internal::MsvcToolChain::amd64:
+ case ProjectExplorer::Internal::MsvcToolChain::x86_amd64:
+ case ProjectExplorer::Internal::MsvcToolChain::amd64_x86:
+ return Abi::X86Architecture;
+ case ProjectExplorer::Internal::MsvcToolChain::arm:
+ case ProjectExplorer::Internal::MsvcToolChain::x86_arm:
+ case ProjectExplorer::Internal::MsvcToolChain::amd64_arm:
+ return Abi::ArmArchitecture;
+ case ProjectExplorer::Internal::MsvcToolChain::ia64:
+ case ProjectExplorer::Internal::MsvcToolChain::x86_ia64:
+ return Abi::ItaniumArchitecture;
+ }
+
+ return Abi::UnknownArchitecture;
+}
+
static Abi findAbiOfMsvc(MsvcToolChain::Type type,
MsvcToolChain::Platform platform,
const QString &version)
{
- Abi::Architecture arch = Abi::X86Architecture;
Abi::OSFlavor flavor = Abi::UnknownFlavor;
- int wordWidth = 64;
-
- switch (platform) {
- case MsvcToolChain::x86:
- case MsvcToolChain::amd64_x86:
- wordWidth = 32;
- break;
- case MsvcToolChain::ia64:
- case MsvcToolChain::x86_ia64:
- arch = Abi::ItaniumArchitecture;
- break;
- case MsvcToolChain::amd64:
- case MsvcToolChain::x86_amd64:
- break;
- case MsvcToolChain::arm:
- case MsvcToolChain::x86_arm:
- case MsvcToolChain::amd64_arm:
- arch = Abi::ArmArchitecture;
- wordWidth = 32;
- break;
- };
QString msvcVersionString = version;
if (type == MsvcToolChain::WindowsSDK) {
@@ -400,7 +420,8 @@ static Abi findAbiOfMsvc(MsvcToolChain::Type type,
flavor = Abi::WindowsMsvc2008Flavor;
else
flavor = Abi::WindowsMsvc2005Flavor;
- const Abi result = Abi(arch, Abi::WindowsOS, flavor, Abi::PEFormat, wordWidth);
+ const Abi result = Abi(archForPlatform(platform), Abi::WindowsOS, flavor, Abi::PEFormat,
+ wordWidthForPlatform(platform));
if (!result.isValid())
qWarning("Unable to completely determine the ABI of MSVC version %s (%s).",
qPrintable(version),
@@ -592,7 +613,7 @@ Macros MsvcToolChain::msvcPredefinedMacros(const QStringList &cxxflags,
cpp.setEnvironment(env.toStringList());
cpp.setWorkingDirectory(Utils::TemporaryDirectory::masterDirectoryPath());
QStringList arguments;
- const Utils::FileName binary = env.searchInPath(QLatin1String("cl.exe"));
+ const Utils::FilePath binary = env.searchInPath(QLatin1String("cl.exe"));
if (binary.isEmpty()) {
qWarning("%s: The compiler binary cl.exe could not be found in the path.", Q_FUNC_INFO);
return predefinedMacros;
@@ -748,10 +769,46 @@ void MsvcToolChain::updateEnvironmentModifications(QList<Utils::EnvironmentItem>
Utils::EnvironmentItem::sort(&modifications);
if (modifications != m_environmentModifications) {
m_environmentModifications = modifications;
+ rescanForCompiler();
toolChainUpdated();
}
}
+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);
+ return;
+ }
+
+ QTC_ASSERT(m_supportedAbis.isEmpty(), return);
+ 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);
+}
+
Utils::Environment MsvcToolChain::readEnvironmentSetting(const Utils::Environment &env) const
{
Utils::Environment resultEnv = env;
@@ -780,67 +837,34 @@ Utils::Environment MsvcToolChain::readEnvironmentSetting(const Utils::Environmen
MsvcToolChain::MsvcToolChain(const QString &name,
const Abi &abi,
const QString &varsBat,
- const QString &varsBatArg,
- Core::Id l,
- Detection d)
- : MsvcToolChain(Constants::MSVC_TOOLCHAIN_TYPEID, name, abi, varsBat, varsBatArg, l, d)
+ const QString &varsBatArg)
+ : MsvcToolChain(Constants::MSVC_TOOLCHAIN_TYPEID, name, abi, varsBat, varsBatArg)
{}
-MsvcToolChain::MsvcToolChain(const MsvcToolChain &other)
- : ToolChain(other)
- , m_headerPathsMutex(new QMutex)
- , m_environmentModifications(other.m_environmentModifications)
- , m_debuggerCommand(other.m_debuggerCommand)
- , m_predefinedMacrosCache(other.m_predefinedMacrosCache)
- , m_lastEnvironment(other.m_lastEnvironment)
- , m_resultEnvironment(other.m_resultEnvironment)
- , m_abi(other.m_abi)
- , m_vcvarsBat(other.m_vcvarsBat)
- , m_varsBatArg(other.m_varsBatArg)
-{
- if (other.m_envModWatcher.isRunning()) {
- initEnvModWatcher(other.m_envModWatcher.future());
- } else if (m_environmentModifications.isEmpty() && other.m_envModWatcher.future().isFinished()
- && !other.m_envModWatcher.future().isCanceled()) {
- const GenerateEnvResult &result = m_envModWatcher.result();
- if (result.error) {
- const QString &errorMessage = *result.error;
- if (!errorMessage.isEmpty())
- TaskHub::addTask(Task::Error, errorMessage, Constants::TASK_CATEGORY_COMPILE);
- } else {
- updateEnvironmentModifications(result.environmentItems);
- }
- }
-
- setDisplayName(other.displayName());
-}
-
static void addToAvailableMsvcToolchains(const MsvcToolChain *toolchain)
{
if (toolchain->typeId() != Constants::MSVC_TOOLCHAIN_TYPEID)
return;
- g_availableMsvcToolchains.push_back(toolchain);
+ if (!g_availableMsvcToolchains.contains(toolchain))
+ g_availableMsvcToolchains.push_back(toolchain);
}
MsvcToolChain::MsvcToolChain(Core::Id typeId,
const QString &name,
const Abi &abi,
const QString &varsBat,
- const QString &varsBatArg,
- Core::Id l,
- Detection d)
- : ToolChain(typeId, d)
+ const QString &varsBatArg)
+ : ToolChain(typeId)
, m_headerPathsMutex(new QMutex)
- , m_predefinedMacrosCache(std::make_shared<Cache<MacroInspectionReport, 64>>())
, m_lastEnvironment(Utils::Environment::systemEnvironment())
, m_abi(abi)
, m_vcvarsBat(varsBat)
, m_varsBatArg(varsBatArg)
{
+ detectInstalledAbis();
addToAvailableMsvcToolchains(this);
- setLanguage(l);
initEnvModWatcher(Utils::runAsync(envModThreadPool(),
&MsvcToolChain::environmentModifications,
varsBat,
@@ -852,9 +876,7 @@ MsvcToolChain::MsvcToolChain(Core::Id typeId,
}
MsvcToolChain::MsvcToolChain(Core::Id typeId)
- : ToolChain(typeId, ManualDetection)
- , m_predefinedMacrosCache(std::make_shared<Cache<MacroInspectionReport, 64>>())
- , m_lastEnvironment(Utils::Environment::systemEnvironment())
+ : ToolChain(typeId)
{}
void MsvcToolChain::inferWarningsForLevel(int warningLevel, WarningFlags &flags)
@@ -876,11 +898,6 @@ void MsvcToolChain::inferWarningsForLevel(int warningLevel, WarningFlags &flags)
flags |= WarningFlags::UnusedParams;
}
-void MsvcToolChain::toolChainUpdated()
-{
- m_predefinedMacrosCache->invalidate();
-}
-
MsvcToolChain::MsvcToolChain()
: MsvcToolChain(Constants::MSVC_TOOLCHAIN_TYPEID)
{}
@@ -896,6 +913,19 @@ Abi MsvcToolChain::targetAbi() const
return m_abi;
}
+Abis MsvcToolChain::supportedAbis() const
+{
+ return m_supportedAbis;
+}
+
+void MsvcToolChain::setTargetAbi(const Abi &abi)
+{
+ if (m_abi == abi)
+ return;
+
+ m_abi = abi;
+}
+
bool MsvcToolChain::isValid() const
{
if (m_vcvarsBat.isEmpty())
@@ -915,53 +945,52 @@ QString MsvcToolChain::typeDisplayName() const
return MsvcToolChainFactory::tr("MSVC");
}
-Utils::FileNameList MsvcToolChain::suggestedMkspecList() const
+QStringList MsvcToolChain::suggestedMkspecList() const
{
- Utils::FileNameList result;
- result << Utils::FileName::fromLatin1("win32-msvc"); // Common MSVC mkspec introduced in 5.8.1
+ QStringList result = {"win32-msvc"}; // Common MSVC mkspec introduced in 5.8.1
switch (m_abi.osFlavor()) {
case Abi::WindowsMsvc2005Flavor:
- result << Utils::FileName::fromLatin1("win32-msvc2005");
+ result << "win32-msvc2005";
break;
case Abi::WindowsMsvc2008Flavor:
- result << Utils::FileName::fromLatin1("win32-msvc2008");
+ result << "win32-msvc2008";
break;
case Abi::WindowsMsvc2010Flavor:
- result << Utils::FileName::fromLatin1("win32-msvc2010");
+ result << "win32-msvc2010";
break;
case Abi::WindowsMsvc2012Flavor:
- result << Utils::FileName::fromLatin1("win32-msvc2012")
- << Utils::FileName::fromLatin1("win32-msvc2010");
+ result << "win32-msvc2012"
+ << "win32-msvc2010";
break;
case Abi::WindowsMsvc2013Flavor:
- result << Utils::FileName::fromLatin1("win32-msvc2013")
- << Utils::FileName::fromLatin1("winphone-arm-msvc2013")
- << Utils::FileName::fromLatin1("winphone-x86-msvc2013")
- << Utils::FileName::fromLatin1("winrt-arm-msvc2013")
- << Utils::FileName::fromLatin1("winrt-x86-msvc2013")
- << Utils::FileName::fromLatin1("winrt-x64-msvc2013")
- << Utils::FileName::fromLatin1("win32-msvc2012")
- << Utils::FileName::fromLatin1("win32-msvc2010");
+ result << "win32-msvc2013"
+ << "winphone-arm-msvc2013"
+ << "winphone-x86-msvc2013"
+ << "winrt-arm-msvc2013"
+ << "winrt-x86-msvc2013"
+ << "winrt-x64-msvc2013"
+ << "win32-msvc2012"
+ << "win32-msvc2010";
break;
case Abi::WindowsMsvc2015Flavor:
- result << Utils::FileName::fromLatin1("win32-msvc2015")
- << Utils::FileName::fromLatin1("winphone-arm-msvc2015")
- << Utils::FileName::fromLatin1("winphone-x86-msvc2015")
- << Utils::FileName::fromLatin1("winrt-arm-msvc2015")
- << Utils::FileName::fromLatin1("winrt-x86-msvc2015")
- << Utils::FileName::fromLatin1("winrt-x64-msvc2015");
+ result << "win32-msvc2015"
+ << "winphone-arm-msvc2015"
+ << "winphone-x86-msvc2015"
+ << "winrt-arm-msvc2015"
+ << "winrt-x86-msvc2015"
+ << "winrt-x64-msvc2015";
break;
case Abi::WindowsMsvc2017Flavor:
- result << Utils::FileName::fromLatin1("win32-msvc2017")
- << Utils::FileName::fromLatin1("winrt-arm-msvc2017")
- << Utils::FileName::fromLatin1("winrt-x86-msvc2017")
- << Utils::FileName::fromLatin1("winrt-x64-msvc2017");
+ result << "win32-msvc2017"
+ << "winrt-arm-msvc2017"
+ << "winrt-x86-msvc2017"
+ << "winrt-x64-msvc2017";
break;
case Abi::WindowsMsvc2019Flavor:
- result << Utils::FileName::fromLatin1("win32-msvc2019")
- << Utils::FileName::fromLatin1("winrt-arm-msvc2019")
- << Utils::FileName::fromLatin1("winrt-x86-msvc2019")
- << Utils::FileName::fromLatin1("winrt-x64-msvc2019");
+ result << "win32-msvc2019"
+ << "winrt-arm-msvc2019"
+ << "winrt-x86-msvc2019"
+ << "winrt-x64-msvc2019";
break;
default:
result.clear();
@@ -977,6 +1006,7 @@ 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));
@@ -989,34 +1019,40 @@ bool MsvcToolChain::fromMap(const QVariantMap &data)
return false;
m_vcvarsBat = QDir::fromNativeSeparators(data.value(QLatin1String(varsBatKeyC)).toString());
m_varsBatArg = data.value(QLatin1String(varsBatArgKeyC)).toString();
- addToAvailableMsvcToolchains(this);
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();
initEnvModWatcher(Utils::runAsync(envModThreadPool(),
&MsvcToolChain::environmentModifications,
m_vcvarsBat,
m_varsBatArg));
- return !m_vcvarsBat.isEmpty() && m_abi.isValid();
-}
+ // supported Abis were not stored in the map in previous versions of the settings. Re-detect
+ if (m_supportedAbis.isEmpty())
+ detectInstalledAbis();
-std::unique_ptr<ToolChainConfigWidget> MsvcToolChain::createConfigurationWidget()
-{
- return std::make_unique<MsvcToolChainConfigWidget>(this);
-}
+ const bool valid = !m_vcvarsBat.isEmpty() && m_abi.isValid() && !m_supportedAbis.isEmpty();
+ if (valid)
+ addToAvailableMsvcToolchains(this);
-bool MsvcToolChain::canClone() const
-{
- return true;
+ return valid;
}
-ToolChain *MsvcToolChain::clone() const
+std::unique_ptr<ToolChainConfigWidget> MsvcToolChain::createConfigurationWidget()
{
- return new MsvcToolChain(*this);
+ return std::make_unique<MsvcToolChainConfigWidget>(this);
}
bool static hasFlagEffectOnMacros(const QString &flag)
@@ -1037,7 +1073,7 @@ ToolChain::MacroInspectionRunner MsvcToolChain::createMacroInspectionRunner() co
{
Utils::Environment env(m_lastEnvironment);
addToEnvironment(env);
- std::shared_ptr<Cache<MacroInspectionReport, 64>> macroCache = m_predefinedMacrosCache;
+ MacrosCache macroCache = predefinedMacrosCache();
const Core::Id lang = language();
// This runner must be thread-safe!
@@ -1131,7 +1167,7 @@ ToolChain::BuiltInHeaderPathsRunner MsvcToolChain::createBuiltInHeaderPathsRunne
Utils::Environment env(m_lastEnvironment);
addToEnvironment(env);
- return [this, env](const QStringList &, const QString &) {
+ return [this, env](const QStringList &, const QString &, const QString &) {
QMutexLocker locker(m_headerPathsMutex);
if (m_headerPaths.isEmpty()) {
foreach (const QString &path,
@@ -1144,9 +1180,9 @@ ToolChain::BuiltInHeaderPathsRunner MsvcToolChain::createBuiltInHeaderPathsRunne
}
HeaderPaths MsvcToolChain::builtInHeaderPaths(const QStringList &cxxflags,
- const Utils::FileName &sysRoot) const
+ const Utils::FilePath &sysRoot) const
{
- return createBuiltInHeaderPathsRunner()(cxxflags, sysRoot.toString());
+ return createBuiltInHeaderPathsRunner()(cxxflags, sysRoot.toString(), "");
}
void MsvcToolChain::addToEnvironment(Utils::Environment &env) const
@@ -1174,44 +1210,49 @@ static QString wrappedMakeCommand(const QString &command)
return wrapperPath;
}
-QString MsvcToolChain::makeCommand(const Utils::Environment &environment) const
+FilePath MsvcToolChain::makeCommand(const Environment &environment) const
{
bool useJom = ProjectExplorerPlugin::projectExplorerSettings().useJom;
const QString jom("jom.exe");
const QString nmake("nmake.exe");
- Utils::FileName tmp;
+ Utils::FilePath tmp;
- QString command;
+ FilePath command;
if (useJom) {
tmp = environment.searchInPath(jom,
- {Utils::FileName::fromString(
+ {Utils::FilePath::fromString(
QCoreApplication::applicationDirPath())});
if (!tmp.isEmpty())
- command = tmp.toString();
+ command = tmp;
}
if (command.isEmpty()) {
tmp = environment.searchInPath(nmake);
if (!tmp.isEmpty())
- command = tmp.toString();
+ command = tmp;
}
if (command.isEmpty())
- command = useJom ? jom : nmake;
+ command = FilePath::fromString(useJom ? jom : nmake);
if (environment.hasKey("VSLANG"))
- return wrappedMakeCommand(command);
+ return FilePath::fromString(wrappedMakeCommand(command.toString()));
return command;
}
-Utils::FileName MsvcToolChain::compilerCommand() const
+Utils::FilePath MsvcToolChain::compilerCommand() const
+{
+ return m_compilerCommand;
+}
+
+void MsvcToolChain::rescanForCompiler()
{
Utils::Environment env = Utils::Environment::systemEnvironment();
addToEnvironment(env);
- Utils::FileName clexe
- = env.searchInPath(QLatin1String("cl.exe"), {}, [](const Utils::FileName &name) {
+ m_compilerCommand
+ = env.searchInPath(QLatin1String("cl.exe"), {}, [](const Utils::FilePath &name) {
QDir dir(QDir::cleanPath(name.toFileInfo().absolutePath() + QStringLiteral("/..")));
do {
if (QFile::exists(dir.absoluteFilePath(QStringLiteral("vcvarsall.bat")))
@@ -1220,7 +1261,6 @@ Utils::FileName MsvcToolChain::compilerCommand() const
} while (dir.cdUp() && !dir.isRoot());
return false;
});
- return clexe;
}
IOutputParser *MsvcToolChain::outputParser() const
@@ -1228,6 +1268,20 @@ IOutputParser *MsvcToolChain::outputParser() const
return new MsvcParser;
}
+void MsvcToolChain::changeVcVarsCall(const QString &varsBat, const QString &varsBatArg)
+{
+ m_vcvarsBat = varsBat;
+ m_varsBatArg = varsBatArg;
+
+ if (!varsBat.isEmpty()) {
+ detectInstalledAbis();
+ initEnvModWatcher(Utils::runAsync(envModThreadPool(),
+ &ClangClToolChain::environmentModifications,
+ m_vcvarsBat,
+ m_varsBatArg));
+ }
+}
+
// --------------------------------------------------------------------------
// MsvcBasedToolChainConfigWidget: Creates a simple GUI without error label
// to display name and varsBat. Derived classes should add the error label and
@@ -1269,9 +1323,148 @@ void MsvcBasedToolChainConfigWidget::setFromMsvcToolChain()
MsvcToolChainConfigWidget::MsvcToolChainConfigWidget(ToolChain *tc)
: MsvcBasedToolChainConfigWidget(tc)
+ , m_varsBatPathCombo(new QComboBox(this))
+ , m_varsBatArchCombo(new QComboBox(this))
+ , m_varsBatArgumentsEdit(new QLineEdit(this))
+ , m_abiWidget(new AbiWidget)
{
+ m_mainLayout->removeRow(m_mainLayout->rowCount() - 1);
+
+ QHBoxLayout *hLayout = new QHBoxLayout();
+ m_varsBatPathCombo->setObjectName("varsBatCombo");
+ m_varsBatPathCombo->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
+ m_varsBatPathCombo->setEditable(true);
+ for (const MsvcToolChain *tmpTc : g_availableMsvcToolchains) {
+ const QString nativeVcVars = QDir::toNativeSeparators(tmpTc->varsBat());
+ if (!tmpTc->varsBat().isEmpty()
+ && m_varsBatPathCombo->findText(nativeVcVars) == -1) {
+ m_varsBatPathCombo->addItem(nativeVcVars);
+ }
+ }
+ const bool isAmd64
+ = Utils::HostOsInfo::hostArchitecture() == Utils::HostOsInfo::HostArchitectureAMD64;
+ // TODO: Add missing values to MsvcToolChain::Platform
+ m_varsBatArchCombo->addItem(tr("<empty>"), isAmd64 ? MsvcToolChain::amd64 : MsvcToolChain::x86);
+ m_varsBatArchCombo->addItem("x86", MsvcToolChain::x86);
+ m_varsBatArchCombo->addItem("amd64", MsvcToolChain::amd64);
+ m_varsBatArchCombo->addItem("arm", MsvcToolChain::arm);
+ m_varsBatArchCombo->addItem("x86_amd64", MsvcToolChain::x86_amd64);
+ m_varsBatArchCombo->addItem("x86_arm", MsvcToolChain::x86_arm);
+// m_varsBatArchCombo->addItem("x86_arm64", MsvcToolChain::x86_arm64);
+ m_varsBatArchCombo->addItem("amd64_x86", MsvcToolChain::amd64_x86);
+ m_varsBatArchCombo->addItem("amd64_arm", MsvcToolChain::amd64_arm);
+// m_varsBatArchCombo->addItem("amd64_arm64", MsvcToolChain::amd64_arm64);
+ m_varsBatArchCombo->addItem("ia64", MsvcToolChain::ia64);
+ m_varsBatArchCombo->addItem("x86_ia64", MsvcToolChain::x86_ia64);
+ m_varsBatArgumentsEdit->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
+ m_varsBatArgumentsEdit->setToolTip(tr("Additional arguments for the vcvarsall.bat call"));
+ hLayout->addWidget(m_varsBatPathCombo);
+ hLayout->addWidget(m_varsBatArchCombo);
+ hLayout->addWidget(m_varsBatArgumentsEdit);
+ m_mainLayout->addRow(tr("Initialization:"), hLayout);
+ m_mainLayout->addRow(tr("&ABI:"), m_abiWidget);
addErrorLabel();
setFromMsvcToolChain();
+
+ connect(m_varsBatPathCombo, &QComboBox::currentTextChanged,
+ this, &MsvcToolChainConfigWidget::handleVcVarsChange);
+ connect(m_varsBatArchCombo, &QComboBox::currentTextChanged,
+ this, &MsvcToolChainConfigWidget::handleVcVarsArchChange);
+ connect(m_varsBatArgumentsEdit, &QLineEdit::textChanged,
+ this, &ToolChainConfigWidget::dirty);
+ connect(m_abiWidget, &AbiWidget::abiChanged, this, &ToolChainConfigWidget::dirty);
+}
+
+void MsvcToolChainConfigWidget::applyImpl()
+{
+ auto *tc = static_cast<MsvcToolChain *>(toolChain());
+ QTC_ASSERT(tc, return );
+ tc->setTargetAbi(m_abiWidget->currentAbi());
+ const QString vcVars = QDir::fromNativeSeparators(m_varsBatPathCombo->currentText());
+ tc->changeVcVarsCall(vcVars, vcVarsArguments());
+ setFromMsvcToolChain();
+}
+
+void MsvcToolChainConfigWidget::discardImpl()
+{
+ setFromMsvcToolChain();
+}
+
+bool MsvcToolChainConfigWidget::isDirtyImpl() const
+{
+ auto msvcToolChain = static_cast<MsvcToolChain *>(toolChain());
+
+ return msvcToolChain->varsBat() != QDir::fromNativeSeparators(m_varsBatPathCombo->currentText())
+ || msvcToolChain->varsBatArg() != vcVarsArguments()
+ || msvcToolChain->targetAbi() != m_abiWidget->currentAbi();
+}
+
+void MsvcToolChainConfigWidget::makeReadOnlyImpl()
+{
+ m_varsBatPathCombo->setEnabled(false);
+ m_varsBatArchCombo->setEnabled(false);
+ m_varsBatArgumentsEdit->setEnabled(false);
+ m_abiWidget->setEnabled(false);
+}
+
+void MsvcToolChainConfigWidget::setFromMsvcToolChain()
+{
+ const auto *tc = static_cast<const MsvcToolChain *>(toolChain());
+ QTC_ASSERT(tc, return );
+ m_nameDisplayLabel->setText(tc->displayName());
+ QString args = tc->varsBatArg();
+ QStringList argList = args.split(' ');
+ for (int i = 0; i < argList.count(); ++i) {
+ if (m_varsBatArchCombo->findText(argList.at(i).trimmed()) != -1) {
+ const QString arch = argList.takeAt(i);
+ m_varsBatArchCombo->setCurrentText(arch);
+ args = argList.join(QLatin1Char(' '));
+ break;
+ }
+ }
+ m_varsBatPathCombo->setCurrentText(QDir::toNativeSeparators(tc->varsBat()));
+ m_varsBatArgumentsEdit->setText(args);
+ m_abiWidget->setAbis(tc->supportedAbis(), tc->targetAbi());
+}
+
+void MsvcToolChainConfigWidget::handleVcVarsChange(const QString &vcVars)
+{
+ const QString normalizedVcVars = QDir::fromNativeSeparators(vcVars);
+ 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);
+
+ 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;
+ }
+ }
+ emit dirty();
+}
+
+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();
+}
+
+QString MsvcToolChainConfigWidget::vcVarsArguments() const
+{
+ QString varsBatArg
+ = m_varsBatArchCombo->currentText() == tr("<empty>")
+ ? "" : m_varsBatArchCombo->currentText();
+ if (!m_varsBatArgumentsEdit->text().isEmpty())
+ varsBatArg += QLatin1Char(' ') + m_varsBatArgumentsEdit->text();
+ return varsBatArg;
}
// --------------------------------------------------------------------------
@@ -1284,6 +1477,7 @@ ClangClToolChainConfigWidget::ClangClToolChainConfigWidget(ToolChain *tc) :
{
m_mainLayout->removeRow(m_mainLayout->rowCount() - 1);
+ m_varsBatDisplayCombo->setObjectName("varsBatCombo");
m_varsBatDisplayCombo->setSizeAdjustPolicy(QComboBox::AdjustToContents);
m_mainLayout->addRow(tr("Initialization:"), m_varsBatDisplayCombo);
@@ -1326,7 +1520,7 @@ void ClangClToolChainConfigWidget::setFromClangClToolChain()
if (clangClToolChain->isAutoDetected())
m_llvmDirLabel->setText(QDir::toNativeSeparators(clangClToolChain->clangPath()));
else
- m_compilerCommand->setFileName(Utils::FileName::fromString(clangClToolChain->clangPath()));
+ m_compilerCommand->setFileName(Utils::FilePath::fromString(clangClToolChain->clangPath()));
}
static const MsvcToolChain *findMsvcToolChain(unsigned char wordWidth, Abi::OSFlavor flavor)
@@ -1418,7 +1612,9 @@ static QList<ToolChain *> detectClangClToolChainInPath(const QString &clangClPat
clangClPath);
}));
if (!tc) {
- tc = new ClangClToolChain(name, clangClPath, language, ToolChain::AutoDetection);
+ tc = new ClangClToolChain(name, clangClPath);
+ tc->setDetection(ToolChain::AutoDetection);
+ tc->setLanguage(language);
tc->resetMsvcToolChain(toolChain);
}
res << tc;
@@ -1433,7 +1629,7 @@ static QString compilerFromPath(const QString &path)
void ClangClToolChainConfigWidget::applyImpl()
{
- Utils::FileName clangClPath = m_compilerCommand->fileName();
+ Utils::FilePath clangClPath = m_compilerCommand->fileName();
auto clangClToolChain = static_cast<ClangClToolChain *>(toolChain());
clangClToolChain->setClangPath(clangClPath.toString());
@@ -1479,10 +1675,8 @@ void ClangClToolChainConfigWidget::makeReadOnlyImpl()
// --------------------------------------------------------------------------
ClangClToolChain::ClangClToolChain(const QString &name,
- const QString &clangPath,
- Core::Id language,
- Detection d)
- : MsvcToolChain(Constants::CLANG_CL_TOOLCHAIN_TYPEID, name, Abi(), "", "", language, d)
+ const QString &clangPath)
+ : MsvcToolChain(Constants::CLANG_CL_TOOLCHAIN_TYPEID, name, Abi(), "", "")
, m_clangPath(clangPath)
{}
@@ -1503,9 +1697,9 @@ void ClangClToolChain::addToEnvironment(Utils::Environment &env) const
env.prependOrSetPath(path.canonicalPath());
}
-Utils::FileName ClangClToolChain::compilerCommand() const
+Utils::FilePath ClangClToolChain::compilerCommand() const
{
- return Utils::FileName::fromString(m_clangPath);
+ return Utils::FilePath::fromString(m_clangPath);
}
QString ClangClToolChain::typeDisplayName() const
@@ -1513,11 +1707,10 @@ QString ClangClToolChain::typeDisplayName() const
return QCoreApplication::translate("ProjectExplorer::ClangToolChainFactory", "Clang");
}
-QList<Utils::FileName> ClangClToolChain::suggestedMkspecList() const
+QStringList ClangClToolChain::suggestedMkspecList() const
{
- const QString mkspec = QLatin1String("win32-clang-") + Abi::toString(targetAbi().osFlavor());
- return QList<Utils::FileName>{Utils::FileName::fromString(mkspec),
- Utils::FileName::fromString("win32-clang-msvc")};
+ const QString mkspec = "win32-clang-" + Abi::toString(targetAbi().osFlavor());
+ return {mkspec, "win32-clang-msvc"};
}
IOutputParser *ClangClToolChain::outputParser() const
@@ -1525,11 +1718,6 @@ IOutputParser *ClangClToolChain::outputParser() const
return new ClangClParser;
}
-ToolChain *ClangClToolChain::clone() const
-{
- return new ClangClToolChain(*this);
-}
-
static inline QString llvmDirKey()
{
return QStringLiteral("ProjectExplorer.ClangClToolChain.LlvmDir");
@@ -1563,18 +1751,12 @@ void ClangClToolChain::resetMsvcToolChain(const MsvcToolChain *base)
{
if (!base) {
m_abi = Abi();
- m_vcvarsBat.clear();
- setVarsBatArg("");
+ changeVcVarsCall("");
return;
}
- m_abi = base->targetAbi();
- m_vcvarsBat = base->varsBat();
- setVarsBatArg(base->varsBatArg());
- initEnvModWatcher(Utils::runAsync(envModThreadPool(),
- &ClangClToolChain::environmentModifications,
- m_vcvarsBat,
- base->varsBatArg()));
+ m_abi = base->targetAbi();
+ changeVcVarsCall(base->varsBat(), base->varsBatArg());
}
bool ClangClToolChain::operator==(const ToolChain &other) const
@@ -1618,12 +1800,6 @@ Utils::LanguageVersion ClangClToolChain::msvcLanguageVersion(const QStringList &
return MsvcToolChain::msvcLanguageVersion(cxxflags, language, macros);
}
-void ClangClToolChain::toolChainUpdated()
-{
- MsvcToolChain::toolChainUpdated();
- ToolChain::toolChainUpdated();
-}
-
ClangClToolChain::BuiltInHeaderPathsRunner ClangClToolChain::createBuiltInHeaderPathsRunner() const
{
{
@@ -1641,11 +1817,9 @@ ClangClToolChain::BuiltInHeaderPathsRunner ClangClToolChain::createBuiltInHeader
MsvcToolChainFactory::MsvcToolChainFactory()
{
setDisplayName(tr("MSVC"));
-}
-
-QSet<Core::Id> MsvcToolChainFactory::supportedLanguages() const
-{
- return {Constants::C_LANGUAGE_ID, Constants::CXX_LANGUAGE_ID};
+ setSupportedToolChainType(Constants::MSVC_TOOLCHAIN_TYPEID);
+ setSupportedLanguages({Constants::C_LANGUAGE_ID, Constants::CXX_LANGUAGE_ID});
+ setToolchainConstructor([] { return new MsvcToolChain; });
}
QString MsvcToolChainFactory::vcVarsBatFor(const QString &basePath,
@@ -1668,8 +1842,7 @@ static QList<ToolChain *> findOrCreateToolChain(const QList<ToolChain *> &alread
const QString &name,
const Abi &abi,
const QString &varsBat,
- const QString &varsBatArg,
- ToolChain::Detection d = ToolChain::ManualDetection)
+ const QString &varsBatArg)
{
QList<ToolChain *> res;
for (auto language : {Constants::C_LANGUAGE_ID, Constants::CXX_LANGUAGE_ID}) {
@@ -1683,8 +1856,10 @@ static QList<ToolChain *> findOrCreateToolChain(const QList<ToolChain *> &alread
auto mtc = static_cast<MsvcToolChain *>(tc);
return mtc->varsBat() == varsBat && mtc->varsBatArg() == varsBatArg;
});
- if (!tc)
- tc = new MsvcToolChain(name, abi, varsBat, varsBatArg, language, d);
+ if (!tc) {
+ tc = new MsvcToolChain(name, abi, varsBat, varsBatArg);
+ tc->setLanguage(language);
+ }
res << tc;
}
return res;
@@ -1719,12 +1894,13 @@ static void detectCppBuildTools2015(QList<ToolChain *> *list)
e.format,
e.wordSize);
for (auto language : {Constants::C_LANGUAGE_ID, Constants::CXX_LANGUAGE_ID}) {
- list->append(new MsvcToolChain(name + QLatin1String(e.postFix),
- abi,
- vcVarsBat,
- QLatin1String(e.varsBatArg),
- language,
- ToolChain::AutoDetection));
+ auto tc = new MsvcToolChain(name + QLatin1String(e.postFix),
+ abi,
+ vcVarsBat,
+ QLatin1String(e.varsBatArg));
+ tc->setDetection(ToolChain::AutoDetection);
+ tc->setLanguage(language);
+ list->append(tc);
}
}
}
@@ -1770,8 +1946,7 @@ QList<ToolChain *> MsvcToolChainFactory::autoDetect(const QList<ToolChain *> &al
platform.first,
sdkKey),
fi.absoluteFilePath(),
- "/" + platform.second,
- ToolChain::AutoDetection));
+ "/" + platform.second));
}
// Make sure the default is front.
if (folder == defaultSdkPath)
@@ -1806,23 +1981,28 @@ QList<ToolChain *> MsvcToolChainFactory::autoDetect(const QList<ToolChain *> &al
generateDisplayName(i.vsName, MsvcToolChain::VS, platform),
findAbiOfMsvc(MsvcToolChain::VS, platform, i.vsName),
i.vcVarsAll,
- platformName(platform),
- ToolChain::AutoDetection));
+ platformName(platform)));
}
}
}
detectCppBuildTools2015(&results);
+ for (ToolChain *tc : results)
+ tc->setDetection(ToolChain::AutoDetection);
+
return results;
}
ClangClToolChainFactory::ClangClToolChainFactory()
{
setDisplayName(tr("clang-cl"));
+ setSupportedLanguages({Constants::C_LANGUAGE_ID, Constants::CXX_LANGUAGE_ID});
+ setSupportedToolChainType(Constants::CLANG_CL_TOOLCHAIN_TYPEID);
+ setToolchainConstructor([] { return new ClangClToolChain; });
}
-bool ClangClToolChainFactory::canCreate()
+bool ClangClToolChainFactory::canCreate() const
{
return !g_availableMsvcToolchains.isEmpty();
}
@@ -1842,9 +2022,9 @@ QList<ToolChain *> ClangClToolChainFactory::autoDetect(const QList<ToolChain *>
QString qtCreatorsClang = Core::ICore::clangExecutable(CLANG_BINDIR);
if (!qtCreatorsClang.isEmpty()) {
- qtCreatorsClang = Utils::FileName::fromString(qtCreatorsClang)
+ qtCreatorsClang = Utils::FilePath::fromString(qtCreatorsClang)
.parentDir()
- .appendPath("clang-cl.exe")
+ .pathAppended("clang-cl.exe")
.toString();
results.append(detectClangClToolChainInPath(qtCreatorsClang, alreadyKnown, "", true));
known.append(results);
@@ -1861,16 +2041,16 @@ QList<ToolChain *> ClangClToolChainFactory::autoDetect(const QList<ToolChain *>
}
const Utils::Environment systemEnvironment = Utils::Environment::systemEnvironment();
- const Utils::FileName clangClPath = systemEnvironment.searchInPath("clang-cl");
+ const Utils::FilePath clangClPath = systemEnvironment.searchInPath("clang-cl");
if (!clangClPath.isEmpty())
results.append(detectClangClToolChainInPath(clangClPath.toString(), known, ""));
return results;
}
-ToolChain *ClangClToolChainFactory::create(Core::Id l)
+ToolChain *ClangClToolChainFactory::create()
{
- return new ClangClToolChain("clang-cl", "", l, ToolChain::ManualDetection);
+ return new ClangClToolChain("clang-cl", "");
}
bool MsvcToolChain::operator==(const ToolChain &other) const
@@ -1926,7 +2106,7 @@ Utils::optional<QString> MsvcToolChain::generateEnvironmentSettings(const Utils:
runEnv.unset(QLatin1String("ORIGINALPATH"));
run.setEnvironment(runEnv.toStringList());
run.setTimeoutS(30);
- Utils::FileName cmdPath = Utils::FileName::fromUserInput(
+ Utils::FilePath cmdPath = Utils::FilePath::fromUserInput(
QString::fromLocal8Bit(qgetenv("COMSPEC")));
if (cmdPath.isEmpty())
cmdPath = env.searchInPath(QLatin1String("cmd.exe"));
@@ -1984,36 +2164,15 @@ Utils::optional<QString> MsvcToolChain::generateEnvironmentSettings(const Utils:
return Utils::nullopt;
}
-bool MsvcToolChainFactory::canRestore(const QVariantMap &data)
-{
- const Core::Id id = typeIdFromMap(data);
- return id == Constants::MSVC_TOOLCHAIN_TYPEID;
-}
-
-template<class ToolChainType>
-ToolChainType *readFromMap(const QVariantMap &data)
+bool MsvcToolChainFactory::canCreate() const
{
- auto result = new ToolChainType;
- if (result->fromMap(data))
- return result;
- delete result;
- return nullptr;
-}
-
-ToolChain *MsvcToolChainFactory::restore(const QVariantMap &data)
-{
- return readFromMap<MsvcToolChain>(data);
-}
-
-bool ClangClToolChainFactory::canRestore(const QVariantMap &data)
-{
- const Core::Id id = typeIdFromMap(data);
- return id == Constants::CLANG_CL_TOOLCHAIN_TYPEID;
+ return !g_availableMsvcToolchains.isEmpty();
}
-ToolChain *ClangClToolChainFactory::restore(const QVariantMap &data)
+ToolChain *MsvcToolChainFactory::create()
{
- return readFromMap<ClangClToolChain>(data);
+ return new MsvcToolChain("Microsoft Visual C++ Compiler",
+ Abi::hostAbi(), g_availableMsvcToolchains.first()->varsBat(), "");
}
MsvcToolChain::WarningFlagAdder::WarningFlagAdder(const QString &flag, WarningFlags &flags)
@@ -2056,3 +2215,5 @@ bool MsvcToolChain::WarningFlagAdder::triggered() const
} // namespace Internal
} // namespace ProjectExplorer
+
+Q_DECLARE_METATYPE(ProjectExplorer::Internal::MsvcToolChain::Platform)
diff --git a/src/plugins/projectexplorer/msvctoolchain.h b/src/plugins/projectexplorer/msvctoolchain.h
index 10caaadfee..bc0adb00ba 100644
--- a/src/plugins/projectexplorer/msvctoolchain.h
+++ b/src/plugins/projectexplorer/msvctoolchain.h
@@ -26,8 +26,8 @@
#pragma once
#include "abi.h"
+#include "abiwidget.h"
#include "toolchain.h"
-#include "toolchaincache.h"
#include "toolchainconfigwidget.h"
#include <QFutureWatcher>
@@ -59,20 +59,19 @@ public:
explicit MsvcToolChain(const QString &name,
const Abi &abi,
const QString &varsBat,
- const QString &varsBatArg,
- Core::Id l,
- Detection d = ManualDetection);
- MsvcToolChain(const MsvcToolChain &other);
+ const QString &varsBatArg);
MsvcToolChain();
~MsvcToolChain() override;
Abi targetAbi() const override;
+ Abis supportedAbis() const override;
+ void setTargetAbi(const Abi &abi);
bool isValid() const override;
QString originalTargetTriple() const override;
- Utils::FileNameList suggestedMkspecList() const override;
+ QStringList suggestedMkspecList() const override;
QString typeDisplayName() const override;
@@ -81,34 +80,33 @@ public:
std::unique_ptr<ToolChainConfigWidget> createConfigurationWidget() override;
- bool canClone() const override;
- ToolChain *clone() const override;
-
MacroInspectionRunner createMacroInspectionRunner() const override;
Macros predefinedMacros(const QStringList &cxxflags) const override;
Utils::LanguageExtensions languageExtensions(const QStringList &cxxflags) const override;
WarningFlags warningFlags(const QStringList &cflags) const override;
BuiltInHeaderPathsRunner createBuiltInHeaderPathsRunner() const override;
HeaderPaths builtInHeaderPaths(const QStringList &cxxflags,
- const Utils::FileName &sysRoot) const override;
+ const Utils::FilePath &sysRoot) const override;
void addToEnvironment(Utils::Environment &env) const override;
- QString makeCommand(const Utils::Environment &environment) const override;
- Utils::FileName compilerCommand() const override;
+ Utils::FilePath makeCommand(const Utils::Environment &environment) const override;
+ Utils::FilePath compilerCommand() const override;
IOutputParser *outputParser() const override;
QString varsBatArg() const { return m_varsBatArg; }
QString varsBat() const { return m_vcvarsBat; }
void setVarsBatArg(const QString &varsBA) { m_varsBatArg = varsBA; }
+ void changeVcVarsCall(const QString &varsBat, const QString &varsBatArgs = QString());
bool operator==(const ToolChain &) const override;
+ bool isJobCountSupported() const override { return false; }
+
static void cancelMsvcToolChainDetection();
static Utils::optional<QString> generateEnvironmentSettings(const Utils::Environment &env,
const QString &batchFile,
const QString &batchArgs,
QMap<QString, QString> &envPairs);
-
protected:
class WarningFlagAdder
{
@@ -128,13 +126,10 @@ protected:
const QString &name,
const Abi &abi,
const QString &varsBat,
- const QString &varsBatArg,
- Core::Id l,
- Detection d);
+ const QString &varsBatArg);
explicit MsvcToolChain(Core::Id typeId);
static void inferWarningsForLevel(int warningLevel, WarningFlags &flags);
- void toolChainUpdated() override;
Utils::Environment readEnvironmentSetting(const Utils::Environment &env) const;
// Function must be thread-safe!
@@ -160,37 +155,37 @@ protected:
private:
void updateEnvironmentModifications(QList<Utils::EnvironmentItem> modifications);
+ void rescanForCompiler();
+ void detectInstalledAbis();
mutable QList<Utils::EnvironmentItem> m_environmentModifications;
mutable QFutureWatcher<GenerateEnvResult> m_envModWatcher;
- Utils::FileName m_debuggerCommand;
-
- mutable std::shared_ptr<Cache<MacroInspectionReport, 64>> m_predefinedMacrosCache;
-
mutable Utils::Environment m_lastEnvironment; // Last checked 'incoming' environment.
mutable Utils::Environment m_resultEnvironment; // Resulting environment for VC
+ Utils::FilePath m_compilerCommand;
+
protected:
Abi m_abi;
+ Abis m_supportedAbis;
QString m_vcvarsBat;
QString m_varsBatArg; // Argument
};
-class ClangClToolChain : public MsvcToolChain
+class PROJECTEXPLORER_EXPORT ClangClToolChain : public MsvcToolChain
{
public:
- ClangClToolChain(const QString &name, const QString &llvmDir, Core::Id language, Detection d);
+ ClangClToolChain(const QString &name, const QString &llvmDir);
ClangClToolChain();
bool isValid() const override;
QString typeDisplayName() const override;
- QList<Utils::FileName> suggestedMkspecList() const override;
+ QStringList suggestedMkspecList() const override;
void addToEnvironment(Utils::Environment &env) const override;
- Utils::FileName compilerCommand() const override;
+ Utils::FilePath compilerCommand() const override;
IOutputParser *outputParser() const override;
- ToolChain *clone() const override;
QVariantMap toMap() const override;
bool fromMap(const QVariantMap &data) override;
std::unique_ptr<ToolChainConfigWidget> createConfigurationWidget() override;
@@ -210,9 +205,6 @@ public:
bool operator==(const ToolChain &) const override;
private:
- void toolChainUpdated() override;
-
-private:
QString m_clangPath;
};
@@ -226,19 +218,18 @@ class MsvcToolChainFactory : public ToolChainFactory
public:
MsvcToolChainFactory();
- QSet<Core::Id> supportedLanguages() const override;
QList<ToolChain *> autoDetect(const QList<ToolChain *> &alreadyKnown) override;
- bool canRestore(const QVariantMap &data) override;
- ToolChain *restore(const QVariantMap &data) override;
+ bool canCreate() const override;
+ ToolChain *create() override;
static QString vcVarsBatFor(const QString &basePath,
MsvcToolChain::Platform platform,
const QVersionNumber &v);
};
-class ClangClToolChainFactory : public MsvcToolChainFactory
+class ClangClToolChainFactory : public ToolChainFactory
{
Q_OBJECT
@@ -247,11 +238,8 @@ public:
QList<ToolChain *> autoDetect(const QList<ToolChain *> &alreadyKnown) override;
- bool canRestore(const QVariantMap &data) override;
- ToolChain *restore(const QVariantMap &data) override;
-
- bool canCreate() override;
- ToolChain *create(Core::Id l) override;
+ bool canCreate() const override;
+ ToolChain *create() override;
};
// --------------------------------------------------------------------------
@@ -288,6 +276,24 @@ class MsvcToolChainConfigWidget : public MsvcBasedToolChainConfigWidget
public:
explicit MsvcToolChainConfigWidget(ToolChain *);
+
+private:
+ void applyImpl() override;
+ void discardImpl() override;
+ bool isDirtyImpl() const override;
+ void makeReadOnlyImpl() override;
+
+ void setFromMsvcToolChain();
+
+ void handleVcVarsChange(const QString &vcVars);
+ void handleVcVarsArchChange(const QString &arch);
+
+ QString vcVarsArguments() const;
+
+ QComboBox *m_varsBatPathCombo;
+ QComboBox *m_varsBatArchCombo;
+ QLineEdit *m_varsBatArgumentsEdit;
+ AbiWidget *m_abiWidget;
};
// --------------------------------------------------------------------------
@@ -304,6 +310,7 @@ public:
protected:
void applyImpl() override;
void discardImpl() override;
+ bool isDirtyImpl() const override { return false; }
void makeReadOnlyImpl() override;
private:
diff --git a/src/plugins/projectexplorer/namedwidget.h b/src/plugins/projectexplorer/namedwidget.h
index 26c9550f7e..870941c73b 100644
--- a/src/plugins/projectexplorer/namedwidget.h
+++ b/src/plugins/projectexplorer/namedwidget.h
@@ -39,13 +39,11 @@ public:
explicit NamedWidget(QWidget *parent = nullptr);
QString displayName() const;
+ void setDisplayName(const QString &displayName);
signals:
void displayNameChanged(const QString &);
-protected:
- void setDisplayName(const QString &displayName);
-
private:
QString m_displayName;
};
diff --git a/src/plugins/projectexplorer/osparser.cpp b/src/plugins/projectexplorer/osparser.cpp
index 9190f45d73..ecbef759ef 100644
--- a/src/plugins/projectexplorer/osparser.cpp
+++ b/src/plugins/projectexplorer/osparser.cpp
@@ -41,7 +41,7 @@ void OsParser::stdError(const QString &line)
if (Utils::HostOsInfo::isLinuxHost()) {
const QString trimmed = line.trimmed();
if (trimmed.contains(QLatin1String(": error while loading shared libraries:"))) {
- emit addTask(Task(Task::Error, trimmed, Utils::FileName(), -1,
+ emit addTask(Task(Task::Error, trimmed, Utils::FilePath(), -1,
Constants::TASK_CATEGORY_COMPILE));
}
}
@@ -55,7 +55,7 @@ void OsParser::stdOutput(const QString &line)
if (trimmed == QLatin1String("The process cannot access the file because it is being used by another process.")) {
emit addTask(Task(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."),
- Utils::FileName(), -1, Constants::TASK_CATEGORY_COMPILE));
+ Utils::FilePath(), -1, Constants::TASK_CATEGORY_COMPILE));
m_hasFatalError = true;
}
}
diff --git a/src/plugins/projectexplorer/outputparser_test.cpp b/src/plugins/projectexplorer/outputparser_test.cpp
index cb2a9772c3..765a087650 100644
--- a/src/plugins/projectexplorer/outputparser_test.cpp
+++ b/src/plugins/projectexplorer/outputparser_test.cpp
@@ -32,7 +32,7 @@
namespace ProjectExplorer {
-static inline QByteArray msgFileComparisonFail(const Utils::FileName &f1, const Utils::FileName &f2)
+static inline QByteArray msgFileComparisonFail(const Utils::FilePath &f1, const Utils::FilePath &f2)
{
const QString result = '"' + f1.toUserOutput() + "\" != \"" + f2.toUserOutput() + '"';
return result.toLocal8Bit();
@@ -43,7 +43,7 @@ OutputParserTester::OutputParserTester() = default;
// test functions:
void OutputParserTester::testParsing(const QString &lines,
Channel inputChannel,
- QList<Task> tasks,
+ Tasks tasks,
const QString &childStdOutLines,
const QString &childStdErrLines,
const QString &outputLines)
diff --git a/src/plugins/projectexplorer/outputparser_test.h b/src/plugins/projectexplorer/outputparser_test.h
index 7836331632..43920d0ebf 100644
--- a/src/plugins/projectexplorer/outputparser_test.h
+++ b/src/plugins/projectexplorer/outputparser_test.h
@@ -50,7 +50,7 @@ public:
// test functions:
void testParsing(const QString &lines, Channel inputChannel,
- QList<Task> tasks,
+ Tasks tasks,
const QString &childStdOutLines,
const QString &childStdErrLines,
const QString &outputLines);
@@ -76,7 +76,7 @@ private:
QString m_receivedStdErrChildLine;
QString m_receivedStdOutChildLine;
- QList<Task> m_receivedTasks;
+ Tasks m_receivedTasks;
QString m_receivedOutput;
friend class TestTerminator;
diff --git a/src/plugins/projectexplorer/parseissuesdialog.cpp b/src/plugins/projectexplorer/parseissuesdialog.cpp
new file mode 100644
index 0000000000..7b0d3758e6
--- /dev/null
+++ b/src/plugins/projectexplorer/parseissuesdialog.cpp
@@ -0,0 +1,171 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "parseissuesdialog.h"
+
+#include "ioutputparser.h"
+#include "kitinformation.h"
+#include "kitchooser.h"
+#include "kitmanager.h"
+#include "projectexplorerconstants.h"
+#include "taskhub.h"
+
+#include <coreplugin/progressmanager/progressmanager.h>
+#include <utils/runextensions.h>
+
+#include <QButtonGroup>
+#include <QCheckBox>
+#include <QDialogButtonBox>
+#include <QFile>
+#include <QFileDialog>
+#include <QGroupBox>
+#include <QLabel>
+#include <QMessageBox>
+#include <QPlainTextEdit>
+#include <QPushButton>
+#include <QVBoxLayout>
+
+#include <memory>
+
+namespace ProjectExplorer {
+namespace Internal {
+
+class ParseIssuesDialog::Private
+{
+public:
+ QPlainTextEdit compileOutputEdit;
+ QCheckBox stderrCheckBox;
+ QCheckBox clearTasksCheckBox;
+ KitChooser kitChooser;
+};
+
+ParseIssuesDialog::ParseIssuesDialog(QWidget *parent) : QDialog(parent), d(new Private)
+{
+ setWindowTitle(tr("Parse Build Output"));
+
+ d->stderrCheckBox.setText(tr("Output went to stderr"));
+ d->stderrCheckBox.setChecked(true);
+
+ d->clearTasksCheckBox.setText(tr("Clear existing tasks"));
+ d->clearTasksCheckBox.setChecked(true);
+
+ const auto loadFileButton = new QPushButton(tr("Load from File..."));
+ connect(loadFileButton, &QPushButton::clicked, this, [this] {
+ const QString filePath = QFileDialog::getOpenFileName(this, tr("Choose File"));
+ if (filePath.isEmpty())
+ return;
+ QFile file(filePath);
+ if (!file.open(QIODevice::ReadOnly)) {
+ QMessageBox::critical(this, tr("Could Not Open File"),
+ tr("Could not open file: \"%1\": %2")
+ .arg(filePath, file.errorString()));
+ return;
+ }
+ d->compileOutputEdit.setPlainText(QString::fromLocal8Bit(file.readAll()));
+ });
+
+ d->kitChooser.populate();
+ if (!d->kitChooser.hasStartupKit()) {
+ for (const Kit * const k : KitManager::kits()) {
+ if (DeviceTypeKitAspect::deviceTypeId(k) == Constants::DESKTOP_DEVICE_TYPE) {
+ d->kitChooser.setCurrentKitId(k->id());
+ break;
+ }
+ }
+ }
+
+ const auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
+ connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
+ connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
+ buttonBox->button(QDialogButtonBox::Ok)->setEnabled(d->kitChooser.currentKit());
+
+ const auto layout = new QVBoxLayout(this);
+ const auto outputGroupBox = new QGroupBox(tr("Build Output"));
+ layout->addWidget(outputGroupBox);
+ const auto outputLayout = new QHBoxLayout(outputGroupBox);
+ outputLayout->addWidget(&d->compileOutputEdit);
+ const auto buttonsWidget = new QWidget;
+ const auto outputButtonsLayout = new QVBoxLayout(buttonsWidget);
+ outputLayout->addWidget(buttonsWidget);
+ outputButtonsLayout->addWidget(loadFileButton);
+ outputButtonsLayout->addWidget(&d->stderrCheckBox);
+ outputButtonsLayout->addStretch(1);
+
+ // TODO: Only very few parsers are available from a Kit (basically just the Toolchain one).
+ // If we introduced factories for IOutputParsers, we could offer the user
+ // to combine arbitrary parsers here.
+ const auto parserGroupBox = new QGroupBox(tr("Parsing Options"));
+ layout->addWidget(parserGroupBox);
+ const auto parserLayout = new QVBoxLayout(parserGroupBox);
+ const auto kitChooserWidget = new QWidget;
+ const auto kitChooserLayout = new QHBoxLayout(kitChooserWidget);
+ kitChooserLayout->setContentsMargins(0, 0, 0, 0);
+ kitChooserLayout->addWidget(new QLabel(tr("Use parsers from kit:")));
+ kitChooserLayout->addWidget(&d->kitChooser);
+ parserLayout->addWidget(kitChooserWidget);
+ parserLayout->addWidget(&d->clearTasksCheckBox);
+
+ layout->addWidget(buttonBox);
+}
+
+ParseIssuesDialog::~ParseIssuesDialog()
+{
+ delete d;
+}
+
+static void parse(QFutureInterface<void> &future, const QString &output,
+ const std::unique_ptr<IOutputParser> &parser, bool isStderr)
+{
+ const QStringList lines = output.split('\n');
+ future.setProgressRange(0, lines.count());
+ const auto parserFunc = isStderr ? &IOutputParser::stdError : &IOutputParser::stdOutput;
+ for (const QString &line : lines) {
+ (parser.get()->*parserFunc)(line);
+ future.setProgressValue(future.progressValue() + 1);
+ if (future.isCanceled())
+ return;
+ }
+}
+
+void ParseIssuesDialog::accept()
+{
+ std::unique_ptr<IOutputParser> parser(d->kitChooser.currentKit()->createOutputParser());
+ if (!parser) {
+ QMessageBox::critical(this, tr("Cannot Parse"), tr("Cannot parse: The chosen kit does "
+ "not provide an output parser."));
+ return;
+ }
+ 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"),
+ "ProgressExplorer.ParseExternalBuildOutput");
+ QDialog::accept();
+}
+
+} // namespace Internal
+} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/parseissuesdialog.h b/src/plugins/projectexplorer/parseissuesdialog.h
new file mode 100644
index 0000000000..555727c3b9
--- /dev/null
+++ b/src/plugins/projectexplorer/parseissuesdialog.h
@@ -0,0 +1,48 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 <QDialog>
+
+namespace ProjectExplorer {
+namespace Internal {
+
+class ParseIssuesDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ ParseIssuesDialog(QWidget *parent = nullptr);
+ ~ParseIssuesDialog() override;
+
+private:
+ void accept() override;
+
+ class Private;
+ Private * const d;
+};
+
+} // namespace Internal
+} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/processparameters.cpp b/src/plugins/projectexplorer/processparameters.cpp
index db56c57cdb..f535cc120e 100644
--- a/src/plugins/projectexplorer/processparameters.cpp
+++ b/src/plugins/projectexplorer/processparameters.cpp
@@ -44,7 +44,9 @@
\sa ProjectExplorer::AbstractProcessStep
*/
-using namespace ProjectExplorer;
+using namespace Utils;
+
+namespace ProjectExplorer {
ProcessParameters::ProcessParameters() :
m_macroExpander(nullptr),
@@ -52,11 +54,19 @@ ProcessParameters::ProcessParameters() :
{
}
+void ProcessParameters::setCommandLine(const CommandLine &cmdLine)
+{
+ m_command = cmdLine.executable();
+ m_arguments = cmdLine.arguments();
+ m_effectiveCommand.clear();
+ m_effectiveArguments.clear();
+}
+
/*!
Sets the executable to run.
*/
-void ProcessParameters::setCommand(const QString &cmd)
+void ProcessParameters::setCommand(const Utils::FilePath &cmd)
{
m_command = cmd;
m_effectiveCommand.clear();
@@ -78,7 +88,7 @@ void ProcessParameters::setArguments(const QString &arguments)
Should be called from init().
*/
-void ProcessParameters::setWorkingDirectory(const QString &workingDirectory)
+void ProcessParameters::setWorkingDirectory(const FilePath &workingDirectory)
{
m_workingDirectory = workingDirectory;
m_effectiveWorkingDirectory.clear();
@@ -103,13 +113,14 @@ void ProcessParameters::setWorkingDirectory(const QString &workingDirectory)
Gets the fully expanded working directory.
*/
-QString ProcessParameters::effectiveWorkingDirectory() const
+FilePath ProcessParameters::effectiveWorkingDirectory() const
{
if (m_effectiveWorkingDirectory.isEmpty()) {
- QString wds = m_workingDirectory;
+ QString wds = m_workingDirectory.toString();
if (m_macroExpander)
wds = m_macroExpander->expand(wds);
- m_effectiveWorkingDirectory = QDir::cleanPath(m_environment.expandVariables(wds));
+ m_effectiveWorkingDirectory
+ = FilePath::fromString(QDir::cleanPath(m_environment.expandVariables(wds)));
}
return m_effectiveWorkingDirectory;
}
@@ -118,14 +129,15 @@ QString ProcessParameters::effectiveWorkingDirectory() const
Gets the fully expanded command name to run.
*/
-QString ProcessParameters::effectiveCommand() const
+FilePath ProcessParameters::effectiveCommand() const
{
if (m_effectiveCommand.isEmpty()) {
- QString cmd = m_command;
+ FilePath cmd = m_command;
if (m_macroExpander)
cmd = m_macroExpander->expand(cmd);
m_effectiveCommand =
- m_environment.searchInPath(cmd, {Utils::FileName::fromString(effectiveWorkingDirectory())}).toString();
+ m_environment.searchInPath(cmd.toString(),
+ {effectiveWorkingDirectory()});
m_commandMissing = m_effectiveCommand.isEmpty();
if (m_commandMissing)
m_effectiveCommand = cmd;
@@ -155,16 +167,16 @@ QString ProcessParameters::effectiveArguments() const
QString ProcessParameters::prettyCommand() const
{
- QString cmd = m_command;
+ QString cmd = m_command.toString();
if (m_macroExpander)
cmd = m_macroExpander->expand(cmd);
- return Utils::FileName::fromString(cmd).fileName();
+ return Utils::FilePath::fromString(cmd).fileName();
}
QString ProcessParameters::prettyArguments() const
{
QString margs = effectiveArguments();
- QString workDir = effectiveWorkingDirectory();
+ QString workDir = effectiveWorkingDirectory().toString();
Utils::QtcProcess::SplitError err;
Utils::QtcProcess::Arguments args =
Utils::QtcProcess::prepareArgs(margs, &err, Utils::HostOsInfo::hostOs(), &m_environment, &workDir);
@@ -187,7 +199,7 @@ QString ProcessParameters::summaryInWorkdir(const QString &displayName) const
.arg(displayName,
Utils::QtcProcess::quoteArg(prettyCommand()),
prettyArguments(),
- QDir::toNativeSeparators(effectiveWorkingDirectory()));
+ QDir::toNativeSeparators(effectiveWorkingDirectory().toString()));
}
void ProcessParameters::resolveAll()
@@ -196,3 +208,5 @@ void ProcessParameters::resolveAll()
effectiveArguments();
effectiveWorkingDirectory();
}
+
+} // ProcessExplorer
diff --git a/src/plugins/projectexplorer/processparameters.h b/src/plugins/projectexplorer/processparameters.h
index fd43e03bf7..c87ede7d5b 100644
--- a/src/plugins/projectexplorer/processparameters.h
+++ b/src/plugins/projectexplorer/processparameters.h
@@ -28,8 +28,12 @@
#include "projectexplorer_export.h"
#include <utils/environment.h>
+#include <utils/fileutils.h>
-namespace Utils { class MacroExpander; }
+namespace Utils {
+class CommandLine;
+class MacroExpander;
+} // Utils
namespace ProjectExplorer {
@@ -39,14 +43,16 @@ class PROJECTEXPLORER_EXPORT ProcessParameters
public:
ProcessParameters();
- void setCommand(const QString &cmd);
- QString command() const { return m_command; }
+ void setCommandLine(const Utils::CommandLine &cmdLine);
+
+ void setCommand(const Utils::FilePath &cmd);
+ Utils::FilePath command() const { return m_command; }
void setArguments(const QString &arguments);
QString arguments() const { return m_arguments; }
- void setWorkingDirectory(const QString &workingDirectory);
- QString workingDirectory() const { return m_workingDirectory; }
+ void setWorkingDirectory(const Utils::FilePath &workingDirectory);
+ Utils::FilePath workingDirectory() const { return m_workingDirectory; }
void setEnvironment(const Utils::Environment &env) { m_environment = env; }
Utils::Environment environment() const { return m_environment; }
@@ -55,9 +61,9 @@ public:
Utils::MacroExpander *macroExpander() const { return m_macroExpander; }
/// Get the fully expanded working directory:
- QString effectiveWorkingDirectory() const;
+ Utils::FilePath effectiveWorkingDirectory() const;
/// Get the fully expanded command name to run:
- QString effectiveCommand() const;
+ Utils::FilePath effectiveCommand() const;
/// Get the fully expanded arguments to use:
QString effectiveArguments() const;
@@ -71,14 +77,14 @@ public:
void resolveAll();
private:
- QString m_workingDirectory;
- QString m_command;
+ Utils::FilePath m_workingDirectory;
+ Utils::FilePath m_command;
QString m_arguments;
Utils::Environment m_environment;
Utils::MacroExpander *m_macroExpander;
- mutable QString m_effectiveWorkingDirectory;
- mutable QString m_effectiveCommand;
+ mutable Utils::FilePath m_effectiveWorkingDirectory;
+ mutable Utils::FilePath m_effectiveCommand;
mutable QString m_effectiveArguments;
mutable bool m_commandMissing;
};
diff --git a/src/plugins/projectexplorer/processstep.cpp b/src/plugins/projectexplorer/processstep.cpp
index c6c6057f4b..231cb831bb 100644
--- a/src/plugins/projectexplorer/processstep.cpp
+++ b/src/plugins/projectexplorer/processstep.cpp
@@ -24,114 +24,106 @@
****************************************************************************/
#include "processstep.h"
-#include "buildstep.h"
#include "buildconfiguration.h"
+#include "buildstep.h"
+#include "kit.h"
#include "processparameters.h"
#include "projectexplorerconstants.h"
#include "target.h"
-#include "kit.h"
#include <coreplugin/variablechooser.h>
#include <utils/macroexpander.h>
-#include <QDebug>
+#include <QFormLayout>
-using namespace ProjectExplorer;
-using namespace ProjectExplorer::Internal;
+namespace ProjectExplorer {
-namespace {
const char PROCESS_STEP_ID[] = "ProjectExplorer.ProcessStep";
const char PROCESS_COMMAND_KEY[] = "ProjectExplorer.ProcessStep.Command";
const char PROCESS_WORKINGDIRECTORY_KEY[] = "ProjectExplorer.ProcessStep.WorkingDirectory";
const char PROCESS_ARGUMENTS_KEY[] = "ProjectExplorer.ProcessStep.Arguments";
-}
ProcessStep::ProcessStep(BuildStepList *bsl)
: AbstractProcessStep(bsl, PROCESS_STEP_ID)
{
//: Default ProcessStep display name
setDefaultDisplayName(tr("Custom Process Step"));
- if (m_workingDirectory.isEmpty())
- m_workingDirectory = Constants::DEFAULT_WORKING_DIR;
+
+ m_command = addAspect<BaseStringAspect>();
+ m_command->setSettingsKey(PROCESS_COMMAND_KEY);
+ m_command->setDisplayStyle(BaseStringAspect::PathChooserDisplay);
+ m_command->setLabelText(tr("Command:"));
+ m_command->setExpectedKind(Utils::PathChooser::Command);
+ m_command->setHistoryCompleter("PE.ProcessStepCommand.History");
+
+ m_arguments = addAspect<BaseStringAspect>();
+ m_arguments->setSettingsKey(PROCESS_ARGUMENTS_KEY);
+ m_arguments->setDisplayStyle(BaseStringAspect::LineEditDisplay);
+ m_arguments->setLabelText(tr("Arguments:"));
+
+ m_workingDirectory = addAspect<BaseStringAspect>();
+ m_workingDirectory->setSettingsKey(PROCESS_WORKINGDIRECTORY_KEY);
+ m_workingDirectory->setValue(Constants::DEFAULT_WORKING_DIR);
+ m_workingDirectory->setDisplayStyle(BaseStringAspect::PathChooserDisplay);
+ m_workingDirectory->setLabelText(tr("Working directory:"));
+ m_workingDirectory->setExpectedKind(Utils::PathChooser::Directory);
}
bool ProcessStep::init()
{
- BuildConfiguration *bc = buildConfiguration();
- ProcessParameters *pp = processParameters();
- pp->setMacroExpander(bc ? bc->macroExpander() : Utils::globalMacroExpander());
- pp->setEnvironment(bc ? bc->environment() : Utils::Environment::systemEnvironment());
- pp->setWorkingDirectory(workingDirectory());
- pp->setCommand(m_command);
- pp->setArguments(m_arguments);
- pp->resolveAll();
-
+ setupProcessParameters(processParameters());
setOutputParser(target()->kit()->createOutputParser());
return AbstractProcessStep::init();
}
-void ProcessStep::doRun()
+void ProcessStep::setupProcessParameters(ProcessParameters *pp)
{
- AbstractProcessStep::doRun();
-}
+ BuildConfiguration *bc = buildConfiguration();
-BuildStepConfigWidget *ProcessStep::createConfigWidget()
-{
- return new ProcessStepConfigWidget(this);
-}
+ QString command = m_command->value();
+ QString arguments = m_arguments->value();
+ QString workingDirectory = m_workingDirectory->value();
+ if (workingDirectory.isEmpty()) {
+ if (bc)
+ workingDirectory = Constants::DEFAULT_WORKING_DIR;
+ else
+ workingDirectory = Constants::DEFAULT_WORKING_DIR_ALTERNATE;
+ }
-QString ProcessStep::command() const
-{
- return m_command;
+ pp->setMacroExpander(bc ? bc->macroExpander() : Utils::globalMacroExpander());
+ pp->setEnvironment(bc ? bc->environment() : Utils::Environment::systemEnvironment());
+ pp->setWorkingDirectory(Utils::FilePath::fromString(workingDirectory));
+ pp->setCommand(Utils::FilePath::fromString(command));
+ pp->setArguments(arguments);
+ pp->resolveAll();
}
-QString ProcessStep::arguments() const
+BuildStepConfigWidget *ProcessStep::createConfigWidget()
{
- return m_arguments;
-}
+ auto widget = AbstractProcessStep::createConfigWidget();
-QString ProcessStep::workingDirectory() const
-{
- return m_workingDirectory;
-}
+ Core::VariableChooser::addSupportForChildWidgets(widget, macroExpander());
-void ProcessStep::setCommand(const QString &command)
-{
- m_command = command;
-}
+ auto updateDetails = [this, widget] {
+ QString display = displayName();
+ if (display.isEmpty())
+ display = tr("Custom Process Step");
+ ProcessParameters param;
+ setupProcessParameters(&param);
+ widget->setSummaryText(param.summary(display));
+ };
-void ProcessStep::setArguments(const QString &arguments)
-{
- m_arguments = arguments;
-}
+ updateDetails();
-void ProcessStep::setWorkingDirectory(const QString &workingDirectory)
-{
- if (workingDirectory.isEmpty())
- if (buildConfiguration())
- m_workingDirectory = Constants::DEFAULT_WORKING_DIR;
- else
- m_workingDirectory = Constants::DEFAULT_WORKING_DIR_ALTERNATE;
- else
- m_workingDirectory = workingDirectory;
-}
+ connect(m_command, &ProjectConfigurationAspect::changed,
+ widget, updateDetails);
+ connect(m_workingDirectory, &ProjectConfigurationAspect::changed,
+ widget, updateDetails);
+ connect(m_arguments, &ProjectConfigurationAspect::changed,
+ widget, updateDetails);
-QVariantMap ProcessStep::toMap() const
-{
- QVariantMap map(AbstractProcessStep::toMap());
- map.insert(PROCESS_COMMAND_KEY, command());
- map.insert(PROCESS_ARGUMENTS_KEY, arguments());
- map.insert(PROCESS_WORKINGDIRECTORY_KEY, workingDirectory());
- return map;
-}
-
-bool ProcessStep::fromMap(const QVariantMap &map)
-{
- setCommand(map.value(PROCESS_COMMAND_KEY).toString());
- setArguments(map.value(PROCESS_ARGUMENTS_KEY).toString());
- setWorkingDirectory(map.value(PROCESS_WORKINGDIRECTORY_KEY).toString());
- return AbstractProcessStep::fromMap(map);
+ return widget;
}
//*******
@@ -144,80 +136,4 @@ ProcessStepFactory::ProcessStepFactory()
setDisplayName(ProcessStep::tr("Custom Process Step", "item in combobox"));
}
-//*******
-// ProcessStepConfigWidget
-//*******
-
-ProcessStepConfigWidget::ProcessStepConfigWidget(ProcessStep *step)
- : BuildStepConfigWidget(step), m_step(step)
-{
- m_ui.setupUi(this);
- m_ui.command->setExpectedKind(Utils::PathChooser::Command);
- m_ui.command->setHistoryCompleter("PE.ProcessStepCommand.History");
- m_ui.workingDirectory->setExpectedKind(Utils::PathChooser::Directory);
-
- BuildConfiguration *bc = m_step->buildConfiguration();
- Utils::Environment env = bc ? bc->environment() : Utils::Environment::systemEnvironment();
- m_ui.command->setEnvironment(env);
- m_ui.command->setPath(m_step->command());
-
- m_ui.workingDirectory->setEnvironment(env);
- m_ui.workingDirectory->setPath(m_step->workingDirectory());
-
- m_ui.commandArgumentsLineEdit->setText(m_step->arguments());
-
- updateDetails();
-
- connect(m_ui.command, &Utils::PathChooser::rawPathChanged,
- this, &ProcessStepConfigWidget::commandLineEditTextEdited);
- connect(m_ui.workingDirectory, &Utils::PathChooser::rawPathChanged,
- this, &ProcessStepConfigWidget::workingDirectoryLineEditTextEdited);
-
- connect(m_ui.commandArgumentsLineEdit, &QLineEdit::textEdited,
- this, &ProcessStepConfigWidget::commandArgumentsLineEditTextEdited);
- Core::VariableChooser::addSupportForChildWidgets(this, m_step->macroExpander());
-}
-
-void ProcessStepConfigWidget::updateDetails()
-{
- QString displayName = m_step->displayName();
- if (displayName.isEmpty())
- displayName = tr("Custom Process Step");
- ProcessParameters param;
- BuildConfiguration *bc = m_step->buildConfiguration();
- param.setMacroExpander(bc ? bc->macroExpander() : Utils::globalMacroExpander());
- param.setEnvironment(bc ? bc->environment() : Utils::Environment::systemEnvironment());
-
- param.setWorkingDirectory(m_step->workingDirectory());
- param.setCommand(m_step->command());
- param.setArguments(m_step->arguments());
- m_summaryText = param.summary(displayName);
- emit updateSummary();
-}
-
-QString ProcessStepConfigWidget::displayName() const
-{
- return m_step->displayName();
-}
-
-QString ProcessStepConfigWidget::summaryText() const
-{
- return m_summaryText;
-}
-
-void ProcessStepConfigWidget::commandLineEditTextEdited()
-{
- m_step->setCommand(m_ui.command->rawPath());
- updateDetails();
-}
-
-void ProcessStepConfigWidget::workingDirectoryLineEditTextEdited()
-{
- m_step->setWorkingDirectory(m_ui.workingDirectory->rawPath());
-}
-
-void ProcessStepConfigWidget::commandArgumentsLineEditTextEdited()
-{
- m_step->setArguments(m_ui.commandArgumentsLineEdit->text());
- updateDetails();
-}
+} // ProjectExplorer
diff --git a/src/plugins/projectexplorer/processstep.h b/src/plugins/projectexplorer/processstep.h
index 3bff8fbdca..241d440ad2 100644
--- a/src/plugins/projectexplorer/processstep.h
+++ b/src/plugins/projectexplorer/processstep.h
@@ -25,11 +25,11 @@
#pragma once
-#include "ui_processstep.h"
#include "abstractprocessstep.h"
+#include "projectconfigurationaspects.h"
+#include "projectexplorer_export.h"
namespace ProjectExplorer {
-namespace Internal {
class ProcessStepFactory : public BuildStepFactory
{
@@ -37,7 +37,7 @@ public:
ProcessStepFactory();
};
-class ProcessStep : public AbstractProcessStep
+class PROJECTEXPLORER_EXPORT ProcessStep : public AbstractProcessStep
{
Q_OBJECT
friend class ProcessStepFactory;
@@ -47,41 +47,13 @@ public:
BuildStepConfigWidget *createConfigWidget() override;
- QString command() const;
- QString arguments() const;
- QString workingDirectory() const;
-
- void setCommand(const QString &command);
- void setArguments(const QString &arguments);
- void setWorkingDirectory(const QString &workingDirectory);
-
private:
bool init() override;
- void doRun() override;
- QVariantMap toMap() const override;
- bool fromMap(const QVariantMap &map) override;
-
- QString m_command;
- QString m_arguments;
- QString m_workingDirectory;
-};
+ void setupProcessParameters(ProcessParameters *pp);
-class ProcessStepConfigWidget : public BuildStepConfigWidget
-{
- Q_OBJECT
-public:
- ProcessStepConfigWidget(ProcessStep *step);
- virtual QString displayName() const;
- virtual QString summaryText() const;
-private:
- void commandLineEditTextEdited();
- void workingDirectoryLineEditTextEdited();
- void commandArgumentsLineEditTextEdited();
- void updateDetails();
- ProcessStep *m_step;
- Ui::ProcessStepWidget m_ui;
- QString m_summaryText;
+ ProjectExplorer::BaseStringAspect *m_command;
+ ProjectExplorer::BaseStringAspect *m_arguments;
+ ProjectExplorer::BaseStringAspect *m_workingDirectory;
};
-} // namespace Internal
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/processstep.ui b/src/plugins/projectexplorer/processstep.ui
deleted file mode 100644
index bcbaf740dd..0000000000
--- a/src/plugins/projectexplorer/processstep.ui
+++ /dev/null
@@ -1,62 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>ProjectExplorer::Internal::ProcessStepWidget</class>
- <widget class="QWidget" name="ProjectExplorer::Internal::ProcessStepWidget">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>262</width>
- <height>85</height>
- </rect>
- </property>
- <layout class="QFormLayout" name="formLayout">
- <property name="fieldGrowthPolicy">
- <enum>QFormLayout::AllNonFixedFieldsGrow</enum>
- </property>
- <property name="margin">
- <number>0</number>
- </property>
- <item row="0" column="0">
- <widget class="QLabel" name="commandLabel">
- <property name="text">
- <string>Command:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="Utils::PathChooser" name="command" native="true"/>
- </item>
- <item row="2" column="0">
- <widget class="QLabel" name="commandArgumentsLabel">
- <property name="text">
- <string>Arguments:</string>
- </property>
- </widget>
- </item>
- <item row="2" column="1">
- <widget class="QLineEdit" name="commandArgumentsLineEdit"/>
- </item>
- <item row="3" column="0">
- <widget class="QLabel" name="workingDirecoryLabel">
- <property name="text">
- <string>Working directory:</string>
- </property>
- </widget>
- </item>
- <item row="3" column="1">
- <widget class="Utils::PathChooser" name="workingDirectory" native="true"/>
- </item>
- </layout>
- </widget>
- <customwidgets>
- <customwidget>
- <class>Utils::PathChooser</class>
- <extends>QWidget</extends>
- <header location="global">utils/pathchooser.h</header>
- <container>1</container>
- </customwidget>
- </customwidgets>
- <resources/>
- <connections/>
-</ui>
diff --git a/src/plugins/projectexplorer/project.cpp b/src/plugins/projectexplorer/project.cpp
index 94484f3493..d909c4b909 100644
--- a/src/plugins/projectexplorer/project.cpp
+++ b/src/plugins/projectexplorer/project.cpp
@@ -30,6 +30,7 @@
#include "deployconfiguration.h"
#include "editorconfiguration.h"
#include "kit.h"
+#include "makestep.h"
#include "projectexplorer.h"
#include "projectnodes.h"
#include "target.h"
@@ -51,6 +52,8 @@
#include <utils/macroexpander.h>
#include <utils/qtcassert.h>
+#include <QFileDialog>
+
#include <limits>
#include <memory>
@@ -112,7 +115,7 @@ const Project::NodeMatcher Project::GeneratedFiles = [](const Node *node) {
// ProjectDocument:
// --------------------------------------------------------------------
-ProjectDocument::ProjectDocument(const QString &mimeType, const Utils::FileName &fileName,
+ProjectDocument::ProjectDocument(const QString &mimeType, const Utils::FilePath &fileName,
const ProjectDocument::ProjectCallback &callback) :
m_callback(callback)
{
@@ -149,7 +152,7 @@ bool ProjectDocument::reload(QString *errorString, Core::IDocument::ReloadFlag f
class ProjectPrivate
{
public:
- ProjectPrivate(const QString &mimeType, const Utils::FileName &fileName,
+ ProjectPrivate(const QString &mimeType, const Utils::FilePath &fileName,
const ProjectDocument::ProjectCallback &callback)
{
m_document = std::make_unique<ProjectDocument>(mimeType, fileName, callback);
@@ -177,6 +180,7 @@ public:
Kit::Predicate m_preferredKitPredicate;
Utils::MacroExpander m_macroExpander;
+ Utils::FilePath m_rootProjectDirectory;
mutable QVector<const Node *> m_sortedNodeList;
};
@@ -186,7 +190,7 @@ ProjectPrivate::~ProjectPrivate()
std::unique_ptr<ProjectNode> oldNode = std::move(m_rootProjectNode);
}
-Project::Project(const QString &mimeType, const Utils::FileName &fileName,
+Project::Project(const QString &mimeType, const Utils::FilePath &fileName,
const ProjectDocument::ProjectCallback &callback) :
d(new ProjectPrivate(mimeType, fileName, callback))
{
@@ -229,9 +233,9 @@ Core::IDocument *Project::document() const
return d->m_document.get();
}
-Utils::FileName Project::projectFilePath() const
+Utils::FilePath Project::projectFilePath() const
{
- QTC_ASSERT(document(), return Utils::FileName());
+ QTC_ASSERT(document(), return Utils::FilePath());
return document()->filePath();
}
@@ -327,9 +331,9 @@ Target *Project::target(Kit *k) const
return Utils::findOrDefault(d->m_targets, Utils::equal(&Target::kit, k));
}
-QList<Task> Project::projectIssues(const Kit *k) const
+Tasks Project::projectIssues(const Kit *k) const
{
- QList<Task> result;
+ Tasks result;
if (!k->isValid())
result.append(createProjectTask(Task::TaskType::Error, tr("Kit is not valid.")));
return {};
@@ -580,19 +584,19 @@ Project::RestoreResult Project::restoreSettings(QString *errorMessage)
/*!
* Returns a sorted list of all files matching the predicate \a filter.
*/
-Utils::FileNameList Project::files(const Project::NodeMatcher &filter) const
+Utils::FilePathList Project::files(const Project::NodeMatcher &filter) const
{
- Utils::FileNameList result;
+ Utils::FilePathList result;
if (d->m_sortedNodeList.empty() && filter(containerNode()))
result.append(projectFilePath());
- Utils::FileName lastAdded;
+ Utils::FilePath lastAdded;
for (const Node *n : qAsConst(d->m_sortedNodeList)) {
if (filter && !filter(n))
continue;
// Remove duplicates:
- const Utils::FileName path = n->filePath();
+ const Utils::FilePath path = n->filePath();
if (path == lastAdded)
continue; // skip duplicates
lastAdded = path;
@@ -635,7 +639,7 @@ QVariantMap Project::toMap() const
This includes the absolute path.
*/
-Utils::FileName Project::projectDirectory() const
+Utils::FilePath Project::projectDirectory() const
{
return projectDirectory(projectFilePath());
}
@@ -646,20 +650,37 @@ Utils::FileName Project::projectDirectory() const
This includes the absolute path.
*/
-Utils::FileName Project::projectDirectory(const Utils::FileName &top)
+Utils::FilePath Project::projectDirectory(const Utils::FilePath &top)
{
if (top.isEmpty())
- return Utils::FileName();
- return Utils::FileName::fromString(top.toFileInfo().absoluteDir().path());
+ return Utils::FilePath();
+ return Utils::FilePath::fromString(top.toFileInfo().absoluteDir().path());
+}
+
+void Project::changeRootProjectDirectory()
+{
+ Utils::FilePath rootPath = Utils::FilePath::fromString(
+ QFileDialog::getExistingDirectory(Core::ICore::dialogParent(),
+ tr("Select the Root Directory"),
+ rootProjectDirectory().toString(),
+ QFileDialog::ShowDirsOnly
+ | QFileDialog::DontResolveSymlinks));
+ if (rootPath != d->m_rootProjectDirectory) {
+ d->m_rootProjectDirectory = rootPath;
+ setNamedSettings(Constants::PROJECT_ROOT_PATH_KEY, d->m_rootProjectDirectory.toString());
+ emit rootProjectDirectoryChanged();
+ }
}
/*!
- Returns the common root directory that contains all files which belongs to a project.
+ Returns the common root directory that contains all files which belong to a project.
*/
-
-Utils::FileName Project::rootProjectDirectory() const
+Utils::FilePath Project::rootProjectDirectory() const
{
- return projectDirectory(); // TODO parse all files and find the common path
+ if (!d->m_rootProjectDirectory.isEmpty())
+ return d->m_rootProjectDirectory;
+
+ return projectDirectory();
}
ProjectNode *Project::rootProjectNode() const
@@ -701,6 +722,9 @@ Project::RestoreResult Project::fromMap(const QVariantMap &map, QString *errorMe
createTargetFromMap(map, i);
}
+ d->m_rootProjectDirectory = Utils::FilePath::fromString(
+ namedSettings(Constants::PROJECT_ROOT_PATH_KEY).toString());
+
return RestoreResult::Ok;
}
@@ -729,11 +753,11 @@ QStringList Project::filesGeneratedFrom(const QString &file) const
return QStringList();
}
-bool Project::isKnownFile(const Utils::FileName &filename) const
+bool Project::isKnownFile(const Utils::FilePath &filename) const
{
if (d->m_sortedNodeList.empty())
return filename == projectFilePath();
- const FileNode element(filename, FileType::Unknown, false);
+ const FileNode element(filename, FileType::Unknown);
return std::binary_search(std::begin(d->m_sortedNodeList), std::end(d->m_sortedNodeList),
&element, nodeLessThan);
}
@@ -778,7 +802,7 @@ void Project::projectLoaded()
Task Project::createProjectTask(Task::TaskType type, const QString &description)
{
- return Task(type, description, Utils::FileName(), -1, Core::Id());
+ return Task(type, description, Utils::FilePath(), -1, Core::Id());
}
Core::Context Project::projectContext() const
@@ -824,6 +848,20 @@ bool Project::knowsAllBuildExecutables() const
return true;
}
+MakeInstallCommand Project::makeInstallCommand(const Target *target, const QString &installRoot)
+{
+ QTC_ASSERT(hasMakeInstallEquivalent(), return MakeInstallCommand());
+ MakeInstallCommand cmd;
+ if (const BuildConfiguration * const bc = target->activeBuildConfiguration()) {
+ if (const auto makeStep = bc->stepList(ProjectExplorer::Constants::BUILDSTEPS_BUILD)
+ ->firstOfType<MakeStep>()) {
+ cmd.command = makeStep->effectiveMakeCommand();
+ }
+ }
+ cmd.arguments << "install" << ("INSTALL_ROOT=" + QDir::toNativeSeparators(installRoot));
+ return cmd;
+}
+
void Project::setup(const QList<BuildInfo> &infoList)
{
std::vector<std::unique_ptr<Target>> toRegister;
@@ -921,18 +959,18 @@ void Project::setPreferredKitPredicate(const Kit::Predicate &predicate)
namespace ProjectExplorer {
-static Utils::FileName constructTestPath(const char *basePath)
+static Utils::FilePath constructTestPath(const char *basePath)
{
- Utils::FileName drive;
+ Utils::FilePath drive;
if (Utils::HostOsInfo::isWindowsHost())
- drive = Utils::FileName::fromString("C:");
+ drive = Utils::FilePath::fromString("C:");
return drive + QLatin1String(basePath);
}
-const Utils::FileName TEST_PROJECT_PATH = constructTestPath("/tmp/foobar/baz.project");
-const Utils::FileName TEST_PROJECT_NONEXISTING_FILE = constructTestPath("/tmp/foobar/nothing.cpp");
-const Utils::FileName TEST_PROJECT_CPP_FILE = constructTestPath("/tmp/foobar/main.cpp");
-const Utils::FileName TEST_PROJECT_GENERATED_FILE = constructTestPath("/tmp/foobar/generated.foo");
+const Utils::FilePath TEST_PROJECT_PATH = constructTestPath("/tmp/foobar/baz.project");
+const Utils::FilePath TEST_PROJECT_NONEXISTING_FILE = constructTestPath("/tmp/foobar/nothing.cpp");
+const Utils::FilePath TEST_PROJECT_CPP_FILE = constructTestPath("/tmp/foobar/main.cpp");
+const Utils::FilePath TEST_PROJECT_GENERATED_FILE = constructTestPath("/tmp/foobar/generated.foo");
const QString TEST_PROJECT_MIMETYPE = "application/vnd.test.qmakeprofile";
const QString TEST_PROJECT_DISPLAYNAME = "testProjectFoo";
const char TEST_PROJECT_ID[] = "Test.Project.Id";
@@ -958,12 +996,6 @@ public:
bool needsConfiguration() const final { return false; }
};
-class TestProjectNode : public ProjectNode
-{
-public:
- TestProjectNode(const Utils::FileName &dir) : ProjectNode(dir) { }
-};
-
void ProjectExplorerPlugin::testProject_setup()
{
TestProject project;
@@ -1060,11 +1092,12 @@ void ProjectExplorerPlugin::testProject_parsingFail()
std::unique_ptr<ProjectNode> createFileTree(Project *project)
{
- std::unique_ptr<ProjectNode> root = std::make_unique<TestProjectNode>(project->projectDirectory());
+ std::unique_ptr<ProjectNode> root = std::make_unique<ProjectNode>(project->projectDirectory());
std::vector<std::unique_ptr<FileNode>> nodes;
- nodes.emplace_back(std::make_unique<FileNode>(TEST_PROJECT_PATH, FileType::Project, false));
- nodes.emplace_back(std::make_unique<FileNode>(TEST_PROJECT_CPP_FILE, FileType::Source, false));
- nodes.emplace_back(std::make_unique<FileNode>(TEST_PROJECT_GENERATED_FILE, FileType::Source, true));
+ nodes.emplace_back(std::make_unique<FileNode>(TEST_PROJECT_PATH, FileType::Project));
+ nodes.emplace_back(std::make_unique<FileNode>(TEST_PROJECT_CPP_FILE, FileType::Source));
+ nodes.emplace_back(std::make_unique<FileNode>(TEST_PROJECT_GENERATED_FILE, FileType::Source));
+ nodes.back()->setIsGenerated(true);
root->addNestedNodes(std::move(nodes));
return root;
@@ -1079,7 +1112,7 @@ void ProjectExplorerPlugin::testProject_projectTree()
QCOMPARE(fileSpy.count(), 0);
QVERIFY(!project.rootProjectNode());
- project.setRootProjectNode(std::make_unique<TestProjectNode>(project.projectDirectory()));
+ project.setRootProjectNode(std::make_unique<ProjectNode>(project.projectDirectory()));
QCOMPARE(fileSpy.count(), 0);
QVERIFY(!project.rootProjectNode());
@@ -1095,14 +1128,14 @@ void ProjectExplorerPlugin::testProject_projectTree()
QCOMPARE(project.isKnownFile(TEST_PROJECT_CPP_FILE), true);
QCOMPARE(project.isKnownFile(TEST_PROJECT_GENERATED_FILE), true);
- Utils::FileNameList allFiles = project.files(Project::AllFiles);
+ Utils::FilePathList allFiles = project.files(Project::AllFiles);
QCOMPARE(allFiles.count(), 3);
QVERIFY(allFiles.contains(TEST_PROJECT_PATH));
QVERIFY(allFiles.contains(TEST_PROJECT_CPP_FILE));
QVERIFY(allFiles.contains(TEST_PROJECT_GENERATED_FILE));
QCOMPARE(project.files(Project::GeneratedFiles), {TEST_PROJECT_GENERATED_FILE});
- Utils::FileNameList sourceFiles = project.files(Project::SourceFiles);
+ Utils::FilePathList sourceFiles = project.files(Project::SourceFiles);
QCOMPARE(sourceFiles.count(), 2);
QVERIFY(sourceFiles.contains(TEST_PROJECT_PATH));
QVERIFY(sourceFiles.contains(TEST_PROJECT_CPP_FILE));
diff --git a/src/plugins/projectexplorer/project.h b/src/plugins/projectexplorer/project.h
index cf9590ad68..e66e049c0c 100644
--- a/src/plugins/projectexplorer/project.h
+++ b/src/plugins/projectexplorer/project.h
@@ -27,6 +27,7 @@
#include "projectexplorer_export.h"
+#include "deploymentdata.h"
#include "kit.h"
#include "subscription.h"
@@ -63,7 +64,7 @@ class PROJECTEXPLORER_EXPORT ProjectDocument : public Core::IDocument
public:
using ProjectCallback = std::function<void()>;
- ProjectDocument(const QString &mimeType, const Utils::FileName &fileName,
+ ProjectDocument(const QString &mimeType, const Utils::FilePath &fileName,
const ProjectCallback &callback = {});
Core::IDocument::ReloadBehavior reloadBehavior(Core::IDocument::ChangeTrigger state,
@@ -90,7 +91,7 @@ public:
isParsingRole
};
- Project(const QString &mimeType, const Utils::FileName &fileName,
+ Project(const QString &mimeType, const Utils::FilePath &fileName,
const ProjectDocument::ProjectCallback &callback = {});
~Project() override;
@@ -100,10 +101,13 @@ public:
QString mimeType() const;
Core::IDocument *document() const;
- Utils::FileName projectFilePath() const;
- Utils::FileName projectDirectory() const;
- Utils::FileName rootProjectDirectory() const;
- static Utils::FileName projectDirectory(const Utils::FileName &top);
+ Utils::FilePath projectFilePath() const;
+ Utils::FilePath projectDirectory() const;
+ static Utils::FilePath projectDirectory(const Utils::FilePath &top);
+
+ // This does not affect nodes, only the root path.
+ void changeRootProjectDirectory();
+ Utils::FilePath rootProjectDirectory() const;
virtual ProjectNode *rootProjectNode() const;
ContainerNode *containerNode() const;
@@ -122,7 +126,7 @@ public:
Target *activeTarget() const;
Target *target(Core::Id id) const;
Target *target(Kit *k) const;
- virtual QList<Task> projectIssues(const Kit *k) const;
+ virtual Tasks projectIssues(const Kit *k) const;
std::unique_ptr<Target> createTarget(Kit *k);
static bool copySteps(Target *sourceTarget, Target *newTarget);
@@ -137,9 +141,9 @@ public:
static const NodeMatcher SourceFiles;
static const NodeMatcher GeneratedFiles;
- Utils::FileNameList files(const NodeMatcher &matcher) const;
+ Utils::FilePathList files(const NodeMatcher &matcher) const;
virtual QStringList filesGeneratedFrom(const QString &sourceFile) const;
- bool isKnownFile(const Utils::FileName &filename) const;
+ bool isKnownFile(const Utils::FilePath &filename) const;
virtual QVariantMap toMap() const;
@@ -162,6 +166,10 @@ public:
// of configuration.
virtual bool knowsAllBuildExecutables() const;
+ virtual DeploymentKnowledge deploymentKnowledge() const { return DeploymentKnowledge::Bad; }
+ virtual bool hasMakeInstallEquivalent() const { return false; }
+ virtual MakeInstallCommand makeInstallCommand(const Target *target, const QString &installRoot);
+
void setup(const QList<BuildInfo> &infoList);
Utils::MacroExpander *macroExpander() const;
@@ -221,6 +229,8 @@ signals:
void parsingStarted();
void parsingFinished(bool success);
+ void rootProjectDirectoryChanged();
+
protected:
virtual RestoreResult fromMap(const QVariantMap &map, QString *errorMessage);
void createTargetFromMap(const QVariantMap &map, int index);
diff --git a/src/plugins/projectexplorer/projectconfiguration.cpp b/src/plugins/projectexplorer/projectconfiguration.cpp
index d51084f1ed..3d05c9ff87 100644
--- a/src/plugins/projectexplorer/projectconfiguration.cpp
+++ b/src/plugins/projectexplorer/projectconfiguration.cpp
@@ -181,26 +181,13 @@ ProjectConfigurationAspect *ProjectConfiguration::aspect(Core::Id id) const
return m_aspects.aspect(id);
}
-Core::Id ProjectExplorer::idFromMap(const QVariantMap &map)
-{
- return Core::Id::fromSetting(map.value(QLatin1String(CONFIGURATION_ID_KEY)));
-}
-
-// StatefulProjectConfiguration
-
-bool StatefulProjectConfiguration::isEnabled() const
+void ProjectConfiguration::acquaintAspects()
{
- return m_isEnabled;
+ for (ProjectConfigurationAspect *aspect : m_aspects)
+ aspect->acquaintSiblings(m_aspects);
}
-StatefulProjectConfiguration::StatefulProjectConfiguration(QObject *parent, Core::Id id) :
- ProjectConfiguration(parent, id)
-{ }
-
-void StatefulProjectConfiguration::setEnabled(bool enabled)
+Core::Id ProjectExplorer::idFromMap(const QVariantMap &map)
{
- if (enabled == m_isEnabled)
- return;
- m_isEnabled = enabled;
- emit enabledChanged();
+ return Core::Id::fromSetting(map.value(QLatin1String(CONFIGURATION_ID_KEY)));
}
diff --git a/src/plugins/projectexplorer/projectconfiguration.h b/src/plugins/projectexplorer/projectconfiguration.h
index 685661d482..2d5be2299d 100644
--- a/src/plugins/projectexplorer/projectconfiguration.h
+++ b/src/plugins/projectexplorer/projectconfiguration.h
@@ -41,6 +41,7 @@ QT_END_NAMESPACE
namespace ProjectExplorer {
class Project;
+class ProjectConfigurationAspects;
class PROJECTEXPLORER_EXPORT ProjectConfigurationAspect : public QObject
{
@@ -68,6 +69,7 @@ public:
virtual void fromMap(const QVariantMap &) {}
virtual void toMap(QVariantMap &) const {}
virtual void addToConfigurationLayout(QFormLayout *) {}
+ virtual void acquaintSiblings(const ProjectConfigurationAspects &) {}
signals:
void changed();
@@ -168,6 +170,8 @@ public:
ProjectConfigurationAspect *aspect(Core::Id id) const;
template <typename T> T *aspect() const { return m_aspects.aspect<T>(); }
+ void acquaintAspects();
+
signals:
void displayNameChanged();
void toolTipChanged();
@@ -183,29 +187,6 @@ private:
Utils::MacroExpander m_macroExpander;
};
-class PROJECTEXPLORER_EXPORT StatefulProjectConfiguration : public ProjectConfiguration
-{
- Q_OBJECT
-
-public:
- StatefulProjectConfiguration() = default;
-
- bool isEnabled() const;
-
- virtual QString disabledReason() const = 0;
-
-signals:
- void enabledChanged();
-
-protected:
- StatefulProjectConfiguration(QObject *parent, Core::Id id);
-
- void setEnabled(bool enabled);
-
-private:
- bool m_isEnabled = false;
-};
-
// helper function:
PROJECTEXPLORER_EXPORT Core::Id idFromMap(const QVariantMap &map);
diff --git a/src/plugins/projectexplorer/projectconfigurationaspects.cpp b/src/plugins/projectexplorer/projectconfigurationaspects.cpp
index c6f9ad9552..a4cec91d28 100644
--- a/src/plugins/projectexplorer/projectconfigurationaspects.cpp
+++ b/src/plugins/projectexplorer/projectconfigurationaspects.cpp
@@ -79,15 +79,17 @@ public:
QPointer<PathChooser> m_pathChooserDisplay;
QPointer<QTextEdit> m_textEditDisplay;
QPixmap m_labelPixmap;
+ Utils::FilePath m_baseFileName;
};
class BaseIntegerAspectPrivate
{
public:
- QVariant m_value;
+ qint64 m_value = 0;
QVariant m_minimumValue;
QVariant m_maximumValue;
int m_displayIntegerBase = 10;
+ qint64 m_displayScaleFactor = 1;
QString m_label;
QString m_prefix;
QString m_suffix;
@@ -136,9 +138,14 @@ void BaseStringAspect::toMap(QVariantMap &map) const
d->m_checker->toMap(map);
}
-FileName BaseStringAspect::fileName() const
+FilePath BaseStringAspect::fileName() const
{
- return FileName::fromString(d->m_value);
+ return FilePath::fromString(d->m_value);
+}
+
+void BaseStringAspect::setFileName(const FilePath &val)
+{
+ setValue(val.toString());
}
void BaseStringAspect::setLabelText(const QString &labelText)
@@ -207,6 +214,13 @@ void BaseStringAspect::setEnvironment(const Environment &env)
d->m_pathChooserDisplay->setEnvironment(env);
}
+void BaseStringAspect::setBaseFileName(const FilePath &baseFileName)
+{
+ d->m_baseFileName = baseFileName;
+ if (d->m_pathChooserDisplay)
+ d->m_pathChooserDisplay->setBaseFileName(baseFileName);
+}
+
void BaseStringAspect::addToConfigurationLayout(QFormLayout *layout)
{
QTC_CHECK(!d->m_label);
@@ -225,6 +239,7 @@ void BaseStringAspect::addToConfigurationLayout(QFormLayout *layout)
if (!d->m_historyCompleterKey.isEmpty())
d->m_pathChooserDisplay->setHistoryCompleter(d->m_historyCompleterKey);
d->m_pathChooserDisplay->setEnvironment(d->m_environment);
+ d->m_pathChooserDisplay->setBaseFileName(d->m_baseFileName);
connect(d->m_pathChooserDisplay, &PathChooser::pathChanged,
this, &BaseStringAspect::setValue);
hbox->addWidget(d->m_pathChooserDisplay);
@@ -277,7 +292,7 @@ void BaseStringAspect::update()
const bool enabled = !d->m_checker || d->m_checker->value();
if (d->m_pathChooserDisplay) {
- d->m_pathChooserDisplay->setFileName(FileName::fromString(displayedString));
+ d->m_pathChooserDisplay->setFileName(FilePath::fromString(displayedString));
d->m_pathChooserDisplay->setEnabled(enabled);
}
@@ -357,6 +372,7 @@ bool BaseBoolAspect::defaultValue() const
void BaseBoolAspect::setDefaultValue(bool defaultValue)
{
d->m_defaultValue = defaultValue;
+ d->m_value = defaultValue;
}
bool BaseBoolAspect::value() const
@@ -397,23 +413,24 @@ void BaseIntegerAspect::addToConfigurationLayout(QFormLayout *layout)
{
QTC_CHECK(!d->m_spinBox);
d->m_spinBox = new QSpinBox(layout->parentWidget());
- d->m_spinBox->setValue(d->m_value.toInt());
+ d->m_spinBox->setValue(int(d->m_value / d->m_displayScaleFactor));
d->m_spinBox->setDisplayIntegerBase(d->m_displayIntegerBase);
d->m_spinBox->setPrefix(d->m_prefix);
d->m_spinBox->setSuffix(d->m_suffix);
if (d->m_maximumValue.isValid() && d->m_maximumValue.isValid())
- d->m_spinBox->setRange(d->m_minimumValue.toInt(), d->m_maximumValue.toInt());
+ d->m_spinBox->setRange(int(d->m_minimumValue.toLongLong() / d->m_displayScaleFactor),
+ int(d->m_maximumValue.toLongLong() / d->m_displayScaleFactor));
layout->addRow(d->m_label, d->m_spinBox);
- connect(d->m_spinBox.data(), static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
+ connect(d->m_spinBox.data(), QOverload<int>::of(&QSpinBox::valueChanged),
this, [this](int value) {
- d->m_value = value;
+ d->m_value = value * d->m_displayScaleFactor;
emit changed();
});
}
void BaseIntegerAspect::fromMap(const QVariantMap &map)
{
- d->m_value = map.value(settingsKey());
+ d->m_value = map.value(settingsKey()).toLongLong();
}
void BaseIntegerAspect::toMap(QVariantMap &data) const
@@ -421,19 +438,19 @@ void BaseIntegerAspect::toMap(QVariantMap &data) const
data.insert(settingsKey(), d->m_value);
}
-int BaseIntegerAspect::value() const
+qint64 BaseIntegerAspect::value() const
{
- return d->m_value.toInt();
+ return d->m_value;
}
-void BaseIntegerAspect::setValue(int value)
+void BaseIntegerAspect::setValue(qint64 value)
{
d->m_value = value;
if (d->m_spinBox)
- d->m_spinBox->setValue(d->m_value.toInt());
+ d->m_spinBox->setValue(int(d->m_value / d->m_displayScaleFactor));
}
-void BaseIntegerAspect::setRange(int min, int max)
+void BaseIntegerAspect::setRange(qint64 min, qint64 max)
{
d->m_minimumValue = min;
d->m_maximumValue = max;
@@ -459,4 +476,9 @@ void BaseIntegerAspect::setDisplayIntegerBase(int base)
d->m_displayIntegerBase = base;
}
+void BaseIntegerAspect::setDisplayScaleFactor(qint64 factor)
+{
+ d->m_displayScaleFactor = factor;
+}
+
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/projectconfigurationaspects.h b/src/plugins/projectexplorer/projectconfigurationaspects.h
index 593f6d3ed5..250482b44e 100644
--- a/src/plugins/projectexplorer/projectconfigurationaspects.h
+++ b/src/plugins/projectexplorer/projectconfigurationaspects.h
@@ -89,6 +89,7 @@ public:
void setHistoryCompleter(const QString &historyCompleterKey);
void setExpectedKind(const Utils::PathChooser::Kind expectedKind);
void setEnvironment(const Utils::Environment &env);
+ void setBaseFileName(const Utils::FilePath &baseFileName);
bool isChecked() const;
void makeCheckable(const QString &optionalLabel, const QString &optionalBaseKey);
@@ -104,8 +105,8 @@ public:
void fromMap(const QVariantMap &map) override;
void toMap(QVariantMap &map) const override;
- Utils::FileName fileName() const;
- void setFileName(const Utils::FileName &val);
+ Utils::FilePath fileName() const;
+ void setFileName(const Utils::FilePath &val);
private:
void update();
@@ -123,14 +124,15 @@ public:
void addToConfigurationLayout(QFormLayout *layout) override;
- int value() const;
- void setValue(int val);
+ qint64 value() const;
+ void setValue(qint64 val);
- void setRange(int min, int max);
+ void setRange(qint64 min, qint64 max);
void setLabel(const QString &label);
void setPrefix(const QString &prefix);
void setSuffix(const QString &suffix);
void setDisplayIntegerBase(int base);
+ void setDisplayScaleFactor(qint64 factor);
void fromMap(const QVariantMap &map) override;
void toMap(QVariantMap &map) const override;
diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp
index 3d619eab82..488a9fe117 100644
--- a/src/plugins/projectexplorer/projectexplorer.cpp
+++ b/src/plugins/projectexplorer/projectexplorer.cpp
@@ -25,7 +25,9 @@
#include "projectexplorer.h"
+#include "appoutputpane.h"
#include "buildsteplist.h"
+#include "compileoutputwindow.h"
#include "configtaskhandler.h"
#include "customexecutablerunconfiguration.h"
#include "customwizard/customwizard.h"
@@ -48,6 +50,7 @@
#include "kitfeatureprovider.h"
#include "kitmanager.h"
#include "kitoptionspage.h"
+#include "parseissuesdialog.h"
#include "target.h"
#include "toolchainmanager.h"
#include "toolchainoptionspage.h"
@@ -98,31 +101,32 @@
#include "projectwelcomepage.h"
#include <app/app_version.h>
-#include <extensionsystem/pluginspec.h>
-#include <extensionsystem/pluginmanager.h>
-#include <coreplugin/icore.h>
-#include <coreplugin/id.h>
-#include <coreplugin/idocumentfactory.h>
-#include <coreplugin/idocument.h>
-#include <coreplugin/coreconstants.h>
-#include <coreplugin/documentmanager.h>
-#include <coreplugin/imode.h>
-#include <coreplugin/modemanager.h>
-#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/actioncontainer.h>
+#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/command.h>
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/diffservice.h>
+#include <coreplugin/documentmanager.h>
#include <coreplugin/editormanager/documentmodel.h>
#include <coreplugin/editormanager/editormanager.h>
+#include <coreplugin/fileutils.h>
#include <coreplugin/findplaceholder.h>
-#include <coreplugin/vcsmanager.h>
+#include <coreplugin/icore.h>
+#include <coreplugin/id.h>
+#include <coreplugin/idocument.h>
+#include <coreplugin/idocumentfactory.h>
+#include <coreplugin/imode.h>
#include <coreplugin/iversioncontrol.h>
-#include <coreplugin/fileutils.h>
-#include <coreplugin/diffservice.h>
+#include <coreplugin/locator/directoryfilter.h>
+#include <coreplugin/modemanager.h>
+#include <coreplugin/vcsmanager.h>
+#include <extensionsystem/pluginmanager.h>
+#include <extensionsystem/pluginspec.h>
+#include <ssh/sshconnection.h>
+#include <ssh/sshsettings.h>
#include <texteditor/findinfiles.h>
#include <texteditor/textdocument.h>
#include <texteditor/texteditorconstants.h>
-#include <ssh/sshconnection.h>
-#include <ssh/sshsettings.h>
#include <utils/algorithm.h>
#include <utils/fileutils.h>
@@ -244,6 +248,11 @@ const char PROJECT_OPEN_LOCATIONS_CONTEXT_MENU[] = "Project.P.OpenLocation.CtxM
const char DEFAULT_BUILD_DIRECTORY_TEMPLATE[] = "../%{JS: Util.asciify(\"build-%{CurrentProject:Name}-%{CurrentKit:FileSystemName}-%{CurrentBuild:Name}\")}";
const char DEFAULT_BUILD_DIRECTORY_TEMPLATE_KEY[] = "Directories/BuildDirectory.Template";
+const char TERMINAL_MODE_SETTINGS_KEY[] = "ProjectExplorer/Settings/TerminalMode";
+const char CLOSE_FILES_WITH_PROJECT_SETTINGS_KEY[]
+ = "ProjectExplorer/Settings/CloseFilesWithProject";
+const char CLEAR_ISSUES_ON_REBUILD_SETTINGS_KEY[] = "ProjectExplorer/Settings/ClearIssuesOnRebuild";
+
} // namespace Constants
@@ -259,11 +268,20 @@ static Utils::optional<Utils::Environment> buildEnv(const Project *project)
return project->activeTarget()->activeBuildConfiguration()->environment();
}
-static Utils::optional<Utils::Environment> runEnv(const Project *project)
+static bool canOpenTerminalWithRunEnv(const Project *project)
{
- if (!project || !project->activeTarget() || !project->activeTarget()->activeRunConfiguration())
- return {};
- return project->activeTarget()->activeRunConfiguration()->runnable().environment;
+ if (!project)
+ return false;
+ const Target * const target = project->activeTarget();
+ if (!target)
+ return false;
+ const RunConfiguration * const runConfig = target->activeRunConfiguration();
+ if (!runConfig)
+ return false;
+ IDevice::ConstPtr device = runConfig->runnable().device;
+ if (!device)
+ device = DeviceKitAspect::device(target->kit());
+ return device && device->canOpenTerminal();
}
static Target *activeTarget()
@@ -316,6 +334,8 @@ class ProjectExplorerPluginPrivate : public QObject
Q_DECLARE_TR_FUNCTIONS(ProjectExplorer::ProjectExplorerPlugin)
public:
+ ProjectExplorerPluginPrivate();
+
void deploy(QList<Project *>);
int queue(QList<Project *>, QList<Id> stepIds);
void updateContextMenuActions();
@@ -352,6 +372,7 @@ public:
void handleAddExistingFiles();
void addExistingDirectory();
void addNewSubproject();
+ void addExistingProjects();
void removeProject();
void openFile();
void searchOnFileSystem();
@@ -370,6 +391,7 @@ public:
void updateUnloadProjectMenu();
using EnvironmentGetter = std::function<Utils::optional<Utils::Environment>(const Project *project)>;
void openTerminalHere(const EnvironmentGetter &env);
+ void openTerminalHereWithRunEnv();
void invalidateProject(ProjectExplorer::Project *project);
@@ -434,6 +456,7 @@ public:
QAction *m_addExistingFilesAction;
QAction *m_addExistingDirectoryAction;
QAction *m_addNewSubprojectAction;
+ QAction *m_addExistingProjectsAction;
QAction *m_removeFileAction;
QAction *m_duplicateFileAction;
QAction *m_removeProjectAction;
@@ -464,7 +487,7 @@ public:
int m_activeRunControlCount = 0;
int m_shutdownWatchDogId = -1;
- QHash<QString, std::function<Project *(const Utils::FileName &)>> m_projectCreators;
+ QHash<QString, std::function<Project *(const Utils::FilePath &)>> m_projectCreators;
QList<QPair<QString, QString> > m_recentProjects; // pair of filename, displayname
static const int m_maxRecentProjects = 25;
@@ -478,7 +501,6 @@ public:
bool m_shuttingDown = false;
Core::Id m_runMode = Constants::NO_RUN_MODE;
- KitManager *m_kitManager = nullptr;
ToolChainManager *m_toolChainManager = nullptr;
QStringList m_arguments;
@@ -532,6 +554,7 @@ public:
AllProjectsFilter m_allProjectsFilter;
CurrentProjectFilter m_currentProjectFilter;
+ DirectoryFilter m_allProjectDirectoriesFilter;
ProcessStepFactory m_processStepFactory;
@@ -539,11 +562,15 @@ public:
CurrentProjectFind m_curretProjectFind;
CustomExecutableRunConfigurationFactory m_customExecutableRunConfigFactory;
+ SimpleRunWorkerFactory<SimpleTargetRunner, CustomExecutableRunConfiguration>
+ m_customExecutableRunWorkerFactory;
ProjectFileWizardExtension m_projectFileWizardExtension;
// Settings pages
ProjectExplorerSettingsPage m_projectExplorerSettingsPage;
+ AppOutputSettingsPage m_appOutputSettingsPage;
+ CompileOutputSettingsPage m_compileOutputSettingsPage;
DeviceSettingsPage m_deviceSettingsPage;
SshSettingsPage m_sshSettingsPage;
@@ -552,6 +579,12 @@ public:
DefaultDeployConfigurationFactory m_defaultDeployConfigFactory;
IDocumentFactory m_documentFactory;
+
+ DeviceTypeKitAspect deviceTypeKitAspect;
+ DeviceKitAspect deviceeKitAspect;
+ ToolChainKitAspect toolChainKitAspect;
+ SysRootKitAspect sysRootKitAspect;
+ EnvironmentKitAspect environmentKitAspect;
};
static ProjectExplorerPlugin *m_instance = nullptr;
@@ -568,7 +601,7 @@ ProjectExplorerPlugin::~ProjectExplorerPlugin()
JsonWizardFactory::destroyAllFactories();
// Force sequence of deletion:
- delete dd->m_kitManager; // remove all the profile information
+ KitManager::destroy(); // remove all the profile information
delete dd->m_toolChainManager;
ProjectPanelFactory::destroyFactories();
delete dd;
@@ -595,7 +628,6 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
CustomWizard::setVerbose(arguments.count(QLatin1String("-customwizard-verbose")));
JsonWizardFactory::setVerbose(arguments.count(QLatin1String("-customwizard-verbose")));
- dd->m_kitManager = new KitManager; // register before ToolChainManager
dd->m_toolChainManager = new ToolChainManager;
// Register languages
@@ -604,13 +636,6 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
IWizardFactory::registerFeatureProvider(new KitFeatureProvider);
- // Register KitInformation:
- KitManager::registerKitInformation<DeviceTypeKitInformation>();
- KitManager::registerKitInformation<DeviceKitInformation>();
- KitManager::registerKitInformation<ToolChainKitInformation>();
- KitManager::registerKitInformation<SysRootKitInformation>();
- KitManager::registerKitInformation<EnvironmentKitInformation>();
-
IWizardFactory::registerFactoryCreator([]() -> QList<IWizardFactory *> {
QList<IWizardFactory *> result;
result << CustomWizard::createWizards();
@@ -640,8 +665,21 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
dd, &ProjectExplorerPluginPrivate::updateActions);
connect(sessionManager, &SessionManager::sessionLoaded,
dd, &ProjectExplorerPluginPrivate::updateActions);
- connect(sessionManager, &SessionManager::sessionLoaded,
- dd, &ProjectExplorerPluginPrivate::updateWelcomePage);
+ connect(sessionManager,
+ &SessionManager::sessionLoaded,
+ dd,
+ &ProjectExplorerPluginPrivate::updateWelcomePage);
+
+ connect(sessionManager, &SessionManager::projectAdded, dd, [](ProjectExplorer::Project *project) {
+ dd->m_allProjectDirectoriesFilter.addDirectory(project->projectDirectory().toString());
+ });
+ connect(sessionManager,
+ &SessionManager::projectRemoved,
+ dd,
+ [](ProjectExplorer::Project *project) {
+ dd->m_allProjectDirectoriesFilter.removeDirectory(
+ project->projectDirectory().toString());
+ });
ProjectTree *tree = &dd->m_projectTree;
connect(tree, &ProjectTree::currentProjectChanged,
@@ -652,7 +690,7 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
dd, &ProjectExplorerPluginPrivate::updateActions);
connect(tree, &ProjectTree::currentProjectChanged, this, [](Project *project) {
TextEditor::FindInFiles::instance()->setBaseDirectory(project ? project->projectDirectory()
- : Utils::FileName());
+ : Utils::FilePath());
});
// For JsonWizard:
@@ -807,13 +845,11 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
mfileContextMenu->appendGroup(Constants::G_PROJECT_TREE);
// Open Terminal submenu
-#if !defined(Q_OS_UNIX) || QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
ActionContainer * const openTerminal =
ActionManager::createMenu(ProjectExplorer::Constants::M_OPENTERMINALCONTEXT);
openTerminal->setOnAllDisabledBehavior(ActionContainer::Show);
dd->m_openTerminalMenu = openTerminal->menu();
- dd->m_openTerminalMenu->setTitle(FileUtils::msgTerminalAction());
-#endif
+ dd->m_openTerminalMenu->setTitle(FileUtils::msgTerminalWithAction());
// "open with" submenu
ActionContainer * const openWith =
@@ -881,27 +917,19 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
mfileContextMenu->addAction(cmd, Constants::G_FILE_OPEN);
mfolderContextMenu->addAction(cmd, Constants::G_FOLDER_FILES);
-#if !defined(Q_OS_UNIX) || QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
// Open Terminal Here menu
- mfileContextMenu->addMenu(openTerminal, Constants::G_FILE_OPEN);
- mfolderContextMenu->addMenu(openTerminal, Constants::G_FOLDER_FILES);
-
- dd->m_openTerminalHere = new QAction(tr("System Environment"), this);
- cmd = ActionManager::registerAction(dd->m_openTerminalHere, Constants::OPENTERMINALHERE,
- projecTreeContext);
- dd->m_openTerminalMenu->addAction(dd->m_openTerminalHere);
-#else
- dd->m_openTerminalHere = new QAction(FileUtils::msgTerminalAction(), this);
+ dd->m_openTerminalHere = new QAction(FileUtils::msgTerminalHereAction(), this);
cmd = ActionManager::registerAction(dd->m_openTerminalHere, Constants::OPENTERMINALHERE,
projecTreeContext);
mfileContextMenu->addAction(cmd, Constants::G_FILE_OPEN);
mfolderContextMenu->addAction(cmd, Constants::G_FOLDER_FILES);
-#endif
+
+ mfileContextMenu->addMenu(openTerminal, Constants::G_FILE_OPEN);
+ mfolderContextMenu->addMenu(openTerminal, Constants::G_FOLDER_FILES);
dd->m_openTerminalHereBuildEnv = new QAction(tr("Build Environment"), this);
dd->m_openTerminalHereRunEnv = new QAction(tr("Run Environment"), this);
-#if !defined(Q_OS_UNIX) || QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
cmd = ActionManager::registerAction(dd->m_openTerminalHereBuildEnv,
"ProjectExplorer.OpenTerminalHereBuildEnv",
projecTreeContext);
@@ -911,7 +939,6 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
"ProjectExplorer.OpenTerminalHereRunEnv",
projecTreeContext);
dd->m_openTerminalMenu->addAction(dd->m_openTerminalHereRunEnv);
-#endif
// Open With menu
mfileContextMenu->addMenu(openWith, Constants::G_FILE_OPEN);
@@ -1141,6 +1168,13 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
msubProjectContextMenu->addAction(cmd, Constants::G_PROJECT_FILES);
mfolderContextMenu->addAction(cmd, Constants::G_FOLDER_FILES);
+ // add existing projects action
+ dd->m_addExistingProjectsAction = new QAction(tr("Add Existing Projects..."), this);
+ cmd = ActionManager::registerAction(dd->m_addExistingProjectsAction,
+ "ProjectExplorer.AddExistingProjects", projecTreeContext);
+ mprojectContextMenu->addAction(cmd, Constants::G_PROJECT_FILES);
+ msubProjectContextMenu->addAction(cmd, Constants::G_PROJECT_FILES);
+
// add existing directory action
dd->m_addExistingDirectoryAction = new QAction(tr("Add Existing Directory..."), this);
cmd = ActionManager::registerAction(dd->m_addExistingDirectoryAction,
@@ -1306,18 +1340,6 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
s->value(QLatin1String("ProjectExplorer/Settings/DeployBeforeRun"), true).toBool();
dd->m_projectExplorerSettings.saveBeforeBuild =
s->value(QLatin1String("ProjectExplorer/Settings/SaveBeforeBuild"), false).toBool();
- dd->m_projectExplorerSettings.showCompilerOutput =
- s->value(QLatin1String("ProjectExplorer/Settings/ShowCompilerOutput"), false).toBool();
- dd->m_projectExplorerSettings.showRunOutput =
- s->value(QLatin1String("ProjectExplorer/Settings/ShowRunOutput"), true).toBool();
- dd->m_projectExplorerSettings.showDebugOutput =
- s->value(QLatin1String("ProjectExplorer/Settings/ShowDebugOutput"), false).toBool();
- dd->m_projectExplorerSettings.cleanOldAppOutput =
- s->value(QLatin1String("ProjectExplorer/Settings/CleanOldAppOutput"), false).toBool();
- dd->m_projectExplorerSettings.mergeStdErrAndStdOut =
- s->value(QLatin1String("ProjectExplorer/Settings/MergeStdErrAndStdOut"), false).toBool();
- dd->m_projectExplorerSettings.wrapAppOutput =
- s->value(QLatin1String("ProjectExplorer/Settings/WrapAppOutput"), true).toBool();
dd->m_projectExplorerSettings.useJom =
s->value(QLatin1String("ProjectExplorer/Settings/UseJom"), true).toBool();
dd->m_projectExplorerSettings.autorestoreLastSession =
@@ -1328,12 +1350,6 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
s->value(QLatin1String("ProjectExplorer/Settings/PromptToStopRunControl"), false).toBool();
dd->m_projectExplorerSettings.automaticallyCreateRunConfigurations =
s->value(QLatin1String("ProjectExplorer/Settings/AutomaticallyCreateRunConfigurations"), true).toBool();
- dd->m_projectExplorerSettings.maxAppOutputChars =
- s->value(QLatin1String("ProjectExplorer/Settings/MaxAppOutputLines"),
- Core::Constants::DEFAULT_MAX_CHAR_COUNT).toInt() * 100;
- dd->m_projectExplorerSettings.maxBuildOutputChars =
- s->value(QLatin1String("ProjectExplorer/Settings/MaxBuildOutputLines"),
- Core::Constants::DEFAULT_MAX_CHAR_COUNT).toInt() * 100;
dd->m_projectExplorerSettings.environmentId =
QUuid(s->value(QLatin1String("ProjectExplorer/Settings/EnvironmentId")).toByteArray());
if (dd->m_projectExplorerSettings.environmentId.isNull())
@@ -1343,6 +1359,12 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
if (tmp < 0 || tmp > ProjectExplorerSettings::StopSameBuildDir)
tmp = Utils::HostOsInfo::isWindowsHost() ? 1 : 0;
dd->m_projectExplorerSettings.stopBeforeBuild = ProjectExplorerSettings::StopBeforeBuild(tmp);
+ dd->m_projectExplorerSettings.terminalMode = static_cast<TerminalMode>(s->value(
+ Constants::TERMINAL_MODE_SETTINGS_KEY, int(TerminalMode::Smart)).toInt());
+ dd->m_projectExplorerSettings.closeSourceFilesWithProject
+ = s->value(Constants::CLOSE_FILES_WITH_PROJECT_SETTINGS_KEY, true).toBool();
+ dd->m_projectExplorerSettings.clearIssuesOnRebuild
+ = s->value(Constants::CLEAR_ISSUES_ON_REBUILD_SETTINGS_KEY, true).toBool();
dd->m_projectExplorerSettings.buildDirectoryTemplate
= s->value(Constants::DEFAULT_BUILD_DIRECTORY_TEMPLATE_KEY).toString();
if (dd->m_projectExplorerSettings.buildDirectoryTemplate.isEmpty())
@@ -1448,6 +1470,8 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
dd, &ProjectExplorerPluginPrivate::addExistingDirectory);
connect(dd->m_addNewSubprojectAction, &QAction::triggered,
dd, &ProjectExplorerPluginPrivate::addNewSubproject);
+ connect(dd->m_addExistingProjectsAction, &QAction::triggered,
+ dd, &ProjectExplorerPluginPrivate::addExistingProjects);
connect(dd->m_removeProjectAction, &QAction::triggered,
dd, &ProjectExplorerPluginPrivate::removeProject);
connect(dd->m_openFileAction, &QAction::triggered,
@@ -1459,11 +1483,11 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
connect(dd->m_openTerminalHere, &QAction::triggered, dd, []() { dd->openTerminalHere(sysEnv); });
connect(dd->m_openTerminalHereBuildEnv, &QAction::triggered, dd, []() { dd->openTerminalHere(buildEnv); });
- connect(dd->m_openTerminalHereRunEnv, &QAction::triggered, dd, []() { dd->openTerminalHere(runEnv); });
+ connect(dd->m_openTerminalHereRunEnv, &QAction::triggered, dd, []() { dd->openTerminalHereWithRunEnv(); });
connect(dd->m_filePropertiesAction, &QAction::triggered, this, []() {
- const Node *currentNode = ProjectTree::findCurrentNode();
- QTC_ASSERT(currentNode && currentNode->nodeType() == NodeType::File, return);
+ const Node *currentNode = ProjectTree::currentNode();
+ QTC_ASSERT(currentNode && currentNode->asFileNode(), return);
DocumentManager::showFilePropertiesDialog(currentNode->filePath());
});
connect(dd->m_removeFileAction, &QAction::triggered,
@@ -1502,7 +1526,7 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
expander->registerFileVariables(Constants::VAR_CURRENTPROJECT_PREFIX,
tr("Current project's main file."),
[]() -> QString {
- Utils::FileName projectFilePath;
+ Utils::FilePath projectFilePath;
if (Project *project = ProjectTree::currentProject())
projectFilePath = project->projectFilePath();
return projectFilePath.toString();
@@ -1547,7 +1571,7 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
tr("The host address of the device in the currently active kit."),
[]() -> QString {
Kit *kit = currentKit();
- const IDevice::ConstPtr device = DeviceKitInformation::device(kit);
+ const IDevice::ConstPtr device = DeviceKitAspect::device(kit);
return device ? device->sshParameters().host() : QString();
});
@@ -1555,7 +1579,7 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
tr("The SSH port of the device in the currently active kit."),
[]() -> QString {
Kit *kit = currentKit();
- const IDevice::ConstPtr device = DeviceKitInformation::device(kit);
+ const IDevice::ConstPtr device = DeviceKitAspect::device(kit);
return device ? QString::number(device->sshParameters().port()) : QString();
});
@@ -1563,7 +1587,7 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
tr("The username with which to log into the device in the currently active kit."),
[]() -> QString {
Kit *kit = currentKit();
- const IDevice::ConstPtr device = DeviceKitInformation::device(kit);
+ const IDevice::ConstPtr device = DeviceKitAspect::device(kit);
return device ? device->sshParameters().userName() : QString();
});
@@ -1573,7 +1597,7 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
"in the currently active kit."),
[]() -> QString {
Kit *kit = currentKit();
- const IDevice::ConstPtr device = DeviceKitInformation::device(kit);
+ const IDevice::ConstPtr device = DeviceKitAspect::device(kit);
return device ? device->sshParameters().privateKeyFile : QString();
});
@@ -1598,14 +1622,8 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
tr("The currently active run configuration's executable (if applicable)."),
[]() -> QString {
if (Target *target = activeTarget()) {
- if (RunConfiguration *rc = target->activeRunConfiguration()) {
- // TODO: This duplicates code and is not always correct, but see
- // QTCREATORBUG-18317.
- // Solution: Re-introduce RunConfiguration::executable()?
- if (auto executableAspect = rc->aspect<ExecutableAspect>())
- return executableAspect->executable().toString();
- return QString();
- }
+ if (RunConfiguration *rc = target->activeRunConfiguration())
+ return rc->executable().toString();
}
return QString();
});
@@ -1718,7 +1736,7 @@ void ProjectExplorerPlugin::unloadProject(Project *project)
if (!DocumentManager::saveModifiedDocumentSilently(document))
return;
- if (!dd->closeAllFilesInProject(project))
+ if (projectExplorerSettings().closeSourceFilesWithProject && !dd->closeAllFilesInProject(project))
return;
dd->addToRecentProjects(document->filePath().toString(), project->displayName());
@@ -1729,7 +1747,7 @@ void ProjectExplorerPlugin::unloadProject(Project *project)
void ProjectExplorerPluginPrivate::closeAllProjects()
{
- if (!EditorManager::closeAllEditors())
+ if (!EditorManager::closeAllDocuments())
return; // Action has been cancelled
SessionManager::closeAllProjects();
@@ -1778,16 +1796,16 @@ void ProjectExplorerPlugin::extensionsInitialized()
QSsh::SshSettings::loadSettings(Core::ICore::settings());
const auto searchPathRetriever = [] {
- Utils::FileNameList searchPaths;
- searchPaths << Utils::FileName::fromString(Core::ICore::libexecPath());
+ Utils::FilePathList searchPaths;
+ searchPaths << Utils::FilePath::fromString(Core::ICore::libexecPath());
if (Utils::HostOsInfo::isWindowsHost()) {
const QString gitBinary = Core::ICore::settings()->value("Git/BinaryPath", "git")
.toString();
const QStringList rawGitSearchPaths = Core::ICore::settings()->value("Git/Path")
.toString().split(':', QString::SkipEmptyParts);
- const Utils::FileNameList gitSearchPaths = Utils::transform(rawGitSearchPaths,
- [](const QString &rawPath) { return Utils::FileName::fromString(rawPath); });
- const Utils::FileName fullGitPath = Utils::Environment::systemEnvironment()
+ const Utils::FilePathList gitSearchPaths = Utils::transform(rawGitSearchPaths,
+ [](const QString &rawPath) { return Utils::FilePath::fromString(rawPath); });
+ const Utils::FilePath fullGitPath = Utils::Environment::systemEnvironment()
.searchInPath(gitBinary, gitSearchPaths);
if (!fullGitPath.isEmpty()) {
searchPaths << fullGitPath.parentDir()
@@ -1798,6 +1816,16 @@ void ProjectExplorerPlugin::extensionsInitialized()
};
QSsh::SshSettings::setExtraSearchPathRetriever(searchPathRetriever);
+ const auto parseIssuesAction = new QAction(tr("Parse Build Output..."), this);
+ ActionContainer *mtools = ActionManager::actionContainer(Core::Constants::M_TOOLS);
+ Command * const cmd = ActionManager::registerAction(parseIssuesAction,
+ "ProjectExplorer.ParseIssuesAction");
+ connect(parseIssuesAction, &QAction::triggered, this, [] {
+ ParseIssuesDialog dlg(ICore::mainWindow());
+ dlg.exec();
+ });
+ mtools->addAction(cmd);
+
// delay restoring kits until UI is shown for improved perceived startup performance
QTimer::singleShot(0, this, &ProjectExplorerPlugin::restoreKits);
}
@@ -1808,7 +1836,7 @@ void ProjectExplorerPlugin::restoreKits()
ExtraAbi::load(); // Load this before Toolchains!
DeviceManager::instance()->load();
ToolChainManager::restoreToolChains();
- dd->m_kitManager->restoreKits();
+ KitManager::restoreKits();
QTimer::singleShot(0, dd, &ProjectExplorerPluginPrivate::restoreSession); // delay a bit...
}
@@ -1874,15 +1902,15 @@ void ProjectExplorerPluginPrivate::setStartupProject(Project *project)
bool ProjectExplorerPluginPrivate::closeAllFilesInProject(const Project *project)
{
QTC_ASSERT(project, return false);
- QList<IDocument *> openFiles = DocumentModel::openedDocuments();
- Utils::erase(openFiles, [project](const IDocument *doc) {
- return !project->isKnownFile(doc->filePath());
+ QList<DocumentModel::Entry *> openFiles = DocumentModel::entries();
+ Utils::erase(openFiles, [project](const DocumentModel::Entry *entry) {
+ return entry->pinned || !project->isKnownFile(entry->fileName());
});
for (const Project * const otherProject : SessionManager::projects()) {
if (otherProject == project)
continue;
- Utils::erase(openFiles, [otherProject](const IDocument *doc) {
- return otherProject->isKnownFile(doc->filePath());
+ Utils::erase(openFiles, [otherProject](const DocumentModel::Entry *entry) {
+ return otherProject->isKnownFile(entry->fileName());
});
}
return EditorManager::closeDocuments(openFiles);
@@ -1920,20 +1948,18 @@ void ProjectExplorerPluginPrivate::savePersistentSettings()
s->setValue(QLatin1String("ProjectExplorer/Settings/BuildBeforeDeploy"), dd->m_projectExplorerSettings.buildBeforeDeploy);
s->setValue(QLatin1String("ProjectExplorer/Settings/DeployBeforeRun"), dd->m_projectExplorerSettings.deployBeforeRun);
s->setValue(QLatin1String("ProjectExplorer/Settings/SaveBeforeBuild"), dd->m_projectExplorerSettings.saveBeforeBuild);
- s->setValue(QLatin1String("ProjectExplorer/Settings/ShowCompilerOutput"), dd->m_projectExplorerSettings.showCompilerOutput);
- s->setValue(QLatin1String("ProjectExplorer/Settings/ShowRunOutput"), dd->m_projectExplorerSettings.showRunOutput);
- s->setValue(QLatin1String("ProjectExplorer/Settings/ShowDebugOutput"), dd->m_projectExplorerSettings.showDebugOutput);
- s->setValue(QLatin1String("ProjectExplorer/Settings/CleanOldAppOutput"), dd->m_projectExplorerSettings.cleanOldAppOutput);
- s->setValue(QLatin1String("ProjectExplorer/Settings/MergeStdErrAndStdOut"), dd->m_projectExplorerSettings.mergeStdErrAndStdOut);
- s->setValue(QLatin1String("ProjectExplorer/Settings/WrapAppOutput"), dd->m_projectExplorerSettings.wrapAppOutput);
s->setValue(QLatin1String("ProjectExplorer/Settings/UseJom"), dd->m_projectExplorerSettings.useJom);
s->setValue(QLatin1String("ProjectExplorer/Settings/AutoRestoreLastSession"), dd->m_projectExplorerSettings.autorestoreLastSession);
s->setValue(QLatin1String("ProjectExplorer/Settings/AddLibraryPathsToRunEnv"), dd->m_projectExplorerSettings.addLibraryPathsToRunEnv);
s->setValue(QLatin1String("ProjectExplorer/Settings/PromptToStopRunControl"), dd->m_projectExplorerSettings.prompToStopRunControl);
+ s->setValue(Constants::TERMINAL_MODE_SETTINGS_KEY,
+ int(dd->m_projectExplorerSettings.terminalMode));
+ s->setValue(Constants::CLOSE_FILES_WITH_PROJECT_SETTINGS_KEY,
+ dd->m_projectExplorerSettings.closeSourceFilesWithProject);
+ s->setValue(Constants::CLEAR_ISSUES_ON_REBUILD_SETTINGS_KEY,
+ dd->m_projectExplorerSettings.clearIssuesOnRebuild);
s->setValue(QLatin1String("ProjectExplorer/Settings/AutomaticallyCreateRunConfigurations"),
dd->m_projectExplorerSettings.automaticallyCreateRunConfigurations);
- s->setValue(QLatin1String("ProjectExplorer/Settings/MaxAppOutputLines"), dd->m_projectExplorerSettings.maxAppOutputChars / 100);
- s->setValue(QLatin1String("ProjectExplorer/Settings/MaxBuildOutputLines"), dd->m_projectExplorerSettings.maxBuildOutputChars / 100);
s->setValue(QLatin1String("ProjectExplorer/Settings/EnvironmentId"), dd->m_projectExplorerSettings.environmentId.toByteArray());
s->setValue(QLatin1String("ProjectExplorer/Settings/StopBeforeBuild"), dd->m_projectExplorerSettings.stopBeforeBuild);
@@ -2008,7 +2034,7 @@ ProjectExplorerPlugin::OpenProjectResult ProjectExplorerPlugin::openProjects(con
QTC_ASSERT(!fileName.isEmpty(), continue);
const QFileInfo fi(fileName);
- const auto filePath = Utils::FileName::fromString(fi.absoluteFilePath());
+ const auto filePath = Utils::FilePath::fromString(fi.absoluteFilePath());
Project *found = Utils::findOrDefault(SessionManager::projects(),
Utils::equal(&Project::projectFilePath, filePath));
if (found) {
@@ -2073,7 +2099,7 @@ void ProjectExplorerPluginPrivate::currentModeChanged(Id mode, Id oldMode)
// Saving settings directly in a mode change is not a good idea, since the mode change
// can be part of a bigger change. Save settings after that bigger change had a chance to
// complete.
- QTimer::singleShot(0, ICore::instance(), &ICore::saveSettings);
+ QTimer::singleShot(0, ICore::instance(), [] { ICore::saveSettings(ICore::ModeChanged); });
}
if (mode == Core::Constants::MODE_WELCOME)
updateWelcomePage();
@@ -2216,14 +2242,13 @@ void ProjectExplorerPluginPrivate::executeRunConfiguration(RunConfiguration *run
}
}
- RunControl::WorkerCreator producer = RunControl::producer(runConfiguration, runMode);
- QTC_ASSERT(producer, return);
- auto runControl = new RunControl(runConfiguration, runMode);
+ auto runControl = new RunControl(runMode);
+ runControl->setRunConfiguration(runConfiguration);
// A user needed interaction may have cancelled the run
// (by example asking for a process pid or server url).
- if (!producer(runControl)) {
+ if (!runControl->createMainWorker()) {
delete runControl;
return;
}
@@ -2250,8 +2275,8 @@ void ProjectExplorerPluginPrivate::startRunControl(RunControl *runControl)
m_outputPane.flash(); // one flash for starting
m_outputPane.showTabFor(runControl);
Core::Id runMode = runControl->runMode();
- bool popup = (runMode == Constants::NORMAL_RUN_MODE && dd->m_projectExplorerSettings.showRunOutput)
- || (runMode == Constants::DEBUG_RUN_MODE && m_projectExplorerSettings.showDebugOutput);
+ bool popup = (runMode == Constants::NORMAL_RUN_MODE && m_outputPane.settings().popUpForRunOutput)
+ || (runMode == Constants::DEBUG_RUN_MODE && m_outputPane.settings().popUpForDebugOutput);
m_outputPane.setBehaviorOnOutput(runControl, popup ? AppOutputPane::Popup : AppOutputPane::Flash);
connect(runControl, &QObject::destroyed, this, &ProjectExplorerPluginPrivate::checkForShutdown,
Qt::QueuedConnection);
@@ -2334,10 +2359,10 @@ QList<QPair<QString, QString> > ProjectExplorerPluginPrivate::recentProjects() c
static QString pathOrDirectoryFor(const Node *node, bool dir)
{
- Utils::FileName path = node->filePath();
+ Utils::FilePath path = node->filePath();
QString location;
const FolderNode *folder = node->asFolderNode();
- if (node->nodeType() == NodeType::VirtualFolder && folder) {
+ if (node->isVirtualFolderType() && folder) {
// Virtual Folder case
// If there are files directly below or no subfolders, take the folder path
if (!folder->fileNodes().isEmpty() || folder->folderNodes().isEmpty()) {
@@ -2515,6 +2540,16 @@ bool ProjectExplorerPlugin::saveModifiedFiles()
//NBS handle case where there is no activeBuildConfiguration
// because someone delete all build configurations
+ProjectExplorerPluginPrivate::ProjectExplorerPluginPrivate()
+ : m_allProjectDirectoriesFilter("Files in All Project Directories")
+{
+ m_allProjectDirectoriesFilter.setDisplayName(m_allProjectDirectoriesFilter.id().toString());
+ m_allProjectDirectoriesFilter.setShortcutString("a"); // shared with "Files in Any Project"
+ m_allProjectDirectoriesFilter.setIncludedByDefault(false); // but not included in default
+ m_allProjectDirectoriesFilter.setFilters({});
+ m_allProjectDirectoriesFilter.setIsCustomFilter(false);
+}
+
void ProjectExplorerPluginPrivate::deploy(QList<Project *> projects)
{
QList<Id> steps;
@@ -2561,11 +2596,11 @@ int ProjectExplorerPluginPrivate::queue(QList<Project *> projects, QList<Id> ste
BuildConfiguration *bc = t ? t->activeBuildConfiguration() : nullptr;
if (!bc)
return false;
- if (!Utils::FileName::fromString(rc->runnable().executable).isChildOf(bc->buildDirectory()))
+ if (!Utils::FilePath::fromString(rc->runnable().executable).isChildOf(bc->buildDirectory()))
return false;
IDevice::ConstPtr device = rc->runnable().device;
if (device.isNull())
- device = DeviceKitInformation::device(t->kit());
+ device = DeviceKitAspect::device(t->kit());
return !device.isNull() && device->type() == Core::Id(Constants::DESKTOP_DEVICE_TYPE);
});
}
@@ -2637,7 +2672,7 @@ void ProjectExplorerPlugin::buildProject(Project *p)
void ProjectExplorerPluginPrivate::runProjectContextMenu()
{
- const Node *node = ProjectTree::findCurrentNode();
+ const Node *node = ProjectTree::currentNode();
const ProjectNode *projectNode = node ? node->asProjectNode() : nullptr;
if (projectNode == ProjectTree::currentProject()->rootProjectNode() || !projectNode) {
m_instance->runProject(ProjectTree::currentProject(), Constants::NORMAL_RUN_MODE);
@@ -3015,8 +3050,7 @@ bool ProjectExplorerPlugin::canRunStartupProject(Core::Id runMode, QString *whyN
}
// shouldn't actually be shown to the user...
- RunControl::WorkerCreator producer = RunControl::producer(activeRC, runMode);
- if (!producer) {
+ if (!RunControl::canRun(activeRC, runMode)) {
if (whyNot)
*whyNot = tr("Cannot run \"%1\".").arg(activeRC->displayName());
return false;
@@ -3139,6 +3173,7 @@ void ProjectExplorerPluginPrivate::updateContextMenuActions()
m_addExistingDirectoryAction->setEnabled(false);
m_addNewFileAction->setEnabled(false);
m_addNewSubprojectAction->setEnabled(false);
+ m_addExistingProjectsAction->setEnabled(false);
m_removeProjectAction->setEnabled(false);
m_removeFileAction->setEnabled(false);
m_duplicateFileAction->setEnabled(false);
@@ -3150,6 +3185,7 @@ void ProjectExplorerPluginPrivate::updateContextMenuActions()
m_addExistingDirectoryAction->setVisible(true);
m_addNewFileAction->setVisible(true);
m_addNewSubprojectAction->setVisible(true);
+ m_addExistingProjectsAction->setVisible(true);
m_removeProjectAction->setVisible(true);
m_removeFileAction->setVisible(true);
m_duplicateFileAction->setVisible(false);
@@ -3168,7 +3204,7 @@ void ProjectExplorerPluginPrivate::updateContextMenuActions()
runMenu->menu()->clear();
runMenu->menu()->menuAction()->setVisible(false);
- const Node *currentNode = ProjectTree::findCurrentNode();
+ const Node *currentNode = ProjectTree::currentNode();
if (currentNode && currentNode->managingProject()) {
ProjectNode *pn;
@@ -3179,7 +3215,7 @@ void ProjectExplorerPluginPrivate::updateContextMenuActions()
Project *project = ProjectTree::currentProject();
m_openTerminalHereBuildEnv->setVisible(bool(buildEnv(project)));
- m_openTerminalHereRunEnv->setVisible(bool(runEnv(project)));
+ m_openTerminalHereRunEnv->setVisible(canOpenTerminalWithRunEnv(project));
if (pn && project) {
if (pn == project->rootProjectNode()) {
@@ -3187,8 +3223,9 @@ void ProjectExplorerPluginPrivate::updateContextMenuActions()
} else {
QList<RunConfiguration *> runConfigs;
if (Target *t = project->activeTarget()) {
+ const QString buildKey = pn->buildKey();
for (RunConfiguration *rc : t->runConfigurations()) {
- if (rc->canRunForNode(pn))
+ if (rc->buildKey() == buildKey)
runConfigs.append(rc);
}
}
@@ -3217,10 +3254,12 @@ void ProjectExplorerPluginPrivate::updateContextMenuActions()
// Also handles ProjectNode
m_addNewFileAction->setEnabled(supports(AddNewFile)
&& !ICore::isNewItemDialogRunning());
- m_addNewSubprojectAction->setEnabled(currentNode->nodeType() == NodeType::Project
+ m_addNewSubprojectAction->setEnabled(currentNode->isProjectNodeType()
&& supports(AddSubProject)
&& !ICore::isNewItemDialogRunning());
- m_removeProjectAction->setEnabled(currentNode->nodeType() == NodeType::Project
+ m_addExistingProjectsAction->setEnabled(currentNode->isProjectNodeType()
+ && supports(AddExistingProject));
+ m_removeProjectAction->setEnabled(currentNode->isProjectNodeType()
&& supports(RemoveSubProject));
m_addExistingFilesAction->setEnabled(supports(AddExistingFile));
m_addExistingDirectoryAction->setEnabled(supports(AddExistingDirectory));
@@ -3265,6 +3304,7 @@ void ProjectExplorerPluginPrivate::updateContextMenuActions()
if (supports(HideFolderActions)) {
m_addNewFileAction->setVisible(false);
m_addNewSubprojectAction->setVisible(false);
+ m_addExistingProjectsAction->setVisible(false);
m_removeProjectAction->setVisible(false);
m_addExistingFilesAction->setVisible(false);
m_addExistingDirectoryAction->setVisible(false);
@@ -3289,7 +3329,7 @@ void ProjectExplorerPluginPrivate::updateLocationSubMenus()
QTC_CHECK(folderMenu->actions().isEmpty());
const FolderNode *const fn
- = ProjectTree::findCurrentNode() ? ProjectTree::findCurrentNode()->asFolderNode() : nullptr;
+ = ProjectTree::currentNode() ? ProjectTree::currentNode()->asFolderNode() : nullptr;
const QList<FolderNode::LocationInfo> locations
= fn ? fn->locationInfo() : QList<FolderNode::LocationInfo>();
@@ -3302,7 +3342,7 @@ void ProjectExplorerPluginPrivate::updateLocationSubMenus()
for (const FolderNode::LocationInfo &li : locations) {
const int line = li.line;
- const Utils::FileName path = li.path;
+ const Utils::FilePath path = li.path;
auto *action = new QAction(li.displayName, nullptr);
connect(action, &QAction::triggered, this, [line, path]() {
Core::EditorManager::openEditorAt(path.toString(), line);
@@ -3317,7 +3357,7 @@ void ProjectExplorerPluginPrivate::updateLocationSubMenus()
void ProjectExplorerPluginPrivate::addNewFile()
{
- Node* currentNode = ProjectTree::findCurrentNode();
+ Node *currentNode = ProjectTree::currentNode();
QTC_ASSERT(currentNode, return);
QString location = directoryFor(currentNode);
@@ -3343,11 +3383,11 @@ void ProjectExplorerPluginPrivate::addNewFile()
void ProjectExplorerPluginPrivate::addNewSubproject()
{
- Node* currentNode = ProjectTree::findCurrentNode();
+ Node* currentNode = ProjectTree::currentNode();
QTC_ASSERT(currentNode, return);
QString location = directoryFor(currentNode);
- if (currentNode->nodeType() == NodeType::Project
+ if (currentNode->isProjectNodeType()
&& currentNode->supportsAction(AddSubProject, currentNode)) {
QVariantMap map;
map.insert(QLatin1String(Constants::PREFERRED_PROJECT_NODE), QVariant::fromValue(currentNode));
@@ -3371,9 +3411,50 @@ void ProjectExplorerPluginPrivate::addNewSubproject()
}
}
+void ProjectExplorerPluginPrivate::addExistingProjects()
+{
+ Node * const currentNode = ProjectTree::currentNode();
+ if (!currentNode)
+ return;
+ ProjectNode *projectNode = currentNode->asProjectNode();
+ if (!projectNode && currentNode->asContainerNode())
+ projectNode = currentNode->asContainerNode()->rootProjectNode();
+ QTC_ASSERT(projectNode, return);
+ const QString dir = directoryFor(currentNode);
+ QStringList subProjectFilePaths = QFileDialog::getOpenFileNames(
+ ICore::mainWindow(), tr("Choose Project File"), dir,
+ projectNode->subProjectFileNamePatterns().join(";;"));
+ if (!ProjectTree::hasNode(projectNode))
+ return;
+ const QList<Node *> childNodes = projectNode->nodes();
+ Utils::erase(subProjectFilePaths, [childNodes](const QString &filePath) {
+ return Utils::anyOf(childNodes, [filePath](const Node *n) {
+ return n->filePath().toString() == filePath;
+ });
+ });
+ if (subProjectFilePaths.empty())
+ return;
+ QStringList failedProjects;
+ QStringList addedProjects;
+ for (const QString &filePath : subProjectFilePaths) {
+ if (projectNode->addSubProject(filePath))
+ addedProjects << filePath;
+ else
+ failedProjects << filePath;
+ }
+ if (!failedProjects.empty()) {
+ const QString message = tr("The following subprojects could not be added to project "
+ "\"%2\":").arg(projectNode->managingProject()->displayName());
+ QMessageBox::warning(ICore::mainWindow(), tr("Adding Subproject Failed"),
+ message + "\n " + failedProjects.join("\n "));
+ return;
+ }
+ VcsManager::promptToAdd(dir, addedProjects);
+}
+
void ProjectExplorerPluginPrivate::handleAddExistingFiles()
{
- Node *node = ProjectTree::findCurrentNode();
+ Node *node = ProjectTree::currentNode();
FolderNode *folderNode = node ? node->asFolderNode() : nullptr;
QTC_ASSERT(folderNode, return);
@@ -3388,19 +3469,17 @@ void ProjectExplorerPluginPrivate::handleAddExistingFiles()
void ProjectExplorerPluginPrivate::addExistingDirectory()
{
- Node *node = ProjectTree::findCurrentNode();
+ Node *node = ProjectTree::currentNode();
FolderNode *folderNode = node ? node->asFolderNode() : nullptr;
QTC_ASSERT(folderNode, return);
- SelectableFilesDialogAddDirectory dialog(Utils::FileName::fromString(directoryFor(node)),
- Utils::FileNameList(), ICore::mainWindow());
- const QString addFileFilter = folderNode->addFileFilter();
- if (!addFileFilter.isEmpty())
- dialog.setAddFileFilter(addFileFilter);
+ SelectableFilesDialogAddDirectory dialog(Utils::FilePath::fromString(directoryFor(node)),
+ Utils::FilePathList(), ICore::mainWindow());
+ dialog.setAddFileFilter({});
if (dialog.exec() == QDialog::Accepted)
- ProjectExplorerPlugin::addExistingFiles(folderNode, Utils::transform(dialog.selectedFiles(), &Utils::FileName::toString));
+ ProjectExplorerPlugin::addExistingFiles(folderNode, Utils::transform(dialog.selectedFiles(), &Utils::FilePath::toString));
}
void ProjectExplorerPlugin::addExistingFiles(FolderNode *folderNode, const QStringList &filePaths)
@@ -3430,7 +3509,7 @@ void ProjectExplorerPlugin::addExistingFiles(FolderNode *folderNode, const QStri
void ProjectExplorerPluginPrivate::removeProject()
{
- Node *node = ProjectTree::findCurrentNode();
+ Node *node = ProjectTree::currentNode();
if (!node)
return;
ProjectNode *projectNode = node->managingProject();
@@ -3444,28 +3523,28 @@ void ProjectExplorerPluginPrivate::removeProject()
void ProjectExplorerPluginPrivate::openFile()
{
- const Node *currentNode = ProjectTree::findCurrentNode();
+ const Node *currentNode = ProjectTree::currentNode();
QTC_ASSERT(currentNode, return);
EditorManager::openEditor(currentNode->filePath().toString());
}
void ProjectExplorerPluginPrivate::searchOnFileSystem()
{
- const Node *currentNode = ProjectTree::findCurrentNode();
+ const Node *currentNode = ProjectTree::currentNode();
QTC_ASSERT(currentNode, return);
TextEditor::FindInFiles::findOnFileSystem(pathFor(currentNode));
}
void ProjectExplorerPluginPrivate::showInGraphicalShell()
{
- Node *currentNode = ProjectTree::findCurrentNode();
+ Node *currentNode = ProjectTree::currentNode();
QTC_ASSERT(currentNode, return);
FileUtils::showInGraphicalShell(ICore::mainWindow(), pathFor(currentNode));
}
void ProjectExplorerPluginPrivate::openTerminalHere(const EnvironmentGetter &env)
{
- const Node *currentNode = ProjectTree::findCurrentNode();
+ const Node *currentNode = ProjectTree::currentNode();
QTC_ASSERT(currentNode, return);
const auto environment = env(ProjectTree::projectForNode(currentNode));
@@ -3475,21 +3554,46 @@ void ProjectExplorerPluginPrivate::openTerminalHere(const EnvironmentGetter &env
FileUtils::openTerminal(directoryFor(currentNode), environment.value());
}
+void ProjectExplorerPluginPrivate::openTerminalHereWithRunEnv()
+{
+ const Node *currentNode = ProjectTree::currentNode();
+ QTC_ASSERT(currentNode, return);
+
+ const Project * const project = ProjectTree::projectForNode(currentNode);
+ QTC_ASSERT(project, return);
+ const Target * const target = project->activeTarget();
+ QTC_ASSERT(target, return);
+ const RunConfiguration * const runConfig = target->activeRunConfiguration();
+ QTC_ASSERT(runConfig, return);
+
+ const Runnable runnable = runConfig->runnable();
+ IDevice::ConstPtr device = runnable.device;
+ if (!device)
+ device = DeviceKitAspect::device(target->kit());
+ QTC_ASSERT(device && device->canOpenTerminal(), return);
+ const QString workingDir = device->type() == Constants::DESKTOP_DEVICE_TYPE
+ ? directoryFor(currentNode) : runnable.workingDirectory;
+ device->openTerminal(runnable.environment, workingDir);
+}
+
void ProjectExplorerPluginPrivate::removeFile()
{
- const Node *currentNode = ProjectTree::findCurrentNode();
- QTC_ASSERT(currentNode && currentNode->nodeType() == NodeType::File, return);
+ const Node *currentNode = ProjectTree::currentNode();
+ QTC_ASSERT(currentNode && currentNode->asFileNode(), return);
- const Utils::FileName filePath = currentNode->filePath();
+ const Utils::FilePath filePath = currentNode->filePath();
Utils::RemoveFileDialog removeFileDialog(filePath.toString(), ICore::mainWindow());
if (removeFileDialog.exec() == QDialog::Accepted) {
const bool deleteFile = removeFileDialog.isDeleteFileChecked();
// Re-read the current node, in case the project is re-parsed while the dialog is open
- if (currentNode != ProjectTree::findCurrentNode()) {
- currentNode = ProjectTreeWidget::nodeForFile(filePath);
- QTC_ASSERT(currentNode && currentNode->nodeType() == NodeType::File, return);
+ if (!ProjectTree::hasNode(currentNode)) {
+ QMessageBox::warning(ICore::mainWindow(), tr("Removing File Failed"),
+ tr("File %1 was not removed, because the project has changed "
+ "in the meantime.\nPlease try again.")
+ .arg(filePath.toUserOutput()));
+ return;
}
// remove from project
@@ -3512,8 +3616,8 @@ void ProjectExplorerPluginPrivate::removeFile()
void ProjectExplorerPluginPrivate::duplicateFile()
{
- Node *currentNode = ProjectTree::findCurrentNode();
- QTC_ASSERT(currentNode && currentNode->nodeType() == NodeType::File, return);
+ Node *currentNode = ProjectTree::currentNode();
+ QTC_ASSERT(currentNode && currentNode->asFileNode(), return);
FileNode *fileNode = currentNode->asFileNode();
QString filePath = currentNode->filePath().toString();
@@ -3543,8 +3647,8 @@ void ProjectExplorerPluginPrivate::duplicateFile()
void ProjectExplorerPluginPrivate::deleteFile()
{
- Node *currentNode = ProjectTree::findCurrentNode();
- QTC_ASSERT(currentNode && currentNode->nodeType() == NodeType::File, return);
+ Node *currentNode = ProjectTree::currentNode();
+ QTC_ASSERT(currentNode && currentNode->asFileNode(), return);
FileNode *fileNode = currentNode->asFileNode();
@@ -3696,6 +3800,16 @@ const ProjectExplorerSettings &ProjectExplorerPlugin::projectExplorerSettings()
return dd->m_projectExplorerSettings;
}
+void ProjectExplorerPlugin::setAppOutputSettings(const AppOutputSettings &settings)
+{
+ dd->m_outputPane.setSettings(settings);
+}
+
+const AppOutputSettings &ProjectExplorerPlugin::appOutputSettings()
+{
+ return dd->m_outputPane.settings();
+}
+
QStringList ProjectExplorerPlugin::projectFilePatterns()
{
QStringList patterns;
@@ -3707,7 +3821,7 @@ QStringList ProjectExplorerPlugin::projectFilePatterns()
return patterns;
}
-bool ProjectExplorerPlugin::isProjectFile(const Utils::FileName &filePath)
+bool ProjectExplorerPlugin::isProjectFile(const Utils::FilePath &filePath)
{
Utils::MimeType mt = Utils::mimeTypeForFile(filePath.toString());
for (const QString &mime : dd->m_projectCreators.keys()) {
@@ -3737,16 +3851,6 @@ QString ProjectExplorerPlugin::buildDirectoryTemplate()
return dd->m_projectExplorerSettings.buildDirectoryTemplate;
}
-/*!
- Sets the current build directory template to \a directory.
-
- \sa defaultbuildDirectory
-*/
-void ProjectExplorerPlugin::setBuildDirectoryTemplate(const QString &dir)
-{
- dd->m_projectExplorerSettings.buildDirectoryTemplate = dir;
-}
-
QString ProjectExplorerPlugin::defaultBuildDirectoryTemplate()
{
return QString(Constants::DEFAULT_BUILD_DIRECTORY_TEMPLATE);
@@ -3758,12 +3862,12 @@ QList<QPair<QString, QString> > ProjectExplorerPlugin::recentProjects()
}
void ProjectManager::registerProjectCreator(const QString &mimeType,
- const std::function<Project *(const Utils::FileName &)> &creator)
+ const std::function<Project *(const Utils::FilePath &)> &creator)
{
dd->m_projectCreators[mimeType] = creator;
}
-Project *ProjectManager::openProject(const Utils::MimeType &mt, const Utils::FileName &fileName)
+Project *ProjectManager::openProject(const Utils::MimeType &mt, const Utils::FilePath &fileName)
{
if (mt.isValid()) {
for (const QString &mimeType : dd->m_projectCreators.keys()) {
diff --git a/src/plugins/projectexplorer/projectexplorer.h b/src/plugins/projectexplorer/projectexplorer.h
index e00fc393d0..23c2098216 100644
--- a/src/plugins/projectexplorer/projectexplorer.h
+++ b/src/plugins/projectexplorer/projectexplorer.h
@@ -45,7 +45,7 @@ class Id;
namespace Utils {
class ProcessHandle;
-class FileName;
+class FilePath;
}
namespace ProjectExplorer {
@@ -56,7 +56,10 @@ class Node;
class FolderNode;
class FileNode;
-namespace Internal { class ProjectExplorerSettings; }
+namespace Internal {
+class AppOutputSettings;
+class ProjectExplorerSettings;
+}
class PROJECTEXPLORER_EXPORT ProjectExplorerPlugin : public ExtensionSystem::IPlugin
{
@@ -129,13 +132,16 @@ public:
static void setProjectExplorerSettings(const Internal::ProjectExplorerSettings &pes);
static const Internal::ProjectExplorerSettings &projectExplorerSettings();
+ static void setAppOutputSettings(const Internal::AppOutputSettings &settings);
+ static const Internal::AppOutputSettings &appOutputSettings();
+
static void startRunControl(RunControl *runControl);
static void showRunErrorMessage(const QString &errorMessage);
// internal public for FlatModel
static void renameFile(Node *node, const QString &newFilePath);
static QStringList projectFilePatterns();
- static bool isProjectFile(const Utils::FileName &filePath);
+ static bool isProjectFile(const Utils::FilePath &filePath);
static QList<QPair<QString, QString> > recentProjects();
static bool canRunStartupProject(Core::Id runMode, QString *whyNot = nullptr);
@@ -164,7 +170,6 @@ public:
static void openOpenProjectDialog();
static QString buildDirectoryTemplate();
- static void setBuildDirectoryTemplate(const QString &dir);
static QString defaultBuildDirectoryTemplate();
signals:
@@ -252,6 +257,8 @@ private slots:
void testProject_parsingSuccess();
void testProject_parsingFail();
void testProject_projectTree();
+
+ void testSessionSwitch();
#endif // WITH_TESTS
};
diff --git a/src/plugins/projectexplorer/projectexplorer.pro b/src/plugins/projectexplorer/projectexplorer.pro
index 8ef32ae9ba..097fcb6da5 100644
--- a/src/plugins/projectexplorer/projectexplorer.pro
+++ b/src/plugins/projectexplorer/projectexplorer.pro
@@ -10,6 +10,7 @@ include(../../shared/clang/clang_defines.pri)
HEADERS += projectexplorer.h \
abi.h \
abiwidget.h \
+ addrunconfigdialog.h \
ansifilterparser.h \
buildinfo.h \
clangparser.h \
@@ -17,6 +18,8 @@ HEADERS += projectexplorer.h \
environmentaspect.h \
environmentaspectwidget.h \
extraabi.h \
+ fileinsessionfinder.h \
+ filterkitaspectsdialog.h \
gcctoolchain.h \
importwidget.h \
userfileaccessor.h \
@@ -31,9 +34,7 @@ HEADERS += projectexplorer.h \
targetsetupwidget.h \
kit.h \
kitchooser.h \
- kitconfigwidget.h \
kitinformation.h \
- kitinformationconfigwidget.h \
kitfeatureprovider.h \
kitmanager.h \
kitmanagerconfigwidget.h \
@@ -76,6 +77,7 @@ HEADERS += projectexplorer.h \
editorconfiguration.h \
editorsettingspropertiespage.h \
runconfiguration.h \
+ runcontrol.h \
applicationlauncher.h \
runsettingspropertiespage.h \
projecttreewidget.h \
@@ -158,11 +160,14 @@ HEADERS += projectexplorer.h \
customexecutablerunconfiguration.h \
projectmacro.h \
makestep.h \
- projectconfigurationaspects.h
+ parseissuesdialog.h \
+ projectconfigurationaspects.h \
+ treescanner.h
SOURCES += projectexplorer.cpp \
abi.cpp \
abiwidget.cpp \
+ addrunconfigdialog.cpp \
ansifilterparser.cpp \
buildinfo.cpp \
clangparser.cpp \
@@ -170,6 +175,8 @@ SOURCES += projectexplorer.cpp \
environmentaspect.cpp \
environmentaspectwidget.cpp \
extraabi.cpp \
+ fileinsessionfinder.cpp \
+ filterkitaspectsdialog.cpp \
gcctoolchain.cpp \
importwidget.cpp \
projectconfigurationmodel.cpp \
@@ -184,9 +191,7 @@ SOURCES += projectexplorer.cpp \
targetsetupwidget.cpp \
kit.cpp \
kitchooser.cpp \
- kitconfigwidget.cpp \
kitinformation.cpp \
- kitinformationconfigwidget.cpp \
kitmanager.cpp \
kitmanagerconfigwidget.cpp \
kitmodel.cpp \
@@ -224,6 +229,7 @@ SOURCES += projectexplorer.cpp \
editorconfiguration.cpp \
editorsettingspropertiespage.cpp \
runconfiguration.cpp \
+ runcontrol.cpp \
applicationlauncher.cpp \
runsettingspropertiespage.cpp \
projecttreewidget.cpp \
@@ -298,9 +304,11 @@ SOURCES += projectexplorer.cpp \
customexecutablerunconfiguration.cpp \
projectmacro.cpp \
makestep.cpp \
- projectconfigurationaspects.cpp
+ parseissuesdialog.cpp \
+ projectconfigurationaspects.cpp \
+ treescanner.cpp
-FORMS += processstep.ui \
+FORMS += \
editorsettingspropertiespage.ui \
sessiondialog.ui \
projectwizardpage.ui \
@@ -344,3 +352,7 @@ journald {
RESOURCES += projectexplorer.qrc
DEFINES += PROJECTEXPLORER_LIBRARY
+
+!isEmpty(PROJECT_USER_FILE_EXTENSION) {
+ DEFINES += PROJECT_USER_FILE_EXTENSION=$${PROJECT_USER_FILE_EXTENSION}
+}
diff --git a/src/plugins/projectexplorer/projectexplorer.qbs b/src/plugins/projectexplorer/projectexplorer.qbs
index 5836c06c45..395c1cced9 100644
--- a/src/plugins/projectexplorer/projectexplorer.qbs
+++ b/src/plugins/projectexplorer/projectexplorer.qbs
@@ -24,6 +24,7 @@ Project {
"abi.cpp", "abi.h",
"abiwidget.cpp", "abiwidget.h",
"abstractprocessstep.cpp", "abstractprocessstep.h",
+ "addrunconfigdialog.cpp", "addrunconfigdialog.h",
"allprojectsfilter.cpp", "allprojectsfilter.h",
"allprojectsfind.cpp", "allprojectsfind.h",
"ansifilterparser.cpp", "ansifilterparser.h",
@@ -69,6 +70,8 @@ Project {
"expanddata.cpp", "expanddata.h",
"extraabi.cpp", "extraabi.h",
"extracompiler.cpp", "extracompiler.h",
+ "fileinsessionfinder.cpp", "fileinsessionfinder.h",
+ "filterkitaspectsdialog.cpp", "filterkitaspectsdialog.h",
"foldernavigationwidget.cpp", "foldernavigationwidget.h",
"gccparser.cpp", "gccparser.h",
"gcctoolchain.cpp", "gcctoolchain.h",
@@ -81,10 +84,8 @@ Project {
"itaskhandler.h",
"kit.cpp", "kit.h",
"kitchooser.cpp", "kitchooser.h",
- "kitconfigwidget.cpp", "kitconfigwidget.h",
"kitfeatureprovider.h",
"kitinformation.cpp", "kitinformation.h",
- "kitinformationconfigwidget.cpp", "kitinformationconfigwidget.h",
"kitmanager.cpp", "kitmanager.h",
"kitmanagerconfigwidget.cpp", "kitmanagerconfigwidget.h",
"kitmodel.cpp", "kitmodel.h",
@@ -98,8 +99,9 @@ Project {
"namedwidget.cpp", "namedwidget.h",
"osparser.cpp", "osparser.h",
"panelswidget.cpp", "panelswidget.h",
+ "parseissuesdialog.cpp", "parseissuesdialog.h",
"processparameters.cpp", "processparameters.h",
- "processstep.cpp", "processstep.h", "processstep.ui",
+ "processstep.cpp", "processstep.h",
"project.cpp", "project.h",
"projectconfiguration.cpp", "projectconfiguration.h",
"projectconfigurationaspects.cpp", "projectconfigurationaspects.h",
@@ -127,6 +129,7 @@ Project {
"projectwizardpage.cpp", "projectwizardpage.h", "projectwizardpage.ui",
"removetaskhandler.cpp", "removetaskhandler.h",
"runconfiguration.cpp", "runconfiguration.h",
+ "runcontrol.cpp", "runcontrol.h",
"runconfigurationaspects.cpp", "runconfigurationaspects.h",
"runsettingspropertiespage.cpp", "runsettingspropertiespage.h",
"selectablefilesmodel.cpp", "selectablefilesmodel.h",
@@ -151,6 +154,7 @@ Project {
"toolchainmanager.cpp", "toolchainmanager.h",
"toolchainoptionspage.cpp", "toolchainoptionspage.h",
"toolchainsettingsaccessor.cpp", "toolchainsettingsaccessor.h",
+ "treescanner.cpp", "treescanner.h",
"userfileaccessor.cpp", "userfileaccessor.h",
"vcsannotatetaskhandler.cpp", "vcsannotatetaskhandler.h",
"waitforstopdialog.cpp", "waitforstopdialog.h",
diff --git a/src/plugins/projectexplorer/projectexplorer.qrc b/src/plugins/projectexplorer/projectexplorer.qrc
index 9eb42e7ebc..29bda00509 100644
--- a/src/plugins/projectexplorer/projectexplorer.qrc
+++ b/src/plugins/projectexplorer/projectexplorer.qrc
@@ -73,6 +73,8 @@
<file>images/fileoverlay_cpp@2x.png</file>
<file>images/fileoverlay_h.png</file>
<file>images/fileoverlay_h@2x.png</file>
+ <file>images/fileoverlay_py.png</file>
+ <file>images/fileoverlay_py@2x.png</file>
<file>images/fileoverlay_unknown.png</file>
<file>images/fileoverlay_unknown@2x.png</file>
<file>images/cancelbuild_overlay.png</file>
diff --git a/src/plugins/projectexplorer/projectexplorerconstants.h b/src/plugins/projectexplorer/projectexplorerconstants.h
index 34e218b149..ad2d9e049e 100644
--- a/src/plugins/projectexplorer/projectexplorerconstants.h
+++ b/src/plugins/projectexplorer/projectexplorerconstants.h
@@ -124,6 +124,7 @@ const char DEVICE_SETTINGS_PAGE_ID[] = "AA.Device Settings";
const char TASK_CATEGORY_COMPILE[] = "Task.Category.Compile";
const char TASK_CATEGORY_BUILDSYSTEM[] = "Task.Category.Buildsystem";
const char TASK_CATEGORY_DEPLOYMENT[] = "Task.Category.Deploy";
+const char TASK_CATEGORY_AUTOTEST[] = "Task.Category.Autotest";
// Wizard categories
const char QT_PROJECT_WIZARD_CATEGORY[] = "H.Project";
@@ -185,6 +186,7 @@ const char VAR_CURRENTBUILD_NAME[] = "CurrentBuild:Name";
const char VAR_CURRENTBUILD_TYPE[] = "CurrentBuild:Type";
const char VAR_CURRENTBUILD_ENV[] = "CurrentBuild:Env";
const char VAR_CURRENTRUN_NAME[] = "CurrentRun:Name";
+const char VAR_CURRENTRUN_WORKINGDIR[] = "CurrentRun:WorkingDir";
// JsonWizard:
const char PAGE_ID_PREFIX[] = "PE.Wizard.Page.";
@@ -209,9 +211,11 @@ const char FILEOVERLAY_QRC[]=":/projectexplorer/images/fileoverlay_qrc.png";
const char FILEOVERLAY_CPP[]=":/projectexplorer/images/fileoverlay_cpp.png";
const char FILEOVERLAY_H[]=":/projectexplorer/images/fileoverlay_h.png";
const char FILEOVERLAY_SCXML[]=":/projectexplorer/images/fileoverlay_scxml.png";
+const char FILEOVERLAY_PY[]=":/projectexplorer/images/fileoverlay_py.png";
const char FILEOVERLAY_UNKNOWN[]=":/projectexplorer/images/fileoverlay_unknown.png";
const char ADD_FILES_DIALOG_FILTER_HISTORY_KEY[] = "ProjectExplorer.AddFilesFilterKey";
+const char PROJECT_ROOT_PATH_KEY[] = "ProjectExplorer.Project.RootPath";
} // namespace Constants
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/projectexplorersettings.h b/src/plugins/projectexplorer/projectexplorersettings.h
index 13277e9736..85e9a77abe 100644
--- a/src/plugins/projectexplorer/projectexplorersettings.h
+++ b/src/plugins/projectexplorer/projectexplorersettings.h
@@ -33,6 +33,8 @@
namespace ProjectExplorer {
namespace Internal {
+enum class TerminalMode { On, Off, Smart };
+
class ProjectExplorerSettings
{
public:
@@ -41,20 +43,15 @@ public:
bool buildBeforeDeploy = true;
bool deployBeforeRun = true;
bool saveBeforeBuild = false;
- bool showCompilerOutput = false;
- bool showRunOutput = true;
- bool showDebugOutput = false;
- bool cleanOldAppOutput = false;
- bool mergeStdErrAndStdOut = false;
- bool wrapAppOutput = true;
bool useJom = true;
bool autorestoreLastSession = false; // This option is set in the Session Manager!
bool prompToStopRunControl = false;
bool automaticallyCreateRunConfigurations = true;
bool addLibraryPathsToRunEnv = true;
- int maxAppOutputChars = Core::Constants::DEFAULT_MAX_CHAR_COUNT;
- int maxBuildOutputChars = Core::Constants::DEFAULT_MAX_CHAR_COUNT;
+ bool closeSourceFilesWithProject = true;
+ bool clearIssuesOnRebuild = true;
StopBeforeBuild stopBeforeBuild = StopBeforeBuild::StopNone;
+ TerminalMode terminalMode = TerminalMode::Smart;
QString buildDirectoryTemplate;
// Add a UUid which is used to identify the development environment.
@@ -68,23 +65,37 @@ inline bool operator==(const ProjectExplorerSettings &p1, const ProjectExplorerS
return p1.buildBeforeDeploy == p2.buildBeforeDeploy
&& p1.deployBeforeRun == p2.deployBeforeRun
&& p1.saveBeforeBuild == p2.saveBeforeBuild
- && p1.showCompilerOutput == p2.showCompilerOutput
- && p1.showRunOutput == p2.showRunOutput
- && p1.showDebugOutput == p2.showDebugOutput
- && p1.cleanOldAppOutput == p2.cleanOldAppOutput
- && p1.mergeStdErrAndStdOut == p2.mergeStdErrAndStdOut
- && p1.wrapAppOutput == p2.wrapAppOutput
&& p1.useJom == p2.useJom
&& p1.autorestoreLastSession == p2.autorestoreLastSession
&& p1.prompToStopRunControl == p2.prompToStopRunControl
&& p1.automaticallyCreateRunConfigurations == p2.automaticallyCreateRunConfigurations
&& p1.addLibraryPathsToRunEnv == p2.addLibraryPathsToRunEnv
- && p1.maxAppOutputChars == p2.maxAppOutputChars
- && p1.maxBuildOutputChars == p2.maxBuildOutputChars
&& p1.environmentId == p2.environmentId
&& p1.stopBeforeBuild == p2.stopBeforeBuild
+ && p1.terminalMode == p2.terminalMode
+ && p1.closeSourceFilesWithProject == p2.closeSourceFilesWithProject
+ && p1.clearIssuesOnRebuild == p2.clearIssuesOnRebuild
&& p1.buildDirectoryTemplate == p2.buildDirectoryTemplate;
}
+class AppOutputSettings
+{
+public:
+ bool popUpForRunOutput = true;
+ bool popUpForDebugOutput = false;
+ bool cleanOldOutput = false;
+ bool mergeChannels = false;
+ bool wrapOutput = false;
+ int maxCharCount = Core::Constants::DEFAULT_MAX_CHAR_COUNT;
+};
+
+class CompileOutputSettings
+{
+public:
+ bool popUp = false;
+ bool wrapOutput = false;
+ int maxCharCount = Core::Constants::DEFAULT_MAX_CHAR_COUNT;
+};
+
} // namespace ProjectExplorer
} // namespace Internal
diff --git a/src/plugins/projectexplorer/projectexplorersettingspage.cpp b/src/plugins/projectexplorer/projectexplorersettingspage.cpp
index d7e506021c..73f622aedf 100644
--- a/src/plugins/projectexplorer/projectexplorersettingspage.cpp
+++ b/src/plugins/projectexplorer/projectexplorersettingspage.cpp
@@ -57,15 +57,14 @@ public:
bool useProjectsDirectory();
void setUseProjectsDirectory(bool v);
- QString buildDirectoryTemplate() const;
- void setBuildDirectoryTemplate(const QString &bd);
-
private:
void slotDirectoryButtonGroupChanged();
void resetBuildDirectoryTemplate();
void updateBuildDirectoryResetButton();
void setJomVisible(bool);
+ QString buildDirectoryTemplate() const;
+ void setBuildDirectoryTemplate(const QString &bd);
Ui::ProjectExplorerSettingsPageUi m_ui;
mutable ProjectExplorerSettings m_settings;
@@ -79,7 +78,7 @@ ProjectExplorerSettingsWidget::ProjectExplorerSettingsWidget(QWidget *parent) :
m_ui.directoryButtonGroup->setId(m_ui.currentDirectoryRadioButton, UseCurrentDirectory);
m_ui.directoryButtonGroup->setId(m_ui.directoryRadioButton, UseProjectDirectory);
- connect(m_ui.directoryButtonGroup, static_cast<void (QButtonGroup::*)(int)>(&QButtonGroup::buttonClicked),
+ connect(m_ui.directoryButtonGroup, QOverload<int>::of(&QButtonGroup::buttonClicked),
this, &ProjectExplorerSettingsWidget::slotDirectoryButtonGroupChanged);
connect(m_ui.buildDirectoryResetButton, &QAbstractButton::clicked,
this, &ProjectExplorerSettingsWidget::resetBuildDirectoryTemplate);
@@ -101,19 +100,15 @@ ProjectExplorerSettings ProjectExplorerSettingsWidget::settings() const
m_settings.buildBeforeDeploy = m_ui.buildProjectBeforeDeployCheckBox->isChecked();
m_settings.deployBeforeRun = m_ui.deployProjectBeforeRunCheckBox->isChecked();
m_settings.saveBeforeBuild = m_ui.saveAllFilesCheckBox->isChecked();
- m_settings.showCompilerOutput = m_ui.showCompileOutputCheckBox->isChecked();
- m_settings.showRunOutput = m_ui.showRunOutputCheckBox->isChecked();
- m_settings.showDebugOutput = m_ui.showDebugOutputCheckBox->isChecked();
- m_settings.cleanOldAppOutput = m_ui.cleanOldAppOutputCheckBox->isChecked();
- m_settings.mergeStdErrAndStdOut = m_ui.mergeStdErrAndStdOutCheckBox->isChecked();
- m_settings.wrapAppOutput = m_ui.wrapAppOutputCheckBox->isChecked();
m_settings.useJom = m_ui.jomCheckbox->isChecked();
m_settings.addLibraryPathsToRunEnv = m_ui.addLibraryPathsToRunEnvCheckBox->isChecked();
m_settings.prompToStopRunControl = m_ui.promptToStopRunControlCheckBox->isChecked();
m_settings.automaticallyCreateRunConfigurations = m_ui.automaticallyCreateRunConfiguration->isChecked();
- m_settings.maxAppOutputChars = m_ui.maxAppOutputBox->value();
- m_settings.maxBuildOutputChars = m_ui.maxBuildOutputBox->value();
m_settings.stopBeforeBuild = static_cast<ProjectExplorerSettings::StopBeforeBuild>(m_ui.stopBeforeBuildComboBox->currentIndex());
+ m_settings.terminalMode = static_cast<TerminalMode>(m_ui.terminalModeComboBox->currentIndex());
+ m_settings.closeSourceFilesWithProject = m_ui.closeSourceFilesCheckBox->isChecked();
+ m_settings.clearIssuesOnRebuild = m_ui.clearIssuesCheckBox->isChecked();
+ m_settings.buildDirectoryTemplate = buildDirectoryTemplate();
return m_settings;
}
@@ -123,19 +118,15 @@ void ProjectExplorerSettingsWidget::setSettings(const ProjectExplorerSettings &
m_ui.buildProjectBeforeDeployCheckBox->setChecked(m_settings.buildBeforeDeploy);
m_ui.deployProjectBeforeRunCheckBox->setChecked(m_settings.deployBeforeRun);
m_ui.saveAllFilesCheckBox->setChecked(m_settings.saveBeforeBuild);
- m_ui.showCompileOutputCheckBox->setChecked(m_settings.showCompilerOutput);
- m_ui.showRunOutputCheckBox->setChecked(m_settings.showRunOutput);
- m_ui.showDebugOutputCheckBox->setChecked(m_settings.showDebugOutput);
- m_ui.cleanOldAppOutputCheckBox->setChecked(m_settings.cleanOldAppOutput);
- m_ui.mergeStdErrAndStdOutCheckBox->setChecked(m_settings.mergeStdErrAndStdOut);
- m_ui.wrapAppOutputCheckBox->setChecked(m_settings.wrapAppOutput);
m_ui.jomCheckbox->setChecked(m_settings.useJom);
m_ui.addLibraryPathsToRunEnvCheckBox->setChecked(m_settings.addLibraryPathsToRunEnv);
m_ui.promptToStopRunControlCheckBox->setChecked(m_settings.prompToStopRunControl);
m_ui.automaticallyCreateRunConfiguration->setChecked(m_settings.automaticallyCreateRunConfigurations);
- m_ui.maxAppOutputBox->setValue(m_settings.maxAppOutputChars);
- m_ui.maxBuildOutputBox->setValue(m_settings.maxBuildOutputChars);
m_ui.stopBeforeBuildComboBox->setCurrentIndex(static_cast<int>(m_settings.stopBeforeBuild));
+ m_ui.terminalModeComboBox->setCurrentIndex(static_cast<int>(m_settings.terminalMode));
+ m_ui.closeSourceFilesCheckBox->setChecked(m_settings.closeSourceFilesWithProject);
+ m_ui.clearIssuesCheckBox->setChecked(m_settings.clearIssuesOnRebuild);
+ setBuildDirectoryTemplate(pes.buildDirectoryTemplate);
}
QString ProjectExplorerSettingsWidget::projectsDirectory() const
@@ -205,7 +196,6 @@ QWidget *ProjectExplorerSettingsPage::widget()
m_widget->setSettings(ProjectExplorerPlugin::projectExplorerSettings());
m_widget->setProjectsDirectory(Core::DocumentManager::projectsDirectory().toString());
m_widget->setUseProjectsDirectory(Core::DocumentManager::useProjectsDirectory());
- m_widget->setBuildDirectoryTemplate(ProjectExplorerPlugin::buildDirectoryTemplate());
}
return m_widget;
}
@@ -215,9 +205,8 @@ void ProjectExplorerSettingsPage::apply()
if (m_widget) {
ProjectExplorerPlugin::setProjectExplorerSettings(m_widget->settings());
Core::DocumentManager::setProjectsDirectory(
- Utils::FileName::fromString(m_widget->projectsDirectory()));
+ Utils::FilePath::fromString(m_widget->projectsDirectory()));
Core::DocumentManager::setUseProjectsDirectory(m_widget->useProjectsDirectory());
- ProjectExplorerPlugin::setBuildDirectoryTemplate(m_widget->buildDirectoryTemplate());
}
}
diff --git a/src/plugins/projectexplorer/projectexplorersettingspage.ui b/src/plugins/projectexplorer/projectexplorersettingspage.ui
index 7fecbfb38e..448ad3655b 100644
--- a/src/plugins/projectexplorer/projectexplorersettingspage.ui
+++ b/src/plugins/projectexplorer/projectexplorersettingspage.ui
@@ -6,11 +6,11 @@
<rect>
<x>0</x>
<y>0</y>
- <width>831</width>
- <height>520</height>
+ <width>994</width>
+ <height>808</height>
</rect>
</property>
- <layout class="QVBoxLayout" name="verticalLayout_2">
+ <layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QGroupBox" name="directoryGroupBox">
<property name="title">
@@ -47,126 +47,56 @@
</widget>
</item>
<item>
- <widget class="QGroupBox" name="buildAndRunGroupBox">
+ <widget class="QGroupBox" name="closeProjectGroupBox">
<property name="title">
- <string>Build and Run</string>
+ <string>Closing Projects</string>
</property>
- <layout class="QGridLayout" name="gridLayout">
- <item row="0" column="0">
- <widget class="QCheckBox" name="saveAllFilesCheckBox">
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QCheckBox" name="closeSourceFilesCheckBox">
<property name="text">
- <string>Save all files before build</string>
+ <string>Close source files along with project</string>
</property>
</widget>
</item>
- <item row="0" column="1">
- <widget class="QCheckBox" name="cleanOldAppOutputCheckBox">
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="buildAndRunGroupBox">
+ <property name="title">
+ <string>Build and Run</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <widget class="QCheckBox" name="saveAllFilesCheckBox">
<property name="text">
- <string>Clear old application output on a new run</string>
+ <string>Save all files before build</string>
</property>
</widget>
</item>
- <item row="1" column="0">
+ <item>
<widget class="QCheckBox" name="buildProjectBeforeDeployCheckBox">
<property name="text">
<string>Always build project before deploying it</string>
</property>
</widget>
</item>
- <item row="1" column="1">
- <widget class="QCheckBox" name="mergeStdErrAndStdOutCheckBox">
- <property name="toolTip">
- <string>Enabling this option ensures that the order of interleaved messages from stdout and stderr is preserved, at the cost of disabling highlighting of stderr.</string>
- </property>
- <property name="text">
- <string>Merge stderr and stdout</string>
- </property>
- </widget>
- </item>
- <item row="2" column="0">
+ <item>
<widget class="QCheckBox" name="deployProjectBeforeRunCheckBox">
<property name="text">
<string>Always deploy project before running it</string>
</property>
</widget>
</item>
- <item row="2" column="1">
- <widget class="QCheckBox" name="wrapAppOutputCheckBox">
- <property name="text">
- <string>Word-wrap application output</string>
- </property>
- </widget>
- </item>
- <item row="3" column="1">
+ <item>
<widget class="QCheckBox" name="addLibraryPathsToRunEnvCheckBox">
<property name="text">
<string>Add linker library search paths to run environment</string>
</property>
</widget>
</item>
- <item row="3" column="0">
- <widget class="QCheckBox" name="showCompileOutputCheckBox">
- <property name="text">
- <string>Open Compile Output pane when building</string>
- </property>
- </widget>
- </item>
- <item row="4" column="1">
- <widget class="QWidget" name="widget" native="true">
- <layout class="QHBoxLayout" name="horizontalLayout">
- <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="QLabel" name="limitBuildOutputLabel">
- <property name="text">
- <string>Limit build output to</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QSpinBox" name="maxBuildOutputBox">
- <property name="minimum">
- <number>5000</number>
- </property>
- <property name="maximum">
- <number>100000000</number>
- </property>
- <property name="singleStep">
- <number>5000</number>
- </property>
- <property name="value">
- <number>10000000</number>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QLabel" name="limitBuildOutputLabel_2">
- <property name="text">
- <string>characters</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item row="4" column="0">
- <widget class="QCheckBox" name="showRunOutputCheckBox">
- <property name="text">
- <string>Open Application Output pane on output when running</string>
- </property>
- </widget>
- </item>
- <item row="5" column="1">
+ <item>
<widget class="QWidget" name="widget_1" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_5">
<property name="leftMargin">
@@ -181,47 +111,10 @@
<property name="bottomMargin">
<number>0</number>
</property>
- <item>
- <widget class="QLabel" name="label">
- <property name="text">
- <string>Limit application output to</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QSpinBox" name="maxAppOutputBox">
- <property name="minimum">
- <number>5000</number>
- </property>
- <property name="maximum">
- <number>100000000</number>
- </property>
- <property name="singleStep">
- <number>5000</number>
- </property>
- <property name="value">
- <number>10000000</number>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QLabel" name="label_2">
- <property name="text">
- <string>characters</string>
- </property>
- </widget>
- </item>
</layout>
</widget>
</item>
- <item row="5" column="0">
- <widget class="QCheckBox" name="showDebugOutputCheckBox">
- <property name="text">
- <string>Open Application Output pane on output when debugging</string>
- </property>
- </widget>
- </item>
- <item row="6" column="0">
+ <item>
<widget class="QCheckBox" name="promptToStopRunControlCheckBox">
<property name="toolTip">
<string>Asks before terminating the running application in response to clicking the stop button in Application Output.</string>
@@ -231,7 +124,7 @@
</property>
</widget>
</item>
- <item row="7" column="0">
+ <item>
<widget class="QCheckBox" name="automaticallyCreateRunConfiguration">
<property name="toolTip">
<string>Creates suitable run configurations automatically when setting up a new kit.</string>
@@ -241,55 +134,109 @@
</property>
</widget>
</item>
- <item row="8" column="0" colspan="2">
- <layout class="QHBoxLayout" name="horizontalLayout_4">
- <item>
+ <item>
+ <widget class="QCheckBox" name="clearIssuesCheckBox">
+ <property name="text">
+ <string>Clear issues list on new build</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QFormLayout" name="formLayout">
+ <item row="0" column="0">
<widget class="QLabel" name="labelStopBeforeBuild">
<property name="text">
<string>Stop applications before building:</string>
</property>
</widget>
</item>
- <item>
- <widget class="QComboBox" name="stopBeforeBuildComboBox">
+ <item row="0" column="1">
+ <layout class="QHBoxLayout" name="horizontalLayout">
<item>
- <property name="text">
- <string>None</string>
- </property>
+ <widget class="QComboBox" name="stopBeforeBuildComboBox">
+ <item>
+ <property name="text">
+ <string>None</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Same Project</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>All</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Same Build Directory</string>
+ </property>
+ </item>
+ </widget>
</item>
<item>
- <property name="text">
- <string>Same Project</string>
- </property>
+ <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>
+ </layout>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="terminalModeLabel">
+ <property name="text">
+ <string>Default for &quot;Run in terminal&quot;:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
- <property name="text">
- <string>All</string>
- </property>
+ <widget class="QComboBox" name="terminalModeComboBox">
+ <item>
+ <property name="text">
+ <string>Enabled</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Disabled</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Deduced From Project</string>
+ </property>
+ </item>
+ </widget>
</item>
<item>
- <property name="text">
- <string>Same Build Directory</string>
- </property>
+ <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>
- </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>
+ </layout>
</item>
</layout>
</item>
- <item row="9" column="0" colspan="2">
+ <item>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>0</number>
@@ -322,7 +269,7 @@
</item>
</layout>
</item>
- <item row="10" column="0" colspan="2">
+ <item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="topMargin">
<number>12</number>
@@ -347,17 +294,14 @@
</layout>
</item>
</layout>
+ <zorder>widget_1</zorder>
+ <zorder>automaticallyCreateRunConfiguration</zorder>
<zorder>saveAllFilesCheckBox</zorder>
<zorder>buildProjectBeforeDeployCheckBox</zorder>
<zorder>deployProjectBeforeRunCheckBox</zorder>
- <zorder>showCompileOutputCheckBox</zorder>
- <zorder>cleanOldAppOutputCheckBox</zorder>
- <zorder>mergeStdErrAndStdOutCheckBox</zorder>
- <zorder>wrapAppOutputCheckBox</zorder>
- <zorder>widget</zorder>
<zorder>promptToStopRunControlCheckBox</zorder>
- <zorder>showRunOutputCheckBox</zorder>
- <zorder>showDebugOutputCheckBox</zorder>
+ <zorder>addLibraryPathsToRunEnvCheckBox</zorder>
+ <zorder>clearIssuesCheckBox</zorder>
</widget>
</item>
<item>
diff --git a/src/plugins/projectexplorer/projectfilewizardextension.cpp b/src/plugins/projectexplorer/projectfilewizardextension.cpp
index 5dab7bbf99..33be4cdcfe 100644
--- a/src/plugins/projectexplorer/projectfilewizardextension.cpp
+++ b/src/plugins/projectexplorer/projectfilewizardextension.cpp
@@ -256,7 +256,7 @@ void ProjectFileWizardExtension::applyCodeStyle(GeneratedFile *file) const
Indenter *indenter = nullptr;
if (factory) {
indenter = factory->createIndenter(&doc);
- indenter->setFileName(Utils::FileName::fromString(file->path()));
+ indenter->setFileName(Utils::FilePath::fromString(file->path()));
}
if (!indenter)
indenter = new NormalIndenter(&doc);
diff --git a/src/plugins/projectexplorer/projectimporter.cpp b/src/plugins/projectexplorer/projectimporter.cpp
index 174f6a7472..4d32dba9d6 100644
--- a/src/plugins/projectexplorer/projectimporter.cpp
+++ b/src/plugins/projectexplorer/projectimporter.cpp
@@ -71,9 +71,9 @@ static bool hasOtherUsers(Core::Id id, const QVariant &v, Kit *k)
});
}
-ProjectImporter::ProjectImporter(const Utils::FileName &path) : m_projectPath(path)
+ProjectImporter::ProjectImporter(const Utils::FilePath &path) : m_projectPath(path)
{
- useTemporaryKitInformation(ToolChainKitInformation::id(),
+ useTemporaryKitAspect(ToolChainKitAspect::id(),
[this](Kit *k, const QVariantList &vl) { cleanupTemporaryToolChains(k, vl); },
[this](Kit *k, const QVariantList &vl) { persistTemporaryToolChains(k, vl); });
}
@@ -84,7 +84,7 @@ ProjectImporter::~ProjectImporter()
removeProject(k);
}
-const QList<BuildInfo> ProjectImporter::import(const Utils::FileName &importPath, bool silent)
+const QList<BuildInfo> ProjectImporter::import(const Utils::FilePath &importPath, bool silent)
{
QList<BuildInfo> result;
@@ -97,12 +97,20 @@ const QList<BuildInfo> ProjectImporter::import(const Utils::FileName &importPath
return result;
}
- const Utils::FileName absoluteImportPath = Utils::FileName::fromString(fi.absoluteFilePath());
+ const Utils::FilePath absoluteImportPath = Utils::FilePath::fromString(fi.absoluteFilePath());
+ const auto handleFailure = [this, importPath, silent] {
+ if (silent)
+ return;
+ QMessageBox::critical(Core::ICore::mainWindow(), tr("No Build Found"),
+ tr("No build found in %1 matching project %2.")
+ .arg(importPath.toUserOutput(), projectFilePath().toUserOutput()));
+ };
qCDebug(log) << "Examining directory" << absoluteImportPath.toString();
QList<void *> dataList = examineDirectory(absoluteImportPath);
if (dataList.isEmpty()) {
qCDebug(log) << "Nothing to import found in" << absoluteImportPath.toString();
+ handleFailure();
return result;
}
@@ -141,11 +149,8 @@ const QList<BuildInfo> ProjectImporter::import(const Utils::FileName &importPath
deleteDirectoryData(dd);
dataList.clear();
- if (result.isEmpty() && !silent)
- QMessageBox::critical(Core::ICore::mainWindow(),
- QCoreApplication::translate("ProjectExplorer::ProjectImporter", "No Build Found"),
- QCoreApplication::translate("ProjectExplorer::ProjectImporter", "No build found in %1 matching project %2.")
- .arg(importPath.toUserOutput()).arg(projectFilePath().toUserOutput()));
+ if (result.isEmpty())
+ handleFailure();
return result;
}
@@ -167,7 +172,7 @@ Target *ProjectImporter::preferredTarget(const QList<Target *> &possibleTargets)
return t;
if (pickedFallback)
continue;
- if (DeviceTypeKitInformation::deviceTypeId(t->kit()) == Constants::DESKTOP_DEVICE_TYPE) {
+ if (DeviceTypeKitAspect::deviceTypeId(t->kit()) == Constants::DESKTOP_DEVICE_TYPE) {
activeTarget = t;
pickedFallback = true;
}
@@ -286,27 +291,18 @@ bool ProjectImporter::isTemporaryKit(Kit *k) const
Kit *ProjectImporter::createTemporaryKit(const KitSetupFunction &setup) const
{
- auto k = std::make_unique<Kit>();
- Kit *kptr = k.get();
UpdateGuard guard(*this);
- {
- KitGuard kitGuard(kptr);
- k->setUnexpandedDisplayName(QCoreApplication::translate("ProjectExplorer::ProjectImporter", "Imported Kit"));;
-
- // Set up values:
- foreach (KitInformation *ki, KitManager::kitInformation())
- ki->setup(kptr);
-
- setup(kptr);
-
- foreach (KitInformation *ki, KitManager::kitInformation())
- ki->fix(kptr);
-
- markKitAsTemporary(kptr);
- addProject(kptr);
- } // ~KitGuard, sending kitUpdated
- KitManager::registerKit(std::move(k)); // potentially adds kits to other targetsetuppages
- return kptr;
+ const auto init = [&](Kit *k) {
+ KitGuard kitGuard(k);
+ k->setUnexpandedDisplayName(QCoreApplication::translate("ProjectExplorer::ProjectImporter",
+ "Imported Kit"));
+ k->setup();
+ setup(k);
+ k->fix();
+ markKitAsTemporary(k);
+ addProject(k);
+ }; // ~KitGuard, sending kitUpdated
+ return KitManager::registerKit(init); // potentially adds kits to other targetsetuppages
}
bool ProjectImporter::findTemporaryHandler(Core::Id id) const
@@ -326,7 +322,7 @@ void ProjectImporter::cleanupTemporaryToolChains(Kit *k, const QVariantList &vl)
ToolChain *tc = toolChainFromVariant(v);
QTC_ASSERT(tc, continue);
ToolChainManager::deregisterToolChain(tc);
- ToolChainKitInformation::setToolChain(k, nullptr);
+ ToolChainKitAspect::setToolChain(k, nullptr);
}
}
@@ -335,13 +331,13 @@ void ProjectImporter::persistTemporaryToolChains(Kit *k, const QVariantList &vl)
for (const QVariant &v : vl) {
ToolChain *tmpTc = toolChainFromVariant(v);
QTC_ASSERT(tmpTc, continue);
- ToolChain *actualTc = ToolChainKitInformation::toolChain(k, tmpTc->language());
+ ToolChain *actualTc = ToolChainKitAspect::toolChain(k, tmpTc->language());
if (tmpTc && actualTc != tmpTc)
ToolChainManager::deregisterToolChain(tmpTc);
}
}
-void ProjectImporter::useTemporaryKitInformation(Core::Id id,
+void ProjectImporter::useTemporaryKitAspect(Core::Id id,
ProjectImporter::CleanupFunction cleanup,
ProjectImporter::PersistFunction persist)
{
@@ -371,7 +367,7 @@ bool ProjectImporter::hasKitWithTemporaryData(Core::Id id, const QVariant &data)
}
static ProjectImporter::ToolChainData
-createToolChains(const Utils::FileName &toolChainPath, const Core::Id &language)
+createToolChains(const Utils::FilePath &toolChainPath, const Core::Id &language)
{
ProjectImporter::ToolChainData data;
@@ -391,7 +387,7 @@ createToolChains(const Utils::FileName &toolChainPath, const Core::Id &language)
}
ProjectImporter::ToolChainData
-ProjectImporter::findOrCreateToolChains(const Utils::FileName &toolChainPath,
+ProjectImporter::findOrCreateToolChains(const Utils::FilePath &toolChainPath,
const Core::Id &language) const
{
ToolChainData result;
@@ -400,7 +396,7 @@ ProjectImporter::findOrCreateToolChains(const Utils::FileName &toolChainPath,
});
for (const ToolChain *tc : result.tcs) {
const QByteArray tcId = tc->id();
- result.areTemporary = result.areTemporary ? true : hasKitWithTemporaryData(ToolChainKitInformation::id(), tcId);
+ result.areTemporary = result.areTemporary ? true : hasKitWithTemporaryData(ToolChainKitAspect::id(), tcId);
}
if (!result.tcs.isEmpty())
return result;
diff --git a/src/plugins/projectexplorer/projectimporter.h b/src/plugins/projectexplorer/projectimporter.h
index c7df542a7a..f1cf482607 100644
--- a/src/plugins/projectexplorer/projectimporter.h
+++ b/src/plugins/projectexplorer/projectimporter.h
@@ -44,19 +44,20 @@ class ToolChain;
// Documentation inside.
class PROJECTEXPLORER_EXPORT ProjectImporter : public QObject
{
+ Q_OBJECT
public:
struct ToolChainData {
QList<ToolChain *> tcs;
bool areTemporary = false;
};
- ProjectImporter(const Utils::FileName &path);
+ ProjectImporter(const Utils::FilePath &path);
~ProjectImporter() override;
- const Utils::FileName projectFilePath() const { return m_projectPath; }
- const Utils::FileName projectDirectory() const { return m_projectPath.parentDir(); }
+ const Utils::FilePath projectFilePath() const { return m_projectPath; }
+ const Utils::FilePath projectDirectory() const { return m_projectPath.parentDir(); }
- virtual const QList<BuildInfo> import(const Utils::FileName &importPath, bool silent = false);
+ virtual const QList<BuildInfo> import(const Utils::FilePath &importPath, bool silent = false);
virtual QStringList importCandidates() = 0;
virtual Target *preferredTarget(const QList<Target *> &possibleTargets);
@@ -87,7 +88,7 @@ protected:
};
// importPath is an existing directory at this point!
- virtual QList<void *> examineDirectory(const Utils::FileName &importPath) const = 0;
+ virtual QList<void *> examineDirectory(const Utils::FilePath &importPath) const = 0;
// will get one of the results from examineDirectory
virtual bool matchKit(void *directoryData, const Kit *k) const = 0;
// will get one of the results from examineDirectory
@@ -103,13 +104,13 @@ protected:
// Handle temporary additions to Kits (Qt Versions, ToolChains, etc.)
using CleanupFunction = std::function<void(Kit *, const QVariantList &)>;
using PersistFunction = std::function<void(Kit *, const QVariantList &)>;
- void useTemporaryKitInformation(Core::Id id,
+ void useTemporaryKitAspect(Core::Id id,
CleanupFunction cleanup, PersistFunction persist);
void addTemporaryData(Core::Id id, const QVariant &cleanupData, Kit *k) const;
// Does *any* kit feature the requested data yet?
bool hasKitWithTemporaryData(Core::Id id, const QVariant &data) const;
- ToolChainData findOrCreateToolChains(const Utils::FileName &toolChainPath, const Core::Id &language) const;
+ ToolChainData findOrCreateToolChains(const Utils::FilePath &toolChainPath, const Core::Id &language) const;
private:
void markKitAsTemporary(Kit *k) const;
@@ -118,7 +119,7 @@ private:
void cleanupTemporaryToolChains(ProjectExplorer::Kit *k, const QVariantList &vl);
void persistTemporaryToolChains(ProjectExplorer::Kit *k, const QVariantList &vl);
- const Utils::FileName m_projectPath;
+ const Utils::FilePath m_projectPath;
mutable bool m_isUpdating = false;
class TemporaryInformationHandler {
diff --git a/src/plugins/projectexplorer/projectmanager.h b/src/plugins/projectexplorer/projectmanager.h
index e504b1968e..c0f91cebc7 100644
--- a/src/plugins/projectexplorer/projectmanager.h
+++ b/src/plugins/projectexplorer/projectmanager.h
@@ -32,7 +32,7 @@
#include <functional>
namespace Utils {
-class FileName;
+class FilePath;
class MimeType;
} // Utils
@@ -44,19 +44,19 @@ class PROJECTEXPLORER_EXPORT ProjectManager
{
public:
static bool canOpenProjectForMimeType(const Utils::MimeType &mt);
- static Project *openProject(const Utils::MimeType &mt, const Utils::FileName &fileName);
+ static Project *openProject(const Utils::MimeType &mt, const Utils::FilePath &fileName);
template <typename T>
static void registerProjectType(const QString &mimeType)
{
- ProjectManager::registerProjectCreator(mimeType, [](const Utils::FileName &fileName) {
+ ProjectManager::registerProjectCreator(mimeType, [](const Utils::FilePath &fileName) {
return new T(fileName);
});
}
private:
static void registerProjectCreator(const QString &mimeType,
- const std::function<Project *(const Utils::FileName &)> &);
+ const std::function<Project *(const Utils::FilePath &)> &);
};
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/projectmodels.cpp b/src/plugins/projectexplorer/projectmodels.cpp
index d69d9aad6a..c3df0688ae 100644
--- a/src/plugins/projectexplorer/projectmodels.cpp
+++ b/src/plugins/projectexplorer/projectmodels.cpp
@@ -32,17 +32,31 @@
#include "session.h"
#include "target.h"
+#include <coreplugin/documentmanager.h>
#include <coreplugin/fileiconprovider.h>
+#include <coreplugin/icore.h>
+#include <coreplugin/iversioncontrol.h>
+#include <coreplugin/vcsmanager.h>
#include <utils/utilsicons.h>
#include <utils/algorithm.h>
#include <utils/dropsupport.h>
+#include <utils/pathchooser.h>
#include <utils/stringutils.h>
#include <utils/theme/theme.h>
+#include <QButtonGroup>
+#include <QDialog>
+#include <QDialogButtonBox>
#include <QFileInfo>
#include <QFont>
+#include <QHBoxLayout>
+#include <QLabel>
+#include <QMessageBox>
#include <QMimeData>
#include <QLoggingCategory>
+#include <QPushButton>
+#include <QRadioButton>
+#include <QVBoxLayout>
#include <functional>
@@ -188,6 +202,8 @@ Qt::ItemFlags FlatModel::flags(const QModelIndex &index) const
// either folder or file node
if (node->supportsAction(Rename, node))
f = f | Qt::ItemIsEditable;
+ } else if (node->supportsAction(ProjectAction::AddExistingFile, node)) {
+ f |= Qt::ItemIsDropEnabled;
}
}
return f;
@@ -203,8 +219,8 @@ bool FlatModel::setData(const QModelIndex &index, const QVariant &value, int rol
Node *node = nodeForIndex(index);
QTC_ASSERT(node, return false);
- Utils::FileName orgFilePath = node->filePath();
- Utils::FileName newFilePath = orgFilePath.parentDir().appendPath(value.toString());
+ const Utils::FilePath orgFilePath = node->filePath();
+ const Utils::FilePath newFilePath = orgFilePath.parentDir().pathAppended(value.toString());
ProjectExplorerPlugin::renameFile(node, newFilePath.toString());
emit renamed(orgFilePath, newFilePath);
@@ -245,7 +261,7 @@ void FlatModel::addOrRebuildProjectModel(Project *project)
if (container->childCount() == 0) {
auto projectFileNode = std::make_unique<FileNode>(project->projectFilePath(),
- FileType::Project, false);
+ FileType::Project);
seen.insert(projectFileNode.get());
container->appendChild(new WrapperNode(projectFileNode.get()));
project->containerNode()->addNestedNode(std::move(projectFileNode));
@@ -409,7 +425,7 @@ QStringList FlatModel::mimeTypes() const
QMimeData *FlatModel::mimeData(const QModelIndexList &indexes) const
{
- auto data = new Utils::DropMimeData;
+ auto data = new DropMimeData;
foreach (const QModelIndex &index, indexes) {
if (Node *node = nodeForIndex(index)) {
if (node->asFileNode())
@@ -420,6 +436,303 @@ QMimeData *FlatModel::mimeData(const QModelIndexList &indexes) const
return data;
}
+bool FlatModel::canDropMimeData(const QMimeData *data, Qt::DropAction, int, int,
+ const QModelIndex &) const
+{
+ // For now, we support only drops of Qt Creator file nodes.
+ const auto * const dropData = dynamic_cast<const DropMimeData *>(data);
+ if (!dropData)
+ return false;
+ QTC_ASSERT(!dropData->values().empty(), return false);
+ return dropData->files().size() == dropData->values().size();
+}
+
+enum class DropAction { Copy, CopyWithFiles, Move, MoveWithFiles };
+
+class DropFileDialog : public QDialog
+{
+ Q_DECLARE_TR_FUNCTIONS(ProjectExplorer::Internal::FlatModel)
+public:
+ DropFileDialog(const FilePath &defaultTargetDir)
+ : m_buttonBox(new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel)),
+ m_buttonGroup(new QButtonGroup(this))
+ {
+ setWindowTitle(tr("Choose Drop Action"));
+ const bool offerFileIo = !defaultTargetDir.isEmpty();
+ auto * const layout = new QVBoxLayout(this);
+ layout->addWidget(new QLabel(tr("You just dragged some files from one project node to "
+ "another.\nWhat should Qt Creator do now?"), this));
+ auto * const copyButton = new QRadioButton(this);
+ m_buttonGroup->addButton(copyButton, int(DropAction::Copy));
+ layout->addWidget(copyButton);
+ auto * const moveButton = new QRadioButton(this);
+ m_buttonGroup->addButton(moveButton, int(DropAction::Move));
+ layout->addWidget(moveButton);
+ if (offerFileIo) {
+ copyButton->setText(tr("Copy Only File References"));
+ moveButton->setText(tr("Move Only File References"));
+ auto * const copyWithFilesButton
+ = new QRadioButton(tr("Copy file references and files"), this);
+ m_buttonGroup->addButton(copyWithFilesButton, int(DropAction::CopyWithFiles));
+ layout->addWidget(copyWithFilesButton);
+ auto * const moveWithFilesButton
+ = new QRadioButton(tr("Move file references and files"), this);
+ m_buttonGroup->addButton(moveWithFilesButton, int(DropAction::MoveWithFiles));
+ layout->addWidget(moveWithFilesButton);
+ moveWithFilesButton->setChecked(true);
+ auto * const targetDirLayout = new QHBoxLayout;
+ layout->addLayout(targetDirLayout);
+ targetDirLayout->addWidget(new QLabel(tr("Target directory:"), this));
+ m_targetDirChooser = new PathChooser(this);
+ m_targetDirChooser->setExpectedKind(PathChooser::ExistingDirectory);
+ m_targetDirChooser->setFileName(defaultTargetDir);
+ connect(m_targetDirChooser, &PathChooser::validChanged, this, [this](bool valid) {
+ m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(valid);
+ });
+ targetDirLayout->addWidget(m_targetDirChooser);
+ connect(m_buttonGroup, QOverload<int>::of(&QButtonGroup::buttonClicked), this, [this] {
+ switch (dropAction()) {
+ case DropAction::CopyWithFiles:
+ case DropAction::MoveWithFiles:
+ m_targetDirChooser->setEnabled(true);
+ m_buttonBox->button(QDialogButtonBox::Ok)
+ ->setEnabled(m_targetDirChooser->isValid());
+ break;
+ case DropAction::Copy:
+ case DropAction::Move:
+ m_targetDirChooser->setEnabled(false);
+ m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
+ break;
+ }
+ });
+ } else {
+ copyButton->setText(tr("Copy File References"));
+ moveButton->setText(tr("Move File References"));
+ moveButton->setChecked(true);
+ }
+ connect(m_buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
+ connect(m_buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
+ layout->addWidget(m_buttonBox);
+ }
+
+ DropAction dropAction() const { return static_cast<DropAction>(m_buttonGroup->checkedId()); }
+ FilePath targetDir() const
+ {
+ return m_targetDirChooser ? m_targetDirChooser->fileName() : FilePath();
+ }
+
+private:
+ PathChooser *m_targetDirChooser = nullptr;
+ QDialogButtonBox * const m_buttonBox;
+ QButtonGroup * const m_buttonGroup;
+};
+
+
+bool FlatModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column,
+ const QModelIndex &parent)
+{
+ Q_UNUSED(action);
+
+ const auto * const dropData = dynamic_cast<const DropMimeData *>(data);
+ QTC_ASSERT(dropData, return false);
+
+ auto fileNodes = transform<QList<const Node *>>(dropData->values(),
+ [](const QVariant &v) { return v.value<Node *>(); });
+ QTC_ASSERT(!fileNodes.empty(), return true);
+
+ // The drag operation does not block event handling, so it's possible that the project
+ // was reparsed and the nodes in the drop data are now invalid. If that happens for any node,
+ // we chicken out and abort the entire operation.
+ // Note: In theory, it might be possible that the memory was reused in such an unlucky
+ // way that the pointers refer to different project nodes now, but...
+ if (!allOf(fileNodes, [](const Node *n) { return ProjectTree::hasNode(n); }))
+ return true;
+
+ // We handle only proper file nodes, i.e. no project or folder nodes and no "pseudo"
+ // file nodes that represent the project file.
+ fileNodes = filtered(fileNodes, [](const Node *n) {
+ return n->asFileNode() && n->asFileNode()->fileType() != FileType::Project;
+ });
+ if (fileNodes.empty())
+ return true;
+
+ // We can handle more than one file being dropped, as long as they have the same parent node.
+ ProjectNode * const sourceProjectNode = fileNodes.first()->parentProjectNode();
+ QTC_ASSERT(sourceProjectNode, return true);
+ if (anyOf(fileNodes, [sourceProjectNode](const Node *n) {
+ return n->parentProjectNode() != sourceProjectNode; })) {
+ return true;
+ }
+ Node *targetNode = nodeForIndex(index(row, column, parent));
+ if (!targetNode)
+ targetNode = nodeForIndex(parent);
+ QTC_ASSERT(targetNode, return true);
+ ProjectNode *targetProjectNode = targetNode->asProjectNode();
+ if (!targetProjectNode)
+ targetProjectNode = targetNode->parentProjectNode();
+ QTC_ASSERT(targetProjectNode, return true);
+ if (sourceProjectNode == targetProjectNode)
+ return true;
+
+ // Node weirdness: Sometimes the "file path" is a directory, sometimes it's a file...
+ const auto dirForProjectNode = [](const ProjectNode *pNode) {
+ const FilePath dir = pNode->filePath();
+ if (dir.toFileInfo().isDir())
+ return dir;
+ return FilePath::fromString(dir.toFileInfo().path());
+ };
+ FilePath targetDir = dirForProjectNode(targetProjectNode);
+
+ // Ask the user what to do now: Copy or add? With or without file transfer?
+ DropFileDialog dlg(targetDir == dirForProjectNode(sourceProjectNode) ? FilePath() : targetDir);
+ if (dlg.exec() != QDialog::Accepted)
+ return true;
+ if (!dlg.targetDir().isEmpty())
+ targetDir = dlg.targetDir();
+
+ // Check the nodes again.
+ if (!allOf(fileNodes, [](const Node *n) { return ProjectTree::hasNode(n); }))
+ return true;
+
+ // Some helper functions for the file operations.
+ const auto targetFilePath = [&targetDir](const QString &sourceFilePath) {
+ return targetDir.pathAppended(QFileInfo(sourceFilePath).fileName()).toString();
+ };
+
+ struct VcsInfo {
+ Core::IVersionControl *vcs = nullptr;
+ QString repoDir;
+ bool operator==(const VcsInfo &other) const {
+ return vcs == other.vcs && repoDir == other.repoDir;
+ }
+ };
+ QHash<QString, VcsInfo> vcsHash;
+ const auto vcsInfoForFile = [&vcsHash](const QString &filePath) {
+ const QString dir = QFileInfo(filePath).path();
+ const auto it = vcsHash.constFind(dir);
+ if (it != vcsHash.constEnd())
+ return it.value();
+ VcsInfo vcsInfo;
+ vcsInfo.vcs = Core::VcsManager::findVersionControlForDirectory(dir, &vcsInfo.repoDir);
+ vcsHash.insert(dir, vcsInfo);
+ return vcsInfo;
+ };
+
+ // Now do the actual work.
+ const QStringList sourceFiles = transform(fileNodes, [](const Node *n) {
+ return n->filePath().toString();
+ });
+ QStringList failedRemoveFromProject;
+ QStringList failedAddToProject;
+ QStringList failedCopyOrMove;
+ QStringList failedDelete;
+ QStringList failedVcsOp;
+ switch (dlg.dropAction()) {
+ case DropAction::CopyWithFiles: {
+ QStringList filesToAdd;
+ Core::IVersionControl * const vcs = Core::VcsManager::findVersionControlForDirectory(
+ targetDir.toString());
+ const bool addToVcs = vcs && vcs->supportsOperation(Core::IVersionControl::AddOperation);
+ for (const QString &sourceFile : sourceFiles) {
+ const QString targetFile = targetFilePath(sourceFile);
+ if (QFile::copy(sourceFile, targetFile)) {
+ filesToAdd << targetFile;
+ if (addToVcs && !vcs->vcsAdd(targetFile))
+ failedVcsOp << targetFile;
+ } else {
+ failedCopyOrMove << sourceFile;
+ }
+ }
+ targetProjectNode->addFiles(filesToAdd, &failedAddToProject);
+ break;
+ }
+ case DropAction::Copy:
+ targetProjectNode->addFiles(sourceFiles, &failedAddToProject);
+ break;
+ case DropAction::MoveWithFiles: {
+ QStringList filesToAdd;
+ QStringList filesToRemove;
+ const VcsInfo targetVcs = vcsInfoForFile(targetDir.toString());
+ const bool vcsAddPossible = targetVcs.vcs
+ && targetVcs.vcs->supportsOperation(Core::IVersionControl::AddOperation);
+ for (const QString &sourceFile : sourceFiles) {
+ const QString targetFile = targetFilePath(sourceFile);
+ const VcsInfo sourceVcs = vcsInfoForFile(sourceFile);
+ if (sourceVcs.vcs && targetVcs.vcs && sourceVcs == targetVcs
+ && sourceVcs.vcs->supportsOperation(Core::IVersionControl::MoveOperation)) {
+ if (sourceVcs.vcs->vcsMove(sourceFile, targetFile)) {
+ filesToAdd << targetFile;
+ filesToRemove << sourceFile;
+ } else {
+ failedCopyOrMove << sourceFile;
+ }
+ continue;
+ }
+ if (!QFile::copy(sourceFile, targetFile)) {
+ failedCopyOrMove << sourceFile;
+ continue;
+ }
+ filesToAdd << targetFile;
+ filesToRemove << sourceFile;
+ Core::FileChangeBlocker changeGuard(sourceFile);
+ if (sourceVcs.vcs && sourceVcs.vcs->supportsOperation(
+ Core::IVersionControl::DeleteOperation)
+ && !sourceVcs.vcs->vcsDelete(sourceFile)) {
+ failedVcsOp << sourceFile;
+ }
+ if (QFile::exists(sourceFile) && !QFile::remove(sourceFile))
+ failedDelete << sourceFile;
+ if (vcsAddPossible && !targetVcs.vcs->vcsAdd(targetFile))
+ failedVcsOp << targetFile;
+ }
+ sourceProjectNode->removeFiles(filesToRemove, &failedRemoveFromProject);
+ targetProjectNode->addFiles(filesToAdd, &failedAddToProject);
+ break;
+ }
+ case DropAction::Move:
+ sourceProjectNode->removeFiles(sourceFiles, &failedRemoveFromProject);
+ targetProjectNode->addFiles(sourceFiles, &failedAddToProject);
+ break;
+ }
+
+ // Summary for the user in case anything went wrong.
+ const auto makeUserFileList = [](const QStringList &files) {
+ return transform(files, [](const QString &f) { return QDir::toNativeSeparators(f); })
+ .join("\n ");
+ };
+ if (!failedAddToProject.empty() || !failedRemoveFromProject.empty()
+ || !failedCopyOrMove.empty() || !failedDelete.empty() || !failedVcsOp.empty()) {
+ QString message = tr("Not all operations finished successfully.");
+ if (!failedCopyOrMove.empty()) {
+ message.append('\n').append(tr("The following files could not be copied or moved:"))
+ .append("\n ").append(makeUserFileList(failedCopyOrMove));
+ }
+ if (!failedRemoveFromProject.empty()) {
+ message.append('\n').append(tr("The following files could not be removed from the "
+ "project file:"))
+ .append("\n ").append(makeUserFileList(failedRemoveFromProject));
+ }
+ if (!failedAddToProject.empty()) {
+ message.append('\n').append(tr("The following files could not be added to the "
+ "project file:"))
+ .append("\n ").append(makeUserFileList(failedAddToProject));
+ }
+ if (!failedDelete.empty()) {
+ message.append('\n').append(tr("The following files could not be deleted:"))
+ .append("\n ").append(makeUserFileList(failedDelete));
+ }
+ if (!failedVcsOp.empty()) {
+ message.append('\n').append(tr("A version control operation failed for the following "
+ "files. Please check your repository."))
+ .append("\n ").append(makeUserFileList(failedVcsOp));
+ }
+ QMessageBox::warning(Core::ICore::mainWindow(), tr("Failure Updating Project"),
+ message);
+ }
+
+ return true;
+}
+
WrapperNode *FlatModel::wrapperForNode(const Node *node) const
{
return findNonRootItem([node](WrapperNode *item) {
diff --git a/src/plugins/projectexplorer/projectmodels.h b/src/plugins/projectexplorer/projectmodels.h
index e406360f34..78753bf1da 100644
--- a/src/plugins/projectexplorer/projectmodels.h
+++ b/src/plugins/projectexplorer/projectmodels.h
@@ -67,6 +67,10 @@ public:
Qt::DropActions supportedDragActions() const override;
QStringList mimeTypes() const override;
QMimeData *mimeData(const QModelIndexList &indexes) const override;
+ bool canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column,
+ const QModelIndex &parent) const override;
+ bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column,
+ const QModelIndex &parent) override;
Node *nodeForIndex(const QModelIndex &index) const;
WrapperNode *wrapperForNode(const Node *node) const;
@@ -83,7 +87,7 @@ public:
void onCollapsed(const QModelIndex &idx);
signals:
- void renamed(const Utils::FileName &oldName, const Utils::FileName &newName);
+ void renamed(const Utils::FilePath &oldName, const Utils::FilePath &newName);
void requestExpansion(const QModelIndex &index);
private:
diff --git a/src/plugins/projectexplorer/projectnodes.cpp b/src/plugins/projectexplorer/projectnodes.cpp
index 286899b1b7..e6825e98be 100644
--- a/src/plugins/projectexplorer/projectnodes.cpp
+++ b/src/plugins/projectexplorer/projectnodes.cpp
@@ -52,7 +52,7 @@
namespace ProjectExplorer {
-static FolderNode *folderNode(const FolderNode *folder, const Utils::FileName &directory)
+static FolderNode *folderNode(const FolderNode *folder, const Utils::FilePath &directory)
{
return static_cast<FolderNode *>(Utils::findOrDefault(folder->folderNodes(),
[&directory](const FolderNode *fn) {
@@ -61,13 +61,13 @@ static FolderNode *folderNode(const FolderNode *folder, const Utils::FileName &d
}
static FolderNode *recursiveFindOrCreateFolderNode(FolderNode *folder,
- const Utils::FileName &directory,
- const Utils::FileName &overrideBaseDir,
+ const Utils::FilePath &directory,
+ const Utils::FilePath &overrideBaseDir,
const FolderNode::FolderNodeFactory &factory)
{
- Utils::FileName path = overrideBaseDir.isEmpty() ? folder->filePath() : overrideBaseDir;
+ Utils::FilePath path = overrideBaseDir.isEmpty() ? folder->filePath() : overrideBaseDir;
- Utils::FileName directoryWithoutPrefix;
+ Utils::FilePath directoryWithoutPrefix;
bool isRelative = false;
if (path.isEmpty() || path.toFileInfo().isRoot()) {
@@ -89,7 +89,7 @@ static FolderNode *recursiveFindOrCreateFolderNode(FolderNode *folder,
ProjectExplorer::FolderNode *parent = folder;
foreach (const QString &part, parts) {
- path.appendPath(part);
+ path = path.pathAppended(part);
// Find folder in subFolders
FolderNode *next = folderNode(parent, path);
if (!next) {
@@ -119,15 +119,23 @@ static FolderNode *recursiveFindOrCreateFolderNode(FolderNode *folder,
\sa ProjectExplorer::NodesWatcher
*/
-Node::Node(NodeType nodeType, const Utils::FileName &filePath, int line, const QByteArray &id) :
- m_filePath(filePath), m_nodeId(id), m_line(line), m_nodeType(nodeType)
-{ }
+Node::Node() = default;
void Node::setPriority(int p)
{
m_priority = p;
}
+void Node::setFilePath(const Utils::FilePath &filePath)
+{
+ m_filePath = filePath;
+}
+
+void Node::setLine(int line)
+{
+ m_line = line;
+}
+
void Node::setListInProject(bool l)
{
if (l)
@@ -144,7 +152,7 @@ void Node::setIsGenerated(bool g)
m_flags = static_cast<NodeFlag>(m_flags & ~FlagIsGenerated);
}
-void Node::setAbsoluteFilePathAndLine(const Utils::FileName &path, int line)
+void Node::setAbsoluteFilePathAndLine(const Utils::FilePath &path, int line)
{
if (m_filePath == path && m_line == line)
return;
@@ -155,11 +163,6 @@ void Node::setAbsoluteFilePathAndLine(const Utils::FileName &path, int line)
Node::~Node() = default;
-NodeType Node::nodeType() const
-{
- return m_nodeType;
-}
-
int Node::priority() const
{
return m_priority;
@@ -212,7 +215,7 @@ const ProjectNode *Node::managingProject() const
/*!
The path of the file or folder in the filesystem the node represents.
*/
-const Utils::FileName &Node::filePath() const
+const Utils::FilePath &Node::filePath() const
{
return m_filePath;
}
@@ -222,11 +225,6 @@ int Node::line() const
return m_line;
}
-QByteArray Node::id() const
-{
- return m_nodeId;
-}
-
QString Node::displayName() const
{
return filePath().fileName();
@@ -299,7 +297,7 @@ FileType Node::fileTypeForMimeType(const Utils::MimeType &mt)
return type;
}
-FileType Node::fileTypeForFileName(const Utils::FileName &file)
+FileType Node::fileTypeForFileName(const Utils::FilePath &file)
{
return fileTypeForMimeType(Utils::mimeTypeForFile(file.toString(),
Utils::MimeMatchMode::MatchExtension));
@@ -315,13 +313,11 @@ FileType Node::fileTypeForFileName(const Utils::FileName &file)
\sa ProjectExplorer::FolderNode, ProjectExplorer::ProjectNode
*/
-FileNode::FileNode(const Utils::FileName &filePath, const FileType fileType, bool generated,
- int line, const QByteArray &id) :
- Node(NodeType::File, filePath, line, id),
+FileNode::FileNode(const Utils::FilePath &filePath, const FileType fileType) :
m_fileType(fileType)
{
+ setFilePath(filePath);
setListInProject(true);
- setIsGenerated(generated);
if (fileType == FileType::Project)
setPriority(DefaultProjectFilePriority);
else
@@ -330,7 +326,9 @@ FileNode::FileNode(const Utils::FileName &filePath, const FileType fileType, boo
FileNode *FileNode::clone() const
{
- auto fn = new FileNode(filePath(), fileType(), isGenerated(), line(), id());
+ auto fn = new FileNode(filePath(), fileType());
+ fn->setLine(line());
+ fn->setIsGenerated(isGenerated());
fn->setEnabled(isEnabled());
fn->setPriority(priority());
fn->setListInProject(listInProject());
@@ -342,8 +340,8 @@ FileType FileNode::fileType() const
return m_fileType;
}
-static QList<FileNode *> scanForFilesRecursively(const Utils::FileName &directory,
- const std::function<FileNode *(const Utils::FileName &)> factory,
+static QList<FileNode *> scanForFilesRecursively(const Utils::FilePath &directory,
+ const std::function<FileNode *(const Utils::FilePath &)> factory,
QSet<QString> &visited, QFutureInterface<QList<FileNode*>> *future,
double progressStart, double progressRange,
const QList<Core::IVersionControl*> &versionControls)
@@ -358,7 +356,7 @@ static QList<FileNode *> scanForFilesRecursively(const Utils::FileName &director
if (visitedCount == visited.count())
return result;
- const QList<QFileInfo> entries = baseDir.entryInfoList(QStringList(), QDir::AllEntries|QDir::NoDotAndDotDot);
+ const QFileInfoList entries = baseDir.entryInfoList(QStringList(), QDir::AllEntries|QDir::NoDotAndDotDot);
double progress = 0;
const double progressIncrement = progressRange / static_cast<double>(entries.count());
int lastIntProgress = 0;
@@ -366,7 +364,7 @@ static QList<FileNode *> scanForFilesRecursively(const Utils::FileName &director
if (future && future->isCanceled())
return result;
- const Utils::FileName entryName = Utils::FileName::fromString(entry.absoluteFilePath());
+ const Utils::FilePath entryName = Utils::FilePath::fromString(entry.absoluteFilePath());
if (!Utils::contains(versionControls, [&entryName](const Core::IVersionControl *vc) {
return vc->isVcsFileOrDirectory(entryName);
})) {
@@ -390,8 +388,8 @@ static QList<FileNode *> scanForFilesRecursively(const Utils::FileName &director
}
QList<FileNode *>
-FileNode::scanForFiles(const Utils::FileName &directory,
- const std::function<FileNode *(const Utils::FileName &)> factory,
+FileNode::scanForFiles(const Utils::FilePath &directory,
+ const std::function<FileNode *(const Utils::FilePath &)> factory,
QFutureInterface<QList<FileNode *>> *future)
{
QSet<QString> visited;
@@ -409,6 +407,14 @@ bool FileNode::supportsAction(ProjectAction action, const Node *node) const
return parentFolder && parentFolder->supportsAction(action, node);
}
+QString FileNode::displayName() const
+{
+ int l = line();
+ if (l < 0)
+ return Node::displayName();
+ return Node::displayName() + ':' + QString::number(l);
+}
+
/*!
\class ProjectExplorer::FolderNode
@@ -416,16 +422,13 @@ bool FileNode::supportsAction(ProjectAction action, const Node *node) const
\sa ProjectExplorer::FileNode, ProjectExplorer::ProjectNode
*/
-FolderNode::FolderNode(const Utils::FileName &folderPath, NodeType nodeType,
- const QString &displayName, const QByteArray &id) :
- Node(nodeType, folderPath, -1, id),
- m_displayName(displayName)
+FolderNode::FolderNode(const Utils::FilePath &folderPath)
{
+ setFilePath(folderPath);
setPriority(DefaultFolderPriority);
setListInProject(false);
setIsGenerated(false);
- if (m_displayName.isEmpty())
- m_displayName = folderPath.toUserOutput();
+ m_displayName = folderPath.toUserOutput();
}
/*!
@@ -556,7 +559,7 @@ QList<FileNode*> FolderNode::fileNodes() const
return result;
}
-FileNode *FolderNode::fileNode(const Utils::FileName &file) const
+FileNode *FolderNode::fileNode(const Utils::FilePath &file) const
{
return static_cast<FileNode *>(Utils::findOrDefault(m_nodes,
[&file](const std::unique_ptr<Node> &n) {
@@ -576,7 +579,7 @@ QList<FolderNode*> FolderNode::folderNodes() const
}
void FolderNode::addNestedNode(std::unique_ptr<FileNode> &&fileNode,
- const Utils::FileName &overrideBaseDir,
+ const Utils::FilePath &overrideBaseDir,
const FolderNodeFactory &factory)
{
FolderNode *folder = recursiveFindOrCreateFolderNode(this, fileNode->filePath().parentDir(),
@@ -585,7 +588,7 @@ void FolderNode::addNestedNode(std::unique_ptr<FileNode> &&fileNode,
}
void FolderNode::addNestedNodes(std::vector<std::unique_ptr<FileNode> > &&files,
- const Utils::FileName &overrideBaseDir,
+ const Utils::FilePath &overrideBaseDir,
const FolderNode::FolderNodeFactory &factory)
{
for (std::unique_ptr<FileNode> &f : files)
@@ -599,8 +602,12 @@ void FolderNode::addNestedNodes(std::vector<std::unique_ptr<FileNode> > &&files,
void FolderNode::compress()
{
if (auto subFolder = m_nodes.size() == 1 ? m_nodes.at(0)->asFolderNode() : nullptr) {
- if (subFolder->nodeType() != nodeType())
+ const bool sameType = (isFolderNodeType() && subFolder->isFolderNodeType())
+ || (isProjectNodeType() && subFolder->isProjectNodeType())
+ || (isVirtualFolderType() && subFolder->isVirtualFolderType());
+ if (!sameType)
return;
+
// Only one subfolder: Compress!
setDisplayName(QDir::toNativeSeparators(displayName() + "/" + subFolder->displayName()));
for (Node *n : subFolder->nodes()) {
@@ -619,16 +626,6 @@ void FolderNode::compress()
}
}
-bool FolderNode::isAncesterOf(Node *n)
-{
- if (n == this)
- return true;
- FolderNode *p = n->parentFolderNode();
- while (p && p != this)
- p = p->parentFolderNode();
- return p == this;
-}
-
bool FolderNode::replaceSubtree(Node *oldNode, std::unique_ptr<Node> &&newNode)
{
std::unique_ptr<Node> keepAlive;
@@ -676,6 +673,9 @@ const QList<FolderNode::LocationInfo> FolderNode::locationInfo() const
QString FolderNode::addFileFilter() const
{
+ if (!m_addFileFilter.isNull())
+ return m_addFileFilter;
+
FolderNode *fn = parentFolderNode();
return fn ? fn->addFileFilter() : QString();
}
@@ -762,7 +762,7 @@ bool FolderNode::showInSimpleTree() const
bool FolderNode::showWhenEmpty() const
{
- return false;
+ return m_showWhenEmpty;
}
/*!
@@ -776,18 +776,9 @@ bool FolderNode::showWhenEmpty() const
\sa ProjectExplorer::FileNode, ProjectExplorer::ProjectNode
*/
-VirtualFolderNode::VirtualFolderNode(const Utils::FileName &folderPath, int priority,
- const QByteArray &id) :
- FolderNode(folderPath, NodeType::VirtualFolder, QString(), id)
+VirtualFolderNode::VirtualFolderNode(const Utils::FilePath &folderPath) :
+ FolderNode(folderPath)
{
- setPriority(priority);
-}
-
-QString VirtualFolderNode::addFileFilter() const
-{
- if (!m_addFileFilter.isNull())
- return m_addFileFilter;
- return FolderNode::addFileFilter();
}
/*!
@@ -803,11 +794,12 @@ QString VirtualFolderNode::addFileFilter() const
/*!
Creates an uninitialized project node object.
*/
-ProjectNode::ProjectNode(const Utils::FileName &projectFilePath, const QByteArray &id) :
- FolderNode(projectFilePath, NodeType::Project, projectFilePath.fileName(), id)
+ProjectNode::ProjectNode(const Utils::FilePath &projectFilePath) :
+ FolderNode(projectFilePath)
{
setPriority(DefaultProjectPriority);
setListInProject(true);
+ setDisplayName(projectFilePath.fileName());
}
bool ProjectNode::canAddSubProject(const QString &proFilePath) const
@@ -822,6 +814,11 @@ bool ProjectNode::addSubProject(const QString &proFilePath)
return false;
}
+QStringList ProjectNode::subProjectFileNamePatterns() const
+{
+ return QStringList();
+}
+
bool ProjectNode::removeSubProject(const QString &proFilePath)
{
Q_UNUSED(proFilePath)
@@ -873,7 +870,7 @@ bool ProjectNode::deploysFolder(const QString &folder) const
return false;
}
-ProjectNode *ProjectNode::projectNode(const Utils::FileName &file) const
+ProjectNode *ProjectNode::projectNode(const Utils::FilePath &file) const
{
for (const std::unique_ptr<Node> &n: m_nodes) {
if (ProjectNode *pnode = n->asProjectNode())
@@ -907,9 +904,15 @@ void FolderNode::handleSubTreeChanged(FolderNode *node)
parent->handleSubTreeChanged(node);
}
+void FolderNode::setShowWhenEmpty(bool showWhenEmpty)
+{
+ m_showWhenEmpty = showWhenEmpty;
+}
+
ContainerNode::ContainerNode(Project *project)
- : FolderNode(project->projectDirectory(), NodeType::Project), m_project(project)
-{}
+ : FolderNode(project->projectDirectory()), m_project(project)
+{
+}
QString ContainerNode::displayName() const
{
diff --git a/src/plugins/projectexplorer/projectnodes.h b/src/plugins/projectexplorer/projectnodes.h
index c96b8f8713..ce36882aa9 100644
--- a/src/plugins/projectexplorer/projectnodes.h
+++ b/src/plugins/projectexplorer/projectnodes.h
@@ -44,13 +44,6 @@ namespace ProjectExplorer {
class Project;
-enum class NodeType : quint16 {
- File = 1,
- Folder,
- VirtualFolder,
- Project
-};
-
// File types common for qt projects
enum class FileType : quint16 {
Unknown = 0,
@@ -68,6 +61,7 @@ enum ProjectAction {
// Special value to indicate that the actions are handled by the parent
InheritedFromParent,
AddSubProject,
+ AddExistingProject,
RemoveSubProject,
// Let's the user select to which project file
// the file is added
@@ -89,7 +83,6 @@ enum ProjectAction {
HidePathActions,
HideFileActions,
HideFolderActions,
- HasSubProjectRunConfigurations
};
class FileNode;
@@ -111,8 +104,11 @@ public:
};
virtual ~Node();
- Node(const Node &other) = delete;
- NodeType nodeType() const;
+
+ virtual bool isFolderNodeType() const { return false; }
+ virtual bool isProjectNodeType() const { return false; }
+ virtual bool isVirtualFolderType() const { return false; }
+
int priority() const;
ProjectNode *parentProjectNode() const; // parent project, will be nullptr for the top-level project
@@ -125,9 +121,8 @@ public:
// or node->parentProjectNode() for all other cases.
const ProjectNode *managingProject() const; // see above.
- const Utils::FileName &filePath() const; // file system path
+ const Utils::FilePath &filePath() const; // file system path
int line() const;
- QByteArray id() const;
virtual QString displayName() const;
virtual QString tooltip() const;
bool isEnabled() const;
@@ -137,7 +132,7 @@ public:
virtual bool supportsAction(ProjectAction action, const Node *node) const;
void setEnabled(bool enabled);
- void setAbsoluteFilePathAndLine(const Utils::FileName &filePath, int line);
+ void setAbsoluteFilePathAndLine(const Utils::FilePath &filePath, int line);
virtual FileNode *asFileNode() { return nullptr; }
virtual const FileNode *asFileNode() const { return nullptr; }
@@ -154,24 +149,26 @@ public:
void setParentFolderNode(FolderNode *parentFolder);
void setListInProject(bool l);
+ void setIsGenerated(bool g);
+ void setPriority(int priority);
+ void setLine(int line);
static FileType fileTypeForMimeType(const Utils::MimeType &mt);
- static FileType fileTypeForFileName(const Utils::FileName &file);
+ static FileType fileTypeForFileName(const Utils::FilePath &file);
protected:
- Node(NodeType nodeType, const Utils::FileName &filePath, int line = -1,
- const QByteArray &id = {});
+ Node();
+ Node(const Node &other) = delete;
+ bool operator=(const Node &other) = delete;
- void setPriority(int priority);
- void setIsGenerated(bool g);
+ void setFilePath(const Utils::FilePath &filePath);
private:
FolderNode *m_parentFolderNode = nullptr;
- Utils::FileName m_filePath;
- QByteArray m_nodeId;
+ Utils::FilePath m_filePath;
int m_line = -1;
int m_priority = DefaultPriority;
- const NodeType m_nodeType;
+
enum NodeFlag : quint16 {
FlagNone = 0,
FlagIsEnabled = 1 << 0,
@@ -184,8 +181,7 @@ private:
class PROJECTEXPLORER_EXPORT FileNode : public Node
{
public:
- FileNode(const Utils::FileName &filePath, const FileType fileType, bool generated, int line = -1,
- const QByteArray &id = {});
+ FileNode(const Utils::FilePath &filePath, const FileType fileType);
FileNode *clone() const;
@@ -195,10 +191,11 @@ public:
const FileNode *asFileNode() const final { return this; }
static QList<FileNode *>
- scanForFiles(const Utils::FileName &directory,
- const std::function<FileNode *(const Utils::FileName &fileName)> factory,
+ scanForFiles(const Utils::FilePath &directory,
+ const std::function<FileNode *(const Utils::FilePath &fileName)> factory,
QFutureInterface<QList<FileNode *>> *future = nullptr);
bool supportsAction(ProjectAction action, const Node *node) const override;
+ QString displayName() const override;
private:
FileType m_fileType;
@@ -208,12 +205,13 @@ private:
class PROJECTEXPLORER_EXPORT FolderNode : public Node
{
public:
- explicit FolderNode(const Utils::FileName &folderPath, NodeType nodeType = NodeType::Folder,
- const QString &displayName = QString(), const QByteArray &id = {});
+ explicit FolderNode(const Utils::FilePath &folderPath);
QString displayName() const override;
QIcon icon() const;
+ bool isFolderNodeType() const override { return true; }
+
Node *findNode(const std::function<bool(Node *)> &filter);
QList<Node *> findNodes(const std::function<bool(Node *)> &filter);
@@ -225,21 +223,19 @@ public:
ProjectNode *findProjectNode(const std::function<bool(const ProjectNode *)> &predicate);
const QList<Node *> nodes() const;
QList<FileNode *> fileNodes() const;
- FileNode *fileNode(const Utils::FileName &file) const;
+ FileNode *fileNode(const Utils::FilePath &file) const;
QList<FolderNode *> folderNodes() const;
- using FolderNodeFactory = std::function<std::unique_ptr<FolderNode>(const Utils::FileName &)>;
+ using FolderNodeFactory = std::function<std::unique_ptr<FolderNode>(const Utils::FilePath &)>;
void addNestedNodes(std::vector<std::unique_ptr<FileNode>> &&files,
- const Utils::FileName &overrideBaseDir = Utils::FileName(),
+ const Utils::FilePath &overrideBaseDir = Utils::FilePath(),
const FolderNodeFactory &factory
- = [](const Utils::FileName &fn) { return std::make_unique<FolderNode>(fn); });
+ = [](const Utils::FilePath &fn) { return std::make_unique<FolderNode>(fn); });
void addNestedNode(std::unique_ptr<FileNode> &&fileNode,
- const Utils::FileName &overrideBaseDir = Utils::FileName(),
+ const Utils::FilePath &overrideBaseDir = Utils::FilePath(),
const FolderNodeFactory &factory
- = [](const Utils::FileName &fn) { return std::make_unique<FolderNode>(fn); });
+ = [](const Utils::FilePath &fn) { return std::make_unique<FolderNode>(fn); });
void compress();
- bool isAncesterOf(Node *n);
-
// takes ownership of newNode.
// Will delete newNode if oldNode is not a child of this node.
bool replaceSubtree(Node *oldNode, std::unique_ptr<Node> &&newNode);
@@ -249,17 +245,18 @@ public:
class LocationInfo {
public:
- LocationInfo(const QString &dn, const Utils::FileName &p, const int l = -1) :
+ LocationInfo(const QString &dn, const Utils::FilePath &p, const int l = -1) :
path(p), line(l), displayName(dn) { }
- Utils::FileName path;
+ Utils::FilePath path;
int line = -1;
QString displayName;
};
void setLocationInfo(const QList<LocationInfo> &info);
const QList<LocationInfo> locationInfo() const;
- virtual QString addFileFilter() const;
+ QString addFileFilter() const;
+ void setAddFileFilter(const QString &filter) { m_addFileFilter = filter; }
bool supportsAction(ProjectAction action, const Node *node) const override;
@@ -284,11 +281,12 @@ public:
// determines if node will be shown in the flat view, by default folder and projects aren't shown
virtual bool showInSimpleTree() const;
+
// determines if node will always be shown when hiding empty directories
- virtual bool showWhenEmpty() const;
+ bool showWhenEmpty() const;
+ void setShowWhenEmpty(bool showWhenEmpty);
void addNode(std::unique_ptr<Node> &&node);
- std::unique_ptr<Node> takeNode(Node *node);
bool isEmpty() const;
@@ -302,34 +300,41 @@ protected:
QList<LocationInfo> m_locations;
private:
+ std::unique_ptr<Node> takeNode(Node *node);
+
QString m_displayName;
+ QString m_addFileFilter;
mutable QIcon m_icon;
+ bool m_showWhenEmpty = false;
};
class PROJECTEXPLORER_EXPORT VirtualFolderNode : public FolderNode
{
public:
- explicit VirtualFolderNode(const Utils::FileName &folderPath, int priority,
- const QByteArray &id = {});
+ explicit VirtualFolderNode(const Utils::FilePath &folderPath);
- void setAddFileFilter(const QString &filter) { m_addFileFilter = filter; }
- QString addFileFilter() const override;
-
-private:
- QString m_addFileFilter;
+ bool isFolderNodeType() const override { return false; }
+ bool isVirtualFolderType() const override { return true; }
};
// Documentation inside.
class PROJECTEXPLORER_EXPORT ProjectNode : public FolderNode
{
public:
+ explicit ProjectNode(const Utils::FilePath &projectFilePath);
+
virtual bool canAddSubProject(const QString &proFilePath) const;
virtual bool addSubProject(const QString &proFile);
+ virtual QStringList subProjectFileNamePatterns() const;
virtual bool removeSubProject(const QString &proFilePath);
- virtual Utils::optional<Utils::FileName> visibleAfterAddFileAction() const {
+ virtual Utils::optional<Utils::FilePath> visibleAfterAddFileAction() const {
return Utils::nullopt;
}
+ bool isFolderNodeType() const override { return false; }
+ bool isProjectNodeType() const override { return true; }
+ bool showInSimpleTree() const override { return true; }
+
bool addFiles(const QStringList &filePaths, QStringList *notAdded = nullptr) override;
bool removeFiles(const QStringList &filePaths, QStringList *notRemoved = nullptr) override;
bool deleteFiles(const QStringList &filePaths) override;
@@ -340,7 +345,7 @@ public:
// by default returns false
virtual bool deploysFolder(const QString &folder) const;
- ProjectNode *projectNode(const Utils::FileName &file) const;
+ ProjectNode *projectNode(const Utils::FilePath &file) const;
ProjectNode *asProjectNode() final { return this; }
const ProjectNode *asProjectNode() const final { return this; }
@@ -352,8 +357,15 @@ public:
virtual QVariant data(Core::Id role) const;
virtual bool setData(Core::Id role, const QVariant &value) const;
+ bool isProduct() const { return m_isProduct; }
+
protected:
- explicit ProjectNode(const Utils::FileName &projectFilePath, const QByteArray &id = {});
+ void setIsProduct() { m_isProduct = true; }
+
+ QString m_target;
+
+private:
+ bool m_isProduct = false;
};
class PROJECTEXPLORER_EXPORT ContainerNode : public FolderNode
@@ -364,6 +376,9 @@ public:
QString displayName() const final;
bool supportsAction(ProjectAction action, const Node *node) const final;
+ bool isFolderNodeType() const override { return false; }
+ bool isProjectNodeType() const override { return true; }
+
ContainerNode *asContainerNode() final { return this; }
const ContainerNode *asContainerNode() const final { return this; }
diff --git a/src/plugins/projectexplorer/projecttree.cpp b/src/plugins/projectexplorer/projecttree.cpp
index 5e853e6a78..5259a0d609 100644
--- a/src/plugins/projectexplorer/projecttree.cpp
+++ b/src/plugins/projectexplorer/projecttree.cpp
@@ -104,16 +104,16 @@ Project *ProjectTree::currentProject()
return s_instance->m_currentProject;
}
-Node *ProjectTree::findCurrentNode()
+Node *ProjectTree::currentNode()
{
s_instance->update();
return s_instance->m_currentNode;
}
-FileName ProjectTree::currentFilePath()
+FilePath ProjectTree::currentFilePath()
{
- Node *currentNode = findCurrentNode();
- return currentNode ? currentNode->filePath() : FileName();
+ Node *node = currentNode();
+ return node ? node->filePath() : FilePath();
}
void ProjectTree::registerWidget(ProjectTreeWidget *widget)
@@ -167,7 +167,7 @@ void ProjectTree::updateFromProjectTreeWidget(ProjectTreeWidget *widget)
void ProjectTree::updateFromDocumentManager()
{
if (Core::IDocument *document = Core::EditorManager::currentDocument()) {
- const FileName fileName = document->filePath();
+ const FilePath fileName = document->filePath();
updateFromNode(ProjectTreeWidget::nodeForFile(fileName));
} else {
updateFromNode(nullptr);
@@ -283,6 +283,12 @@ void ProjectTree::expandAll()
w->expandAll();
}
+void ProjectTree::changeProjectRootDirectory()
+{
+ if (m_currentProject)
+ m_currentProject->changeRootProjectDirectory();
+}
+
void ProjectTree::updateExternalFileWarning()
{
auto document = qobject_cast<Core::IDocument *>(sender());
@@ -296,12 +302,12 @@ void ProjectTree::updateExternalFileWarning()
}
if (!infoBar->canInfoBeAdded(externalFileId))
return;
- const FileName fileName = document->filePath();
+ const FilePath fileName = document->filePath();
const QList<Project *> projects = SessionManager::projects();
if (projects.isEmpty())
return;
for (Project *project : projects) {
- FileName projectDir = project->projectDirectory();
+ FilePath projectDir = project->projectDirectory();
if (projectDir.isEmpty())
continue;
if (fileName.isChildOf(projectDir))
@@ -309,7 +315,7 @@ void ProjectTree::updateExternalFileWarning()
// External file. Test if it under the same VCS
QString topLevel;
if (Core::VcsManager::findVersionControlForDirectory(projectDir.toString(), &topLevel)
- && fileName.isChildOf(FileName::fromString(topLevel))) {
+ && fileName.isChildOf(FilePath::fromString(topLevel))) {
return;
}
}
@@ -333,26 +339,16 @@ void ProjectTree::showContextMenu(ProjectTreeWidget *focus, const QPoint &global
if (!node) {
contextMenu = Core::ActionManager::actionContainer(Constants::M_SESSIONCONTEXT)->menu();
- } else {
- switch (node->nodeType()) {
- case NodeType::Project: {
- if ((node->parentFolderNode() && node->parentFolderNode()->asContainerNode())
- || node->asContainerNode())
- contextMenu = Core::ActionManager::actionContainer(Constants::M_PROJECTCONTEXT)->menu();
- else
- contextMenu = Core::ActionManager::actionContainer(Constants::M_SUBPROJECTCONTEXT)->menu();
- break;
- }
- case NodeType::VirtualFolder:
- case NodeType::Folder:
- contextMenu = Core::ActionManager::actionContainer(Constants::M_FOLDERCONTEXT)->menu();
- break;
- case NodeType::File:
- contextMenu = Core::ActionManager::actionContainer(Constants::M_FILECONTEXT)->menu();
- break;
- default:
- qWarning("ProjectExplorerPlugin::showContextMenu - Missing handler for node type");
- }
+ } else if (node->isProjectNodeType()) {
+ if ((node->parentFolderNode() && node->parentFolderNode()->asContainerNode())
+ || node->asContainerNode())
+ contextMenu = Core::ActionManager::actionContainer(Constants::M_PROJECTCONTEXT)->menu();
+ else
+ contextMenu = Core::ActionManager::actionContainer(Constants::M_SUBPROJECTCONTEXT)->menu();
+ } else if (node->isVirtualFolderType() || node->isFolderNodeType()) {
+ contextMenu = Core::ActionManager::actionContainer(Constants::M_FOLDERCONTEXT)->menu();
+ } else if (node->asFileNode()) {
+ contextMenu = Core::ActionManager::actionContainer(Constants::M_FILECONTEXT)->menu();
}
if (contextMenu && contextMenu->actions().count() > 0) {
@@ -433,7 +429,7 @@ Project *ProjectTree::projectForNode(const Node *node)
});
}
-Node *ProjectTree::nodeForFile(const FileName &fileName)
+Node *ProjectTree::nodeForFile(const FilePath &fileName)
{
Node *node = nullptr;
for (const Project *project : SessionManager::projects()) {
@@ -441,7 +437,7 @@ Node *ProjectTree::nodeForFile(const FileName &fileName)
projectNode->forEachGenericNode([&](Node *n) {
if (n->filePath() == fileName) {
// prefer file nodes
- if (!node || (node->nodeType() != NodeType::File && n->nodeType() == NodeType::File))
+ if (!node || (!node->asFileNode() && n->asFileNode()))
node = n;
}
});
diff --git a/src/plugins/projectexplorer/projecttree.h b/src/plugins/projectexplorer/projecttree.h
index 238c55a910..4adcaa7571 100644
--- a/src/plugins/projectexplorer/projecttree.h
+++ b/src/plugins/projectexplorer/projecttree.h
@@ -31,7 +31,7 @@
#include <functional>
-namespace Utils { class FileName; }
+namespace Utils { class FilePath; }
namespace ProjectExplorer {
class FileNode;
@@ -53,8 +53,8 @@ public:
static ProjectTree *instance();
static Project *currentProject();
- static Node *findCurrentNode();
- static Utils::FileName currentFilePath();
+ static Node *currentNode();
+ static Utils::FilePath currentFilePath();
// Integration with ProjectTreeWidget
static void registerWidget(Internal::ProjectTreeWidget *widget);
@@ -76,11 +76,13 @@ public:
static void forEachNode(const std::function<void(Node *)> &task);
static Project *projectForNode(const Node *node);
- static Node *nodeForFile(const Utils::FileName &fileName);
+ static Node *nodeForFile(const Utils::FilePath &fileName);
void collapseAll();
void expandAll();
+ void changeProjectRootDirectory();
+
// for nodes to emit signals, do not call unless you are a node
static void emitSubtreeChanged(FolderNode *node);
diff --git a/src/plugins/projectexplorer/projecttreewidget.cpp b/src/plugins/projectexplorer/projecttreewidget.cpp
index af4334a21e..5e4b19f8c9 100644
--- a/src/plugins/projectexplorer/projecttreewidget.cpp
+++ b/src/plugins/projectexplorer/projecttreewidget.cpp
@@ -149,7 +149,9 @@ public:
setEditTriggers(QAbstractItemView::EditKeyPressed);
setContextMenuPolicy(Qt::CustomContextMenu);
setDragEnabled(true);
- setDragDropMode(QAbstractItemView::DragOnly);
+ setDragDropMode(QAbstractItemView::DragDrop);
+ viewport()->setAcceptDrops(true);
+ setDropIndicatorShown(true);
m_context = new IContext(this);
m_context->setContext(Context(ProjectExplorer::Constants::C_PROJECT_TREE));
m_context->setWidget(this);
@@ -296,7 +298,7 @@ ProjectTreeWidget::ProjectTreeWidget(QWidget *parent) : QWidget(parent)
connect(m_toggleSync, &QAbstractButton::clicked,
this, &ProjectTreeWidget::toggleAutoSynchronization);
- setCurrentItem(ProjectTree::findCurrentNode());
+ setCurrentItem(ProjectTree::currentNode());
setAutoSynchronization(true);
m_projectTreeWidgets << this;
@@ -348,11 +350,26 @@ void ProjectTreeWidget::rowsInserted(const QModelIndex &parent, int start, int e
}
}
-Node *ProjectTreeWidget::nodeForFile(const FileName &fileName)
+Node *ProjectTreeWidget::nodeForFile(const FilePath &fileName)
{
Node *bestNode = nullptr;
int bestNodeExpandCount = INT_MAX;
+ // FIXME: Check that the values used make sense in the context.
+ auto priority = [](Node *node) {
+ if (node->asFileNode())
+ return 1;
+ if (node->isFolderNodeType())
+ return 2;
+ if (node->isVirtualFolderType())
+ return 3;
+ if (node->isProjectNodeType())
+ return 4;
+ QTC_CHECK(false);
+ return 1;
+ };
+
+ // FIXME: Looks like this could be done with less cycles.
for (Project *project : SessionManager::projects()) {
if (ProjectNode *projectNode = project->rootProjectNode()) {
projectNode->forEachGenericNode([&](Node *node) {
@@ -360,10 +377,10 @@ Node *ProjectTreeWidget::nodeForFile(const FileName &fileName)
if (!bestNode) {
bestNode = node;
bestNodeExpandCount = ProjectTreeWidget::expandedCount(node);
- } else if (node->nodeType() < bestNode->nodeType()) {
+ } else if (priority(node) < priority(bestNode)) {
bestNode = node;
bestNodeExpandCount = ProjectTreeWidget::expandedCount(node);
- } else if (node->nodeType() == bestNode->nodeType()) {
+ } else if (priority(node) == priority(bestNode)) {
int nodeExpandCount = ProjectTreeWidget::expandedCount(node);
if (nodeExpandCount < bestNodeExpandCount) {
bestNode = node;
@@ -440,7 +457,7 @@ void ProjectTreeWidget::editCurrentItem()
editor->setSelection(0, dotIndex);
}
-void ProjectTreeWidget::renamed(const FileName &oldPath, const FileName &newPath)
+void ProjectTreeWidget::renamed(const FilePath &oldPath, const FilePath &newPath)
{
update();
Q_UNUSED(oldPath);
@@ -457,7 +474,7 @@ void ProjectTreeWidget::renamed(const FileName &oldPath, const FileName &newPath
void ProjectTreeWidget::syncFromDocumentManager()
{
// sync from document manager
- FileName fileName;
+ FilePath fileName;
if (IDocument *doc = EditorManager::currentDocument())
fileName = doc->filePath();
if (!currentNode() || currentNode()->filePath() != fileName)
@@ -522,7 +539,7 @@ void ProjectTreeWidget::showContextMenu(const QPoint &pos)
void ProjectTreeWidget::openItem(const QModelIndex &mainIndex)
{
Node *node = m_model->nodeForIndex(mainIndex);
- if (!node || node->nodeType() != NodeType::File)
+ if (!node || !node->asFileNode())
return;
IEditor *editor = EditorManager::openEditor(node->filePath().toString());
if (editor && node->line() >= 0)
diff --git a/src/plugins/projectexplorer/projecttreewidget.h b/src/plugins/projectexplorer/projecttreewidget.h
index 6de41b0adf..c4b729f097 100644
--- a/src/plugins/projectexplorer/projecttreewidget.h
+++ b/src/plugins/projectexplorer/projecttreewidget.h
@@ -62,7 +62,7 @@ public:
void sync(ProjectExplorer::Node *node);
void showMessage(ProjectExplorer::Node *node, const QString &message);
- static Node *nodeForFile(const Utils::FileName &fileName);
+ static Node *nodeForFile(const Utils::FilePath &fileName);
void toggleAutoSynchronization();
void editCurrentItem();
@@ -81,7 +81,7 @@ private:
void setCurrentItem(ProjectExplorer::Node *node);
static int expandedCount(Node *node);
void rowsInserted(const QModelIndex &parent, int start, int end);
- void renamed(const Utils::FileName &oldPath, const Utils::FileName &newPath);
+ void renamed(const Utils::FilePath &oldPath, const Utils::FilePath &newPath);
void syncFromDocumentManager();
@@ -94,7 +94,7 @@ private:
QString m_modelId;
bool m_autoSync = true;
- Utils::FileName m_delayedRename;
+ Utils::FilePath m_delayedRename;
static QList<ProjectTreeWidget *> m_projectTreeWidgets;
friend class ProjectTreeWidgetFactory;
diff --git a/src/plugins/projectexplorer/projectwelcomepage.cpp b/src/plugins/projectexplorer/projectwelcomepage.cpp
index 2cbb9a9b9d..7827034c2a 100644
--- a/src/plugins/projectexplorer/projectwelcomepage.cpp
+++ b/src/plugins/projectexplorer/projectwelcomepage.cpp
@@ -340,7 +340,7 @@ public:
};
for (int i = 0; i < 3; ++i) {
const QString &action = actions.at(i);
- const int ww = fm.width(action);
+ const int ww = fm.horizontalAdvance(action);
const QRect actionRect(xx, yy - 10, ww, 15);
const bool isForcedDisabled = (i != 0 && sessionName == "default");
const bool isActive = actionRect.contains(mousePos) && !isForcedDisabled;
@@ -399,7 +399,7 @@ public:
else if (m_activeActionRects[1].contains(pos))
sessionModel->renameSession(ICore::mainWindow(), sessionName);
else if (m_activeActionRects[2].contains(pos))
- sessionModel->deleteSession(sessionName);
+ sessionModel->deleteSessions(QStringList(sessionName));
return true;
}
}
@@ -475,7 +475,8 @@ public:
QString projectName = idx.data(Qt::DisplayRole).toString();
QString projectPath = idx.data(ProjectModel::FilePathRole).toString();
QFontMetrics fm(sizedFont(13, option.widget));
- int width = std::max(fm.width(projectName), fm.width(projectPath)) + 36;
+ int width = std::max(fm.horizontalAdvance(projectName),
+ fm.horizontalAdvance(projectPath)) + 36;
return QSize(width, 48);
}
diff --git a/src/plugins/projectexplorer/projectwindow.cpp b/src/plugins/projectexplorer/projectwindow.cpp
index 434249bee1..065de1e715 100644
--- a/src/plugins/projectexplorer/projectwindow.cpp
+++ b/src/plugins/projectexplorer/projectwindow.cpp
@@ -376,7 +376,7 @@ public:
m_projectSelection = new QComboBox;
m_projectSelection->setModel(&m_comboBoxModel);
- connect(m_projectSelection, static_cast<void(QComboBox::*)(int)>(&QComboBox::activated),
+ connect(m_projectSelection, QOverload<int>::of(&QComboBox::activated),
this, &ProjectWindowPrivate::projectSelected, Qt::QueuedConnection);
SessionManager *sessionManager = SessionManager::instance();
@@ -546,7 +546,7 @@ public:
QString importDir = QFileDialog::getExistingDirectory(ICore::mainWindow(),
ProjectWindow::tr("Import Directory"),
dir);
- FileName path = FileName::fromString(importDir);
+ FilePath path = FilePath::fromString(importDir);
Target *lastTarget = nullptr;
BuildConfiguration *lastBc = nullptr;
diff --git a/src/plugins/projectexplorer/projectwizardpage.cpp b/src/plugins/projectexplorer/projectwizardpage.cpp
index 500a13a4fc..9eaf136d8b 100644
--- a/src/plugins/projectexplorer/projectwizardpage.cpp
+++ b/src/plugins/projectexplorer/projectwizardpage.cpp
@@ -171,7 +171,7 @@ BestNodeSelector::BestNodeSelector(const QString &commonDirectory, const QString
void BestNodeSelector::inspect(AddNewTree *tree, bool isContextNode)
{
FolderNode *node = tree->node();
- if (node->nodeType() == NodeType::Project) {
+ if (node->isProjectNodeType()) {
if (static_cast<ProjectNode *>(node)->deploysFolder(m_commonDirectory)) {
m_deploys = true;
m_deployText += tree->displayName() + QLatin1Char('\n');
@@ -284,9 +284,9 @@ ProjectWizardPage::ProjectWizardPage(QWidget *parent) : WizardPage(parent),
{
m_ui->setupUi(this);
m_ui->vcsManageButton->setText(ICore::msgShowOptionsDialog());
- connect(m_ui->projectComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
+ connect(m_ui->projectComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &ProjectWizardPage::projectChanged);
- connect(m_ui->addToVersionControlComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
+ connect(m_ui->addToVersionControlComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &ProjectWizardPage::versionControlChanged);
connect(m_ui->vcsManageButton, &QAbstractButton::clicked, this, &ProjectWizardPage::manageVcs);
setProperty(SHORT_TITLE_PROPERTY, tr("Summary"));
@@ -299,7 +299,7 @@ ProjectWizardPage::ProjectWizardPage(QWidget *parent) : WizardPage(parent),
ProjectWizardPage::~ProjectWizardPage()
{
- disconnect(m_ui->projectComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
+ disconnect(m_ui->projectComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &ProjectWizardPage::projectChanged);
delete m_ui;
}
@@ -534,7 +534,7 @@ void ProjectWizardPage::setFiles(const QStringList &fileNames)
const bool filePath2HasDir = filePath2.contains(QLatin1Char('/'));
if (filePath1HasDir == filePath2HasDir)
- return FileName::fromString(filePath1) < FileName::fromString(filePath2);
+ return FilePath::fromString(filePath1) < FilePath::fromString(filePath2);
return filePath1HasDir;
}
);
diff --git a/src/plugins/projectexplorer/runconfiguration.cpp b/src/plugins/projectexplorer/runconfiguration.cpp
index 2c8e238495..5c3c6fc0e9 100644
--- a/src/plugins/projectexplorer/runconfiguration.cpp
+++ b/src/plugins/projectexplorer/runconfiguration.cpp
@@ -26,6 +26,7 @@
#include "runconfiguration.h"
#include "project.h"
+#include "runcontrol.h"
#include "target.h"
#include "toolchain.h"
#include "abi.h"
@@ -55,21 +56,9 @@
#include <QLoggingCategory>
#include <QSettings>
-#ifdef Q_OS_OSX
-#include <ApplicationServices/ApplicationServices.h>
-#endif
-
-#if defined (WITH_JOURNALD)
-#include "journaldwatcher.h"
-#endif
-
using namespace Utils;
using namespace ProjectExplorer::Internal;
-namespace {
-Q_LOGGING_CATEGORY(statesLog, "qtc.projectmanager.states", QtWarningMsg)
-}
-
namespace ProjectExplorer {
///////////////////////////////////////////////////////////////////////
@@ -169,7 +158,7 @@ void GlobalOrProjectAspect::resetProjectToGlobalSettings()
static std::vector<RunConfiguration::AspectFactory> theAspectFactories;
RunConfiguration::RunConfiguration(Target *target, Core::Id id)
- : StatefulProjectConfiguration(target, id)
+ : ProjectConfiguration(target, id)
{
connect(target->project(), &Project::parsingStarted,
this, [this]() { updateEnabledState(); });
@@ -197,12 +186,26 @@ RunConfiguration::RunConfiguration(Target *target, Core::Id id)
const auto envAspect = aspect<EnvironmentAspect>();
return envAspect ? envAspect->environment().value(var) : QString();
});
+
+ expander->registerVariable(Constants::VAR_CURRENTRUN_WORKINGDIR,
+ tr("The currently active run configuration's working directory"),
+ [this, expander] {
+ const auto wdAspect = aspect<WorkingDirectoryAspect>();
+ return wdAspect ? wdAspect->workingDirectory(expander).toString() : QString();
+ });
+
expander->registerVariable(Constants::VAR_CURRENTRUN_NAME,
QCoreApplication::translate("ProjectExplorer", "The currently active run configuration's name."),
[this] { return displayName(); }, false);
for (const AspectFactory &factory : theAspectFactories)
m_aspects.append(factory(target));
+
+ m_executableGetter = [this] {
+ if (const auto executableAspect = aspect<ExecutableAspect>())
+ return executableAspect->executable();
+ return FilePath();
+ };
}
RunConfiguration::~RunConfiguration() = default;
@@ -212,12 +215,25 @@ bool RunConfiguration::isActive() const
return target()->isActive() && target()->activeRunConfiguration() == this;
}
+void RunConfiguration::setEnabled(bool enabled)
+{
+ if (enabled == m_isEnabled)
+ return;
+ m_isEnabled = enabled;
+ emit enabledChanged();
+}
+
QString RunConfiguration::disabledReason() const
{
if (target()->project()->isParsing())
return tr("The Project is currently being parsed.");
- if (!target()->project()->hasParsingData())
- return tr("The project could not be fully parsed.");
+ if (!target()->project()->hasParsingData()) {
+ QString msg = tr("The project could not be fully parsed.");
+ const FilePath projectFilePath = buildTargetInfo().projectFilePath;
+ if (!projectFilePath.exists())
+ msg += '\n' + tr("The project file \"%1\" does not exist.").arg(projectFilePath.toString());
+ return msg;
+ }
return QString();
}
@@ -311,9 +327,19 @@ QVariantMap RunConfiguration::toMap() const
return map;
}
+void RunConfiguration::setExecutableGetter(const RunConfiguration::ExecutableGetter &exeGetter)
+{
+ m_executableGetter = exeGetter;
+}
+
+FilePath RunConfiguration::executable() const
+{
+ return m_executableGetter();
+}
+
BuildTargetInfo RunConfiguration::buildTargetInfo() const
{
- return target()->applicationTargets().buildTargetInfo(m_buildKey);
+ return target()->buildTarget(m_buildKey);
}
bool RunConfiguration::fromMap(const QVariantMap &map)
@@ -366,8 +392,7 @@ bool RunConfiguration::fromMap(const QVariantMap &map)
Runnable RunConfiguration::runnable() const
{
Runnable r;
- if (auto executableAspect = aspect<ExecutableAspect>())
- r.executable = executableAspect->executable().toString();
+ r.executable = executable().toString();
if (auto argumentsAspect = aspect<ArgumentsAspect>())
r.commandLineArguments = argumentsAspect->arguments(macroExpander());
if (auto workingDirectoryAspect = aspect<WorkingDirectoryAspect>())
@@ -426,8 +451,6 @@ RunConfigurationFactory::RunConfigurationFactory()
RunConfigurationFactory::~RunConfigurationFactory()
{
g_runConfigurationFactories.removeOne(this);
- qDeleteAll(m_ownedRunWorkerFactories);
- m_ownedRunWorkerFactories.clear();
}
QString RunConfigurationFactory::decoratedTargetName(const QString &targetName, Target *target)
@@ -435,9 +458,9 @@ QString RunConfigurationFactory::decoratedTargetName(const QString &targetName,
QString displayName;
if (!targetName.isEmpty())
displayName = QFileInfo(targetName).completeBaseName();
- Core::Id devType = DeviceTypeKitInformation::deviceTypeId(target->kit());
+ Core::Id devType = DeviceTypeKitAspect::deviceTypeId(target->kit());
if (devType != Constants::DESKTOP_DEVICE_TYPE) {
- if (IDevice::ConstPtr dev = DeviceKitInformation::device(target->kit())) {
+ if (IDevice::ConstPtr dev = DeviceKitAspect::device(target->kit())) {
if (displayName.isEmpty()) {
//: Shown in Run configuration if no executable is given, %1 is device name
displayName = RunConfiguration::tr("Run on %1").arg(dev->displayName());
@@ -453,7 +476,7 @@ QString RunConfigurationFactory::decoratedTargetName(const QString &targetName,
QList<RunConfigurationCreationInfo>
RunConfigurationFactory::availableCreators(Target *parent) const
{
- const QList<BuildTargetInfo> buildTargets = parent->applicationTargets().list;
+ const QList<BuildTargetInfo> buildTargets = parent->applicationTargets();
const bool hasAnyQtcRunnable = Utils::anyOf(buildTargets,
Utils::equal(&BuildTargetInfo::isQtcRunnable, true));
return Utils::transform(buildTargets, [&](const BuildTargetInfo &ti) {
@@ -466,6 +489,7 @@ RunConfigurationFactory::availableCreators(Target *parent) const
rci.factory = this;
rci.id = m_runConfigBaseId;
rci.buildKey = ti.buildKey;
+ rci.projectFilePath = ti.projectFilePath;
rci.displayName = displayName;
rci.displayNameUniquifier = ti.displayNameUniquifier;
rci.creationMode = ti.isQtcRunnable || !hasAnyQtcRunnable
@@ -495,16 +519,6 @@ void RunConfigurationFactory::setDecorateDisplayNames(bool on)
m_decorateDisplayNames = on;
}
-RunWorkerFactory *RunConfigurationFactory::addRunWorkerFactoryHelper
- (Core::Id runMode, const std::function<RunWorker *(RunControl *)> &creator)
-{
- auto factory = new RunWorkerFactory;
- factory->addConstraint(m_ownTypeChecker);
- factory->addSupportedRunMode(runMode);
- factory->setProducer(creator);
- return factory;
-}
-
void RunConfigurationFactory::addSupportedProjectType(Core::Id id)
{
m_supportedProjectTypes.append(id);
@@ -524,7 +538,7 @@ bool RunConfigurationFactory::canHandle(Target *target) const
if (!m_supportedTargetDeviceTypes.isEmpty())
if (!m_supportedTargetDeviceTypes.contains(
- DeviceTypeKitInformation::deviceTypeId(kit)))
+ DeviceTypeKitAspect::deviceTypeId(kit)))
return false;
return true;
@@ -540,6 +554,7 @@ RunConfiguration *RunConfigurationCreationInfo::create(Target *target) const
if (!rc)
return nullptr;
+ rc->acquaintAspects();
rc->m_buildKey = buildKey;
rc->doAdditionalSetup(*this);
rc->setDisplayName(displayName);
@@ -555,6 +570,7 @@ RunConfiguration *RunConfigurationFactory::restore(Target *parent, const QVarian
if (id.name().startsWith(factory->m_runConfigBaseId.name())) {
QTC_ASSERT(factory->m_creator, continue);
RunConfiguration *rc = factory->m_creator(parent);
+ rc->acquaintAspects();
if (rc->fromMap(map))
return rc;
delete rc;
@@ -607,1413 +623,4 @@ FixedRunConfigurationFactory::availableCreators(Target *parent) const
return {rci};
}
-
-// RunWorkerFactory
-
-static QList<RunWorkerFactory *> g_runWorkerFactories;
-
-RunWorkerFactory::RunWorkerFactory()
-{
- g_runWorkerFactories.append(this);
-}
-
-RunWorkerFactory::~RunWorkerFactory()
-{
- g_runWorkerFactories.removeOne(this);
-}
-
-bool RunWorkerFactory::canRun(RunConfiguration *runConfiguration, Core::Id runMode) const
-{
- if (!m_supportedRunModes.contains(runMode))
- return false;
-
- for (const Constraint &constraint : m_constraints) {
- if (!constraint(runConfiguration))
- return false;
- }
-
- return true;
-}
-
-void RunWorkerFactory::setProducer(const WorkerCreator &producer)
-{
- m_producer = producer;
-}
-
-void RunWorkerFactory::addConstraint(const Constraint &constraint)
-{
- // Default constructed Constraints are not worth keeping.
- // FIXME: Make it a QTC_ASSERT once there is no code path
- // using this "feature" anymore.
- if (!constraint)
- return;
- m_constraints.append(constraint);
-}
-
-void RunWorkerFactory::addSupportedRunMode(Core::Id runMode)
-{
- m_supportedRunModes.append(runMode);
-}
-
-void RunWorkerFactory::destroyRemainingRunWorkerFactories()
-{
- qDeleteAll(g_runWorkerFactories);
-}
-
-/*!
- \class ProjectExplorer::RunControl
- \brief The RunControl class instances represent one item that is run.
-*/
-
-/*!
- \fn QIcon ProjectExplorer::RunControl::icon() const
- Returns the icon to be shown in the Outputwindow.
-
- TODO the icon differs currently only per "mode", so this is more flexible
- than it needs to be.
-*/
-
-
-namespace Internal {
-
-enum class RunWorkerState
-{
- Initialized, Starting, Running, Stopping, Done
-};
-
-static QString stateName(RunWorkerState s)
-{
-# define SN(x) case x: return QLatin1String(#x);
- switch (s) {
- SN(RunWorkerState::Initialized)
- SN(RunWorkerState::Starting)
- SN(RunWorkerState::Running)
- SN(RunWorkerState::Stopping)
- SN(RunWorkerState::Done)
- }
- return QString("<unknown: %1>").arg(int(s));
-# undef SN
-}
-
-class RunWorkerPrivate : public QObject
-{
-public:
- RunWorkerPrivate(RunWorker *runWorker, RunControl *runControl);
-
- bool canStart() const;
- bool canStop() const;
- void timerEvent(QTimerEvent *ev) override;
-
- void killStartWatchdog()
- {
- if (startWatchdogTimerId != -1) {
- killTimer(startWatchdogTimerId);
- startWatchdogTimerId = -1;
- }
- }
-
- void killStopWatchdog()
- {
- if (stopWatchdogTimerId != -1) {
- killTimer(stopWatchdogTimerId);
- stopWatchdogTimerId = -1;
- }
- }
-
- void startStartWatchdog()
- {
- killStartWatchdog();
- killStopWatchdog();
-
- if (startWatchdogInterval != 0)
- startWatchdogTimerId = startTimer(startWatchdogInterval);
- }
-
- void startStopWatchdog()
- {
- killStopWatchdog();
- killStartWatchdog();
-
- if (stopWatchdogInterval != 0)
- stopWatchdogTimerId = startTimer(stopWatchdogInterval);
- }
-
- RunWorker *q;
- RunWorkerState state = RunWorkerState::Initialized;
- const QPointer<RunControl> runControl;
- QList<RunWorker *> startDependencies;
- QList<RunWorker *> stopDependencies;
- QString id;
-
- QVariantMap data;
- int startWatchdogInterval = 0;
- int startWatchdogTimerId = -1;
- std::function<void()> startWatchdogCallback;
- int stopWatchdogInterval = 0; // 5000;
- int stopWatchdogTimerId = -1;
- std::function<void()> stopWatchdogCallback;
- bool supportsReRunning = true;
- bool essential = false;
-};
-
-enum class RunControlState
-{
- Initialized, // Default value after creation.
- Starting, // Actual process/tool starts.
- Running, // All good and running.
- Stopping, // initiateStop() was called, stop application/tool
- Stopped, // all good, but stopped. Can possibly be re-started
- Finishing, // Application tab manually closed
- Finished // Final state, will self-destruct with deleteLater()
-};
-
-static QString stateName(RunControlState s)
-{
-# define SN(x) case x: return QLatin1String(#x);
- switch (s) {
- SN(RunControlState::Initialized)
- SN(RunControlState::Starting)
- SN(RunControlState::Running)
- SN(RunControlState::Stopping)
- SN(RunControlState::Stopped)
- SN(RunControlState::Finishing)
- SN(RunControlState::Finished)
- }
- return QString("<unknown: %1>").arg(int(s));
-# undef SN
-}
-
-class RunControlPrivate : public QObject
-{
-public:
- RunControlPrivate(RunControl *parent, RunConfiguration *runConfiguration, Core::Id mode)
- : q(parent), runMode(mode), runConfiguration(runConfiguration)
- {
- icon = Icons::RUN_SMALL_TOOLBAR;
- if (runConfiguration) {
- runnable = runConfiguration->runnable();
- displayName = runConfiguration->displayName();
- outputFormatter = runConfiguration->createOutputFormatter();
- device = runnable.device;
- if (!device)
- device = DeviceKitInformation::device(runConfiguration->target()->kit());
- project = runConfiguration->target()->project();
- } else {
- outputFormatter = new OutputFormatter();
- }
- }
-
- ~RunControlPrivate() override
- {
- QTC_CHECK(state == RunControlState::Finished || state == RunControlState::Initialized);
- disconnect();
- q = nullptr;
- qDeleteAll(m_workers);
- m_workers.clear();
- delete outputFormatter;
- }
-
- Q_ENUM(RunControlState)
-
- void checkState(RunControlState expectedState);
- void setState(RunControlState state);
-
- void debugMessage(const QString &msg);
-
- void initiateStart();
- void initiateReStart();
- void continueStart();
- void initiateStop();
- void forceStop();
- void continueStopOrFinish();
- void initiateFinish();
-
- void onWorkerStarted(RunWorker *worker);
- void onWorkerStopped(RunWorker *worker);
- void onWorkerFailed(RunWorker *worker, const QString &msg);
-
- void showError(const QString &msg);
-
- static bool isAllowedTransition(RunControlState from, RunControlState to);
- bool supportsReRunning() const;
-
- RunControl *q;
- QString displayName;
- Runnable runnable;
- IDevice::ConstPtr device;
- Core::Id runMode;
- Utils::Icon icon;
- const QPointer<RunConfiguration> runConfiguration; // Not owned.
- QPointer<Project> project; // Not owned.
- QPointer<Utils::OutputFormatter> outputFormatter = nullptr;
- std::function<bool(bool*)> promptToStop;
- std::vector<RunWorkerFactory> m_factories;
-
- // A handle to the actual application process.
- Utils::ProcessHandle applicationProcessHandle;
-
- RunControlState state = RunControlState::Initialized;
-
- QList<QPointer<RunWorker>> m_workers;
-};
-
-} // Internal
-
-using namespace Internal;
-
-RunControl::RunControl(RunConfiguration *runConfiguration, Core::Id mode) :
- d(std::make_unique<RunControlPrivate>(this, runConfiguration, mode))
-{
-#ifdef WITH_JOURNALD
- if (!device().isNull() && device()->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) {
- JournaldWatcher::instance()->subscribe(this, [this](const JournaldWatcher::LogEntry &entry) {
-
- if (entry.value("_MACHINE_ID") != JournaldWatcher::instance()->machineId())
- return;
-
- const QByteArray pid = entry.value("_PID");
- if (pid.isEmpty())
- return;
-
- const qint64 pidNum = static_cast<qint64>(QString::fromLatin1(pid).toInt());
- if (pidNum != d->applicationProcessHandle.pid())
- return;
-
- const QString message = QString::fromUtf8(entry.value("MESSAGE")) + "\n";
- appendMessageRequested(this, message, Utils::OutputFormat::LogMessageFormat);
- });
- }
-#endif
-}
-
-RunControl::RunControl(const IDevice::ConstPtr &device, Core::Id mode)
- : RunControl(nullptr, mode)
-{
- d->device = device;
-}
-
-RunControl::~RunControl()
-{
-#ifdef WITH_JOURNALD
- JournaldWatcher::instance()->unsubscribe(this);
-#endif
-}
-
-void RunControl::initiateStart()
-{
- emit aboutToStart();
- d->initiateStart();
-}
-
-void RunControl::initiateReStart()
-{
- emit aboutToStart();
- d->initiateReStart();
-}
-
-void RunControl::initiateStop()
-{
- d->initiateStop();
-}
-
-void RunControl::forceStop()
-{
- d->forceStop();
-}
-
-void RunControl::initiateFinish()
-{
- QTimer::singleShot(0, d.get(), &RunControlPrivate::initiateFinish);
-}
-
-using WorkerCreators = QHash<Core::Id, RunControl::WorkerCreator>;
-
-static WorkerCreators &theWorkerCreators()
-{
- static WorkerCreators creators;
- return creators;
-}
-
-void RunControl::registerWorkerCreator(Core::Id id, const WorkerCreator &workerCreator)
-{
- theWorkerCreators().insert(id, workerCreator);
- auto keys = theWorkerCreators().keys();
- Q_UNUSED(keys);
-}
-
-RunWorker *RunControl::createWorker(Core::Id id)
-{
- auto keys = theWorkerCreators().keys();
- Q_UNUSED(keys);
- WorkerCreator creator = theWorkerCreators().value(id);
- if (creator)
- return creator(this);
- creator = device()->workerCreator(id);
- if (creator)
- return creator(this);
- return nullptr;
-}
-
-RunWorkerFactory::WorkerCreator RunControl::producer(RunConfiguration *runConfig, Core::Id runMode)
-{
- const auto canRun = std::bind(&RunWorkerFactory::canRun, std::placeholders::_1, runConfig, runMode);
- const QList<RunWorkerFactory *> candidates = Utils::filtered(g_runWorkerFactories, canRun);
-
- // This is legit, there might be combinations that cannot run.
- if (candidates.empty())
- return {};
-
- // There should be at most one top-level producer feeling responsible per combination.
- // Breaking a tie should be done by tightening the restrictions on one of them.
- QTC_CHECK(candidates.size() == 1);
- return candidates.front()->producer();
-}
-
-void RunControlPrivate::initiateStart()
-{
- checkState(RunControlState::Initialized);
- setState(RunControlState::Starting);
- debugMessage("Queue: Starting");
-
- continueStart();
-}
-
-void RunControlPrivate::initiateReStart()
-{
- checkState(RunControlState::Stopped);
-
- // Re-set worked on re-runs.
- for (RunWorker *worker : m_workers) {
- if (worker->d->state == RunWorkerState::Done)
- worker->d->state = RunWorkerState::Initialized;
- }
-
- setState(RunControlState::Starting);
- debugMessage("Queue: ReStarting");
-
- continueStart();
-}
-
-void RunControlPrivate::continueStart()
-{
- checkState(RunControlState::Starting);
- bool allDone = true;
- debugMessage("Looking for next worker");
- for (RunWorker *worker : m_workers) {
- if (worker) {
- const QString &workerId = worker->d->id;
- debugMessage(" Examining worker " + workerId);
- switch (worker->d->state) {
- case RunWorkerState::Initialized:
- debugMessage(" " + workerId + " is not done yet.");
- if (worker->d->canStart()) {
- debugMessage("Starting " + workerId);
- worker->d->state = RunWorkerState::Starting;
- QTimer::singleShot(0, worker, &RunWorker::initiateStart);
- return;
- }
- allDone = false;
- debugMessage(" " + workerId + " cannot start.");
- break;
- case RunWorkerState::Starting:
- debugMessage(" " + workerId + " currently starting");
- allDone = false;
- break;
- case RunWorkerState::Running:
- debugMessage(" " + workerId + " currently running");
- break;
- case RunWorkerState::Stopping:
- debugMessage(" " + workerId + " currently stopping");
- continue;
- case RunWorkerState::Done:
- debugMessage(" " + workerId + " was done before");
- break;
- }
- } else {
- debugMessage("Found unknown deleted worker while starting");
- }
- }
- if (allDone)
- setState(RunControlState::Running);
-}
-
-void RunControlPrivate::initiateStop()
-{
- if (state != RunControlState::Starting && state != RunControlState::Running)
- qDebug() << "Unexpected initiateStop() in state" << stateName(state);
-
- setState(RunControlState::Stopping);
- debugMessage("Queue: Stopping for all workers");
-
- continueStopOrFinish();
-}
-
-void RunControlPrivate::continueStopOrFinish()
-{
- bool allDone = true;
-
- auto queueStop = [this](RunWorker *worker, const QString &message) {
- if (worker->d->canStop()) {
- debugMessage(message);
- worker->d->state = RunWorkerState::Stopping;
- QTimer::singleShot(0, worker, &RunWorker::initiateStop);
- } else {
- debugMessage(" " + worker->d->id + " is waiting for dependent workers to stop");
- }
- };
-
- for (RunWorker *worker : m_workers) {
- if (worker) {
- const QString &workerId = worker->d->id;
- debugMessage(" Examining worker " + workerId);
- switch (worker->d->state) {
- case RunWorkerState::Initialized:
- debugMessage(" " + workerId + " was Initialized, setting to Done");
- worker->d->state = RunWorkerState::Done;
- break;
- case RunWorkerState::Stopping:
- debugMessage(" " + workerId + " was already Stopping. Keeping it that way");
- allDone = false;
- break;
- case RunWorkerState::Starting:
- queueStop(worker, " " + workerId + " was Starting, queuing stop");
- allDone = false;
- break;
- case RunWorkerState::Running:
- queueStop(worker, " " + workerId + " was Running, queuing stop");
- allDone = false;
- break;
- case RunWorkerState::Done:
- debugMessage(" " + workerId + " was Done. Good.");
- break;
- }
- } else {
- debugMessage("Found unknown deleted worker");
- }
- }
-
- RunControlState targetState;
- if (state == RunControlState::Finishing) {
- targetState = RunControlState::Finished;
- } else {
- checkState(RunControlState::Stopping);
- targetState = RunControlState::Stopped;
- }
-
- if (allDone) {
- debugMessage("All Stopped");
- setState(targetState);
- } else {
- debugMessage("Not all workers Stopped. Waiting...");
- }
-}
-
-void RunControlPrivate::forceStop()
-{
- if (state == RunControlState::Finished) {
- debugMessage("Was finished, too late to force Stop");
- return;
- }
- for (RunWorker *worker : m_workers) {
- if (worker) {
- const QString &workerId = worker->d->id;
- debugMessage(" Examining worker " + workerId);
- switch (worker->d->state) {
- case RunWorkerState::Initialized:
- debugMessage(" " + workerId + " was Initialized, setting to Done");
- break;
- case RunWorkerState::Stopping:
- debugMessage(" " + workerId + " was already Stopping. Set it forcefully to Done.");
- break;
- case RunWorkerState::Starting:
- debugMessage(" " + workerId + " was Starting. Set it forcefully to Done.");
- break;
- case RunWorkerState::Running:
- debugMessage(" " + workerId + " was Running. Set it forcefully to Done.");
- break;
- case RunWorkerState::Done:
- debugMessage(" " + workerId + " was Done. Good.");
- break;
- }
- worker->d->state = RunWorkerState::Done;
- } else {
- debugMessage("Found unknown deleted worker");
- }
- }
-
- setState(RunControlState::Stopped);
- debugMessage("All Stopped");
-}
-
-void RunControlPrivate::initiateFinish()
-{
- setState(RunControlState::Finishing);
- debugMessage("Ramping down");
-
- continueStopOrFinish();
-}
-
-void RunControlPrivate::onWorkerStarted(RunWorker *worker)
-{
- worker->d->state = RunWorkerState::Running;
-
- if (state == RunControlState::Starting) {
- debugMessage(worker->d->id + " start succeeded");
- continueStart();
- return;
- }
- showError(RunControl::tr("Unexpected run control state %1 when worker %2 started.")
- .arg(stateName(state))
- .arg(worker->d->id));
-}
-
-void RunControlPrivate::onWorkerFailed(RunWorker *worker, const QString &msg)
-{
- worker->d->state = RunWorkerState::Done;
-
- showError(msg);
- switch (state) {
- case RunControlState::Initialized:
- // FIXME 1: We don't have an output pane yet, so use some other mechanism for now.
- // FIXME 2: Translation...
- QMessageBox::critical(Core::ICore::dialogParent(),
- QCoreApplication::translate("TaskHub", "Error"),
- QString("Failure during startup. Aborting.") + "<p>" + msg);
- continueStopOrFinish();
- break;
- case RunControlState::Starting:
- case RunControlState::Running:
- initiateStop();
- break;
- case RunControlState::Stopping:
- case RunControlState::Finishing:
- continueStopOrFinish();
- break;
- case RunControlState::Stopped:
- case RunControlState::Finished:
- QTC_CHECK(false); // Should not happen.
- continueStopOrFinish();
- break;
- }
-}
-
-void RunControlPrivate::onWorkerStopped(RunWorker *worker)
-{
- const QString &workerId = worker->d->id;
- switch (worker->d->state) {
- case RunWorkerState::Running:
- // That was a spontaneous stop.
- worker->d->state = RunWorkerState::Done;
- debugMessage(workerId + " stopped spontaneously.");
- break;
- case RunWorkerState::Stopping:
- worker->d->state = RunWorkerState::Done;
- debugMessage(workerId + " stopped expectedly.");
- break;
- case RunWorkerState::Done:
- worker->d->state = RunWorkerState::Done;
- debugMessage(workerId + " stopped twice. Huh? But harmless.");
- return; // Sic!
- default:
- debugMessage(workerId + " stopped unexpectedly in state"
- + stateName(worker->d->state));
- worker->d->state = RunWorkerState::Done;
- break;
- }
-
- if (state == RunControlState::Finishing || state == RunControlState::Stopping) {
- continueStopOrFinish();
- return;
- } else if (worker->isEssential()) {
- debugMessage(workerId + " is essential. Stopping all others.");
- initiateStop();
- return;
- }
-
- for (RunWorker *dependent : worker->d->stopDependencies) {
- switch (dependent->d->state) {
- case RunWorkerState::Done:
- break;
- case RunWorkerState::Initialized:
- dependent->d->state = RunWorkerState::Done;
- break;
- default:
- debugMessage("Killing " + dependent->d->id + " as it depends on stopped " + workerId);
- dependent->d->state = RunWorkerState::Stopping;
- QTimer::singleShot(0, dependent, &RunWorker::initiateStop);
- break;
- }
- }
-
- debugMessage("Checking whether all stopped");
- bool allDone = true;
- for (RunWorker *worker : m_workers) {
- if (worker) {
- const QString &workerId = worker->d->id;
- debugMessage(" Examining worker " + workerId);
- switch (worker->d->state) {
- case RunWorkerState::Initialized:
- debugMessage(" " + workerId + " was Initialized.");
- break;
- case RunWorkerState::Starting:
- debugMessage(" " + workerId + " was Starting, waiting for its response");
- allDone = false;
- break;
- case RunWorkerState::Running:
- debugMessage(" " + workerId + " was Running, waiting for its response");
- allDone = false;
- break;
- case RunWorkerState::Stopping:
- debugMessage(" " + workerId + " was already Stopping. Keeping it that way");
- allDone = false;
- break;
- case RunWorkerState::Done:
- debugMessage(" " + workerId + " was Done. Good.");
- break;
- }
- } else {
- debugMessage("Found unknown deleted worker");
- }
- }
-
- if (allDone) {
- if (state == RunControlState::Stopped) {
- debugMessage("All workers stopped, but runControl was already stopped.");
- } else {
- debugMessage("All workers stopped. Set runControl to Stopped");
- setState(RunControlState::Stopped);
- }
- } else {
- debugMessage("Not all workers stopped. Waiting...");
- }
-}
-
-void RunControlPrivate::showError(const QString &msg)
-{
- if (!msg.isEmpty())
- q->appendMessage(msg + '\n', ErrorMessageFormat);
-}
-
-Utils::OutputFormatter *RunControl::outputFormatter() const
-{
- return d->outputFormatter;
-}
-
-Core::Id RunControl::runMode() const
-{
- return d->runMode;
-}
-
-const Runnable &RunControl::runnable() const
-{
- return d->runnable;
-}
-
-void RunControl::setRunnable(const Runnable &runnable)
-{
- d->runnable = runnable;
-}
-
-QString RunControl::displayName() const
-{
- return d->displayName;
-}
-
-void RunControl::setDisplayName(const QString &displayName)
-{
- d->displayName = displayName;
-}
-
-void RunControl::setIcon(const Utils::Icon &icon)
-{
- d->icon = icon;
-}
-
-Utils::Icon RunControl::icon() const
-{
- return d->icon;
-}
-
-IDevice::ConstPtr RunControl::device() const
-{
- return d->device;
-}
-
-RunConfiguration *RunControl::runConfiguration() const
-{
- return d->runConfiguration.data();
-}
-
-Project *RunControl::project() const
-{
- return d->project.data();
-}
-
-/*!
- A handle to the application process.
-
- This is typically a process id, but should be treated as
- opaque handle to the process controled by this \c RunControl.
-*/
-
-ProcessHandle RunControl::applicationProcessHandle() const
-{
- return d->applicationProcessHandle;
-}
-
-void RunControl::setApplicationProcessHandle(const ProcessHandle &handle)
-{
- if (d->applicationProcessHandle != handle) {
- d->applicationProcessHandle = handle;
- emit applicationProcessHandleChanged(QPrivateSignal());
- }
-}
-
-/*!
- Prompts to stop. If \a optionalPrompt is passed, a \gui {Do not ask again}
- checkbox is displayed and the result is returned in \a *optionalPrompt.
-*/
-
-bool RunControl::promptToStop(bool *optionalPrompt) const
-{
- QTC_ASSERT(isRunning(), return true);
- if (optionalPrompt && !*optionalPrompt)
- return true;
-
- // Overridden.
- if (d->promptToStop)
- return d->promptToStop(optionalPrompt);
-
- const QString msg = tr("<html><head/><body><center><i>%1</i> is still running.<center/>"
- "<center>Force it to quit?</center></body></html>").arg(displayName());
- return showPromptToStopDialog(tr("Application Still Running"), msg,
- tr("Force &Quit"), tr("&Keep Running"),
- optionalPrompt);
-}
-
-void RunControl::setPromptToStop(const std::function<bool (bool *)> &promptToStop)
-{
- d->promptToStop = promptToStop;
-}
-
-bool RunControl::supportsReRunning() const
-{
- return d->supportsReRunning();
-}
-
-bool RunControlPrivate::supportsReRunning() const
-{
- for (RunWorker *worker : m_workers) {
- if (!worker->d->supportsReRunning)
- return false;
- if (worker->d->state != RunWorkerState::Done)
- return false;
- }
- return true;
-}
-
-bool RunControl::isRunning() const
-{
- return d->state == RunControlState::Running;
-}
-
-bool RunControl::isStarting() const
-{
- return d->state == RunControlState::Starting;
-}
-
-bool RunControl::isStopping() const
-{
- return d->state == RunControlState::Stopping;
-}
-
-bool RunControl::isStopped() const
-{
- return d->state == RunControlState::Stopped;
-}
-
-/*!
- Prompts to terminate the application with the \gui {Do not ask again}
- checkbox.
-*/
-
-bool RunControl::showPromptToStopDialog(const QString &title,
- const QString &text,
- const QString &stopButtonText,
- const QString &cancelButtonText,
- bool *prompt)
-{
- // Show a question message box where user can uncheck this
- // question for this class.
- Utils::CheckableMessageBox messageBox(Core::ICore::mainWindow());
- messageBox.setWindowTitle(title);
- messageBox.setText(text);
- messageBox.setStandardButtons(QDialogButtonBox::Yes|QDialogButtonBox::Cancel);
- if (!stopButtonText.isEmpty())
- messageBox.button(QDialogButtonBox::Yes)->setText(stopButtonText);
- if (!cancelButtonText.isEmpty())
- messageBox.button(QDialogButtonBox::Cancel)->setText(cancelButtonText);
- messageBox.setDefaultButton(QDialogButtonBox::Yes);
- if (prompt) {
- messageBox.setCheckBoxText(Utils::CheckableMessageBox::msgDoNotAskAgain());
- messageBox.setChecked(false);
- } else {
- messageBox.setCheckBoxVisible(false);
- }
- messageBox.exec();
- const bool close = messageBox.clickedStandardButton() == QDialogButtonBox::Yes;
- if (close && prompt && messageBox.isChecked())
- *prompt = false;
- return close;
-}
-
-bool RunControlPrivate::isAllowedTransition(RunControlState from, RunControlState to)
-{
- switch (from) {
- case RunControlState::Initialized:
- return to == RunControlState::Starting
- || to == RunControlState::Finishing;
- case RunControlState::Starting:
- return to == RunControlState::Running
- || to == RunControlState::Stopping
- || to == RunControlState::Finishing;
- case RunControlState::Running:
- return to == RunControlState::Stopping
- || to == RunControlState::Stopped
- || to == RunControlState::Finishing;
- case RunControlState::Stopping:
- return to == RunControlState::Stopped
- || to == RunControlState::Finishing;
- case RunControlState::Stopped:
- return to == RunControlState::Finishing;
- case RunControlState::Finishing:
- return to == RunControlState::Finished;
- case RunControlState::Finished:
- return false;
- }
- return false;
-}
-
-void RunControlPrivate::checkState(RunControlState expectedState)
-{
- if (state != expectedState)
- qDebug() << "Unexpected run control state " << stateName(expectedState)
- << " have: " << stateName(state);
-}
-
-void RunControlPrivate::setState(RunControlState newState)
-{
- if (!isAllowedTransition(state, newState))
- qDebug() << "Invalid run control state transition from " << stateName(state)
- << " to " << stateName(newState);
-
- state = newState;
-
- debugMessage("Entering state " + stateName(newState));
-
- // Extra reporting.
- switch (state) {
- case RunControlState::Running:
- emit q->started();
- break;
- case RunControlState::Stopped:
- q->setApplicationProcessHandle(Utils::ProcessHandle());
- emit q->stopped();
- break;
- case RunControlState::Finished:
- emit q->finished();
- debugMessage("All finished. Deleting myself");
- q->deleteLater();
- break;
- default:
- break;
- }
-}
-
-void RunControlPrivate::debugMessage(const QString &msg)
-{
- qCDebug(statesLog()) << msg;
-}
-
-void RunControl::appendMessage(const QString &msg, Utils::OutputFormat format)
-{
- emit appendMessageRequested(this, msg, format);
-}
-
-// SimpleTargetRunner
-
-SimpleTargetRunner::SimpleTargetRunner(RunControl *runControl)
- : RunWorker(runControl)
-{
- setId("SimpleTargetRunner");
- m_runnable = runControl->runnable(); // Default value. Can be overridden using setRunnable.
- m_device = runControl->device(); // Default value. Can be overridden using setDevice.
- if (auto runConfig = runControl->runConfiguration()) {
- if (auto terminalAspect = runConfig->aspect<TerminalAspect>())
- m_useTerminal = terminalAspect->useTerminal();
- }
-}
-
-void SimpleTargetRunner::start()
-{
- m_stopReported = false;
- m_launcher.disconnect(this);
- m_launcher.setUseTerminal(m_useTerminal);
-
- const bool isDesktop = m_device.isNull()
- || m_device->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE;
- const QString rawDisplayName = m_runnable.displayName();
- const QString displayName = isDesktop
- ? QDir::toNativeSeparators(rawDisplayName)
- : rawDisplayName;
- const QString msg = RunControl::tr("Starting %1 %2...")
- .arg(displayName).arg(m_runnable.commandLineArguments);
- appendMessage(msg, Utils::NormalMessageFormat);
-
- if (isDesktop) {
-
- connect(&m_launcher, &ApplicationLauncher::appendMessage,
- this, &SimpleTargetRunner::appendMessage);
- connect(&m_launcher, &ApplicationLauncher::processStarted,
- this, &SimpleTargetRunner::onProcessStarted);
- connect(&m_launcher, &ApplicationLauncher::processExited,
- this, &SimpleTargetRunner::onProcessFinished);
- connect(&m_launcher, &ApplicationLauncher::error,
- this, &SimpleTargetRunner::onProcessError);
-
- const QString executable = m_runnable.executable;
- if (executable.isEmpty()) {
- reportFailure(RunControl::tr("No executable specified."));
- } else {
- m_launcher.start(m_runnable);
- }
-
- } else {
-
- connect(&m_launcher, &ApplicationLauncher::reportError,
- this, [this](const QString &msg) {
- reportFailure(msg);
- });
-
- connect(&m_launcher, &ApplicationLauncher::remoteStderr,
- this, [this](const QString &output) {
- appendMessage(output, Utils::StdErrFormatSameLine, false);
- });
-
- connect(&m_launcher, &ApplicationLauncher::remoteStdout,
- this, [this](const QString &output) {
- appendMessage(output, Utils::StdOutFormatSameLine, false);
- });
-
- connect(&m_launcher, &ApplicationLauncher::finished,
- this, [this] {
- m_launcher.disconnect(this);
- reportStopped();
- });
-
- connect(&m_launcher, &ApplicationLauncher::processStarted,
- this, [this] {
- appendMessage("Application launcher started", Utils::NormalMessageFormat);
-// reportStarted();
- });
-
- connect(&m_launcher, &ApplicationLauncher::processExited,
- this, [this] {
- m_launcher.disconnect(this);
- reportStopped();
- });
-
- connect(&m_launcher, &ApplicationLauncher::remoteProcessStarted,
- this, [this] {
- reportStarted();
- });
-
- connect(&m_launcher, &ApplicationLauncher::reportProgress,
- this, [this](const QString &progressString) {
- appendMessage(progressString, Utils::NormalMessageFormat);
- });
-
- m_launcher.start(m_runnable, device());
- }
-}
-
-void SimpleTargetRunner::stop()
-{
- m_launcher.stop();
-}
-
-void SimpleTargetRunner::onProcessStarted()
-{
- // Console processes only know their pid after being started
- ProcessHandle pid = m_launcher.applicationPID();
- runControl()->setApplicationProcessHandle(pid);
- pid.activate();
- reportStarted();
-}
-
-void SimpleTargetRunner::onProcessFinished(int exitCode, QProcess::ExitStatus status)
-{
- QString msg;
- if (status == QProcess::CrashExit)
- msg = tr("%1 crashed.");
- else
- msg = tr("%2 exited with code %1").arg(exitCode);
- appendMessage(msg.arg(m_runnable.displayName()), Utils::NormalMessageFormat);
- if (!m_stopReported) {
- m_stopReported = true;
- reportStopped();
- }
-}
-
-void SimpleTargetRunner::onProcessError(QProcess::ProcessError error)
-{
- if (error == QProcess::Timedout)
- return; // No actual change on the process side.
- QString msg = userMessageForProcessError(error, m_runnable.displayName());
- appendMessage(msg, Utils::NormalMessageFormat);
- if (!m_stopReported) {
- m_stopReported = true;
- reportStopped();
- }
-}
-
-IDevice::ConstPtr SimpleTargetRunner::device() const
-{
- return m_device;
-}
-
-void SimpleTargetRunner::setRunnable(const Runnable &runnable)
-{
- m_runnable = runnable;
-}
-
-void SimpleTargetRunner::setDevice(const IDevice::ConstPtr &device)
-{
- m_device = device;
-}
-
-// RunWorkerPrivate
-
-RunWorkerPrivate::RunWorkerPrivate(RunWorker *runWorker, RunControl *runControl)
- : q(runWorker), runControl(runControl)
-{
- runControl->d->m_workers.append(runWorker);
-}
-
-bool RunWorkerPrivate::canStart() const
-{
- if (state != RunWorkerState::Initialized)
- return false;
- for (RunWorker *worker : startDependencies) {
- QTC_ASSERT(worker, continue);
- if (worker->d->state != RunWorkerState::Done
- && worker->d->state != RunWorkerState::Running)
- return false;
- }
- return true;
-}
-
-bool RunWorkerPrivate::canStop() const
-{
- if (state != RunWorkerState::Starting && state != RunWorkerState::Running)
- return false;
- for (RunWorker *worker : stopDependencies) {
- QTC_ASSERT(worker, continue);
- if (worker->d->state != RunWorkerState::Done)
- return false;
- }
- return true;
-}
-
-void RunWorkerPrivate::timerEvent(QTimerEvent *ev)
-{
- if (ev->timerId() == startWatchdogTimerId) {
- if (startWatchdogCallback) {
- killStartWatchdog();
- startWatchdogCallback();
- } else {
- q->reportFailure(RunWorker::tr("Worker start timed out."));
- }
- return;
- }
- if (ev->timerId() == stopWatchdogTimerId) {
- if (stopWatchdogCallback) {
- killStopWatchdog();
- stopWatchdogCallback();
- } else {
- q->reportFailure(RunWorker::tr("Worker stop timed out."));
- }
- return;
- }
-}
-
-/*!
- \class ProjectExplorer::RunWorker
-
- \brief The RunWorker class encapsulates a task that forms part, or
- the whole of the operation of a tool for a certain \c RunConfiguration
- according to some \c RunMode.
-
- A typical example for a \c RunWorker is a process, either the
- application process itself, or a helper process, such as a watchdog
- or a log parser.
-
- A \c RunWorker has a simple state model covering the \c Initialized,
- \c Starting, \c Running, \c Stopping, and \c Done states.
-
- In the course of the operation of tools several \c RunWorkers
- may co-operate and form a combined state that is presented
- to the user as \c RunControl, with direct interaction made
- possible through the buttons in the \uicontrol{Application Output}
- pane.
-
- RunWorkers are typically created together with their RunControl.
- The startup order of RunWorkers under a RunControl can be
- specified by making a RunWorker dependent on others.
-
- When a RunControl starts, it calls \c initiateStart() on RunWorkers
- with fulfilled dependencies until all workers are \c Running, or in case
- of short-lived helper tasks, \c Done.
-
- A RunWorker can stop spontaneously, for example when the main application
- process ends. In this case, it typically calls \c initiateStop()
- on its RunControl, which in turn passes this to all sibling
- RunWorkers.
-
- Pressing the stop button in the \uicontrol{Application Output} pane
- also calls \c initiateStop on the RunControl.
-*/
-
-RunWorker::RunWorker(RunControl *runControl)
- : d(std::make_unique<RunWorkerPrivate>(this, runControl))
-{ }
-
-RunWorker::~RunWorker() = default;
-
-/*!
- * This function is called by the RunControl once all dependencies
- * are fulfilled.
- */
-void RunWorker::initiateStart()
-{
- d->startStartWatchdog();
- d->runControl->d->debugMessage("Initiate start for " + d->id);
- start();
-}
-
-/*!
- * This function has to be called by a RunWorker implementation
- * to notify its RunControl about the successful start of this RunWorker.
- *
- * The RunControl may start other RunWorkers in response.
- */
-void RunWorker::reportStarted()
-{
- d->killStartWatchdog();
- d->runControl->d->onWorkerStarted(this);
- emit started();
-}
-
-/*!
- * This function is called by the RunControl in its own \c initiateStop
- * implementation, which is triggered in response to pressing the
- * stop button in the \uicontrol{Application Output} pane or on direct
- * request of one of the sibling RunWorkers.
- */
-void RunWorker::initiateStop()
-{
- d->startStopWatchdog();
- d->runControl->d->debugMessage("Initiate stop for " + d->id);
- stop();
-}
-
-/*!
- * This function has to be called by a RunWorker implementation
- * to notify its RunControl about this RunWorker having stopped.
- *
- * The stop can be spontaneous, or in response to an initiateStop()
- * or an initiateFinish() call.
- *
- * The RunControl will adjust its global state in response.
- */
-void RunWorker::reportStopped()
-{
- d->killStopWatchdog();
- d->runControl->d->onWorkerStopped(this);
- emit stopped();
-}
-
-/*!
- * This function can be called by a RunWorker implementation for short-lived
- * tasks to notify its RunControl about this task being successful finished.
- * Dependent startup tasks can proceed, in cases of spontaneous or scheduled
- * stops, the effect is the same as \c reportStopped().
- *
- */
-void RunWorker::reportDone()
-{
- d->killStartWatchdog();
- d->killStopWatchdog();
- switch (d->state) {
- case RunWorkerState::Initialized:
- QTC_CHECK(false);
- d->state = RunWorkerState::Done;
- break;
- case RunWorkerState::Starting:
- reportStarted();
- reportStopped();
- break;
- case RunWorkerState::Running:
- case RunWorkerState::Stopping:
- reportStopped();
- break;
- case RunWorkerState::Done:
- break;
- }
-}
-
-/*!
- * This function can be called by a RunWorker implementation to
- * signal a problem in the operation in this worker. The
- * RunControl will start to ramp down through initiateStop().
- */
-void RunWorker::reportFailure(const QString &msg)
-{
- d->killStartWatchdog();
- d->killStopWatchdog();
- d->runControl->d->onWorkerFailed(this, msg);
-}
-
-/*!
- * Appends a message in the specified \a format to
- * the owning RunControl's \uicontrol{Application Output} pane.
- */
-void RunWorker::appendMessage(const QString &msg, OutputFormat format, bool appendNewLine)
-{
- if (!appendNewLine || msg.endsWith('\n'))
- d->runControl->appendMessage(msg, format);
- else
- d->runControl->appendMessage(msg + '\n', format);
-}
-
-IDevice::ConstPtr RunWorker::device() const
-{
- return d->runControl->device();
-}
-
-const Runnable &RunWorker::runnable() const
-{
- return d->runControl->runnable();
-}
-
-Core::Id RunWorker::runMode() const
-{
- return d->runControl->runMode();
-}
-
-void RunWorker::addStartDependency(RunWorker *dependency)
-{
- d->startDependencies.append(dependency);
-}
-
-void RunWorker::addStopDependency(RunWorker *dependency)
-{
- d->stopDependencies.append(dependency);
-}
-
-RunControl *RunWorker::runControl() const
-{
- return d->runControl;
-}
-
-void RunWorker::setId(const QString &id)
-{
- d->id = id;
-}
-
-void RunWorker::setStartTimeout(int ms, const std::function<void()> &callback)
-{
- d->startWatchdogInterval = ms;
- d->startWatchdogCallback = callback;
-}
-
-void RunWorker::setStopTimeout(int ms, const std::function<void()> &callback)
-{
- d->stopWatchdogInterval = ms;
- d->stopWatchdogCallback = callback;
-}
-
-void RunWorker::recordData(const QString &channel, const QVariant &data)
-{
- d->data[channel] = data;
-}
-
-QVariant RunWorker::recordedData(const QString &channel) const
-{
- return d->data[channel];
-}
-
-void RunWorker::setSupportsReRunning(bool reRunningSupported)
-{
- d->supportsReRunning = reRunningSupported;
-}
-
-bool RunWorker::supportsReRunning() const
-{
- return d->supportsReRunning;
-}
-
-QString RunWorker::userMessageForProcessError(QProcess::ProcessError error, const QString &program)
-{
- QString failedToStart = tr("The process failed to start.");
- QString msg = tr("An unknown error in the process occurred.");
- switch (error) {
- case QProcess::FailedToStart:
- msg = failedToStart + ' ' + tr("Either the "
- "invoked program \"%1\" is missing, or you may have insufficient "
- "permissions to invoke the program.").arg(program);
- break;
- case QProcess::Crashed:
- msg = tr("The process was ended forcefully.");
- break;
- case QProcess::Timedout:
- // "The last waitFor...() function timed out. "
- // "The state of QProcess is unchanged, and you can try calling "
- // "waitFor...() again."
- return QString(); // sic!
- case QProcess::WriteError:
- msg = tr("An error occurred when attempting to write "
- "to the process. For example, the process may not be running, "
- "or it may have closed its input channel.");
- break;
- case QProcess::ReadError:
- msg = tr("An error occurred when attempting to read from "
- "the process. For example, the process may not be running.");
- break;
- case QProcess::UnknownError:
- break;
- }
- return msg;
-}
-
-bool RunWorker::isEssential() const
-{
- return d->essential;
-}
-
-void RunWorker::setEssential(bool essential)
-{
- d->essential = essential;
-}
-
-void RunWorker::start()
-{
- reportStarted();
-}
-
-void RunWorker::stop()
-{
- reportStopped();
-}
-
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/runconfiguration.h b/src/plugins/projectexplorer/runconfiguration.h
index c0443ae07e..3e5cbc6b15 100644
--- a/src/plugins/projectexplorer/runconfiguration.h
+++ b/src/plugins/projectexplorer/runconfiguration.h
@@ -50,7 +50,7 @@ namespace Utils { class OutputFormatter; }
namespace ProjectExplorer {
class BuildConfiguration;
class GlobalOrProjectAspect;
-class Node;
+class Runnable;
class RunConfigurationFactory;
class RunConfiguration;
class RunConfigurationCreationInfo;
@@ -129,24 +129,8 @@ private:
ISettingsAspect *m_globalSettings = nullptr; // Not owned.
};
-class PROJECTEXPLORER_EXPORT Runnable
-{
-public:
- Runnable() = default;
-
- QString executable;
- QString commandLineArguments;
- QString workingDirectory;
- Utils::Environment environment;
- IDevice::ConstPtr device; // Override the kit's device. Keep unset by default.
- QHash<Core::Id, QVariant> extraData;
-
- // FIXME: Not necessarily a display name
- QString displayName() const { return executable; }
-};
-
// Documentation inside.
-class PROJECTEXPLORER_EXPORT RunConfiguration : public StatefulProjectConfiguration
+class PROJECTEXPLORER_EXPORT RunConfiguration : public ProjectConfiguration
{
Q_OBJECT
@@ -155,7 +139,10 @@ public:
bool isActive() const override;
- QString disabledReason() const override;
+ bool isEnabled() const { return m_isEnabled; }
+ void setEnabled(bool enabled);
+
+ virtual QString disabledReason() const;
virtual QWidget *createConfigurationWidget();
@@ -173,6 +160,10 @@ public:
bool fromMap(const QVariantMap &map) override;
QVariantMap toMap() const override;
+ using ExecutableGetter = std::function<Utils::FilePath()>;
+ void setExecutableGetter(const ExecutableGetter &exeGetter);
+ Utils::FilePath executable() const;
+
virtual Runnable runnable() const;
// Return a handle to the build system target that created this run configuration.
@@ -182,7 +173,6 @@ public:
BuildTargetInfo buildTargetInfo() const;
static RunConfiguration *startupRunConfiguration();
- virtual bool canRunForNode(const ProjectExplorer::Node *) const { return false; }
template <class T = ISettingsAspect> T *currentSettings(Core::Id id) const
{
@@ -200,6 +190,7 @@ public:
signals:
void requestRunActionsUpdate();
void configurationFinished();
+ void enabledChanged();
protected:
RunConfiguration(Target *target, Core::Id id);
@@ -221,7 +212,9 @@ private:
friend class RunConfigurationCreationInfo;
QString m_buildKey;
+ bool m_isEnabled = false;
std::function<Utils::OutputFormatter *(Project *)> m_outputFormatterCreator;
+ ExecutableGetter m_executableGetter;
};
class RunConfigurationCreationInfo
@@ -235,6 +228,7 @@ public:
QString buildKey;
QString displayName;
QString displayNameUniquifier;
+ Utils::FilePath projectFilePath;
CreationMode creationMode = AlwaysCreate;
bool useTerminal = false;
};
@@ -267,25 +261,13 @@ protected:
return new RunConfig(t, runConfigBaseId);
};
m_runConfigBaseId = runConfigBaseId;
- m_ownTypeChecker = [](RunConfiguration *runConfig) {
- return qobject_cast<RunConfig *>(runConfig) != nullptr;
- };
}
void addSupportedProjectType(Core::Id id);
void addSupportedTargetDeviceType(Core::Id id);
void setDecorateDisplayNames(bool on);
- template<class Worker>
- RunWorkerFactory *addRunWorkerFactory(Core::Id runMode)
- {
- return addRunWorkerFactoryHelper(runMode, [](RunControl *rc) { return new Worker(rc); });
- }
-
private:
- RunWorkerFactory *addRunWorkerFactoryHelper
- (Core::Id runMode, const std::function<RunWorker *(RunControl *)> &creator);
-
bool canHandle(Target *target) const;
friend class RunConfigurationCreationInfo;
@@ -294,8 +276,6 @@ private:
QList<Core::Id> m_supportedProjectTypes;
QList<Core::Id> m_supportedTargetDeviceTypes;
bool m_decorateDisplayNames = false;
- QList<RunWorkerFactory *> m_ownedRunWorkerFactories;
- std::function<bool(RunConfiguration *)> m_ownTypeChecker;
};
class PROJECTEXPLORER_EXPORT FixedRunConfigurationFactory : public RunConfigurationFactory
@@ -311,227 +291,4 @@ private:
const bool m_decorateTargetName;
};
-class PROJECTEXPLORER_EXPORT RunWorker : public QObject
-{
- Q_OBJECT
-
-public:
- explicit RunWorker(RunControl *runControl);
- ~RunWorker() override;
-
- RunControl *runControl() const;
-
- void addStartDependency(RunWorker *dependency);
- void addStopDependency(RunWorker *dependency);
-
- void setId(const QString &id);
-
- void setStartTimeout(int ms, const std::function<void()> &callback = {});
- void setStopTimeout(int ms, const std::function<void()> &callback = {});
-
- void recordData(const QString &channel, const QVariant &data);
- QVariant recordedData(const QString &channel) const;
-
- // Part of read-only interface of RunControl for convenience.
- void appendMessage(const QString &msg, Utils::OutputFormat format, bool appendNewLine = true);
- IDevice::ConstPtr device() const;
- const Runnable &runnable() const;
- Core::Id runMode() const;
-
- // States
- void initiateStart();
- void reportStarted();
-
- void initiateStop();
- void reportStopped();
-
- void reportDone();
-
- void reportFailure(const QString &msg = QString());
- void setSupportsReRunning(bool reRunningSupported);
- bool supportsReRunning() const;
-
- static QString userMessageForProcessError(QProcess::ProcessError, const QString &programName);
-
- bool isEssential() const;
- void setEssential(bool essential);
-
-signals:
- void started();
- void stopped();
-
-protected:
- void virtual start();
- void virtual stop();
- void virtual onFinished() {}
-
-private:
- friend class Internal::RunControlPrivate;
- friend class Internal::RunWorkerPrivate;
- const std::unique_ptr<Internal::RunWorkerPrivate> d;
-};
-
-class PROJECTEXPLORER_EXPORT RunWorkerFactory
-{
-public:
- using WorkerCreator = std::function<RunWorker *(RunControl *)>;
- using Constraint = std::function<bool(RunConfiguration *)>;
-
- RunWorkerFactory();
- virtual ~RunWorkerFactory();
-
- bool canRun(RunConfiguration *runConfiguration, Core::Id runMode) const;
-
- void setProducer(const WorkerCreator &producer);
- void addConstraint(const Constraint &constraint);
- void addSupportedRunMode(Core::Id runMode);
-
- WorkerCreator producer() const { return m_producer; }
-
-private:
- // FIXME: That's temporary until ownership has been transferred to
- // the individual plugins.
- friend class ProjectExplorerPlugin;
- static void destroyRemainingRunWorkerFactories();
-
- QList<Core::Id> m_supportedRunModes;
- QList<Constraint> m_constraints;
- WorkerCreator m_producer;
-};
-
-/**
- * A RunControl controls the running of an application or tool
- * on a target device. It controls start and stop, and handles
- * application output.
- *
- * RunControls are created by RunControlFactories.
- */
-
-class PROJECTEXPLORER_EXPORT RunControl : public QObject
-{
- Q_OBJECT
-
-public:
- RunControl(RunConfiguration *runConfiguration, Core::Id mode);
- RunControl(const IDevice::ConstPtr &device, Core::Id mode);
- ~RunControl() override;
-
- void initiateStart();
- void initiateReStart();
- void initiateStop();
- void forceStop();
- void initiateFinish();
-
- bool promptToStop(bool *optionalPrompt = nullptr) const;
- void setPromptToStop(const std::function<bool(bool *)> &promptToStop);
-
- bool supportsReRunning() const;
-
- virtual QString displayName() const;
- void setDisplayName(const QString &displayName);
-
- bool isRunning() const;
- bool isStarting() const;
- bool isStopping() const;
- bool isStopped() const;
-
- void setIcon(const Utils::Icon &icon);
- Utils::Icon icon() const;
-
- Utils::ProcessHandle applicationProcessHandle() const;
- void setApplicationProcessHandle(const Utils::ProcessHandle &handle);
- IDevice::ConstPtr device() const;
-
- RunConfiguration *runConfiguration() const;
- Project *project() const;
-
- Utils::OutputFormatter *outputFormatter() const;
- Core::Id runMode() const;
-
- const Runnable &runnable() const;
- void setRunnable(const Runnable &runnable);
-
- virtual void appendMessage(const QString &msg, Utils::OutputFormat format);
-
- static bool showPromptToStopDialog(const QString &title, const QString &text,
- const QString &stopButtonText = QString(),
- const QString &cancelButtonText = QString(),
- bool *prompt = nullptr);
-
- RunWorker *createWorker(Core::Id id);
-
- using WorkerCreator = RunWorkerFactory::WorkerCreator;
- using Constraint = RunWorkerFactory::Constraint;
-
- static void registerWorkerCreator(Core::Id id, const WorkerCreator &workerCreator);
-
- static void registerWorker(Core::Id runMode, const WorkerCreator &producer,
- const Constraint &constraint = {})
- {
- auto factory = new RunWorkerFactory;
- factory->setProducer(producer);
- factory->addSupportedRunMode(runMode);
- factory->addConstraint(constraint);
- }
- template <class Worker>
- static void registerWorker(Core::Id runMode, const Constraint &constraint)
- {
- auto factory = new RunWorkerFactory;
- factory->setProducer([](RunControl *rc) { return new Worker(rc); });
- factory->addSupportedRunMode(runMode);
- factory->addConstraint(constraint);
- }
-
- static WorkerCreator producer(RunConfiguration *runConfiguration, Core::Id runMode);
-
-signals:
- void appendMessageRequested(ProjectExplorer::RunControl *runControl,
- const QString &msg, Utils::OutputFormat format);
- void aboutToStart();
- void started();
- void stopped();
- void finished();
- void applicationProcessHandleChanged(QPrivateSignal); // Use setApplicationProcessHandle
-
-private:
- friend class RunWorker;
- friend class Internal::RunWorkerPrivate;
-
- const std::unique_ptr<Internal::RunControlPrivate> d;
-};
-
-
-/**
- * A simple TargetRunner for cases where a plain ApplicationLauncher is
- * sufficient for running purposes.
- */
-
-class PROJECTEXPLORER_EXPORT SimpleTargetRunner : public RunWorker
-{
- Q_OBJECT
-
-public:
- explicit SimpleTargetRunner(RunControl *runControl);
-
- void setRunnable(const Runnable &runnable);
-
- void setDevice(const IDevice::ConstPtr &device);
- IDevice::ConstPtr device() const;
-
-protected:
- void start() override;
- void stop() override;
-
-private:
- void onProcessStarted();
- void onProcessFinished(int exitCode, QProcess::ExitStatus status);
- void onProcessError(QProcess::ProcessError error);
-
- ApplicationLauncher m_launcher;
- Runnable m_runnable;
- IDevice::ConstPtr m_device;
- bool m_stopReported = false;
- bool m_useTerminal = false;
-};
-
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/runconfigurationaspects.cpp b/src/plugins/projectexplorer/runconfigurationaspects.cpp
index 06aa1e583e..fe890b3a29 100644
--- a/src/plugins/projectexplorer/runconfigurationaspects.cpp
+++ b/src/plugins/projectexplorer/runconfigurationaspects.cpp
@@ -56,6 +56,9 @@ TerminalAspect::TerminalAspect()
setDisplayName(tr("Terminal"));
setId("TerminalAspect");
setSettingsKey("RunConfiguration.UseTerminal");
+ calculateUseTerminal();
+ connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::settingsChanged,
+ this, &TerminalAspect::calculateUseTerminal);
}
void TerminalAspect::addToConfigurationLayout(QFormLayout *layout)
@@ -90,13 +93,16 @@ void TerminalAspect::toMap(QVariantMap &data) const
data.insert(settingsKey(), m_useTerminal);
}
-bool TerminalAspect::useTerminal() const
-{
- return m_useTerminal;
-}
-
-void TerminalAspect::setUseTerminal(bool useTerminal)
+void TerminalAspect::calculateUseTerminal()
{
+ if (m_userSet)
+ return;
+ bool useTerminal;
+ switch (ProjectExplorerPlugin::projectExplorerSettings().terminalMode) {
+ case Internal::TerminalMode::On: useTerminal = true; break;
+ case Internal::TerminalMode::Off: useTerminal = false; break;
+ case Internal::TerminalMode::Smart: useTerminal = m_useTerminalHint;
+ }
if (m_useTerminal != useTerminal) {
m_useTerminal = useTerminal;
emit changed();
@@ -105,6 +111,17 @@ void TerminalAspect::setUseTerminal(bool useTerminal)
m_checkBox->setChecked(m_useTerminal);
}
+bool TerminalAspect::useTerminal() const
+{
+ return m_useTerminal;
+}
+
+void TerminalAspect::setUseTerminalHint(bool hint)
+{
+ m_useTerminalHint = hint;
+ calculateUseTerminal();
+}
+
bool TerminalAspect::isUserSet() const
{
return m_userSet;
@@ -114,8 +131,7 @@ bool TerminalAspect::isUserSet() const
\class ProjectExplorer::WorkingDirectoryAspect
*/
-WorkingDirectoryAspect::WorkingDirectoryAspect(EnvironmentAspect *envAspect)
- : m_envAspect(envAspect)
+WorkingDirectoryAspect::WorkingDirectoryAspect()
{
setDisplayName(tr("Working Directory"));
setId("WorkingDirectoryAspect");
@@ -125,11 +141,6 @@ WorkingDirectoryAspect::WorkingDirectoryAspect(EnvironmentAspect *envAspect)
void WorkingDirectoryAspect::addToConfigurationLayout(QFormLayout *layout)
{
QTC_CHECK(!m_chooser);
- m_resetButton = new QToolButton(layout->parentWidget());
- m_resetButton->setToolTip(tr("Reset to Default"));
- m_resetButton->setIcon(Utils::Icons::RESET.icon());
- connect(m_resetButton.data(), &QAbstractButton::clicked, this, &WorkingDirectoryAspect::resetPath);
-
m_chooser = new PathChooser(layout->parentWidget());
m_chooser->setHistoryCompleter(settingsKey());
m_chooser->setExpectedKind(Utils::PathChooser::Directory);
@@ -142,6 +153,10 @@ void WorkingDirectoryAspect::addToConfigurationLayout(QFormLayout *layout)
m_resetButton->setEnabled(m_workingDirectory != m_defaultWorkingDirectory);
});
+ m_resetButton = new QToolButton(layout->parentWidget());
+ m_resetButton->setToolTip(tr("Reset to Default"));
+ m_resetButton->setIcon(Utils::Icons::RESET.icon());
+ connect(m_resetButton.data(), &QAbstractButton::clicked, this, &WorkingDirectoryAspect::resetPath);
m_resetButton->setEnabled(m_workingDirectory != m_defaultWorkingDirectory);
if (m_envAspect) {
@@ -157,6 +172,11 @@ void WorkingDirectoryAspect::addToConfigurationLayout(QFormLayout *layout)
layout->addRow(tr("Working directory:"), hbox);
}
+void WorkingDirectoryAspect::acquaintSiblings(const ProjectConfigurationAspects &siblings)
+{
+ m_envAspect = siblings.aspect<EnvironmentAspect>();
+}
+
QString WorkingDirectoryAspect::keyForDefaultWd() const
{
return settingsKey() + ".default";
@@ -169,8 +189,8 @@ void WorkingDirectoryAspect::resetPath()
void WorkingDirectoryAspect::fromMap(const QVariantMap &map)
{
- m_workingDirectory = FileName::fromString(map.value(settingsKey()).toString());
- m_defaultWorkingDirectory = FileName::fromString(map.value(keyForDefaultWd()).toString());
+ m_workingDirectory = FilePath::fromString(map.value(settingsKey()).toString());
+ m_defaultWorkingDirectory = FilePath::fromString(map.value(keyForDefaultWd()).toString());
if (m_workingDirectory.isEmpty())
m_workingDirectory = m_defaultWorkingDirectory;
@@ -187,32 +207,32 @@ void WorkingDirectoryAspect::toMap(QVariantMap &data) const
data.insert(keyForDefaultWd(), m_defaultWorkingDirectory.toString());
}
-FileName WorkingDirectoryAspect::workingDirectory(const MacroExpander *expander) const
+FilePath WorkingDirectoryAspect::workingDirectory(const MacroExpander *expander) const
{
const Utils::Environment env = m_envAspect ? m_envAspect->environment()
: Utils::Environment::systemEnvironment();
QString workingDir = m_workingDirectory.toUserOutput();
if (expander)
workingDir = expander->expandProcessArgs(workingDir);
- return FileName::fromString(PathChooser::expandedDirectory(workingDir, env, QString()));
+ return FilePath::fromString(PathChooser::expandedDirectory(workingDir, env, QString()));
}
-FileName WorkingDirectoryAspect::defaultWorkingDirectory() const
+FilePath WorkingDirectoryAspect::defaultWorkingDirectory() const
{
return m_defaultWorkingDirectory;
}
-FileName WorkingDirectoryAspect::unexpandedWorkingDirectory() const
+FilePath WorkingDirectoryAspect::unexpandedWorkingDirectory() const
{
return m_workingDirectory;
}
-void WorkingDirectoryAspect::setDefaultWorkingDirectory(const FileName &defaultWorkingDir)
+void WorkingDirectoryAspect::setDefaultWorkingDirectory(const FilePath &defaultWorkingDir)
{
if (defaultWorkingDir == m_defaultWorkingDirectory)
return;
- Utils::FileName oldDefaultDir = m_defaultWorkingDirectory;
+ Utils::FilePath oldDefaultDir = m_defaultWorkingDirectory;
m_defaultWorkingDirectory = defaultWorkingDir;
if (m_chooser)
m_chooser->setBaseFileName(m_defaultWorkingDirectory);
@@ -360,7 +380,7 @@ void ExecutableAspect::makeOverridable(const QString &overridingKey, const QStri
this, &ExecutableAspect::changed);
}
-FileName ExecutableAspect::executable() const
+FilePath ExecutableAspect::executable() const
{
if (m_alternativeExecutable && m_alternativeExecutable->isChecked())
return m_alternativeExecutable->fileName();
@@ -385,7 +405,7 @@ void ExecutableAspect::setPlaceHolderText(const QString &placeHolderText)
m_executable.setPlaceHolderText(placeHolderText);
}
-void ExecutableAspect::setExecutable(const FileName &executable)
+void ExecutableAspect::setExecutable(const FilePath &executable)
{
m_executable.setValue(executable.toString());
}
diff --git a/src/plugins/projectexplorer/runconfigurationaspects.h b/src/plugins/projectexplorer/runconfigurationaspects.h
index be40af6d29..77973f65f4 100644
--- a/src/plugins/projectexplorer/runconfigurationaspects.h
+++ b/src/plugins/projectexplorer/runconfigurationaspects.h
@@ -46,7 +46,7 @@ public:
void addToConfigurationLayout(QFormLayout *layout) override;
bool useTerminal() const;
- void setUseTerminal(bool useTerminal);
+ void setUseTerminalHint(bool useTerminal);
bool isUserSet() const;
@@ -54,6 +54,9 @@ private:
void fromMap(const QVariantMap &map) override;
void toMap(QVariantMap &map) const override;
+ void calculateUseTerminal();
+
+ bool m_useTerminalHint = false;
bool m_useTerminal = false;
bool m_userSet = false;
QPointer<QCheckBox> m_checkBox; // Owned by RunConfigWidget
@@ -64,14 +67,15 @@ class PROJECTEXPLORER_EXPORT WorkingDirectoryAspect : public ProjectConfiguratio
Q_OBJECT
public:
- explicit WorkingDirectoryAspect(EnvironmentAspect *envAspect = nullptr);
+ WorkingDirectoryAspect();
void addToConfigurationLayout(QFormLayout *layout) override;
+ void acquaintSiblings(const ProjectConfigurationAspects &) override;
- Utils::FileName workingDirectory(const Utils::MacroExpander *expander) const;
- Utils::FileName defaultWorkingDirectory() const;
- Utils::FileName unexpandedWorkingDirectory() const;
- void setDefaultWorkingDirectory(const Utils::FileName &defaultWorkingDir);
+ Utils::FilePath workingDirectory(const Utils::MacroExpander *expander) const;
+ Utils::FilePath defaultWorkingDirectory() const;
+ Utils::FilePath unexpandedWorkingDirectory() const;
+ void setDefaultWorkingDirectory(const Utils::FilePath &defaultWorkingDir);
Utils::PathChooser *pathChooser() const;
private:
@@ -81,9 +85,9 @@ private:
void resetPath();
QString keyForDefaultWd() const;
- EnvironmentAspect * const m_envAspect = nullptr;
- Utils::FileName m_workingDirectory;
- Utils::FileName m_defaultWorkingDirectory;
+ EnvironmentAspect *m_envAspect = nullptr;
+ Utils::FilePath m_workingDirectory;
+ Utils::FilePath m_defaultWorkingDirectory;
QPointer<Utils::PathChooser> m_chooser;
QPointer<QToolButton> m_resetButton;
};
@@ -137,8 +141,8 @@ public:
ExecutableAspect();
~ExecutableAspect() override;
- Utils::FileName executable() const;
- void setExecutable(const Utils::FileName &executable);
+ Utils::FilePath executable() const;
+ void setExecutable(const Utils::FilePath &executable);
void setSettingsKey(const QString &key);
void makeOverridable(const QString &overridingKey, const QString &useOverridableKey);
diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp
new file mode 100644
index 0000000000..f90a8fd48c
--- /dev/null
+++ b/src/plugins/projectexplorer/runcontrol.cpp
@@ -0,0 +1,1563 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "runcontrol.h"
+
+#include "project.h"
+#include "target.h"
+#include "toolchain.h"
+#include "abi.h"
+#include "buildconfiguration.h"
+#include "environmentaspect.h"
+#include "kitinformation.h"
+#include "runconfigurationaspects.h"
+#include "session.h"
+#include "kitinformation.h"
+
+#include <utils/algorithm.h>
+#include <utils/checkablemessagebox.h>
+#include <utils/detailswidget.h>
+#include <utils/outputformatter.h>
+#include <utils/qtcassert.h>
+#include <utils/utilsicons.h>
+
+#include <coreplugin/icontext.h>
+#include <coreplugin/icore.h>
+#include <coreplugin/variablechooser.h>
+
+#include <QDir>
+#include <QFormLayout>
+#include <QHash>
+#include <QPushButton>
+#include <QTimer>
+#include <QLoggingCategory>
+#include <QSettings>
+
+#if defined (WITH_JOURNALD)
+#include "journaldwatcher.h"
+#endif
+
+using namespace Utils;
+using namespace ProjectExplorer::Internal;
+
+namespace {
+Q_LOGGING_CATEGORY(statesLog, "qtc.projectmanager.states", QtWarningMsg)
+}
+
+namespace ProjectExplorer {
+
+// RunWorkerFactory
+
+static QList<RunWorkerFactory *> g_runWorkerFactories;
+
+RunWorkerFactory::RunWorkerFactory()
+{
+ g_runWorkerFactories.append(this);
+}
+
+RunWorkerFactory::~RunWorkerFactory()
+{
+ g_runWorkerFactories.removeOne(this);
+}
+
+bool RunWorkerFactory::canRun(RunConfiguration *runConfiguration, Core::Id runMode) const
+{
+ if (!m_supportedRunModes.contains(runMode))
+ return false;
+
+ if (!m_supportedRunConfigurations.isEmpty()) {
+ if (!m_supportedRunConfigurations.contains(runConfiguration->id()))
+ return false;
+ }
+
+ for (const Constraint &constraint : m_constraints) {
+ if (!constraint(runConfiguration))
+ return false;
+ }
+
+ return true;
+}
+
+void RunWorkerFactory::setProducer(const WorkerCreator &producer)
+{
+ m_producer = producer;
+}
+
+void RunWorkerFactory::addConstraint(const Constraint &constraint)
+{
+ // Default constructed Constraints are not worth keeping.
+ // FIXME: Make it a QTC_ASSERT once there is no code path
+ // using this "feature" anymore.
+ if (!constraint)
+ return;
+ m_constraints.append(constraint);
+}
+
+void RunWorkerFactory::addSupportedRunMode(Core::Id runMode)
+{
+ m_supportedRunModes.append(runMode);
+}
+
+void RunWorkerFactory::setSupportedRunConfigurations(const QList<Core::Id> &ids)
+{
+ m_supportedRunConfigurations = ids;
+}
+
+void RunWorkerFactory::addSupportedRunConfiguration(Core::Id id)
+{
+ m_supportedRunConfigurations.append(id);
+}
+
+void RunWorkerFactory::destroyRemainingRunWorkerFactories()
+{
+ qDeleteAll(g_runWorkerFactories);
+}
+
+/*!
+ \class ProjectExplorer::RunControl
+ \brief The RunControl class instances represent one item that is run.
+*/
+
+/*!
+ \fn QIcon ProjectExplorer::RunControl::icon() const
+ Returns the icon to be shown in the Outputwindow.
+
+ TODO the icon differs currently only per "mode", so this is more flexible
+ than it needs to be.
+*/
+
+
+namespace Internal {
+
+enum class RunWorkerState
+{
+ Initialized, Starting, Running, Stopping, Done
+};
+
+static QString stateName(RunWorkerState s)
+{
+# define SN(x) case x: return QLatin1String(#x);
+ switch (s) {
+ SN(RunWorkerState::Initialized)
+ SN(RunWorkerState::Starting)
+ SN(RunWorkerState::Running)
+ SN(RunWorkerState::Stopping)
+ SN(RunWorkerState::Done)
+ }
+ return QString("<unknown: %1>").arg(int(s));
+# undef SN
+}
+
+class RunWorkerPrivate : public QObject
+{
+public:
+ RunWorkerPrivate(RunWorker *runWorker, RunControl *runControl);
+
+ bool canStart() const;
+ bool canStop() const;
+ void timerEvent(QTimerEvent *ev) override;
+
+ void killStartWatchdog()
+ {
+ if (startWatchdogTimerId != -1) {
+ killTimer(startWatchdogTimerId);
+ startWatchdogTimerId = -1;
+ }
+ }
+
+ void killStopWatchdog()
+ {
+ if (stopWatchdogTimerId != -1) {
+ killTimer(stopWatchdogTimerId);
+ stopWatchdogTimerId = -1;
+ }
+ }
+
+ void startStartWatchdog()
+ {
+ killStartWatchdog();
+ killStopWatchdog();
+
+ if (startWatchdogInterval != 0)
+ startWatchdogTimerId = startTimer(startWatchdogInterval);
+ }
+
+ void startStopWatchdog()
+ {
+ killStopWatchdog();
+ killStartWatchdog();
+
+ if (stopWatchdogInterval != 0)
+ stopWatchdogTimerId = startTimer(stopWatchdogInterval);
+ }
+
+ RunWorker *q;
+ RunWorkerState state = RunWorkerState::Initialized;
+ const QPointer<RunControl> runControl;
+ QList<RunWorker *> startDependencies;
+ QList<RunWorker *> stopDependencies;
+ QString id;
+
+ QVariantMap data;
+ int startWatchdogInterval = 0;
+ int startWatchdogTimerId = -1;
+ std::function<void()> startWatchdogCallback;
+ int stopWatchdogInterval = 0; // 5000;
+ int stopWatchdogTimerId = -1;
+ std::function<void()> stopWatchdogCallback;
+ bool supportsReRunning = true;
+ bool essential = false;
+};
+
+enum class RunControlState
+{
+ Initialized, // Default value after creation.
+ Starting, // Actual process/tool starts.
+ Running, // All good and running.
+ Stopping, // initiateStop() was called, stop application/tool
+ Stopped, // all good, but stopped. Can possibly be re-started
+ Finishing, // Application tab manually closed
+ Finished // Final state, will self-destruct with deleteLater()
+};
+
+static QString stateName(RunControlState s)
+{
+# define SN(x) case x: return QLatin1String(#x);
+ switch (s) {
+ SN(RunControlState::Initialized)
+ SN(RunControlState::Starting)
+ SN(RunControlState::Running)
+ SN(RunControlState::Stopping)
+ SN(RunControlState::Stopped)
+ SN(RunControlState::Finishing)
+ SN(RunControlState::Finished)
+ }
+ return QString("<unknown: %1>").arg(int(s));
+# undef SN
+}
+
+class RunControlPrivate : public QObject
+{
+public:
+ RunControlPrivate(RunControl *parent, Core::Id mode)
+ : q(parent), runMode(mode)
+ {
+ icon = Icons::RUN_SMALL_TOOLBAR;
+ outputFormatter = new OutputFormatter();
+ }
+
+ ~RunControlPrivate() override
+ {
+ QTC_CHECK(state == RunControlState::Finished || state == RunControlState::Initialized);
+ disconnect();
+ q = nullptr;
+ qDeleteAll(m_workers);
+ m_workers.clear();
+ delete outputFormatter;
+ }
+
+ Q_ENUM(RunControlState)
+
+ void checkState(RunControlState expectedState);
+ void setState(RunControlState state);
+
+ void debugMessage(const QString &msg);
+
+ void initiateStart();
+ void initiateReStart();
+ void continueStart();
+ void initiateStop();
+ void forceStop();
+ void continueStopOrFinish();
+ void initiateFinish();
+
+ void onWorkerStarted(RunWorker *worker);
+ void onWorkerStopped(RunWorker *worker);
+ void onWorkerFailed(RunWorker *worker, const QString &msg);
+
+ void showError(const QString &msg);
+
+ static bool isAllowedTransition(RunControlState from, RunControlState to);
+ bool supportsReRunning() const;
+
+ RunControl *q;
+ QString displayName;
+ Runnable runnable;
+ IDevice::ConstPtr device;
+ Core::Id runMode;
+ Utils::Icon icon;
+ MacroExpander *macroExpander;
+ QPointer<RunConfiguration> runConfiguration; // Not owned. Avoid use.
+ 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;
+
+ // A handle to the actual application process.
+ Utils::ProcessHandle applicationProcessHandle;
+
+ RunControlState state = RunControlState::Initialized;
+
+ QList<QPointer<RunWorker>> m_workers;
+};
+
+} // Internal
+
+using namespace Internal;
+
+RunControl::RunControl(Core::Id mode) :
+ d(std::make_unique<RunControlPrivate>(this, mode))
+{
+}
+
+void RunControl::setRunConfiguration(RunConfiguration *runConfig)
+{
+ QTC_ASSERT(runConfig, return);
+ QTC_CHECK(!d->runConfiguration);
+ d->runConfiguration = runConfig;
+ d->runnable = runConfig->runnable();
+ d->displayName = runConfig->displayName();
+ if (auto outputFormatter = runConfig->createOutputFormatter()) {
+ delete d->outputFormatter;
+ d->outputFormatter = outputFormatter;
+ }
+ d->macroExpander = runConfig->macroExpander();
+ setTarget(runConfig->target());
+}
+
+void RunControl::setTarget(Target *target)
+{
+ QTC_ASSERT(target, return);
+ QTC_CHECK(!d->target);
+ d->target = target;
+ setKit(target->kit());
+ d->project = target->project();
+}
+
+void RunControl::setKit(Kit *kit)
+{
+ QTC_ASSERT(kit, return);
+ QTC_CHECK(!d->kit);
+ d->kit = kit;
+
+ if (d->runnable.device)
+ setDevice(d->runnable.device);
+ else
+ setDevice(DeviceKitAspect::device(kit));
+}
+
+void RunControl::setDevice(const IDevice::ConstPtr &device)
+{
+ QTC_CHECK(!d->device);
+ d->device = device;
+#ifdef WITH_JOURNALD
+ if (!device.isNull() && device->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) {
+ JournaldWatcher::instance()->subscribe(this, [this](const JournaldWatcher::LogEntry &entry) {
+
+ if (entry.value("_MACHINE_ID") != JournaldWatcher::instance()->machineId())
+ return;
+
+ const QByteArray pid = entry.value("_PID");
+ if (pid.isEmpty())
+ return;
+
+ const qint64 pidNum = static_cast<qint64>(QString::fromLatin1(pid).toInt());
+ if (pidNum != d->applicationProcessHandle.pid())
+ return;
+
+ const QString message = QString::fromUtf8(entry.value("MESSAGE")) + "\n";
+ appendMessage(message, Utils::OutputFormat::LogMessageFormat);
+ });
+ }
+#endif
+}
+
+RunControl::~RunControl()
+{
+#ifdef WITH_JOURNALD
+ JournaldWatcher::instance()->unsubscribe(this);
+#endif
+}
+
+void RunControl::initiateStart()
+{
+ emit aboutToStart();
+ d->initiateStart();
+}
+
+void RunControl::initiateReStart()
+{
+ emit aboutToStart();
+ d->initiateReStart();
+}
+
+void RunControl::initiateStop()
+{
+ d->initiateStop();
+}
+
+void RunControl::forceStop()
+{
+ d->forceStop();
+}
+
+void RunControl::initiateFinish()
+{
+ QTimer::singleShot(0, d.get(), &RunControlPrivate::initiateFinish);
+}
+
+using WorkerCreators = QHash<Core::Id, RunControl::WorkerCreator>;
+
+static WorkerCreators &theWorkerCreators()
+{
+ static WorkerCreators creators;
+ return creators;
+}
+
+void RunControl::registerWorkerCreator(Core::Id id, const WorkerCreator &workerCreator)
+{
+ theWorkerCreators().insert(id, workerCreator);
+ auto keys = theWorkerCreators().keys();
+ Q_UNUSED(keys);
+}
+
+RunWorker *RunControl::createWorker(Core::Id id)
+{
+ auto keys = theWorkerCreators().keys();
+ Q_UNUSED(keys);
+ WorkerCreator creator = theWorkerCreators().value(id);
+ if (creator)
+ return creator(this);
+ creator = device()->workerCreator(id);
+ if (creator)
+ return creator(this);
+ return nullptr;
+}
+
+bool RunControl::createMainWorker()
+{
+ const auto canRun = std::bind(&RunWorkerFactory::canRun, std::placeholders::_1,
+ d->runConfiguration, d->runMode);
+ const QList<RunWorkerFactory *> candidates = Utils::filtered(g_runWorkerFactories, canRun);
+ // There might be combinations that cannot run. But that should have been checked
+ // with canRun below.
+ QTC_ASSERT(!candidates.empty(), return false);
+
+ // There should be at most one top-level producer feeling responsible per combination.
+ // Breaking a tie should be done by tightening the restrictions on one of them.
+ QTC_CHECK(candidates.size() == 1);
+ return candidates.front()->producer()(this) != nullptr;
+}
+
+bool RunControl::canRun(RunConfiguration *runConfig, Core::Id runMode)
+{
+ const auto check = std::bind(&RunWorkerFactory::canRun, std::placeholders::_1, runConfig, runMode);
+ return Utils::contains(g_runWorkerFactories, check);
+}
+
+void RunControlPrivate::initiateStart()
+{
+ checkState(RunControlState::Initialized);
+ setState(RunControlState::Starting);
+ debugMessage("Queue: Starting");
+
+ continueStart();
+}
+
+void RunControlPrivate::initiateReStart()
+{
+ checkState(RunControlState::Stopped);
+
+ // Re-set worked on re-runs.
+ for (RunWorker *worker : m_workers) {
+ if (worker->d->state == RunWorkerState::Done)
+ worker->d->state = RunWorkerState::Initialized;
+ }
+
+ setState(RunControlState::Starting);
+ debugMessage("Queue: ReStarting");
+
+ continueStart();
+}
+
+void RunControlPrivate::continueStart()
+{
+ checkState(RunControlState::Starting);
+ bool allDone = true;
+ debugMessage("Looking for next worker");
+ for (RunWorker *worker : m_workers) {
+ if (worker) {
+ const QString &workerId = worker->d->id;
+ debugMessage(" Examining worker " + workerId);
+ switch (worker->d->state) {
+ case RunWorkerState::Initialized:
+ debugMessage(" " + workerId + " is not done yet.");
+ if (worker->d->canStart()) {
+ debugMessage("Starting " + workerId);
+ worker->d->state = RunWorkerState::Starting;
+ QTimer::singleShot(0, worker, &RunWorker::initiateStart);
+ return;
+ }
+ allDone = false;
+ debugMessage(" " + workerId + " cannot start.");
+ break;
+ case RunWorkerState::Starting:
+ debugMessage(" " + workerId + " currently starting");
+ allDone = false;
+ break;
+ case RunWorkerState::Running:
+ debugMessage(" " + workerId + " currently running");
+ break;
+ case RunWorkerState::Stopping:
+ debugMessage(" " + workerId + " currently stopping");
+ continue;
+ case RunWorkerState::Done:
+ debugMessage(" " + workerId + " was done before");
+ break;
+ }
+ } else {
+ debugMessage("Found unknown deleted worker while starting");
+ }
+ }
+ if (allDone)
+ setState(RunControlState::Running);
+}
+
+void RunControlPrivate::initiateStop()
+{
+ if (state != RunControlState::Starting && state != RunControlState::Running)
+ qDebug() << "Unexpected initiateStop() in state" << stateName(state);
+
+ setState(RunControlState::Stopping);
+ debugMessage("Queue: Stopping for all workers");
+
+ continueStopOrFinish();
+}
+
+void RunControlPrivate::continueStopOrFinish()
+{
+ bool allDone = true;
+
+ auto queueStop = [this](RunWorker *worker, const QString &message) {
+ if (worker->d->canStop()) {
+ debugMessage(message);
+ worker->d->state = RunWorkerState::Stopping;
+ QTimer::singleShot(0, worker, &RunWorker::initiateStop);
+ } else {
+ debugMessage(" " + worker->d->id + " is waiting for dependent workers to stop");
+ }
+ };
+
+ for (RunWorker *worker : m_workers) {
+ if (worker) {
+ const QString &workerId = worker->d->id;
+ debugMessage(" Examining worker " + workerId);
+ switch (worker->d->state) {
+ case RunWorkerState::Initialized:
+ debugMessage(" " + workerId + " was Initialized, setting to Done");
+ worker->d->state = RunWorkerState::Done;
+ break;
+ case RunWorkerState::Stopping:
+ debugMessage(" " + workerId + " was already Stopping. Keeping it that way");
+ allDone = false;
+ break;
+ case RunWorkerState::Starting:
+ queueStop(worker, " " + workerId + " was Starting, queuing stop");
+ allDone = false;
+ break;
+ case RunWorkerState::Running:
+ queueStop(worker, " " + workerId + " was Running, queuing stop");
+ allDone = false;
+ break;
+ case RunWorkerState::Done:
+ debugMessage(" " + workerId + " was Done. Good.");
+ break;
+ }
+ } else {
+ debugMessage("Found unknown deleted worker");
+ }
+ }
+
+ RunControlState targetState;
+ if (state == RunControlState::Finishing) {
+ targetState = RunControlState::Finished;
+ } else {
+ checkState(RunControlState::Stopping);
+ targetState = RunControlState::Stopped;
+ }
+
+ if (allDone) {
+ debugMessage("All Stopped");
+ setState(targetState);
+ } else {
+ debugMessage("Not all workers Stopped. Waiting...");
+ }
+}
+
+void RunControlPrivate::forceStop()
+{
+ if (state == RunControlState::Finished) {
+ debugMessage("Was finished, too late to force Stop");
+ return;
+ }
+ for (RunWorker *worker : m_workers) {
+ if (worker) {
+ const QString &workerId = worker->d->id;
+ debugMessage(" Examining worker " + workerId);
+ switch (worker->d->state) {
+ case RunWorkerState::Initialized:
+ debugMessage(" " + workerId + " was Initialized, setting to Done");
+ break;
+ case RunWorkerState::Stopping:
+ debugMessage(" " + workerId + " was already Stopping. Set it forcefully to Done.");
+ break;
+ case RunWorkerState::Starting:
+ debugMessage(" " + workerId + " was Starting. Set it forcefully to Done.");
+ break;
+ case RunWorkerState::Running:
+ debugMessage(" " + workerId + " was Running. Set it forcefully to Done.");
+ break;
+ case RunWorkerState::Done:
+ debugMessage(" " + workerId + " was Done. Good.");
+ break;
+ }
+ worker->d->state = RunWorkerState::Done;
+ } else {
+ debugMessage("Found unknown deleted worker");
+ }
+ }
+
+ setState(RunControlState::Stopped);
+ debugMessage("All Stopped");
+}
+
+void RunControlPrivate::initiateFinish()
+{
+ setState(RunControlState::Finishing);
+ debugMessage("Ramping down");
+
+ continueStopOrFinish();
+}
+
+void RunControlPrivate::onWorkerStarted(RunWorker *worker)
+{
+ worker->d->state = RunWorkerState::Running;
+
+ if (state == RunControlState::Starting) {
+ debugMessage(worker->d->id + " start succeeded");
+ continueStart();
+ return;
+ }
+ showError(RunControl::tr("Unexpected run control state %1 when worker %2 started.")
+ .arg(stateName(state))
+ .arg(worker->d->id));
+}
+
+void RunControlPrivate::onWorkerFailed(RunWorker *worker, const QString &msg)
+{
+ worker->d->state = RunWorkerState::Done;
+
+ showError(msg);
+ switch (state) {
+ case RunControlState::Initialized:
+ // FIXME 1: We don't have an output pane yet, so use some other mechanism for now.
+ // FIXME 2: Translation...
+ QMessageBox::critical(Core::ICore::dialogParent(),
+ QCoreApplication::translate("TaskHub", "Error"),
+ QString("Failure during startup. Aborting.") + "<p>" + msg);
+ continueStopOrFinish();
+ break;
+ case RunControlState::Starting:
+ case RunControlState::Running:
+ initiateStop();
+ break;
+ case RunControlState::Stopping:
+ case RunControlState::Finishing:
+ continueStopOrFinish();
+ break;
+ case RunControlState::Stopped:
+ case RunControlState::Finished:
+ QTC_CHECK(false); // Should not happen.
+ continueStopOrFinish();
+ break;
+ }
+}
+
+void RunControlPrivate::onWorkerStopped(RunWorker *worker)
+{
+ const QString &workerId = worker->d->id;
+ switch (worker->d->state) {
+ case RunWorkerState::Running:
+ // That was a spontaneous stop.
+ worker->d->state = RunWorkerState::Done;
+ debugMessage(workerId + " stopped spontaneously.");
+ break;
+ case RunWorkerState::Stopping:
+ worker->d->state = RunWorkerState::Done;
+ debugMessage(workerId + " stopped expectedly.");
+ break;
+ case RunWorkerState::Done:
+ worker->d->state = RunWorkerState::Done;
+ debugMessage(workerId + " stopped twice. Huh? But harmless.");
+ return; // Sic!
+ default:
+ debugMessage(workerId + " stopped unexpectedly in state"
+ + stateName(worker->d->state));
+ worker->d->state = RunWorkerState::Done;
+ break;
+ }
+
+ if (state == RunControlState::Finishing || state == RunControlState::Stopping) {
+ continueStopOrFinish();
+ return;
+ } else if (worker->isEssential()) {
+ debugMessage(workerId + " is essential. Stopping all others.");
+ initiateStop();
+ return;
+ }
+
+ for (RunWorker *dependent : worker->d->stopDependencies) {
+ switch (dependent->d->state) {
+ case RunWorkerState::Done:
+ break;
+ case RunWorkerState::Initialized:
+ dependent->d->state = RunWorkerState::Done;
+ break;
+ default:
+ debugMessage("Killing " + dependent->d->id + " as it depends on stopped " + workerId);
+ dependent->d->state = RunWorkerState::Stopping;
+ QTimer::singleShot(0, dependent, &RunWorker::initiateStop);
+ break;
+ }
+ }
+
+ debugMessage("Checking whether all stopped");
+ bool allDone = true;
+ for (RunWorker *worker : m_workers) {
+ if (worker) {
+ const QString &workerId = worker->d->id;
+ debugMessage(" Examining worker " + workerId);
+ switch (worker->d->state) {
+ case RunWorkerState::Initialized:
+ debugMessage(" " + workerId + " was Initialized.");
+ break;
+ case RunWorkerState::Starting:
+ debugMessage(" " + workerId + " was Starting, waiting for its response");
+ allDone = false;
+ break;
+ case RunWorkerState::Running:
+ debugMessage(" " + workerId + " was Running, waiting for its response");
+ allDone = false;
+ break;
+ case RunWorkerState::Stopping:
+ debugMessage(" " + workerId + " was already Stopping. Keeping it that way");
+ allDone = false;
+ break;
+ case RunWorkerState::Done:
+ debugMessage(" " + workerId + " was Done. Good.");
+ break;
+ }
+ } else {
+ debugMessage("Found unknown deleted worker");
+ }
+ }
+
+ if (allDone) {
+ if (state == RunControlState::Stopped) {
+ debugMessage("All workers stopped, but runControl was already stopped.");
+ } else {
+ debugMessage("All workers stopped. Set runControl to Stopped");
+ setState(RunControlState::Stopped);
+ }
+ } else {
+ debugMessage("Not all workers stopped. Waiting...");
+ }
+}
+
+void RunControlPrivate::showError(const QString &msg)
+{
+ if (!msg.isEmpty())
+ q->appendMessage(msg + '\n', ErrorMessageFormat);
+}
+
+Utils::OutputFormatter *RunControl::outputFormatter() const
+{
+ return d->outputFormatter;
+}
+
+Core::Id RunControl::runMode() const
+{
+ return d->runMode;
+}
+
+const Runnable &RunControl::runnable() const
+{
+ return d->runnable;
+}
+
+void RunControl::setRunnable(const Runnable &runnable)
+{
+ d->runnable = runnable;
+}
+
+QString RunControl::displayName() const
+{
+ return d->displayName;
+}
+
+void RunControl::setDisplayName(const QString &displayName)
+{
+ d->displayName = displayName;
+}
+
+void RunControl::setIcon(const Utils::Icon &icon)
+{
+ d->icon = icon;
+}
+
+Utils::Icon RunControl::icon() const
+{
+ return d->icon;
+}
+
+IDevice::ConstPtr RunControl::device() const
+{
+ return d->device;
+}
+
+RunConfiguration *RunControl::runConfiguration() const
+{
+ return d->runConfiguration.data();
+}
+
+Target *RunControl::target() const
+{
+ return d->target;
+}
+
+Project *RunControl::project() const
+{
+ return d->project;
+}
+
+Kit *RunControl::kit() const
+{
+ return d->kit;
+}
+
+MacroExpander *RunControl::macroExpander() const
+{
+ return d->macroExpander;
+}
+
+ProjectConfigurationAspect *RunControl::aspect(Core::Id id) const
+{
+ return d->runConfiguration ? d->runConfiguration->aspect(id) : nullptr;
+}
+
+ISettingsAspect *RunControl::settings(Core::Id id) const
+{
+ return d->runConfiguration ? d->runConfiguration->currentSettings(id) : nullptr;
+}
+
+QString RunControl::buildKey() const
+{
+ return d->runConfiguration ? d->runConfiguration->buildKey() : QString();
+}
+
+BuildTargetInfo RunControl::buildTargetInfo() const
+{
+ return d->runConfiguration->buildTargetInfo();
+}
+
+/*!
+ A handle to the application process.
+
+ This is typically a process id, but should be treated as
+ opaque handle to the process controled by this \c RunControl.
+*/
+
+ProcessHandle RunControl::applicationProcessHandle() const
+{
+ return d->applicationProcessHandle;
+}
+
+void RunControl::setApplicationProcessHandle(const ProcessHandle &handle)
+{
+ if (d->applicationProcessHandle != handle) {
+ d->applicationProcessHandle = handle;
+ emit applicationProcessHandleChanged(QPrivateSignal());
+ }
+}
+
+/*!
+ Prompts to stop. If \a optionalPrompt is passed, a \gui {Do not ask again}
+ checkbox is displayed and the result is returned in \a *optionalPrompt.
+*/
+
+bool RunControl::promptToStop(bool *optionalPrompt) const
+{
+ QTC_ASSERT(isRunning(), return true);
+ if (optionalPrompt && !*optionalPrompt)
+ return true;
+
+ // Overridden.
+ if (d->promptToStop)
+ return d->promptToStop(optionalPrompt);
+
+ const QString msg = tr("<html><head/><body><center><i>%1</i> is still running.<center/>"
+ "<center>Force it to quit?</center></body></html>").arg(displayName());
+ return showPromptToStopDialog(tr("Application Still Running"), msg,
+ tr("Force &Quit"), tr("&Keep Running"),
+ optionalPrompt);
+}
+
+void RunControl::setPromptToStop(const std::function<bool (bool *)> &promptToStop)
+{
+ d->promptToStop = promptToStop;
+}
+
+bool RunControl::supportsReRunning() const
+{
+ return d->supportsReRunning();
+}
+
+bool RunControlPrivate::supportsReRunning() const
+{
+ for (RunWorker *worker : m_workers) {
+ if (!worker->d->supportsReRunning)
+ return false;
+ if (worker->d->state != RunWorkerState::Done)
+ return false;
+ }
+ return true;
+}
+
+bool RunControl::isRunning() const
+{
+ return d->state == RunControlState::Running;
+}
+
+bool RunControl::isStarting() const
+{
+ return d->state == RunControlState::Starting;
+}
+
+bool RunControl::isStopping() const
+{
+ return d->state == RunControlState::Stopping;
+}
+
+bool RunControl::isStopped() const
+{
+ return d->state == RunControlState::Stopped;
+}
+
+/*!
+ Prompts to terminate the application with the \gui {Do not ask again}
+ checkbox.
+*/
+
+bool RunControl::showPromptToStopDialog(const QString &title,
+ const QString &text,
+ const QString &stopButtonText,
+ const QString &cancelButtonText,
+ bool *prompt)
+{
+ // Show a question message box where user can uncheck this
+ // question for this class.
+ Utils::CheckableMessageBox messageBox(Core::ICore::mainWindow());
+ messageBox.setWindowTitle(title);
+ messageBox.setText(text);
+ messageBox.setStandardButtons(QDialogButtonBox::Yes|QDialogButtonBox::Cancel);
+ if (!stopButtonText.isEmpty())
+ messageBox.button(QDialogButtonBox::Yes)->setText(stopButtonText);
+ if (!cancelButtonText.isEmpty())
+ messageBox.button(QDialogButtonBox::Cancel)->setText(cancelButtonText);
+ messageBox.setDefaultButton(QDialogButtonBox::Yes);
+ if (prompt) {
+ messageBox.setCheckBoxText(Utils::CheckableMessageBox::msgDoNotAskAgain());
+ messageBox.setChecked(false);
+ } else {
+ messageBox.setCheckBoxVisible(false);
+ }
+ messageBox.exec();
+ const bool close = messageBox.clickedStandardButton() == QDialogButtonBox::Yes;
+ if (close && prompt && messageBox.isChecked())
+ *prompt = false;
+ return close;
+}
+
+bool RunControlPrivate::isAllowedTransition(RunControlState from, RunControlState to)
+{
+ switch (from) {
+ case RunControlState::Initialized:
+ return to == RunControlState::Starting
+ || to == RunControlState::Finishing;
+ case RunControlState::Starting:
+ return to == RunControlState::Running
+ || to == RunControlState::Stopping
+ || to == RunControlState::Finishing;
+ case RunControlState::Running:
+ return to == RunControlState::Stopping
+ || to == RunControlState::Stopped
+ || to == RunControlState::Finishing;
+ case RunControlState::Stopping:
+ return to == RunControlState::Stopped
+ || to == RunControlState::Finishing;
+ case RunControlState::Stopped:
+ return to == RunControlState::Finishing;
+ case RunControlState::Finishing:
+ return to == RunControlState::Finished;
+ case RunControlState::Finished:
+ return false;
+ }
+ return false;
+}
+
+void RunControlPrivate::checkState(RunControlState expectedState)
+{
+ if (state != expectedState)
+ qDebug() << "Unexpected run control state " << stateName(expectedState)
+ << " have: " << stateName(state);
+}
+
+void RunControlPrivate::setState(RunControlState newState)
+{
+ if (!isAllowedTransition(state, newState))
+ qDebug() << "Invalid run control state transition from " << stateName(state)
+ << " to " << stateName(newState);
+
+ state = newState;
+
+ debugMessage("Entering state " + stateName(newState));
+
+ // Extra reporting.
+ switch (state) {
+ case RunControlState::Running:
+ emit q->started();
+ break;
+ case RunControlState::Stopped:
+ q->setApplicationProcessHandle(Utils::ProcessHandle());
+ emit q->stopped();
+ break;
+ case RunControlState::Finished:
+ emit q->finished();
+ debugMessage("All finished. Deleting myself");
+ q->deleteLater();
+ break;
+ default:
+ break;
+ }
+}
+
+void RunControlPrivate::debugMessage(const QString &msg)
+{
+ qCDebug(statesLog()) << msg;
+}
+
+// SimpleTargetRunner
+
+SimpleTargetRunner::SimpleTargetRunner(RunControl *runControl)
+ : RunWorker(runControl)
+{
+ setId("SimpleTargetRunner");
+ m_runnable = runControl->runnable(); // Default value. Can be overridden using setRunnable.
+ m_device = runControl->device(); // Default value. Can be overridden using setDevice.
+ if (auto terminalAspect = runControl->aspect<TerminalAspect>())
+ m_useTerminal = terminalAspect->useTerminal();
+}
+
+void SimpleTargetRunner::start()
+{
+ m_stopReported = false;
+ m_launcher.disconnect(this);
+ m_launcher.setUseTerminal(m_useTerminal);
+
+ const bool isDesktop = m_device.isNull()
+ || m_device->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE;
+ const QString rawDisplayName = m_runnable.displayName();
+ const QString displayName = isDesktop
+ ? QDir::toNativeSeparators(rawDisplayName)
+ : rawDisplayName;
+ const QString msg = RunControl::tr("Starting %1 %2...")
+ .arg(displayName).arg(m_runnable.commandLineArguments);
+ appendMessage(msg, Utils::NormalMessageFormat);
+
+ if (isDesktop) {
+
+ connect(&m_launcher, &ApplicationLauncher::appendMessage,
+ this, &SimpleTargetRunner::appendMessage);
+ connect(&m_launcher, &ApplicationLauncher::processStarted,
+ this, &SimpleTargetRunner::onProcessStarted);
+ connect(&m_launcher, &ApplicationLauncher::processExited,
+ this, &SimpleTargetRunner::onProcessFinished);
+ connect(&m_launcher, &ApplicationLauncher::error,
+ this, &SimpleTargetRunner::onProcessError);
+
+ const QString executable = m_runnable.executable;
+ if (executable.isEmpty()) {
+ reportFailure(RunControl::tr("No executable specified."));
+ } else {
+ m_launcher.start(m_runnable);
+ }
+
+ } else {
+
+ connect(&m_launcher, &ApplicationLauncher::reportError,
+ this, [this](const QString &msg) {
+ reportFailure(msg);
+ });
+
+ connect(&m_launcher, &ApplicationLauncher::remoteStderr,
+ this, [this](const QString &output) {
+ appendMessage(output, Utils::StdErrFormatSameLine, false);
+ });
+
+ connect(&m_launcher, &ApplicationLauncher::remoteStdout,
+ this, [this](const QString &output) {
+ appendMessage(output, Utils::StdOutFormatSameLine, false);
+ });
+
+ connect(&m_launcher, &ApplicationLauncher::finished,
+ this, [this] {
+ m_launcher.disconnect(this);
+ reportStopped();
+ });
+
+ connect(&m_launcher, &ApplicationLauncher::processStarted,
+ this, [this] {
+ appendMessage("Application launcher started", Utils::NormalMessageFormat);
+// reportStarted();
+ });
+
+ connect(&m_launcher, &ApplicationLauncher::processExited,
+ this, [this] {
+ m_launcher.disconnect(this);
+ reportStopped();
+ });
+
+ connect(&m_launcher, &ApplicationLauncher::remoteProcessStarted,
+ this, [this] {
+ reportStarted();
+ });
+
+ connect(&m_launcher, &ApplicationLauncher::reportProgress,
+ this, [this](const QString &progressString) {
+ appendMessage(progressString, Utils::NormalMessageFormat);
+ });
+
+ m_launcher.start(m_runnable, device());
+ }
+}
+
+void SimpleTargetRunner::stop()
+{
+ m_launcher.stop();
+}
+
+void SimpleTargetRunner::onProcessStarted()
+{
+ // Console processes only know their pid after being started
+ ProcessHandle pid = m_launcher.applicationPID();
+ runControl()->setApplicationProcessHandle(pid);
+ pid.activate();
+ reportStarted();
+}
+
+void SimpleTargetRunner::onProcessFinished(int exitCode, QProcess::ExitStatus status)
+{
+ QString msg;
+ if (status == QProcess::CrashExit)
+ msg = tr("%1 crashed.");
+ else
+ msg = tr("%2 exited with code %1").arg(exitCode);
+ appendMessage(msg.arg(m_runnable.displayName()), Utils::NormalMessageFormat);
+ if (!m_stopReported) {
+ m_stopReported = true;
+ reportStopped();
+ }
+}
+
+void SimpleTargetRunner::onProcessError(QProcess::ProcessError error)
+{
+ if (error == QProcess::Timedout)
+ return; // No actual change on the process side.
+ QString msg = userMessageForProcessError(error, m_runnable.displayName());
+ appendMessage(msg, Utils::NormalMessageFormat);
+ if (!m_stopReported) {
+ m_stopReported = true;
+ reportStopped();
+ }
+}
+
+IDevice::ConstPtr SimpleTargetRunner::device() const
+{
+ return m_device;
+}
+
+void SimpleTargetRunner::setRunnable(const Runnable &runnable)
+{
+ m_runnable = runnable;
+}
+
+void SimpleTargetRunner::setDevice(const IDevice::ConstPtr &device)
+{
+ m_device = device;
+}
+
+// RunWorkerPrivate
+
+RunWorkerPrivate::RunWorkerPrivate(RunWorker *runWorker, RunControl *runControl)
+ : q(runWorker), runControl(runControl)
+{
+ runControl->d->m_workers.append(runWorker);
+}
+
+bool RunWorkerPrivate::canStart() const
+{
+ if (state != RunWorkerState::Initialized)
+ return false;
+ for (RunWorker *worker : startDependencies) {
+ QTC_ASSERT(worker, continue);
+ if (worker->d->state != RunWorkerState::Done
+ && worker->d->state != RunWorkerState::Running)
+ return false;
+ }
+ return true;
+}
+
+bool RunWorkerPrivate::canStop() const
+{
+ if (state != RunWorkerState::Starting && state != RunWorkerState::Running)
+ return false;
+ for (RunWorker *worker : stopDependencies) {
+ QTC_ASSERT(worker, continue);
+ if (worker->d->state != RunWorkerState::Done)
+ return false;
+ }
+ return true;
+}
+
+void RunWorkerPrivate::timerEvent(QTimerEvent *ev)
+{
+ if (ev->timerId() == startWatchdogTimerId) {
+ if (startWatchdogCallback) {
+ killStartWatchdog();
+ startWatchdogCallback();
+ } else {
+ q->reportFailure(RunWorker::tr("Worker start timed out."));
+ }
+ return;
+ }
+ if (ev->timerId() == stopWatchdogTimerId) {
+ if (stopWatchdogCallback) {
+ killStopWatchdog();
+ stopWatchdogCallback();
+ } else {
+ q->reportFailure(RunWorker::tr("Worker stop timed out."));
+ }
+ return;
+ }
+}
+
+/*!
+ \class ProjectExplorer::RunWorker
+
+ \brief The RunWorker class encapsulates a task that forms part, or
+ the whole of the operation of a tool for a certain \c RunConfiguration
+ according to some \c RunMode.
+
+ A typical example for a \c RunWorker is a process, either the
+ application process itself, or a helper process, such as a watchdog
+ or a log parser.
+
+ A \c RunWorker has a simple state model covering the \c Initialized,
+ \c Starting, \c Running, \c Stopping, and \c Done states.
+
+ In the course of the operation of tools several \c RunWorkers
+ may co-operate and form a combined state that is presented
+ to the user as \c RunControl, with direct interaction made
+ possible through the buttons in the \uicontrol{Application Output}
+ pane.
+
+ RunWorkers are typically created together with their RunControl.
+ The startup order of RunWorkers under a RunControl can be
+ specified by making a RunWorker dependent on others.
+
+ When a RunControl starts, it calls \c initiateStart() on RunWorkers
+ with fulfilled dependencies until all workers are \c Running, or in case
+ of short-lived helper tasks, \c Done.
+
+ A RunWorker can stop spontaneously, for example when the main application
+ process ends. In this case, it typically calls \c initiateStop()
+ on its RunControl, which in turn passes this to all sibling
+ RunWorkers.
+
+ Pressing the stop button in the \uicontrol{Application Output} pane
+ also calls \c initiateStop on the RunControl.
+*/
+
+RunWorker::RunWorker(RunControl *runControl)
+ : d(std::make_unique<RunWorkerPrivate>(this, runControl))
+{ }
+
+RunWorker::~RunWorker() = default;
+
+/*!
+ * This function is called by the RunControl once all dependencies
+ * are fulfilled.
+ */
+void RunWorker::initiateStart()
+{
+ d->startStartWatchdog();
+ d->runControl->d->debugMessage("Initiate start for " + d->id);
+ start();
+}
+
+/*!
+ * This function has to be called by a RunWorker implementation
+ * to notify its RunControl about the successful start of this RunWorker.
+ *
+ * The RunControl may start other RunWorkers in response.
+ */
+void RunWorker::reportStarted()
+{
+ d->killStartWatchdog();
+ d->runControl->d->onWorkerStarted(this);
+ emit started();
+}
+
+/*!
+ * This function is called by the RunControl in its own \c initiateStop
+ * implementation, which is triggered in response to pressing the
+ * stop button in the \uicontrol{Application Output} pane or on direct
+ * request of one of the sibling RunWorkers.
+ */
+void RunWorker::initiateStop()
+{
+ d->startStopWatchdog();
+ d->runControl->d->debugMessage("Initiate stop for " + d->id);
+ stop();
+}
+
+/*!
+ * This function has to be called by a RunWorker implementation
+ * to notify its RunControl about this RunWorker having stopped.
+ *
+ * The stop can be spontaneous, or in response to an initiateStop()
+ * or an initiateFinish() call.
+ *
+ * The RunControl will adjust its global state in response.
+ */
+void RunWorker::reportStopped()
+{
+ d->killStopWatchdog();
+ d->runControl->d->onWorkerStopped(this);
+ emit stopped();
+}
+
+/*!
+ * This function can be called by a RunWorker implementation for short-lived
+ * tasks to notify its RunControl about this task being successful finished.
+ * Dependent startup tasks can proceed, in cases of spontaneous or scheduled
+ * stops, the effect is the same as \c reportStopped().
+ *
+ */
+void RunWorker::reportDone()
+{
+ d->killStartWatchdog();
+ d->killStopWatchdog();
+ switch (d->state) {
+ case RunWorkerState::Initialized:
+ QTC_CHECK(false);
+ d->state = RunWorkerState::Done;
+ break;
+ case RunWorkerState::Starting:
+ reportStarted();
+ reportStopped();
+ break;
+ case RunWorkerState::Running:
+ case RunWorkerState::Stopping:
+ reportStopped();
+ break;
+ case RunWorkerState::Done:
+ break;
+ }
+}
+
+/*!
+ * This function can be called by a RunWorker implementation to
+ * signal a problem in the operation in this worker. The
+ * RunControl will start to ramp down through initiateStop().
+ */
+void RunWorker::reportFailure(const QString &msg)
+{
+ d->killStartWatchdog();
+ d->killStopWatchdog();
+ d->runControl->d->onWorkerFailed(this, msg);
+}
+
+/*!
+ * Appends a message in the specified \a format to
+ * the owning RunControl's \uicontrol{Application Output} pane.
+ */
+void RunWorker::appendMessage(const QString &msg, OutputFormat format, bool appendNewLine)
+{
+ if (!appendNewLine || msg.endsWith('\n'))
+ d->runControl->appendMessage(msg, format);
+ else
+ d->runControl->appendMessage(msg + '\n', format);
+}
+
+IDevice::ConstPtr RunWorker::device() const
+{
+ return d->runControl->device();
+}
+
+const Runnable &RunWorker::runnable() const
+{
+ return d->runControl->runnable();
+}
+
+void RunWorker::addStartDependency(RunWorker *dependency)
+{
+ d->startDependencies.append(dependency);
+}
+
+void RunWorker::addStopDependency(RunWorker *dependency)
+{
+ d->stopDependencies.append(dependency);
+}
+
+RunControl *RunWorker::runControl() const
+{
+ return d->runControl;
+}
+
+void RunWorker::setId(const QString &id)
+{
+ d->id = id;
+}
+
+void RunWorker::setStartTimeout(int ms, const std::function<void()> &callback)
+{
+ d->startWatchdogInterval = ms;
+ d->startWatchdogCallback = callback;
+}
+
+void RunWorker::setStopTimeout(int ms, const std::function<void()> &callback)
+{
+ d->stopWatchdogInterval = ms;
+ d->stopWatchdogCallback = callback;
+}
+
+void RunWorker::recordData(const QString &channel, const QVariant &data)
+{
+ d->data[channel] = data;
+}
+
+QVariant RunWorker::recordedData(const QString &channel) const
+{
+ return d->data[channel];
+}
+
+void RunWorker::setSupportsReRunning(bool reRunningSupported)
+{
+ d->supportsReRunning = reRunningSupported;
+}
+
+bool RunWorker::supportsReRunning() const
+{
+ return d->supportsReRunning;
+}
+
+QString RunWorker::userMessageForProcessError(QProcess::ProcessError error, const QString &program)
+{
+ QString failedToStart = tr("The process failed to start.");
+ QString msg = tr("An unknown error in the process occurred.");
+ switch (error) {
+ case QProcess::FailedToStart:
+ msg = failedToStart + ' ' + tr("Either the "
+ "invoked program \"%1\" is missing, or you may have insufficient "
+ "permissions to invoke the program.").arg(program);
+ break;
+ case QProcess::Crashed:
+ msg = tr("The process was ended forcefully.");
+ break;
+ case QProcess::Timedout:
+ // "The last waitFor...() function timed out. "
+ // "The state of QProcess is unchanged, and you can try calling "
+ // "waitFor...() again."
+ return QString(); // sic!
+ case QProcess::WriteError:
+ msg = tr("An error occurred when attempting to write "
+ "to the process. For example, the process may not be running, "
+ "or it may have closed its input channel.");
+ break;
+ case QProcess::ReadError:
+ msg = tr("An error occurred when attempting to read from "
+ "the process. For example, the process may not be running.");
+ break;
+ case QProcess::UnknownError:
+ break;
+ }
+ return msg;
+}
+
+bool RunWorker::isEssential() const
+{
+ return d->essential;
+}
+
+void RunWorker::setEssential(bool essential)
+{
+ d->essential = essential;
+}
+
+void RunWorker::start()
+{
+ reportStarted();
+}
+
+void RunWorker::stop()
+{
+ reportStopped();
+}
+
+CommandLine Runnable::commandLine() const
+{
+ return CommandLine(FilePath::fromString(executable), commandLineArguments);
+}
+
+void Runnable::setCommandLine(const CommandLine &cmdLine)
+{
+ executable = cmdLine.executable().toString();
+ commandLineArguments = cmdLine.arguments();
+}
+
+} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/runcontrol.h b/src/plugins/projectexplorer/runcontrol.h
new file mode 100644
index 0000000000..fbb1c151ff
--- /dev/null
+++ b/src/plugins/projectexplorer/runcontrol.h
@@ -0,0 +1,346 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "applicationlauncher.h"
+#include "buildtargetinfo.h"
+#include "devicesupport/idevice.h"
+#include "projectexplorerconstants.h"
+#include "runconfiguration.h"
+
+#include <utils/environment.h>
+#include <utils/port.h>
+#include <utils/processhandle.h>
+#include <utils/qtcassert.h>
+#include <utils/qtcprocess.h>
+#include <utils/icon.h>
+
+#include <QHash>
+#include <QPointer>
+#include <QVariant>
+#include <QWidget>
+
+#include <functional>
+#include <memory>
+
+namespace Utils {
+class MacroExpander;
+class OutputFormatter;
+} // Utils
+
+namespace ProjectExplorer {
+class BuildConfiguration;
+class GlobalOrProjectAspect;
+class Node;
+class RunConfigurationFactory;
+class RunConfiguration;
+class RunConfigurationCreationInfo;
+class RunControl;
+class RunWorkerFactory;
+class Target;
+
+namespace Internal {
+class RunControlPrivate;
+class RunWorkerPrivate;
+} // Internal
+
+
+class PROJECTEXPLORER_EXPORT Runnable
+{
+public:
+ Runnable() = default;
+
+ Utils::CommandLine commandLine() const;
+ void setCommandLine(const Utils::CommandLine &cmdLine);
+
+ QString executable;
+ QString commandLineArguments;
+ QString workingDirectory;
+ Utils::Environment environment;
+ IDevice::ConstPtr device; // Override the kit's device. Keep unset by default.
+ QHash<Core::Id, QVariant> extraData;
+
+ // FIXME: Not necessarily a display name
+ QString displayName() const { return executable; }
+};
+
+class PROJECTEXPLORER_EXPORT RunWorker : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit RunWorker(RunControl *runControl);
+ ~RunWorker() override;
+
+ RunControl *runControl() const;
+
+ void addStartDependency(RunWorker *dependency);
+ void addStopDependency(RunWorker *dependency);
+
+ void setId(const QString &id);
+
+ void setStartTimeout(int ms, const std::function<void()> &callback = {});
+ void setStopTimeout(int ms, const std::function<void()> &callback = {});
+
+ void recordData(const QString &channel, const QVariant &data);
+ QVariant recordedData(const QString &channel) const;
+
+ // Part of read-only interface of RunControl for convenience.
+ void appendMessage(const QString &msg, Utils::OutputFormat format, bool appendNewLine = true);
+ IDevice::ConstPtr device() const;
+ const Runnable &runnable() const;
+
+ // States
+ void initiateStart();
+ void reportStarted();
+
+ void initiateStop();
+ void reportStopped();
+
+ void reportDone();
+
+ void reportFailure(const QString &msg = QString());
+ void setSupportsReRunning(bool reRunningSupported);
+ bool supportsReRunning() const;
+
+ static QString userMessageForProcessError(QProcess::ProcessError, const QString &programName);
+
+ bool isEssential() const;
+ void setEssential(bool essential);
+
+signals:
+ void started();
+ void stopped();
+
+protected:
+ void virtual start();
+ void virtual stop();
+ void virtual onFinished() {}
+
+private:
+ friend class Internal::RunControlPrivate;
+ friend class Internal::RunWorkerPrivate;
+ const std::unique_ptr<Internal::RunWorkerPrivate> d;
+};
+
+class PROJECTEXPLORER_EXPORT RunWorkerFactory
+{
+public:
+ using WorkerCreator = std::function<RunWorker *(RunControl *)>;
+ using Constraint = std::function<bool(RunConfiguration *)>;
+
+ RunWorkerFactory();
+ virtual ~RunWorkerFactory();
+
+ bool canRun(RunConfiguration *runConfiguration, Core::Id runMode) const;
+
+ void setProducer(const WorkerCreator &producer);
+ void addConstraint(const Constraint &constraint);
+ void addSupportedRunMode(Core::Id runMode);
+
+ void setSupportedRunConfigurations(const QList<Core::Id> &ids);
+ void addSupportedRunConfiguration(Core::Id id);
+
+ WorkerCreator producer() const { return m_producer; }
+
+private:
+ // FIXME: That's temporary until ownership has been transferred to
+ // the individual plugins.
+ friend class ProjectExplorerPlugin;
+ static void destroyRemainingRunWorkerFactories();
+
+ QList<Core::Id> m_supportedRunModes;
+ QList<Core::Id> m_supportedRunConfigurations;
+ QList<Constraint> m_constraints;
+ WorkerCreator m_producer;
+};
+
+/**
+ * A RunControl controls the running of an application or tool
+ * on a target device. It controls start and stop, and handles
+ * application output.
+ *
+ * RunControls are created by RunControlFactories.
+ */
+
+class PROJECTEXPLORER_EXPORT RunControl : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit RunControl(Core::Id mode);
+ ~RunControl() override;
+
+ void setRunConfiguration(RunConfiguration *runConfig);
+ void setTarget(Target *target);
+ void setKit(Kit *kit);
+
+ void initiateStart();
+ void initiateReStart();
+ void initiateStop();
+ void forceStop();
+ void initiateFinish();
+
+ bool promptToStop(bool *optionalPrompt = nullptr) const;
+ void setPromptToStop(const std::function<bool(bool *)> &promptToStop);
+
+ bool supportsReRunning() const;
+
+ virtual QString displayName() const;
+ void setDisplayName(const QString &displayName);
+
+ bool isRunning() const;
+ bool isStarting() const;
+ bool isStopping() const;
+ bool isStopped() const;
+
+ void setIcon(const Utils::Icon &icon);
+ Utils::Icon icon() const;
+
+ Utils::ProcessHandle applicationProcessHandle() const;
+ void setApplicationProcessHandle(const Utils::ProcessHandle &handle);
+ IDevice::ConstPtr device() const;
+
+ RunConfiguration *runConfiguration() const; // FIXME: Remove.
+ // FIXME: Try to cut down to amount of functions.
+ Target *target() const;
+ Project *project() const;
+ Kit *kit() const;
+ Utils::MacroExpander *macroExpander() const;
+ ProjectConfigurationAspect *aspect(Core::Id id) const;
+ template <typename T> T *aspect() const {
+ return runConfiguration() ? runConfiguration()->aspect<T>() : nullptr;
+ }
+
+ template <typename T>
+ auto aspectData() -> decltype(T::runData(nullptr, this)) {
+ if (T *asp = aspect<T>())
+ return T::runData(asp, this);
+ return {};
+ }
+
+ ISettingsAspect *settings(Core::Id id) const;
+ QString buildKey() const;
+ BuildTargetInfo buildTargetInfo() const;
+
+ Utils::OutputFormatter *outputFormatter() const;
+ Core::Id runMode() const;
+
+ const Runnable &runnable() const;
+ void setRunnable(const Runnable &runnable);
+
+ static bool showPromptToStopDialog(const QString &title, const QString &text,
+ const QString &stopButtonText = QString(),
+ const QString &cancelButtonText = QString(),
+ bool *prompt = nullptr);
+
+ RunWorker *createWorker(Core::Id id);
+
+ using WorkerCreator = RunWorkerFactory::WorkerCreator;
+ using Constraint = RunWorkerFactory::Constraint;
+
+ static void registerWorkerCreator(Core::Id id, const WorkerCreator &workerCreator);
+
+ template <class Worker>
+ static void registerWorker(Core::Id runMode, const Constraint &constraint)
+ {
+ auto factory = new RunWorkerFactory;
+ factory->setProducer([](RunControl *rc) { return new Worker(rc); });
+ factory->addSupportedRunMode(runMode);
+ factory->addConstraint(constraint);
+ }
+
+ bool createMainWorker();
+ static bool canRun(RunConfiguration *runConfig, Core::Id runMode);
+
+signals:
+ void appendMessage(const QString &msg, Utils::OutputFormat format);
+ void aboutToStart();
+ void started();
+ void stopped();
+ void finished();
+ void applicationProcessHandleChanged(QPrivateSignal); // Use setApplicationProcessHandle
+
+private:
+ void setDevice(const IDevice::ConstPtr &device);
+
+ friend class RunWorker;
+ friend class Internal::RunWorkerPrivate;
+
+ const std::unique_ptr<Internal::RunControlPrivate> d;
+};
+
+
+/**
+ * A simple TargetRunner for cases where a plain ApplicationLauncher is
+ * sufficient for running purposes.
+ */
+
+class PROJECTEXPLORER_EXPORT SimpleTargetRunner : public RunWorker
+{
+ Q_OBJECT
+
+public:
+ explicit SimpleTargetRunner(RunControl *runControl);
+
+ void setRunnable(const Runnable &runnable);
+
+ void setDevice(const IDevice::ConstPtr &device);
+ IDevice::ConstPtr device() const;
+
+protected:
+ void start() override;
+ void stop() override;
+
+private:
+ void onProcessStarted();
+ void onProcessFinished(int exitCode, QProcess::ExitStatus status);
+ void onProcessError(QProcess::ProcessError error);
+
+ ApplicationLauncher m_launcher;
+ Runnable m_runnable;
+ IDevice::ConstPtr m_device;
+ bool m_stopReported = false;
+ bool m_useTerminal = false;
+};
+
+template <class RunWorker, class RunConfig>
+class SimpleRunWorkerFactory : public RunWorkerFactory
+{
+public:
+ SimpleRunWorkerFactory(Core::Id runMode = ProjectExplorer::Constants::NORMAL_RUN_MODE)
+ {
+ addSupportedRunMode(runMode);
+ addConstraint([](RunConfiguration *runConfig) {
+ return qobject_cast<RunConfig *>(runConfig) != nullptr;
+ });
+ setProducer([](RunControl *runControl) {
+ return new RunWorker(runControl);
+ });
+ }
+};
+
+} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/runsettingspropertiespage.cpp b/src/plugins/projectexplorer/runsettingspropertiespage.cpp
index 3b30bf63ad..39b2f01af6 100644
--- a/src/plugins/projectexplorer/runsettingspropertiespage.cpp
+++ b/src/plugins/projectexplorer/runsettingspropertiespage.cpp
@@ -25,6 +25,7 @@
#include "runsettingspropertiespage.h"
+#include "addrunconfigdialog.h"
#include "buildstepspage.h"
#include "deployconfiguration.h"
#include "runconfiguration.h"
@@ -92,7 +93,7 @@ RunSettingsWidget::RunSettingsWidget(Target *target) :
m_runConfigurationCombo->setSizeAdjustPolicy(QComboBox::AdjustToContents);
m_runConfigurationCombo->setMinimumContentsLength(15);
- m_addRunToolButton = new QPushButton(tr("Add"), this);
+ m_addRunToolButton = new QPushButton(tr("Add..."), this);
m_removeRunToolButton = new QPushButton(tr("Remove"), this);
m_renameRunButton = new QPushButton(tr("Rename..."), this);
m_cloneRunButton = new QPushButton(tr("Clone..."), this);
@@ -161,7 +162,7 @@ RunSettingsWidget::RunSettingsWidget(Target *target) :
connect(m_addDeployMenu, &QMenu::aboutToShow,
this, &RunSettingsWidget::aboutToShowDeployMenu);
- connect(m_deployConfigurationCombo, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
+ connect(m_deployConfigurationCombo, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &RunSettingsWidget::currentDeployConfigurationChanged);
connect(m_removeDeployToolButton, &QAbstractButton::clicked,
this, &RunSettingsWidget::removeDeployConfiguration);
@@ -187,8 +188,6 @@ RunSettingsWidget::RunSettingsWidget(Target *target) :
m_runLayout->addLayout(disabledHBox);
- m_addRunMenu = new QMenu(m_addRunToolButton);
- m_addRunToolButton->setMenu(m_addRunMenu);
RunConfiguration *rc = m_target->activeRunConfiguration();
m_runConfigurationCombo->setModel(m_runConfigurationsModel);
m_runConfigurationCombo->setCurrentIndex(
@@ -200,9 +199,9 @@ RunSettingsWidget::RunSettingsWidget(Target *target) :
setConfigurationWidget(rc);
- connect(m_addRunMenu, &QMenu::aboutToShow,
- this, &RunSettingsWidget::aboutToShowAddMenu);
- connect(m_runConfigurationCombo, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
+ connect(m_addRunToolButton, &QAbstractButton::clicked,
+ this, &RunSettingsWidget::showAddRunConfigDialog);
+ connect(m_runConfigurationCombo, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &RunSettingsWidget::currentRunConfigurationChanged);
connect(m_removeRunToolButton, &QAbstractButton::clicked,
this, &RunSettingsWidget::removeRunConfiguration);
@@ -225,28 +224,20 @@ RunSettingsWidget::RunSettingsWidget(Target *target) :
this, &RunSettingsWidget::activeRunConfigurationChanged);
}
-void RunSettingsWidget::aboutToShowAddMenu()
+void RunSettingsWidget::showAddRunConfigDialog()
{
- m_addRunMenu->clear();
- QList<QAction *> menuActions;
- for (const RunConfigurationCreationInfo &item :
- RunConfigurationFactory::creatorsForTarget(m_target)) {
- auto action = new QAction(item.displayName, m_addRunMenu);
- connect(action, &QAction::triggered, [item, this] {
- RunConfiguration *newRC = item.create(m_target);
- if (!newRC)
- return;
- QTC_CHECK(newRC->id() == item.id);
- m_target->addRunConfiguration(newRC);
- m_target->setActiveRunConfiguration(newRC);
- m_removeRunToolButton->setEnabled(m_target->runConfigurations().size() > 1);
- });
- menuActions.append(action);
- }
-
- Utils::sort(menuActions, &QAction::text);
- foreach (QAction *action, menuActions)
- m_addRunMenu->addAction(action);
+ AddRunConfigDialog dlg(m_target, this);
+ if (dlg.exec() != QDialog::Accepted)
+ return;
+ RunConfigurationCreationInfo rci = dlg.creationInfo();
+ QTC_ASSERT(rci.id.isValid(), return);
+ RunConfiguration *newRC = rci.create(m_target);
+ if (!newRC)
+ return;
+ QTC_CHECK(newRC->id() == rci.id);
+ m_target->addRunConfiguration(newRC);
+ m_target->setActiveRunConfiguration(newRC);
+ m_removeRunToolButton->setEnabled(m_target->runConfigurations().size() > 1);
}
void RunSettingsWidget::cloneRunConfiguration()
diff --git a/src/plugins/projectexplorer/runsettingspropertiespage.h b/src/plugins/projectexplorer/runsettingspropertiespage.h
index 1857fea945..bf86fe56ba 100644
--- a/src/plugins/projectexplorer/runsettingspropertiespage.h
+++ b/src/plugins/projectexplorer/runsettingspropertiespage.h
@@ -58,7 +58,7 @@ public:
private:
void currentRunConfigurationChanged(int index);
- void aboutToShowAddMenu();
+ void showAddRunConfigDialog();
void cloneRunConfiguration();
void removeRunConfiguration();
void activeRunConfigurationChanged();
@@ -91,7 +91,6 @@ private:
NamedWidget *m_deployConfigurationWidget = nullptr;
QVBoxLayout *m_deployLayout = nullptr;
BuildStepListWidget *m_deploySteps = nullptr;
- QMenu *m_addRunMenu;
QMenu *m_addDeployMenu;
bool m_ignoreChange = false;
using RunConfigItem = QPair<QWidget *, QLabel *>;
diff --git a/src/plugins/projectexplorer/selectablefilesmodel.cpp b/src/plugins/projectexplorer/selectablefilesmodel.cpp
index b8925e4f57..28d6f4ef23 100644
--- a/src/plugins/projectexplorer/selectablefilesmodel.cpp
+++ b/src/plugins/projectexplorer/selectablefilesmodel.cpp
@@ -53,13 +53,13 @@ SelectableFilesModel::SelectableFilesModel(QObject *parent) : QAbstractItemModel
m_root = new Tree;
}
-void SelectableFilesModel::setInitialMarkedFiles(const Utils::FileNameList &files)
+void SelectableFilesModel::setInitialMarkedFiles(const Utils::FilePathList &files)
{
m_files = files.toSet();
m_allFiles = files.isEmpty();
}
-void SelectableFilesFromDirModel::startParsing(const Utils::FileName &baseDir)
+void SelectableFilesFromDirModel::startParsing(const Utils::FilePath &baseDir)
{
m_watcher.cancel();
m_watcher.waitForFinished();
@@ -87,7 +87,7 @@ void SelectableFilesFromDirModel::buildTreeFinished()
m_root = m_rootForFuture;
m_rootForFuture = nullptr;
m_outOfBaseDirFiles
- = Utils::filtered(m_files, [this](const Utils::FileName &fn) { return !fn.isChildOf(m_baseDir); });
+ = Utils::filtered(m_files, [this](const Utils::FilePath &fn) { return !fn.isChildOf(m_baseDir); });
endResetModel();
emit parsingFinished();
@@ -116,7 +116,7 @@ SelectableFilesModel::FilterState SelectableFilesModel::filter(Tree *t)
return Utils::anyOf(m_hideFilesFilter, matchesTreeName) ? FilterState::HIDDEN : FilterState::SHOWN;
}
-void SelectableFilesFromDirModel::buildTree(const Utils::FileName &baseDir, Tree *tree,
+void SelectableFilesFromDirModel::buildTree(const Utils::FilePath &baseDir, Tree *tree,
QFutureInterface<void> &fi, int symlinkDepth)
{
if (symlinkDepth == 0)
@@ -128,7 +128,7 @@ void SelectableFilesFromDirModel::buildTree(const Utils::FileName &baseDir, Tree
bool allChecked = true;
bool allUnchecked = true;
for (const QFileInfo &fileInfo : fileInfoList) {
- Utils::FileName fn = Utils::FileName(fileInfo);
+ Utils::FilePath fn = Utils::FilePath::fromFileInfo(fileInfo);
if (m_futureCount % 100) {
emit parsingProgress(fn);
if (fi.isCanceled())
@@ -302,14 +302,14 @@ Qt::ItemFlags SelectableFilesModel::flags(const QModelIndex &index) const
return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable;
}
-Utils::FileNameList SelectableFilesModel::selectedPaths() const
+Utils::FilePathList SelectableFilesModel::selectedPaths() const
{
- Utils::FileNameList result;
+ Utils::FilePathList result;
collectPaths(m_root, &result);
return result;
}
-void SelectableFilesModel::collectPaths(Tree *root, Utils::FileNameList *result) const
+void SelectableFilesModel::collectPaths(Tree *root, Utils::FilePathList *result) const
{
if (root->checked == Qt::Unchecked)
return;
@@ -318,14 +318,14 @@ void SelectableFilesModel::collectPaths(Tree *root, Utils::FileNameList *result)
collectPaths(t, result);
}
-Utils::FileNameList SelectableFilesModel::selectedFiles() const
+Utils::FilePathList SelectableFilesModel::selectedFiles() const
{
- Utils::FileNameList result = m_outOfBaseDirFiles.toList();
+ Utils::FilePathList result = m_outOfBaseDirFiles.toList();
collectFiles(m_root, &result);
return result;
}
-Utils::FileNameList SelectableFilesModel::preservedFiles() const
+Utils::FilePathList SelectableFilesModel::preservedFiles() const
{
return m_outOfBaseDirFiles.toList();
}
@@ -335,7 +335,7 @@ bool SelectableFilesModel::hasCheckedFiles() const
return m_root->checked != Qt::Unchecked;
}
-void SelectableFilesModel::collectFiles(Tree *root, Utils::FileNameList *result) const
+void SelectableFilesModel::collectFiles(Tree *root, Utils::FilePathList *result) const
{
if (root->checked == Qt::Unchecked)
return;
@@ -591,8 +591,8 @@ SelectableFilesWidget::SelectableFilesWidget(QWidget *parent) :
layout->addWidget(m_progressLabel, static_cast<int>(SelectableFilesWidgetRows::Progress), 0, 1, 4);
}
-SelectableFilesWidget::SelectableFilesWidget(const Utils::FileName &path,
- const Utils::FileNameList &files, QWidget *parent) :
+SelectableFilesWidget::SelectableFilesWidget(const Utils::FilePath &path,
+ const Utils::FilePathList &files, QWidget *parent) :
SelectableFilesWidget(parent)
{
resetModel(path, files);
@@ -601,6 +601,10 @@ SelectableFilesWidget::SelectableFilesWidget(const Utils::FileName &path,
void SelectableFilesWidget::setAddFileFilter(const QString &filter)
{
m_selectFilesFilterEdit->setText(filter);
+ if (m_applyFiltersButton->isEnabled())
+ applyFilter();
+ else
+ m_filteringScheduled = true;
}
void SelectableFilesWidget::setBaseDirEditable(bool edit)
@@ -611,14 +615,14 @@ void SelectableFilesWidget::setBaseDirEditable(bool edit)
m_startParsingButton->setVisible(edit);
}
-Utils::FileNameList SelectableFilesWidget::selectedFiles() const
+Utils::FilePathList SelectableFilesWidget::selectedFiles() const
{
- return m_model ? m_model->selectedFiles() : Utils::FileNameList();
+ return m_model ? m_model->selectedFiles() : Utils::FilePathList();
}
-Utils::FileNameList SelectableFilesWidget::selectedPaths() const
+Utils::FilePathList SelectableFilesWidget::selectedPaths() const
{
- return m_model ? m_model->selectedPaths() : Utils::FileNameList();
+ return m_model ? m_model->selectedPaths() : Utils::FilePathList();
}
bool SelectableFilesWidget::hasFilesSelected() const
@@ -626,7 +630,7 @@ bool SelectableFilesWidget::hasFilesSelected() const
return m_model ? m_model->hasCheckedFiles() : false;
}
-void SelectableFilesWidget::resetModel(const Utils::FileName &path, const Utils::FileNameList &files)
+void SelectableFilesWidget::resetModel(const Utils::FilePath &path, const Utils::FilePathList &files)
{
m_view->setModel(nullptr);
@@ -675,6 +679,7 @@ void SelectableFilesWidget::enableWidgets(bool enabled)
void SelectableFilesWidget::applyFilter()
{
+ m_filteringScheduled = false;
if (m_model)
m_model->applyFilter(m_selectFilesFilterEdit->text(), m_hideFilesFilterEdit->text());
}
@@ -684,7 +689,7 @@ void SelectableFilesWidget::baseDirectoryChanged(bool validState)
m_startParsingButton->setEnabled(validState);
}
-void SelectableFilesWidget::startParsing(const Utils::FileName &baseDir)
+void SelectableFilesWidget::startParsing(const Utils::FilePath &baseDir)
{
if (!m_model)
return;
@@ -694,7 +699,7 @@ void SelectableFilesWidget::startParsing(const Utils::FileName &baseDir)
m_model->startParsing(baseDir);
}
-void SelectableFilesWidget::parsingProgress(const Utils::FileName &fileName)
+void SelectableFilesWidget::parsingProgress(const Utils::FilePath &fileName)
{
m_progressLabel->setText(tr("Generating file list...\n\n%1").arg(fileName.toUserOutput()));
}
@@ -706,11 +711,13 @@ void SelectableFilesWidget::parsingFinished()
smartExpand(m_model->index(0,0, QModelIndex()));
- const Utils::FileNameList preservedFiles = m_model->preservedFiles();
+ const Utils::FilePathList preservedFiles = m_model->preservedFiles();
m_preservedFilesLabel->setText(tr("Not showing %n files that are outside of the base directory.\n"
"These files are preserved.", nullptr, preservedFiles.count()));
enableWidgets(true);
+ if (m_filteringScheduled)
+ applyFilter();
}
void SelectableFilesWidget::smartExpand(const QModelIndex &idx)
@@ -728,8 +735,8 @@ void SelectableFilesWidget::smartExpand(const QModelIndex &idx)
// SelectableFilesDialogs
//////////
-SelectableFilesDialogEditFiles::SelectableFilesDialogEditFiles(const Utils::FileName &path,
- const Utils::FileNameList &files,
+SelectableFilesDialogEditFiles::SelectableFilesDialogEditFiles(const Utils::FilePath &path,
+ const Utils::FilePathList &files,
QWidget *parent) :
QDialog(parent),
m_filesWidget(new SelectableFilesWidget(path, files))
@@ -752,7 +759,7 @@ SelectableFilesDialogEditFiles::SelectableFilesDialogEditFiles(const Utils::File
layout->addWidget(buttonBox);
}
-Utils::FileNameList SelectableFilesDialogEditFiles::selectedFiles() const
+Utils::FilePathList SelectableFilesDialogEditFiles::selectedFiles() const
{
return m_filesWidget->selectedFiles();
}
@@ -763,8 +770,8 @@ Utils::FileNameList SelectableFilesDialogEditFiles::selectedFiles() const
//////////
-SelectableFilesDialogAddDirectory::SelectableFilesDialogAddDirectory(const Utils::FileName &path,
- const Utils::FileNameList &files,
+SelectableFilesDialogAddDirectory::SelectableFilesDialogAddDirectory(const Utils::FilePath &path,
+ const Utils::FilePathList &files,
QWidget *parent) :
SelectableFilesDialogEditFiles(path, files, parent)
{
diff --git a/src/plugins/projectexplorer/selectablefilesmodel.h b/src/plugins/projectexplorer/selectablefilesmodel.h
index 698ae03d05..a04a059ffc 100644
--- a/src/plugins/projectexplorer/selectablefilesmodel.h
+++ b/src/plugins/projectexplorer/selectablefilesmodel.h
@@ -64,7 +64,7 @@ public:
QList<Tree *> files;
QList<Tree *> visibleFiles;
QIcon icon;
- Utils::FileName fullPath;
+ Utils::FilePath fullPath;
Tree *parent = nullptr;
};
@@ -107,7 +107,7 @@ public:
SelectableFilesModel(QObject *parent);
~SelectableFilesModel() override;
- void setInitialMarkedFiles(const Utils::FileNameList &files);
+ void setInitialMarkedFiles(const Utils::FilePathList &files);
int columnCount(const QModelIndex &parent) const override;
int rowCount(const QModelIndex &parent) const override;
@@ -118,9 +118,9 @@ public:
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
- Utils::FileNameList selectedFiles() const;
- Utils::FileNameList selectedPaths() const;
- Utils::FileNameList preservedFiles() const;
+ Utils::FilePathList selectedFiles() const;
+ Utils::FilePathList selectedPaths() const;
+ Utils::FilePathList preservedFiles() const;
bool hasCheckedFiles() const;
@@ -141,14 +141,14 @@ protected:
private:
QList<Glob> parseFilter(const QString &filter);
Qt::CheckState applyFilter(const QModelIndex &idx);
- void collectFiles(Tree *root, Utils::FileNameList *result) const;
- void collectPaths(Tree *root, Utils::FileNameList *result) const;
+ void collectFiles(Tree *root, Utils::FilePathList *result) const;
+ void collectPaths(Tree *root, Utils::FilePathList *result) const;
void selectAllFiles(Tree *root);
protected:
bool m_allFiles = true;
- QSet<Utils::FileName> m_outOfBaseDirFiles;
- QSet<Utils::FileName> m_files;
+ QSet<Utils::FilePath> m_outOfBaseDirFiles;
+ QSet<Utils::FilePath> m_files;
Tree *m_root = nullptr;
private:
@@ -164,15 +164,15 @@ public:
SelectableFilesFromDirModel(QObject *parent);
~SelectableFilesFromDirModel() override;
- void startParsing(const Utils::FileName &baseDir);
+ void startParsing(const Utils::FilePath &baseDir);
void cancel();
signals:
void parsingFinished();
- void parsingProgress(const Utils::FileName &fileName);
+ void parsingProgress(const Utils::FilePath &fileName);
private:
- void buildTree(const Utils::FileName &baseDir,
+ void buildTree(const Utils::FilePath &baseDir,
Tree *tree,
QFutureInterface<void> &fi,
int symlinkDepth);
@@ -180,7 +180,7 @@ private:
void buildTreeFinished();
// Used in the future thread need to all not used after calling startParsing
- Utils::FileName m_baseDir;
+ Utils::FilePath m_baseDir;
QFutureWatcher<void> m_watcher;
Tree *m_rootForFuture = nullptr;
int m_futureCount = 0;
@@ -192,18 +192,18 @@ class PROJECTEXPLORER_EXPORT SelectableFilesWidget : public QWidget
public:
explicit SelectableFilesWidget(QWidget *parent = nullptr);
- SelectableFilesWidget(const Utils::FileName &path, const Utils::FileNameList &files,
+ SelectableFilesWidget(const Utils::FilePath &path, const Utils::FilePathList &files,
QWidget *parent = nullptr);
void setAddFileFilter(const QString &filter);
void setBaseDirEditable(bool edit);
- Utils::FileNameList selectedFiles() const;
- Utils::FileNameList selectedPaths() const;
+ Utils::FilePathList selectedFiles() const;
+ Utils::FilePathList selectedPaths() const;
bool hasFilesSelected() const;
- void resetModel(const Utils::FileName &path, const Utils::FileNameList &files);
+ void resetModel(const Utils::FilePath &path, const Utils::FilePathList &files);
void cancelParsing();
void enableFilterHistoryCompletion(const QString &keyPrefix);
@@ -216,8 +216,8 @@ private:
void applyFilter();
void baseDirectoryChanged(bool validState);
- void startParsing(const Utils::FileName &baseDir);
- void parsingProgress(const Utils::FileName &fileName);
+ void startParsing(const Utils::FilePath &baseDir);
+ void parsingProgress(const Utils::FilePath &fileName);
void parsingFinished();
void smartExpand(const QModelIndex &idx);
@@ -241,6 +241,7 @@ private:
QLabel *m_preservedFilesLabel;
QLabel *m_progressLabel;
+ bool m_filteringScheduled = false;
};
class PROJECTEXPLORER_EXPORT SelectableFilesDialogEditFiles : public QDialog
@@ -248,9 +249,9 @@ class PROJECTEXPLORER_EXPORT SelectableFilesDialogEditFiles : public QDialog
Q_OBJECT
public:
- SelectableFilesDialogEditFiles(const Utils::FileName &path, const Utils::FileNameList &files,
+ SelectableFilesDialogEditFiles(const Utils::FilePath &path, const Utils::FilePathList &files,
QWidget *parent);
- Utils::FileNameList selectedFiles() const;
+ Utils::FilePathList selectedFiles() const;
void setAddFileFilter(const QString &filter) { m_filesWidget->setAddFileFilter(filter); }
@@ -263,7 +264,7 @@ class SelectableFilesDialogAddDirectory : public SelectableFilesDialogEditFiles
Q_OBJECT
public:
- SelectableFilesDialogAddDirectory(const Utils::FileName &path, const Utils::FileNameList &files,
+ SelectableFilesDialogAddDirectory(const Utils::FilePath &path, const Utils::FilePathList &files,
QWidget *parent);
};
diff --git a/src/plugins/projectexplorer/session.cpp b/src/plugins/projectexplorer/session.cpp
index 26a70669d4..95a8fbd4e6 100644
--- a/src/plugins/projectexplorer/session.cpp
+++ b/src/plugins/projectexplorer/session.cpp
@@ -55,6 +55,12 @@
#include <QMessageBox>
#include <QPushButton>
+#ifdef WITH_TESTS
+#include <QTemporaryFile>
+#include <QTest>
+#include <vector>
+#endif
+
using namespace Core;
using namespace Utils;
using namespace ProjectExplorer::Internal;
@@ -204,7 +210,7 @@ QList<Project *> SessionManager::dependencies(const Project *project)
QList<Project *> projects;
foreach (const QString &dep, proDeps) {
- const Utils::FileName fn = Utils::FileName::fromString(dep);
+ const Utils::FilePath fn = Utils::FilePath::fromString(dep);
Project *pro = Utils::findOrDefault(d->m_projects, [&fn](Project *p) { return p->projectFilePath() == fn; });
if (pro)
projects += pro;
@@ -552,17 +558,17 @@ QString SessionManagerPrivate::sessionTitle(const QString &filePath)
}
QString SessionManagerPrivate::locationInProject(const QString &filePath) {
- const Project *project = SessionManager::projectForFile(Utils::FileName::fromString(filePath));
+ const Project *project = SessionManager::projectForFile(Utils::FilePath::fromString(filePath));
if (!project)
return QString();
- const Utils::FileName file = Utils::FileName::fromString(filePath);
- const Utils::FileName parentDir = file.parentDir();
+ const Utils::FilePath file = Utils::FilePath::fromString(filePath);
+ const Utils::FilePath parentDir = file.parentDir();
if (parentDir == project->projectDirectory())
return "@ " + project->displayName();
if (file.isChildOf(project->projectDirectory())) {
- const Utils::FileName dirInProject = parentDir.relativeChildPath(project->projectDirectory());
+ const Utils::FilePath dirInProject = parentDir.relativeChildPath(project->projectDirectory());
return "(" + dirInProject.toUserOutput() + " @ " + project->displayName() + ")";
}
@@ -632,7 +638,7 @@ QList<Project *> SessionManager::projectOrder(const Project *project)
return result;
}
-Project *SessionManager::projectForFile(const Utils::FileName &fileName)
+Project *SessionManager::projectForFile(const Utils::FilePath &fileName)
{
return Utils::findOrDefault(SessionManager::projects(),
[&fileName](const Project *p) { return p->isKnownFile(fileName); });
@@ -641,7 +647,7 @@ Project *SessionManager::projectForFile(const Utils::FileName &fileName)
void SessionManager::configureEditor(IEditor *editor, const QString &fileName)
{
if (auto textEditor = qobject_cast<TextEditor::BaseTextEditor*>(editor)) {
- Project *project = projectForFile(Utils::FileName::fromString(fileName));
+ Project *project = projectForFile(Utils::FilePath::fromString(fileName));
// Global settings are the default.
if (project)
project->editorConfiguration()->configureEditor(textEditor);
@@ -738,7 +744,7 @@ QStringList SessionManager::sessions()
if (d->m_sessions.isEmpty()) {
// We are not initialized yet, so do that now
QDir sessionDir(ICore::userResourcePath());
- QList<QFileInfo> sessionFiles = sessionDir.entryInfoList(QStringList() << QLatin1String("*.qws"), QDir::NoFilter, QDir::Time);
+ QFileInfoList sessionFiles = sessionDir.entryInfoList(QStringList() << QLatin1String("*.qws"), QDir::NoFilter, QDir::Time);
foreach (const QFileInfo &fileInfo, sessionFiles) {
const QString &name = fileInfo.completeBaseName();
d->m_sessionDateTimes.insert(name, fileInfo.lastModified());
@@ -755,9 +761,9 @@ QDateTime SessionManager::sessionDateTime(const QString &session)
return d->m_sessionDateTimes.value(session);
}
-FileName SessionManager::sessionNameToFileName(const QString &session)
+FilePath SessionManager::sessionNameToFileName(const QString &session)
{
- return FileName::fromString(ICore::userResourcePath() + QLatin1Char('/') + session + QLatin1String(".qws"));
+ return FilePath::fromString(ICore::userResourcePath() + QLatin1Char('/') + session + QLatin1String(".qws"));
}
/*!
@@ -786,11 +792,15 @@ bool SessionManager::renameSession(const QString &original, const QString &newNa
/*!
\brief Shows a dialog asking the user to confirm deleting the session \p session
*/
-bool SessionManager::confirmSessionDelete(const QString &session)
+bool SessionManager::confirmSessionDelete(const QStringList &sessions)
{
+ const QString title = sessions.size() == 1 ? tr("Delete Session") : tr("Delete Sessions");
+ const QString question = sessions.size() == 1
+ ? tr("Delete session %1?").arg(sessions.first())
+ : tr("Delete these sessions?\n %1").arg(sessions.join("\n "));
return QMessageBox::question(ICore::mainWindow(),
- tr("Delete Session"),
- tr("Delete session %1?").arg(session),
+ title,
+ question,
QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes;
}
@@ -808,6 +818,12 @@ bool SessionManager::deleteSession(const QString &session)
return false;
}
+void SessionManager::deleteSessions(const QStringList &sessions)
+{
+ for (const QString &session : sessions)
+ deleteSession(session);
+}
+
bool SessionManager::cloneSession(const QString &original, const QString &clone)
{
if (!d->m_sessions.contains(original))
@@ -931,7 +947,7 @@ bool SessionManager::loadSession(const QString &session)
QStringList fileList;
// Try loading the file
- FileName fileName = sessionNameToFileName(session);
+ FilePath fileName = sessionNameToFileName(session);
PersistentSettingsReader reader;
if (fileName.exists()) {
if (!reader.load(fileName)) {
@@ -1002,11 +1018,8 @@ bool SessionManager::loadSession(const QString &session)
d->m_future.setProgressRange(0, projectPathsToLoad.count() + 1/*initialization above*/ + 1/*editors*/);
d->m_future.setProgressValue(1);
-
- // if one processEvents doesn't get the job done
- // just use two!
- QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
+
d->restoreProjects(projectPathsToLoad);
d->sessionLoadingProgress();
d->restoreDependencies(reader);
@@ -1065,7 +1078,7 @@ void SessionManagerPrivate::sessionLoadingProgress()
QStringList SessionManager::projectsForSessionName(const QString &session)
{
- const FileName fileName = sessionNameToFileName(session);
+ const FilePath fileName = sessionNameToFileName(session);
PersistentSettingsReader reader;
if (fileName.exists()) {
if (!reader.load(fileName)) {
@@ -1076,4 +1089,58 @@ QStringList SessionManager::projectsForSessionName(const QString &session)
return reader.restoreValue(QLatin1String("ProjectList")).toStringList();
}
+#ifdef WITH_TESTS
+
+void ProjectExplorerPlugin::testSessionSwitch()
+{
+ QVERIFY(SessionManager::createSession("session1"));
+ QVERIFY(SessionManager::createSession("session2"));
+ QTemporaryFile cppFile("main.cpp");
+ QVERIFY(cppFile.open());
+ cppFile.close();
+ QTemporaryFile projectFile1("XXXXXX.pro");
+ QTemporaryFile projectFile2("XXXXXX.pro");
+ struct SessionSpec {
+ SessionSpec(const QString &n, QTemporaryFile &f) : name(n), projectFile(f) {}
+ const QString name;
+ QTemporaryFile &projectFile;
+ };
+ std::vector<SessionSpec> sessionSpecs{SessionSpec("session1", projectFile1),
+ SessionSpec("session2", projectFile2)};
+ for (const SessionSpec &sessionSpec : sessionSpecs) {
+ static const QByteArray proFileContents
+ = "TEMPLATE = app\n"
+ "CONFIG -= qt\n"
+ "SOURCES = " + cppFile.fileName().toLocal8Bit();
+ QVERIFY(sessionSpec.projectFile.open());
+ sessionSpec.projectFile.write(proFileContents);
+ sessionSpec.projectFile.close();
+ QVERIFY(SessionManager::loadSession(sessionSpec.name));
+ const OpenProjectResult openResult
+ = ProjectExplorerPlugin::openProject(sessionSpec.projectFile.fileName());
+ if (openResult.errorMessage().contains("text/plain"))
+ QSKIP("This test requires the presence of QmakeProjectManager to be fully functional");
+ QVERIFY(openResult);
+ QCOMPARE(openResult.projects().count(), 1);
+ QVERIFY(openResult.project());
+ QCOMPARE(SessionManager::projects().count(), 1);
+ }
+ for (int i = 0; i < 30; ++i) {
+ QVERIFY(SessionManager::loadSession("session1"));
+ QCOMPARE(SessionManager::activeSession(), "session1");
+ QCOMPARE(SessionManager::projects().count(), 1);
+ QVERIFY(SessionManager::loadSession("session2"));
+ QCOMPARE(SessionManager::activeSession(), "session2");
+ QCOMPARE(SessionManager::projects().count(), 1);
+ }
+ QVERIFY(SessionManager::loadSession("session1"));
+ SessionManager::closeAllProjects();
+ QVERIFY(SessionManager::loadSession("session2"));
+ SessionManager::closeAllProjects();
+ QVERIFY(SessionManager::deleteSession("session1"));
+ QVERIFY(SessionManager::deleteSession("session2"));
+}
+
+#endif // WITH_TESTS
+
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/session.h b/src/plugins/projectexplorer/session.h
index 3a49be8308..782079f9d7 100644
--- a/src/plugins/projectexplorer/session.h
+++ b/src/plugins/projectexplorer/session.h
@@ -63,8 +63,9 @@ public:
static bool createSession(const QString &session);
- static bool confirmSessionDelete(const QString &session);
+ static bool confirmSessionDelete(const QStringList &sessions);
static bool deleteSession(const QString &session);
+ static void deleteSessions(const QStringList &sessions);
static bool cloneSession(const QString &original, const QString &clone);
static bool renameSession(const QString &original, const QString &newName);
@@ -93,7 +94,7 @@ public:
static void setActiveBuildConfiguration(Target *t, BuildConfiguration *bc, SetActive cascade);
static void setActiveDeployConfiguration(Target *t, DeployConfiguration *dc, SetActive cascade);
- static Utils::FileName sessionNameToFileName(const QString &session);
+ static Utils::FilePath sessionNameToFileName(const QString &session);
static Project *startupProject();
static const QList<Project *> projects();
@@ -110,7 +111,7 @@ public:
// NBS rewrite projectOrder (dependency management)
static QList<Project *> projectOrder(const Project *project = nullptr);
- static Project *projectForFile(const Utils::FileName &fileName);
+ static Project *projectForFile(const Utils::FilePath &fileName);
static QStringList projectsForSessionName(const QString &session);
diff --git a/src/plugins/projectexplorer/sessiondialog.cpp b/src/plugins/projectexplorer/sessiondialog.cpp
index 2dfb944a35..6cda77927b 100644
--- a/src/plugins/projectexplorer/sessiondialog.cpp
+++ b/src/plugins/projectexplorer/sessiondialog.cpp
@@ -26,6 +26,8 @@
#include "sessiondialog.h"
#include "session.h"
+#include <utils/algorithm.h>
+
#include <QInputDialog>
#include <QValidator>
@@ -131,7 +133,7 @@ SessionDialog::SessionDialog(QWidget *parent) : QDialog(parent)
connect(m_ui.btClone, &QAbstractButton::clicked,
m_ui.sessionView, &SessionView::cloneCurrentSession);
connect(m_ui.btDelete, &QAbstractButton::clicked,
- m_ui.sessionView, &SessionView::deleteCurrentSession);
+ m_ui.sessionView, &SessionView::deleteSelectedSessions);
connect(m_ui.btSwitch, &QAbstractButton::clicked,
m_ui.sessionView, &SessionView::switchToCurrentSession);
connect(m_ui.btRename, &QAbstractButton::clicked,
@@ -157,21 +159,23 @@ bool SessionDialog::autoLoadSession() const
return m_ui.autoLoadCheckBox->checkState() == Qt::Checked;
}
-void SessionDialog::updateActions(const QString &session)
+void SessionDialog::updateActions(const QStringList &sessions)
{
- if (session.isEmpty()) {
+ if (sessions.isEmpty()) {
m_ui.btDelete->setEnabled(false);
m_ui.btRename->setEnabled(false);
m_ui.btClone->setEnabled(false);
m_ui.btSwitch->setEnabled(false);
- } else {
- bool isDefault = (session == QLatin1String("default"));
- bool isActive = (session == SessionManager::activeSession());
- m_ui.btDelete->setEnabled(!isActive && !isDefault);
- m_ui.btRename->setEnabled(!isDefault);
- m_ui.btClone->setEnabled(true);
- m_ui.btSwitch->setEnabled(true);
+ return;
}
+ const bool defaultIsSelected = sessions.contains("default");
+ const bool activeIsSelected = Utils::anyOf(sessions, [](const QString &session) {
+ return session == SessionManager::activeSession();
+ });
+ m_ui.btDelete->setEnabled(!defaultIsSelected && !activeIsSelected);
+ m_ui.btRename->setEnabled(sessions.size() == 1 && !defaultIsSelected);
+ m_ui.btClone->setEnabled(sessions.size() == 1);
+ m_ui.btSwitch->setEnabled(sessions.size() == 1);
}
} // namespace Internal
diff --git a/src/plugins/projectexplorer/sessiondialog.h b/src/plugins/projectexplorer/sessiondialog.h
index 654736694e..701748b55c 100644
--- a/src/plugins/projectexplorer/sessiondialog.h
+++ b/src/plugins/projectexplorer/sessiondialog.h
@@ -49,7 +49,7 @@ public:
bool autoLoadSession() const;
private:
- void updateActions(const QString &session);
+ void updateActions(const QStringList &sessions);
Ui::SessionDialog m_ui;
};
diff --git a/src/plugins/projectexplorer/sessionmodel.cpp b/src/plugins/projectexplorer/sessionmodel.cpp
index 21b3ec3f48..bcf13e96dd 100644
--- a/src/plugins/projectexplorer/sessionmodel.cpp
+++ b/src/plugins/projectexplorer/sessionmodel.cpp
@@ -55,7 +55,7 @@ int SessionModel::indexOfSession(const QString &session)
return SessionManager::sessions().indexOf(session);
}
-QString SessionModel::sessionAt(int row)
+QString SessionModel::sessionAt(int row) const
{
return SessionManager::sessions().value(row, QString());
}
@@ -209,12 +209,12 @@ void SessionModel::cloneSession(QWidget *parent, const QString &session)
});
}
-void SessionModel::deleteSession(const QString &session)
+void SessionModel::deleteSessions(const QStringList &sessions)
{
- if (!SessionManager::confirmSessionDelete(session))
+ if (!SessionManager::confirmSessionDelete(sessions))
return;
beginResetModel();
- SessionManager::deleteSession(session);
+ SessionManager::deleteSessions(sessions);
endResetModel();
}
diff --git a/src/plugins/projectexplorer/sessionmodel.h b/src/plugins/projectexplorer/sessionmodel.h
index 7feff2b433..63f9984215 100644
--- a/src/plugins/projectexplorer/sessionmodel.h
+++ b/src/plugins/projectexplorer/sessionmodel.h
@@ -53,7 +53,7 @@ public:
explicit SessionModel(QObject *parent = nullptr);
int indexOfSession(const QString &session);
- QString sessionAt(int row);
+ QString sessionAt(int row) const;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
@@ -72,7 +72,7 @@ public slots:
void resetSessions();
void newSession(QWidget *parent);
void cloneSession(QWidget *parent, const QString &session);
- void deleteSession(const QString &session);
+ void deleteSessions(const QStringList &sessions);
void renameSession(QWidget *parent, const QString &session);
void switchToSession(const QString &session);
diff --git a/src/plugins/projectexplorer/sessionview.cpp b/src/plugins/projectexplorer/sessionview.cpp
index 4e3bda6510..07d918ca77 100644
--- a/src/plugins/projectexplorer/sessionview.cpp
+++ b/src/plugins/projectexplorer/sessionview.cpp
@@ -27,9 +27,12 @@
#include "session.h"
+#include <utils/algorithm.h>
+
+#include <QHeaderView>
#include <QItemSelection>
+#include <QStringList>
#include <QStyledItemDelegate>
-#include <QHeaderView>
namespace ProjectExplorer {
namespace Internal {
@@ -57,7 +60,7 @@ SessionView::SessionView(QWidget *parent)
{
setItemDelegate(new RemoveItemFocusDelegate(this));
setSelectionBehavior(QAbstractItemView::SelectRows);
- setSelectionMode(QAbstractItemView::SingleSelection);
+ setSelectionMode(QAbstractItemView::ExtendedSelection);
setWordWrap(false);
setRootIsDecorated(false);
@@ -74,9 +77,8 @@ SessionView::SessionView(QWidget *parent)
connect(this, &Utils::TreeView::activated, [this](const QModelIndex &index){
emit activated(m_sessionModel.sessionAt(index.row()));
});
- connect(selectionModel(), &QItemSelectionModel::currentRowChanged, [this]
- (const QModelIndex &index) {
- emit selected(m_sessionModel.sessionAt(index.row()));
+ connect(selectionModel(), &QItemSelectionModel::selectionChanged, [this] {
+ emit selected(selectedSessions());
});
connect(&m_sessionModel, &SessionModel::sessionSwitched,
@@ -92,9 +94,14 @@ void SessionView::createNewSession()
m_sessionModel.newSession(this);
}
-void SessionView::deleteCurrentSession()
+void SessionView::deleteSelectedSessions()
+{
+ deleteSessions(selectedSessions());
+}
+
+void SessionView::deleteSessions(const QStringList &sessions)
{
- m_sessionModel.deleteSession(currentSession());
+ m_sessionModel.deleteSessions(sessions);
}
void SessionView::cloneCurrentSession()
@@ -141,5 +148,25 @@ void SessionView::showEvent(QShowEvent *event)
setFocus();
}
+void SessionView::keyPressEvent(QKeyEvent *event)
+{
+ if (event->key() != Qt::Key_Delete) {
+ TreeView::keyPressEvent(event);
+ return;
+ }
+ const QStringList sessions = selectedSessions();
+ if (!sessions.contains("default") && !Utils::anyOf(sessions,
+ [](const QString &session) { return session == SessionManager::activeSession(); })) {
+ deleteSessions(sessions);
+ }
+}
+
+QStringList SessionView::selectedSessions() const
+{
+ return Utils::transform(selectionModel()->selectedRows(), [this](const QModelIndex &index) {
+ return m_sessionModel.sessionAt(index.row());
+ });
+}
+
} // namespace Internal
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/sessionview.h b/src/plugins/projectexplorer/sessionview.h
index 0f85e6ed21..21988c3838 100644
--- a/src/plugins/projectexplorer/sessionview.h
+++ b/src/plugins/projectexplorer/sessionview.h
@@ -41,7 +41,7 @@ public:
explicit SessionView(QWidget *parent = nullptr);
void createNewSession();
- void deleteCurrentSession();
+ void deleteSelectedSessions();
void cloneCurrentSession();
void renameCurrentSession();
void switchToCurrentSession();
@@ -51,15 +51,18 @@ public:
void selectActiveSession();
void selectSession(const QString &sessionName);
-protected:
- void showEvent(QShowEvent* event) override;
-
signals:
void activated(const QString &session);
- void selected(const QString &session);
+ void selected(const QStringList &sessions);
void sessionSwitched();
private:
+ void showEvent(QShowEvent* event) override;
+ void keyPressEvent(QKeyEvent *event) override;
+
+ void deleteSessions(const QStringList &sessions);
+ QStringList selectedSessions() const;
+
SessionModel m_sessionModel;
};
diff --git a/src/plugins/projectexplorer/target.cpp b/src/plugins/projectexplorer/target.cpp
index 70d742e34e..d02dc8c6e8 100644
--- a/src/plugins/projectexplorer/target.cpp
+++ b/src/plugins/projectexplorer/target.cpp
@@ -102,7 +102,7 @@ public:
QList<RunConfiguration *> m_runConfigurations;
RunConfiguration* m_activeRunConfiguration = nullptr;
DeploymentData m_deploymentData;
- BuildTargetInfoList m_appTargets;
+ QList<BuildTargetInfo> m_appTargets;
QVariantMap m_pluginSettings;
Kit *const m_kit;
@@ -345,19 +345,26 @@ DeploymentData Target::deploymentData() const
return d->m_deploymentData;
}
-void Target::setApplicationTargets(const BuildTargetInfoList &appTargets)
+void Target::setApplicationTargets(const QList<BuildTargetInfo> &appTargets)
{
- if (d->m_appTargets != appTargets) {
+ if (appTargets.toSet() != d->m_appTargets.toSet()) {
d->m_appTargets = appTargets;
emit applicationTargetsChanged();
}
}
-BuildTargetInfoList Target::applicationTargets() const
+const QList<BuildTargetInfo> Target::applicationTargets() const
{
return d->m_appTargets;
}
+BuildTargetInfo Target::buildTarget(const QString &buildKey) const
+{
+ return Utils::findOrDefault(d->m_appTargets, [&buildKey](const BuildTargetInfo &ti) {
+ return ti.buildKey == buildKey;
+ });
+}
+
QList<ProjectConfiguration *> Target::projectConfigurations() const
{
QList<ProjectConfiguration *> result;
@@ -452,7 +459,7 @@ void Target::setOverlayIcon(const QIcon &icon)
QString Target::overlayIconToolTip()
{
- IDevice::ConstPtr current = DeviceKitInformation::device(kit());
+ IDevice::ConstPtr current = DeviceKitAspect::device(kit());
return current.isNull() ? QString() : formatDeviceInfo(current->deviceInformation());
}
@@ -680,9 +687,14 @@ QVariant Target::additionalData(Core::Id id) const
return project()->additionalData(id, this);
}
+MakeInstallCommand Target::makeInstallCommand(const QString &installRoot) const
+{
+ return project()->makeInstallCommand(this, installRoot);
+}
+
void Target::updateDeviceState()
{
- IDevice::ConstPtr current = DeviceKitInformation::device(kit());
+ IDevice::ConstPtr current = DeviceKitAspect::device(kit());
QIcon overlay;
static const QIcon disconnected = Icons::DEVICE_DISCONNECTED_INDICATOR_OVERLAY.icon();
diff --git a/src/plugins/projectexplorer/target.h b/src/plugins/projectexplorer/target.h
index 18eb92d273..a630e28468 100644
--- a/src/plugins/projectexplorer/target.h
+++ b/src/plugins/projectexplorer/target.h
@@ -34,18 +34,13 @@
QT_FORWARD_DECLARE_CLASS(QIcon)
-namespace Utils { class Environment; }
-
namespace ProjectExplorer {
class BuildConfiguration;
-class BuildTargetInfoList;
+class BuildTargetInfo;
class DeployConfiguration;
-class DeployConfigurationFactory;
class DeploymentData;
-class BuildConfigurationFactory;
-class RunConfigurationFactory;
class Kit;
-class NamedWidget;
+class MakeInstallCommand;
class Project;
class RunConfiguration;
@@ -86,8 +81,9 @@ public:
void setDeploymentData(const DeploymentData &deploymentData);
DeploymentData deploymentData() const;
- void setApplicationTargets(const BuildTargetInfoList &appTargets);
- BuildTargetInfoList applicationTargets() const;
+ void setApplicationTargets(const QList<BuildTargetInfo> &appTargets);
+ const QList<BuildTargetInfo> applicationTargets() const;
+ BuildTargetInfo buildTarget(const QString &buildKey) const;
QList<ProjectConfiguration *> projectConfigurations() const;
@@ -121,6 +117,7 @@ public:
void setNamedSettings(const QString &name, const QVariant &value);
QVariant additionalData(Core::Id id) const;
+ MakeInstallCommand makeInstallCommand(const QString &installRoot) const;
template<typename S, typename R, typename T>
void subscribeSignal(void (S::*sig)(), R*recv, T (R::*sl)()) {
diff --git a/src/plugins/projectexplorer/targetsettingspanel.cpp b/src/plugins/projectexplorer/targetsettingspanel.cpp
index 78d7daabc8..adaba34842 100644
--- a/src/plugins/projectexplorer/targetsettingspanel.cpp
+++ b/src/plugins/projectexplorer/targetsettingspanel.cpp
@@ -80,6 +80,12 @@ class TargetSetupPageWrapper : public QWidget
public:
explicit TargetSetupPageWrapper(Project *project);
+ void ensureSetupPage()
+ {
+ if (!m_targetSetupPage)
+ addTargetSetupPage();
+ }
+
protected:
void keyReleaseEvent(QKeyEvent *event) override
{
@@ -89,24 +95,26 @@ protected:
void keyPressEvent(QKeyEvent *event) override
{
+ if (m_targetSetupPage && m_targetSetupPage->importLineEditHasFocus())
+ return;
if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) {
event->accept();
- done();
+ if (m_targetSetupPage)
+ done();
}
}
private:
void done()
{
+ QTC_ASSERT(m_targetSetupPage, return);
+ m_targetSetupPage->disconnect();
m_targetSetupPage->setupProject(m_project);
+ m_targetSetupPage->deleteLater();
+ m_targetSetupPage = nullptr;
Core::ModeManager::activateMode(Core::Constants::MODE_EDIT);
}
- void cancel()
- {
- ProjectExplorerPlugin::unloadProject(m_project);
- }
-
void kitUpdated(ProjectExplorer::Kit *k)
{
if (k == KitManager::defaultKit())
@@ -115,29 +123,21 @@ private:
void completeChanged()
{
- m_configureButton->setEnabled(m_targetSetupPage->isComplete());
+ m_configureButton->setEnabled(m_targetSetupPage && m_targetSetupPage->isComplete());
}
void updateNoteText();
+ void addTargetSetupPage();
- Project *m_project;
- TargetSetupPage *m_targetSetupPage;
- QPushButton *m_configureButton;
+ Project * const m_project;
+ TargetSetupPage *m_targetSetupPage = nullptr;
+ QPushButton *m_configureButton = nullptr;
+ QVBoxLayout *m_setupPageContainer = nullptr;
};
TargetSetupPageWrapper::TargetSetupPageWrapper(Project *project)
: m_project(project)
{
- m_targetSetupPage = new TargetSetupPage(this);
- m_targetSetupPage->setUseScrollArea(false);
- m_targetSetupPage->setProjectPath(project->projectFilePath().toString());
- m_targetSetupPage->setRequiredKitPredicate(project->requiredKitPredicate());
- m_targetSetupPage->setPreferredKitPredicate(project->preferredKitPredicate());
- m_targetSetupPage->setProjectImporter(project->projectImporter());
- m_targetSetupPage->initializePage();
- m_targetSetupPage->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
- updateNoteText();
-
auto box = new QDialogButtonBox(this);
m_configureButton = new QPushButton(this);
@@ -150,24 +150,20 @@ TargetSetupPageWrapper::TargetSetupPageWrapper(Project *project)
auto layout = new QVBoxLayout(this);
layout->setMargin(0);
- layout->addWidget(m_targetSetupPage);
+ m_setupPageContainer = new QVBoxLayout;
+ layout->addLayout(m_setupPageContainer);
layout->addLayout(hbox);
layout->addStretch(10);
-
completeChanged();
-
connect(m_configureButton, &QAbstractButton::clicked,
this, &TargetSetupPageWrapper::done);
- connect(m_targetSetupPage, &QWizardPage::completeChanged,
- this, &TargetSetupPageWrapper::completeChanged);
- connect(KitManager::instance(), &KitManager::defaultkitChanged,
- this, &TargetSetupPageWrapper::updateNoteText);
- connect(KitManager::instance(), &KitManager::kitUpdated,
- this, &TargetSetupPageWrapper::kitUpdated);
}
void TargetSetupPageWrapper::updateNoteText()
{
+ if (!m_targetSetupPage)
+ return;
+
Kit *k = KitManager::defaultKit();
QString text;
@@ -198,6 +194,29 @@ void TargetSetupPageWrapper::updateNoteText()
m_targetSetupPage->showOptionsHint(showHint);
}
+void TargetSetupPageWrapper::addTargetSetupPage()
+{
+ m_targetSetupPage = new TargetSetupPage(this);
+ m_targetSetupPage->setUseScrollArea(false);
+ m_targetSetupPage->setProjectPath(m_project->projectFilePath().toString());
+ m_targetSetupPage->setRequiredKitPredicate(m_project->requiredKitPredicate());
+ m_targetSetupPage->setPreferredKitPredicate(m_project->preferredKitPredicate());
+ m_targetSetupPage->setProjectImporter(m_project->projectImporter());
+ m_targetSetupPage->initializePage();
+ m_targetSetupPage->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+ m_setupPageContainer->addWidget(m_targetSetupPage);
+ updateNoteText();
+
+ completeChanged();
+
+ connect(m_targetSetupPage, &QWizardPage::completeChanged,
+ this, &TargetSetupPageWrapper::completeChanged);
+ connect(KitManager::instance(), &KitManager::defaultkitChanged,
+ this, &TargetSetupPageWrapper::updateNoteText);
+ connect(KitManager::instance(), &KitManager::kitUpdated,
+ this, &TargetSetupPageWrapper::kitUpdated);
+}
+
//
// TargetSettingsPanelItem
//
@@ -228,6 +247,7 @@ public:
QPointer<QWidget> m_noKitLabel;
QPointer<QWidget> m_configurePage;
QPointer<QWidget> m_configuredPage;
+ TargetSetupPageWrapper *m_targetSetupPageWrapper = nullptr;
};
void TargetGroupItemPrivate::ensureWidget()
@@ -253,12 +273,13 @@ void TargetGroupItemPrivate::ensureWidget()
}
if (!m_configurePage) {
- auto widget = new TargetSetupPageWrapper(m_project);
+ m_targetSetupPageWrapper = new TargetSetupPageWrapper(m_project);
m_configurePage = new PanelsWidget(tr("Configure Project"),
QIcon(":/projectexplorer/images/unconfigured.png"),
- widget);
- m_configurePage->setFocusProxy(widget);
+ m_targetSetupPageWrapper);
+ m_configurePage->setFocusProxy(m_targetSetupPageWrapper);
}
+ m_targetSetupPageWrapper->ensureSetupPage();
if (!m_configuredPage) {
auto widget = new QWidget;
@@ -283,7 +304,7 @@ class TargetItem : public TypedTreeItem<TreeItem, TargetGroupItem>
public:
enum { DefaultPage = 0 }; // Build page.
- TargetItem(Project *project, Id kitId, const QList<Task> &issues)
+ TargetItem(Project *project, Id kitId, const Tasks &issues)
: m_project(project), m_kitId(kitId), m_kitIssues(issues)
{
m_kitWarningForProject = containsType(m_kitIssues, Task::TaskType::Warning);
@@ -483,7 +504,7 @@ public:
int m_currentChild = DefaultPage;
bool m_kitErrorsForProject = false;
bool m_kitWarningForProject = false;
- QList<Task> m_kitIssues;
+ Tasks m_kitIssues;
private:
enum class IconOverlay {
diff --git a/src/plugins/projectexplorer/targetsetuppage.cpp b/src/plugins/projectexplorer/targetsetuppage.cpp
index 501e0efc39..0a750199fe 100644
--- a/src/plugins/projectexplorer/targetsetuppage.cpp
+++ b/src/plugins/projectexplorer/targetsetuppage.cpp
@@ -67,10 +67,10 @@ IPotentialKit::~IPotentialKit()
}
namespace Internal {
-static Utils::FileName importDirectory(const QString &projectPath)
+static Utils::FilePath importDirectory(const QString &projectPath)
{
// Setup import widget:
- auto path = Utils::FileName::fromString(projectPath);
+ auto path = Utils::FilePath::fromString(projectPath);
path = path.parentDir(); // base dir
path = path.parentDir(); // parent dir
@@ -210,7 +210,7 @@ TargetSetupPage::TargetSetupPage(QWidget *parent) :
connect(km, &KitManager::kitRemoved, this, &TargetSetupPage::handleKitRemoval);
connect(km, &KitManager::kitUpdated, this, &TargetSetupPage::handleKitUpdate);
connect(m_importWidget, &ImportWidget::importFrom,
- this, [this](const Utils::FileName &dir) { import(dir); });
+ this, [this](const Utils::FilePath &dir) { import(dir); });
setProperty(Utils::SHORT_TITLE_PROPERTY, tr("Kits"));
}
@@ -328,6 +328,11 @@ void TargetSetupPage::setProjectImporter(ProjectImporter *importer)
initializePage();
}
+bool TargetSetupPage::importLineEditHasFocus() const
+{
+ return m_importWidget->lineEditHasFocus();
+}
+
void TargetSetupPage::setNoteText(const QString &text)
{
m_ui->descriptionLabel->setText(text);
@@ -347,7 +352,7 @@ void TargetSetupPage::setupImports()
QStringList toImport = m_importer->importCandidates();
foreach (const QString &path, toImport)
- import(Utils::FileName::fromString(path), true);
+ import(Utils::FilePath::fromString(path), true);
}
void TargetSetupPage::handleKitAddition(Kit *k)
@@ -485,7 +490,7 @@ bool TargetSetupPage::isUpdating() const
return false;
}
-void TargetSetupPage::import(const Utils::FileName &path, bool silent)
+void TargetSetupPage::import(const Utils::FilePath &path, bool silent)
{
if (!m_importer)
return;
diff --git a/src/plugins/projectexplorer/targetsetuppage.h b/src/plugins/projectexplorer/targetsetuppage.h
index 86eeb65013..102ffbd57c 100644
--- a/src/plugins/projectexplorer/targetsetuppage.h
+++ b/src/plugins/projectexplorer/targetsetuppage.h
@@ -40,7 +40,7 @@
QT_FORWARD_DECLARE_CLASS(QSpacerItem)
namespace Core { class Id; }
-namespace Utils { class FileName; }
+namespace Utils { class FilePath; }
namespace ProjectExplorer {
class Kit;
@@ -70,6 +70,7 @@ public:
void setPreferredKitPredicate(const ProjectExplorer::Kit::Predicate &predicate);
void setProjectPath(const QString &dir);
void setProjectImporter(ProjectImporter *importer);
+ bool importLineEditHasFocus() const;
/// Sets whether the targetsetupage uses a scrollarea
/// to host the widgets from the factories
@@ -105,7 +106,7 @@ private:
Internal::TargetSetupWidget *addWidget(Kit *k);
void setupImports();
- void import(const Utils::FileName &path, bool silent = false);
+ void import(const Utils::FilePath &path, bool silent = false);
void setupWidgets(const QString &filterText = QString());
void reset();
diff --git a/src/plugins/projectexplorer/targetsetupwidget.cpp b/src/plugins/projectexplorer/targetsetupwidget.cpp
index 88e5b4ab06..6aa66517e3 100644
--- a/src/plugins/projectexplorer/targetsetupwidget.cpp
+++ b/src/plugins/projectexplorer/targetsetupwidget.cpp
@@ -29,7 +29,6 @@
#include "buildinfo.h"
#include "projectexplorerconstants.h"
#include "kit.h"
-#include "kitconfigwidget.h"
#include "kitmanager.h"
#include "kitoptionspage.h"
@@ -73,7 +72,7 @@ TargetSetupWidget::TargetSetupWidget(Kit *k, const QString &projectPath) :
auto panel = new Utils::FadingWidget(m_detailsWidget);
auto panelLayout = new QHBoxLayout(panel);
- m_manageButton = new QPushButton(KitConfigWidget::msgManage());
+ m_manageButton = new QPushButton(KitAspectWidget::msgManage());
panelLayout->addWidget(m_manageButton);
m_detailsWidget->setToolWidget(panel);
@@ -319,7 +318,7 @@ QPair<Task::TaskType, QString> TargetSetupWidget::findIssues(const BuildInfo &in
return qMakePair(Task::Unknown, QString());
QString buildDir = info.buildDirectory.toString();
- QList<Task> issues;
+ Tasks issues;
if (info.factory())
issues = info.factory()->reportIssues(m_kit, m_projectPath, buildDir);
diff --git a/src/plugins/projectexplorer/task.cpp b/src/plugins/projectexplorer/task.cpp
index 83409fadd5..2a323f0041 100644
--- a/src/plugins/projectexplorer/task.cpp
+++ b/src/plugins/projectexplorer/task.cpp
@@ -25,6 +25,7 @@
#include "task.h"
+#include "fileinsessionfinder.h"
#include "projectexplorerconstants.h"
#include <app/app_version.h>
@@ -34,6 +35,7 @@
#include <utils/utilsicons.h>
#include <utils/qtcassert.h>
+#include <QFileInfo>
#include <QTextStream>
namespace ProjectExplorer
@@ -60,13 +62,14 @@ unsigned int Task::s_nextId = 1;
*/
Task::Task(TaskType type_, const QString &description_,
- const Utils::FileName &file_, int line_, Core::Id category_,
+ const Utils::FilePath &file_, int line_, Core::Id category_,
const QIcon &icon, Options options) :
taskId(s_nextId), type(type_), options(options), description(description_),
- file(file_), line(line_), movedLine(line_), category(category_),
+ line(line_), movedLine(line_), category(category_),
icon(icon.isNull() ? taskTypeIcon(type_) : icon)
{
++s_nextId;
+ setFile(file_);
}
Task Task::compilerMissingTask()
@@ -76,7 +79,7 @@ Task Task::compilerMissingTask()
"%1 needs a compiler set up to build. "
"Configure a compiler in the kit options.")
.arg(Core::Constants::IDE_DISPLAY_NAME),
- Utils::FileName(), -1,
+ Utils::FilePath(), -1,
Constants::TASK_CATEGORY_BUILDSYSTEM);
}
@@ -87,7 +90,7 @@ Task Task::buildConfigurationMissingTask()
"%1 needs a build configuration set up to build. "
"Configure a build configuration in the project settings.")
.arg(Core::Constants::IDE_DISPLAY_NAME),
- Utils::FileName(), -1,
+ Utils::FilePath(), -1,
Constants::TASK_CATEGORY_BUILDSYSTEM);
}
@@ -108,7 +111,7 @@ void Task::clear()
taskId = 0;
type = Task::Unknown;
description.clear();
- file = Utils::FileName();
+ file = Utils::FilePath();
line = -1;
movedLine = -1;
category = Core::Id();
@@ -117,6 +120,18 @@ void Task::clear()
m_mark.clear();
}
+void Task::setFile(const Utils::FilePath &file_)
+{
+ file = file_;
+ if (!file.isEmpty() && !file.toFileInfo().isAbsolute()) {
+ Utils::FilePathList possiblePaths = Internal::findFileInSession(file);
+ if (possiblePaths.length() == 1)
+ file = possiblePaths.first();
+ else
+ fileCandidates = possiblePaths;
+ }
+}
+
//
// functions
//
@@ -153,7 +168,7 @@ uint qHash(const Task &task)
return task.taskId;
}
-QString toHtml(const QList<Task> &issues)
+QString toHtml(const Tasks &issues)
{
QString result;
QTextStream str(&result);
@@ -176,7 +191,7 @@ QString toHtml(const QList<Task> &issues)
return result;
}
-bool containsType(const QList<Task> &issues, Task::TaskType type)
+bool containsType(const Tasks &issues, Task::TaskType type)
{
return Utils::contains(issues, [type](const Task &t) { return t.type == type; });
}
diff --git a/src/plugins/projectexplorer/task.h b/src/plugins/projectexplorer/task.h
index f3e1b76c88..739e90f176 100644
--- a/src/plugins/projectexplorer/task.h
+++ b/src/plugins/projectexplorer/task.h
@@ -61,7 +61,7 @@ public:
Task() = default;
Task(TaskType type, const QString &description,
- const Utils::FileName &file, int line, Core::Id category,
+ const Utils::FilePath &file, int line, Core::Id category,
const QIcon &icon = QIcon(),
Options options = AddTextMark | FlashWorthy);
@@ -70,12 +70,14 @@ public:
bool isNull() const;
void clear();
+ void setFile(const Utils::FilePath &file);
unsigned int taskId = 0;
TaskType type = Unknown;
Options options = AddTextMark | FlashWorthy;
QString description;
- Utils::FileName file;
+ Utils::FilePath file;
+ Utils::FilePathList fileCandidates;
int line = -1;
int movedLine = -1; // contains a line number if the line was moved in the editor
Core::Id category;
@@ -100,13 +102,15 @@ private:
friend class TaskHub;
};
+using Tasks = QVector<Task>;
+
bool PROJECTEXPLORER_EXPORT operator==(const Task &t1, const Task &t2);
uint PROJECTEXPLORER_EXPORT qHash(const Task &task);
bool PROJECTEXPLORER_EXPORT operator<(const Task &a, const Task &b);
-QString PROJECTEXPLORER_EXPORT toHtml(const QList<Task> &issues);
-bool PROJECTEXPLORER_EXPORT containsType(const QList<Task> &issues, Task::TaskType);
+QString PROJECTEXPLORER_EXPORT toHtml(const Tasks &issues);
+bool PROJECTEXPLORER_EXPORT containsType(const Tasks &issues, Task::TaskType);
} //namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/taskhub.cpp b/src/plugins/projectexplorer/taskhub.cpp
index 5ed8aa9677..10b04c4d5b 100644
--- a/src/plugins/projectexplorer/taskhub.cpp
+++ b/src/plugins/projectexplorer/taskhub.cpp
@@ -79,7 +79,7 @@ public:
bool isClickable() const override;
void clicked() override;
- void updateFileName(const FileName &fileName) override;
+ void updateFileName(const FilePath &fileName) override;
void updateLineNumber(int lineNumber) override;
void removedFromEditor() override;
private:
@@ -92,10 +92,10 @@ void TaskMark::updateLineNumber(int lineNumber)
TextMark::updateLineNumber(lineNumber);
}
-void TaskMark::updateFileName(const FileName &fileName)
+void TaskMark::updateFileName(const FilePath &fileName)
{
TaskHub::updateTaskFileName(m_id, fileName.toString());
- TextMark::updateFileName(FileName::fromString(fileName.toString()));
+ TextMark::updateFileName(FilePath::fromString(fileName.toString()));
}
void TaskMark::removedFromEditor()
@@ -117,7 +117,7 @@ TaskHub::TaskHub()
{
m_instance = this;
qRegisterMetaType<ProjectExplorer::Task>("ProjectExplorer::Task");
- qRegisterMetaType<QList<ProjectExplorer::Task> >("QList<ProjectExplorer::Task>");
+ qRegisterMetaType<Tasks >("Tasks");
}
TaskHub::~TaskHub()
@@ -138,7 +138,7 @@ TaskHub *TaskHub::instance()
return m_instance;
}
-void TaskHub::addTask(Task::TaskType type, const QString &description, Core::Id category, const Utils::FileName &file, int line)
+void TaskHub::addTask(Task::TaskType type, const QString &description, Core::Id category, const Utils::FilePath &file, int line)
{
addTask(Task(type, description, file, line, category));
}
diff --git a/src/plugins/projectexplorer/taskhub.h b/src/plugins/projectexplorer/taskhub.h
index 80bb6a5219..fc2c489c1a 100644
--- a/src/plugins/projectexplorer/taskhub.h
+++ b/src/plugins/projectexplorer/taskhub.h
@@ -43,7 +43,7 @@ public:
// Convenience overload
static void addTask(Task::TaskType type, const QString &description,
Core::Id category,
- const Utils::FileName &file = Utils::FileName(),
+ const Utils::FilePath &file = Utils::FilePath(),
int line = -1);
public slots:
diff --git a/src/plugins/projectexplorer/taskmodel.cpp b/src/plugins/projectexplorer/taskmodel.cpp
index dcdf1554c8..8fcc48e737 100644
--- a/src/plugins/projectexplorer/taskmodel.cpp
+++ b/src/plugins/projectexplorer/taskmodel.cpp
@@ -25,11 +25,13 @@
#include "taskmodel.h"
+#include "fileinsessionfinder.h"
#include "task.h"
#include "taskhub.h"
#include <utils/qtcassert.h>
+#include <QFileInfo>
#include <QFontMetrics>
#include <algorithm>
@@ -84,12 +86,12 @@ void TaskModel::addCategory(Core::Id categoryId, const QString &categoryName)
m_categories.insert(categoryId, data);
}
-QList<Task> TaskModel::tasks(Core::Id categoryId) const
+Tasks TaskModel::tasks(Core::Id categoryId) const
{
if (!categoryId.isValid())
return m_tasks;
- QList<Task> taskList;
+ Tasks taskList;
foreach (const Task &t, m_tasks) {
if (t.category == categoryId)
taskList.append(t);
@@ -117,17 +119,18 @@ void TaskModel::addTask(const Task &task)
endInsertRows();
}
-void TaskModel::removeTask(const Task &task)
+void TaskModel::removeTask(unsigned int id)
{
- int index = m_tasks.indexOf(task);
- if (index >= 0) {
+ for (int index = 0; index < m_tasks.length(); ++index) {
+ if (m_tasks.at(index).taskId != id)
+ continue;
const Task &t = m_tasks.at(index);
-
beginRemoveRows(QModelIndex(), index, index);
- m_categories[task.category].removeTask(t);
+ m_categories[t.category].removeTask(t);
m_categories[Core::Id()].removeTask(t);
m_tasks.removeAt(index);
endRemoveRows();
+ break;
}
}
@@ -144,7 +147,7 @@ void TaskModel::updateTaskFileName(unsigned int id, const QString &fileName)
int i = rowForId(id);
QTC_ASSERT(i != -1, return);
if (m_tasks.at(i).taskId == id) {
- m_tasks[i].file = Utils::FileName::fromString(fileName);
+ m_tasks[i].file = Utils::FilePath::fromString(fileName);
emit dataChanged(index(i, 0), index(i, 0));
}
}
@@ -294,7 +297,7 @@ int TaskModel::sizeOfFile(const QFont &font)
if (pos != -1)
filename = filename.mid(pos +1);
- m_maxSizeOfFileName = qMax(m_maxSizeOfFileName, fm.width(filename));
+ m_maxSizeOfFileName = qMax(m_maxSizeOfFileName, fm.horizontalAdvance(filename));
}
m_lastMaxSizeIndex = count - 1;
return m_maxSizeOfFileName;
@@ -305,7 +308,7 @@ int TaskModel::sizeOfLineNumber(const QFont &font)
if (m_sizeOfLineNumber == 0 || font != m_lineMeasurementFont) {
QFontMetrics fm(font);
m_lineMeasurementFont = font;
- m_sizeOfLineNumber = fm.width(QLatin1String("88888"));
+ m_sizeOfLineNumber = fm.horizontalAdvance(QLatin1String("88888"));
}
return m_sizeOfLineNumber;
}
@@ -323,174 +326,44 @@ void TaskModel::setFileNotFound(const QModelIndex &idx, bool b)
// TaskFilterModel
/////
-TaskFilterModel::TaskFilterModel(TaskModel *sourceModel, QObject *parent) : QAbstractItemModel(parent),
- m_sourceModel(sourceModel)
+TaskFilterModel::TaskFilterModel(TaskModel *sourceModel, QObject *parent)
+ : QSortFilterProxyModel(parent)
{
- Q_ASSERT(m_sourceModel);
- updateMapping();
-
- connect(m_sourceModel, &QAbstractItemModel::rowsInserted,
- this, &TaskFilterModel::handleNewRows);
-
- connect(m_sourceModel, &QAbstractItemModel::rowsAboutToBeRemoved,
- this, &TaskFilterModel::handleRowsAboutToBeRemoved);
- connect(m_sourceModel, &QAbstractItemModel::rowsRemoved,
- this, [this](const QModelIndex &parent, int, int) {
- QTC_ASSERT(!parent.isValid(), return);
- if (m_beginRemoveRowsSent) {
- m_beginRemoveRowsSent = false;
- endRemoveRows();
- }
- });
-
- connect(m_sourceModel, &QAbstractItemModel::modelReset,
- this, &TaskFilterModel::invalidateFilter);
-
- connect(m_sourceModel, &QAbstractItemModel::dataChanged,
- this, &TaskFilterModel::handleDataChanged);
-
+ QTC_ASSERT(sourceModel, return);
+ setSourceModel(sourceModel);
m_includeUnknowns = m_includeWarnings = m_includeErrors = true;
}
-QModelIndex TaskFilterModel::index(int row, int column, const QModelIndex &parent) const
-{
- if (parent.isValid())
- return QModelIndex();
- return createIndex(row, column);
-}
-
-QModelIndex TaskFilterModel::parent(const QModelIndex &child) const
-{
- Q_UNUSED(child)
- return QModelIndex();
-}
-
-int TaskFilterModel::rowCount(const QModelIndex &parent) const
-{
- if (parent.isValid())
- return 0;
-
- return m_mapping.count();
-}
-
-int TaskFilterModel::columnCount(const QModelIndex &parent) const
-{
- if (parent.isValid())
- return 0;
- return m_sourceModel->columnCount(parent);
-}
-
-QVariant TaskFilterModel::data(const QModelIndex &index, int role) const
-{
- return m_sourceModel->data(mapToSource(index), role);
-}
-
-static QPair<int, int> findFilteredRange(int first, int last, const QList<int> &list)
+void TaskFilterModel::setFilterIncludesWarnings(bool b)
{
- auto filteredFirst = std::lower_bound(list.constBegin(), list.constEnd(), first);
- auto filteredLast = std::upper_bound(filteredFirst, list.constEnd(), last);
- return qMakePair(filteredFirst - list.constBegin(), filteredLast - list.constBegin() - 1);
+ m_includeWarnings = b;
+ m_includeUnknowns = b; // "Unknowns" are often associated with warnings
+ invalidateFilter();
}
-void TaskFilterModel::handleNewRows(const QModelIndex &index, int first, int last)
+void TaskFilterModel::updateFilterProperties(const QString &filterText,
+ Qt::CaseSensitivity caseSensitivity, bool isRegexp)
{
- QTC_ASSERT(!index.isValid(), return);
-
- const int newItemCount = last - first + 1;
-
- QList<int> newMapping;
- for (int i = first; i <= last; ++i) {
- const Task &task = m_sourceModel->task(m_sourceModel->index(i, 0));
- if (filterAcceptsTask(task))
- newMapping.append(i);
- }
-
- const int newMappingCount = newMapping.count();
- if (!newMappingCount)
+ if (filterText == m_filterText && m_filterCaseSensitivity == caseSensitivity
+ && m_filterStringIsRegexp == isRegexp) {
return;
-
- int filteredFirst = -1;
- if (last == m_sourceModel->rowCount() - 1)
- filteredFirst = m_mapping.count();
- else
- filteredFirst = std::lower_bound(m_mapping.constBegin(), m_mapping.constEnd(), first) - m_mapping.constBegin();
-
- const int filteredLast = filteredFirst + newMappingCount - 1;
- beginInsertRows(QModelIndex(), filteredFirst, filteredLast);
- if (filteredFirst == m_mapping.count()) {
- m_mapping.append(newMapping);
- } else {
- const QList<int> rest = m_mapping.mid(filteredFirst);
-
- m_mapping.reserve(m_mapping.count() + newMappingCount);
- m_mapping.erase(m_mapping.begin() + filteredFirst, m_mapping.end());
- m_mapping.append(newMapping);
- for (int pos : rest)
- m_mapping.append(pos + newItemCount);
}
- endInsertRows();
-}
-
-void TaskFilterModel::handleRowsAboutToBeRemoved(const QModelIndex &index, int first, int last)
-{
- m_beginRemoveRowsSent = false;
- QTC_ASSERT(!index.isValid(), return);
-
- const QPair<int, int> range = findFilteredRange(first, last, m_mapping);
- if (range.first <= range.second) { // remove corresponding rows in filtermodel
- beginRemoveRows(QModelIndex(), range.first, range.second);
- m_beginRemoveRowsSent = true;
- m_mapping.erase(m_mapping.begin() + range.first, m_mapping.begin() + range.second + 1);
+ m_filterText = filterText;
+ m_filterCaseSensitivity = caseSensitivity;
+ m_filterStringIsRegexp = isRegexp;
+ if (m_filterStringIsRegexp) {
+ m_filterRegexp.setPattern(m_filterText);
+ m_filterRegexp.setPatternOptions(m_filterCaseSensitivity == Qt::CaseInsensitive
+ ? QRegularExpression::CaseInsensitiveOption
+ : QRegularExpression::NoPatternOption);
}
- // adapt existing mapping to removed source indices
- const int sourceRemovedCount = (last - first) + 1;
- for (int i = range.first; i < m_mapping.count(); ++i)
- m_mapping[i] = m_mapping.at(i) - sourceRemovedCount;
-}
-
-void TaskFilterModel::handleDataChanged(const QModelIndex &top, const QModelIndex &bottom)
-{
- const QPair<int, int> range = findFilteredRange(top.row(), bottom.row(), m_mapping);
- if (range.first > range.second)
- return;
-
- emit dataChanged(index(range.first, top.column()), index(range.second, bottom.column()));
-}
-
-QModelIndex TaskFilterModel::mapFromSource(const QModelIndex &idx) const
-{
- if (!idx.isValid())
- return QModelIndex();
- auto it = std::lower_bound(m_mapping.constBegin(), m_mapping.constEnd(), idx.row());
- QTC_ASSERT(it != m_mapping.constEnd() && idx.row() == *it, return QModelIndex());
- return index(it - m_mapping.constBegin(), 0);
-}
-
-QModelIndex TaskFilterModel::mapToSource(const QModelIndex &index) const
-{
- if (!index.isValid())
- return QModelIndex();
- int row = index.row();
- QTC_ASSERT(row >= 0 && row < m_mapping.count(), return QModelIndex());
- return m_sourceModel->index(m_mapping.at(row), index.column(), index.parent());
-}
-
-void TaskFilterModel::invalidateFilter()
-{
- beginResetModel();
- updateMapping();
- endResetModel();
+ invalidateFilter();
}
-void TaskFilterModel::updateMapping() const
+bool TaskFilterModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
- m_mapping.clear();
- for (int i = 0; i < m_sourceModel->rowCount(); ++i) {
- QModelIndex index = m_sourceModel->index(i, 0);
- const Task &task = m_sourceModel->task(index);
- if (filterAcceptsTask(task))
- m_mapping.append(i);
- }
+ Q_UNUSED(source_parent);
+ return filterAcceptsTask(taskModel()->tasks().at(source_row));
}
bool TaskFilterModel::filterAcceptsTask(const Task &task) const
@@ -508,9 +381,18 @@ bool TaskFilterModel::filterAcceptsTask(const Task &task) const
break;
}
- if (m_categoryIds.contains(task.category))
+ if (accept && m_categoryIds.contains(task.category))
accept = false;
+ if (accept && !m_filterText.isEmpty()) {
+ const auto accepts = [this](const QString &s) {
+ return m_filterStringIsRegexp ? m_filterRegexp.isValid() && s.contains(m_filterRegexp)
+ : s.contains(m_filterText, m_filterCaseSensitivity);
+ };
+ if (!accepts(task.file.toString()) && !accepts(task.description))
+ accept = false;
+ }
+
return accept;
}
diff --git a/src/plugins/projectexplorer/taskmodel.h b/src/plugins/projectexplorer/taskmodel.h
index 4b2757c289..b1044a3234 100644
--- a/src/plugins/projectexplorer/taskmodel.h
+++ b/src/plugins/projectexplorer/taskmodel.h
@@ -25,9 +25,10 @@
#pragma once
-#include <QAbstractItemModel>
+#include <QSortFilterProxyModel>
#include <QIcon>
+#include <QRegularExpression>
#include "task.h"
@@ -53,9 +54,9 @@ public:
QString categoryDisplayName(Core::Id categoryId) const;
void addCategory(Core::Id categoryId, const QString &categoryName);
- QList<Task> tasks(Core::Id categoryId = Core::Id()) const;
- void addTask(const Task &task);
- void removeTask(const Task &task);
+ Tasks tasks(Core::Id categoryId = Core::Id()) const;
+ void addTask(const Task &t);
+ void removeTask(unsigned int id);
void clearTasks(Core::Id categoryId = Core::Id());
void updateTaskFileName(unsigned int id, const QString &fileName);
void updateTaskLineNumber(unsigned int id, int line);
@@ -110,7 +111,7 @@ private:
};
QHash<Core::Id,CategoryData> m_categories; // category id to data
- QList<Task> m_tasks; // all tasks (in order of id)
+ Tasks m_tasks; // all tasks (in order of id)
QHash<QString,bool> m_fileNotFound;
QFont m_fileMeasurementFont;
@@ -120,26 +121,17 @@ private:
int m_sizeOfLineNumber = 0;
};
-class TaskFilterModel : public QAbstractItemModel
+class TaskFilterModel : public QSortFilterProxyModel
{
Q_OBJECT
public:
TaskFilterModel(TaskModel *sourceModel, QObject *parent = nullptr);
- TaskModel *taskModel() { return m_sourceModel; }
-
- QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
- QModelIndex parent(const QModelIndex &child) const override;
- int rowCount(const QModelIndex &parent = QModelIndex()) const override;
- int columnCount(const QModelIndex &parent = QModelIndex()) const override;
- QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
-
- bool filterIncludesUnknowns() const { return m_includeUnknowns; }
- void setFilterIncludesUnknowns(bool b) { m_includeUnknowns = b; invalidateFilter(); }
+ TaskModel *taskModel() const { return static_cast<TaskModel *>(sourceModel()); }
bool filterIncludesWarnings() const { return m_includeWarnings; }
- void setFilterIncludesWarnings(bool b) { m_includeWarnings = b; invalidateFilter(); }
+ void setFilterIncludesWarnings(bool b);
bool filterIncludesErrors() const { return m_includeErrors; }
void setFilterIncludesErrors(bool b) { m_includeErrors = b; invalidateFilter(); }
@@ -147,33 +139,27 @@ public:
QList<Core::Id> filteredCategories() const { return m_categoryIds; }
void setFilteredCategories(const QList<Core::Id> &categoryIds) { m_categoryIds = categoryIds; invalidateFilter(); }
- Task task(const QModelIndex &index) const
- { return m_sourceModel->task(mapToSource(index)); }
+ Task task(const QModelIndex &index) const { return taskModel()->task(mapToSource(index)); }
bool hasFile(const QModelIndex &index) const
- { return m_sourceModel->hasFile(mapToSource(index)); }
+ { return taskModel()->hasFile(mapToSource(index)); }
- QModelIndex mapFromSource(const QModelIndex &idx) const;
+ void updateFilterProperties(const QString &filterText, Qt::CaseSensitivity caseSensitivity,
+ bool isRegex);
private:
- void handleNewRows(const QModelIndex &index, int first, int last);
- void handleRowsAboutToBeRemoved(const QModelIndex &index, int first, int last);
- void handleDataChanged(const QModelIndex &top, const QModelIndex &bottom);
-
- QModelIndex mapToSource(const QModelIndex &index) const;
- void invalidateFilter();
- void updateMapping() const;
+ bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
bool filterAcceptsTask(const Task &task) const;
bool m_beginRemoveRowsSent = false;
bool m_includeUnknowns;
bool m_includeWarnings;
bool m_includeErrors;
+ bool m_filterStringIsRegexp = false;
+ Qt::CaseSensitivity m_filterCaseSensitivity = Qt::CaseInsensitive;
QList<Core::Id> m_categoryIds;
-
- mutable QList<int> m_mapping;
-
- TaskModel *m_sourceModel;
+ QString m_filterText;
+ QRegularExpression m_filterRegexp;
};
} // namespace Internal
diff --git a/src/plugins/projectexplorer/taskwindow.cpp b/src/plugins/projectexplorer/taskwindow.cpp
index 7d8010aa27..7a98d0fd33 100644
--- a/src/plugins/projectexplorer/taskwindow.cpp
+++ b/src/plugins/projectexplorer/taskwindow.cpp
@@ -38,6 +38,7 @@
#include <coreplugin/icontext.h>
#include <utils/algorithm.h>
+#include <utils/fileinprojectfinder.h>
#include <utils/qtcassert.h>
#include <utils/itemviews.h>
#include <utils/utilsicons.h>
@@ -236,7 +237,6 @@ static QToolButton *createFilterButton(const QIcon &icon, const QString &toolTip
button->setToolTip(toolTip);
button->setCheckable(true);
button->setChecked(true);
- button->setAutoRaise(true);
button->setEnabled(true);
QObject::connect(button, &QToolButton::toggled, receiver, lambda);
return button;
@@ -282,7 +282,6 @@ TaskWindow::TaskWindow() : d(std::make_unique<TaskWindowPrivate>())
d->m_categoriesButton->setIcon(Utils::Icons::FILTER.icon());
d->m_categoriesButton->setToolTip(tr("Filter by categories"));
d->m_categoriesButton->setProperty("noArrow", true);
- d->m_categoriesButton->setAutoRaise(true);
d->m_categoriesButton->setPopupMode(QToolButton::InstantPopup);
d->m_categoriesMenu = new QMenu(d->m_categoriesButton);
@@ -290,6 +289,9 @@ TaskWindow::TaskWindow() : d(std::make_unique<TaskWindowPrivate>())
d->m_categoriesButton->setMenu(d->m_categoriesMenu);
+ setupFilterUi("IssuesPane.Filter");
+ setFilteringEnabled(true);
+
TaskHub *hub = TaskHub::instance();
connect(hub, &TaskHub::categoryAdded, this, &TaskWindow::addCategory);
connect(hub, &TaskHub::taskAdded, this, &TaskWindow::addTask);
@@ -356,7 +358,7 @@ void TaskWindow::delayedInitialization()
QList<QWidget*> TaskWindow::toolBarWidgets() const
{
- return {d->m_filterWarningsButton, d->m_categoriesButton};
+ return {d->m_filterWarningsButton, d->m_categoriesButton, filterWidget()};
}
QWidget *TaskWindow::outputWidget(QWidget *)
@@ -416,7 +418,6 @@ void TaskWindow::loadSettings()
if (value.isValid()) {
bool includeWarnings = value.toBool();
d->m_filter->setFilterIncludesWarnings(includeWarnings);
- d->m_filter->setFilterIncludesUnknowns(includeWarnings);
d->m_filterWarningsButton->setDown(d->m_filter->filterIncludesWarnings());
}
}
@@ -454,7 +455,7 @@ void TaskWindow::addTask(const Task &task)
void TaskWindow::removeTask(const Task &task)
{
- d->m_model->removeTask(task);
+ d->m_model->removeTask(task.taskId);
emit tasksChanged();
navigateStateChanged();
@@ -498,6 +499,15 @@ void TaskWindow::triggerDefaultHandler(const QModelIndex &index)
if (task.isNull())
return;
+ if (!task.file.isEmpty() && !task.file.toFileInfo().isAbsolute()
+ && !task.fileCandidates.empty()) {
+ const Utils::FilePath userChoice = Utils::chooseFileFromList(task.fileCandidates);
+ if (!userChoice.isEmpty()) {
+ task.file = userChoice;
+ updatedTaskFileName(task.taskId, task.file.toString());
+ }
+ }
+
if (d->m_defaultHandler->canHandle(task)) {
d->m_defaultHandler->handle(task);
} else {
@@ -526,7 +536,6 @@ void TaskWindow::actionTriggered()
void TaskWindow::setShowWarnings(bool show)
{
d->m_filter->setFilterIncludesWarnings(show);
- d->m_filter->setFilterIncludesUnknowns(show); // "Unknowns" are often associated with warnings
}
void TaskWindow::updateCategoriesMenu()
@@ -658,6 +667,11 @@ void TaskWindow::goToPrev()
triggerDefaultHandler(currentIndex);
}
+void TaskWindow::updateFilter()
+{
+ d->m_filter->updateFilterProperties(filterText(), filterCaseSensitivity(), filterUsesRegexp());
+}
+
bool TaskWindow::canNavigate() const
{
return true;
@@ -786,7 +800,7 @@ void TaskDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
QString bottom = index.data(TaskModel::Description).toString().split(QLatin1Char('\n')).first();
painter->setClipRect(positions.textArea());
painter->drawText(positions.textAreaLeft(), positions.top() + fm.ascent(), bottom);
- if (fm.width(bottom) > positions.textAreaWidth()) {
+ if (fm.horizontalAdvance(bottom) > positions.textAreaWidth()) {
// draw a gradient to mask the text
int gradientStart = positions.textAreaRight() - ELLIPSIS_GRADIENT_WIDTH + 1;
QLinearGradient lg(gradientStart, 0, gradientStart + ELLIPSIS_GRADIENT_WIDTH, 0);
@@ -840,7 +854,7 @@ void TaskDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
const int pos = file.lastIndexOf(QLatin1Char('/'));
if (pos != -1)
file = file.mid(pos +1);
- const int realFileWidth = fm.width(file);
+ const int realFileWidth = fm.horizontalAdvance(file);
painter->setClipRect(positions.fileArea());
painter->drawText(qMin(positions.fileAreaLeft(), positions.fileAreaRight() - realFileWidth),
positions.top() + fm.ascent(), file);
@@ -877,7 +891,7 @@ void TaskDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
}
painter->setClipRect(positions.lineArea());
- const int realLineWidth = fm.width(lineText);
+ const int realLineWidth = fm.horizontalAdvance(lineText);
painter->drawText(positions.lineAreaRight() - realLineWidth, positions.top() + fm.ascent(), lineText);
painter->setClipRect(opt.rect);
diff --git a/src/plugins/projectexplorer/taskwindow.h b/src/plugins/projectexplorer/taskwindow.h
index 290927b47b..efefb72658 100644
--- a/src/plugins/projectexplorer/taskwindow.h
+++ b/src/plugins/projectexplorer/taskwindow.h
@@ -82,6 +82,8 @@ signals:
void tasksCleared();
private:
+ void updateFilter() override;
+
void addCategory(Core::Id categoryId, const QString &displayName, bool visible);
void addTask(const ProjectExplorer::Task &task);
void removeTask(const ProjectExplorer::Task &task);
diff --git a/src/plugins/projectexplorer/toolchain.cpp b/src/plugins/projectexplorer/toolchain.cpp
index 212427417a..66c5ac83db 100644
--- a/src/plugins/projectexplorer/toolchain.cpp
+++ b/src/plugins/projectexplorer/toolchain.cpp
@@ -46,6 +46,8 @@ static const char LANGUAGE_KEY_V2[] = "ProjectExplorer.ToolChain.LanguageV2"; //
namespace ProjectExplorer {
namespace Internal {
+static QList<ToolChainFactory *> g_toolChainFactories;
+
// --------------------------------------------------------------------------
// ToolChainPrivate
// --------------------------------------------------------------------------
@@ -55,10 +57,11 @@ class ToolChainPrivate
public:
using Detection = ToolChain::Detection;
- explicit ToolChainPrivate(Core::Id typeId, Detection d) :
+ explicit ToolChainPrivate(Core::Id typeId) :
m_id(QUuid::createUuid().toByteArray()),
m_typeId(typeId),
- m_detection(d)
+ m_predefinedMacrosCache(new ToolChain::MacrosCache::element_type()),
+ m_headerPathsCache(new ToolChain::HeaderPathsCache::element_type())
{
QTC_ASSERT(m_typeId.isValid(), return);
QTC_ASSERT(!m_typeId.toString().contains(QLatin1Char(':')), return);
@@ -69,7 +72,10 @@ public:
mutable QString m_displayName;
Core::Id m_typeId;
Core::Id m_language;
- Detection m_detection;
+ Detection m_detection = ToolChain::UninitializedDetection;
+
+ ToolChain::MacrosCache m_predefinedMacrosCache;
+ ToolChain::HeaderPathsCache m_headerPathsCache;
};
@@ -116,20 +122,11 @@ QString languageId(Language l)
// --------------------------------------------------------------------------
-ToolChain::ToolChain(Core::Id typeId, Detection d) :
- d(std::make_unique<Internal::ToolChainPrivate>(typeId, d))
+ToolChain::ToolChain(Core::Id typeId) :
+ d(std::make_unique<Internal::ToolChainPrivate>(typeId))
{
}
-ToolChain::ToolChain(const ToolChain &other) : ToolChain(other.d->m_typeId, ManualDetection)
-{
- d->m_language = other.d->m_language;
-
- // leave the autodetection bit at false.
- d->m_displayName = QCoreApplication::translate("ProjectExplorer::ToolChain", "Clone of %1")
- .arg(other.displayName());
-}
-
void ToolChain::setLanguage(Core::Id language)
{
QTC_ASSERT(!d->m_language.isValid() || isAutoDetected(), return);
@@ -167,12 +164,12 @@ QByteArray ToolChain::id() const
return d->m_id;
}
-Utils::FileNameList ToolChain::suggestedMkspecList() const
+QStringList ToolChain::suggestedMkspecList() const
{
- return Utils::FileNameList();
+ return {};
}
-Utils::FileName ToolChain::suggestedDebugger() const
+Utils::FilePath ToolChain::suggestedDebugger() const
{
return ToolChainManager::defaultDebugger(targetAbi());
}
@@ -182,7 +179,7 @@ Core::Id ToolChain::typeId() const
return d->m_typeId;
}
-QList<Abi> ToolChain::supportedAbis() const
+Abis ToolChain::supportedAbis() const
{
return {targetAbi()};
}
@@ -192,11 +189,6 @@ Core::Id ToolChain::language() const
return d->m_language;
}
-bool ToolChain::canClone() const
-{
- return true;
-}
-
bool ToolChain::operator == (const ToolChain &tc) const
{
if (this == &tc)
@@ -208,6 +200,22 @@ bool ToolChain::operator == (const ToolChain &tc) const
&& language() == tc.language();
}
+ToolChain *ToolChain::clone() const
+{
+ for (ToolChainFactory *f : Internal::g_toolChainFactories) {
+ if (f->supportedToolChainType() == d->m_typeId) {
+ ToolChain *tc = f->create();
+ QTC_ASSERT(tc, return nullptr);
+ tc->fromMap(toMap());
+ // New ID for the clone. It's different.
+ tc->d->m_id = QUuid::createUuid().toByteArray();
+ return tc;
+ }
+ }
+ QTC_CHECK(false);
+ return nullptr;
+}
+
/*!
Used by the tool chain manager to save user-generated tool chains.
@@ -236,6 +244,9 @@ QVariantMap ToolChain::toMap() const
void ToolChain::toolChainUpdated()
{
+ d->m_predefinedMacrosCache->invalidate();
+ d->m_headerPathsCache->invalidate();
+
ToolChainManager::notifyAboutUpdate(this);
}
@@ -243,8 +254,12 @@ void ToolChain::setDetection(ToolChain::Detection de)
{
if (d->m_detection == de)
return;
- d->m_detection = de;
- toolChainUpdated();
+ if (d->m_detection == ToolChain::UninitializedDetection) {
+ d->m_detection = de;
+ } else {
+ d->m_detection = de;
+ toolChainUpdated();
+ }
}
/*!
@@ -265,7 +280,7 @@ bool ToolChain::fromMap(const QVariantMap &data)
d->m_id = id.mid(pos + 1).toUtf8();
const bool autoDetect = data.value(QLatin1String(AUTODETECT_KEY), false).toBool();
- d->m_detection = autoDetect ? AutoDetectionFromSettings : ManualDetection;
+ d->m_detection = autoDetect ? AutoDetection : ManualDetection;
if (data.contains(LANGUAGE_KEY_V2)) {
// remove hack to trim language id in 4.4: This is to fix up broken language
@@ -286,6 +301,16 @@ bool ToolChain::fromMap(const QVariantMap &data)
return true;
}
+const ToolChain::HeaderPathsCache &ToolChain::headerPathsCache() const
+{
+ return d->m_headerPathsCache;
+}
+
+const ToolChain::MacrosCache &ToolChain::predefinedMacrosCache() const
+{
+ return d->m_predefinedMacrosCache;
+}
+
static long toLanguageVersionAsLong(QByteArray dateAsByteArray)
{
dateAsByteArray.chop(1); // Strip 'L'.
@@ -357,9 +382,9 @@ Utils::LanguageVersion ToolChain::languageVersion(const Core::Id &language, cons
Used by the tool chain kit information to validate the kit.
*/
-QList<Task> ToolChain::validateKit(const Kit *) const
+Tasks ToolChain::validateKit(const Kit *) const
{
- return QList<Task>();
+ return {};
}
QString ToolChain::sysRoot() const
@@ -390,21 +415,19 @@ QString ToolChain::sysRoot() const
Used by the tool chain manager to restore user-generated tool chains.
*/
-static QList<ToolChainFactory *> g_toolChainFactories;
-
ToolChainFactory::ToolChainFactory()
{
- g_toolChainFactories.append(this);
+ Internal::g_toolChainFactories.append(this);
}
ToolChainFactory::~ToolChainFactory()
{
- g_toolChainFactories.removeOne(this);
+ Internal::g_toolChainFactories.removeOne(this);
}
const QList<ToolChainFactory *> ToolChainFactory::allToolChainFactories()
{
- return g_toolChainFactories;
+ return Internal::g_toolChainFactories;
}
QList<ToolChain *> ToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown)
@@ -413,31 +436,35 @@ QList<ToolChain *> ToolChainFactory::autoDetect(const QList<ToolChain *> &alread
return QList<ToolChain *>();
}
-QList<ToolChain *> ToolChainFactory::autoDetect(const Utils::FileName &compilerPath, const Core::Id &language)
+QList<ToolChain *> ToolChainFactory::autoDetect(const Utils::FilePath &compilerPath, const Core::Id &language)
{
Q_UNUSED(compilerPath);
Q_UNUSED(language);
return QList<ToolChain *>();
}
-bool ToolChainFactory::canCreate()
+bool ToolChainFactory::canCreate() const
{
- return false;
+ return m_userCreatable;
}
-ToolChain *ToolChainFactory::create(Core::Id l)
+ToolChain *ToolChainFactory::create()
{
- Q_UNUSED(l);
- return nullptr;
+ return m_toolchainConstructor ? m_toolchainConstructor() : nullptr;
}
-bool ToolChainFactory::canRestore(const QVariantMap &)
+ToolChain *ToolChainFactory::restore(const QVariantMap &data)
{
- return false;
-}
+ if (!m_toolchainConstructor)
+ return nullptr;
-ToolChain *ToolChainFactory::restore(const QVariantMap &)
-{
+ ToolChain *tc = m_toolchainConstructor();
+ QTC_ASSERT(tc, return nullptr);
+
+ if (tc->fromMap(data))
+ return tc;
+
+ delete tc;
return nullptr;
}
@@ -464,4 +491,40 @@ void ToolChainFactory::autoDetectionToMap(QVariantMap &data, bool detected)
data.insert(QLatin1String(AUTODETECT_KEY), detected);
}
+QSet<Core::Id> ToolChainFactory::supportedLanguages() const
+{
+ return m_supportsAllLanguages ? ToolChainManager::allLanguages() : m_supportedLanguages;
+}
+
+Core::Id ToolChainFactory::supportedToolChainType() const
+{
+ return m_supportedToolChainType;
+}
+
+void ToolChainFactory::setSupportedToolChainType(const Core::Id &supportedToolChain)
+{
+ m_supportedToolChainType = supportedToolChain;
+}
+
+void ToolChainFactory::setSupportedLanguages(const QSet<Core::Id> &supportedLanguages)
+{
+ m_supportedLanguages = supportedLanguages;
+}
+
+void ToolChainFactory::setSupportsAllLanguages(bool supportsAllLanguages)
+{
+ m_supportsAllLanguages = supportsAllLanguages;
+}
+
+void ToolChainFactory::setToolchainConstructor
+ (const std::function<ToolChain *()> &toolchainContructor)
+{
+ m_toolchainConstructor = toolchainContructor;
+}
+
+void ToolChainFactory::setUserCreatable(bool userCreatable)
+{
+ m_userCreatable = userCreatable;
+}
+
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/toolchain.h b/src/plugins/projectexplorer/toolchain.h
index 8925b449a4..1cbe478691 100644
--- a/src/plugins/projectexplorer/toolchain.h
+++ b/src/plugins/projectexplorer/toolchain.h
@@ -28,13 +28,15 @@
#include "projectexplorer_export.h"
#include "projectexplorer_global.h"
+#include "abi.h"
#include "headerpath.h"
#include "projectmacro.h"
+#include "task.h"
+#include "toolchaincache.h"
#include <coreplugin/id.h>
#include <utils/cpplanguage_details.h>
-#include <utils/fileutils.h>
#include <QObject>
#include <QSet>
@@ -66,7 +68,6 @@ class Abi;
class IOutputParser;
class ToolChainConfigWidget;
class ToolChainFactory;
-class Task;
class Kit;
namespace Internal { class ToolChainSettingsAccessor; }
@@ -81,7 +82,8 @@ public:
enum Detection {
ManualDetection,
AutoDetection,
- AutoDetectionFromSettings
+ AutoDetectionFromSdk,
+ UninitializedDetection,
};
using Predicate = std::function<bool(const ToolChain *)>;
@@ -96,13 +98,13 @@ public:
QByteArray id() const;
- virtual Utils::FileNameList suggestedMkspecList() const;
- virtual Utils::FileName suggestedDebugger() const;
+ virtual QStringList suggestedMkspecList() const;
+ virtual Utils::FilePath suggestedDebugger() const;
Core::Id typeId() const;
virtual QString typeDisplayName() const = 0;
virtual Abi targetAbi() const = 0;
- virtual QList<Abi> supportedAbis() const;
+ virtual ProjectExplorer::Abis supportedAbis() const;
virtual QString originalTargetTriple() const { return QString(); }
virtual QStringList extraCodeModelFlags() const { return QStringList(); }
@@ -119,43 +121,51 @@ public:
Utils::LanguageVersion languageVersion;
};
+ using MacrosCache = std::shared_ptr<Cache<ToolChain::MacroInspectionReport, 64>>;
+ using HeaderPathsCache = std::shared_ptr<Cache<HeaderPaths>>;
+
// A MacroInspectionRunner is created in the ui thread and runs in another thread.
using MacroInspectionRunner = std::function<MacroInspectionReport(const QStringList &cxxflags)>;
virtual MacroInspectionRunner createMacroInspectionRunner() const = 0;
virtual Macros predefinedMacros(const QStringList &cxxflags) const = 0;
// A BuiltInHeaderPathsRunner is created in the ui thread and runs in another thread.
- using BuiltInHeaderPathsRunner = std::function<HeaderPaths(const QStringList &cxxflags,
- const QString &sysRoot)>;
+ using BuiltInHeaderPathsRunner = std::function<HeaderPaths(
+ const QStringList &cxxflags, const QString &sysRoot, const QString &originalTargetTriple)>;
virtual BuiltInHeaderPathsRunner createBuiltInHeaderPathsRunner() const = 0;
virtual HeaderPaths builtInHeaderPaths(const QStringList &cxxflags,
- const Utils::FileName &sysRoot) const = 0;
+ const Utils::FilePath &sysRoot) const = 0;
virtual void addToEnvironment(Utils::Environment &env) const = 0;
- virtual QString makeCommand(const Utils::Environment &env) const = 0;
+ virtual Utils::FilePath makeCommand(const Utils::Environment &env) const = 0;
Core::Id language() const;
- virtual Utils::FileName compilerCommand() const = 0;
+ virtual Utils::FilePath compilerCommand() const = 0;
virtual IOutputParser *outputParser() const = 0;
virtual bool operator ==(const ToolChain &) const;
virtual std::unique_ptr<ToolChainConfigWidget> createConfigurationWidget() = 0;
- virtual bool canClone() const;
- virtual ToolChain *clone() const = 0;
+ ToolChain *clone() const;
// Used by the toolchainmanager to save user-generated tool chains.
// Make sure to call this function when deriving!
virtual QVariantMap toMap() const;
- virtual QList<Task> validateKit(const Kit *k) const;
+ virtual Tasks validateKit(const Kit *k) const;
+
+ virtual bool isJobCountSupported() const { return true; }
void setLanguage(Core::Id language);
+ void setDetection(Detection d);
+
static Utils::LanguageVersion cxxLanguageVersion(const QByteArray &cplusplusMacroValue);
static Utils::LanguageVersion languageVersion(const Core::Id &language, const Macros &macros);
protected:
- explicit ToolChain(Core::Id typeId, Detection d);
- explicit ToolChain(const ToolChain &);
+ explicit ToolChain(Core::Id typeId);
+
+ const MacrosCache &predefinedMacrosCache() const;
+ const HeaderPathsCache &headerPathsCache() const;
virtual void toolChainUpdated();
@@ -163,7 +173,8 @@ protected:
virtual bool fromMap(const QVariantMap &data);
private:
- void setDetection(Detection d);
+ ToolChain(const ToolChain &) = delete;
+ ToolChain &operator=(const ToolChain &) = delete;
const std::unique_ptr<Internal::ToolChainPrivate> d;
@@ -182,27 +193,51 @@ public:
static const QList<ToolChainFactory *> allToolChainFactories();
QString displayName() const { return m_displayName; }
+ Core::Id supportedToolChainType() const;
virtual QList<ToolChain *> autoDetect(const QList<ToolChain *> &alreadyKnown);
- virtual QList<ToolChain *> autoDetect(const Utils::FileName &compilerPath, const Core::Id &language);
+ virtual QList<ToolChain *> autoDetect(const Utils::FilePath &compilerPath, const Core::Id &language);
- virtual bool canCreate();
- virtual ToolChain *create(Core::Id l);
+ virtual bool canCreate() const;
+ virtual ToolChain *create();
- virtual bool canRestore(const QVariantMap &data);
- virtual ToolChain *restore(const QVariantMap &data);
+ ToolChain *restore(const QVariantMap &data);
static QByteArray idFromMap(const QVariantMap &data);
static Core::Id typeIdFromMap(const QVariantMap &data);
static void autoDetectionToMap(QVariantMap &data, bool detected);
- virtual QSet<Core::Id> supportedLanguages() const = 0;
+ QSet<Core::Id> supportedLanguages() const;
+
+ void setUserCreatable(bool userCreatable);
protected:
void setDisplayName(const QString &name) { m_displayName = name; }
+ void setSupportedToolChainType(const Core::Id &supportedToolChainType);
+ void setSupportedLanguages(const QSet<Core::Id> &supportedLanguages);
+ void setSupportsAllLanguages(bool supportsAllLanguages);
+ void setToolchainConstructor(const std::function<ToolChain *()> &constructor);
+
+ class Candidate {
+ public:
+ Utils::FilePath compilerPath;
+ QString compilerVersion;
+
+ bool operator==(const ToolChainFactory::Candidate &other) const {
+ return compilerPath == other.compilerPath
+ && compilerVersion == other.compilerVersion;
+ }
+ };
+
+ using Candidates = QVector<Candidate>;
private:
QString m_displayName;
+ Core::Id m_supportedToolChainType;
+ QSet<Core::Id> m_supportedLanguages;
+ bool m_supportsAllLanguages = false;
+ bool m_userCreatable = false;
+ std::function<ToolChain *()> m_toolchainConstructor;
};
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/toolchainmanager.cpp b/src/plugins/projectexplorer/toolchainmanager.cpp
index caa15e6d2f..ffea568dbe 100644
--- a/src/plugins/projectexplorer/toolchainmanager.cpp
+++ b/src/plugins/projectexplorer/toolchainmanager.cpp
@@ -63,11 +63,12 @@ class ToolChainManagerPrivate
public:
~ToolChainManagerPrivate();
- QMap<QString, FileName> m_abiToDebugger;
+ QMap<QString, FilePath> m_abiToDebugger;
std::unique_ptr<ToolChainSettingsAccessor> m_accessor;
QList<ToolChain *> m_toolChains; // prioritized List
QVector<LanguageDisplayPair> m_languages;
+ ToolchainDetectionSettings m_detectionSettings;
};
ToolChainManagerPrivate::~ToolChainManagerPrivate()
@@ -83,6 +84,8 @@ static ToolChainManagerPrivate *d = nullptr;
using namespace Internal;
+const char DETECT_X64_AS_X32_KEY[] = "ProjectExplorer/Toolchains/DetectX64AsX32";
+
// --------------------------------------------------------------------------
// ToolChainManager
// --------------------------------------------------------------------------
@@ -100,6 +103,9 @@ ToolChainManager::ToolChainManager(QObject *parent) :
connect(this, &ToolChainManager::toolChainAdded, this, &ToolChainManager::toolChainsChanged);
connect(this, &ToolChainManager::toolChainRemoved, this, &ToolChainManager::toolChainsChanged);
connect(this, &ToolChainManager::toolChainUpdated, this, &ToolChainManager::toolChainsChanged);
+
+ QSettings * const s = Core::ICore::settings();
+ d->m_detectionSettings.detectX64AsX32 = s->value(DETECT_X64_AS_X32_KEY, false).toBool();
}
ToolChainManager::~ToolChainManager()
@@ -130,6 +136,8 @@ void ToolChainManager::saveToolChains()
QTC_ASSERT(d->m_accessor, return);
d->m_accessor->saveToolChains(d->m_toolChains, Core::ICore::dialogParent());
+ QSettings * const s = Core::ICore::settings();
+ s->setValue(DETECT_X64_AS_X32_KEY, d->m_detectionSettings.detectX64AsX32);
}
QList<ToolChain *> ToolChainManager::toolChains(const ToolChain::Predicate &predicate)
@@ -178,7 +186,7 @@ ToolChain *ToolChainManager::findToolChain(const QByteArray &id)
return tc;
}
-FileName ToolChainManager::defaultDebugger(const Abi &abi)
+FilePath ToolChainManager::defaultDebugger(const Abi &abi)
{
return d->m_abiToDebugger.value(abi.toString());
}
@@ -257,4 +265,14 @@ void ToolChainManager::aboutToShutdown()
#endif
}
+ToolchainDetectionSettings ToolChainManager::detectionSettings()
+{
+ return d->m_detectionSettings;
+}
+
+void ToolChainManager::setDetectionSettings(const ToolchainDetectionSettings &settings)
+{
+ d->m_detectionSettings = settings;
+}
+
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/toolchainmanager.h b/src/plugins/projectexplorer/toolchainmanager.h
index 2e26431b84..4de51c2b2a 100644
--- a/src/plugins/projectexplorer/toolchainmanager.h
+++ b/src/plugins/projectexplorer/toolchainmanager.h
@@ -38,13 +38,19 @@
#include <functional>
-namespace Utils { class FileName; }
+namespace Utils { class FilePath; }
namespace ProjectExplorer {
class ProjectExplorerPlugin;
class Abi;
+class ToolchainDetectionSettings
+{
+public:
+ bool detectX64AsX32 = false;
+};
+
// --------------------------------------------------------------------------
// ToolChainManager
// --------------------------------------------------------------------------
@@ -62,7 +68,7 @@ public:
static QList<ToolChain *> findToolChains(const Abi &abi);
static ToolChain *findToolChain(const QByteArray &id);
- static Utils::FileName defaultDebugger(const Abi &abi);
+ static Utils::FilePath defaultDebugger(const Abi &abi);
static bool isLoaded();
@@ -76,6 +82,9 @@ public:
static void aboutToShutdown();
+ static ToolchainDetectionSettings detectionSettings();
+ static void setDetectionSettings(const ToolchainDetectionSettings &settings);
+
void saveToolChains();
signals:
diff --git a/src/plugins/projectexplorer/toolchainoptionspage.cpp b/src/plugins/projectexplorer/toolchainoptionspage.cpp
index 2e41c8cd42..a16c6f216e 100644
--- a/src/plugins/projectexplorer/toolchainoptionspage.cpp
+++ b/src/plugins/projectexplorer/toolchainoptionspage.cpp
@@ -38,15 +38,21 @@
#include <utils/detailswidget.h>
#include <utils/qtcassert.h>
#include <utils/treemodel.h>
+#include <utils/utilsicons.h>
#include <QAction>
#include <QApplication>
+#include <QCheckBox>
+#include <QCoreApplication>
+#include <QDialog>
+#include <QDialogButtonBox>
#include <QHBoxLayout>
#include <QHeaderView>
#include <QItemSelectionModel>
#include <QMenu>
#include <QMessageBox>
#include <QPushButton>
+#include <QSet>
#include <QSpacerItem>
#include <QStackedWidget>
#include <QTextStream>
@@ -84,17 +90,20 @@ public:
if (column == 0)
return toolChain->displayName();
return toolChain->typeDisplayName();
-
case Qt::FontRole: {
QFont font;
font.setBold(changed);
return font;
}
-
case Qt::ToolTipRole:
+ if (!toolChain->isValid())
+ return ToolChainOptionsPage::tr("This toolchain is no longer valid.");
return ToolChainOptionsPage::tr("<nobr><b>ABI:</b> %1").arg(
changed ? ToolChainOptionsPage::tr("not up-to-date")
: toolChain->targetAbi().toString());
+ case Qt::DecorationRole:
+ return column == 0 && !toolChain->isValid()
+ ? Utils::Icons::CRITICAL.icon() : QVariant();
}
return QVariant();
}
@@ -104,6 +113,39 @@ public:
bool changed;
};
+class DetectionSettingsDialog : public QDialog
+{
+public:
+ DetectionSettingsDialog(const ToolchainDetectionSettings &settings, QWidget *parent)
+ : QDialog(parent)
+ {
+ setWindowTitle(ToolChainOptionsPage::tr("Toolchain Auto-detection Settings"));
+ const auto layout = new QVBoxLayout(this);
+ m_detectX64AsX32CheckBox.setText(ToolChainOptionsPage::tr("Detect x86_64 GCC compilers "
+ "as x86_64 and x86"));
+ m_detectX64AsX32CheckBox.setToolTip(ToolChainOptionsPage::tr("If checked, Qt Creator will "
+ "set up two instances of each x86_64 compiler:\nOne for the native x86_64 target, "
+ "and one for a plain x86 target.\nEnable this if you plan to create 32-bit x86 "
+ "binaries without using a dedicated cross compiler."));
+ m_detectX64AsX32CheckBox.setChecked(settings.detectX64AsX32);
+ layout->addWidget(&m_detectX64AsX32CheckBox);
+ const auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
+ connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
+ connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
+ layout->addWidget(buttonBox);
+ }
+
+ ToolchainDetectionSettings settings() const
+ {
+ ToolchainDetectionSettings s;
+ s.detectX64AsX32 = m_detectX64AsX32CheckBox.isChecked();
+ return s;
+ }
+
+private:
+ QCheckBox m_detectX64AsX32CheckBox;
+};
+
// --------------------------------------------------------------------------
// ToolChainOptionsWidget
// --------------------------------------------------------------------------
@@ -113,6 +155,7 @@ class ToolChainOptionsWidget : public QWidget
public:
ToolChainOptionsWidget()
{
+ m_detectionSettings = ToolChainManager::detectionSettings();
m_factories = Utils::filtered(ToolChainFactory::allToolChainFactories(),
[](ToolChainFactory *factory) { return factory->canCreate();});
@@ -169,6 +212,34 @@ public:
m_delButton = new QPushButton(ToolChainOptionsPage::tr("Remove"), this);
+ m_removeAllButton = new QPushButton(ToolChainOptionsPage::tr("Remove All"), this);
+ connect(m_removeAllButton, &QAbstractButton::clicked, this,
+ [this] {
+ QList<ToolChainTreeItem *> itemsToRemove;
+ m_model.forAllItems([&itemsToRemove](TreeItem *item) {
+ if (item->level() != 3)
+ return;
+ const auto tcItem = static_cast<ToolChainTreeItem *>(item);
+ if (tcItem->toolChain->detection() != ToolChain::AutoDetectionFromSdk)
+ itemsToRemove << tcItem;
+ });
+ for (ToolChainTreeItem * const tcItem : qAsConst(itemsToRemove))
+ markForRemoval(tcItem);
+ });
+
+ m_redetectButton = new QPushButton(ToolChainOptionsPage::tr("Re-detect"), this);
+ connect(m_redetectButton, &QAbstractButton::clicked,
+ this, &ToolChainOptionsWidget::redetectToolchains);
+
+ m_detectionSettingsButton = new QPushButton(
+ ToolChainOptionsPage::tr("Auto-detection Settings..."), this);
+ connect(m_detectionSettingsButton, &QAbstractButton::clicked, this,
+ [this] {
+ DetectionSettingsDialog dlg(m_detectionSettings, this);
+ if (dlg.exec() == QDialog::Accepted)
+ m_detectionSettings = dlg.settings();
+ });
+
m_container = new DetailsWidget(this);
m_container->setState(DetailsWidget::NoSummary);
m_container->setVisible(false);
@@ -185,6 +256,9 @@ public:
buttonLayout->addWidget(m_addButton);
buttonLayout->addWidget(m_cloneButton);
buttonLayout->addWidget(m_delButton);
+ buttonLayout->addWidget(m_removeAllButton);
+ buttonLayout->addWidget(m_redetectButton);
+ buttonLayout->addWidget(m_detectionSettingsButton);
buttonLayout->addItem(new QSpacerItem(10, 40, QSizePolicy::Minimum, QSizePolicy::Expanding));
auto verticalLayout = new QVBoxLayout;
@@ -232,9 +306,11 @@ public:
return action;
}
+ void redetectToolchains();
+
void apply();
- public:
+ private:
TreeModel<TreeItem, ToolChainTreeItem> m_model;
QList<ToolChainFactory *> m_factories;
QTreeView *m_toolChainView;
@@ -243,11 +319,16 @@ public:
QPushButton *m_addButton;
QPushButton *m_cloneButton;
QPushButton *m_delButton;
+ QPushButton *m_removeAllButton;
+ QPushButton *m_redetectButton;
+ QPushButton *m_detectionSettingsButton;
QHash<Core::Id, QPair<StaticTreeItem *, StaticTreeItem *>> m_languageMap;
QList<ToolChainTreeItem *> m_toAddList;
QList<ToolChainTreeItem *> m_toRemoveList;
+
+ ToolchainDetectionSettings m_detectionSettings;
};
void ToolChainOptionsWidget::markForRemoval(ToolChainTreeItem *item)
@@ -312,6 +393,50 @@ StaticTreeItem *ToolChainOptionsWidget::parentForToolChain(ToolChain *tc)
return tc->isAutoDetected() ? nodes.first : nodes.second;
}
+void ToolChainOptionsWidget::redetectToolchains()
+{
+ QList<ToolChainTreeItem *> itemsToRemove;
+ QList<ToolChain *> knownTcs;
+ m_model.forAllItems([&itemsToRemove, &knownTcs](TreeItem *item) {
+ if (item->level() != 3)
+ return;
+ const auto tcItem = static_cast<ToolChainTreeItem *>(item);
+ if (tcItem->toolChain->isAutoDetected()
+ && tcItem->toolChain->detection() != ToolChain::AutoDetectionFromSdk) {
+ itemsToRemove << tcItem;
+ } else {
+ knownTcs << tcItem->toolChain;
+ }
+ });
+ QList<ToolChain *> toAdd;
+ QSet<ToolChain *> toDelete;
+ for (ToolChainFactory *f : ToolChainFactory::allToolChainFactories()) {
+ for (ToolChain * const tc : f->autoDetect(knownTcs)) {
+ if (knownTcs.contains(tc) || toDelete.contains(tc))
+ continue;
+ const auto matchItem = [tc](const ToolChainTreeItem *item) {
+ return item->toolChain->compilerCommand() == tc->compilerCommand()
+ && item->toolChain->typeId() == tc->typeId()
+ && item->toolChain->language() == tc->language()
+ && item->toolChain->targetAbi() == tc->targetAbi();
+ };
+ ToolChainTreeItem * const item = findOrDefault(itemsToRemove, matchItem);
+ if (item) {
+ itemsToRemove.removeOne(item);
+ toDelete << tc;
+ continue;
+ }
+ knownTcs << tc;
+ toAdd << tc;
+ }
+ }
+ for (ToolChainTreeItem * const tcItem : qAsConst(itemsToRemove))
+ markForRemoval(tcItem);
+ for (ToolChain * const newTc : qAsConst(toAdd))
+ m_toAddList.append(insertToolChain(newTc, true));
+ qDeleteAll(toDelete);
+}
+
void ToolChainOptionsWidget::toolChainSelectionChanged()
{
ToolChainTreeItem *item = currentTreeItem();
@@ -334,14 +459,16 @@ void ToolChainOptionsWidget::apply()
// Update tool chains:
foreach (const Core::Id &l, m_languageMap.keys()) {
- StaticTreeItem *parent = m_languageMap.value(l).second;
- for (TreeItem *item : *parent) {
- auto tcItem = static_cast<ToolChainTreeItem *>(item);
- Q_ASSERT(tcItem->toolChain);
- if (tcItem->widget)
- tcItem->widget->apply();
- tcItem->changed = false;
- tcItem->update();
+ const QPair<StaticTreeItem *, StaticTreeItem *> autoAndManual = m_languageMap.value(l);
+ for (StaticTreeItem *parent : {autoAndManual.first, autoAndManual.second}) {
+ for (TreeItem *item : *parent) {
+ auto tcItem = static_cast<ToolChainTreeItem *>(item);
+ Q_ASSERT(tcItem->toolChain);
+ if (!tcItem->toolChain->isAutoDetected() && tcItem->widget)
+ tcItem->widget->apply();
+ tcItem->changed = false;
+ tcItem->update();
+ }
}
}
@@ -374,6 +501,7 @@ void ToolChainOptionsWidget::apply()
"They were not configured again.")
.arg(removedTcs.join(QLatin1String(",<br>&nbsp;"))));
}
+ ToolChainManager::setDetectionSettings(m_detectionSettings);
}
void ToolChainOptionsWidget::createToolChain(ToolChainFactory *factory, const Core::Id &language)
@@ -382,10 +510,13 @@ void ToolChainOptionsWidget::createToolChain(ToolChainFactory *factory, const Co
QTC_ASSERT(factory->canCreate(), return);
QTC_ASSERT(language.isValid(), return);
- ToolChain *tc = factory->create(language);
+ ToolChain *tc = factory->create();
if (!tc)
return;
+ tc->setDetection(ToolChain::ManualDetection);
+ tc->setLanguage(language);
+
auto item = insertToolChain(tc, true);
m_toAddList.append(item);
@@ -397,11 +528,15 @@ void ToolChainOptionsWidget::cloneToolChain()
ToolChainTreeItem *current = currentTreeItem();
if (!current)
return;
- ToolChain *tc = current->toolChain->clone();
+ ToolChain *tc = current->toolChain->clone();
if (!tc)
return;
+ tc->setDetection(ToolChain::ManualDetection);
+ tc->setDisplayName(QCoreApplication::translate("ProjectExplorer::ToolChain", "Clone of %1")
+ .arg(current->toolChain->displayName()));
+
auto item = insertToolChain(tc, true);
m_toAddList.append(item);
@@ -414,8 +549,8 @@ void ToolChainOptionsWidget::updateState()
bool canDelete = false;
if (ToolChainTreeItem *item = currentTreeItem()) {
ToolChain *tc = item->toolChain;
- canCopy = tc->isValid() && tc->canClone();
- canDelete = tc->detection() != ToolChain::AutoDetection;
+ canCopy = tc->isValid();
+ canDelete = tc->detection() != ToolChain::AutoDetectionFromSdk;
}
m_cloneButton->setEnabled(canCopy);
diff --git a/src/plugins/projectexplorer/toolchainsettingsaccessor.cpp b/src/plugins/projectexplorer/toolchainsettingsaccessor.cpp
index 80d280a122..d2c347dd37 100644
--- a/src/plugins/projectexplorer/toolchainsettingsaccessor.cpp
+++ b/src/plugins/projectexplorer/toolchainsettingsaccessor.cpp
@@ -164,12 +164,9 @@ static ToolChainOperations mergeToolChainLists(const QList<ToolChain *> &systemF
const QList<ToolChain *> notRedetectedButValidUserTcs
= Utils::filtered(notRedetectedUserTcs, &ToolChain::isValid);
- const QList<ToolChain *> validManualUserTcs
- = Utils::filtered(manualUserFileTcs, &ToolChain::isValid);
-
ToolChainOperations result;
result.toDemote = notRedetectedButValidUserTcs;
- result.toRegister = stabilizeOrder(systemFileTcs + validManualUserTcs + result.toDemote // manual TCs
+ result.toRegister = stabilizeOrder(systemFileTcs + manualUserFileTcs + result.toDemote // manual TCs
+ redetectedUserTcs + newlyAutodetectedTcs, // auto TCs
userFileTcs);
@@ -187,7 +184,7 @@ ToolChainSettingsAccessor::ToolChainSettingsAccessor() :
QCoreApplication::translate("ProjectExplorer::ToolChainManager", "Tool Chains"),
Core::Constants::IDE_DISPLAY_NAME)
{
- setBaseFilePath(FileName::fromString(Core::ICore::userResourcePath() + TOOLCHAIN_FILENAME));
+ setBaseFilePath(FilePath::fromString(Core::ICore::userResourcePath() + TOOLCHAIN_FILENAME));
addVersionUpgrader(std::make_unique<ToolChainSettingsUpgraderV0>());
}
@@ -196,8 +193,10 @@ QList<ToolChain *> ToolChainSettingsAccessor::restoreToolChains(QWidget *parent)
{
// read all tool chains from SDK
const QList<ToolChain *> systemFileTcs
- = toolChains(restoreSettings(FileName::fromString(Core::ICore::installerResourcePath() + TOOLCHAIN_FILENAME),
+ = toolChains(restoreSettings(FilePath::fromString(Core::ICore::installerResourcePath() + TOOLCHAIN_FILENAME),
parent));
+ for (ToolChain * const systemTc : systemFileTcs)
+ systemTc->setDetection(ToolChain::AutoDetectionFromSdk);
// read all tool chains from user file.
const QList<ToolChain *> userFileTcs = toolChains(restoreSettings(parent));
@@ -225,7 +224,7 @@ void ToolChainSettingsAccessor::saveToolChains(const QList<ToolChain *> &toolcha
int count = 0;
for (const ToolChain *tc : toolchains) {
- if (!tc || !tc->isValid())
+ if (!tc || (!tc->isValid() && tc->isAutoDetected()))
continue;
const QVariantMap tmp = tc->toMap();
if (tmp.isEmpty())
@@ -254,18 +253,21 @@ QList<ToolChain *> ToolChainSettingsAccessor::toolChains(const QVariantMap &data
const QVariantMap tcMap = data.value(key).toMap();
bool restored = false;
- for (ToolChainFactory *f : factories) {
- if (f->canRestore(tcMap)) {
- if (ToolChain *tc = f->restore(tcMap)) {
- result.append(tc);
- restored = true;
- break;
+ const Core::Id tcType = ToolChainFactory::typeIdFromMap(tcMap);
+ if (tcType.isValid()) {
+ for (ToolChainFactory *f : factories) {
+ if (f->supportedToolChainType() == tcType) {
+ if (ToolChain *tc = f->restore(tcMap)) {
+ result.append(tc);
+ restored = true;
+ break;
+ }
}
}
}
if (!restored)
qWarning("Warning: Unable to restore compiler type '%s' for tool chain %s.",
- qPrintable(ToolChainFactory::typeIdFromMap(tcMap).toString()),
+ qPrintable(tcType.toString()),
qPrintable(QString::fromUtf8(ToolChainFactory::idFromMap(tcMap))));
}
@@ -290,11 +292,17 @@ namespace ProjectExplorer {
using TCList = QList<ToolChain *>;
+const char TestTokenKey[] = "TestTokenKey";
+const char TestToolChainType[] = "TestToolChainType";
+
+
class TTC : public ToolChain
{
public:
- TTC(ToolChain::Detection d, const QByteArray &t, bool v = true) :
- ToolChain("TestToolChainType", d),
+ TTC() : ToolChain(TestToolChainType) {}
+
+ TTC(const QByteArray &t, bool v = true) :
+ ToolChain(TestToolChainType),
token(t),
m_valid(v)
{
@@ -313,28 +321,36 @@ public:
LanguageExtensions languageExtensions(const QStringList &cxxflags) const override { Q_UNUSED(cxxflags); return LanguageExtension::None; }
WarningFlags warningFlags(const QStringList &cflags) const override { Q_UNUSED(cflags); return WarningFlags::NoWarnings; }
BuiltInHeaderPathsRunner createBuiltInHeaderPathsRunner() const override { return BuiltInHeaderPathsRunner(); }
- HeaderPaths builtInHeaderPaths(const QStringList &cxxflags, const FileName &sysRoot) const override
+ HeaderPaths builtInHeaderPaths(const QStringList &cxxflags, const FilePath &sysRoot) const override
{ Q_UNUSED(cxxflags); Q_UNUSED(sysRoot); return {}; }
void addToEnvironment(Environment &env) const override { Q_UNUSED(env); }
- QString makeCommand(const Environment &env) const override { Q_UNUSED(env); return QString("make"); }
- FileName compilerCommand() const override { return Utils::FileName::fromString("/tmp/test/gcc"); }
+ 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; }
std::unique_ptr<ToolChainConfigWidget> createConfigurationWidget() override { return nullptr; }
- TTC *clone() const override { return new TTC(*this); }
bool operator ==(const ToolChain &other) const override {
if (!ToolChain::operator==(other))
return false;
return static_cast<const TTC *>(&other)->token == token;
}
+ bool fromMap(const QVariantMap &data) final
+ {
+ ToolChain::fromMap(data);
+ token = data.value(TestTokenKey).toByteArray();
+ return true;
+ }
+
+ QVariantMap toMap() const final
+ {
+ QVariantMap data = ToolChain::toMap();
+ data[TestTokenKey] = token;
+ return data;
+ }
+
QByteArray token;
private:
- TTC(const TTC &other) :
- ToolChain(other.typeId(), other.detection()),
- token(other.token)
- {}
-
bool m_valid = false;
static QList<TTC *> m_toolChains;
@@ -352,6 +368,17 @@ namespace ProjectExplorer {
void ProjectExplorerPlugin::testToolChainMerging_data()
{
+ class TestToolChainFactory : ToolChainFactory
+ {
+ public:
+ TestToolChainFactory() {
+ setSupportedToolChainType(TestToolChainType);
+ setToolchainConstructor([] { return new TTC; });
+ }
+ };
+
+ TestToolChainFactory factory;
+
QTest::addColumn<TCList>("system");
QTest::addColumn<TCList>("user");
QTest::addColumn<TCList>("autodetect");
@@ -359,33 +386,43 @@ void ProjectExplorerPlugin::testToolChainMerging_data()
QTest::addColumn<TCList>("toRegister");
TTC *system1 = nullptr;
- TTC *system1c = nullptr;
+ ToolChain *system1c = nullptr;
TTC *system2 = nullptr;
TTC *system3i = nullptr;
TTC *user1 = nullptr;
- TTC *user1c = nullptr;
+ ToolChain *user1c = nullptr;
TTC *user3i = nullptr;
TTC *user2 = nullptr;
TTC *auto1 = nullptr;
- TTC *auto1c = nullptr;
+ ToolChain *auto1c = nullptr;
TTC *auto1_2 = nullptr;
TTC *auto2 = nullptr;
TTC *auto3i = nullptr;
if (!TTC::hasToolChains()) {
- system1 = new TTC(ToolChain::AutoDetection, "system1"); Q_UNUSED(system1);
- system1c = system1->clone(); Q_UNUSED(system1c);
- system2 = new TTC(ToolChain::AutoDetection, "system2"); Q_UNUSED(system2);
- system3i = new TTC(ToolChain::AutoDetection, "system3", false); Q_UNUSED(system3i);
- user1 = new TTC(ToolChain::ManualDetection, "user1"); Q_UNUSED(user1);
- user1c = user1->clone(); Q_UNUSED(user1c);
- user2 = new TTC(ToolChain::ManualDetection, "user2"); Q_UNUSED(user2);
- user3i = new TTC(ToolChain::ManualDetection, "user3", false); Q_UNUSED(user3i);
- auto1 = new TTC(ToolChain::AutoDetectionFromSettings, "auto1"); Q_UNUSED(auto1);
- auto1c = auto1->clone(); Q_UNUSED(auto1c);
- auto1_2 = new TTC(ToolChain::AutoDetectionFromSettings, "auto1"); Q_UNUSED(auto1_2);
- auto2 = new TTC(ToolChain::AutoDetectionFromSettings, "auto2"); Q_UNUSED(auto2);
- auto3i = new TTC(ToolChain::AutoDetectionFromSettings, "auto3", false); Q_UNUSED(auto3i);
+ system1 = new TTC("system1");
+ system1->setDetection(ToolChain::AutoDetection);
+ system1c = system1->clone(); Q_UNUSED(system1c)
+ system2 = new TTC("system2");
+ system2->setDetection(ToolChain::AutoDetection);
+ system3i = new TTC("system3", false);
+ system3i->setDetection(ToolChain::AutoDetection);
+ user1 = new TTC("user1");
+ user1->setDetection(ToolChain::ManualDetection);
+ user1c = user1->clone(); Q_UNUSED(user1c)
+ user2 = new TTC("user2");
+ user2->setDetection(ToolChain::ManualDetection);
+ user3i = new TTC("user3", false);
+ user3i->setDetection(ToolChain::ManualDetection);
+ auto1 = new TTC("auto1");
+ auto1->setDetection(ToolChain::AutoDetection);
+ auto1c = auto1->clone();
+ auto1_2 = new TTC("auto1");
+ auto1_2->setDetection(ToolChain::AutoDetection);
+ auto2 = new TTC("auto2");
+ auto2->setDetection(ToolChain::AutoDetection);
+ auto3i = new TTC("auto3", false);
+ auto3i->setDetection(ToolChain::AutoDetection);
}
QTest::newRow("no toolchains")
@@ -424,9 +461,9 @@ void ProjectExplorerPlugin::testToolChainMerging_data()
<< (TCList()) << (TCList() << auto3i) << (TCList())
<< (TCList()) << (TCList());
- QTest::newRow("Delete invalid user")
+ QTest::newRow("invalid user")
<< (TCList()) << (TCList() << user3i) << (TCList())
- << (TCList()) << (TCList());
+ << (TCList()) << (TCList{user3i});
QTest::newRow("one of everything")
<< (TCList() << system1) << (TCList() << user1) << (TCList() << auto1)
diff --git a/src/plugins/projectexplorer/treescanner.cpp b/src/plugins/projectexplorer/treescanner.cpp
new file mode 100644
index 0000000000..7c7f634d1a
--- /dev/null
+++ b/src/plugins/projectexplorer/treescanner.cpp
@@ -0,0 +1,176 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Alexander Drozdov.
+** Contact: Alexander Drozdov (adrozdoff@gmail.com)
+**
+** 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 "treescanner.h"
+#include "projectexplorerconstants.h"
+
+#include <coreplugin/iversioncontrol.h>
+#include <coreplugin/vcsmanager.h>
+
+#include <cpptools/cpptoolsconstants.h>
+
+#include <utils/qtcassert.h>
+#include <utils/algorithm.h>
+#include <utils/runextensions.h>
+
+#include <memory>
+
+namespace ProjectExplorer {
+
+TreeScanner::TreeScanner(QObject *parent) : QObject(parent)
+{
+ m_factory = TreeScanner::genericFileType;
+ m_filter = [](const Utils::MimeType &mimeType, const Utils::FilePath &fn) {
+ return isWellKnownBinary(mimeType, fn) && isMimeBinary(mimeType, fn);
+ };
+
+ connect(&m_futureWatcher, &FutureWatcher::finished, this, &TreeScanner::finished);
+}
+
+TreeScanner::~TreeScanner()
+{
+ if (!m_futureWatcher.isFinished()) {
+ m_futureWatcher.cancel();
+ m_futureWatcher.waitForFinished();
+ }
+}
+
+bool TreeScanner::asyncScanForFiles(const Utils::FilePath &directory)
+{
+ if (!m_futureWatcher.isFinished())
+ return false;
+
+ auto fi = new FutureInterface();
+ m_scanFuture = fi->future();
+ m_futureWatcher.setFuture(m_scanFuture);
+
+ Utils::runAsync([this, fi, directory]() { TreeScanner::scanForFiles(fi, directory, m_filter, m_factory); });
+
+ return true;
+}
+
+void TreeScanner::setFilter(TreeScanner::FileFilter filter)
+{
+ if (isFinished())
+ m_filter = filter;
+}
+
+void TreeScanner::setTypeFactory(TreeScanner::FileTypeFactory factory)
+{
+ if (isFinished())
+ m_factory = factory;
+}
+
+TreeScanner::Future TreeScanner::future() const
+{
+ return m_scanFuture;
+}
+
+bool TreeScanner::isFinished() const
+{
+ return m_futureWatcher.isFinished();
+}
+
+TreeScanner::Result TreeScanner::result() const
+{
+ if (isFinished())
+ return m_scanFuture.result();
+ return Result();
+}
+
+TreeScanner::Result TreeScanner::release()
+{
+ if (isFinished()) {
+ auto result = m_scanFuture.result();
+ m_scanFuture = Future();
+ return result;
+ }
+ return Result();
+}
+
+void TreeScanner::reset()
+{
+ if (isFinished())
+ m_scanFuture = Future();
+}
+
+bool TreeScanner::isWellKnownBinary(const Utils::MimeType & /*mdb*/, const Utils::FilePath &fn)
+{
+ return fn.endsWith(QLatin1String(".a")) ||
+ fn.endsWith(QLatin1String(".o")) ||
+ fn.endsWith(QLatin1String(".d")) ||
+ fn.endsWith(QLatin1String(".exe")) ||
+ fn.endsWith(QLatin1String(".dll")) ||
+ fn.endsWith(QLatin1String(".obj")) ||
+ fn.endsWith(QLatin1String(".elf"));
+}
+
+bool TreeScanner::isMimeBinary(const Utils::MimeType &mimeType, const Utils::FilePath &/*fn*/)
+{
+ bool isBinary = false;
+ if (mimeType.isValid()) {
+ QStringList mimes;
+ mimes << mimeType.name() << mimeType.allAncestors();
+ isBinary = !mimes.contains(QLatin1String("text/plain"));
+ }
+ return isBinary;
+}
+
+FileType TreeScanner::genericFileType(const Utils::MimeType &mimeType, const Utils::FilePath &/*fn*/)
+{
+ return Node::fileTypeForMimeType(mimeType);
+}
+
+void TreeScanner::scanForFiles(FutureInterface *fi, const Utils::FilePath& directory,
+ const FileFilter &filter, const FileTypeFactory &factory)
+{
+ std::unique_ptr<FutureInterface> fip(fi);
+ fip->reportStarted();
+
+ Result nodes = FileNode::scanForFiles(
+ directory,
+ [&filter, &factory](const Utils::FilePath &fn) -> FileNode * {
+ const Utils::MimeType mimeType = Utils::mimeTypeForFile(fn.toString());
+
+ // Skip some files during scan.
+ if (filter && filter(mimeType, fn))
+ return nullptr;
+
+ // Type detection
+ FileType type = FileType::Unknown;
+ if (factory)
+ type = factory(mimeType, fn);
+
+ return new FileNode(fn, type);
+ }, fip.get());
+
+ Utils::sort(nodes, ProjectExplorer::Node::sortByPath);
+
+ fip->setProgressValue(fip->progressMaximum());
+ fip->reportResult(nodes);
+ fip->reportFinished();
+}
+
+} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/treescanner.h b/src/plugins/projectexplorer/treescanner.h
new file mode 100644
index 0000000000..e2ad544bde
--- /dev/null
+++ b/src/plugins/projectexplorer/treescanner.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Alexander Drozdov.
+** Contact: Alexander Drozdov (adrozdoff@gmail.com)
+**
+** 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_export.h"
+#include "projectnodes.h"
+
+#include <utils/mimetypes/mimedatabase.h>
+#include <utils/fileutils.h>
+
+#include <QObject>
+#include <QFuture>
+#include <QFutureWatcher>
+
+#include <functional>
+
+namespace Core { class IVersionControl; }
+
+namespace ProjectExplorer {
+
+class PROJECTEXPLORER_EXPORT TreeScanner : public QObject
+{
+ Q_OBJECT
+
+public:
+ using Result = QList<ProjectExplorer::FileNode *>;
+ using Future = QFuture<Result>;
+ using FutureWatcher = QFutureWatcher<Result>;
+ using FutureInterface = QFutureInterface<Result>;
+
+ using FileFilter = std::function<bool(const Utils::MimeType &, const Utils::FilePath &)>;
+ using FileTypeFactory = std::function<ProjectExplorer::FileType(const Utils::MimeType &, const Utils::FilePath &)>;
+
+ explicit TreeScanner(QObject *parent = nullptr);
+ ~TreeScanner() override;
+
+ // Start scanning in given directory
+ bool asyncScanForFiles(const Utils::FilePath& directory);
+
+ // Setup filter for ignored files
+ void setFilter(FileFilter filter);
+
+ // Setup factory for file types
+ void setTypeFactory(FileTypeFactory factory);
+
+ Future future() const;
+ bool isFinished() const;
+
+ // Takes not-owning result
+ Result result() const;
+ // Takes owning of result
+ Result release();
+ // Clear scan results
+ void reset();
+
+ // Standard filters helpers
+ static bool isWellKnownBinary(const Utils::MimeType &mimeType, const Utils::FilePath &fn);
+ static bool isMimeBinary(const Utils::MimeType &mimeType, const Utils::FilePath &fn);
+
+ // Standard file factory
+ static ProjectExplorer::FileType genericFileType(const Utils::MimeType &mdb, const Utils::FilePath& fn);
+
+signals:
+ void finished();
+
+private:
+ static void scanForFiles(FutureInterface *fi, const Utils::FilePath &directory,
+ const FileFilter &filter, const FileTypeFactory &factory);
+
+private:
+ FileFilter m_filter;
+ FileTypeFactory m_factory;
+
+ FutureWatcher m_futureWatcher;
+ Future m_scanFuture;
+};
+
+} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/userfileaccessor.cpp b/src/plugins/projectexplorer/userfileaccessor.cpp
index 49a0ccdf7b..838507e544 100644
--- a/src/plugins/projectexplorer/userfileaccessor.cpp
+++ b/src/plugins/projectexplorer/userfileaccessor.cpp
@@ -52,6 +52,16 @@ const char OBSOLETE_VERSION_KEY[] = "ProjectExplorer.Project.Updater.FileVersion
const char SHARED_SETTINGS[] = "SharedSettings";
const char USER_STICKY_KEYS_KEY[] = "UserStickyKeys";
+#ifdef PROJECT_USER_FILE_EXTENSION
+#define STRINGIFY_INTERNAL(x) #x
+#define STRINGIFY(x) STRINGIFY_INTERNAL(x)
+
+const char FILE_EXTENSION_STR[] = STRINGIFY(PROJECT_USER_FILE_EXTENSION);
+#else
+const char FILE_EXTENSION_STR[] = ".user";
+
+#endif
+
// Version 14 Move builddir into BuildConfiguration
class UserFileVersion14Upgrader : public VersionUpgrader
{
@@ -230,19 +240,18 @@ static QString makeRelative(QString path)
}
// Return complete file path of the .user file.
-static FileName externalUserFilePath(const Utils::FileName &projectFilePath, const QString &suffix)
+static FilePath externalUserFilePath(const Utils::FilePath &projectFilePath, const QString &suffix)
{
- FileName result;
static const optional<QString> externalUserFileDir = defineExternalUserFileDir();
if (externalUserFileDir) {
// Recreate the relative project file hierarchy under the shared directory.
// PersistentSettingsWriter::write() takes care of creating the path.
- result = FileName::fromString(externalUserFileDir.value());
- result.appendString('/' + makeRelative(projectFilePath.toString()));
- result.appendString(suffix);
+ return FilePath::fromString(externalUserFileDir.value()
+ + '/' + makeRelative(projectFilePath.toString())
+ + suffix);
}
- return result;
+ return {};
}
} // namespace
@@ -257,18 +266,18 @@ public:
UserFileBackUpStrategy(UserFileAccessor *accessor) : Utils::VersionedBackUpStrategy(accessor)
{ }
- FileNameList readFileCandidates(const Utils::FileName &baseFileName) const final;
+ FilePathList readFileCandidates(const Utils::FilePath &baseFileName) const final;
};
-FileNameList UserFileBackUpStrategy::readFileCandidates(const FileName &baseFileName) const
+FilePathList UserFileBackUpStrategy::readFileCandidates(const FilePath &baseFileName) const
{
const auto *const ac = static_cast<const UserFileAccessor *>(accessor());
- const FileName externalUser = ac->externalUserFile();
- const FileName projectUser = ac->projectUserFile();
+ const FilePath externalUser = ac->externalUserFile();
+ const FilePath projectUser = ac->projectUserFile();
QTC_CHECK(!baseFileName.isEmpty());
QTC_CHECK(baseFileName == externalUser || baseFileName == projectUser);
- FileNameList result = Utils::VersionedBackUpStrategy::readFileCandidates(projectUser);
+ FilePathList result = Utils::VersionedBackUpStrategy::readFileCandidates(projectUser);
if (!externalUser.isEmpty())
result.append(Utils::VersionedBackUpStrategy::readFileCandidates(externalUser));
@@ -286,8 +295,8 @@ UserFileAccessor::UserFileAccessor(Project *project) :
m_project(project)
{
// Setup:
- const FileName externalUser = externalUserFile();
- const FileName projectUser = projectUserFile();
+ const FilePath externalUser = externalUserFile();
+ const FilePath projectUser = projectUserFile();
setBaseFilePath(externalUser.isEmpty() ? projectUser : externalUser);
auto secondary
@@ -375,27 +384,25 @@ QVariant UserFileAccessor::retrieveSharedSettings() const
return project()->property(SHARED_SETTINGS);
}
-FileName UserFileAccessor::projectUserFile() const
+FilePath UserFileAccessor::projectUserFile() const
{
static const QString qtcExt = QLatin1String(qgetenv("QTC_EXTENSION"));
- FileName projectUserFile = m_project->projectFilePath();
- projectUserFile.appendString(generateSuffix(qtcExt.isEmpty() ? ".user" : qtcExt));
- return projectUserFile;
+ return m_project->projectFilePath()
+ .stringAppended(generateSuffix(qtcExt.isEmpty() ? FILE_EXTENSION_STR : qtcExt));
}
-FileName UserFileAccessor::externalUserFile() const
+FilePath UserFileAccessor::externalUserFile() const
{
static const QString qtcExt = QFile::decodeName(qgetenv("QTC_EXTENSION"));
return externalUserFilePath(m_project->projectFilePath(),
- generateSuffix(qtcExt.isEmpty() ? ".user" : qtcExt));
+ generateSuffix(qtcExt.isEmpty() ? FILE_EXTENSION_STR : qtcExt));
}
-FileName UserFileAccessor::sharedFile() const
+FilePath UserFileAccessor::sharedFile() const
{
static const QString qtcExt = QLatin1String(qgetenv("QTC_SHARED_EXTENSION"));
- FileName sharedFile = m_project->projectFilePath();
- sharedFile.appendString(generateSuffix(qtcExt.isEmpty() ? ".shared" : qtcExt));
- return sharedFile;
+ return m_project->projectFilePath()
+ .stringAppended(generateSuffix(qtcExt.isEmpty() ? ".shared" : qtcExt));
}
QVariantMap UserFileAccessor::postprocessMerge(const QVariantMap &main,
@@ -877,7 +884,7 @@ private:
class TestProject : public Project
{
public:
- TestProject() : Project("x-test/testproject", Utils::FileName::fromString("/test/project")) {
+ TestProject() : Project("x-test/testproject", Utils::FilePath::fromString("/test/project")) {
setDisplayName("Test Project");
}
@@ -974,7 +981,7 @@ void ProjectExplorerPlugin::testUserFileAccessor_mergeSettings()
sharedData.insert("shared1", "bar");
sharedData.insert("shared2", "baz");
sharedData.insert("shared3", "foooo");
- TestUserFileAccessor::RestoreData shared(FileName::fromString("/shared/data"), sharedData);
+ TestUserFileAccessor::RestoreData shared(FilePath::fromString("/shared/data"), sharedData);
QVariantMap data;
data.insert("Version", accessor.currentVersion());
@@ -983,7 +990,7 @@ void ProjectExplorerPlugin::testUserFileAccessor_mergeSettings()
data.insert("shared1", "bar1");
data.insert("unique1", 1234);
data.insert("shared3", "foo");
- TestUserFileAccessor::RestoreData user(FileName::fromString("/user/data"), data);
+ TestUserFileAccessor::RestoreData user(FilePath::fromString("/user/data"), data);
TestUserFileAccessor::RestoreData result = accessor.mergeSettings(user, shared);
QVERIFY(!result.hasIssue());
@@ -1009,10 +1016,10 @@ void ProjectExplorerPlugin::testUserFileAccessor_mergeSettingsEmptyUser()
sharedData.insert("shared1", "bar");
sharedData.insert("shared2", "baz");
sharedData.insert("shared3", "foooo");
- TestUserFileAccessor::RestoreData shared(FileName::fromString("/shared/data"), sharedData);
+ TestUserFileAccessor::RestoreData shared(FilePath::fromString("/shared/data"), sharedData);
QVariantMap data;
- TestUserFileAccessor::RestoreData user(FileName::fromString("/shared/data"), data);
+ TestUserFileAccessor::RestoreData user(FilePath::fromString("/shared/data"), data);
TestUserFileAccessor::RestoreData result = accessor.mergeSettings(user, shared);
@@ -1026,7 +1033,7 @@ void ProjectExplorerPlugin::testUserFileAccessor_mergeSettingsEmptyShared()
TestUserFileAccessor accessor(&project);
QVariantMap sharedData;
- TestUserFileAccessor::RestoreData shared(FileName::fromString("/shared/data"), sharedData);
+ TestUserFileAccessor::RestoreData shared(FilePath::fromString("/shared/data"), sharedData);
QVariantMap data;
data.insert("Version", accessor.currentVersion());
@@ -1036,7 +1043,7 @@ void ProjectExplorerPlugin::testUserFileAccessor_mergeSettingsEmptyShared()
data.insert("shared1", "bar1");
data.insert("unique1", 1234);
data.insert("shared3", "foo");
- TestUserFileAccessor::RestoreData user(FileName::fromString("/shared/data"), data);
+ TestUserFileAccessor::RestoreData user(FilePath::fromString("/shared/data"), data);
TestUserFileAccessor::RestoreData result = accessor.mergeSettings(user, shared);
diff --git a/src/plugins/projectexplorer/userfileaccessor.h b/src/plugins/projectexplorer/userfileaccessor.h
index 6544de987e..6b7d42ec1a 100644
--- a/src/plugins/projectexplorer/userfileaccessor.h
+++ b/src/plugins/projectexplorer/userfileaccessor.h
@@ -47,9 +47,9 @@ public:
virtual QVariant retrieveSharedSettings() const;
- Utils::FileName projectUserFile() const;
- Utils::FileName externalUserFile() const;
- Utils::FileName sharedFile() const;
+ Utils::FilePath projectUserFile() const;
+ Utils::FilePath externalUserFile() const;
+ Utils::FilePath sharedFile() const;
protected:
QVariantMap postprocessMerge(const QVariantMap &main,
diff --git a/src/plugins/projectexplorer/waitforstopdialog.h b/src/plugins/projectexplorer/waitforstopdialog.h
index d8c0037712..47c960dba8 100644
--- a/src/plugins/projectexplorer/waitforstopdialog.h
+++ b/src/plugins/projectexplorer/waitforstopdialog.h
@@ -29,7 +29,7 @@
#include <QDialog>
#include <QTime>
-#include "runconfiguration.h"
+#include "runcontrol.h"
QT_BEGIN_NAMESPACE
class QLabel;
diff --git a/src/plugins/projectexplorer/xcodebuildparser.cpp b/src/plugins/projectexplorer/xcodebuildparser.cpp
index a96d4bb097..ae551e259c 100644
--- a/src/plugins/projectexplorer/xcodebuildparser.cpp
+++ b/src/plugins/projectexplorer/xcodebuildparser.cpp
@@ -73,7 +73,7 @@ void XcodebuildParser::stdOutput(const QString &line)
Task task(Task::Warning,
QCoreApplication::translate("ProjectExplorer::XcodebuildParser",
"Replacing signature"),
- Utils::FileName::fromString(
+ Utils::FilePath::fromString(
lne.left(lne.size() - QLatin1String(signatureChangeEndsWithPattern).size())), /* filename */
-1, /* line */
Constants::TASK_CATEGORY_COMPILE);
@@ -96,7 +96,7 @@ void XcodebuildParser::stdError(const QString &line)
Task task(Task::Error,
QCoreApplication::translate("ProjectExplorer::XcodebuildParser",
"Xcodebuild failed."),
- Utils::FileName(), /* filename */
+ Utils::FilePath(), /* filename */
-1, /* line */
Constants::TASK_CATEGORY_COMPILE);
taskAdded(task);
@@ -139,7 +139,7 @@ void ProjectExplorerPlugin::testXcodebuildParserParsing_data()
QTest::addColumn<OutputParserTester::Channel>("inputChannel");
QTest::addColumn<QString>("childStdOutLines");
QTest::addColumn<QString>("childStdErrLines");
- QTest::addColumn<QList<Task> >("tasks");
+ QTest::addColumn<Tasks >("tasks");
QTest::addColumn<QString>("outputLines");
QTest::addColumn<ProjectExplorer::XcodebuildParser::XcodebuildStatus>("finalStatus");
@@ -147,42 +147,42 @@ void ProjectExplorerPlugin::testXcodebuildParserParsing_data()
<< XcodebuildParser::OutsideXcodebuild
<< QString::fromLatin1("Sometext") << OutputParserTester::STDOUT
<< QString::fromLatin1("Sometext\n") << QString()
- << QList<Task>()
+ << Tasks()
<< QString()
<< XcodebuildParser::OutsideXcodebuild;
QTest::newRow("outside pass-through stderr")
<< XcodebuildParser::OutsideXcodebuild
<< QString::fromLatin1("Sometext") << OutputParserTester::STDERR
<< QString() << QString::fromLatin1("Sometext\n")
- << QList<Task>()
+ << Tasks()
<< QString()
<< XcodebuildParser::OutsideXcodebuild;
QTest::newRow("inside pass stdout to stderr")
<< XcodebuildParser::InXcodebuild
<< QString::fromLatin1("Sometext") << OutputParserTester::STDOUT
<< QString() << QString::fromLatin1("Sometext\n")
- << QList<Task>()
+ << Tasks()
<< QString()
<< XcodebuildParser::InXcodebuild;
QTest::newRow("inside ignore stderr")
<< XcodebuildParser::InXcodebuild
<< QString::fromLatin1("Sometext") << OutputParserTester::STDERR
<< QString() << QString()
- << QList<Task>()
+ << Tasks()
<< QString()
<< XcodebuildParser::InXcodebuild;
QTest::newRow("unknown pass stdout to stderr")
<< XcodebuildParser::UnknownXcodebuildState
<< QString::fromLatin1("Sometext") << OutputParserTester::STDOUT
<< QString() << QString::fromLatin1("Sometext\n")
- << QList<Task>()
+ << Tasks()
<< QString()
<< XcodebuildParser::UnknownXcodebuildState;
QTest::newRow("unknown ignore stderr (change?)")
<< XcodebuildParser::UnknownXcodebuildState
<< QString::fromLatin1("Sometext") << OutputParserTester::STDERR
<< QString() << QString()
- << QList<Task>()
+ << Tasks()
<< QString()
<< XcodebuildParser::UnknownXcodebuildState;
QTest::newRow("switch outside->in->outside")
@@ -196,7 +196,7 @@ void ProjectExplorerPlugin::testXcodebuildParserParsing_data()
"outside2")
<< OutputParserTester::STDOUT
<< QString::fromLatin1("outside\noutside2\n") << QString::fromLatin1("in xcodebuild\nin xcodebuild2\n")
- << QList<Task>()
+ << Tasks()
<< QString()
<< XcodebuildParser::OutsideXcodebuild;
QTest::newRow("switch Unknown->in->outside")
@@ -208,7 +208,7 @@ void ProjectExplorerPlugin::testXcodebuildParserParsing_data()
"outside")
<< OutputParserTester::STDOUT
<< QString::fromLatin1("outside\n") << QString::fromLatin1("unknown\nin xcodebuild\n")
- << QList<Task>()
+ << Tasks()
<< QString()
<< XcodebuildParser::OutsideXcodebuild;
QTest::newRow("switch in->unknown")
@@ -218,12 +218,12 @@ void ProjectExplorerPlugin::testXcodebuildParserParsing_data()
"unknownErr")
<< OutputParserTester::STDERR
<< QString() << QString()
- << (QList<Task>()
+ << (Tasks()
<< Task(
Task::Error,
QCoreApplication::translate("ProjectExplorer::XcodebuildParser",
"Xcodebuild failed."),
- Utils::FileName(), /* filename */
+ Utils::FilePath(), /* filename */
-1, /* line */
Constants::TASK_CATEGORY_COMPILE))
<< QString()
@@ -235,12 +235,12 @@ void ProjectExplorerPlugin::testXcodebuildParserParsing_data()
"unknownErr")
<< OutputParserTester::STDERR
<< QString() << QString::fromLatin1("outErr\n")
- << (QList<Task>()
+ << (Tasks()
<< Task(
Task::Error,
QCoreApplication::translate("ProjectExplorer::XcodebuildParser",
"Xcodebuild failed."),
- Utils::FileName(), /* filename */
+ Utils::FilePath(), /* filename */
-1, /* line */
Constants::TASK_CATEGORY_COMPILE))
<< QString()
@@ -249,11 +249,11 @@ void ProjectExplorerPlugin::testXcodebuildParserParsing_data()
<< XcodebuildParser::InXcodebuild
<< QString::fromLatin1("/somepath/somefile.app: replacing existing signature") << OutputParserTester::STDOUT
<< QString() << QString()
- << (QList<Task>()
+ << (Tasks()
<< Task(Task::Warning,
QCoreApplication::translate("ProjectExplorer::XcodebuildParser",
"Replacing signature"),
- Utils::FileName::fromString(QLatin1String("/somepath/somefile.app")), /* filename */
+ Utils::FilePath::fromString(QLatin1String("/somepath/somefile.app")), /* filename */
-1, /* line */
Constants::TASK_CATEGORY_COMPILE))
<< QString()
@@ -262,7 +262,7 @@ void ProjectExplorerPlugin::testXcodebuildParserParsing_data()
<< XcodebuildParser::OutsideXcodebuild
<< QString::fromLatin1("/somepath/somefile.app: replacing existing signature") << OutputParserTester::STDOUT
<< QString::fromLatin1("/somepath/somefile.app: replacing existing signature\n") << QString()
- << QList<Task>()
+ << Tasks()
<< QString()
<< XcodebuildParser::OutsideXcodebuild;
}
@@ -282,7 +282,7 @@ void ProjectExplorerPlugin::testXcodebuildParserParsing()
QFETCH(OutputParserTester::Channel, inputChannel);
QFETCH(QString, childStdOutLines);
QFETCH(QString, childStdErrLines);
- QFETCH(QList<Task>, tasks);
+ QFETCH(Tasks, tasks);
QFETCH(QString, outputLines);
QFETCH(ProjectExplorer::XcodebuildParser::XcodebuildStatus, finalStatus);